1 /*****************************************************************************
2 Copyright (c) 2006 EMC Corporation.
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)
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
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.
18 The full GNU General Public License is included in this distribution in the
21 Authors: Srinivas Aji <Aji_Srinivas@emc.com>
23 ******************************************************************************/
25 #include "bridge_ctl.h"
26 #include "netif_utils.h"
32 #include <linux/if_bridge.h>
33 #include <linux/if_ether.h>
34 #include <arpa/inet.h>
35 #include <sys/types.h>
48 /*------------------------------------------------------------*/
55 unsigned char macaddr
[ETH_ALEN
];
59 struct ifdata
*bridge_next
;
60 struct ifdata
*port_list
;
63 struct stp_instance
*stp
;
64 UID_BRIDGE_ID_T bridge_id
;
66 UID_STP_MODE_T stp_enabled
;
77 struct ifdata
*master
;
78 struct ifdata
*port_next
;
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 */
88 struct epoll_event_handler event
;
92 struct ifdata
*current_br
= NULL
;
94 void instance_begin(struct ifdata
*br
)
97 ERROR("BUG: Trying to set instance over existing instance.");
98 ERROR("%d", *(int *)0); /* ABORT */
101 STP_IN_instance_begin(br
->stp
);
104 void instance_end(void)
106 STP_IN_instance_end(current_br
->stp
);
110 struct ifdata
*find_port(int port_index
)
112 struct ifdata
*ifc
= current_br
->port_list
;
113 while (ifc
&& ifc
->port_index
!= port_index
)
114 ifc
= ifc
->port_next
;
118 /*************************************************************/
119 /* Bridge and port defaults */
121 UID_STP_CFG_T default_bridge_stp_cfg
= {
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 */
130 void update_bridge_stp_config(struct ifdata
*br
, UID_STP_CFG_T
* cfg
)
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
;
144 UID_STP_PORT_CFG_T default_port_stp_cfg
= {
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
,
153 void update_port_stp_config(struct ifdata
*ifc
, UID_STP_PORT_CFG_T
* cfg
)
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
;
167 /**************************************************************/
169 int add_port_stp(struct ifdata
*ifc
)
170 { /* Bridge is ifc->master */
171 TST((ifc
->port_index
= get_bridge_portno(ifc
->name
)) >= 0, -1);
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
;
182 if (r
/* check for failure */ ) {
183 ERROR("Couldn't add port for ifindex %d to STP", ifc
->if_index
);
189 void remove_port_stp(struct ifdata
*ifc
)
191 /* Remove port from STP */
192 instance_begin(ifc
->master
);
193 int r
= STP_IN_port_delete(0, ifc
->port_index
);
195 ifc
->port_index
= -1;
197 ERROR("removing port %s failed for bridge %s: %s",
198 ifc
->name
, ifc
->master
->name
,
199 STP_IN_get_error_explanation(r
));
203 int init_rstplib_instance(struct ifdata
*br
)
205 br
->stp
= STP_IN_instance_create();
206 if (br
->stp
== NULL
) {
207 ERROR("Couldn't create STP instance for bridge %s", br
->name
);
214 int r
= STP_IN_stpm_create(0, br
->name
, &ports
);
217 ERROR("stpm create failed for bridge %s: %s",
218 br
->name
, STP_IN_get_error_explanation(r
));
225 void clear_rstplib_instance(struct ifdata
*br
)
228 int r
= STP_IN_delete_all();
231 ERROR("stpm delete failed for bridge %s: %s",
232 br
->name
, STP_IN_get_error_explanation(r
));
235 STP_IN_instance_delete(br
->stp
);
239 int init_bridge_stp(struct ifdata
*br
)
242 ERROR("STP already started");
247 TST(init_rstplib_instance(br
) == 0, -1);
249 struct ifdata
*p
= br
->port_list
;
251 if (add_port_stp(p
) != 0)
256 struct ifdata
*q
= br
->port_list
;
261 /* Clear bridge STP state */
262 clear_rstplib_instance(br
);
269 void clear_bridge_stp(struct ifdata
*br
)
274 struct ifdata
*p
= br
->port_list
;
279 /* Clear bridge STP state */
280 clear_rstplib_instance(br
);
283 struct ifdata
*if_head
= NULL
;
284 struct ifdata
*br_head
= NULL
;
286 struct ifdata
*find_if(int if_index
)
288 struct ifdata
*p
= if_head
;
289 while (p
&& p
->if_index
!= if_index
)
294 #define ADD_TO_LIST(_list, _next, _ifc) \
296 (_ifc)->_next = (_list); \
300 #define REMOVE_FROM_LIST(_list, _next, _ifc, _error_fmt, _args...) \
302 struct ifdata **_prev = &(_list); \
303 while (*_prev && *_prev != (_ifc)) \
304 _prev = &(*_prev)->_next; \
305 if (*_prev != (_ifc)) \
306 ERROR(_error_fmt, ##_args); \
308 *_prev = (_ifc)->_next; \
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 */
313 struct ifdata
*create_if(int if_index
, struct ifdata
*br
)
316 TST((p
= malloc(sizeof(*p
))) != NULL
, NULL
);
318 memset(p
, 0, sizeof(*p
));
321 p
->if_index
= if_index
;
322 p
->is_bridge
= (br
== NULL
);
324 /* TODO: purge use of name, due to issue with renameing */
325 if_indextoname(if_index
, p
->name
);
326 get_hwaddr(p
->name
, p
->macaddr
);
329 INFO("Add bridge %s", p
->name
);
330 /* Init slave list */
337 update_bridge_stp_config(p
, &default_bridge_stp_cfg
);
338 ADD_TO_LIST(br_head
, bridge_next
, p
); /* Add to bridge list */
340 INFO("Add iface %s to bridge %s", p
->name
, br
->name
);
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 */
354 /* Add to interface list */
355 ADD_TO_LIST(if_head
, next
, p
);
360 void delete_if(struct ifdata
*ifc
)
362 INFO("Delete iface %s", ifc
->name
);
363 if (ifc
->is_bridge
) { /* Bridge: */
365 clear_bridge_stp(ifc
);
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",
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
);
382 /* Remove from bridge interface list */
383 REMOVE_FROM_LIST(if_head
, next
, ifc
,
384 "Can't find interface ifindex %d on iflist",
389 /* New MAC address is stored in addr, which also holds the old value on entry.
390 Return nonzero if the address changed */
391 static int check_mac_address(char *name
, unsigned char *addr
)
393 unsigned char temp_addr
[6];
394 if (get_hwaddr(name
, temp_addr
)) {
395 /* Error. Ignore the new value */
398 if (memcmp(addr
, temp_addr
, sizeof(temp_addr
)) == 0)
401 memcpy(addr
, temp_addr
, sizeof(temp_addr
));
407 static int stp_enabled(struct ifdata
*br
)
409 char path
[40 + IFNAMSIZ
];
410 sprintf(path
, "/sys/class/net/%s/bridge/stp_state", br
->name
);
411 FILE *f
= fopen(path
, "r");
413 LOG("Open %s failed", path
);
417 fscanf(f
, "%d", &enabled
);
419 INFO("STP on %s state %d", br
->name
, enabled
);
421 return enabled
== 2; /* ie user mode STP */
424 void set_br_up(struct ifdata
*br
, int up
)
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");
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 */
441 if (br
->stp_up
!= stp_up
) {
445 clear_bridge_stp(br
);
449 void set_if_up(struct ifdata
*ifc
, int up
)
451 INFO("Port %s : %s", ifc
->name
, (up
? "up" : "down"));
454 int notify_flags
= 0;
455 const int NOTIFY_UP
= 1, NOTIFY_SPEED
= 2, NOTIFY_DUPLEX
= 4;
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 */
465 if (!up
) { /* Down */
468 notify_flags
|= NOTIFY_UP
;
471 int r
= ethtool_get_speed_duplex(ifc
->name
, &speed
, &duplex
);
472 if (r
< 0) { /* Didn't succeed */
477 duplex
= 0; /* Assume half duplex */
479 if (speed
!= ifc
->speed
) {
481 notify_flags
|= NOTIFY_SPEED
;
483 if (duplex
!= ifc
->duplex
) {
484 ifc
->duplex
= duplex
;
485 notify_flags
|= NOTIFY_DUPLEX
;
489 notify_flags
|= NOTIFY_UP
;
492 if (notify_flags
&& ifc
->master
->stp_up
) {
493 instance_begin(ifc
->master
);
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
);
506 /*------------------------------------------------------------*/
508 int bridge_notify(int br_index
, int if_index
, int newlink
, int up
)
512 LOG("br_index %d, if_index %d, up %d", br_index
, if_index
, up
);
514 struct ifdata
*br
= NULL
;
516 br
= find_if(br_index
);
517 if (br
&& !br
->is_bridge
) {
519 ("Notification shows non bridge interface %d as bridge.",
524 br
= create_if(br_index
, NULL
);
526 ERROR("Couldn't create data for bridge interface %d",
530 /* Bridge must be up if we get such notifications */
534 struct ifdata
*ifc
= find_if(if_index
);
538 if (ifc
->is_bridge
) {
540 ("Notification shows bridge interface %d as slave of %d",
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
);
554 INFO("Got DELLINK for unknown port %d on "
555 "bridge %d", if_index
, br_index
);
558 ifc
= create_if(if_index
, br
);
562 ("Couldn't create data for interface %d (master %d)",
570 set_if_up(ifc
, up
); /* And speed and duplex */
571 } else { /* No br_index */
573 /* DELLINK not from bridge means interface unregistered. */
574 /* Cleanup removed bridge or removed bridge slave */
578 } else { /* This may be a new link */
580 char ifname
[IFNAMSIZ
];
581 if (if_indextoname(if_index
, ifname
)
582 && is_bridge(ifname
)) {
583 ifc
= create_if(if_index
, NULL
);
586 ("Couldn't create data for bridge interface %d",
605 uint8_t dest_addr
[ETH_ALEN
];
606 uint8_t src_addr
[ETH_ALEN
];
608 uint8_t d_sap
; /* 0x42 */
609 uint8_t s_sap
; /* 0x42 */
610 uint8_t llc_ui
; /* 0x03 */
611 } __attribute__((packed
));
613 const unsigned char bridge_group_address
[ETH_ALEN
] = {
614 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00
617 const unsigned char STP_SAP
= 0x42;
619 void bridge_bpdu_rcv(int if_index
, const unsigned char *data
, int len
)
621 struct ifdata
*ifc
= find_if(if_index
);
624 LOG("ifindex %d, len %d", if_index
, len
);
629 TST(ifc
->master
->stp_up
,);
631 /* Validate Ethernet and LLC header */
633 struct llc_header
*h
;
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,
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 */
648 TST(len
> sizeof(ETH_HEADER_T
) + sizeof(BPDU_HEADER_T
),);
650 /* Do some BPDU validation as per 9.3.4 of standard */
651 if (bpdu
->hdr
.protocol
[0] || bpdu
->hdr
.protocol
[1])
654 switch (bpdu
->hdr
.bpdu_type
) {
656 TST(len
>= sizeof(ETH_HEADER_T
) + 36,);
657 case BPDU_CONFIG_TYPE
:
658 TST(len
>= sizeof(ETH_HEADER_T
) + 35,);
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), );
662 TST(memcmp(bpdu
->body
.bridge_id
, &ifc
->master
->bridge_id
, 8) != 0
663 || (ntohs(*(uint16_t *) bpdu
->body
.port_id
) & 0xfff) !=
666 case BPDU_TOPO_CHANGE_TYPE
:
669 LOG("Receive unknown bpdu type %x", bpdu
->hdr
.bpdu_type
);
673 // dump_hex(data, len);
674 instance_begin(ifc
->master
);
675 int r
= STP_IN_rx_bpdu(0, ifc
->port_index
, bpdu
, len
);
677 ERROR("STP_IN_rx_bpdu on port %s returned %s", ifc
->name
,
678 STP_IN_get_error_explanation(r
));
682 void bridge_one_second(void)
686 for (br
= br_head
; br
; br
= br
->bridge_next
) {
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;
699 bridge_get_configuration();
703 /* Implementing STP_OUT functions */
705 int flush_port(char *sys_name
)
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
);
716 STP_OUT_flush_lt(IN
int port_index
, IN
int vlan_id
,
717 IN LT_FLASH_TYPE_T type
, IN
char *reason
)
719 LOG("port index %d, flash type %d, reason %s", port_index
, type
,
721 TST(vlan_id
== 0, 0);
724 if (port_index
== 0) { /* i.e. passed port_index was 0 */
725 sprintf(fname
, "/sys/class/net/%s/bridge/flush",
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
);
734 } else if (type
== LT_FLASH_ALL_PORTS_EXCLUDE_THIS
) {
736 for (port
= current_br
->port_list
; port
; port
= port
->port_next
) {
737 if (port
->port_index
!= port_index
) {
739 "/sys/class/net/%s/brif/%s/flush",
740 current_br
->name
, port
->name
);
750 void /* for bridge id calculation */ STP_OUT_get_port_mac(IN
int port_index
,
754 LOG("port index %d", port_index
);
755 struct ifdata
*port
= find_port(port_index
);
757 memcpy(mac
, port
->macaddr
, sizeof(port
->macaddr
));
760 unsigned long STP_OUT_get_port_oper_speed(IN
unsigned int port_index
)
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
);
769 int /* 1- Up, 0- Down */ STP_OUT_get_port_link_status(IN
int port_index
)
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
);
778 int /* 1- Full, 0- Half */ STP_OUT_get_duplex(IN
int port_index
)
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
);
788 STP_OUT_set_port_state(IN
int port_index
, IN
int vlan_id
,
789 IN RSTP_PORT_STATE state
)
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);
798 case UID_PORT_DISCARDING
:
799 br_state
= BR_STATE_BLOCKING
;
801 case UID_PORT_LEARNING
:
802 br_state
= BR_STATE_LEARNING
;
804 case UID_PORT_FORWARDING
:
805 br_state
= BR_STATE_FORWARDING
;
808 fprintf(stderr
, "set_port_state: Unexpected state %d\n", state
);
812 bridge_set_state(port
->if_index
, br_state
);
816 int STP_OUT_set_hardware_mode(int vlan_id
, UID_STP_MODE_T mode
)
818 LOG("vlan id %d, mode %d", vlan_id
, mode
);
823 STP_OUT_tx_bpdu(IN
int port_index
, IN
int vlan_id
,
824 IN
unsigned char *bpdu
, IN
size_t bpdu_len
)
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);
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 */
839 struct iovec iov
[2] = {
840 { .iov_base
= &h
, .iov_len
= sizeof(h
) },
841 { .iov_base
= bpdu
+ sizeof(h
), .iov_len
= bpdu_len
}
844 packet_send(port
->if_index
, iov
, 2, sizeof(h
) + bpdu_len
);
848 const char *STP_OUT_get_port_name(IN
int port_index
)
850 LOG("port index %d", port_index
);
851 struct ifdata
*port
= find_port(port_index
);
852 TST(port
!= NULL
, 0);
856 int STP_OUT_get_init_stpm_cfg(IN
int vlan_id
, INOUT UID_STP_CFG_T
* cfg
)
859 TST(vlan_id
== 0, 0);
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
;
871 STP_OUT_get_init_port_cfg(IN
int vlan_id
,
872 IN
int port_index
, INOUT UID_STP_PORT_CFG_T
* cfg
)
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);
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
;
888 extern void stp_trace(const char *fmt
, ...)
892 vDprintf(LOG_LEVEL_RSTPLIB
, fmt
, ap
);
896 /* Commands and status */
897 #include "ctl_functions.h"
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; \
906 #define CTL_CHECK_BRIDGE_PORT \
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; \
913 int CTL_enable_bridge_rstp(int br_index
, int enable
)
915 INFO("bridge %d, enable %d", br_index
, enable
);
919 struct ifdata
*br
= find_if(br_index
);
921 char ifname
[IFNAMSIZ
];
922 if (if_indextoname(br_index
, ifname
) && is_bridge(ifname
))
923 br
= create_if(br_index
, NULL
);
925 if (br
== NULL
|| !br
->is_bridge
)
926 return Err_Interface_not_a_bridge
;
927 if (br
->do_stp
!= enable
) {
930 r
= enable
? init_bridge_stp(br
)
931 : (clear_bridge_stp(br
), 0);
936 int CTL_get_bridge_state(int br_index
,
937 UID_STP_CFG_T
* cfg
, UID_STP_STATE_T
* state
)
939 LOG("bridge %d", br_index
);
943 r
= STP_IN_stpm_get_state(0, state
);
945 ERROR("Error getting bridge state for %d: %s", br_index
,
946 STP_IN_get_error_explanation(r
));
950 r
= STP_IN_stpm_get_cfg(0, cfg
);
952 ERROR("Error getting bridge config for %d: %s", br_index
,
953 STP_IN_get_error_explanation(r
));
961 int CTL_set_bridge_config(int br_index
, UID_STP_CFG_T
* cfg
)
963 INFO("bridge %d, flags %#lx", br_index
, cfg
->field_mask
);
967 r
= STP_IN_stpm_set_cfg(0, NULL
, cfg
);
969 ERROR("Error setting bridge config for %d: %s", br_index
,
970 STP_IN_get_error_explanation(r
));
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
);
981 int CTL_get_port_state(int br_index
, int port_index
,
982 UID_STP_PORT_CFG_T
* cfg
, UID_STP_PORT_STATE_T
* state
)
984 LOG("bridge %d port %d", br_index
, port_index
);
985 CTL_CHECK_BRIDGE_PORT
;
988 state
->port_no
= port
->port_index
;
989 r
= STP_IN_port_get_state(0, state
);
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
));
997 r
= STP_IN_port_get_cfg(0, port
->port_index
, cfg
);
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
));
1010 int CTL_set_port_config(int br_index
, int port_index
, UID_STP_PORT_CFG_T
* cfg
)
1012 INFO("bridge %d, port %d, flags %#lx", br_index
, port_index
,
1014 CTL_CHECK_BRIDGE_PORT
;
1017 r
= STP_IN_set_port_cfg(0, port
->port_index
, cfg
);
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
));
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
);
1032 int CTL_set_debug_level(int level
)
1034 INFO("level %d", level
);
1039 #undef CTL_CHECK_BRIDGE_PORT
1040 #undef CTL_CHECK_BRIDGE