]> git.ipfire.org Git - people/ms/rstp.git/blame - bridge_track.c
Ignore carrier state on bridge device
[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
SH
32#include <linux/if_bridge.h>
33#include <arpa/inet.h>
34#include <sys/types.h>
35
36#include <bitmap.h>
37#include <uid_stp.h>
38#include <stp_bpdu.h>
39#include <stp_in.h>
40#include <stp_to.h>
41
42#include <stdio.h>
43#include <string.h>
44
45#include "log.h"
46
ad02a0eb
SH
47/*------------------------------------------------------------*/
48
11904a35
SH
49struct ifdata {
50 int if_index;
51 struct ifdata *next;
52 int up;
53 char name[IFNAMSIZ];
54
55 int is_bridge;
56 /* If bridge */
57 struct ifdata *bridge_next;
58 struct ifdata *port_list;
59 int do_stp;
60 int stp_up;
61 struct stp_instance *stp;
62 UID_BRIDGE_ID_T bridge_id;
63 /* Bridge config */
64 UID_STP_MODE_T stp_enabled;
65 int bridge_priority;
66 int max_age;
67 int hello_time;
68 int forward_delay;
69 int force_version;
70 int hold_time;
71
72 /* If port */
73 int speed;
74 int duplex;
75 struct ifdata *master;
76 struct ifdata *port_next;
77 /* STP port index */
78 int port_index;
79 /* STP port config */
80 int port_priority;
81 int admin_port_path_cost;
82 ADMIN_P2P_T admin_point2point;
83 unsigned char admin_edge;
84 unsigned char admin_non_stp; /* 1- doesn't participate in STP, 1 - regular */
f2592588
SH
85
86 struct epoll_event_handler event;
ad02a0eb
SH
87};
88
89/* Instances */
90struct ifdata *current_br = NULL;
91
92void instance_begin(struct ifdata *br)
93{
11904a35
SH
94 if (current_br) {
95 ERROR("BUG: Trying to set instance over existing instance.");
96 ERROR("%d", *(int *)0); /* ABORT */
97 }
98 current_br = br;
99 STP_IN_instance_begin(br->stp);
ad02a0eb
SH
100}
101
102void instance_end(void)
103{
11904a35
SH
104 STP_IN_instance_end(current_br->stp);
105 current_br = NULL;
ad02a0eb
SH
106}
107
108struct ifdata *find_port(int port_index)
109{
11904a35
SH
110 struct ifdata *ifc = current_br->port_list;
111 while (ifc && ifc->port_index != port_index)
112 ifc = ifc->port_next;
113 return ifc;
ad02a0eb
SH
114}
115
ad02a0eb
SH
116/*************************************************************/
117/* Bridge and port defaults */
118
119UID_STP_CFG_T default_bridge_stp_cfg = {
11904a35
SH
120 .field_mask = BR_CFG_ALL,
121 .bridge_priority = DEF_BR_PRIO,
122 .max_age = DEF_BR_MAXAGE,
123 .hello_time = DEF_BR_HELLOT,
124 .forward_delay = DEF_BR_FWDELAY,
125 .force_version = DEF_FORCE_VERS, /*NORMAL_RSTP */
ad02a0eb
SH
126};
127
11904a35 128void update_bridge_stp_config(struct ifdata *br, UID_STP_CFG_T * cfg)
ad02a0eb 129{
11904a35
SH
130 if (cfg->field_mask & BR_CFG_PRIO)
131 br->bridge_priority = cfg->bridge_priority;
132 if (cfg->field_mask & BR_CFG_AGE)
133 br->max_age = cfg->max_age;
134 if (cfg->field_mask & BR_CFG_HELLO)
135 br->hello_time = cfg->hello_time;
136 if (cfg->field_mask & BR_CFG_DELAY)
137 br->forward_delay = cfg->forward_delay;
138 if (cfg->field_mask & BR_CFG_FORCE_VER)
139 br->force_version = cfg->force_version;
ad02a0eb
SH
140}
141
142UID_STP_PORT_CFG_T default_port_stp_cfg = {
11904a35
SH
143 .field_mask = PT_CFG_ALL,
144 .port_priority = DEF_PORT_PRIO,
145 .admin_non_stp = DEF_ADMIN_NON_STP,
146 .admin_edge = False, // DEF_ADMIN_EDGE,
147 .admin_port_path_cost = ADMIN_PORT_PATH_COST_AUTO,
148 .admin_point2point = DEF_P2P,
ad02a0eb
SH
149};
150
11904a35 151void update_port_stp_config(struct ifdata *ifc, UID_STP_PORT_CFG_T * cfg)
ad02a0eb 152{
11904a35
SH
153 if (cfg->field_mask & PT_CFG_PRIO)
154 ifc->port_priority = cfg->port_priority;
155 if (cfg->field_mask & PT_CFG_NON_STP)
156 ifc->admin_non_stp = cfg->admin_non_stp;
157 if (cfg->field_mask & PT_CFG_EDGE)
158 ifc->admin_edge = cfg->admin_edge;
159 if (cfg->field_mask & PT_CFG_COST)
160 ifc->admin_port_path_cost = cfg->admin_port_path_cost;
161 if (cfg->field_mask & PT_CFG_P2P)
162 ifc->admin_point2point = cfg->admin_point2point;
ad02a0eb
SH
163}
164
165/**************************************************************/
166
167int add_port_stp(struct ifdata *ifc)
11904a35 168{ /* Bridge is ifc->master */
11904a35
SH
169 TST((ifc->port_index = get_bridge_portno(ifc->name)) >= 0, -1);
170
171 /* Add port to STP */
172 instance_begin(ifc->master);
173 int r = STP_IN_port_create(0, ifc->port_index);
174 if (r == 0) { /* Update bridge ID */
175 UID_STP_STATE_T state;
176 STP_IN_stpm_get_state(0, &state);
177 ifc->master->bridge_id = state.bridge_id;
178 }
179 instance_end();
180 if (r /* check for failure */ ) {
181 ERROR("Couldn't add port for ifindex %d to STP", ifc->if_index);
182 return -1;
183 }
184 return 0;
ad02a0eb
SH
185}
186
187void remove_port_stp(struct ifdata *ifc)
188{
11904a35
SH
189 /* Remove port from STP */
190 instance_begin(ifc->master);
191 int r = STP_IN_port_delete(0, ifc->port_index);
192 instance_end();
193 ifc->port_index = -1;
194 if (r != 0) {
195 ERROR("removing port %s failed for bridge %s: %s",
196 ifc->name, ifc->master->name,
197 STP_IN_get_error_explanation(r));
198 }
ad02a0eb
SH
199}
200
201int init_rstplib_instance(struct ifdata *br)
202{
11904a35
SH
203 br->stp = STP_IN_instance_create();
204 if (br->stp == NULL) {
205 ERROR("Couldn't create STP instance for bridge %s", br->name);
206 return -1;
207 }
ad02a0eb 208
11904a35
SH
209 BITMAP_T ports;
210 BitmapClear(&ports);
211 instance_begin(br);
212 int r = STP_IN_stpm_create(0, br->name, &ports);
213 instance_end();
214 if (r != 0) {
215 ERROR("stpm create failed for bridge %s: %s",
216 br->name, STP_IN_get_error_explanation(r));
217 return -1;
218 }
ad02a0eb 219
11904a35 220 return 0;
ad02a0eb
SH
221}
222
223void clear_rstplib_instance(struct ifdata *br)
224{
11904a35
SH
225 instance_begin(br);
226 int r = STP_IN_delete_all();
227 instance_end();
228 if (r != 0) {
229 ERROR("stpm delete failed for bridge %s: %s",
230 br->name, STP_IN_get_error_explanation(r));
231 }
232
233 STP_IN_instance_delete(br->stp);
234 br->stp = NULL;
ad02a0eb
SH
235}
236
237int init_bridge_stp(struct ifdata *br)
238{
11904a35
SH
239 if (br->stp_up) {
240 ERROR("STP already started");
241 return 0;
242 }
243
244 /* Init STP state */
245 TST(init_rstplib_instance(br) == 0, -1);
246
247 struct ifdata *p = br->port_list;
248 while (p) {
249 if (add_port_stp(p) != 0)
250 break;
251 p = p->port_next;
252 }
253 if (p) {
254 struct ifdata *q = br->port_list;
255 while (q != p) {
256 remove_port_stp(q);
257 q = q->port_next;
258 }
259 /* Clear bridge STP state */
260 clear_rstplib_instance(br);
261 return -1;
262 }
263 br->stp_up = 1;
264 return 0;
ad02a0eb
SH
265}
266
267void clear_bridge_stp(struct ifdata *br)
268{
11904a35
SH
269 if (!br->stp_up)
270 return;
271 br->stp_up = 0;
272 struct ifdata *p = br->port_list;
273 while (p) {
274 remove_port_stp(p);
275 p = p->port_next;
276 }
277 /* Clear bridge STP state */
278 clear_rstplib_instance(br);
ad02a0eb
SH
279}
280
ad02a0eb
SH
281struct ifdata *if_head = NULL;
282struct ifdata *br_head = NULL;
283
284struct ifdata *find_if(int if_index)
285{
11904a35
SH
286 struct ifdata *p = if_head;
287 while (p && p->if_index != if_index)
288 p = p->next;
289 return p;
ad02a0eb
SH
290}
291
292#define ADD_TO_LIST(_list, _next, _ifc) \
293 do { \
294 (_ifc)->_next = (_list); \
295 (_list) = (_ifc); \
296 } while (0)
297
298#define REMOVE_FROM_LIST(_list, _next, _ifc, _error_fmt, _args...) \
299 do { \
300 struct ifdata **_prev = &(_list); \
301 while (*_prev && *_prev != (_ifc)) \
302 _prev = &(*_prev)->_next; \
303 if (*_prev != (_ifc)) \
304 ERROR(_error_fmt, ##_args); \
305 else \
306 *_prev = (_ifc)->_next; \
307 } while (0)
308
309/* Caller ensures that there isn't any ifdata with this index */
310/* If br is NULL, new interface is a bridge, else it is a port of br */
311struct ifdata *create_if(int if_index, struct ifdata *br)
312{
11904a35
SH
313 struct ifdata *p;
314 TST((p = malloc(sizeof(*p))) != NULL, NULL);
315
f2592588
SH
316 memset(p, 0, sizeof(*p));
317
11904a35
SH
318 /* Init fields */
319 p->if_index = if_index;
320 p->is_bridge = (br == NULL);
f2592588
SH
321
322 /* TODO: purge use of name, due to issue with renameing */
11904a35 323 if_indextoname(if_index, p->name);
f2592588 324
11904a35
SH
325 if (p->is_bridge) {
326 INFO("Add bridge %s", p->name);
327 /* Init slave list */
328 p->port_list = NULL;
329
330 p->do_stp = 0;
331 p->up = 0;
332 p->stp_up = 0;
333 p->stp = NULL;
334 update_bridge_stp_config(p, &default_bridge_stp_cfg);
335 ADD_TO_LIST(br_head, bridge_next, p); /* Add to bridge list */
336 } else {
337 INFO("Add iface %s to bridge %s", p->name, br->name);
338 p->up = 0;
339 p->speed = 0;
340 p->duplex = 0;
341 p->master = br;
f2592588 342
11904a35
SH
343 update_port_stp_config(p, &default_port_stp_cfg);
344 ADD_TO_LIST(br->port_list, port_next, p); /* Add to bridge port list */
f2592588 345
11904a35
SH
346 if (br->stp_up) {
347 add_port_stp(p);
348 }
349 }
f2592588 350
11904a35
SH
351 /* Add to interface list */
352 ADD_TO_LIST(if_head, next, p);
353
354 return p;
ad02a0eb
SH
355}
356
357void delete_if(struct ifdata *ifc)
358{
11904a35
SH
359 INFO("Delete iface %s", ifc->name);
360 if (ifc->is_bridge) { /* Bridge: */
361 /* Stop STP */
362 clear_bridge_stp(ifc);
363 /* Delete ports */
364 while (ifc->port_list)
365 delete_if(ifc->port_list);
366 /* Remove from bridge list */
367 REMOVE_FROM_LIST(br_head, bridge_next, ifc,
368 "Can't find interface ifindex %d bridge list",
369 ifc->if_index);
370 } else { /* Port */
371 if (ifc->master->stp_up)
372 remove_port_stp(ifc);
373 /* Remove from bridge port list */
374 REMOVE_FROM_LIST(ifc->master->port_list, port_next, ifc,
375 "Can't find interface ifindex %d on br %d's port list",
376 ifc->if_index, ifc->master->if_index);
377 }
f2592588 378
11904a35
SH
379 /* Remove from bridge interface list */
380 REMOVE_FROM_LIST(if_head, next, ifc,
381 "Can't find interface ifindex %d on iflist",
382 ifc->if_index);
f2592588 383 free(ifc);
ad02a0eb
SH
384}
385
358260ff
SH
386static int stp_enabled(struct ifdata *br)
387{
388 char path[40 + IFNAMSIZ];
76eb7423 389 int ret;
358260ff
SH
390 sprintf(path, "/sys/class/net/%s/bridge/stp_state", br->name);
391 FILE *f = fopen(path, "r");
392 if (!f) {
393 LOG("Open %s failed", path);
394 return 0;
395 }
396 int enabled = 0;
76eb7423
DF
397 ret = fscanf(f, "%d", &enabled);
398 if (!ret) {
399 LOG("%s, stp_state parsing error", path);
400 return 0;
401 }
358260ff
SH
402 fclose(f);
403 INFO("STP on %s state %d", br->name, enabled);
404
405 return enabled == 2; /* ie user mode STP */
406}
407
d19d0e35 408static void set_br_up(struct ifdata *br, int up)
ad02a0eb 409{
358260ff 410 int stp_up = stp_enabled(br);
d19d0e35
SH
411 INFO("%s was %s stp was %s", br->name,
412 up ? "up" : "down",
413 br->stp_up ? "up" : "down");
358260ff 414 INFO("Set bridge %s %s stp %s" , br->name,
d19d0e35
SH
415 up ? "up" : "down",
416 stp_up ? "up" : "down");
358260ff
SH
417
418 if (up != br->up)
11904a35 419 br->up = up;
358260ff
SH
420
421 if (br->stp_up != stp_up) {
422 if (stp_up)
423 init_bridge_stp(br);
424 else
425 clear_bridge_stp(br);
11904a35 426 }
ad02a0eb
SH
427}
428
d19d0e35 429static void set_if_up(struct ifdata *ifc, int up)
ad02a0eb 430{
11904a35
SH
431 INFO("Port %s : %s", ifc->name, (up ? "up" : "down"));
432 int speed = -1;
433 int duplex = -1;
434 int notify_flags = 0;
435 const int NOTIFY_UP = 1, NOTIFY_SPEED = 2, NOTIFY_DUPLEX = 4;
436 if (!up) { /* Down */
437 if (ifc->up) {
438 ifc->up = up;
439 notify_flags |= NOTIFY_UP;
440 }
441 } else { /* Up */
442 int r = ethtool_get_speed_duplex(ifc->name, &speed, &duplex);
443 if (r < 0) { /* Didn't succeed */
444 }
445 if (speed < 0)
446 speed = 10;
447 if (duplex < 0)
448 duplex = 0; /* Assume half duplex */
449
450 if (speed != ifc->speed) {
451 ifc->speed = speed;
452 notify_flags |= NOTIFY_SPEED;
453 }
454 if (duplex != ifc->duplex) {
455 ifc->duplex = duplex;
456 notify_flags |= NOTIFY_DUPLEX;
457 }
458 if (!ifc->up) {
459 ifc->up = 1;
460 notify_flags |= NOTIFY_UP;
461 }
462 }
463 if (notify_flags && ifc->master->stp_up) {
464 instance_begin(ifc->master);
465
466 if (notify_flags & NOTIFY_SPEED)
467 STP_IN_changed_port_speed(ifc->port_index, speed);
468 if (notify_flags & NOTIFY_DUPLEX)
469 STP_IN_changed_port_duplex(ifc->port_index);
470 if (notify_flags & NOTIFY_UP)
471 STP_IN_enable_port(ifc->port_index, ifc->up);
472
473 instance_end();
474 }
ad02a0eb
SH
475}
476
477/*------------------------------------------------------------*/
478
968d3d40
SH
479int bridge_notify(int br_index, int if_index, int newlink,
480 unsigned flags)
ad02a0eb 481{
11904a35 482 struct ifdata *br = NULL;
968d3d40
SH
483
484 LOG("br_index %d, if_index %d, up %d running %d",
485 br_index, if_index, (flags & IFF_UP), flags & IFF_RUNNING);
486
11904a35
SH
487 if (br_index >= 0) {
488 br = find_if(br_index);
489 if (br && !br->is_bridge) {
490 ERROR
491 ("Notification shows non bridge interface %d as bridge.",
492 br_index);
493 return -1;
494 }
495 if (!br)
496 br = create_if(br_index, NULL);
497 if (!br) {
498 ERROR("Couldn't create data for bridge interface %d",
499 br_index);
500 return -1;
501 }
502 /* Bridge must be up if we get such notifications */
503 if (!br->up)
504 set_br_up(br, 1);
505 }
506
507 struct ifdata *ifc = find_if(if_index);
508
509 if (br) {
510 if (ifc) {
511 if (ifc->is_bridge) {
512 ERROR
513 ("Notification shows bridge interface %d as slave of %d",
514 if_index, br_index);
515 return -1;
516 }
517 if (ifc->master != br) {
518 INFO("Device %d has come to bridge %d. "
519 "Missed notify for deletion from bridge %d",
520 if_index, br_index, ifc->master->if_index);
521 delete_if(ifc);
522 ifc = NULL;
523 }
524 }
525 if (!ifc)
526 ifc = create_if(if_index, br);
527 if (!ifc) {
528 ERROR
529 ("Couldn't create data for interface %d (master %d)",
530 if_index, br_index);
531 return -1;
532 }
533 if (!newlink && !is_bridge_slave(br->name, ifc->name)) {
534 /* brctl delif generates a DELLINK, but so does ifconfig <slave> down.
535 So check and delete if it has been removed.
536 */
537 delete_if(ifc);
538 return 0;
539 }
968d3d40
SH
540 int up = (flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING);
541
11904a35
SH
542 if (ifc->up != up)
543 set_if_up(ifc, up); /* And speed and duplex */
544 } else { /* No br_index */
545 if (!newlink) {
546 /* DELLINK not from bridge means interface unregistered. */
547 /* Cleanup removed bridge or removed bridge slave */
548 if (ifc)
549 delete_if(ifc);
550 return 0;
551 } else { /* This may be a new link */
552 if (!ifc) {
553 char ifname[IFNAMSIZ];
554 if (if_indextoname(if_index, ifname)
555 && is_bridge(ifname)) {
556 ifc = create_if(if_index, NULL);
557 if (!ifc) {
558 ERROR
559 ("Couldn't create data for bridge interface %d",
560 if_index);
561 return -1;
562 }
563 }
564 }
565 if (ifc && !ifc->is_bridge &&
566 !is_bridge_slave(ifc->master->name, ifc->name)) {
567 /* Interface might have left bridge and we might have missed deletion */
568 delete_if(ifc);
569 return 0;
570 }
968d3d40
SH
571
572 if (ifc) {
573 if (ifc->is_bridge) {
574 int up = (flags & IFF_UP) != 0;
575 if (ifc->up != up)
576 set_br_up(ifc, up);
577 } else {
578 int up = (flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING);
579
580 if (ifc->up != up)
581 set_if_up(ifc, up);
582 }
11904a35
SH
583 }
584 }
585 }
586 return 0;
ad02a0eb
SH
587}
588
96e20123 589void bridge_bpdu_rcv(int if_index, const unsigned char *data, int len)
ad02a0eb 590{
96e20123 591 struct ifdata *ifc = find_if(if_index);
358260ff 592 BPDU_T *bpdu = (BPDU_T *) (data + sizeof(MAC_HEADER_T));
f2592588 593
96e20123 594 LOG("ifindex %d, len %d", if_index, len);
b79b9a98 595 if (!ifc || !ifc->master)
96e20123
SH
596 return;
597
358260ff
SH
598 TST(ifc->up,);
599 TST(ifc->master->stp_up,);
600 TST(len > sizeof(MAC_HEADER_T) + sizeof(ETH_HEADER_T) + sizeof(BPDU_HEADER_T),);
f2592588 601
11904a35 602 /* Do some validation */
358260ff
SH
603 if (bpdu->hdr.protocol[0] || bpdu->hdr.protocol[1])
604 return;
605
606 switch (bpdu->hdr.bpdu_type) {
11904a35
SH
607 case BPDU_RSTP:
608 TST(len >= 36,);
609 case BPDU_CONFIG_TYPE:
610 TST(len >= 35,);
611 /* 802.1w doesn't ask for this */
612 // TST(ntohs(*(uint16_t*)bpdu.body.message_age)
613 // < ntohs(*(uint16_t*)bpdu.body.max_age), );
358260ff
SH
614 TST(memcmp(bpdu->body.bridge_id, &ifc->master->bridge_id, 8) != 0
615 || (ntohs(*(uint16_t *) bpdu->body.port_id) & 0xfff) !=
11904a35
SH
616 ifc->port_index,);
617 break;
618 case BPDU_TOPO_CHANGE_TYPE:
619 break;
620 default:
358260ff
SH
621 LOG("Receive unknown bpdu type %x", bpdu->hdr.bpdu_type);
622 return;
11904a35
SH
623 }
624
625 // dump_hex(data, len);
626 instance_begin(ifc->master);
358260ff 627 int r = STP_IN_rx_bpdu(0, ifc->port_index, bpdu, len);
11904a35
SH
628 if (r)
629 ERROR("STP_IN_rx_bpdu on port %s returned %s", ifc->name,
630 STP_IN_get_error_explanation(r));
631 instance_end();
ad02a0eb
SH
632}
633
634void bridge_one_second(void)
635{
11904a35
SH
636 // LOG("");
637 struct ifdata *br;
638 for (br = br_head; br; br = br->bridge_next) {
639 if (br->stp_up) {
640 instance_begin(br);
641 STP_IN_one_second();
642 instance_end();
643 }
644 }
645
646 /* To get information about port changes when bridge is down */
647 /* But won't work so well since we will not sense deletions */
648 static int count = 0;
649 count++;
650 if (count % 60 == 0)
651 bridge_get_configuration();
ad02a0eb
SH
652
653}
654
655/* Implementing STP_OUT functions */
656
657int flush_port(char *sys_name)
658{
11904a35
SH
659 FILE *f = fopen(sys_name, "w");
660 TSTM(f, -1, "Couldn't open flush file %s for write.", sys_name);
661 int r = fwrite("1", 1, 1, f);
662 fclose(f);
663 TST(r == 1, -1);
664 return 0;
ad02a0eb
SH
665}
666
667int
11904a35
SH
668STP_OUT_flush_lt(IN int port_index, IN int vlan_id,
669 IN LT_FLASH_TYPE_T type, IN char *reason)
670{
671 LOG("port index %d, flash type %d, reason %s", port_index, type,
672 reason);
673 TST(vlan_id == 0, 0);
674
675 char fname[128];
676 if (port_index == 0) { /* i.e. passed port_index was 0 */
677 sprintf(fname, "/sys/class/net/%s/bridge/flush",
678 current_br->name);
679 flush_port(fname);
680 } else if (type == LT_FLASH_ONLY_THE_PORT) {
681 struct ifdata *port = find_port(port_index);
682 TST(port != NULL, 0);
683 sprintf(fname, "/sys/class/net/%s/brif/%s/flush",
684 current_br->name, port->name);
685 flush_port(fname);
686 } else if (type == LT_FLASH_ALL_PORTS_EXCLUDE_THIS) {
687 struct ifdata *port;
688 for (port = current_br->port_list; port; port = port->port_next) {
689 if (port->port_index != port_index) {
690 sprintf(fname,
691 "/sys/class/net/%s/brif/%s/flush",
692 current_br->name, port->name);
693 flush_port(fname);
694 }
695 }
696 } else
697 TST(0, 0);
698
699 return 0;
ad02a0eb
SH
700}
701
11904a35
SH
702void /* for bridge id calculation */ STP_OUT_get_port_mac(IN int port_index,
703 OUT unsigned char
704 *mac)
705{
706 LOG("port index %d", port_index);
707 struct ifdata *port = find_port(port_index);
708 TST(port != NULL,);
709 get_hwaddr(port->name, mac);
ad02a0eb
SH
710}
711
11904a35 712unsigned long STP_OUT_get_port_oper_speed(IN unsigned int port_index)
ad02a0eb 713{
11904a35
SH
714 LOG("port index %d", port_index);
715 struct ifdata *port = find_port(port_index);
716 TST(port != NULL, 0);
717 LOG("Speed: %d", port->speed);
718 return port->speed;
ad02a0eb
SH
719}
720
11904a35 721int /* 1- Up, 0- Down */ STP_OUT_get_port_link_status(IN int port_index)
ad02a0eb 722{
11904a35
SH
723 LOG("port index %d", port_index);
724 struct ifdata *port = find_port(port_index);
725 TST(port != NULL, 0);
726 LOG("Link status: %d", port->up);
727 return port->up;
ad02a0eb
SH
728}
729
11904a35 730int /* 1- Full, 0- Half */ STP_OUT_get_duplex(IN int port_index)
ad02a0eb 731{
11904a35
SH
732 LOG("port index %d", port_index);
733 struct ifdata *port = find_port(port_index);
734 TST(port != NULL, 0);
735 LOG("Duplex: %d", port->duplex);
736 return port->duplex;
737}
738
739int
740STP_OUT_set_port_state(IN int port_index, IN int vlan_id,
741 IN RSTP_PORT_STATE state)
742{
743 LOG("port index %d, state %d", port_index, state);
744 struct ifdata *port = find_port(port_index);
745 TST(port != NULL, 0);
746 TST(vlan_id == 0, 0);
747
748 int br_state;
749 switch (state) {
750 case UID_PORT_DISCARDING:
751 br_state = BR_STATE_BLOCKING;
752 break;
753 case UID_PORT_LEARNING:
754 br_state = BR_STATE_LEARNING;
755 break;
756 case UID_PORT_FORWARDING:
757 br_state = BR_STATE_FORWARDING;
758 break;
759 default:
760 fprintf(stderr, "set_port_state: Unexpected state %d\n", state);
761 return -1;
762 }
763 if (port->up)
764 bridge_set_state(port->if_index, br_state);
765 return 0;
766}
767
768int STP_OUT_set_hardware_mode(int vlan_id, UID_STP_MODE_T mode)
769{
770 LOG("vlan id %d, mode %d", vlan_id, mode);
771 return 0;
ad02a0eb
SH
772}
773
774int
11904a35
SH
775STP_OUT_tx_bpdu(IN int port_index, IN int vlan_id,
776 IN unsigned char *bpdu, IN size_t bpdu_len)
ad02a0eb 777{
11904a35
SH
778 LOG("port index %d, len %zd", port_index, bpdu_len);
779 struct ifdata *port = find_port(port_index);
780 TST(port != NULL, 0);
781 TST(vlan_id == 0, 0);
358260ff
SH
782
783 packet_send(port->if_index, bpdu,
40f958aa 784 bpdu_len + sizeof(MAC_HEADER_T) + sizeof(ETH_HEADER_T));
11904a35
SH
785 return 0;
786}
ad02a0eb 787
11904a35
SH
788const char *STP_OUT_get_port_name(IN int port_index)
789{
790 LOG("port index %d", port_index);
791 struct ifdata *port = find_port(port_index);
792 TST(port != NULL, 0);
793 return port->name;
794}
ad02a0eb 795
11904a35
SH
796int STP_OUT_get_init_stpm_cfg(IN int vlan_id, INOUT UID_STP_CFG_T * cfg)
797{
798 LOG("");
799 TST(vlan_id == 0, 0);
800
801 cfg->bridge_priority = current_br->bridge_priority;
802 cfg->max_age = current_br->max_age;
803 cfg->hello_time = current_br->hello_time;
804 cfg->forward_delay = current_br->forward_delay;
805 cfg->force_version = current_br->force_version;
806
807 return 0;
ad02a0eb
SH
808}
809
810int
11904a35
SH
811STP_OUT_get_init_port_cfg(IN int vlan_id,
812 IN int port_index, INOUT UID_STP_PORT_CFG_T * cfg)
ad02a0eb 813{
11904a35
SH
814 LOG("port index %d", port_index);
815 struct ifdata *port = find_port(port_index);
816 TST(port != NULL, 0);
817 TST(vlan_id == 0, 0);
ad02a0eb 818
11904a35
SH
819 cfg->port_priority = port->port_priority;
820 cfg->admin_non_stp = port->admin_non_stp;
821 cfg->admin_edge = port->admin_edge;
822 cfg->admin_port_path_cost = port->admin_port_path_cost;
823 cfg->admin_point2point = port->admin_point2point;
ad02a0eb 824
11904a35 825 return 0;
ad02a0eb
SH
826}
827
11904a35 828extern void stp_trace(const char *fmt, ...)
ad02a0eb 829{
11904a35
SH
830 va_list ap;
831 va_start(ap, fmt);
832 vDprintf(LOG_LEVEL_RSTPLIB, fmt, ap);
833 va_end(ap);
ad02a0eb
SH
834}
835
836/* Commands and status */
837#include "ctl_functions.h"
838
839#define CTL_CHECK_BRIDGE \
840 struct ifdata *br = find_if(br_index); \
841 if (br == NULL || !br->is_bridge) return Err_Interface_not_a_bridge; \
842 if (!br->do_stp) return Err_Bridge_RSTP_not_enabled; \
843 if (!br->stp_up) return Err_Bridge_is_down; \
844 do { } while (0)
845
846#define CTL_CHECK_BRIDGE_PORT \
847 CTL_CHECK_BRIDGE; \
848 struct ifdata *port = find_if(port_index); \
849 if (port == NULL || port->is_bridge || port->master != br) \
850 return Err_Port_does_not_belong_to_bridge; \
851 do { } while (0)
852
853int CTL_enable_bridge_rstp(int br_index, int enable)
854{
11904a35
SH
855 INFO("bridge %d, enable %d", br_index, enable);
856 int r = 0;
857 if (enable)
858 enable = 1;
859 struct ifdata *br = find_if(br_index);
860 if (br == NULL) {
861 char ifname[IFNAMSIZ];
862 if (if_indextoname(br_index, ifname) && is_bridge(ifname))
863 br = create_if(br_index, NULL);
864 }
865 if (br == NULL || !br->is_bridge)
866 return Err_Interface_not_a_bridge;
867 if (br->do_stp != enable) {
868 br->do_stp = enable;
869 if (br->up)
870 r = enable ? init_bridge_stp(br)
871 : (clear_bridge_stp(br), 0);
872 }
873 return r;
ad02a0eb
SH
874}
875
876int CTL_get_bridge_state(int br_index,
11904a35
SH
877 UID_STP_CFG_T * cfg, UID_STP_STATE_T * state)
878{
879 LOG("bridge %d", br_index);
880 CTL_CHECK_BRIDGE;
881 int r;
882 instance_begin(br);
883 r = STP_IN_stpm_get_state(0, state);
884 if (r) {
885 ERROR("Error getting bridge state for %d: %s", br_index,
886 STP_IN_get_error_explanation(r));
887 instance_end();
888 return r;
889 }
890 r = STP_IN_stpm_get_cfg(0, cfg);
891 if (r) {
892 ERROR("Error getting bridge config for %d: %s", br_index,
893 STP_IN_get_error_explanation(r));
894 instance_end();
895 return r;
896 }
897 instance_end();
898 return 0;
899}
900
901int CTL_set_bridge_config(int br_index, UID_STP_CFG_T * cfg)
902{
903 INFO("bridge %d, flags %#lx", br_index, cfg->field_mask);
904 CTL_CHECK_BRIDGE;
905 int r;
906 instance_begin(br);
907 r = STP_IN_stpm_set_cfg(0, NULL, cfg);
908 if (r) {
909 ERROR("Error setting bridge config for %d: %s", br_index,
910 STP_IN_get_error_explanation(r));
911 instance_end();
912 return r;
913 }
914 instance_end();
915 /* Change init config in ifdata so it will be applied if we
916 disable and enable rstp */
917 update_bridge_stp_config(br, cfg);
918 return 0;
ad02a0eb
SH
919}
920
921int CTL_get_port_state(int br_index, int port_index,
11904a35
SH
922 UID_STP_PORT_CFG_T * cfg, UID_STP_PORT_STATE_T * state)
923{
924 LOG("bridge %d port %d", br_index, port_index);
925 CTL_CHECK_BRIDGE_PORT;
926 int r;
927 instance_begin(br);
928 state->port_no = port->port_index;
929 r = STP_IN_port_get_state(0, state);
930 if (r) {
931 ERROR("Error getting port state for port %d, bridge %d: %s",
932 port->port_index, br_index,
933 STP_IN_get_error_explanation(r));
934 instance_end();
935 return r;
936 }
937 r = STP_IN_port_get_cfg(0, port->port_index, cfg);
938 if (r) {
939 ERROR("Error getting port config for port %d, bridge %d: %s",
940 port->port_index, br_index,
941 STP_IN_get_error_explanation(r));
942 instance_end();
943 return r;
944 }
945 instance_end();
946 return 0;
947
948}
949
950int CTL_set_port_config(int br_index, int port_index, UID_STP_PORT_CFG_T * cfg)
951{
952 INFO("bridge %d, port %d, flags %#lx", br_index, port_index,
953 cfg->field_mask);
954 CTL_CHECK_BRIDGE_PORT;
955 int r;
956 instance_begin(br);
957 r = STP_IN_set_port_cfg(0, port->port_index, cfg);
958 if (r) {
959 ERROR("Error setting port config for port %d, bridge %d: %s",
960 port->port_index, br_index,
961 STP_IN_get_error_explanation(r));
962 instance_end();
963 return r;
964 }
965 instance_end();
966 /* Change init config in ifdata so it will be applied if we
967 disable and enable rstp */
968 update_port_stp_config(port, cfg);
969 return 0;
ad02a0eb
SH
970}
971
972int CTL_set_debug_level(int level)
973{
11904a35
SH
974 INFO("level %d", level);
975 log_level = level;
976 return 0;
ad02a0eb
SH
977}
978
ad02a0eb
SH
979#undef CTL_CHECK_BRIDGE_PORT
980#undef CTL_CHECK_BRIDGE