--- /dev/null
+Index: bridge_ctl.h
+===================================================================
+--- bridge_ctl.h (revision 22)
++++ bridge_ctl.h (revision 27)
+@@ -37,7 +37,7 @@
+ __u8 macaddr[ETH_ALEN];
+ char name[IFNAMSIZ];
+
+- bool up, stp_up;
++ bool up;
+ } sysdep_br_data_t;
+
+ typedef struct
+Index: bridge-stp
+===================================================================
+--- bridge-stp (revision 22)
++++ bridge-stp (revision 27)
+@@ -44,12 +44,12 @@
+ checkpid $pid_file || exit 1
+ for b in $MSTP_BRIDGES; do
+ if [ "$bridge" == "$b" ]; then
+- exec /sbin/mstpctl notify-daemon-that-stp-is-on $bridge
++ exec /sbin/mstpctl addbridge $bridge
+ fi
+ done
+ exit 1 ;;
+ stop)
+- exec /sbin/mstpctl notify-daemon-that-stp-is-off $bridge
++ exec /sbin/mstpctl delbridge $bridge
+ ;;
+ *)
+ echo "Unknown action:" $2
+Index: ctl_functions.h
+===================================================================
+--- ctl_functions.h (revision 22)
++++ ctl_functions.h (revision 27)
+@@ -448,23 +448,16 @@
+ #define set_fids2mstids_CALL (in->br_index, in->fids2mstids)
+ CTL_DECLARE(set_fids2mstids);
+
+-/* stp_mode_notification */
+-#define CMD_CODE_stp_mode_notification (122 | RESPONSE_FIRST_HANDLE_LATER)
+-#define stp_mode_notification_ARGS (int br_index, bool on)
+-struct stp_mode_notification_IN
+-{
+- int br_index;
+- bool on;
+-};
+-struct stp_mode_notification_OUT
+-{
+-};
+-#define stp_mode_notification_COPY_IN ({ in->br_index = br_index; \
+- in->on = on; })
+-#define stp_mode_notification_COPY_OUT ({ (void)0; })
+-#define stp_mode_notification_CALL (in->br_index, in->on)
+-CTL_DECLARE(stp_mode_notification);
++/* add bridges */
++#define CMD_CODE_add_bridges (122 | RESPONSE_FIRST_HANDLE_LATER)
++#define add_bridges_ARGS (int *br_array, int* *ifaces_lists)
++CTL_DECLARE(add_bridges);
+
++/* delete bridges */
++#define CMD_CODE_del_bridges (123 | RESPONSE_FIRST_HANDLE_LATER)
++#define del_bridges_ARGS (int *br_array)
++CTL_DECLARE(del_bridges);
++
+ /* General case part in ctl command server switch */
+ #define SERVER_MESSAGE_CASE(name) \
+ case CMD_CODE_ ## name : do \
+Index: bridge_track.c
+===================================================================
+--- bridge_track.c (revision 22)
++++ bridge_track.c (revision 27)
+@@ -175,27 +175,11 @@
+ }
+ }
+
+-static bool stp_enabled(bridge_t * br)
++static void set_br_up(bridge_t * br, bool up)
+ {
+- char path[40 + IFNAMSIZ];
+- sprintf(path, "/sys/class/net/%s/bridge/stp_state", br->sysdeps.name);
+- FILE *f = fopen(path, "r");
+- int enabled = 0;
+- if(!f || (1 != fscanf(f, "%d", &enabled)))
+- ERROR("Can't read from %s", path);
+- fclose(f);
+- INFO("STP on %s state %d", br->sysdeps.name, enabled);
++ INFO("%s was %s", br->sysdeps.name, br->sysdeps.up ? "up" : "down");
++ INFO("Set bridge %s %s", br->sysdeps.name, up ? "up" : "down");
+
+- return enabled == 2; /* ie user mode STP */
+-}
+-
+-static void set_br_up(bridge_t * br, bool up, bool stp_up)
+-{
+- INFO("%s was %s stp was %s", br->sysdeps.name,
+- br->sysdeps.up ? "up" : "down", br->sysdeps.stp_up ? "up" : "down");
+- INFO("Set bridge %s %s stp %s" , br->sysdeps.name,
+- up ? "up" : "down", stp_up ? "up" : "down");
+-
+ bool changed = false;
+
+ if(up != br->sysdeps.up)
+@@ -204,12 +188,6 @@
+ changed = true;
+ }
+
+- if(br->sysdeps.stp_up != stp_up)
+- {
+- br->sysdeps.stp_up = stp_up;
+- changed = true;
+- }
+-
+ if(check_mac_address(br->sysdeps.name, br->sysdeps.macaddr))
+ {
+ /* MAC address changed */
+@@ -218,7 +196,7 @@
+ }
+
+ if(changed)
+- MSTP_IN_set_bridge_enable(br, br->sysdeps.up && br->sysdeps.stp_up);
++ MSTP_IN_set_bridge_enable(br, br->sysdeps.up);
+ }
+
+ static void set_if_up(port_t * ifc, bool up)
+@@ -291,15 +269,10 @@
+ if((br_index >= 0) && (br_index != if_index))
+ {
+ if(!(br = find_br(br_index)))
+- br = create_br(br_index);
+- if(!br)
+- {
+- ERROR("Couldn't create data for bridge interface %d", br_index);
+- return -1;
+- }
++ return -2; /* bridge not in list */
+ int br_flags = get_flags(br->sysdeps.name);
+ if(br_flags >= 0)
+- set_br_up(br, !!(br_flags & IFF_UP), stp_enabled(br));
++ set_br_up(br, !!(br_flags & IFF_UP));
+ }
+
+ if(br)
+@@ -358,15 +331,8 @@
+ if(br_index == if_index)
+ {
+ if(!(br = find_br(br_index)))
+- {
+- if(!(br = create_br(br_index)))
+- {
+- ERROR("Couldn't create data for bridge interface %d",
+- br_index);
+- return -1;
+- }
+- }
+- set_br_up(br, up, stp_enabled(br));
++ return -2; /* bridge not in list */
++ set_br_up(br, up);
+ }
+ }
+ }
+@@ -412,8 +378,6 @@
+ /* sanity checks */
+ TST(br == ifc->bridge,);
+ TST(ifc->sysdeps.up,);
+- if(!br->sysdeps.stp_up)
+- return;
+
+ /* Validate Ethernet and LLC header,
+ * maybe we can skip this check thanks to Berkeley filter in packet socket?
+@@ -840,12 +804,85 @@
+ return MSTP_IN_set_all_fids2mstids(br, fids2mstids) ? 0 : -1;
+ }
+
+-int CTL_stp_mode_notification(int br_index, bool on)
++int CTL_add_bridges(int *br_array, int* *ifaces_lists)
+ {
+- int br_flags;
+- CTL_CHECK_BRIDGE;
+- if(0 > (br_flags = get_flags(br->sysdeps.name)))
+- return br_flags;
+- set_br_up(br, !!(br_flags & IFF_UP), on);
++ int i, j, ifcount, brcount = br_array[0];
++ bridge_t *br, *other_br;
++ port_t *ifc, *nxt;
++ int br_flags, if_flags;
++ int *if_array;
++ bool found;
++
++ for(i = 1; i <= brcount; ++i)
++ {
++ if(NULL == (br = find_br(br_array[i])))
++ {
++ if(NULL == (br = create_br(br_array[i])))
++ {
++ ERROR("Couldn't create data for bridge interface %d",
++ br_array[i]);
++ return -1;
++ }
++ if(0 <= (br_flags = get_flags(br->sysdeps.name)))
++ set_br_up(br, !!(br_flags & IFF_UP));
++ }
++ if_array = ifaces_lists[i - 1];
++ ifcount = if_array[0];
++ /* delete all interfaces which are not in list */
++ list_for_each_entry_safe(ifc, nxt, &br->ports, br_list)
++ {
++ found = false;
++ for(j = 1; j <= ifcount; ++j)
++ {
++ if(ifc->sysdeps.if_index == if_array[j])
++ {
++ found = true;
++ break;
++ }
++ }
++ if(!found)
++ delete_if(ifc);
++ }
++ /* add all new interfaces from the list */
++ for(j = 1; j <= ifcount; ++j)
++ {
++ if(NULL != find_if(br, if_array[j]))
++ continue;
++ /* Check if this interface is slave of another bridge */
++ list_for_each_entry(other_br, &bridges, list)
++ {
++ if(other_br != br)
++ if(delete_if_byindex(other_br, if_array[j]))
++ {
++ INFO("Device %d has come to bridge %s. "
++ "Missed notify for deletion from bridge %s",
++ if_array[j], br->sysdeps.name,
++ other_br->sysdeps.name);
++ break;
++ }
++ }
++ if(NULL == (ifc = create_if(br, if_array[j])))
++ {
++ INFO("Couldn't create data for interface %d (master %s)",
++ if_array[j], br->sysdeps.name);
++ continue;
++ }
++ if(0 <= (if_flags = get_flags(ifc->sysdeps.name)))
++ set_if_up(ifc, (IFF_UP | IFF_RUNNING) ==
++ (if_flags & (IFF_UP | IFF_RUNNING))
++ );
++ }
++ }
++
+ return 0;
+ }
++
++int CTL_del_bridges(int *br_array)
++{
++ int i, brcount = br_array[0];
++
++ for(i = 1; i <= brcount; ++i)
++ delete_br_byindex(br_array[i]);
++
++ return 0;
++}
+Index: ctl_socket_server.c
+===================================================================
+--- ctl_socket_server.c (revision 22)
++++ ctl_socket_server.c (revision 27)
+@@ -82,8 +82,92 @@
+ SERVER_MESSAGE_CASE(set_fid2mstid);
+ SERVER_MESSAGE_CASE(set_vids2fids);
+ SERVER_MESSAGE_CASE(set_fids2mstids);
+- SERVER_MESSAGE_CASE(stp_mode_notification);
+
++ case CMD_CODE_add_bridges:
++ {
++ if(0 != lout)
++ {
++ LOG("Bad sizes: lout %d != 0", lout);
++ return -1;
++ }
++ if(sizeof(int) > lin)
++ {
++ LOG("Bad sizes: lin == 0");
++ return -1;
++ }
++ int *br_array = inbuf;
++ int i, serialized_data_count, chunk_count, brcount = br_array[0];
++ int *ptr = br_array + (serialized_data_count = (brcount + 1));
++ if(lin < ((serialized_data_count + 1) * sizeof(int)))
++ {
++bad_lin1: LOG("Bad sizes: lin %d < %d", lin,
++ (serialized_data_count + 1) * sizeof(int));
++ return -1;
++ }
++ for(i = 0; i < brcount; ++i)
++ {
++ serialized_data_count += (chunk_count = *ptr + 1);
++ if(i < (brcount - 1))
++ {
++ if(lin < ((serialized_data_count + 1) * sizeof(int)))
++ goto bad_lin1;
++ ptr += chunk_count;
++ }
++ else
++ {
++ if(lin != (serialized_data_count * sizeof(int)))
++ {
++ LOG("Bad sizes: lin %d != %d", lin,
++ serialized_data_count * sizeof(int));
++ return -1;
++ }
++ }
++ }
++ int* *ifaces_lists = malloc(brcount * sizeof(int*));
++ if(NULL == ifaces_lists)
++ {
++ LOG("out of memory, brcount = %d\n", brcount);
++ return -1;
++ }
++ ptr = br_array + (brcount + 1);
++ for(i = 0; i < brcount; ++i)
++ {
++ ifaces_lists[i] = ptr;
++ ptr += ifaces_lists[i][0] + 1;
++ }
++ int r = CTL_add_bridges(br_array, ifaces_lists);
++ free(ifaces_lists);
++ if(r)
++ return r;
++ return r;
++ }
++
++ case CMD_CODE_del_bridges:
++ {
++ if(0 != lout)
++ {
++ LOG("Bad sizes: lout %d != 0", lout);
++ return -1;
++ }
++ if(sizeof(int) > lin)
++ {
++ LOG("Bad sizes: lin == 0");
++ return -1;
++ }
++ int *br_array = inbuf;
++ int brcount = br_array[0];
++ if(((brcount + 1) * sizeof(int)) != lin)
++ {
++ LOG("Bad sizes: lin %d != %d", lin,
++ (brcount + 1) * sizeof(int));
++ return -1;
++ }
++ int r = CTL_del_bridges(br_array);
++ if(r)
++ return r;
++ return r;
++ }
++
+ default:
+ ERROR("CTL: Unknown command %d", cmd);
+ return -1;
+Index: mstp.c
+===================================================================
+--- mstp.c (revision 22)
++++ mstp.c (revision 27)
+@@ -206,7 +206,6 @@
+ return false;
+ list_add_tail(&cist->bridge_list, &br->trees);
+
+- br_state_machines_begin(br);
+ return true;
+ }
+
+Index: ctl_main.c
+===================================================================
+--- ctl_main.c (revision 22)
++++ ctl_main.c (revision 27)
+@@ -636,6 +636,18 @@
+ return !('.' == n[0] && (0 == n[1] || ('.' == n[1] && 0 == n[2])));
+ }
+
++static int get_port_list(const char *br_ifname, struct dirent ***namelist)
++{
++ int res;
++ char buf[SYSFS_PATH_MAX];
++
++ snprintf(buf, sizeof(buf), SYSFS_CLASS_NET "/%s/brif", br_ifname);
++ if(0 > (res = scandir(buf, namelist, not_dot_dotdot, sorting_func)))
++ fprintf(stderr, "Error getting list of all ports of bridge %s\n",
++ br_ifname);
++ return res;
++}
++
+ static int cmd_showport(int argc, char *const *argv)
+ {
+ int r = 0;
+@@ -666,15 +678,8 @@
+ }
+ else
+ {
+- char buf[SYSFS_PATH_MAX];
+- snprintf(buf, sizeof(buf), SYSFS_CLASS_NET "/%s/brif", argv[1]);
+- count = scandir(buf, &namelist, not_dot_dotdot, sorting_func);
+- if(0 > count)
+- {
+- fprintf(stderr, "Error getting list of all ports of bridge %s\n",
+- argv[1]);
+- return -1;
+- }
++ if(0 > (count = get_port_list(argv[1], &namelist)))
++ return count;
+ }
+
+ for(i = 0; i < count; ++i)
+@@ -740,6 +745,91 @@
+ return 0;
+ }
+
++static int cmd_addbridge(int argc, char *const *argv)
++{
++ int i, j, res, ifcount, brcount = argc - 1;
++ int *br_array;
++ int* *ifaces_lists;
++
++ if(NULL == (br_array = malloc((brcount + 1) * sizeof(int))))
++ {
++out_of_memory_exit:
++ fprintf(stderr, "out of memory, brcount = %d\n", brcount);
++ return -1;
++ }
++ if(NULL == (ifaces_lists = malloc(brcount * sizeof(int*))))
++ {
++ free(br_array);
++ goto out_of_memory_exit;
++ }
++
++ br_array[0] = brcount;
++ for(i = 1; i <= brcount; ++i)
++ {
++ struct dirent **namelist;
++
++ br_array[i] = get_index(argv[i], "bridge");
++
++ if(0 > (ifcount = get_port_list(argv[i], &namelist)))
++ {
++ifaces_error_exit:
++ for(i -= 2; i >= 0; --i)
++ free(ifaces_lists[i]);
++ free(ifaces_lists);
++ free(br_array);
++ return ifcount;
++ }
++
++ if(NULL == (ifaces_lists[i - 1] = malloc((ifcount + 1) * sizeof(int))))
++ {
++ fprintf(stderr, "out of memory, bridge %s, ifcount = %d\n",
++ argv[i], ifcount);
++ for(j = 0; j < ifcount; ++j)
++ free(namelist[j]);
++ free(namelist);
++ ifcount = -1;
++ goto ifaces_error_exit;
++ }
++
++ ifaces_lists[i - 1][0] = ifcount;
++ for(j = 1; j <= ifcount; ++j)
++ {
++ ifaces_lists[i - 1][j] = get_index(namelist[j - 1]->d_name, "port");
++ free(namelist[j - 1]);
++ }
++ free(namelist);
++ }
++
++ res = CTL_add_bridges(br_array, ifaces_lists);
++
++ for(i = 0; i < brcount; ++i)
++ free(ifaces_lists[i]);
++ free(ifaces_lists);
++ free(br_array);
++ return res;
++}
++
++static int cmd_delbridge(int argc, char *const *argv)
++{
++ int i, res, brcount = argc - 1;
++ int *br_array;
++
++ if(NULL == (br_array = malloc((brcount + 1) * sizeof(int))))
++ {
++ fprintf(stderr, "out of memory, brcount = %d\n", brcount);
++ return -1;
++ }
++
++ br_array[0] = brcount;
++ for(i = 1; i <= brcount; ++i)
++ br_array[i] = get_index(argv[i], "bridge");
++
++ res = CTL_del_bridges(br_array);
++
++ free(br_array);
++ return res;
++}
++
+ static unsigned int getuint(const char *s)
+ {
+ char *end;
+@@ -1191,23 +1281,6 @@
+ return CTL_set_fid2mstid(br_index, fid, mstid);
+ }
+
+-static int cmd_stp_mode_notification(int argc, char *const *argv, bool on)
+-{
+- int br_index;
+- /* Because this command has special handling,
+- * argc was not checked earlier
+- */
+- if(2 > argc)
+- {
+- fprintf(stderr,
+- "Incorrect number of arguments for notification command\n");
+- exit(1);
+- }
+- if(0 > (br_index = get_index(argv[1], "bridge")))
+- return br_index;
+- return CTL_stp_mode_notification(br_index, on);
+-}
+-
+ struct command
+ {
+ int nargs;
+@@ -1220,6 +1293,12 @@
+
+ static const struct command commands[] =
+ {
++ /* Add/delete bridges */
++ {1, 32, "addbridge", cmd_addbridge,
++ "<bridge> [<bridge> ...]", "Add bridges to the mstpd's list"},
++ {1, 32, "delbridge", cmd_delbridge,
++ "<bridge> [<bridge> ...]", "Remove bridges from the mstpd's list"},
++
+ /* Show global bridge */
+ {0, 32, "showbridge", cmd_showbridge,
+ "[<bridge> ... [param]]", "Show bridge state for the CIST"},
+@@ -1370,12 +1449,6 @@
+ argv += optind;
+ if(NULL == (cmd = command_lookup(argv[0])))
+ {
+- /* Two special commands not intended for interactive use */
+- if(!strcmp(argv[0], "notify-daemon-that-stp-is-on"))
+- return cmd_stp_mode_notification(argc, argv, true);
+- if(!strcmp(argv[0], "notify-daemon-that-stp-is-off"))
+- return cmd_stp_mode_notification(argc, argv, false);
+-
+ fprintf(stderr, "never heard of command [%s]\n", argv[0]);
+ goto help;
+ }
+@@ -1417,8 +1490,61 @@
+ CLIENT_SIDE_FUNCTION(set_fid2mstid)
+ CLIENT_SIDE_FUNCTION(set_vids2fids)
+ CLIENT_SIDE_FUNCTION(set_fids2mstids)
+-CLIENT_SIDE_FUNCTION(stp_mode_notification)
+
++CTL_DECLARE(add_bridges)
++{
++ int res = 0;
++ LogString log = { .buf = "" };
++ int i, chunk_count, brcount, serialized_data_count;
++ int *serialized_data, *ptr;
++
++ chunk_count = serialized_data_count = (brcount = br_array[0]) + 1;
++ for(i = 0; i < brcount; ++i)
++ serialized_data_count += ifaces_lists[i][0] + 1;
++ if(NULL == (serialized_data = malloc(serialized_data_count * sizeof(int))))
++ {
++ LOG("out of memory, serialized_data_count = %d",
++ serialized_data_count);
++ return -1;
++ }
++ memcpy(serialized_data, br_array, chunk_count * sizeof(int));
++ ptr = serialized_data + chunk_count;
++ for(i = 0; i < brcount; ++i)
++ {
++ chunk_count = ifaces_lists[i][0] + 1;
++ memcpy(ptr, ifaces_lists[i], chunk_count * sizeof(int));
++ ptr += chunk_count;
++ }
++
++ int r = send_ctl_message(CMD_CODE_add_bridges, serialized_data,
++ serialized_data_count * sizeof(int),
++ NULL, 0, &log, &res);
++ free(serialized_data);
++ if(r || res)
++ LOG("Got return code %d, %d\n%s", r, res, log.buf);
++ if(r)
++ return r;
++ if(res)
++ return res;
++ return 0;
++}
++
++CTL_DECLARE(del_bridges)
++{
++ int res = 0;
++ LogString log = { .buf = "" };
++ int r = send_ctl_message(CMD_CODE_del_bridges,
++ br_array, (br_array[0] + 1) * sizeof(int),
++ NULL, 0, &log, &res);
++ if(r || res)
++ LOG("Got return code %d, %d\n%s", r, res, log.buf);
++ if(r)
++ return r;
++ if(res)
++ return res;
++ return 0;
++}
++
+ /*********************** Logging *********************/
+
+ void Dprintf(int level, const char *fmt, ...)