/* * Get bridge parameters using either sysfs or old * ioctl. */ static int br_get_bridge_info(const char *bridge, struct bridge_info *info) { #ifdef HAVE_LIBSYSFS struct sysfs_class_device *dev; char path[SYSFS_PATH_MAX]; if (!br_class_net) goto fallback; dev = sysfs_get_class_device(br_class_net, bridge); if (!dev) { dprintf("get_class_device '%s' failed\n", bridge); goto fallback; } snprintf(path, SYSFS_PATH_MAX, "%s/bridge", dev->path); if (sysfs_path_is_dir(path)) { dprintf("path '%s' is not a directory\n", path); sysfs_close_class_device(dev); goto fallback; } memset(info, 0, sizeof(*info)); fetch_id(dev, BRIDGEATTR("root_id"), &info->designated_root); fetch_id(dev, BRIDGEATTR("bridge_id"), &info->bridge_id); info->root_path_cost = fetch_int(dev, BRIDGEATTR("root_path_cost")); fetch_tv(dev, BRIDGEATTR("max_age"), &info->max_age); fetch_tv(dev, BRIDGEATTR("hello_time"), &info->hello_time); fetch_tv(dev, BRIDGEATTR("forward_delay"), &info->forward_delay); fetch_tv(dev, BRIDGEATTR("max_age"), &info->bridge_max_age); fetch_tv(dev, BRIDGEATTR("hello_time"), &info->bridge_hello_time); fetch_tv(dev, BRIDGEATTR("forward_delay"), &info->bridge_forward_delay); fetch_tv(dev, BRIDGEATTR("ageing_time"), &info->ageing_time); fetch_tv(dev, BRIDGEATTR("hello_timer"), &info->hello_timer_value); fetch_tv(dev, BRIDGEATTR("tcn_timer"), &info->tcn_timer_value); fetch_tv(dev, BRIDGEATTR("topology_change_timer"), &info->topology_change_timer_value);; fetch_tv(dev, BRIDGEATTR("gc_timer"), &info->gc_timer_value); info->root_port = fetch_int(dev, BRIDGEATTR("root_port")); info->stp_enabled = fetch_int(dev, BRIDGEATTR("stp_state")); info->topology_change = fetch_int(dev, BRIDGEATTR("topology_change")); info->topology_change_detected = fetch_int(dev, BRIDGEATTR ("topology_change_detected")); sysfs_close_class_device(dev); return 0; fallback: #endif return old_get_bridge_info(bridge, info); }
/** * sysfs_open_class_device_path: Opens and populates class device * @path: path to class device. * returns struct sysfs_class_device with success and NULL with error. */ struct sysfs_class_device *sysfs_open_class_device_path(const char *path) { struct sysfs_class_device *cdev; char temp_path[SYSFS_PATH_MAX]; if (!path) { errno = EINVAL; return NULL; } /* * Post linux-2.6.14 driver model supports nested classes with * links to the nested hierarchy at /sys/class/xxx/. Check for * a link to the actual class device if a directory isn't found */ if (sysfs_path_is_dir(path)) { dprintf("%s: Directory not found, checking for a link\n", path); if (!sysfs_path_is_link(path)) { if (sysfs_get_link(path, temp_path, SYSFS_PATH_MAX)) { dprintf("Error retrieving link at %s\n", path); return NULL; } } else { dprintf("%s is not a valid class device path\n", path); return NULL; } } else safestrcpy(temp_path, path); cdev = alloc_class_device(); if (!cdev) { dprintf("calloc failed\n"); return NULL; } if (sysfs_get_name_from_path(temp_path, cdev->name, SYSFS_NAME_LEN)) { errno = EINVAL; dprintf("Error getting class device name\n"); sysfs_close_class_device(cdev); return NULL; } safestrcpy(cdev->path, temp_path); if (sysfs_remove_trailing_slash(cdev->path)) { dprintf("Invalid path to class device %s\n", cdev->path); sysfs_close_class_device(cdev); return NULL; } set_classdev_classname(cdev); return cdev; }
static int br_set(const char *bridge, const char *name, unsigned long value, unsigned long oldcode) { int ret = -1; #ifdef HAVE_LIBSYSFS struct sysfs_class_device *dev; dev = sysfs_get_class_device(br_class_net, bridge); if (dev) { struct sysfs_attribute *attr; char buf[32]; char path[SYSFS_PATH_MAX]; snprintf(buf, sizeof(buf), "%ld\n", value); snprintf(path, SYSFS_PATH_MAX, "%s/bridge/%s", dev->path, name); attr = sysfs_open_attribute(path); if (attr) { ret = sysfs_write_attribute(attr, buf, strlen(buf)); sysfs_close_attribute(attr); } sysfs_close_class_device(dev); } else #endif { struct ifreq ifr; unsigned long args[4] = { oldcode, value, 0, 0 }; strncpy(ifr.ifr_name, bridge, IFNAMSIZ); ifr.ifr_data = (char *)&args; ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); } return ret < 0 ? errno : 0; }
/** * sysfs_close_class_device: closes a single class device. * @dev: class device to close. */ void sysfs_close_class_device(struct sysfs_class_device *dev) { if (dev) { if (dev->parent) sysfs_close_class_device(dev->parent); if (dev->sysdevice) sysfs_close_device(dev->sysdevice); if (dev->attrlist) dlist_destroy(dev->attrlist); free(dev); } }
static void sysfs_close_cls_dev(void *dev) { sysfs_close_class_device((struct sysfs_class_device *)dev); }