Esempio n. 1
0
int vnic_devcmd_init(struct vnic_dev *vdev)
{
	void __iomem *res;
	int err;

	res = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD2, 0);
	if (res) {
		err = vnic_dev_init_devcmd2(vdev);
		if (err)
			vdev_warn(vdev, "DEVCMD2 init failed: %d, Using DEVCMD1\n",
				  err);
		else
			return 0;
	} else {
		vdev_warn(vdev, "DEVCMD2 resource not found (old firmware?) Using DEVCMD1\n");
	}
	err = vnic_dev_init_devcmd1(vdev);
	if (err)
		vdev_err(vdev, "DEVCMD1 initialization failed: %d\n", err);

	return err;
}
Esempio n. 2
0
File: linux.c Progetto: 8l/vdev
// yield the next device event
// return 0 on success 
// return 1 if there are no more devices
// return -EAGAIN if vdev should try to get this device again 
// return -errno on failure to poll for devices or read the next device packet.
int vdev_os_next_device( struct vdev_device_request* vreq, void* cls ) {
   
   int rc = 0;
   struct vdev_linux_context* ctx = (struct vdev_linux_context*)cls;
   char buf[VDEV_LINUX_NETLINK_BUF_MAX];
   ssize_t len = 0;
   
   char cbuf[CMSG_SPACE(sizeof(struct ucred))];
   struct cmsghdr *chdr = NULL;
   struct ucred *cred = NULL;
   struct msghdr hdr;
   struct iovec iov;
   struct sockaddr_nl cnls;
   
   pthread_mutex_lock( &ctx->initial_requests_lock );
   
   // do we have initial requests?
   if( ctx->initial_requests != NULL ) {
      
      // next request
      struct vdev_device_request* req = ctx->initial_requests;
      
      // consume 
      ctx->initial_requests = ctx->initial_requests->next;
      
      memcpy( vreq, req, sizeof(struct vdev_device_request) );
      free( req );
      
      pthread_mutex_unlock( &ctx->initial_requests_lock );
      
      // was that the last of them?
      if( ctx->initial_requests == NULL ) {
         
         // tell vdevd that we've flushed all pending requests 
         vdev_os_context_signal_flushed( ctx->os_ctx );
      }
      
      return 0;
   }
   else if( ctx->os_ctx->state->once ) {
      
      // out of requests; die 
      pthread_mutex_unlock( &ctx->initial_requests_lock );
      return 1;
   }
   else {
      
      pthread_mutex_unlock( &ctx->initial_requests_lock );
   }
   
   memset(&hdr, 0, sizeof(struct msghdr));
   
   // next event (wait forever)
   // NOTE: this is a cancellation point!
   rc = poll( &ctx->pfd, 1, -1 );
   
   if( rc < 0 ) {
      
      rc = -errno;
      
      if( rc == -EINTR ) {
         // try again 
         return -EAGAIN;
      }
      
      vdev_error("FATAL: poll(%d) rc = %d\n", ctx->pfd.fd, rc );
      
      return rc;
   }
   
   // get the event 
   iov.iov_base = buf;
   iov.iov_len = VDEV_LINUX_NETLINK_BUF_MAX;
                
   hdr.msg_iov = &iov;
   hdr.msg_iovlen = 1;
   
   // get control-plane messages
   hdr.msg_control = cbuf;
   hdr.msg_controllen = sizeof(cbuf);
   
   hdr.msg_name = &cnls;
   hdr.msg_namelen = sizeof(cnls);

   // get the event 
   len = recvmsg( ctx->pfd.fd, &hdr, 0 );
   if( len < 0 ) {
      
      rc = -errno;
      vdev_error("FATAL: recvmsg(%d) rc = %d\n", ctx->pfd.fd, rc );
      
      return rc;
   }
   
   // big enough?
   if( len < 32 || len >= VDEV_LINUX_NETLINK_BUF_MAX ) {
      
      vdev_error("Netlink message is %zd bytes; ignoring...\n", len );
      return -EAGAIN;
   }
   
   // control message, for credentials
   chdr = CMSG_FIRSTHDR( &hdr );
   if( chdr == NULL || chdr->cmsg_type != SCM_CREDENTIALS ) {
      
      vdev_error("%s", "Netlink message has no credentials\n");
      return -EAGAIN;
   }
   
   // get the credentials
   cred = (struct ucred *)CMSG_DATA(chdr);
   
   // if not root, ignore 
   if( cred->uid != 0 ) {
      
      vdev_error("Ignoring message from non-root ID %d\n", cred->uid );
      return -EAGAIN;
   }
   
   // if udev, ignore 
   if( memcmp( buf, VDEV_LINUX_NETLINK_UDEV_HEADER, VDEV_LINUX_NETLINK_UDEV_HEADER_LEN ) == 0 ) {
      
      // message from udev; ignore 
      vdev_warn("%s", "Ignoring libudev message\n");
      return -EAGAIN;
   }
   
   // kernel messages don't come from userspace 
   if( cnls.nl_pid > 0 ) {
      
      // from userspace???
      vdev_warn("Ignoring message from PID %d\n", (int)cnls.nl_pid );
      return -EAGAIN;
   }
   
   // parse the event buffer
   vdev_debug("%p from netlink\n", vreq );
   rc = vdev_linux_parse_request( ctx, vreq, buf, len );
   
   if( rc != 0 ) {
      
      vdev_error("vdev_linux_parse_request rc = %d\n", rc );
      
      return -EAGAIN;
   }
   
   return 0;
}
Esempio n. 3
0
File: linux.c Progetto: 8l/vdev
// parse a uevent, and use the information to fill in a device request.
// nlbuf must be a contiguous concatenation of null-terminated KEY=VALUE strings.
// return 0 on success
static int vdev_linux_parse_request( struct vdev_linux_context* ctx, struct vdev_device_request* vreq, char* nlbuf, ssize_t buflen ) {
   
   char* buf = nlbuf;
   char* key = NULL;
   char* value = NULL;
   int offset = 0;
   int rc = 0;
   unsigned int major = 0;
   unsigned int minor = 0;
   bool have_major = false;
   bool have_minor = false;
   mode_t dev_mode = 0;
   int line_count = 0;
   bool not_param = false;      // if set to true, add as an OS-specific parameter to the vreq
   
   char* devpath = NULL;        // sysfs devpath 
   char* subsystem = NULL;      // sysfs subsystem 
   char* devname = (char*)VDEV_DEVICE_PATH_UNKNOWN;        // DEVNAME from uevent
   
   vdev_device_request_t reqtype = VDEV_DEVICE_INVALID;
   
   vdev_debug("%p: uevent buffer\n", vreq );
   vdev_linux_debug_uevent( nlbuf, buflen );
   
   // sanity check: if the first line is $action@$devpath, then skip it (since the information 
   // contained in the uevent will encode the very same bits of information)
   if( strchr(buf, '@') != NULL ) { 
         
      // advance to the next line
      offset += strlen(buf) + 1;
   }
   
   // get key/value pairs
   while( offset < buflen ) {
      
      line_count++;
      not_param = false;
      
      rc = vdev_keyvalue_next( buf + offset, &key, &value );
      
      if( rc < 0 ) {
         
         vdev_error("Invalid line %d (byte %d): '%s'\n", line_count, offset, buf + offset );
         vdev_linux_error_uevent( nlbuf, buflen );
         
         return -EINVAL;
      }
      
      offset += rc + 1;         // count the \0 at the end
      rc = 0;
      
      // is this the action to take?
      if( strcmp(key, "ACTION") == 0 ) {
         
         reqtype = vdev_linux_parse_device_request_type( value );
         
         if( reqtype == VDEV_DEVICE_INVALID ) {
            
            vdev_error("Invalid ACTION '%s'\n", value );
            vdev_linux_error_uevent( nlbuf, buflen );
            
            return -EINVAL;
         }
         
         vdev_device_request_set_type( vreq, reqtype );
         
         not_param = true;
      }
      
      // is this the sysfs device path?
      else if( strcmp(key, "DEVPATH") == 0 ) {
         
         devpath = value;
      }
      
      // is this the devname?
      else if( strcmp(key, "DEVNAME") == 0 ) {
         
         devname = value;
      }
      
      // subsystem given?
      else if( strcmp(key, "SUBSYSTEM") == 0 ) {
         
         subsystem = vdev_strdup_or_null( value );
      }
      
      // is this the major device number?
      else if( strcmp(key, "MAJOR") == 0 && !have_major ) {
         
         char* tmp = NULL;
         major = (int)strtol( value, &tmp, 10 );
         
         if( *tmp != '\0' ) {
            
            vdev_error("Invalid 'MAJOR' value '%s'\n", value);
            vdev_linux_error_uevent( nlbuf, buflen );
            
            return -EINVAL;
         }
         
         have_major = true;
         not_param = true;
      }
      
      // is this the minor device number?
      else if( strcmp(key, "MINOR") == 0 && !have_minor ) {
         
         char* tmp = NULL;
         minor = (int)strtol( value, &tmp, 10 ) ;
         
         if( *tmp != '\0' ) {
            
            vdev_error("Invalid 'MINOR' value '%s'\n", value );
            vdev_linux_error_uevent( nlbuf, buflen );
            
            return -EINVAL;
         }
         
         have_minor = true;
         not_param = true;
      }
      
      if( !not_param ) {
         
         // add to OS params 
         rc = vdev_device_request_add_param( vreq, key, value );
         if( rc != 0 ) {
            
            // could be OOM 
            if( subsystem != NULL ) {
               free( subsystem );
            }
            
            return rc;
         }
      }
   }
   
   if( reqtype == VDEV_DEVICE_INVALID ) {
      
      vdev_error("%s", "No ACTION given\n");
      vdev_linux_error_uevent( nlbuf, buflen );
      
      if( subsystem != NULL ) {
         free( subsystem );
      }
      
      return -EINVAL;
   }
   
   if( (!have_major && have_minor) || (have_major && !have_minor) ) {
      
      vdev_error("Missing device information: major=%d, minor=%d\n", have_major, have_minor );
      vdev_linux_error_uevent( nlbuf, buflen );
      
      if( subsystem != NULL ) {
         free( subsystem );
      }
      
      return -EINVAL;
   }
   
   if( have_major && have_minor ) {
      
      // explicit major and minor device numbers given 
      vdev_device_request_set_dev( vreq, makedev(major, minor) );
   }
   
   if( devname != NULL ) {
      
      // use this as the device's path 
      vdev_device_request_set_path( vreq, devname );
   }
   
   if( devpath != NULL ) {
      
      // get any remaining information from sysfs 
      // check major/minor?
      if( !have_major || !have_minor ) {
         
         // see if we have major/minor device numbers for this device...
         rc = vdev_linux_sysfs_read_dev_nums( ctx, devpath, &major, &minor );
         
         if( rc == 0 ) {
            
            // yup!
            vdev_device_request_set_dev( vreq, makedev(major, minor) );
            
            have_major = true;
            have_minor = true;
         }
         else {
            
            // it's okay to not have dev numbers
            rc = 0;
         }
      }
      
      // subsystem?
      if( subsystem == NULL ) {
         
         // see if we have a subsystem 
         rc = vdev_linux_sysfs_read_subsystem( ctx, devpath, &subsystem );
         
         if( rc == 0 ) {
            
            // yup!
            rc = vdev_device_request_add_param( vreq, "SUBSYSTEM", subsystem );
            if( rc != 0 ) {
               
               // OOM
               free( subsystem );
               return rc;
            }
         }
         else if( rc != -ENOMEM ) {
            
            // this is weird...
            vdev_warn("no subsystem found for '%s'\n", devpath );
            rc = 0;
         }
      }
   }
   
   if( have_major && have_minor ) {
      
      if( subsystem != NULL && strcasecmp(subsystem, "block") == 0 ) {
         
         // this is a block 
         dev_mode = S_IFBLK;
      }
      
      else {
         
         // this is a character device--we have major/minor numbers
         dev_mode = S_IFCHR;
      }
   
      vdev_device_request_set_mode( vreq, dev_mode );
   }
   
   vdev_debug("subsystem = '%s', have_major=%d, major = %u, have_minor=%d, minor = %u, mode = %o\n", subsystem, have_major, major, have_minor, minor, dev_mode );
   
   if( subsystem != NULL ) {
      free( subsystem );
   }
   
   // tell helpers where /sys is mounted 
   rc = vdev_device_request_add_param( vreq, "SYSFS_MOUNTPOINT", ctx->sysfs_mountpoint );
   if( rc != 0 ) {
      
      // OOM 
      return rc;
   }
   
   return rc;
}