aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/usbip/userspace/libsrc/vhci_driver.c')
-rw-r--r--drivers/staging/usbip/userspace/libsrc/vhci_driver.c397
1 files changed, 102 insertions, 295 deletions
diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
index 209df9b37cb4..8901fcb7946f 100644
--- a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
+++ b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
@@ -6,44 +6,28 @@
#include "vhci_driver.h"
#include <limits.h>
#include <netdb.h>
+#include <libudev.h>
+#include "sysfs_utils.h"
#undef PROGNAME
#define PROGNAME "libusbip"
struct usbip_vhci_driver *vhci_driver;
+struct udev *udev_context;
static struct usbip_imported_device *
imported_device_init(struct usbip_imported_device *idev, char *busid)
{
- struct sysfs_device *sudev;
+ struct udev_device *sudev;
- sudev = sysfs_open_device("usb", busid);
+ sudev = udev_device_new_from_subsystem_sysname(udev_context,
+ "usb", busid);
if (!sudev) {
- dbg("sysfs_open_device failed: %s", busid);
+ dbg("udev_device_new_from_subsystem_sysname failed: %s", busid);
goto err;
}
read_usb_device(sudev, &idev->udev);
- sysfs_close_device(sudev);
-
- /* add class devices of this imported device */
- struct usbip_class_device *cdev;
- dlist_for_each_data(vhci_driver->cdev_list, cdev,
- struct usbip_class_device) {
- if (!strncmp(cdev->dev_path, idev->udev.path,
- strlen(idev->udev.path))) {
- struct usbip_class_device *new_cdev;
- /*
- * alloc and copy because dlist is linked
- * from only one list
- */
- new_cdev = calloc(1, sizeof(*new_cdev));
- if (!new_cdev)
- goto err;
-
- memcpy(new_cdev, cdev, sizeof(*new_cdev));
- dlist_unshift(idev->cdev_list, (void *) new_cdev);
- }
- }
+ udev_device_unref(sudev);
return idev;
@@ -53,7 +37,7 @@ err:
-static int parse_status(char *value)
+static int parse_status(const char *value)
{
int ret = 0;
char *c;
@@ -100,12 +84,6 @@ static int parse_status(char *value)
idev->busnum = (devid >> 16);
idev->devnum = (devid & 0x0000ffff);
- idev->cdev_list = dlist_new(sizeof(struct usbip_class_device));
- if (!idev->cdev_list) {
- dbg("dlist_new failed");
- return -1;
- }
-
if (idev->status != VDEV_ST_NULL
&& idev->status != VDEV_ST_NOTASSIGNED) {
idev = imported_device_init(idev, lbusid);
@@ -129,156 +107,35 @@ static int parse_status(char *value)
return 0;
}
-
-static int check_usbip_device(struct sysfs_class_device *cdev)
-{
- /* /sys/class/video4linux/video0/device */
- char class_path[SYSFS_PATH_MAX];
- /* /sys/devices/platform/vhci_hcd/usb6/6-1:1.1 */
- char dev_path[SYSFS_PATH_MAX];
- int ret;
- struct usbip_class_device *usbip_cdev;
-
- snprintf(class_path, sizeof(class_path), "%s/device", cdev->path);
-
- ret = sysfs_get_link(class_path, dev_path, sizeof(dev_path));
- if (ret == 0) {
- if (!strncmp(dev_path, vhci_driver->hc_device->path,
- strlen(vhci_driver->hc_device->path))) {
- /* found usbip device */
- usbip_cdev = calloc(1, sizeof(*usbip_cdev));
- if (!usbip_cdev) {
- dbg("calloc failed");
- return -1;
- }
- dlist_unshift(vhci_driver->cdev_list, usbip_cdev);
- strncpy(usbip_cdev->class_path, class_path,
- sizeof(usbip_cdev->class_path));
- strncpy(usbip_cdev->dev_path, dev_path,
- sizeof(usbip_cdev->dev_path));
- dbg("found: %s %s", class_path, dev_path);
- }
- }
-
- return 0;
-}
-
-
-static int search_class_for_usbip_device(char *cname)
-{
- struct sysfs_class *class;
- struct dlist *cdev_list;
- struct sysfs_class_device *cdev;
- int ret = 0;
-
- class = sysfs_open_class(cname);
- if (!class) {
- dbg("sysfs_open_class failed");
- return -1;
- }
-
- dbg("class: %s", class->name);
-
- cdev_list = sysfs_get_class_devices(class);
- if (!cdev_list)
- /* nothing */
- goto out;
-
- dlist_for_each_data(cdev_list, cdev, struct sysfs_class_device) {
- dbg("cdev: %s", cdev->name);
- ret = check_usbip_device(cdev);
- if (ret < 0)
- goto out;
- }
-
-out:
- sysfs_close_class(class);
-
- return ret;
-}
-
-
-static int refresh_class_device_list(void)
-{
- int ret;
- struct dlist *cname_list;
- char *cname;
- char sysfs_mntpath[SYSFS_PATH_MAX];
- char class_path[SYSFS_PATH_MAX];
-
- ret = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
- if (ret < 0) {
- dbg("sysfs_get_mnt_path failed");
- return -1;
- }
-
- snprintf(class_path, sizeof(class_path), "%s/%s", sysfs_mntpath,
- SYSFS_CLASS_NAME);
-
- /* search under /sys/class */
- cname_list = sysfs_open_directory_list(class_path);
- if (!cname_list) {
- dbg("sysfs_open_directory failed");
- return -1;
- }
-
- dlist_for_each_data(cname_list, cname, char) {
- ret = search_class_for_usbip_device(cname);
- if (ret < 0) {
- sysfs_close_list(cname_list);
- return -1;
- }
- }
-
- sysfs_close_list(cname_list);
-
- /* search under /sys/block */
- ret = search_class_for_usbip_device(SYSFS_BLOCK_NAME);
- if (ret < 0)
- return -1;
-
- return 0;
-}
-
-
static int refresh_imported_device_list(void)
{
- struct sysfs_attribute *attr_status;
-
+ const char *attr_status;
- attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");
+ attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
+ "status");
if (!attr_status) {
- dbg("sysfs_get_device_attr(\"status\") failed: %s",
- vhci_driver->hc_device->name);
+ err("udev_device_get_sysattr_value failed");
return -1;
}
- dbg("name: %s path: %s len: %d method: %d value: %s",
- attr_status->name, attr_status->path, attr_status->len,
- attr_status->method, attr_status->value);
-
- return parse_status(attr_status->value);
+ return parse_status(attr_status);
}
static int get_nports(void)
{
char *c;
int nports = 0;
- struct sysfs_attribute *attr_status;
+ const char *attr_status;
- attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");
+ attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
+ "status");
if (!attr_status) {
- dbg("sysfs_get_device_attr(\"status\") failed: %s",
- vhci_driver->hc_device->name);
+ err("udev_device_get_sysattr_value failed");
return -1;
}
- dbg("name: %s path: %s len: %d method: %d value: %s",
- attr_status->name, attr_status->path, attr_status->len,
- attr_status->method, attr_status->value);
-
/* skip a header line */
- c = strchr(attr_status->value, '\n');
+ c = strchr(attr_status, '\n');
if (!c)
return 0;
c++;
@@ -295,71 +152,66 @@ static int get_nports(void)
return nports;
}
-static int get_hc_busid(char *sysfs_mntpath, char *hc_busid)
-{
- struct sysfs_driver *sdriver;
- char sdriver_path[SYSFS_PATH_MAX];
-
- struct sysfs_device *hc_dev;
- struct dlist *hc_devs;
-
- int found = 0;
-
- snprintf(sdriver_path, SYSFS_PATH_MAX, "%s/%s/%s/%s/%s", sysfs_mntpath,
- SYSFS_BUS_NAME, USBIP_VHCI_BUS_TYPE, SYSFS_DRIVERS_NAME,
- USBIP_VHCI_DRV_NAME);
-
- sdriver = sysfs_open_driver_path(sdriver_path);
- if (!sdriver) {
- dbg("sysfs_open_driver_path failed: %s", sdriver_path);
- dbg("make sure " USBIP_CORE_MOD_NAME ".ko and "
- USBIP_VHCI_DRV_NAME ".ko are loaded!");
- return -1;
- }
-
- hc_devs = sysfs_get_driver_devices(sdriver);
- if (!hc_devs) {
- dbg("sysfs_get_driver failed");
- goto err;
- }
-
- /* assume only one vhci_hcd */
- dlist_for_each_data(hc_devs, hc_dev, struct sysfs_device) {
- strncpy(hc_busid, hc_dev->bus_id, SYSFS_BUS_ID_SIZE);
- found = 1;
- }
-
-err:
- sysfs_close_driver(sdriver);
-
- if (found)
- return 0;
-
- dbg("%s not found", hc_busid);
- return -1;
-}
-
-static int read_record(int rhport, char *host, char *port, char *busid)
+/*
+ * Read the given port's record.
+ *
+ * To avoid buffer overflow we will read the entire line and
+ * validate each part's size. The initial buffer is padded by 4 to
+ * accommodate the 2 spaces, 1 newline and an additional character
+ * which is needed to properly validate the 3rd part without it being
+ * truncated to an acceptable length.
+ */
+static int read_record(int rhport, char *host, unsigned long host_len,
+ char *port, unsigned long port_len, char *busid)
{
+ int part;
FILE *file;
char path[PATH_MAX+1];
+ char *buffer, *start, *end;
+ char delim[] = {' ', ' ', '\n'};
+ int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE};
+ size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4;
+
+ buffer = malloc(buffer_len);
+ if (!buffer)
+ return -1;
snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
file = fopen(path, "r");
if (!file) {
err("fopen");
+ free(buffer);
return -1;
}
- if (fscanf(file, "%s %s %s\n", host, port, busid) != 3) {
- err("fscanf");
+ if (fgets(buffer, buffer_len, file) == NULL) {
+ err("fgets");
+ free(buffer);
fclose(file);
return -1;
}
-
fclose(file);
+ /* validate the length of each of the 3 parts */
+ start = buffer;
+ for (part = 0; part < 3; part++) {
+ end = strchr(start, delim[part]);
+ if (end == NULL || (end - start) > max_len[part]) {
+ free(buffer);
+ return -1;
+ }
+ start = end + 1;
+ }
+
+ if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) {
+ err("sscanf");
+ free(buffer);
+ return -1;
+ }
+
+ free(buffer);
+
return 0;
}
@@ -367,30 +219,21 @@ static int read_record(int rhport, char *host, char *port, char *busid)
int usbip_vhci_driver_open(void)
{
- int ret;
- char hc_busid[SYSFS_BUS_ID_SIZE];
-
- vhci_driver = (struct usbip_vhci_driver *) calloc(1, sizeof(*vhci_driver));
- if (!vhci_driver) {
- dbg("calloc failed");
+ udev_context = udev_new();
+ if (!udev_context) {
+ err("udev_new failed");
return -1;
}
- ret = sysfs_get_mnt_path(vhci_driver->sysfs_mntpath, SYSFS_PATH_MAX);
- if (ret < 0) {
- dbg("sysfs_get_mnt_path failed");
- goto err;
- }
-
- ret = get_hc_busid(vhci_driver->sysfs_mntpath, hc_busid);
- if (ret < 0)
- goto err;
+ vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver));
/* will be freed in usbip_driver_close() */
- vhci_driver->hc_device = sysfs_open_device(USBIP_VHCI_BUS_TYPE,
- hc_busid);
+ vhci_driver->hc_device =
+ udev_device_new_from_subsystem_sysname(udev_context,
+ USBIP_VHCI_BUS_TYPE,
+ USBIP_VHCI_DRV_NAME);
if (!vhci_driver->hc_device) {
- dbg("sysfs_open_device failed");
+ err("udev_device_new_from_subsystem_sysname failed");
goto err;
}
@@ -398,29 +241,21 @@ int usbip_vhci_driver_open(void)
dbg("available ports: %d", vhci_driver->nports);
- vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device));
- if (!vhci_driver->cdev_list)
- goto err;
-
- if (refresh_class_device_list())
- goto err;
-
if (refresh_imported_device_list())
goto err;
-
return 0;
-
err:
- if (vhci_driver->cdev_list)
- dlist_destroy(vhci_driver->cdev_list);
- if (vhci_driver->hc_device)
- sysfs_close_device(vhci_driver->hc_device);
+ udev_device_unref(vhci_driver->hc_device);
+
if (vhci_driver)
free(vhci_driver);
vhci_driver = NULL;
+
+ udev_unref(udev_context);
+
return -1;
}
@@ -430,53 +265,24 @@ void usbip_vhci_driver_close()
if (!vhci_driver)
return;
- if (vhci_driver->cdev_list)
- dlist_destroy(vhci_driver->cdev_list);
-
- for (int i = 0; i < vhci_driver->nports; i++) {
- if (vhci_driver->idev[i].cdev_list)
- dlist_destroy(vhci_driver->idev[i].cdev_list);
- }
+ udev_device_unref(vhci_driver->hc_device);
- if (vhci_driver->hc_device)
- sysfs_close_device(vhci_driver->hc_device);
free(vhci_driver);
vhci_driver = NULL;
+
+ udev_unref(udev_context);
}
int usbip_vhci_refresh_device_list(void)
{
- if (vhci_driver->cdev_list)
- dlist_destroy(vhci_driver->cdev_list);
-
-
- for (int i = 0; i < vhci_driver->nports; i++) {
- if (vhci_driver->idev[i].cdev_list)
- dlist_destroy(vhci_driver->idev[i].cdev_list);
- }
-
- vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device));
- if (!vhci_driver->cdev_list)
- goto err;
-
- if (refresh_class_device_list())
- goto err;
if (refresh_imported_device_list())
goto err;
return 0;
err:
- if (vhci_driver->cdev_list)
- dlist_destroy(vhci_driver->cdev_list);
-
- for (int i = 0; i < vhci_driver->nports; i++) {
- if (vhci_driver->idev[i].cdev_list)
- dlist_destroy(vhci_driver->idev[i].cdev_list);
- }
-
dbg("failed to refresh device list");
return -1;
}
@@ -494,24 +300,24 @@ int usbip_vhci_get_free_port(void)
int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
uint32_t speed) {
- struct sysfs_attribute *attr_attach;
char buff[200]; /* what size should be ? */
+ char attach_attr_path[SYSFS_PATH_MAX];
+ char attr_attach[] = "attach";
+ const char *path;
int ret;
- attr_attach = sysfs_get_device_attr(vhci_driver->hc_device, "attach");
- if (!attr_attach) {
- dbg("sysfs_get_device_attr(\"attach\") failed: %s",
- vhci_driver->hc_device->name);
- return -1;
- }
-
- snprintf(buff, sizeof(buff), "%u %u %u %u",
+ snprintf(buff, sizeof(buff), "%u %d %u %u",
port, sockfd, devid, speed);
dbg("writing: %s", buff);
- ret = sysfs_write_attribute(attr_attach, buff, strlen(buff));
+ path = udev_device_get_syspath(vhci_driver->hc_device);
+ snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s",
+ path, attr_attach);
+ dbg("attach attribute path: %s", attach_attr_path);
+
+ ret = write_sysfs_attribute(attach_attr_path, buff, strlen(buff));
if (ret < 0) {
- dbg("sysfs_write_attribute failed");
+ dbg("write_sysfs_attribute failed");
return -1;
}
@@ -536,23 +342,23 @@ int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
int usbip_vhci_detach_device(uint8_t port)
{
- struct sysfs_attribute *attr_detach;
+ char detach_attr_path[SYSFS_PATH_MAX];
+ char attr_detach[] = "detach";
char buff[200]; /* what size should be ? */
+ const char *path;
int ret;
- attr_detach = sysfs_get_device_attr(vhci_driver->hc_device, "detach");
- if (!attr_detach) {
- dbg("sysfs_get_device_attr(\"detach\") failed: %s",
- vhci_driver->hc_device->name);
- return -1;
- }
-
snprintf(buff, sizeof(buff), "%u", port);
dbg("writing: %s", buff);
- ret = sysfs_write_attribute(attr_detach, buff, strlen(buff));
+ path = udev_device_get_syspath(vhci_driver->hc_device);
+ snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s",
+ path, attr_detach);
+ dbg("detach attribute path: %s", detach_attr_path);
+
+ ret = write_sysfs_attribute(detach_attr_path, buff, strlen(buff));
if (ret < 0) {
- dbg("sysfs_write_attribute failed");
+ dbg("write_sysfs_attribute failed");
return -1;
}
@@ -573,7 +379,8 @@ int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED)
return 0;
- ret = read_record(idev->port, host, serv, remote_busid);
+ ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv),
+ remote_busid);
if (ret) {
err("read_record");
read_record_error = 1;