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