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