2 * Copyright (C) 2000 Lennert Buytenhek
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <sys/fcntl.h>
27 #include "libbridge.h"
28 #include "libbridge_private.h"
31 /* Given two two character "0a" convert it to a byte */
32 static unsigned char getoctet(const char *cp)
34 char t[3] = { cp[0], cp[1], 0 };
35 return strtoul(t, NULL, 16);
38 static struct sysfs_directory *bridge_sysfs_directory(const char *devname,
41 struct sysfs_directory *sdir;
42 struct sysfs_class_device *dev;
43 char path[SYSFS_PATH_MAX];
49 dprintf("can't find class_net\n");
53 dev = sysfs_get_class_device(br_class_net, (char *) devname);
55 dprintf("can't find device %s in %s\n", devname, br_class_net->path);
59 snprintf(path, SYSFS_PATH_MAX, "%s/%s", dev->path, subname);
60 sdir = sysfs_open_directory(path);
62 dprintf("can't open directory: %s\n", path);
66 static void fetch_id(struct sysfs_directory *sdir, const char *name,
69 struct sysfs_attribute *attr;
71 memset(id, 0, sizeof(id));
72 attr = sysfs_get_directory_attribute(sdir, (char *) name);
74 dprintf("Can't find attribute %s/%s\n", sdir->path, name);
78 if (strlen(attr->value) < 17)
79 dprintf("Bad format for %s: '%s'\n", name, attr->value);
81 const char *cp = attr->value;
82 id->prio[0] = getoctet(cp); cp += 2;
83 id->prio[1] = getoctet(cp); cp += 3;
84 id->addr[0] = getoctet(cp); cp += 2;
85 id->addr[1] = getoctet(cp); cp += 2;
86 id->addr[2] = getoctet(cp); cp += 2;
87 id->addr[3] = getoctet(cp); cp += 2;
88 id->addr[4] = getoctet(cp); cp += 2;
89 id->addr[5] = getoctet(cp);
93 /* Get a time value out of sysfs */
94 static void fetch_tv(struct sysfs_directory *sdir, const char *name,
97 struct sysfs_attribute *attr
98 = sysfs_get_directory_attribute(sdir, (char *) name);
101 dprintf("Can't find attribute %s/%s\n", sdir->path, name);
102 memset(tv, 0, sizeof(tv));
106 __jiffies_to_tv(tv, strtoul(attr->value, NULL, 0));
109 /* Fetch an integer attribute out of sysfs. */
110 static int fetch_int(struct sysfs_directory *sdir, const char *name)
112 struct sysfs_attribute *attr
113 = sysfs_get_directory_attribute(sdir, (char *) name);
117 dprintf("Can't find attribute %s/%s\n", sdir->path, name);
119 val = strtol(attr->value, NULL, 0);
125 * Convert device name to an index in the list of ports in bridge.
127 * Old API does bridge operations as if ports were an array
128 * inside bridge structure.
130 static int get_portno(const char *brname, const char *ifname)
133 int ifindex = if_nametoindex(ifname);
134 int ifindices[MAX_PORTS];
135 unsigned long args[4] = { BRCTL_GET_PORT_LIST,
136 (unsigned long)ifindices, MAX_PORTS, 0 };
142 memset(ifindices, 0, sizeof(ifindices));
143 strncpy(ifr.ifr_name, brname, IFNAMSIZ);
144 ifr.ifr_data = (char *) &args;
146 if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
147 dprintf("get_portno: get ports of %s failed: %s\n",
148 brname, strerror(errno));
152 for (i = 0; i < MAX_PORTS; i++) {
153 if (ifindices[i] == ifindex)
157 dprintf("%s is not a in bridge %s\n", ifname, brname);
162 /* get information via ioctl */
163 static int old_get_bridge_info(const char *bridge, struct bridge_info *info)
166 struct __bridge_info i;
167 unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO,
168 (unsigned long) &i, 0, 0 };
170 memset(info, 0, sizeof(*info));
171 strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
172 ifr.ifr_data = (char *) &args;
174 if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
175 dprintf("%s: can't get info %s\n",
176 bridge, strerror(errno));
180 memcpy(&info->designated_root, &i.designated_root, 8);
181 memcpy(&info->bridge_id, &i.bridge_id, 8);
182 info->root_path_cost = i.root_path_cost;
183 info->root_port = i.root_port;
184 info->topology_change = i.topology_change;
185 info->topology_change_detected = i.topology_change_detected;
186 info->stp_enabled = i.stp_enabled;
187 __jiffies_to_tv(&info->max_age, i.max_age);
188 __jiffies_to_tv(&info->hello_time, i.hello_time);
189 __jiffies_to_tv(&info->forward_delay, i.forward_delay);
190 __jiffies_to_tv(&info->bridge_max_age, i.bridge_max_age);
191 __jiffies_to_tv(&info->bridge_hello_time, i.bridge_hello_time);
192 __jiffies_to_tv(&info->bridge_forward_delay, i.bridge_forward_delay);
193 __jiffies_to_tv(&info->ageing_time, i.ageing_time);
194 __jiffies_to_tv(&info->hello_timer_value, i.hello_timer_value);
195 __jiffies_to_tv(&info->tcn_timer_value, i.tcn_timer_value);
196 __jiffies_to_tv(&info->topology_change_timer_value,
197 i.topology_change_timer_value);
198 __jiffies_to_tv(&info->gc_timer_value, i.gc_timer_value);
204 * Get bridge parameters using either sysfs or old
207 int br_get_bridge_info(const char *bridge, struct bridge_info *info)
209 #ifndef HAVE_LIBSYSFS
210 return old_get_bridge_info(bridge, info);
212 struct sysfs_directory *sdir;
214 sdir = bridge_sysfs_directory(bridge, SYSFS_BRIDGE_ATTR);
216 return old_get_bridge_info(bridge,info);
218 memset(info, 0, sizeof(*info));
219 fetch_id(sdir, "root_id", &info->designated_root);
220 fetch_id(sdir, "bridge_id", &info->bridge_id);
221 info->root_path_cost = fetch_int(sdir, "root_path_cost");
222 fetch_tv(sdir, "max_age", &info->max_age);
223 fetch_tv(sdir, "hello_time", &info->hello_time);
224 fetch_tv(sdir, "forward_delay", &info->forward_delay);
225 fetch_tv(sdir, "max_age", &info->bridge_max_age);
226 fetch_tv(sdir, "hello_time", &info->bridge_hello_time);
227 fetch_tv(sdir, "forward_delay", &info->bridge_forward_delay);
228 fetch_tv(sdir, "ageing_time", &info->ageing_time);
229 fetch_tv(sdir, "hello_timer", &info->hello_timer_value);
230 fetch_tv(sdir, "tcn_timer", &info->tcn_timer_value);
231 fetch_tv(sdir, "topology_change_timer",
232 &info->topology_change_timer_value);;
233 fetch_tv(sdir, "gc_timer", &info->gc_timer_value);
235 info->root_port = fetch_int(sdir, "root_port");
236 info->stp_enabled = fetch_int(sdir, "stp_state");
237 info->topology_change = fetch_int(sdir, "topology_change");
238 info->topology_change_detected = fetch_int(sdir, "topology_change_detected");
239 sysfs_close_directory(sdir);
245 static int old_get_port_info(const char *brname, const char *port,
246 struct port_info *info)
248 struct __port_info i;
251 memset(info, 0, sizeof(*info));
253 index = get_portno(brname, port);
259 unsigned long args[4] = { BRCTL_GET_PORT_INFO,
260 (unsigned long) &i, index, 0 };
262 strncpy(ifr.ifr_name, brname, IFNAMSIZ);
263 ifr.ifr_data = (char *) &args;
265 if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
266 dprintf("old can't get port %s(%d) info %s\n",
267 brname, index, strerror(errno));
272 info->port_no = index;
273 memcpy(&info->designated_root, &i.designated_root, 8);
274 memcpy(&info->designated_bridge, &i.designated_bridge, 8);
275 info->port_id = i.port_id;
276 info->designated_port = i.designated_port;
277 info->path_cost = i.path_cost;
278 info->designated_cost = i.designated_cost;
279 info->state = i.state;
280 info->top_change_ack = i.top_change_ack;
281 info->config_pending = i.config_pending;
282 __jiffies_to_tv(&info->message_age_timer_value,
283 i.message_age_timer_value);
284 __jiffies_to_tv(&info->forward_delay_timer_value,
285 i.forward_delay_timer_value);
286 __jiffies_to_tv(&info->hold_timer_value, i.hold_timer_value);
291 * Get information about port on bridge.
293 int br_get_port_info(const char *brname, const char *port,
294 struct port_info *info)
296 #ifndef HAVE_LIBSYSFS
297 return old_get_port_info(brname, port, info);
299 struct sysfs_directory *sdir
300 = bridge_sysfs_directory(port, SYSFS_BRIDGE_PORT_ATTR);
303 return old_get_port_info(brname, port, info);
305 memset(info, 0, sizeof(*info));
306 fetch_id(sdir, "designated_root", &info->designated_root);
307 fetch_id(sdir, "designated_bridge", &info->designated_bridge);
308 info->port_no = fetch_int(sdir, "port_no");
309 info->port_id = fetch_int(sdir, "port_id");
310 info->designated_port = fetch_int(sdir, "designated_port");
311 info->path_cost = fetch_int(sdir, "path_cost");
312 info->designated_cost = fetch_int(sdir, "designated_cost");
313 info->state = fetch_int(sdir, "state");
314 info->top_change_ack = fetch_int(sdir, "change_ack");
315 info->config_pending = fetch_int(sdir, "config_pending");
316 fetch_tv(sdir, "message_age_timer",
317 &info->message_age_timer_value);
318 fetch_tv(sdir, "forward_delay_timer",
319 &info->forward_delay_timer_value);
320 fetch_tv(sdir, "hold_timer",
321 &info->hold_timer_value);
322 sysfs_close_directory(sdir);
329 static int br_set(const char *bridge, const char *name,
330 unsigned long value, unsigned long oldcode)
334 struct sysfs_directory *sdir;
336 sdir = bridge_sysfs_directory(bridge, SYSFS_BRIDGE_ATTR);
338 struct sysfs_attribute *attr;
340 sprintf(buf, "%ld", value);
342 attr = sysfs_get_directory_attribute(sdir, (char *) name);
344 ret = sysfs_write_attribute(attr, buf, strlen(buf));
349 sysfs_close_directory(sdir);
354 unsigned long args[4] = { oldcode, value, 0, 0 };
356 strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
357 ifr.ifr_data = (char *) &args;
358 ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
361 return ret < 0 ? errno : 0;
364 int br_set_bridge_forward_delay(const char *br, struct timeval *tv)
366 return br_set(br, "forward_delay", __tv_to_jiffies(tv),
367 BRCTL_SET_BRIDGE_FORWARD_DELAY);
370 int br_set_bridge_hello_time(const char *br, struct timeval *tv)
372 return br_set(br, "hello_time", __tv_to_jiffies(tv),
373 BRCTL_SET_BRIDGE_HELLO_TIME);
376 int br_set_bridge_max_age(const char *br, struct timeval *tv)
378 return br_set(br, "max_age", __tv_to_jiffies(tv),
379 BRCTL_SET_BRIDGE_MAX_AGE);
382 int br_set_ageing_time(const char *br, struct timeval *tv)
384 return br_set(br, "ageing_time", __tv_to_jiffies(tv),
385 BRCTL_SET_AGEING_TIME);
388 int br_set_stp_state(const char *br, int stp_state)
390 return br_set(br, "stp_state", stp_state, BRCTL_SET_BRIDGE_STP_STATE);
393 int br_set_bridge_priority(const char *br, int bridge_priority)
395 return br_set(br, "priority", bridge_priority,
396 BRCTL_SET_BRIDGE_PRIORITY);
399 static int port_set(const char *bridge, const char *ifname,
400 const char *name, unsigned long value,
401 unsigned long oldcode)
405 struct sysfs_directory *sdir;
407 sdir = bridge_sysfs_directory(ifname, SYSFS_BRIDGE_PORT_ATTR);
409 struct sysfs_attribute *attr;
412 sprintf(buf, "%ld", value);
414 attr = sysfs_get_directory_attribute(sdir, (char *) name);
416 ret = sysfs_write_attribute(attr, buf, strlen(buf));
421 sysfs_close_directory(sdir);
424 if ( (index = get_portno(bridge, ifname)) < 0)
429 unsigned long args[4] = { oldcode, index, value, 0 };
431 strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
432 ifr.ifr_data = (char *) &args;
433 ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
436 return ret < 0 ? errno : 0;
439 int br_set_port_priority(const char *bridge, const char *port, int priority)
441 return port_set(bridge, port, "priority", priority, BRCTL_SET_PORT_PRIORITY);
445 #define BRCTL_SET_PORT_SNOOPING 21
446 #define BRCTL_CLEAR_PORT_SNOOPING 22
447 #define BRCTL_ENABLE_SNOOPING 23
448 #define BRCTL_SHOW_SNOOPING 24
450 int br_set_port_snooping(const char *br, const char *port, const char *addr)
452 unsigned int iaddr[6];
453 unsigned char dest[6];
456 sscanf(addr, "%02x%02x%02x%02x%02x%02x", iaddr, iaddr+1, iaddr+2, iaddr+3, iaddr+4, iaddr+5);
457 for (i=0; i < 6; i++)
459 sscanf(addr+13, "%02x%02x%02x%02x%02x%02x", iaddr, iaddr+1, iaddr+2, iaddr+3, iaddr+4, iaddr+5);
460 for (i=0; i < 6; i++)
461 dest[i+6] = iaddr[i];
462 return port_set(br, port, "port_snooping", dest, BRCTL_SET_PORT_SNOOPING);
465 int br_clear_port_snooping(const char *br, const char *port, const char *addr)
467 unsigned int iaddr[6];
468 unsigned char dest[6];
471 sscanf(addr, "%02x%02x%02x%02x%02x%02x", iaddr, iaddr+1, iaddr+2, iaddr+3, iaddr+4, iaddr+5);
472 for (i=0; i < 6; i++)
474 sscanf(addr+13, "%02x%02x%02x%02x%02x%02x", iaddr, iaddr+1, iaddr+2, iaddr+3, iaddr+4, iaddr+5);
475 for (i=0; i < 6; i++)
476 dest[i+6] = iaddr[i];
477 return port_set(br, port, "port_snooping", dest, BRCTL_CLEAR_PORT_SNOOPING);
480 int br_show_port_snooping(const char *brname)
487 = { BRCTL_SHOW_SNOOPING, (unsigned long) _br };
489 strncpy(_br, brname, IFNAMSIZ);
490 ret = ioctl(br_socket_fd, SIOCSIFBR, arg);
493 return ret < 0 ? errno : 0;
496 int br_enable_port_snooping(int enable)
502 = { BRCTL_ENABLE_SNOOPING, 0, 0};
505 ret = ioctl(br_socket_fd, SIOCSIFBR, arg);
508 return ret < 0 ? errno : 0;
512 int br_set_path_cost(const char *bridge, const char *port, int cost)
514 return port_set(bridge, port, "path_cost", cost, BRCTL_SET_PATH_COST);
517 static inline void __copy_fdb(struct fdb_entry *ent,
518 const struct __fdb_entry *f)
520 memcpy(ent->mac_addr, f->mac_addr, 6);
521 ent->port_no = f->port_no;
522 ent->is_local = f->is_local;
523 __jiffies_to_tv(&ent->ageing_timer_value, f->ageing_timer_value);
526 int br_read_fdb(const char *bridge, struct fdb_entry *fdbs,
527 unsigned long offset, int num)
530 struct __fdb_entry fe[num];
532 struct sysfs_class_device *dev;
534 /* open /sys/class/net/brXXX/brforward */
536 (dev = sysfs_get_class_device(br_class_net, (char *) bridge))) {
537 char path[SYSFS_PATH_MAX];
539 snprintf(path, SYSFS_PATH_MAX, "%s/%s", dev->path,
541 fd = open(path, O_RDONLY, 0);
545 /* read records from file */
546 lseek(fd, offset*sizeof(struct __fdb_entry), SEEK_SET);
547 n = read(fd, fe, num*sizeof(struct __fdb_entry));
549 n /= sizeof(struct __fdb_entry);
553 /* old kernel, use ioctl */
554 unsigned long args[4] = { BRCTL_GET_FDB_ENTRIES,
560 strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
561 ifr.ifr_data = (char *) args;
564 n = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
566 /* table can change during ioctl processing */
567 if (n < 0 && errno == EAGAIN && ++retries < 10) {
573 for (i = 0; i < n; i++)
574 __copy_fdb(fdbs+i, fe+i);
583 int br_addstaticmac_fdb(char *brname, char *ifname, char *macp)
585 #define BRCTL_ADD_STATIC_MAC 19
587 int index, ret, addResult;
590 if ( (index = get_portno(brname, ifname)) < 0)
594 unsigned long args[4] = { BRCTL_ADD_STATIC_MAC, index, mac, 0 };
595 strncpy(ifr.ifr_name, brname, IFNAMSIZ);
596 ifr.ifr_data = (char *) &args;
597 ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
600 return ret < 0 ? errno : 0;