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