]> git.ipfire.org Git - people/ms/rstp.git/blame - bridge_track.c
Merge remote-tracking branch 'upstream/master'
[people/ms/rstp.git] / bridge_track.c
CommitLineData
ad02a0eb
SH
1/*****************************************************************************
2 Copyright (c) 2006 EMC Corporation.
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2 of the License, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc., 59
16 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 The full GNU General Public License is included in this distribution in the
19 file called LICENSE.
20
21 Authors: Srinivas Aji <Aji_Srinivas@emc.com>
22
23******************************************************************************/
24
25#include "bridge_ctl.h"
26#include "netif_utils.h"
f2592588 27#include "packet.h"
ad02a0eb
SH
28
29#include <unistd.h>
30#include <net/if.h>
f2592588 31#include <stdlib.h>
ad02a0eb 32#include <linux/if_bridge.h>
fcc6b809 33#include <linux/if_ether.h>
ad02a0eb
SH
34#include <arpa/inet.h>
35#include <sys/types.h>
36
ad02a0eb
SH
37#include <stdio.h>
38#include <string.h>
39
40#include "log.h"
41
b600a2c3 42#include "rstp.h"
ad02a0eb
SH
43/*------------------------------------------------------------*/
44
11904a35
SH
45struct ifdata {
46 int if_index;
47 struct ifdata *next;
48 int up;
49 char name[IFNAMSIZ];
3cf368c1 50 unsigned char macaddr[ETH_ALEN];
11904a35
SH
51
52 int is_bridge;
53 /* If bridge */
54 struct ifdata *bridge_next;
55 struct ifdata *port_list;
56 int do_stp;
57 int stp_up;
b600a2c3
SA
58 STP_Bridge *stp_bridge;
59
11904a35
SH
60
61 /* If port */
62 int speed;
63 int duplex;
64 struct ifdata *master;
65 struct ifdata *port_next;
66 /* STP port index */
67 int port_index;
b600a2c3 68 STP_Port *stp_port;
f2592588
SH
69
70 struct epoll_event_handler event;
ad02a0eb
SH
71};
72
73/* Instances */
74struct ifdata *current_br = NULL;
75
ad02a0eb
SH
76struct ifdata *find_port(int port_index)
77{
11904a35
SH
78 struct ifdata *ifc = current_br->port_list;
79 while (ifc && ifc->port_index != port_index)
80 ifc = ifc->port_next;
81 return ifc;
ad02a0eb
SH
82}
83
ad02a0eb 84
ad02a0eb
SH
85struct ifdata *if_head = NULL;
86struct ifdata *br_head = NULL;
87
88struct ifdata *find_if(int if_index)
89{
11904a35
SH
90 struct ifdata *p = if_head;
91 while (p && p->if_index != if_index)
92 p = p->next;
93 return p;
ad02a0eb
SH
94}
95
96#define ADD_TO_LIST(_list, _next, _ifc) \
97 do { \
98 (_ifc)->_next = (_list); \
99 (_list) = (_ifc); \
100 } while (0)
101
102#define REMOVE_FROM_LIST(_list, _next, _ifc, _error_fmt, _args...) \
103 do { \
104 struct ifdata **_prev = &(_list); \
105 while (*_prev && *_prev != (_ifc)) \
106 _prev = &(*_prev)->_next; \
107 if (*_prev != (_ifc)) \
108 ERROR(_error_fmt, ##_args); \
109 else \
110 *_prev = (_ifc)->_next; \
111 } while (0)
112
113/* Caller ensures that there isn't any ifdata with this index */
114/* If br is NULL, new interface is a bridge, else it is a port of br */
115struct ifdata *create_if(int if_index, struct ifdata *br)
116{
11904a35
SH
117 struct ifdata *p;
118 TST((p = malloc(sizeof(*p))) != NULL, NULL);
119
f2592588
SH
120 memset(p, 0, sizeof(*p));
121
11904a35
SH
122 /* Init fields */
123 p->if_index = if_index;
124 p->is_bridge = (br == NULL);
f2592588
SH
125
126 /* TODO: purge use of name, due to issue with renameing */
11904a35 127 if_indextoname(if_index, p->name);
017b1185 128 get_hwaddr(p->name, p->macaddr);
f2592588 129
11904a35
SH
130 if (p->is_bridge) {
131 INFO("Add bridge %s", p->name);
b600a2c3
SA
132 p->stp_bridge = STP_IN_bridge_create(p);
133 if (!p->stp_bridge) {
134 ERROR("Couldn't create STP Bridge");
135 free(p);
136 return NULL;
137 }
138 STP_IN_set_bridge_address(p->stp_bridge,
139 (STP_MacAddress *)p->macaddr);
140 INFO("Set bridge address %s to %02x:%02x:%02x:%02x:%02x:%02x",
141 p->name,
142 p->macaddr[0], p->macaddr[1], p->macaddr[2],
143 p->macaddr[1], p->macaddr[4], p->macaddr[5]
144 );
11904a35
SH
145 /* Init slave list */
146 p->port_list = NULL;
147
148 p->do_stp = 0;
149 p->up = 0;
150 p->stp_up = 0;
b600a2c3 151 ADD_TO_LIST(br_head, bridge_next, p); /* Add to bridge list */
11904a35
SH
152 } else {
153 INFO("Add iface %s to bridge %s", p->name, br->name);
154 p->up = 0;
155 p->speed = 0;
156 p->duplex = 0;
157 p->master = br;
f2592588 158
b600a2c3
SA
159 p->port_index = get_bridge_portno(p->name);
160 if (p->port_index < 0) {
161 ERROR("Couldn't get port number for %s", p->name);
162 free(p);
163 return NULL;
164 }
165 p->stp_port = STP_IN_port_create(p->master->stp_bridge,
166 p->port_index, p);
167 if (!p->stp_port) {
168 ERROR("Couldn't create STP Port");
169 free(p);
170 return NULL;
171 }
172
11904a35 173 ADD_TO_LIST(br->port_list, port_next, p); /* Add to bridge port list */
f2592588 174
11904a35 175 }
f2592588 176
11904a35
SH
177 /* Add to interface list */
178 ADD_TO_LIST(if_head, next, p);
179
180 return p;
ad02a0eb
SH
181}
182
183void delete_if(struct ifdata *ifc)
184{
11904a35
SH
185 INFO("Delete iface %s", ifc->name);
186 if (ifc->is_bridge) { /* Bridge: */
b600a2c3 187 STP_IN_set_bridge_enable(ifc->stp_bridge, 0);
11904a35
SH
188 /* Delete ports */
189 while (ifc->port_list)
190 delete_if(ifc->port_list);
191 /* Remove from bridge list */
192 REMOVE_FROM_LIST(br_head, bridge_next, ifc,
193 "Can't find interface ifindex %d bridge list",
194 ifc->if_index);
b600a2c3 195 STP_IN_bridge_delete(ifc->stp_bridge);
11904a35 196 } else { /* Port */
11904a35
SH
197 /* Remove from bridge port list */
198 REMOVE_FROM_LIST(ifc->master->port_list, port_next, ifc,
199 "Can't find interface ifindex %d on br %d's port list",
200 ifc->if_index, ifc->master->if_index);
b600a2c3 201 STP_IN_port_delete(ifc->stp_port);
11904a35 202 }
f2592588 203
11904a35
SH
204 /* Remove from bridge interface list */
205 REMOVE_FROM_LIST(if_head, next, ifc,
206 "Can't find interface ifindex %d on iflist",
207 ifc->if_index);
f2592588 208 free(ifc);
ad02a0eb
SH
209}
210
017b1185
SA
211/* New MAC address is stored in addr, which also holds the old value on entry.
212 Return nonzero if the address changed */
213static int check_mac_address(char *name, unsigned char *addr)
214{
215 unsigned char temp_addr[6];
216 if (get_hwaddr(name, temp_addr)) {
b600a2c3 217 LOG("Error getting hw address: %s", name);
017b1185
SA
218 /* Error. Ignore the new value */
219 return 0;
220 }
221 if (memcmp(addr, temp_addr, sizeof(temp_addr)) == 0)
222 return 0;
223 else {
224 memcpy(addr, temp_addr, sizeof(temp_addr));
225 return 1;
226 }
227}
228
229
358260ff
SH
230static int stp_enabled(struct ifdata *br)
231{
232 char path[40 + IFNAMSIZ];
c768cf44 233 int ret;
358260ff
SH
234 sprintf(path, "/sys/class/net/%s/bridge/stp_state", br->name);
235 FILE *f = fopen(path, "r");
236 if (!f) {
237 LOG("Open %s failed", path);
238 return 0;
239 }
240 int enabled = 0;
c768cf44
DF
241 ret = fscanf(f, "%d", &enabled);
242 if (!ret) {
243 LOG("%s, stp_state parsing error", path);
244 return 0;
245 }
358260ff
SH
246 fclose(f);
247 INFO("STP on %s state %d", br->name, enabled);
248
249 return enabled == 2; /* ie user mode STP */
250}
251
d19d0e35 252static void set_br_up(struct ifdata *br, int up)
ad02a0eb 253{
358260ff 254 int stp_up = stp_enabled(br);
d19d0e35
SH
255 INFO("%s was %s stp was %s", br->name,
256 up ? "up" : "down",
257 br->stp_up ? "up" : "down");
358260ff 258 INFO("Set bridge %s %s stp %s" , br->name,
d19d0e35
SH
259 up ? "up" : "down",
260 stp_up ? "up" : "down");
358260ff 261
b600a2c3
SA
262 int changed = 0;
263
264 if (up != br->up) {
11904a35 265 br->up = up;
b600a2c3
SA
266 changed = 1;
267 }
358260ff 268
b600a2c3
SA
269 if (br->stp_up != stp_up) {
270 br->stp_up = stp_up;
271 changed = 1;
272 }
273
017b1185
SA
274 if (check_mac_address(br->name, br->macaddr)) {
275 /* MAC address changed */
b600a2c3
SA
276 /* Notify bridge address change */
277 STP_IN_set_bridge_address(
278 br->stp_bridge, (STP_MacAddress *)br->macaddr);
017b1185
SA
279 }
280
b600a2c3
SA
281 if (changed)
282 STP_IN_set_bridge_enable(br->stp_bridge,
283 (br->up && br->stp_up)?1:0);
ad02a0eb
SH
284}
285
d19d0e35 286static void set_if_up(struct ifdata *ifc, int up)
ad02a0eb 287{
11904a35
SH
288 INFO("Port %s : %s", ifc->name, (up ? "up" : "down"));
289 int speed = -1;
290 int duplex = -1;
b600a2c3 291 int changed = 0;
017b1185
SA
292
293 if (check_mac_address(ifc->name, ifc->macaddr)) {
294 /* MAC address changed */
295 if (check_mac_address(ifc->master->name, ifc->master->macaddr)
b600a2c3 296 ) {
017b1185 297 /* Notify bridge address change */
b600a2c3
SA
298 STP_IN_set_bridge_address(
299 ifc->master->stp_bridge,
300 (STP_MacAddress *)ifc->master->macaddr);
017b1185
SA
301 }
302 }
303
11904a35
SH
304 if (!up) { /* Down */
305 if (ifc->up) {
306 ifc->up = up;
b600a2c3 307 changed = 1;
11904a35
SH
308 }
309 } else { /* Up */
310 int r = ethtool_get_speed_duplex(ifc->name, &speed, &duplex);
311 if (r < 0) { /* Didn't succeed */
312 }
313 if (speed < 0)
314 speed = 10;
315 if (duplex < 0)
316 duplex = 0; /* Assume half duplex */
317
318 if (speed != ifc->speed) {
319 ifc->speed = speed;
b600a2c3 320 changed = 1;
11904a35
SH
321 }
322 if (duplex != ifc->duplex) {
323 ifc->duplex = duplex;
b600a2c3 324 changed = 1;
11904a35
SH
325 }
326 if (!ifc->up) {
327 ifc->up = 1;
b600a2c3 328 changed = 1;
11904a35
SH
329 }
330 }
b600a2c3
SA
331 if (changed)
332 STP_IN_set_port_enable(ifc->stp_port,
333 ifc->up, ifc->speed, ifc->duplex);
ad02a0eb
SH
334}
335
336/*------------------------------------------------------------*/
337
968d3d40
SH
338int bridge_notify(int br_index, int if_index, int newlink,
339 unsigned flags)
ad02a0eb 340{
11904a35 341 struct ifdata *br = NULL;
968d3d40
SH
342
343 LOG("br_index %d, if_index %d, up %d running %d",
344 br_index, if_index, (flags & IFF_UP), flags & IFF_RUNNING);
345
11904a35
SH
346 if (br_index >= 0) {
347 br = find_if(br_index);
348 if (br && !br->is_bridge) {
349 ERROR
350 ("Notification shows non bridge interface %d as bridge.",
351 br_index);
352 return -1;
353 }
354 if (!br)
355 br = create_if(br_index, NULL);
356 if (!br) {
357 ERROR("Couldn't create data for bridge interface %d",
358 br_index);
359 return -1;
360 }
361 /* Bridge must be up if we get such notifications */
b600a2c3 362 // Not true anymore - set_br_up(br, 1);
11904a35
SH
363 }
364
365 struct ifdata *ifc = find_if(if_index);
366
367 if (br) {
368 if (ifc) {
369 if (ifc->is_bridge) {
370 ERROR
371 ("Notification shows bridge interface %d as slave of %d",
372 if_index, br_index);
373 return -1;
374 }
375 if (ifc->master != br) {
376 INFO("Device %d has come to bridge %d. "
377 "Missed notify for deletion from bridge %d",
378 if_index, br_index, ifc->master->if_index);
379 delete_if(ifc);
380 ifc = NULL;
381 }
382 }
09dffbd4
SA
383 if (!ifc) {
384 if (!newlink) {
385 INFO("Got DELLINK for unknown port %d on "
386 "bridge %d", if_index, br_index);
387 return -1;
388 }
11904a35 389 ifc = create_if(if_index, br);
09dffbd4 390 }
11904a35
SH
391 if (!ifc) {
392 ERROR
393 ("Couldn't create data for interface %d (master %d)",
394 if_index, br_index);
395 return -1;
396 }
09dffbd4 397 if (!newlink) {
11904a35
SH
398 delete_if(ifc);
399 return 0;
400 }
968d3d40
SH
401 int up = (flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING);
402
11904a35
SH
403 if (ifc->up != up)
404 set_if_up(ifc, up); /* And speed and duplex */
405 } else { /* No br_index */
406 if (!newlink) {
407 /* DELLINK not from bridge means interface unregistered. */
408 /* Cleanup removed bridge or removed bridge slave */
409 if (ifc)
410 delete_if(ifc);
411 return 0;
412 } else { /* This may be a new link */
413 if (!ifc) {
414 char ifname[IFNAMSIZ];
415 if (if_indextoname(if_index, ifname)
416 && is_bridge(ifname)) {
417 ifc = create_if(if_index, NULL);
418 if (!ifc) {
419 ERROR
420 ("Couldn't create data for bridge interface %d",
421 if_index);
422 return -1;
423 }
424 }
425 }
426 if (ifc && !ifc->is_bridge &&
427 !is_bridge_slave(ifc->master->name, ifc->name)) {
428 /* Interface might have left bridge and we might have missed deletion */
429 delete_if(ifc);
430 return 0;
431 }
968d3d40 432
017b1185 433 if (ifc) {
968d3d40
SH
434 if (ifc->is_bridge) {
435 int up = (flags & IFF_UP) != 0;
436 if (ifc->up != up)
437 set_br_up(ifc, up);
438 } else {
439 int up = (flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING);
440
441 if (ifc->up != up)
442 set_if_up(ifc, up);
443 }
11904a35
SH
444 }
445 }
446 }
447 return 0;
ad02a0eb
SH
448}
449
fcc6b809
SA
450struct llc_header
451{
452 uint8_t dest_addr[ETH_ALEN];
453 uint8_t src_addr[ETH_ALEN];
454 uint16_t len8023;
455 uint8_t d_sap; /* 0x42 */
456 uint8_t s_sap; /* 0x42 */
457 uint8_t llc_ui; /* 0x03 */
458} __attribute__((packed));
459
460const unsigned char bridge_group_address[ETH_ALEN] = {
461 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00
462};
463
464const unsigned char STP_SAP = 0x42;
465
96e20123 466void bridge_bpdu_rcv(int if_index, const unsigned char *data, int len)
ad02a0eb 467{
96e20123 468 struct ifdata *ifc = find_if(if_index);
f2592588 469
96e20123 470 LOG("ifindex %d, len %d", if_index, len);
b79b9a98 471 if (!ifc || !ifc->master)
96e20123
SH
472 return;
473
358260ff 474 TST(ifc->up,);
b600a2c3
SA
475 if (!ifc->master->stp_up)
476 return;
f2592588 477
fcc6b809
SA
478 /* Validate Ethernet and LLC header */
479 {
480 struct llc_header *h;
481 unsigned int l;
482 TST(len > sizeof(struct llc_header),);
483 h = (struct llc_header *)data;
484 TST(memcmp(h->dest_addr, bridge_group_address, ETH_ALEN) == 0,
b600a2c3
SA
485 INFO("ifindex %d, len %d, %02x:%02x:%02x:%02x:%02x:%02x",
486 if_index, len,
487 h->dest_addr[0],h->dest_addr[1],h->dest_addr[2],
488 h->dest_addr[3],h->dest_addr[4],h->dest_addr[5]));
fcc6b809
SA
489 l = ntohs(h->len8023);
490 TST(l <= ETH_DATA_LEN && l <= len - ETH_HLEN && l >= 3,);
491 TST(h->d_sap == STP_SAP && h->s_sap == STP_SAP
492 && (h->llc_ui & 0x3) == 0x3 /* LLC UI */,);
fcc6b809 493
b600a2c3
SA
494 STP_IN_rx_bpdu(ifc->stp_port,
495 /* Don't include LLC header */
496 data + sizeof(*h), l - 3);
11904a35 497 }
ad02a0eb
SH
498}
499
500void bridge_one_second(void)
501{
11904a35
SH
502 // LOG("");
503 struct ifdata *br;
504 for (br = br_head; br; br = br->bridge_next) {
b600a2c3 505 STP_IN_one_second(br->stp_bridge);
11904a35 506 }
ad02a0eb
SH
507}
508
509/* Implementing STP_OUT functions */
510
511int flush_port(char *sys_name)
512{
11904a35
SH
513 FILE *f = fopen(sys_name, "w");
514 TSTM(f, -1, "Couldn't open flush file %s for write.", sys_name);
515 int r = fwrite("1", 1, 1, f);
516 fclose(f);
517 TST(r == 1, -1);
518 return 0;
ad02a0eb
SH
519}
520
b600a2c3 521void STP_OUT_port_fdb_flush(void *user_ref)
11904a35 522{
b600a2c3 523 struct ifdata *port = user_ref;
11904a35 524 char fname[128];
b600a2c3
SA
525 snprintf(fname, sizeof(fname),
526 "/sys/class/net/%s/brport/flush", port->name);
527 fname[sizeof(fname) - 1] = 0;
528 TST(flush_port(fname) == 0,);
ad02a0eb
SH
529}
530
b600a2c3 531void STP_OUT_port_set_state(void *user_ref, unsigned int flags)
ad02a0eb 532{
b600a2c3 533 struct ifdata *port = user_ref;
11904a35 534 int br_state;
b600a2c3
SA
535
536 LOG("port index %d, flags %d", port->if_index, flags);
537
538 if (flags & STP_PORT_STATE_FLAG_FORWARDING)
11904a35 539 br_state = BR_STATE_FORWARDING;
b600a2c3
SA
540 else if (flags & STP_PORT_STATE_FLAG_LEARNING)
541 br_state = BR_STATE_LEARNING;
542 else
543 br_state = BR_STATE_BLOCKING;
544
11904a35
SH
545 if (port->up)
546 bridge_set_state(port->if_index, br_state);
11904a35
SH
547}
548
ad02a0eb 549
b600a2c3 550void STP_OUT_tx_bpdu(void *port_user_ref, void *base, unsigned int len)
ad02a0eb 551{
b600a2c3
SA
552 struct ifdata *port = port_user_ref;
553
554 LOG("port index %d, len %d", port->if_index, len);
358260ff 555
3cf368c1
SA
556 struct llc_header h;
557 memcpy(h.dest_addr, bridge_group_address, ETH_ALEN);
558 memcpy(h.src_addr, port->macaddr, ETH_ALEN);
559 /* bpdu_len excludes MAC and LLC headers */
b600a2c3 560 h.len8023 = htons(len + 3);
3cf368c1 561 h.d_sap = h.s_sap = STP_SAP;
b600a2c3 562 h.llc_ui = 0x03; /* LLC UI packet */
3cf368c1
SA
563
564 struct iovec iov[2] = {
565 { .iov_base = &h, .iov_len = sizeof(h) },
b600a2c3 566 { .iov_base = base, .iov_len = len }
3cf368c1
SA
567 };
568
b600a2c3 569 packet_send(port->if_index, iov, 2, sizeof(h) + len);
11904a35 570}
ad02a0eb 571
ad02a0eb 572
b600a2c3
SA
573void STP_OUT_logmsg(void *br_user_ref, void *port_user_ref,
574 int level, char *fmt, ...)
11904a35 575{
b600a2c3
SA
576 struct ifdata *bridge = br_user_ref;
577 struct ifdata *port = port_user_ref;
578 char buf[256];
579 int r;
580 int ll = (level < STP_LOG_LEVEL_DEBUG) ?
581 LOG_LEVEL_INFO : LOG_LEVEL_DEBUG;
582 struct timeval tv;
583 gettimeofday(&tv, NULL);
584 r = snprintf(buf, sizeof(buf), "LOG Level %d:%s:%s: %02d.%03d: ",
585 level,
586 (bridge?bridge->name:""), (port?port->name:""),
587 (int)tv.tv_sec % 60, (int)tv.tv_usec / 1000);
588 if (r >= sizeof(buf)) {
589 buf[sizeof(buf) - 1] = 0;
590 Dprintf(ll, "%s", buf);
591 r = 0;
592 }
11904a35 593
b600a2c3
SA
594 va_list ap;
595 va_start(ap, fmt);
596 vsnprintf(buf + r, sizeof(buf) - r, fmt, ap);
597 buf[sizeof(buf) - 1] = 0;
598 Dprintf(ll, "%s", buf);
599 va_end(ap);
600 if (level == STP_LOG_LEVEL_ERROR)
601 ctl_err_log("%s", buf + r);
ad02a0eb
SH
602}
603
b600a2c3 604void *STP_OUT_mem_zalloc(unsigned int size)
ad02a0eb 605{
b600a2c3 606 return calloc(1, size);
ad02a0eb
SH
607}
608
b600a2c3
SA
609
610void STP_OUT_mem_free(void *p)
ad02a0eb 611{
b600a2c3 612 free(p);
ad02a0eb
SH
613}
614
b600a2c3 615
ad02a0eb
SH
616/* Commands and status */
617#include "ctl_functions.h"
618
619#define CTL_CHECK_BRIDGE \
b600a2c3
SA
620 struct ifdata *br = find_if(br_index); \
621 if (br == NULL || !br->is_bridge) { \
622 ERROR("Couldn't find bridge with index %d", br_index); \
623 return -1; \
624 } \
625 do { } while (0)
ad02a0eb
SH
626
627#define CTL_CHECK_BRIDGE_PORT \
b600a2c3
SA
628 CTL_CHECK_BRIDGE; \
629 struct ifdata *port = find_if(port_index); \
630 if (port == NULL || port->is_bridge || port->master != br) { \
631 ERROR("Interface with index %d not a port of bridge " \
632 "with index %d", port_index, br_index); \
633 return -1; \
634 } \
635 do { } while (0)
ad02a0eb
SH
636
637int CTL_enable_bridge_rstp(int br_index, int enable)
638{
11904a35
SH
639 INFO("bridge %d, enable %d", br_index, enable);
640 int r = 0;
641 if (enable)
642 enable = 1;
643 struct ifdata *br = find_if(br_index);
644 if (br == NULL) {
645 char ifname[IFNAMSIZ];
646 if (if_indextoname(br_index, ifname) && is_bridge(ifname))
647 br = create_if(br_index, NULL);
648 }
b600a2c3
SA
649 if (br == NULL || !br->is_bridge) {
650 ERROR("Couldn't find bridge with index %d", br_index);
651 return -1;
11904a35 652 }
b600a2c3
SA
653 if (br->up)
654 set_br_up(br, 1);
11904a35 655 return r;
ad02a0eb
SH
656}
657
b600a2c3 658int CTL_get_bridge_status(int br_index, STP_BridgeStatus *status)
11904a35
SH
659{
660 LOG("bridge %d", br_index);
661 CTL_CHECK_BRIDGE;
b600a2c3
SA
662
663 STP_IN_get_bridge_status(br->stp_bridge, status);
11904a35
SH
664 return 0;
665}
666
b600a2c3 667int CTL_set_bridge_config(int br_index, STP_BridgeConfig *cfg)
11904a35 668{
b600a2c3 669 INFO("bridge %d", br_index);
11904a35 670 CTL_CHECK_BRIDGE;
b600a2c3
SA
671
672 if (cfg->set_bridge_address) {
673 ERROR("Setting bridge address not permitted: %s", br->name);
674 return -1;
675 }
676
677 int r = STP_IN_set_bridge_config(br->stp_bridge, cfg);
678
11904a35 679 if (r) {
b600a2c3 680 ERROR("Error setting bridge config for %s", br->name);
11904a35
SH
681 return r;
682 }
11904a35 683 return 0;
ad02a0eb
SH
684}
685
b600a2c3 686int CTL_get_port_status(int br_index, int port_index, STP_PortStatus *status)
11904a35
SH
687{
688 LOG("bridge %d port %d", br_index, port_index);
689 CTL_CHECK_BRIDGE_PORT;
b600a2c3
SA
690
691 STP_IN_get_port_status(port->stp_port, status);
692 return 0;
693}
694
695int CTL_set_port_config(int br_index, int port_index, STP_PortConfig *cfg)
696{
697 INFO("bridge %d, port %d", br_index, port_index);
698 CTL_CHECK_BRIDGE_PORT;
699
700 int r = STP_IN_set_port_config(port->stp_port, cfg);
11904a35 701 if (r) {
b600a2c3 702 ERROR("Error setting port config for %s", port->name);
11904a35
SH
703 return r;
704 }
b600a2c3 705
11904a35 706 return 0;
11904a35
SH
707}
708
b600a2c3 709int CTL_port_mcheck(int br_index, int port_index)
11904a35 710{
b600a2c3 711 INFO("bridge %d, port %d", br_index, port_index);
11904a35 712 CTL_CHECK_BRIDGE_PORT;
b600a2c3
SA
713
714 int r = STP_IN_port_mcheck(port->stp_port);
11904a35 715 if (r) {
b600a2c3 716 ERROR("Error doing port mcheck for %s", port->name);
11904a35
SH
717 return r;
718 }
b600a2c3 719
11904a35 720 return 0;
ad02a0eb
SH
721}
722
723int CTL_set_debug_level(int level)
724{
11904a35
SH
725 INFO("level %d", level);
726 log_level = level;
727 return 0;
ad02a0eb
SH
728}
729
ad02a0eb
SH
730#undef CTL_CHECK_BRIDGE_PORT
731#undef CTL_CHECK_BRIDGE