]> git.ipfire.org Git - people/ms/rstp.git/blob - bridge_track.c
remove ifdef'd code
[people/ms/rstp.git] / bridge_track.c
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"
27 #include "packet.h"
28
29 #include <unistd.h>
30 #include <net/if.h>
31 #include <stdlib.h>
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
47 /*------------------------------------------------------------*/
48
49 struct 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 */
85
86 struct epoll_event_handler event;
87 };
88
89 /* Instances */
90 struct ifdata *current_br = NULL;
91
92 void instance_begin(struct ifdata *br)
93 {
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);
100 }
101
102 void instance_end(void)
103 {
104 STP_IN_instance_end(current_br->stp);
105 current_br = NULL;
106 }
107
108 struct ifdata *find_port(int port_index)
109 {
110 struct ifdata *ifc = current_br->port_list;
111 while (ifc && ifc->port_index != port_index)
112 ifc = ifc->port_next;
113 return ifc;
114 }
115
116 /*************************************************************/
117 /* Bridge and port defaults */
118
119 UID_STP_CFG_T default_bridge_stp_cfg = {
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 */
126 };
127
128 void update_bridge_stp_config(struct ifdata *br, UID_STP_CFG_T * cfg)
129 {
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;
140 }
141
142 UID_STP_PORT_CFG_T default_port_stp_cfg = {
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,
149 };
150
151 void update_port_stp_config(struct ifdata *ifc, UID_STP_PORT_CFG_T * cfg)
152 {
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;
163 }
164
165 /**************************************************************/
166
167 int add_port_stp(struct ifdata *ifc)
168 { /* Bridge is ifc->master */
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;
185 }
186
187 void remove_port_stp(struct ifdata *ifc)
188 {
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 }
199 }
200
201 int init_rstplib_instance(struct ifdata *br)
202 {
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 }
208
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 }
219
220 return 0;
221 }
222
223 void clear_rstplib_instance(struct ifdata *br)
224 {
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;
235 }
236
237 int init_bridge_stp(struct ifdata *br)
238 {
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;
265 }
266
267 void clear_bridge_stp(struct ifdata *br)
268 {
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);
279 }
280
281 struct ifdata *if_head = NULL;
282 struct ifdata *br_head = NULL;
283
284 struct ifdata *find_if(int if_index)
285 {
286 struct ifdata *p = if_head;
287 while (p && p->if_index != if_index)
288 p = p->next;
289 return p;
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 */
311 struct ifdata *create_if(int if_index, struct ifdata *br)
312 {
313 struct ifdata *p;
314 TST((p = malloc(sizeof(*p))) != NULL, NULL);
315
316 memset(p, 0, sizeof(*p));
317
318 /* Init fields */
319 p->if_index = if_index;
320 p->is_bridge = (br == NULL);
321
322 /* TODO: purge use of name, due to issue with renameing */
323 if_indextoname(if_index, p->name);
324
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;
342
343 if (packet_sock_create(&p->event, p->if_index, p)) {
344 free(p);
345 return NULL;
346 }
347
348 update_port_stp_config(p, &default_port_stp_cfg);
349 ADD_TO_LIST(br->port_list, port_next, p); /* Add to bridge port list */
350
351 if (br->stp_up) {
352 add_port_stp(p);
353 }
354 }
355
356 /* Add to interface list */
357 ADD_TO_LIST(if_head, next, p);
358
359 return p;
360 }
361
362 void delete_if(struct ifdata *ifc)
363 {
364 INFO("Delete iface %s", ifc->name);
365 if (ifc->is_bridge) { /* Bridge: */
366 /* Stop STP */
367 clear_bridge_stp(ifc);
368 /* Delete ports */
369 while (ifc->port_list)
370 delete_if(ifc->port_list);
371 /* Remove from bridge list */
372 REMOVE_FROM_LIST(br_head, bridge_next, ifc,
373 "Can't find interface ifindex %d bridge list",
374 ifc->if_index);
375 } else { /* Port */
376 if (ifc->master->stp_up)
377 remove_port_stp(ifc);
378 /* Remove from bridge port list */
379 REMOVE_FROM_LIST(ifc->master->port_list, port_next, ifc,
380 "Can't find interface ifindex %d on br %d's port list",
381 ifc->if_index, ifc->master->if_index);
382 packet_sock_delete(&ifc->event);
383 }
384
385 /* Remove from bridge interface list */
386 REMOVE_FROM_LIST(if_head, next, ifc,
387 "Can't find interface ifindex %d on iflist",
388 ifc->if_index);
389 free(ifc);
390 }
391
392 void set_br_up(struct ifdata *br, int up)
393 {
394 if (up != br->up) {
395 br->up = up;
396 if (br->do_stp)
397 up ? (void)init_bridge_stp(br) : clear_bridge_stp(br);
398 }
399 }
400
401 void set_if_up(struct ifdata *ifc, int up)
402 {
403 INFO("Port %s : %s", ifc->name, (up ? "up" : "down"));
404 int speed = -1;
405 int duplex = -1;
406 int notify_flags = 0;
407 const int NOTIFY_UP = 1, NOTIFY_SPEED = 2, NOTIFY_DUPLEX = 4;
408 if (!up) { /* Down */
409 if (ifc->up) {
410 ifc->up = up;
411 notify_flags |= NOTIFY_UP;
412 }
413 } else { /* Up */
414 int r = ethtool_get_speed_duplex(ifc->name, &speed, &duplex);
415 if (r < 0) { /* Didn't succeed */
416 }
417 if (speed < 0)
418 speed = 10;
419 if (duplex < 0)
420 duplex = 0; /* Assume half duplex */
421
422 if (speed != ifc->speed) {
423 ifc->speed = speed;
424 notify_flags |= NOTIFY_SPEED;
425 }
426 if (duplex != ifc->duplex) {
427 ifc->duplex = duplex;
428 notify_flags |= NOTIFY_DUPLEX;
429 }
430 if (!ifc->up) {
431 ifc->up = 1;
432 notify_flags |= NOTIFY_UP;
433 }
434 }
435 if (notify_flags && ifc->master->stp_up) {
436 instance_begin(ifc->master);
437
438 if (notify_flags & NOTIFY_SPEED)
439 STP_IN_changed_port_speed(ifc->port_index, speed);
440 if (notify_flags & NOTIFY_DUPLEX)
441 STP_IN_changed_port_duplex(ifc->port_index);
442 if (notify_flags & NOTIFY_UP)
443 STP_IN_enable_port(ifc->port_index, ifc->up);
444
445 instance_end();
446 }
447 }
448
449 /*------------------------------------------------------------*/
450
451 int bridge_notify(int br_index, int if_index, int newlink, int up)
452 {
453 if (up)
454 up = 1;
455 LOG("br_index %d, if_index %d, up %d", br_index, if_index, up);
456
457 struct ifdata *br = NULL;
458 if (br_index >= 0) {
459 br = find_if(br_index);
460 if (br && !br->is_bridge) {
461 ERROR
462 ("Notification shows non bridge interface %d as bridge.",
463 br_index);
464 return -1;
465 }
466 if (!br)
467 br = create_if(br_index, NULL);
468 if (!br) {
469 ERROR("Couldn't create data for bridge interface %d",
470 br_index);
471 return -1;
472 }
473 /* Bridge must be up if we get such notifications */
474 if (!br->up)
475 set_br_up(br, 1);
476 }
477
478 struct ifdata *ifc = find_if(if_index);
479
480 if (br) {
481 if (ifc) {
482 if (ifc->is_bridge) {
483 ERROR
484 ("Notification shows bridge interface %d as slave of %d",
485 if_index, br_index);
486 return -1;
487 }
488 if (ifc->master != br) {
489 INFO("Device %d has come to bridge %d. "
490 "Missed notify for deletion from bridge %d",
491 if_index, br_index, ifc->master->if_index);
492 delete_if(ifc);
493 ifc = NULL;
494 }
495 }
496 if (!ifc)
497 ifc = create_if(if_index, br);
498 if (!ifc) {
499 ERROR
500 ("Couldn't create data for interface %d (master %d)",
501 if_index, br_index);
502 return -1;
503 }
504 if (!newlink && !is_bridge_slave(br->name, ifc->name)) {
505 /* brctl delif generates a DELLINK, but so does ifconfig <slave> down.
506 So check and delete if it has been removed.
507 */
508 delete_if(ifc);
509 return 0;
510 }
511 if (ifc->up != up)
512 set_if_up(ifc, up); /* And speed and duplex */
513 } else { /* No br_index */
514 if (!newlink) {
515 /* DELLINK not from bridge means interface unregistered. */
516 /* Cleanup removed bridge or removed bridge slave */
517 if (ifc)
518 delete_if(ifc);
519 return 0;
520 } else { /* This may be a new link */
521 if (!ifc) {
522 char ifname[IFNAMSIZ];
523 if (if_indextoname(if_index, ifname)
524 && is_bridge(ifname)) {
525 ifc = create_if(if_index, NULL);
526 if (!ifc) {
527 ERROR
528 ("Couldn't create data for bridge interface %d",
529 if_index);
530 return -1;
531 }
532 }
533 }
534 if (ifc && !ifc->is_bridge &&
535 !is_bridge_slave(ifc->master->name, ifc->name)) {
536 /* Interface might have left bridge and we might have missed deletion */
537 delete_if(ifc);
538 return 0;
539 }
540 if (ifc && ifc->up != up) {
541 if (ifc->is_bridge)
542 set_br_up(ifc, up);
543 else
544 set_if_up(ifc, up);
545 }
546 }
547 }
548 return 0;
549 }
550
551 void bridge_bpdu_rcv(struct ifdata *ifc, const unsigned char *data, int len)
552 {
553 TST(ifc && !ifc->is_bridge,);
554 TST(ifc->up && ifc->master->stp_up,);
555 BPDU_T bpdu;
556
557 memset(&bpdu.eth, 0, sizeof(bpdu.eth));
558 if (len > sizeof(bpdu) - sizeof(bpdu.eth))
559 len = sizeof(bpdu) - sizeof(bpdu.eth);
560 memcpy(&bpdu.hdr, data, len);
561
562 /* Do some validation */
563 TST(len >= 4,);
564 TST(bpdu.hdr.protocol[0] == 0 && bpdu.hdr.protocol[1] == 0,);
565 switch (bpdu.hdr.bpdu_type) {
566 case BPDU_RSTP:
567 TST(len >= 36,);
568 case BPDU_CONFIG_TYPE:
569 TST(len >= 35,);
570 /* 802.1w doesn't ask for this */
571 // TST(ntohs(*(uint16_t*)bpdu.body.message_age)
572 // < ntohs(*(uint16_t*)bpdu.body.max_age), );
573 TST(memcmp(bpdu.body.bridge_id, &ifc->master->bridge_id, 8) != 0
574 || (ntohs(*(uint16_t *) bpdu.body.port_id) & 0xfff) !=
575 ifc->port_index,);
576 break;
577 case BPDU_TOPO_CHANGE_TYPE:
578 break;
579 default:
580 TST(0,);
581 }
582
583 // dump_hex(data, len);
584 instance_begin(ifc->master);
585 int r =
586 STP_IN_rx_bpdu(0, ifc->port_index, &bpdu, len + sizeof(bpdu.eth));
587 if (r)
588 ERROR("STP_IN_rx_bpdu on port %s returned %s", ifc->name,
589 STP_IN_get_error_explanation(r));
590 instance_end();
591 }
592
593 void bridge_one_second(void)
594 {
595 // LOG("");
596 struct ifdata *br;
597 for (br = br_head; br; br = br->bridge_next) {
598 if (br->stp_up) {
599 instance_begin(br);
600 STP_IN_one_second();
601 instance_end();
602 }
603 }
604
605 /* To get information about port changes when bridge is down */
606 /* But won't work so well since we will not sense deletions */
607 static int count = 0;
608 count++;
609 if (count % 60 == 0)
610 bridge_get_configuration();
611
612 }
613
614 /* Implementing STP_OUT functions */
615
616 int flush_port(char *sys_name)
617 {
618 FILE *f = fopen(sys_name, "w");
619 TSTM(f, -1, "Couldn't open flush file %s for write.", sys_name);
620 int r = fwrite("1", 1, 1, f);
621 fclose(f);
622 TST(r == 1, -1);
623 return 0;
624 }
625
626 int
627 STP_OUT_flush_lt(IN int port_index, IN int vlan_id,
628 IN LT_FLASH_TYPE_T type, IN char *reason)
629 {
630 LOG("port index %d, flash type %d, reason %s", port_index, type,
631 reason);
632 TST(vlan_id == 0, 0);
633
634 char fname[128];
635 if (port_index == 0) { /* i.e. passed port_index was 0 */
636 sprintf(fname, "/sys/class/net/%s/bridge/flush",
637 current_br->name);
638 flush_port(fname);
639 } else if (type == LT_FLASH_ONLY_THE_PORT) {
640 struct ifdata *port = find_port(port_index);
641 TST(port != NULL, 0);
642 sprintf(fname, "/sys/class/net/%s/brif/%s/flush",
643 current_br->name, port->name);
644 flush_port(fname);
645 } else if (type == LT_FLASH_ALL_PORTS_EXCLUDE_THIS) {
646 struct ifdata *port;
647 for (port = current_br->port_list; port; port = port->port_next) {
648 if (port->port_index != port_index) {
649 sprintf(fname,
650 "/sys/class/net/%s/brif/%s/flush",
651 current_br->name, port->name);
652 flush_port(fname);
653 }
654 }
655 } else
656 TST(0, 0);
657
658 return 0;
659 }
660
661 void /* for bridge id calculation */ STP_OUT_get_port_mac(IN int port_index,
662 OUT unsigned char
663 *mac)
664 {
665 LOG("port index %d", port_index);
666 struct ifdata *port = find_port(port_index);
667 TST(port != NULL,);
668 get_hwaddr(port->name, mac);
669 }
670
671 unsigned long STP_OUT_get_port_oper_speed(IN unsigned int port_index)
672 {
673 LOG("port index %d", port_index);
674 struct ifdata *port = find_port(port_index);
675 TST(port != NULL, 0);
676 LOG("Speed: %d", port->speed);
677 return port->speed;
678 }
679
680 int /* 1- Up, 0- Down */ STP_OUT_get_port_link_status(IN int port_index)
681 {
682 LOG("port index %d", port_index);
683 struct ifdata *port = find_port(port_index);
684 TST(port != NULL, 0);
685 LOG("Link status: %d", port->up);
686 return port->up;
687 }
688
689 int /* 1- Full, 0- Half */ STP_OUT_get_duplex(IN int port_index)
690 {
691 LOG("port index %d", port_index);
692 struct ifdata *port = find_port(port_index);
693 TST(port != NULL, 0);
694 LOG("Duplex: %d", port->duplex);
695 return port->duplex;
696 }
697
698 int
699 STP_OUT_set_port_state(IN int port_index, IN int vlan_id,
700 IN RSTP_PORT_STATE state)
701 {
702 LOG("port index %d, state %d", port_index, state);
703 struct ifdata *port = find_port(port_index);
704 TST(port != NULL, 0);
705 TST(vlan_id == 0, 0);
706
707 int br_state;
708 switch (state) {
709 case UID_PORT_DISCARDING:
710 br_state = BR_STATE_BLOCKING;
711 break;
712 case UID_PORT_LEARNING:
713 br_state = BR_STATE_LEARNING;
714 break;
715 case UID_PORT_FORWARDING:
716 br_state = BR_STATE_FORWARDING;
717 break;
718 default:
719 fprintf(stderr, "set_port_state: Unexpected state %d\n", state);
720 return -1;
721 }
722 if (port->up)
723 bridge_set_state(port->if_index, br_state);
724 return 0;
725 }
726
727 int STP_OUT_set_hardware_mode(int vlan_id, UID_STP_MODE_T mode)
728 {
729 LOG("vlan id %d, mode %d", vlan_id, mode);
730 return 0;
731 }
732
733 int
734 STP_OUT_tx_bpdu(IN int port_index, IN int vlan_id,
735 IN unsigned char *bpdu, IN size_t bpdu_len)
736 {
737 LOG("port index %d, len %zd", port_index, bpdu_len);
738 struct ifdata *port = find_port(port_index);
739 TST(port != NULL, 0);
740 TST(vlan_id == 0, 0);
741 // dump_hex(bpdu + sizeof(MAC_HEADER_T) + sizeof(ETH_HEADER_T),
742 // bpdu_len - (sizeof(MAC_HEADER_T) + sizeof(ETH_HEADER_T)));
743 bridge_send_bpdu(port->if_index, bpdu + sizeof(MAC_HEADER_T) + sizeof(ETH_HEADER_T), bpdu_len); // The length we get excludes headers!
744 return 0;
745 }
746
747 const char *STP_OUT_get_port_name(IN int port_index)
748 {
749 LOG("port index %d", port_index);
750 struct ifdata *port = find_port(port_index);
751 TST(port != NULL, 0);
752 return port->name;
753 }
754
755 int STP_OUT_get_init_stpm_cfg(IN int vlan_id, INOUT UID_STP_CFG_T * cfg)
756 {
757 LOG("");
758 TST(vlan_id == 0, 0);
759
760 cfg->bridge_priority = current_br->bridge_priority;
761 cfg->max_age = current_br->max_age;
762 cfg->hello_time = current_br->hello_time;
763 cfg->forward_delay = current_br->forward_delay;
764 cfg->force_version = current_br->force_version;
765
766 return 0;
767 }
768
769 int
770 STP_OUT_get_init_port_cfg(IN int vlan_id,
771 IN int port_index, INOUT UID_STP_PORT_CFG_T * cfg)
772 {
773 LOG("port index %d", port_index);
774 struct ifdata *port = find_port(port_index);
775 TST(port != NULL, 0);
776 TST(vlan_id == 0, 0);
777
778 cfg->port_priority = port->port_priority;
779 cfg->admin_non_stp = port->admin_non_stp;
780 cfg->admin_edge = port->admin_edge;
781 cfg->admin_port_path_cost = port->admin_port_path_cost;
782 cfg->admin_point2point = port->admin_point2point;
783
784 return 0;
785 }
786
787 extern void stp_trace(const char *fmt, ...)
788 {
789 va_list ap;
790 va_start(ap, fmt);
791 vDprintf(LOG_LEVEL_RSTPLIB, fmt, ap);
792 va_end(ap);
793 }
794
795 /* Commands and status */
796 #include "ctl_functions.h"
797
798 #define CTL_CHECK_BRIDGE \
799 struct ifdata *br = find_if(br_index); \
800 if (br == NULL || !br->is_bridge) return Err_Interface_not_a_bridge; \
801 if (!br->do_stp) return Err_Bridge_RSTP_not_enabled; \
802 if (!br->stp_up) return Err_Bridge_is_down; \
803 do { } while (0)
804
805 #define CTL_CHECK_BRIDGE_PORT \
806 CTL_CHECK_BRIDGE; \
807 struct ifdata *port = find_if(port_index); \
808 if (port == NULL || port->is_bridge || port->master != br) \
809 return Err_Port_does_not_belong_to_bridge; \
810 do { } while (0)
811
812 int CTL_enable_bridge_rstp(int br_index, int enable)
813 {
814 INFO("bridge %d, enable %d", br_index, enable);
815 int r = 0;
816 if (enable)
817 enable = 1;
818 struct ifdata *br = find_if(br_index);
819 if (br == NULL) {
820 char ifname[IFNAMSIZ];
821 if (if_indextoname(br_index, ifname) && is_bridge(ifname))
822 br = create_if(br_index, NULL);
823 }
824 if (br == NULL || !br->is_bridge)
825 return Err_Interface_not_a_bridge;
826 if (br->do_stp != enable) {
827 br->do_stp = enable;
828 if (br->up)
829 r = enable ? init_bridge_stp(br)
830 : (clear_bridge_stp(br), 0);
831 }
832 return r;
833 }
834
835 int CTL_get_bridge_state(int br_index,
836 UID_STP_CFG_T * cfg, UID_STP_STATE_T * state)
837 {
838 LOG("bridge %d", br_index);
839 CTL_CHECK_BRIDGE;
840 int r;
841 instance_begin(br);
842 r = STP_IN_stpm_get_state(0, state);
843 if (r) {
844 ERROR("Error getting bridge state for %d: %s", br_index,
845 STP_IN_get_error_explanation(r));
846 instance_end();
847 return r;
848 }
849 r = STP_IN_stpm_get_cfg(0, cfg);
850 if (r) {
851 ERROR("Error getting bridge config for %d: %s", br_index,
852 STP_IN_get_error_explanation(r));
853 instance_end();
854 return r;
855 }
856 instance_end();
857 return 0;
858 }
859
860 int CTL_set_bridge_config(int br_index, UID_STP_CFG_T * cfg)
861 {
862 INFO("bridge %d, flags %#lx", br_index, cfg->field_mask);
863 CTL_CHECK_BRIDGE;
864 int r;
865 instance_begin(br);
866 r = STP_IN_stpm_set_cfg(0, NULL, cfg);
867 if (r) {
868 ERROR("Error setting bridge config for %d: %s", br_index,
869 STP_IN_get_error_explanation(r));
870 instance_end();
871 return r;
872 }
873 instance_end();
874 /* Change init config in ifdata so it will be applied if we
875 disable and enable rstp */
876 update_bridge_stp_config(br, cfg);
877 return 0;
878 }
879
880 int CTL_get_port_state(int br_index, int port_index,
881 UID_STP_PORT_CFG_T * cfg, UID_STP_PORT_STATE_T * state)
882 {
883 LOG("bridge %d port %d", br_index, port_index);
884 CTL_CHECK_BRIDGE_PORT;
885 int r;
886 instance_begin(br);
887 state->port_no = port->port_index;
888 r = STP_IN_port_get_state(0, state);
889 if (r) {
890 ERROR("Error getting port state for port %d, bridge %d: %s",
891 port->port_index, br_index,
892 STP_IN_get_error_explanation(r));
893 instance_end();
894 return r;
895 }
896 r = STP_IN_port_get_cfg(0, port->port_index, cfg);
897 if (r) {
898 ERROR("Error getting port config for port %d, bridge %d: %s",
899 port->port_index, br_index,
900 STP_IN_get_error_explanation(r));
901 instance_end();
902 return r;
903 }
904 instance_end();
905 return 0;
906
907 }
908
909 int CTL_set_port_config(int br_index, int port_index, UID_STP_PORT_CFG_T * cfg)
910 {
911 INFO("bridge %d, port %d, flags %#lx", br_index, port_index,
912 cfg->field_mask);
913 CTL_CHECK_BRIDGE_PORT;
914 int r;
915 instance_begin(br);
916 r = STP_IN_set_port_cfg(0, port->port_index, cfg);
917 if (r) {
918 ERROR("Error setting port config for port %d, bridge %d: %s",
919 port->port_index, br_index,
920 STP_IN_get_error_explanation(r));
921 instance_end();
922 return r;
923 }
924 instance_end();
925 /* Change init config in ifdata so it will be applied if we
926 disable and enable rstp */
927 update_port_stp_config(port, cfg);
928 return 0;
929 }
930
931 int CTL_set_debug_level(int level)
932 {
933 INFO("level %d", level);
934 log_level = level;
935 return 0;
936 }
937
938 #undef CTL_CHECK_BRIDGE_PORT
939 #undef CTL_CHECK_BRIDGE