bridge-utils update to 1.5
[tomato.git] / release / src / router / bridge / libbridge / libbridge_devif.c
blobaa8bc3607fca610f2ec9903cfc9162c4e6c87c08
1 /*
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.
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <dirent.h>
26 #include <sys/fcntl.h>
28 #include "libbridge.h"
29 #include "libbridge_private.h"
31 static FILE *fpopen(const char *dir, const char *name)
33 char path[SYSFS_PATH_MAX];
35 snprintf(path, SYSFS_PATH_MAX, "%s/%s", dir, name);
36 return fopen(path, "r");
39 static void fetch_id(const char *dev, const char *name, struct bridge_id *id)
41 FILE *f = fpopen(dev, name);
43 if (!f)
44 fprintf(stderr, "%s: %s\n", dev, strerror(errno));
45 else {
46 fscanf(f, "%2hhx%2hhx.%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
47 &id->prio[0], &id->prio[1],
48 &id->addr[0], &id->addr[1], &id->addr[2],
49 &id->addr[3], &id->addr[4], &id->addr[5]);
50 fclose(f);
54 /* Fetch an integer attribute out of sysfs. */
55 static int fetch_int(const char *dev, const char *name)
57 FILE *f = fpopen(dev, name);
58 int value = -1;
60 if (!f)
61 return 0;
63 fscanf(f, "%i", &value);
64 fclose(f);
65 return value;
68 /* Get a time value out of sysfs */
69 static void fetch_tv(const char *dev, const char *name,
70 struct timeval *tv)
72 __jiffies_to_tv(tv, fetch_int(dev, name));
76 * Convert device name to an index in the list of ports in bridge.
78 * Old API does bridge operations as if ports were an array
79 * inside bridge structure.
81 static int get_portno(const char *brname, const char *ifname)
83 int i;
84 int ifindex = if_nametoindex(ifname);
85 int ifindices[MAX_PORTS];
86 unsigned long args[4] = { BRCTL_GET_PORT_LIST,
87 (unsigned long)ifindices, MAX_PORTS, 0 };
88 struct ifreq ifr;
90 if (ifindex <= 0)
91 goto error;
93 memset(ifindices, 0, sizeof(ifindices));
94 strncpy(ifr.ifr_name, brname, IFNAMSIZ);
95 ifr.ifr_data = (char *) &args;
97 if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
98 dprintf("get_portno: get ports of %s failed: %s\n",
99 brname, strerror(errno));
100 goto error;
103 for (i = 0; i < MAX_PORTS; i++) {
104 if (ifindices[i] == ifindex)
105 return i;
108 dprintf("%s is not a in bridge %s\n", ifname, brname);
109 error:
110 return -1;
113 /* get information via ioctl */
114 static int old_get_bridge_info(const char *bridge, struct bridge_info *info)
116 struct ifreq ifr;
117 struct __bridge_info i;
118 unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO,
119 (unsigned long) &i, 0, 0 };
121 memset(info, 0, sizeof(*info));
122 strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
123 ifr.ifr_data = (char *) &args;
125 if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
126 dprintf("%s: can't get info %s\n",
127 bridge, strerror(errno));
128 return errno;
131 memcpy(&info->designated_root, &i.designated_root, 8);
132 memcpy(&info->bridge_id, &i.bridge_id, 8);
133 info->root_path_cost = i.root_path_cost;
134 info->root_port = i.root_port;
135 info->topology_change = i.topology_change;
136 info->topology_change_detected = i.topology_change_detected;
137 info->stp_enabled = i.stp_enabled;
138 __jiffies_to_tv(&info->max_age, i.max_age);
139 __jiffies_to_tv(&info->hello_time, i.hello_time);
140 __jiffies_to_tv(&info->forward_delay, i.forward_delay);
141 __jiffies_to_tv(&info->bridge_max_age, i.bridge_max_age);
142 __jiffies_to_tv(&info->bridge_hello_time, i.bridge_hello_time);
143 __jiffies_to_tv(&info->bridge_forward_delay, i.bridge_forward_delay);
144 __jiffies_to_tv(&info->ageing_time, i.ageing_time);
145 __jiffies_to_tv(&info->hello_timer_value, i.hello_timer_value);
146 __jiffies_to_tv(&info->tcn_timer_value, i.tcn_timer_value);
147 __jiffies_to_tv(&info->topology_change_timer_value,
148 i.topology_change_timer_value);
149 __jiffies_to_tv(&info->gc_timer_value, i.gc_timer_value);
151 return 0;
155 * Get bridge parameters using either sysfs or old
156 * ioctl.
158 int br_get_bridge_info(const char *bridge, struct bridge_info *info)
160 DIR *dir;
161 char path[SYSFS_PATH_MAX];
163 snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge", bridge);
164 dir = opendir(path);
165 if (dir == NULL) {
166 dprintf("path '%s' is not a directory\n", path);
167 goto fallback;
170 memset(info, 0, sizeof(*info));
171 fetch_id(path, "root_id", &info->designated_root);
172 fetch_id(path, "bridge_id", &info->bridge_id);
173 info->root_path_cost = fetch_int(path, "root_path_cost");
174 fetch_tv(path, "max_age", &info->max_age);
175 fetch_tv(path, "hello_time", &info->hello_time);
176 fetch_tv(path, "forward_delay", &info->forward_delay);
177 fetch_tv(path, "max_age", &info->bridge_max_age);
178 fetch_tv(path, "hello_time", &info->bridge_hello_time);
179 fetch_tv(path, "forward_delay", &info->bridge_forward_delay);
180 fetch_tv(path, "ageing_time", &info->ageing_time);
181 fetch_tv(path, "hello_timer", &info->hello_timer_value);
182 fetch_tv(path, "tcn_timer", &info->tcn_timer_value);
183 fetch_tv(path, "topology_change_timer",
184 &info->topology_change_timer_value);;
185 fetch_tv(path, "gc_timer", &info->gc_timer_value);
187 info->root_port = fetch_int(path, "root_port");
188 info->stp_enabled = fetch_int(path, "stp_state");
189 info->topology_change = fetch_int(path, "topology_change");
190 info->topology_change_detected = fetch_int(path, "topology_change_detected");
192 closedir(dir);
193 return 0;
195 fallback:
196 return old_get_bridge_info(bridge, info);
199 static int old_get_port_info(const char *brname, const char *port,
200 struct port_info *info)
202 struct __port_info i;
203 int index;
205 memset(info, 0, sizeof(*info));
207 index = get_portno(brname, port);
208 if (index < 0)
209 return errno;
211 else {
212 struct ifreq ifr;
213 unsigned long args[4] = { BRCTL_GET_PORT_INFO,
214 (unsigned long) &i, index, 0 };
216 strncpy(ifr.ifr_name, brname, IFNAMSIZ);
217 ifr.ifr_data = (char *) &args;
219 if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
220 dprintf("old can't get port %s(%d) info %s\n",
221 brname, index, strerror(errno));
222 return errno;
226 info->port_no = index;
227 memcpy(&info->designated_root, &i.designated_root, 8);
228 memcpy(&info->designated_bridge, &i.designated_bridge, 8);
229 info->port_id = i.port_id;
230 info->designated_port = i.designated_port;
231 info->path_cost = i.path_cost;
232 info->designated_cost = i.designated_cost;
233 info->state = i.state;
234 info->top_change_ack = i.top_change_ack;
235 info->config_pending = i.config_pending;
236 __jiffies_to_tv(&info->message_age_timer_value,
237 i.message_age_timer_value);
238 __jiffies_to_tv(&info->forward_delay_timer_value,
239 i.forward_delay_timer_value);
240 __jiffies_to_tv(&info->hold_timer_value, i.hold_timer_value);
241 info->hairpin_mode = 0;
242 return 0;
246 * Get information about port on bridge.
248 int br_get_port_info(const char *brname, const char *port,
249 struct port_info *info)
251 DIR *d;
252 char path[SYSFS_PATH_MAX];
254 snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport", port);
255 d = opendir(path);
256 if (!d)
257 goto fallback;
259 memset(info, 0, sizeof(*info));
261 fetch_id(path, "designated_root", &info->designated_root);
262 fetch_id(path, "designated_bridge", &info->designated_bridge);
263 info->port_no = fetch_int(path, "port_no");
264 info->port_id = fetch_int(path, "port_id");
265 info->designated_port = fetch_int(path, "designated_port");
266 info->path_cost = fetch_int(path, "path_cost");
267 info->designated_cost = fetch_int(path, "designated_cost");
268 info->state = fetch_int(path, "state");
269 info->top_change_ack = fetch_int(path, "change_ack");
270 info->config_pending = fetch_int(path, "config_pending");
271 fetch_tv(path, "message_age_timer", &info->message_age_timer_value);
272 fetch_tv(path, "forward_delay_timer", &info->forward_delay_timer_value);
273 fetch_tv(path, "hold_timer", &info->hold_timer_value);
274 info->hairpin_mode = fetch_int(path, "hairpin_mode");
276 closedir(d);
278 return 0;
279 fallback:
280 return old_get_port_info(brname, port, info);
284 static int br_set(const char *bridge, const char *name,
285 unsigned long value, unsigned long oldcode)
287 int ret;
288 char path[SYSFS_PATH_MAX];
289 FILE *f;
291 snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/%s", bridge, name);
293 f = fopen(path, "w");
294 if (f) {
295 ret = fprintf(f, "%ld\n", value);
296 fclose(f);
297 } else {
298 /* fallback to old ioctl */
299 struct ifreq ifr;
300 unsigned long args[4] = { oldcode, value, 0, 0 };
302 strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
303 ifr.ifr_data = (char *) &args;
304 ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
307 return ret < 0 ? errno : 0;
310 int br_set_bridge_forward_delay(const char *br, struct timeval *tv)
312 return br_set(br, "forward_delay", __tv_to_jiffies(tv),
313 BRCTL_SET_BRIDGE_FORWARD_DELAY);
316 int br_set_bridge_hello_time(const char *br, struct timeval *tv)
318 return br_set(br, "hello_time", __tv_to_jiffies(tv),
319 BRCTL_SET_BRIDGE_HELLO_TIME);
322 int br_set_bridge_max_age(const char *br, struct timeval *tv)
324 return br_set(br, "max_age", __tv_to_jiffies(tv),
325 BRCTL_SET_BRIDGE_MAX_AGE);
328 int br_set_ageing_time(const char *br, struct timeval *tv)
330 return br_set(br, "ageing_time", __tv_to_jiffies(tv),
331 BRCTL_SET_AGEING_TIME);
334 int br_set_stp_state(const char *br, int stp_state)
336 return br_set(br, "stp_state", stp_state, BRCTL_SET_BRIDGE_STP_STATE);
339 int br_set_bridge_priority(const char *br, int bridge_priority)
341 return br_set(br, "priority", bridge_priority,
342 BRCTL_SET_BRIDGE_PRIORITY);
345 static int port_set(const char *bridge, const char *ifname,
346 const char *name, unsigned long value,
347 unsigned long oldcode)
349 int ret;
350 char path[SYSFS_PATH_MAX];
351 FILE *f;
353 snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport/%s", ifname, name);
354 f = fopen(path, "w");
355 if (f) {
356 ret = fprintf(f, "%ld\n", value);
357 fclose(f);
358 } else {
359 int index = get_portno(bridge, ifname);
361 if (index < 0)
362 ret = index;
363 else {
364 struct ifreq ifr;
365 unsigned long args[4] = { oldcode, index, value, 0 };
367 strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
368 ifr.ifr_data = (char *) &args;
369 ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
373 return ret < 0 ? errno : 0;
376 int br_set_port_priority(const char *bridge, const char *port, int priority)
378 return port_set(bridge, port, "priority", priority, BRCTL_SET_PORT_PRIORITY);
381 int br_set_path_cost(const char *bridge, const char *port, int cost)
383 return port_set(bridge, port, "path_cost", cost, BRCTL_SET_PATH_COST);
386 int br_set_hairpin_mode(const char *bridge, const char *port, int hairpin_mode)
388 return port_set(bridge, port, "hairpin_mode", hairpin_mode, 0);
391 static inline void __copy_fdb(struct fdb_entry *ent,
392 const struct __fdb_entry *f)
394 memcpy(ent->mac_addr, f->mac_addr, 6);
395 ent->port_no = f->port_no;
396 ent->is_local = f->is_local;
397 __jiffies_to_tv(&ent->ageing_timer_value, f->ageing_timer_value);
400 int br_read_fdb(const char *bridge, struct fdb_entry *fdbs,
401 unsigned long offset, int num)
403 FILE *f;
404 int i, n;
405 struct __fdb_entry fe[num];
406 char path[SYSFS_PATH_MAX];
408 /* open /sys/class/net/brXXX/brforward */
409 snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brforward", bridge);
410 f = fopen(path, "r");
411 if (f) {
412 fseek(f, offset*sizeof(struct __fdb_entry), SEEK_SET);
413 n = fread(fe, sizeof(struct __fdb_entry), num, f);
414 fclose(f);
415 } else {
416 /* old kernel, use ioctl */
417 unsigned long args[4] = { BRCTL_GET_FDB_ENTRIES,
418 (unsigned long) fe,
419 num, offset };
420 struct ifreq ifr;
421 int retries = 0;
423 strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
424 ifr.ifr_data = (char *) args;
426 retry:
427 n = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
429 /* table can change during ioctl processing */
430 if (n < 0 && errno == EAGAIN && ++retries < 10) {
431 sleep(0);
432 goto retry;
436 for (i = 0; i < n; i++)
437 __copy_fdb(fdbs+i, fe+i);
439 return n;