aboutsummaryrefslogtreecommitdiffstats
path: root/libbridge
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2013-01-04 21:55:57 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2013-01-04 21:55:57 -0800
commit1736fa987eb6b66b6eaedbc1cd3df4f48b873721 (patch)
treefab9a0cf0d8a8bfbabf131ae0e3209fed30f98b0 /libbridge
parent96abbc571f9645e14ba9d9faf549ebcb4df40036 (diff)
parent0315bd568b78bcae16e368cfce9311891b05e686 (diff)
downloadandroid_external_brctl-1736fa987eb6b66b6eaedbc1cd3df4f48b873721.tar.gz
android_external_brctl-1736fa987eb6b66b6eaedbc1cd3df4f48b873721.tar.bz2
android_external_brctl-1736fa987eb6b66b6eaedbc1cd3df4f48b873721.zip
Merge "Merge remote-tracking branch 'origin/caf/kernel-bridge-utils/master'"
Diffstat (limited to 'libbridge')
-rw-r--r--libbridge/.gitignore2
-rw-r--r--libbridge/Makefile.in41
-rw-r--r--libbridge/config.h.in79
-rw-r--r--libbridge/libbridge.h119
-rw-r--r--libbridge/libbridge_devif.c449
-rw-r--r--libbridge/libbridge_if.c117
-rw-r--r--libbridge/libbridge_init.c224
-rw-r--r--libbridge/libbridge_misc.c50
-rw-r--r--libbridge/libbridge_private.h56
9 files changed, 1137 insertions, 0 deletions
diff --git a/libbridge/.gitignore b/libbridge/.gitignore
new file mode 100644
index 0000000..f611548
--- /dev/null
+++ b/libbridge/.gitignore
@@ -0,0 +1,2 @@
+config.h
+stamp-h1
diff --git a/libbridge/Makefile.in b/libbridge/Makefile.in
new file mode 100644
index 0000000..20512c4
--- /dev/null
+++ b/libbridge/Makefile.in
@@ -0,0 +1,41 @@
+
+KERNEL_HEADERS=-I@KERNEL_HEADERS@
+
+AR=ar
+RANLIB=@RANLIB@
+
+CC=@CC@
+CFLAGS = -Wall -g $(KERNEL_HEADERS)
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+includedir=@includedir@
+libdir=@libdir@
+
+libbridge_SOURCES= \
+ libbridge_devif.c \
+ libbridge_if.c \
+ libbridge_init.c \
+ libbridge_misc.c
+
+libbridge_OBJECTS=$(libbridge_SOURCES:.c=.o)
+
+all: libbridge.a
+
+# At present there is no need for a bridge-utils-devel package
+install:
+
+
+clean:
+ rm -f *.o libbridge.a
+
+libbridge.a: $(libbridge_OBJECTS)
+ $(AR) rcs $@ $(libbridge_OBJECTS)
+ $(RANLIB) $@
+
+%.o: %.c libbridge.h libbridge_private.h
+ $(CC) $(CFLAGS) $(INCLUDE) -c $<
+
+libbridge_compat.o: libbridge_compat.c if_index.c
+ $(CC) $(CFLAGS) -c libbridge_compat.c
+
diff --git a/libbridge/config.h.in b/libbridge/config.h.in
new file mode 100644
index 0000000..22d1d7a
--- /dev/null
+++ b/libbridge/config.h.in
@@ -0,0 +1,79 @@
+/* libbridge/config.h.in. Generated from configure.in by autoheader. */
+
+/* Define to 1 if you have the `gethostname' function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define to 1 if you have the `if_indextoname' function. */
+#undef HAVE_IF_INDEXTONAME
+
+/* Define to 1 if you have the `if_nametoindex' function. */
+#undef HAVE_IF_NAMETOINDEX
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `socket' function. */
+#undef HAVE_SOCKET
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the `uname' function. */
+#undef HAVE_UNAME
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
diff --git a/libbridge/libbridge.h b/libbridge/libbridge.h
new file mode 100644
index 0000000..39964f2
--- /dev/null
+++ b/libbridge/libbridge.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _LIBBRIDGE_H
+#define _LIBBRIDGE_H
+
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_bridge.h>
+
+/* defined in net/if.h but that conflicts with linux/if.h... */
+extern unsigned int if_nametoindex (const char *__ifname);
+extern char *if_indextoname (unsigned int __ifindex, char *__ifname);
+
+
+struct bridge_id
+{
+ unsigned char prio[2];
+ unsigned char addr[6];
+};
+
+struct bridge_info
+{
+ struct bridge_id designated_root;
+ struct bridge_id bridge_id;
+ unsigned root_path_cost;
+ struct timeval max_age;
+ struct timeval hello_time;
+ struct timeval forward_delay;
+ struct timeval bridge_max_age;
+ struct timeval bridge_hello_time;
+ struct timeval bridge_forward_delay;
+ u_int16_t root_port;
+ unsigned char stp_enabled;
+ unsigned char topology_change;
+ unsigned char topology_change_detected;
+ struct timeval ageing_time;
+ struct timeval hello_timer_value;
+ struct timeval tcn_timer_value;
+ struct timeval topology_change_timer_value;
+ struct timeval gc_timer_value;
+};
+
+struct fdb_entry
+{
+ u_int8_t mac_addr[6];
+ u_int16_t port_no;
+ unsigned char is_local;
+ struct timeval ageing_timer_value;
+};
+
+struct port_info
+{
+ unsigned port_no;
+ struct bridge_id designated_root;
+ struct bridge_id designated_bridge;
+ u_int16_t port_id;
+ u_int16_t designated_port;
+ u_int8_t priority;
+ unsigned char top_change_ack;
+ unsigned char config_pending;
+ unsigned char state;
+ unsigned path_cost;
+ unsigned designated_cost;
+ struct timeval message_age_timer_value;
+ struct timeval forward_delay_timer_value;
+ struct timeval hold_timer_value;
+ unsigned char hairpin_mode;
+};
+
+extern int br_init(void);
+extern int br_refresh(void);
+extern void br_shutdown(void);
+
+extern int br_foreach_bridge(int (*iterator)(const char *brname, void *),
+ void *arg);
+extern int br_foreach_port(const char *brname,
+ int (*iterator)(const char *brname, const char *port,
+ void *arg ),
+ void *arg);
+extern const char *br_get_state_name(int state);
+
+extern int br_get_bridge_info(const char *br, struct bridge_info *info);
+extern int br_get_port_info(const char *brname, const char *port,
+ struct port_info *info);
+extern int br_add_bridge(const char *brname);
+extern int br_del_bridge(const char *brname);
+extern int br_add_interface(const char *br, const char *dev);
+extern int br_del_interface(const char *br, const char *dev);
+extern int br_set_bridge_forward_delay(const char *br, struct timeval *tv);
+extern int br_set_bridge_hello_time(const char *br, struct timeval *tv);
+extern int br_set_bridge_max_age(const char *br, struct timeval *tv);
+extern int br_set_ageing_time(const char *br, struct timeval *tv);
+extern int br_set_stp_state(const char *br, int stp_state);
+extern int br_set_bridge_priority(const char *br, int bridge_priority);
+extern int br_set_port_priority(const char *br, const char *p,
+ int port_priority);
+extern int br_set_path_cost(const char *br, const char *p,
+ int path_cost);
+extern int br_read_fdb(const char *br, struct fdb_entry *fdbs,
+ unsigned long skip, int num);
+extern int br_set_hairpin_mode(const char *bridge, const char *dev,
+ int hairpin_mode);
+#endif
diff --git a/libbridge/libbridge_devif.c b/libbridge/libbridge_devif.c
new file mode 100644
index 0000000..1e83925
--- /dev/null
+++ b/libbridge/libbridge_devif.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/fcntl.h>
+
+#include "libbridge.h"
+#include "libbridge_private.h"
+
+static FILE *fpopen(const char *dir, const char *name)
+{
+ char path[SYSFS_PATH_MAX];
+
+ snprintf(path, SYSFS_PATH_MAX, "%s/%s", dir, name);
+ return fopen(path, "r");
+}
+
+static void fetch_id(const char *dev, const char *name, struct bridge_id *id)
+{
+ FILE *f = fpopen(dev, name);
+
+ if (!f)
+ fprintf(stderr, "%s: %s\n", dev, strerror(errno));
+ else {
+ fscanf(f, "%2hhx%2hhx.%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
+ &id->prio[0], &id->prio[1],
+ &id->addr[0], &id->addr[1], &id->addr[2],
+ &id->addr[3], &id->addr[4], &id->addr[5]);
+ fclose(f);
+ }
+}
+
+/* Fetch an integer attribute out of sysfs. */
+static int fetch_int(const char *dev, const char *name)
+{
+ FILE *f = fpopen(dev, name);
+ int value = -1;
+
+ if (!f)
+ return 0;
+
+ fscanf(f, "%i", &value);
+ fclose(f);
+ return value;
+}
+
+/* Get a time value out of sysfs */
+static void fetch_tv(const char *dev, const char *name,
+ struct timeval *tv)
+{
+ __jiffies_to_tv(tv, fetch_int(dev, name));
+}
+
+/*
+ * Convert device name to an index in the list of ports in bridge.
+ *
+ * Old API does bridge operations as if ports were an array
+ * inside bridge structure.
+ */
+static int get_portno(const char *brname, const char *ifname)
+{
+ int i;
+ int ifindex = if_nametoindex(ifname);
+ int ifindices[MAX_PORTS];
+ unsigned long args[4] = { BRCTL_GET_PORT_LIST,
+ (unsigned long)ifindices, MAX_PORTS, 0 };
+ struct ifreq ifr;
+
+ if (ifindex <= 0)
+ goto error;
+
+ memset(ifindices, 0, sizeof(ifindices));
+ strncpy(ifr.ifr_name, brname, IFNAMSIZ);
+ ifr.ifr_data = (char *) &args;
+
+ if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
+ dprintf("get_portno: get ports of %s failed: %s\n",
+ brname, strerror(errno));
+ goto error;
+ }
+
+ for (i = 0; i < MAX_PORTS; i++) {
+ if (ifindices[i] == ifindex)
+ return i;
+ }
+
+ dprintf("%s is not a in bridge %s\n", ifname, brname);
+ error:
+ return -1;
+}
+
+/* get information via ioctl */
+static int old_get_bridge_info(const char *bridge, struct bridge_info *info)
+{
+ struct ifreq ifr;
+ struct __bridge_info i;
+ unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO,
+ (unsigned long) &i, 0, 0 };
+
+ memset(info, 0, sizeof(*info));
+ strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+ ifr.ifr_data = (char *) &args;
+
+ if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
+ dprintf("%s: can't get info %s\n",
+ bridge, strerror(errno));
+ return errno;
+ }
+
+ 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->root_port = i.root_port;
+ info->topology_change = i.topology_change;
+ info->topology_change_detected = i.topology_change_detected;
+ 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);
+
+ return 0;
+}
+
+/*
+ * Get bridge parameters using either sysfs or old
+ * ioctl.
+ */
+int br_get_bridge_info(const char *bridge, struct bridge_info *info)
+{
+ DIR *dir;
+ char path[SYSFS_PATH_MAX];
+
+ snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge", bridge);
+ dir = opendir(path);
+ if (dir == NULL) {
+ dprintf("path '%s' is not a directory\n", path);
+ goto fallback;
+ }
+
+ memset(info, 0, sizeof(*info));
+ fetch_id(path, "root_id", &info->designated_root);
+ fetch_id(path, "bridge_id", &info->bridge_id);
+ info->root_path_cost = fetch_int(path, "root_path_cost");
+ fetch_tv(path, "max_age", &info->max_age);
+ fetch_tv(path, "hello_time", &info->hello_time);
+ fetch_tv(path, "forward_delay", &info->forward_delay);
+ fetch_tv(path, "max_age", &info->bridge_max_age);
+ fetch_tv(path, "hello_time", &info->bridge_hello_time);
+ fetch_tv(path, "forward_delay", &info->bridge_forward_delay);
+ fetch_tv(path, "ageing_time", &info->ageing_time);
+ fetch_tv(path, "hello_timer", &info->hello_timer_value);
+ fetch_tv(path, "tcn_timer", &info->tcn_timer_value);
+ fetch_tv(path, "topology_change_timer",
+ &info->topology_change_timer_value);;
+ fetch_tv(path, "gc_timer", &info->gc_timer_value);
+
+ info->root_port = fetch_int(path, "root_port");
+ info->stp_enabled = fetch_int(path, "stp_state");
+ info->topology_change = fetch_int(path, "topology_change");
+ info->topology_change_detected = fetch_int(path, "topology_change_detected");
+
+ closedir(dir);
+ return 0;
+
+fallback:
+ return old_get_bridge_info(bridge, info);
+}
+
+static int old_get_port_info(const char *brname, const char *port,
+ struct port_info *info)
+{
+ struct __port_info i;
+ int index;
+
+ memset(info, 0, sizeof(*info));
+
+ index = get_portno(brname, port);
+ if (index < 0)
+ return errno;
+
+ else {
+ struct ifreq ifr;
+ unsigned long args[4] = { BRCTL_GET_PORT_INFO,
+ (unsigned long) &i, index, 0 };
+
+ strncpy(ifr.ifr_name, brname, IFNAMSIZ);
+ ifr.ifr_data = (char *) &args;
+
+ if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
+ dprintf("old can't get port %s(%d) info %s\n",
+ brname, index, strerror(errno));
+ return errno;
+ }
+ }
+
+ info->port_no = index;
+ 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);
+ info->hairpin_mode = 0;
+ return 0;
+}
+
+/*
+ * Get information about port on bridge.
+ */
+int br_get_port_info(const char *brname, const char *port,
+ struct port_info *info)
+{
+ DIR *d;
+ char path[SYSFS_PATH_MAX];
+
+ snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport", port);
+ d = opendir(path);
+ if (!d)
+ goto fallback;
+
+ memset(info, 0, sizeof(*info));
+
+ fetch_id(path, "designated_root", &info->designated_root);
+ fetch_id(path, "designated_bridge", &info->designated_bridge);
+ info->port_no = fetch_int(path, "port_no");
+ info->port_id = fetch_int(path, "port_id");
+ info->designated_port = fetch_int(path, "designated_port");
+ info->path_cost = fetch_int(path, "path_cost");
+ info->designated_cost = fetch_int(path, "designated_cost");
+ info->state = fetch_int(path, "state");
+ info->top_change_ack = fetch_int(path, "change_ack");
+ info->config_pending = fetch_int(path, "config_pending");
+ fetch_tv(path, "message_age_timer", &info->message_age_timer_value);
+ fetch_tv(path, "forward_delay_timer", &info->forward_delay_timer_value);
+ fetch_tv(path, "hold_timer", &info->hold_timer_value);
+ info->hairpin_mode = fetch_int(path, "hairpin_mode");
+
+ closedir(d);
+
+ return 0;
+fallback:
+ return old_get_port_info(brname, port, info);
+}
+
+static int set_sysfs(const char *path, unsigned long value)
+{
+ int fd, ret = 0, cc;
+ char buf[32];
+
+ fd = open(path, O_WRONLY);
+ if (fd < 0)
+ return -1;
+
+ cc = snprintf(buf, sizeof(buf), "%lu\n", value);
+ if (write(fd, buf, cc) < 0)
+ ret = -1;
+ close(fd);
+
+ return ret;
+}
+
+
+static int br_set(const char *bridge, const char *name,
+ unsigned long value, unsigned long oldcode)
+{
+ int ret;
+ char path[SYSFS_PATH_MAX];
+
+ snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge/%s",
+ bridge, name);
+
+ if ((ret = set_sysfs(path, value)) < 0) {
+ /* fallback to old ioctl */
+ 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;
+}
+
+int br_set_bridge_forward_delay(const char *br, struct timeval *tv)
+{
+ return br_set(br, "forward_delay", __tv_to_jiffies(tv),
+ BRCTL_SET_BRIDGE_FORWARD_DELAY);
+}
+
+int br_set_bridge_hello_time(const char *br, struct timeval *tv)
+{
+ return br_set(br, "hello_time", __tv_to_jiffies(tv),
+ BRCTL_SET_BRIDGE_HELLO_TIME);
+}
+
+int br_set_bridge_max_age(const char *br, struct timeval *tv)
+{
+ return br_set(br, "max_age", __tv_to_jiffies(tv),
+ BRCTL_SET_BRIDGE_MAX_AGE);
+}
+
+int br_set_ageing_time(const char *br, struct timeval *tv)
+{
+ return br_set(br, "ageing_time", __tv_to_jiffies(tv),
+ BRCTL_SET_AGEING_TIME);
+}
+
+int br_set_stp_state(const char *br, int stp_state)
+{
+ return br_set(br, "stp_state", stp_state, BRCTL_SET_BRIDGE_STP_STATE);
+}
+
+int br_set_bridge_priority(const char *br, int bridge_priority)
+{
+ return br_set(br, "priority", bridge_priority,
+ BRCTL_SET_BRIDGE_PRIORITY);
+}
+
+static int port_set(const char *bridge, const char *ifname,
+ const char *name, unsigned long value,
+ unsigned long oldcode)
+{
+ int ret;
+ char path[SYSFS_PATH_MAX];
+
+ snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport/%s", ifname, name);
+
+ if ((ret = set_sysfs(path, value)) < 0) {
+ int index = get_portno(bridge, ifname);
+
+ if (index < 0)
+ ret = index;
+ else {
+ struct ifreq ifr;
+ unsigned long args[4] = { oldcode, index, value, 0 };
+
+ strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+ ifr.ifr_data = (char *) &args;
+ ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+ }
+ }
+
+ return ret < 0 ? errno : 0;
+}
+
+int br_set_port_priority(const char *bridge, const char *port, int priority)
+{
+ return port_set(bridge, port, "priority", priority, BRCTL_SET_PORT_PRIORITY);
+}
+
+int br_set_path_cost(const char *bridge, const char *port, int cost)
+{
+ return port_set(bridge, port, "path_cost", cost, BRCTL_SET_PATH_COST);
+}
+
+int br_set_hairpin_mode(const char *bridge, const char *port, int hairpin_mode)
+{
+ return port_set(bridge, port, "hairpin_mode", hairpin_mode, 0);
+}
+
+static inline void __copy_fdb(struct fdb_entry *ent,
+ const struct __fdb_entry *f)
+{
+ memcpy(ent->mac_addr, f->mac_addr, 6);
+ ent->port_no = f->port_no;
+ ent->is_local = f->is_local;
+ __jiffies_to_tv(&ent->ageing_timer_value, f->ageing_timer_value);
+}
+
+int br_read_fdb(const char *bridge, struct fdb_entry *fdbs,
+ unsigned long offset, int num)
+{
+ FILE *f;
+ int i, n;
+ struct __fdb_entry fe[num];
+ char path[SYSFS_PATH_MAX];
+
+ /* open /sys/class/net/brXXX/brforward */
+ snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brforward", bridge);
+ f = fopen(path, "r");
+ if (f) {
+ fseek(f, offset*sizeof(struct __fdb_entry), SEEK_SET);
+ n = fread(fe, sizeof(struct __fdb_entry), num, f);
+ fclose(f);
+ } else {
+ /* old kernel, use ioctl */
+ unsigned long args[4] = { BRCTL_GET_FDB_ENTRIES,
+ (unsigned long) fe,
+ num, offset };
+ struct ifreq ifr;
+ int retries = 0;
+
+ strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+ ifr.ifr_data = (char *) args;
+
+ retry:
+ n = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+
+ /* table can change during ioctl processing */
+ if (n < 0 && errno == EAGAIN && ++retries < 10) {
+ sleep(0);
+ goto retry;
+ }
+ }
+
+ for (i = 0; i < n; i++)
+ __copy_fdb(fdbs+i, fe+i);
+
+ return n;
+}
diff --git a/libbridge/libbridge_if.c b/libbridge/libbridge_if.c
new file mode 100644
index 0000000..77d3f8a
--- /dev/null
+++ b/libbridge/libbridge_if.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+
+#include "libbridge.h"
+#include "libbridge_private.h"
+
+
+int br_add_bridge(const char *brname)
+{
+ int ret;
+
+#ifdef SIOCBRADDBR
+ ret = ioctl(br_socket_fd, SIOCBRADDBR, brname);
+ if (ret < 0)
+#endif
+ {
+ char _br[IFNAMSIZ];
+ unsigned long arg[3]
+ = { BRCTL_ADD_BRIDGE, (unsigned long) _br };
+
+ strncpy(_br, brname, IFNAMSIZ);
+ ret = ioctl(br_socket_fd, SIOCSIFBR, arg);
+ }
+
+ return ret < 0 ? errno : 0;
+}
+
+int br_del_bridge(const char *brname)
+{
+ int ret;
+
+#ifdef SIOCBRDELBR
+ ret = ioctl(br_socket_fd, SIOCBRDELBR, brname);
+ if (ret < 0)
+#endif
+ {
+ char _br[IFNAMSIZ];
+ unsigned long arg[3]
+ = { BRCTL_DEL_BRIDGE, (unsigned long) _br };
+
+ strncpy(_br, brname, IFNAMSIZ);
+ ret = ioctl(br_socket_fd, SIOCSIFBR, arg);
+ }
+ return ret < 0 ? errno : 0;
+}
+
+int br_add_interface(const char *bridge, const char *dev)
+{
+ struct ifreq ifr;
+ int err;
+ int ifindex = if_nametoindex(dev);
+
+ if (ifindex == 0)
+ return ENODEV;
+
+ strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+#ifdef SIOCBRADDIF
+ ifr.ifr_ifindex = ifindex;
+ err = ioctl(br_socket_fd, SIOCBRADDIF, &ifr);
+ if (err < 0)
+#endif
+ {
+ unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 };
+
+ ifr.ifr_data = (char *) args;
+ err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+ }
+
+ return err < 0 ? errno : 0;
+}
+
+int br_del_interface(const char *bridge, const char *dev)
+{
+ struct ifreq ifr;
+ int err;
+ int ifindex = if_nametoindex(dev);
+
+ if (ifindex == 0)
+ return ENODEV;
+
+ strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+#ifdef SIOCBRDELIF
+ ifr.ifr_ifindex = ifindex;
+ err = ioctl(br_socket_fd, SIOCBRDELIF, &ifr);
+ if (err < 0)
+#endif
+ {
+ unsigned long args[4] = { BRCTL_DEL_IF, ifindex, 0, 0 };
+
+ ifr.ifr_data = (char *) args;
+ err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+ }
+
+ return err < 0 ? errno : 0;
+}
diff --git a/libbridge/libbridge_init.c b/libbridge/libbridge_init.c
new file mode 100644
index 0000000..f3a551e
--- /dev/null
+++ b/libbridge/libbridge_init.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "libbridge.h"
+#include "libbridge_private.h"
+
+int br_socket_fd = -1;
+
+int br_init(void)
+{
+ if ((br_socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
+ return errno;
+ return 0;
+}
+
+void br_shutdown(void)
+{
+ close(br_socket_fd);
+ br_socket_fd = -1;
+}
+
+/* If /sys/class/net/XXX/bridge exists then it must be a bridge */
+static int isbridge(const struct dirent *entry)
+{
+ char path[SYSFS_PATH_MAX];
+ struct stat st;
+ int ret, saved_errno;
+
+ if (entry->d_name[0] == '.'
+ && (entry->d_name[1] == '\0'
+ || (entry->d_name[1] == '.'
+ && entry->d_name[2] == '\0')))
+ return 0;
+
+ snprintf(path, SYSFS_PATH_MAX,
+ SYSFS_CLASS_NET "%s/bridge", entry->d_name);
+
+ /* Workaround old glibc breakage.
+ If errno is set, then it fails scandir! */
+ saved_errno = errno;
+ ret = (stat(path, &st) == 0 && S_ISDIR(st.st_mode));
+ errno = saved_errno;
+
+ return ret;
+}
+
+/*
+ * New interface uses sysfs to find bridges
+ */
+static int new_foreach_bridge(int (*iterator)(const char *name, void *),
+ void *arg)
+{
+ struct dirent **namelist;
+ int i, count = 0;
+
+ count = scandir(SYSFS_CLASS_NET, &namelist, isbridge, alphasort);
+ if (count < 0)
+ return -1;
+
+ for (i = 0; i < count; i++) {
+ if (iterator(namelist[i]->d_name, arg))
+ break;
+ }
+
+ for (i = 0; i < count; i++)
+ free(namelist[i]);
+ free(namelist);
+
+ return count;
+}
+
+/*
+ * 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 };
+
+ num = ioctl(br_socket_fd, SIOCGIFBR, args);
+ if (num < 0) {
+ dprintf("Get bridge indices failed: %s\n",
+ strerror(errno));
+ return -errno;
+ }
+
+ for (i = 0; i < num; i++) {
+ if (!if_indextoname(ifindices[i], ifname)) {
+ dprintf("get find name for ifindex %d\n",
+ ifindices[i]);
+ return -errno;
+ }
+
+ ++ret;
+ if(iterator(ifname, iarg))
+ break;
+
+ }
+
+ return ret;
+
+}
+
+/*
+ * 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)
+{
+ int ret;
+
+ ret = new_foreach_bridge(iterator, arg);
+ if (ret <= 0)
+ ret = old_foreach_bridge(iterator, arg);
+
+ return ret;
+}
+
+/*
+ * Only used if sysfs is not available.
+ */
+static int old_foreach_port(const char *brname,
+ int (*iterator)(const char *br, const char *port,
+ void *arg),
+ void *arg)
+{
+ 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 };
+
+ memset(ifindices, 0, sizeof(ifindices));
+ strncpy(ifr.ifr_name, brname, IFNAMSIZ);
+ ifr.ifr_data = (char *) &args;
+
+ err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+ if (err < 0) {
+ dprintf("list ports for bridge:'%s' failed: %s\n",
+ brname, strerror(errno));
+ return -errno;
+ }
+
+ count = 0;
+ for (i = 0; i < MAX_PORTS; i++) {
+ if (!ifindices[i])
+ continue;
+
+ if (!if_indextoname(ifindices[i], ifname)) {
+ dprintf("can't find name for ifindex:%d\n",
+ ifindices[i]);
+ continue;
+ }
+
+ ++count;
+ if (iterator(brname, ifname, arg))
+ break;
+ }
+
+ return count;
+}
+
+/*
+ * Iterate over all ports in bridge (using sysfs).
+ */
+int br_foreach_port(const char *brname,
+ int (*iterator)(const char *br, const char *port, void *arg),
+ void *arg)
+{
+ int i, count;
+ struct dirent **namelist;
+ char path[SYSFS_PATH_MAX];
+
+ snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brif", brname);
+ count = scandir(path, &namelist, 0, alphasort);
+ if (count < 0)
+ return old_foreach_port(brname, iterator, arg);
+
+ for (i = 0; i < count; i++) {
+ if (namelist[i]->d_name[0] == '.'
+ && (namelist[i]->d_name[1] == '\0'
+ || (namelist[i]->d_name[1] == '.'
+ && namelist[i]->d_name[2] == '\0')))
+ continue;
+
+ if (iterator(brname, namelist[i]->d_name, arg))
+ break;
+ }
+ for (i = 0; i < count; i++)
+ free(namelist[i]);
+ free(namelist);
+
+ return count;
+}
diff --git a/libbridge/libbridge_misc.c b/libbridge/libbridge_misc.c
new file mode 100644
index 0000000..5791638
--- /dev/null
+++ b/libbridge/libbridge_misc.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <asm/param.h>
+#include "libbridge.h"
+#include "libbridge_private.h"
+
+
+static const char *state_names[5] = {
+ [BR_STATE_DISABLED] = "disabled",
+ [BR_STATE_LISTENING] = "listening",
+ [BR_STATE_LEARNING] = "learning",
+ [BR_STATE_FORWARDING] = "forwarding",
+ [BR_STATE_BLOCKING] = "blocking",
+};
+
+const char *br_get_state_name(int state)
+{
+ if (state >= 0 && state <= 4)
+ return state_names[state];
+
+ return "<INVALID STATE>";
+}
+
+int __br_hz_internal;
+
+int __get_hz(void)
+{
+ const char * s = getenv("HZ");
+ return s ? atoi(s) : HZ;
+}
diff --git a/libbridge/libbridge_private.h b/libbridge/libbridge_private.h
new file mode 100644
index 0000000..99a511d
--- /dev/null
+++ b/libbridge/libbridge_private.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _LIBBRIDGE_PRIVATE_H
+#define _LIBBRIDGE_PRIVATE_H
+
+#include "config.h"
+
+#include <linux/sockios.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <linux/if_bridge.h>
+
+#define MAX_BRIDGES 1024
+#define MAX_PORTS 1024
+
+#define SYSFS_CLASS_NET "/sys/class/net/"
+#define SYSFS_PATH_MAX 256
+
+#define dprintf(fmt,arg...)
+
+extern int br_socket_fd;
+
+static inline unsigned long __tv_to_jiffies(const struct timeval *tv)
+{
+ unsigned long long jif;
+
+ jif = 1000000ULL * tv->tv_sec + tv->tv_usec;
+
+ return jif/10000;
+}
+
+static inline void __jiffies_to_tv(struct timeval *tv, unsigned long jiffies)
+{
+ unsigned long long tvusec;
+
+ tvusec = 10000ULL*jiffies;
+ tv->tv_sec = tvusec/1000000;
+ tv->tv_usec = tvusec - 1000000 * tv->tv_sec;
+}
+#endif