aboutsummaryrefslogtreecommitdiffstats
path: root/libbridge/libbridge_init.c
diff options
context:
space:
mode:
authorshemminger <shemminger>2004-05-21 17:41:48 +0000
committershemminger <shemminger>2004-05-21 17:41:48 +0000
commit328f4711bbc369dcccf8f8cfba2adf5dd0f74479 (patch)
tree8dd07660534f32407d249d0259e2e8f3a62f2ae5 /libbridge/libbridge_init.c
parent064717a4d7e47b47ba42e658abfd36acaa4a65d6 (diff)
downloadandroid_external_brctl-328f4711bbc369dcccf8f8cfba2adf5dd0f74479.tar.gz
android_external_brctl-328f4711bbc369dcccf8f8cfba2adf5dd0f74479.tar.bz2
android_external_brctl-328f4711bbc369dcccf8f8cfba2adf5dd0f74479.zip
New version of command and library that use sysfs.
Update make system to build with or without sysfs.
Diffstat (limited to 'libbridge/libbridge_init.c')
-rw-r--r--libbridge/libbridge_init.c353
1 files changed, 181 insertions, 172 deletions
diff --git a/libbridge/libbridge_init.c b/libbridge/libbridge_init.c
index d401250..2704f32 100644
--- a/libbridge/libbridge_init.c
+++ b/libbridge/libbridge_init.c
@@ -18,236 +18,245 @@
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include <errno.h>
#include <string.h>
-#include <sys/fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
+
#include "libbridge.h"
#include "libbridge_private.h"
-#define MAX_BRIDGES 1024 /* arbitrary */
-#define MAX_PORTS 4096
+#define MAX_BRIDGES 1024
+#define MAX_PORTS 1024
-int br_socket_fd;
-struct bridge *bridge_list;
+#define dprintf(fmt,arg...)
-static void __bridge_info_copy(struct bridge_info *info,
- const struct __bridge_info *i)
-{
- memcpy(&info->designated_root, &i->designated_root, 8);
- memcpy(&info->bridge_id, &i->bridge_id, 8);
- info->root_path_cost = i->root_path_cost;
- info->topology_change = i->topology_change;
- info->topology_change_detected = i->topology_change_detected;
- info->root_port = i->root_port;
- info->stp_enabled = i->stp_enabled;
- __jiffies_to_tv(&info->max_age, i->max_age);
- __jiffies_to_tv(&info->hello_time, i->hello_time);
- __jiffies_to_tv(&info->forward_delay, i->forward_delay);
- __jiffies_to_tv(&info->bridge_max_age, i->bridge_max_age);
- __jiffies_to_tv(&info->bridge_hello_time, i->bridge_hello_time);
- __jiffies_to_tv(&info->bridge_forward_delay, i->bridge_forward_delay);
- __jiffies_to_tv(&info->ageing_time, i->ageing_time);
- __jiffies_to_tv(&info->hello_timer_value, i->hello_timer_value);
- __jiffies_to_tv(&info->tcn_timer_value, i->tcn_timer_value);
- __jiffies_to_tv(&info->topology_change_timer_value,
- i->topology_change_timer_value);
- __jiffies_to_tv(&info->gc_timer_value, i->gc_timer_value);
-}
+int br_socket_fd = -1;
+struct sysfs_class *br_class_net;
-
-int br_get_bridge_info(const struct bridge *br, struct bridge_info *info)
+int br_init(void)
{
- struct __bridge_info i;
-
- if (br_device_ioctl(br, BRCTL_GET_BRIDGE_INFO,
- (unsigned long )&i, 0, 0) < 0) {
+ if ((br_socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return errno;
- }
- __bridge_info_copy(info, &i);
+ br_class_net = sysfs_open_class("net");
return 0;
}
-static void __port_info_copy(struct port_info *info,
- const struct __port_info *i)
+int br_refresh(void)
{
- memcpy(&info->designated_root, &i->designated_root, 8);
- memcpy(&info->designated_bridge, &i->designated_bridge, 8);
- info->port_id = i->port_id;
- info->designated_port = i->designated_port;
- info->path_cost = i->path_cost;
- info->designated_cost = i->designated_cost;
- info->state = i->state;
- info->top_change_ack = i->top_change_ack;
- info->config_pending = i->config_pending;
- __jiffies_to_tv(&info->message_age_timer_value,
- i->message_age_timer_value);
- __jiffies_to_tv(&info->forward_delay_timer_value,
- i->forward_delay_timer_value);
- __jiffies_to_tv(&info->hold_timer_value,
- i->hold_timer_value);
+ if (br_class_net) {
+ sysfs_close_class(br_class_net);
+ br_class_net = sysfs_open_class("net");
+ }
+
+ return 0;
}
-int br_get_port_info(const struct port *p, struct port_info *info)
+void br_shutdown(void)
{
- struct __port_info i;
+ sysfs_close_class(br_class_net);
+ br_class_net = NULL;
+ close(br_socket_fd);
+ br_socket_fd = -1;
+}
- if (br_device_ioctl(p->parent, BRCTL_GET_PORT_INFO,
- (unsigned long)&i, p->index, 0) < 0) {
- fprintf(stderr, "%s: can't get port %d info %s\n",
- p->parent->ifname, p->index, strerror(errno));
- return errno;
- }
- __port_info_copy(info, &i);
+#ifdef HAVE_LIBSYSFS
+/* If /sys/class/net/XXX/bridge exists then it must be a bridge */
+static int isbridge(const struct sysfs_class_device *dev)
+{
+ char path[SYSFS_PATH_MAX];
- return 0;
+ snprintf(path, sizeof(path), "%s/bridge", dev->path);
+ return !sysfs_path_is_dir(path);
}
-static void br_nuke_bridge(struct bridge *b)
+/*
+ * New interface uses sysfs to find bridges
+ */
+static int new_foreach_bridge(int (*iterator)(const char *name, void *),
+ void *arg)
{
- struct port *p, *n;
+ struct sysfs_class_device *dev;
+ struct dlist *devlist;
+ int count = 0;
- for (p = b->firstport; p; p = n) {
- n = p->next;
- free(p);
+ if (!br_class_net) {
+ dprintf("no class /sys/class/net\n");
+ return -EOPNOTSUPP;
}
- free(b);
-}
-
-static int br_make_port_list(struct bridge *br)
-{
- int i, cnt;
- struct port *p, **top;
- int *ifindices;
-
- ifindices = calloc(MAX_PORTS, sizeof(int));
- if (!ifindices)
- return -ENOMEM;
-
- cnt = br_device_ioctl(br, BRCTL_GET_PORT_LIST,
- (unsigned long)ifindices,
- MAX_PORTS, 0);
- if (cnt < 0)
- return errno;
+ devlist = sysfs_get_class_devices(br_class_net);
+ if (!devlist) {
+ fprintf(stderr, "Can't read devices from sysfs\n");
+ return -errno;
+ }
- if (cnt == 0)
- cnt = 256; /* old 2.4 compatiablity */
+ dlist_for_each_data(devlist, dev, struct sysfs_class_device) {
+ if (isbridge(dev)) {
+ ++count;
+ if (iterator(dev->name, arg))
+ break;
+ }
+ }
- top = &br->firstport;
- for (i = 0; i < cnt; i++) {
- if (!ifindices[i])
- continue;
+ return count;
+}
+#endif
- p = malloc(sizeof(struct port));
- if (!p)
- goto nomem;
+/*
+ * Old interface uses ioctl
+ */
+static int old_foreach_bridge(int (*iterator)(const char *, void *),
+ void *iarg)
+{
+ int i, ret=0, num;
+ char ifname[IFNAMSIZ];
+ int ifindices[MAX_BRIDGES];
+ unsigned long args[3] = { BRCTL_GET_BRIDGES,
+ (unsigned long)ifindices, MAX_BRIDGES };
- p->next = NULL;
- p->ifindex = ifindices[i];
- p->parent = br;
- p->index = i;
- *top = p;
- top = &p->next;
+ num = ioctl(br_socket_fd, SIOCGIFBR, args);
+ dprintf("old_foreach_bridge num=%d\n", num);
+ if (num < 0) {
+ fprintf(stderr, "Get bridge indices failed: %s\n",
+ strerror(errno));
+ return -errno;
}
- free(ifindices);
- return 0;
+ for (i = 0; i < num; i++) {
+ if (!if_indextoname(ifindices[i], ifname)) {
+ fprintf(stderr, "get find name for ifindex %d\n",
+ ifindices[i]);
+ return -errno;
+ }
- nomem:
- p = br->firstport;
- while (p) {
- struct port *n = p->next;
- free(p);
- p = n;
+ ++ret;
+ if(iterator(ifname, iarg))
+ break;
+
}
- br->firstport = NULL;
- free(ifindices);
- return -ENOMEM;
+ return ret;
+
}
-static struct bridge *new_bridge(int ifindex, const char *name)
+/*
+ * Go over all bridges and call iterator function.
+ * if iterator returns non-zero then stop.
+ */
+int br_foreach_bridge(int (*iterator)(const char *, void *),
+ void *arg)
{
- struct bridge *br;
-
- br = malloc(sizeof(struct bridge));
- if (br) {
- memset(br, 0, sizeof(struct bridge));
- br->ifindex = ifindex;
- strncpy(br->ifname, name, IFNAMSIZ);
- br->firstport = NULL;
- }
- return br;
+ int ret;
+#ifdef HAVE_LIBSYSFS
+
+ ret = new_foreach_bridge(iterator, arg);
+ if (ret <= 0)
+#endif
+ ret = old_foreach_bridge(iterator, arg);
+
+ return ret;
}
-static int br_make_bridge_list(void)
+/*
+ * Only used if sysfs is not available.
+ */
+static int old_foreach_port(const char *brname,
+ int (*iterator)(const char *br,
+ const char *port, int ind,
+ void *arg),
+ void *arg)
{
- struct bridge *br;
- int i, num;
- int ifindices[MAX_BRIDGES];
+ int i, err, count;
+ struct ifreq ifr;
char ifname[IFNAMSIZ];
+ int ifindices[MAX_PORTS];
+ unsigned long args[4] = { BRCTL_GET_PORT_LIST,
+ (unsigned long)ifindices, MAX_PORTS, 0 };
- num = br_get_br(BRCTL_GET_BRIDGES, (unsigned long)ifindices,
- MAX_BRIDGES);
- if (num < 0) {
- fprintf(stderr, "Get bridge indices failed: %s\n",
- strerror(errno));
- return errno;
- }
+ memset(ifindices, 0, sizeof(ifindices));
+ strncpy(ifr.ifr_name, brname, IFNAMSIZ);
+ ifr.ifr_data = (char *) &args;
- bridge_list = NULL;
- for (i = 0; i < num; i++) {
- if (!if_indextoname(ifindices[i], ifname))
- continue;
- br = new_bridge(ifindices[i], ifname);
- if (!br) /* ignore the problem could just be a race! */
+ err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+ if (err < 0)
+ return -errno;
+
+ count = 0;
+ for (i = 0; i < MAX_PORTS; i++) {
+ if (!ifindices[i])
continue;
- if ( br_make_port_list(br)) {
- free(br);
+ if (!if_indextoname(ifindices[i], ifname))
continue;
- }
- br->next = bridge_list;
- bridge_list = br;
+ ++count;
+ if (iterator(brname, ifname, ifindices[i], arg))
+ break;
}
- return 0;
+ return count;
}
+
-int br_init()
-{
- int err;
- if ((br_socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- return errno;
-
- if (br_get_version() != BRCTL_VERSION) {
- fprintf(stderr, "bridge utilities not compatiable with kernel version\n");
- exit(1);
+/*
+ * Iterate over all ports in bridge (using sysfs).
+ */
+int br_foreach_port(const char *brname,
+ int (*iterator)(const char *br, const char *port,
+ int ind, void *arg),
+ void *arg)
+{
+#ifndef HAVE_LIBSYSFS
+ return old_foreach_port(brname, iterator, arg);
+#else
+ struct sysfs_class_device *dev;
+ struct sysfs_directory *dir;
+ struct sysfs_link *plink;
+ struct dlist *links;
+ int err = 0;
+ char path[SYSFS_PATH_MAX];
+
+ if (!br_class_net ||
+ !(dev = sysfs_get_class_device(br_class_net, (char *) brname)))
+ return -ENODEV;
+
+ snprintf(path, sizeof(path), "%s/%s",
+ dev->path, SYSFS_BRIDGE_PORT_SUBDIR);
+
+ dir = sysfs_open_directory(path);
+ if (!dir) {
+ /* no /sys/class/net/ethX/brif subdirectory
+ * either: old kernel, or not really a bridge
+ */
+ err = old_foreach_port(brname, iterator, arg);
+ goto out1;
}
- if ((err = br_make_bridge_list()) != 0)
- return err;
+ links = sysfs_get_dir_links(dir);
+ if (!links) {
+ err = -ENOSYS;
+ goto out2;
+ }
- return 0;
-}
+ err = 0;
+ dlist_for_each_data(links, plink, struct sysfs_link) {
+ int ifindex = if_nametoindex(plink->name);
-int br_refresh()
-{
- struct bridge *b;
+ if (!ifindex) {
+ dprintf("can't find ifindex for %s\n", plink->name);
+ continue;
+ }
- b = bridge_list;
- while (b != NULL) {
- struct bridge *bnext;
+ ++err;
+ if (iterator(brname, plink->name, ifindex, arg))
+ break;
- bnext = b->next;
- br_nuke_bridge(b);
- b = bnext;
}
-
- return br_make_bridge_list();
+ out2:
+ sysfs_close_directory(dir);
+ out1:
+ return err;
+#endif
}