diff --git a/rstp/Makefile b/rstp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..30aa0d6f2b9570c5459b76398a399ac217072d53 --- /dev/null +++ b/rstp/Makefile @@ -0,0 +1,43 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=rstp +PKG_VERSION:=2011-10-11 +PKG_RELEASE=$(PKG_SOURCE_VERSION) + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/rstp.git +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE_VERSION:=434d24bae108dbb21461a13a4abcf014afa8b029 +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz +PKG_MAINTAINER:=Stephen Hemminger <shemminger@vyatta.com> +# PKG_MIRROR_MD5SUM:= +# CMAKE_INSTALL:=1 + +PKG_LICENSE:=GPLv2 +PKG_LICENSE_FILES:= + +PKG_BUILD_PARALLEL:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/rstp + SECTION:=net + CATEGORY:=Network + MAINTAINER:=Stephen Hemminger <shemminger@vyatta.com> + URL:=http://git.kernel.org/cgit/linux/kernel/git/shemminger/rstp.git/ + TITLE:=Rapid Spanning Tree Protocol implement + DEPENDS:=+kmod-qca-ssdk-hnat +endef + +TARGET_CFLAGS += \ + -I$(STAGING_DIR)/usr/include/qca-ssdk + +define Package/rstp/install + $(INSTALL_DIR) $(1)/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/bridge-stp $(1)/sbin/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/rstpctl $(1)/sbin/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/rstpd $(1)/sbin/ + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,rstp)) diff --git a/rstp/files/etc/config/rstp b/rstp/files/etc/config/rstp new file mode 100644 index 0000000000000000000000000000000000000000..e0f1f212817f6936701849840c2459dc6eddb9fe --- /dev/null +++ b/rstp/files/etc/config/rstp @@ -0,0 +1,3 @@ +config rstp global + option enable '0' + option autoMode '1' diff --git a/rstp/files/etc/init.d/rstp b/rstp/files/etc/init.d/rstp new file mode 100755 index 0000000000000000000000000000000000000000..311017a1a86c4df9aa8d8f579752958c22416f8e --- /dev/null +++ b/rstp/files/etc/init.d/rstp @@ -0,0 +1,238 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006-2011 OpenWrt.org + +START=55 + +SERVICE_USE_PID=1 +SERVICE_DAEMONIZE=1 +SERVICE_WRITE_PID=1 + +yes_or_no(){ + local xboolean=$1 + if [ "$xboolean" = "1" ] + then + echo "yes" + else + echo "no" + fi +} + +ifname_exist=1 +port_is_valid=1 +option_cb() +{ + local name="$1" + local value="$2" + + if [ "$name" = "ifname" ]; then + [ -d "/sys/class/net/$value" ] || ifname_exist=0 + fi +} + +validate_port(){ + local port_name=$1 + local bridge ifname switch switchPortId + local bridge_ifname switch_ifname + + config_get bridge $port_name bridge + config_get ifname $port_name ifname + config_get switch $port_name switch + config_get switchPortId $port_name switchPortId + + [ -z "$bridge" ] && port_is_valid=0 && return + config_get bridge_ifname $bridge ifname + [ -z "$bridge_ifname" ] && port_is_valid=0 && return + + [ -z "$ifname" ] && [ -z "$switch" ] && port_is_valid=0 && return +# [ -n "$ifname" ] && [ -n "$switch" ] && port_is_valid=0 && return + [ -n "$switch" ] && [ -z "$switchPortId" ] && port_is_valid=0 && return + + if [ -n "$switch" ]; then + config_get switch_ifname $switch ifname + [ -z "$switch_ifname" ] && port_is_valid=0 && return + fi +} + +validate_config(){ + if [ "$ifname_exist" = "0" ]; then + echo "ifname of bridge or switch port not exist" + return -1 + fi + + config_foreach validate_port port + if [ "$port_is_valid" = "0" ]; then + echo "switch port configuration error" + return -1 + fi + + return 0 +} + +rstpctl_add_bridge(){ + local bridge_name=$1 + local enable=0 + local bridge_ifname + local priority helloTime maxAge forwardDelay forceProtocolVersion + + config_get enable $bridge_name enable + [ "$enable" = "0" ] && return + + config_get bridge_ifname $bridge_name ifname + [ -z "$bridge_ifname" ] && return + + /sbin/rstpctl addBridge $bridge_ifname + + config_get priority $bridge_name priority + [ -n "$priority" ] && /sbin/rstpctl setbridgeprio $bridge_ifname $priority + + config_get helloTime $bridge_name helloTime + [ -n "$helloTime" ] && /sbin/rstpctl sethello $bridge_ifname $helloTime + + config_get maxAge $bridge_name maxAge + [ -n "$maxAge" ] && /sbin/rstpctl setmaxage $bridge_ifname $maxAge + + config_get forwardDelay $bridge_name forwardDelay + [ -n "$forwardDelay" ] && /sbin/rstpctl setfdelay $bridge_ifname $forwardDelay + + config_get forceProtocolVersion $bridge_name forceProtocolVersion + [ "$forceProtocolVersion" = "1" ] && /sbin/rstpctl setforcevers $bridge_ifname "slow" + [ "$forceProtocolVersion" = "2" ] && /sbin/rstpctl setforcevers $bridge_ifname "normal" +} + +rstpctl_add_port(){ + local port_name=$1 + local bridge enable ifname switch switchPortId + local bridge_ifname switch_ifname + local priority pathCost edgePort p2pLink + + config_get enable $port_name enable + [ "$enable" = "0" ] && return + enable=0 + + config_get bridge $port_name bridge + config_get bridge_ifname $bridge ifname + config_get enable $bridge enable + [ "$enable" = "0" ] && return + + config_get ifname $port_name ifname + [ -z "$ifname" ] && ifname="no-exist" + config_get switch $port_name switch + config_get switchPortId $port_name switchPortId + if [ -n "$switch" ] && [ -n "$switchPortId" ] ; then + config_get switch_ifname $switch ifname + ifname="$switch_ifname.$port_name" + fi + + /sbin/rstpctl addBridgePort $bridge_ifname $ifname + + config_get priority $port_name priority + [ -n "$priority" ] && /sbin/rstpctl setportprio $bridge_ifname $ifname $priority + + config_get pathCost $port_name pathCost + [ -n "$pathCost" ] && /sbin/rstpctl setportpathcost $bridge_ifname $ifname $pathCost + + config_get edgePort $port_name edgePort + [ -n "$edgePort" ] && /sbin/rstpctl setportedge $bridge_ifname $ifname $(yes_or_no $edgePort) + + config_get p2pLink $port_name p2pLink + [ -n "$p2pLink" ] && /sbin/rstpctl setportp2p $bridge_ifname $ifname $(yes_or_no $p2pLink) +} + +rstpctl_start_bridge(){ + local bridge_name=$1 + local enable=0 + local bridge_ifname + + config_get enable $bridge_name enable + [ "$enable" = "0" ] && return + + config_get bridge_ifname $bridge_name ifname + [ -z "$bridge_ifname" ] && return + + brctl stp $bridge_ifname on +} + +rstpctl_stop_bridge(){ + local bridge_name=$1 + local enable=0 + local bridge_ifname + + config_get enable $bridge_name enable + [ "$enable" = "0" ] && return + + config_get bridge_ifname $bridge_name ifname + [ -z "$bridge_ifname" ] && return + + brctl stp $bridge_ifname off +} +board_set() { + if [ -e /proc/sys/net/edma/enable_stp_rstp ]; then + echo 0xfefefefe > /proc/sys/net/edma/athr_hdr_eth_type + echo 1 > /proc/sys/net/edma/enable_stp_rstp + fi +} + +board_recover() { + if [ -e /proc/sys/net/edma/enable_stp_rstp ]; then + echo 0 > /proc/sys/net/edma/enable_stp_rstp + echo 0 > /proc/sys/net/edma/athr_hdr_eth_type + fi +} + +start() { + local rstp_enable autoMode ifname + + config_load "rstp" + + config_get rstp_enable global enable 0 + [ "$rstp_enable" = "0" ] && return + + config_get autoMode global autoMode 0 + if [ "$autoMode" = "1" ] ; then + service_start /sbin/rstpd -a + sleep 1 + + . /lib/functions/network.sh + network_get_device ifname lan + brctl stp $ifname on + else + validate_config || return + + service_start /sbin/rstpd + sleep 1 + + config_foreach rstpctl_start_bridge bridge + config_foreach rstpctl_add_bridge bridge + config_foreach rstpctl_add_port port + fi + board_set +} + +stop() { + local rstp_enable autoMode ifname + + config_load "rstp" + + config_get rstp_enable global enable 0 + + board_recover + + [ "$rstp_enable" = "0" ] && return + + config_get autoMode global autoMode 0 + if [ "$autoMode" = "1" ] ; then + . /lib/functions/network.sh + network_get_device ifname lan + brctl stp $ifname off + + sleep 1 + service_stop /sbin/rstpd + else + validate_config || return + + config_foreach rstpctl_stop_bridge bridge + sleep 1 + service_stop /sbin/rstpd + fi +} + diff --git a/rstp/files/lib/functions/rstp.sh b/rstp/files/lib/functions/rstp.sh new file mode 100755 index 0000000000000000000000000000000000000000..7d89be36c42cae0ba74ea4781733fb1793f14291 --- /dev/null +++ b/rstp/files/lib/functions/rstp.sh @@ -0,0 +1,88 @@ +#!/bin/sh +# Copyright (c) 2013 The Linux Foundation. All rights reserved. + +. /lib/functions.sh + +get_linkstatus_check_interval(){ + echo 3 +} + +get_atheros_header_type(){ + echo 0xfefe +} + +get_cpu_mirror_port(){ +if [ -e /proc/sys/net/edma/enable_stp_rstp ]; then + echo "-1 -1" +else + . /lib/ipq806x.sh + board=$(ipq806x_board_name) + + case "$board" in + *) + echo "0 6" + ;; + esac +fi +} + +get_switch_config_auto(){ + . /lib/ipq806x.sh + board=$(ipq806x_board_name) + + case "$board" in + *) + echo "=qca eth1 eth1 1 port1" + echo "=qca eth1 eth1 2 port2" + echo "=qca eth1 eth1 3 port3" + echo "=qca eth1 eth1 4 port4" + echo "=qca eth1 eth0 5 eth0" + ;; + esac +} + +get_switch_port_config(){ + local port_name=$1 + local bridge enable switch switchPortId control_channel data_channel + + config_get enable $port_name enable + [ "$enable" = "0" ] && return + enable=0 + + config_get bridge $port_name bridge + config_get enable $bridge enable + [ "$enable" = "0" ] && return + + config_get switch $port_name switch + config_get switchPortId $port_name switchPortId + if [ -n "$switch" ] && [ -n "$switchPortId" ] ; then + config_get control_channel $switch ifname + + config_get data_channel $port_name ifname + [ -z "$data_channel" ] && data_channel="$control_channel" + + echo "=qca $control_channel $data_channel $switchPortId $port_name" + fi +} + +get_switch_config_manual(){ + config_foreach get_switch_port_config port +} + +get_switch_ports(){ + local autoMode + + config_load "rstp" + + config_get autoMode global autoMode + + if [ "$autoMode" = "1" ] ; then + get_switch_config_auto + else + get_switch_config_manual + fi +} + +func=$1 +shift +$func $@ diff --git a/rstp/patches/10-makefile-fit-openwrt.patch b/rstp/patches/10-makefile-fit-openwrt.patch new file mode 100644 index 0000000000000000000000000000000000000000..641828f6d9c0a7dda764d127a681fcfd028459e0 --- /dev/null +++ b/rstp/patches/10-makefile-fit-openwrt.patch @@ -0,0 +1,29 @@ +diff --git a/Makefile b/Makefile +index 3e04bea..f903f91 100644 +--- a/Makefile ++++ b/Makefile +@@ -8,8 +8,7 @@ CTLSOURCES = ctl_main.c ctl_cli_wrap.c ctl_socket_client.c + + CTLOBJECTS = $(CTLSOURCES:.c=.o) + +-CC=gcc +-CFLAGS = -Wall -Werror -fno-strict-aliasing -O2 -g -D_REENTRANT -D__LINUX__ \ ++CFLAGS += -Wall -Werror -fno-strict-aliasing -O2 -g -D_REENTRANT -D__LINUX__ \ + -DVERSION=$(version) -DBUILD=$(build) -I. -I./include -I./rstplib + + all: rstpd rstpctl +diff --git a/rstplib/Makefile b/rstplib/Makefile +index 1ecf211..0bc026d 100644 +--- a/rstplib/Makefile ++++ b/rstplib/Makefile +@@ -21,9 +21,8 @@ + #**********************************************************************/ + + DEFS= +-CC = gcc + #CFLAGS = -g -Wall -D_REENTRANT -D__LINUX__ -DSTP_DBG=1 +-CFLAGS = -g -O -Wall -D_REENTRANT -D__LINUX__ ++CFLAGS += -g -O -Wall -D_REENTRANT -D__LINUX__ + + INCLUDES = -I. + COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CFLAGS) diff --git a/rstp/patches/20-change-to-sh-from-bash.patch b/rstp/patches/20-change-to-sh-from-bash.patch new file mode 100644 index 0000000000000000000000000000000000000000..1026b5d5eb1a23b6d7937d2bc516191ce01534bd --- /dev/null +++ b/rstp/patches/20-change-to-sh-from-bash.patch @@ -0,0 +1,10 @@ +diff --git a/bridge-stp b/bridge-stp +index e699b87..f9277df 100755 +--- a/bridge-stp ++++ b/bridge-stp +@@ -1,4 +1,4 @@ +-#!/bin/bash ++#!/bin/sh + # + # Script to start/stop spanning tree called from kernel + # Make sure umask is sane diff --git a/rstp/patches/30-support-exit-on-signal.patch b/rstp/patches/30-support-exit-on-signal.patch new file mode 100644 index 0000000000000000000000000000000000000000..8d78f52e71c53e347b6fd2d403d58a6cfdb15cd7 --- /dev/null +++ b/rstp/patches/30-support-exit-on-signal.patch @@ -0,0 +1,90 @@ +diff --git a/epoll_loop.c b/epoll_loop.c +index 33c3068..9ecf778 100644 +--- a/epoll_loop.c ++++ b/epoll_loop.c +@@ -36,6 +36,7 @@ + // globals + int epoll_fd = -1; + struct timeval nexttimeout; ++static int epoll_should_stop = 0; + + int init_epoll(void) + { +@@ -95,6 +96,11 @@ void run_timeouts(void) + nexttimeout.tv_sec++; + } + ++void epoll_end_loop(void) ++{ ++ epoll_should_stop = 1; ++} ++ + int epoll_main_loop(void) + { + gettimeofday(&nexttimeout, NULL); +@@ -102,7 +108,7 @@ int epoll_main_loop(void) + #define EV_SIZE 8 + struct epoll_event ev[EV_SIZE]; + +- while (1) { ++ while (!epoll_should_stop) { + int r, i; + int timeout; + +diff --git a/epoll_loop.h b/epoll_loop.h +index 14d0423..c81f3a6 100644 +--- a/epoll_loop.h ++++ b/epoll_loop.h +@@ -42,6 +42,8 @@ int init_epoll(void); + + void clear_epoll(void); + ++void epoll_end_loop(void); ++ + int epoll_main_loop(void); + + int add_epoll(struct epoll_event_handler *h); +diff --git a/main.c b/main.c +index a8c21ac..a8329b3 100644 +--- a/main.c ++++ b/main.c +@@ -35,11 +35,31 @@ + #include <getopt.h> + #include <syslog.h> + #include <errno.h> ++#include <string.h> ++#include <signal.h> + + static int become_daemon = 1; + static int is_daemon = 0; + int log_level = LOG_LEVEL_DEFAULT; + ++static void handle_signal(int signo) ++{ ++ epoll_end_loop(); ++} ++ ++static int setup_signals(void) ++{ ++ struct sigaction s; ++ ++ memset(&s, 0, sizeof(s)); ++ s.sa_handler = handle_signal; ++ s.sa_flags = 0; ++ sigaction(SIGINT, &s, NULL); ++ sigaction(SIGTERM, &s, NULL); ++ ++ return 0; ++} ++ + int main(int argc, char *argv[]) + { + int c,ret; +@@ -66,6 +86,7 @@ int main(int argc, char *argv[]) + } + } + ++ TST(setup_signals() == 0, -1); + TST(init_epoll() == 0, -1); + TST(ctl_socket_init() == 0, -1); + TST(packet_sock_init() == 0, -1); diff --git a/rstp/patches/40-support-manual-and-auto-topology-mode.patch b/rstp/patches/40-support-manual-and-auto-topology-mode.patch new file mode 100644 index 0000000000000000000000000000000000000000..58f4756863e2fe4525adb1fc385a1c1da522fa62 --- /dev/null +++ b/rstp/patches/40-support-manual-and-auto-topology-mode.patch @@ -0,0 +1,401 @@ +diff --git a/bridge_ctl.h b/bridge_ctl.h +index b0449ca..616a044 100644 +--- a/bridge_ctl.h ++++ b/bridge_ctl.h +@@ -25,6 +25,14 @@ + #ifndef BRIDGE_CTL_H + #define BRIDGE_CTL_H + ++typedef enum { ++ AUTO_TOPOLOGY, ++ MANUAL_TOPOLOGY ++}topology_mode_t; ++ ++void set_topology_mode(topology_mode_t mode); ++topology_mode_t get_topology_mode(void); ++ + struct ifdata; + + int init_bridge_ops(void); +@@ -33,6 +41,8 @@ void bridge_get_configuration(void); + + int bridge_set_state(int ifindex, int state); + ++int bridge_notify_simple(int br_index, int if_index, int newlink, unsigned flags); ++ + int bridge_notify(int br_index, int if_index, int newlink, unsigned flags); + + void bridge_bpdu_rcv(int ifindex, const unsigned char *data, int len); +diff --git a/bridge_track.c b/bridge_track.c +index 289fc41..2967d08 100644 +--- a/bridge_track.c ++++ b/bridge_track.c +@@ -476,6 +476,28 @@ static void set_if_up(struct ifdata *ifc, int up) + + /*------------------------------------------------------------*/ + ++int bridge_notify_simple(int br_index, int if_index, int newlink, ++ unsigned flags) ++{ ++ struct ifdata *br = NULL; ++ struct ifdata *ifc = NULL; ++ int up; ++ ++ if (br_index >= 0) { ++ br = find_if(br_index); ++ /* Bridge must be up if we get such notifications */ ++ if (br && br->is_bridge && !br->up) ++ set_br_up(br, 1); ++ } ++ ++ ifc = find_if(if_index); ++ up = (flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING); ++ if (ifc && (!ifc->is_bridge) && ifc->up != up) ++ set_if_up(ifc, up); /* And speed and duplex */ ++ ++ return 0; ++} ++ + int bridge_notify(int br_index, int if_index, int newlink, + unsigned flags) + { +@@ -976,5 +998,97 @@ int CTL_set_debug_level(int level) + return 0; + } + ++int CTL_add_bridge(char *name) ++{ ++ int br_index, up; ++ struct ifdata *br = NULL; ++ ++ br_index = if_nametoindex(name); ++ if(br_index == 0) { ++ ERROR("bridge %s not exist", name); ++ return 0; ++ } ++ ++ br = find_if(br_index); ++ if (br && !br->is_bridge) { ++ ERROR("Existed interface %s is not a bridge.", name); ++ return 0; ++ } ++ ++ if (!br && is_bridge(name)) ++ br = create_if(br_index, NULL); ++ ++ if (!br) { ++ ERROR("Couldn't create data for bridge interface %s", name); ++ return 0; ++ } ++ ++ up = get_link_status(name); ++ if(br->up != up) ++ set_br_up(br, up); ++ ++ INFO("bridge %s created, if_index is %d, link status %d.", name, br_index, up); ++ return 0; ++} ++ ++int CTL_add_bridge_port(char *br_name, char *pt_name) ++{ ++ int br_index, if_index, up; ++ struct ifdata *br, *br_port; ++ ++ br_index = if_nametoindex(br_name); ++ if(br_index == 0) { ++ ERROR("bridge %s not exist", br_name); ++ return 0; ++ } ++ ++ if_index = if_nametoindex(pt_name); ++ if(if_index == 0) { ++ ERROR("bridge port %s not exist", pt_name); ++ return 0; ++ } ++ ++ br = find_if(br_index); ++ if (br && !br->is_bridge) { ++ ERROR("Existed interface %s is not a bridge.", br_name); ++ return 0; ++ } ++ ++ if (!br) { ++ ERROR("Couldn't find data for bridge interface %s", br_name); ++ return 0; ++ } ++ ++ br_port = find_if(if_index); ++ if (br_port) { ++ if (br_port->is_bridge) { ++ ERROR("interface %s is a bridge, can't become a bridge port", pt_name); ++ return 0; ++ } ++ ++ if (br_port->master != br) { ++ INFO("Device %d has come to bridge %d. Missed notify for deletion from bridge %d", ++ if_index, br_index, br_port->master->if_index); ++ delete_if(br_port); ++ br_port = NULL; ++ } ++ } ++ ++ if (!br_port) ++ br_port = create_if(if_index, br); ++ ++ if (!br_port) { ++ ERROR("Couldn't create data for interface %d (master %d)", if_index, br_index); ++ return 0; ++ } ++ ++ up = get_link_status(pt_name); ++ if(br_port->up != up) ++ set_if_up(br_port, up); ++ ++ INFO("bridge port %s created, master is %s, link status %d.", pt_name, br_name, up); ++ return 0; ++} ++ + #undef CTL_CHECK_BRIDGE_PORT + #undef CTL_CHECK_BRIDGE +diff --git a/brmon.c b/brmon.c +index 4c4e490..96a1113 100644 +--- a/brmon.c ++++ b/brmon.c +@@ -47,27 +47,12 @@ static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, + if (len < 0) + return -1; + +- if (ifi->ifi_family != AF_BRIDGE && ifi->ifi_family != AF_UNSPEC) +- return 0; +- + if (n->nlmsg_type != RTM_NEWLINK && + n->nlmsg_type != RTM_DELLINK) + return 0; + + parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); + +- /* Check if we got this from bonding */ +- if (tb[IFLA_MASTER] && ifi->ifi_family != AF_BRIDGE) +- return 0; +- +- /* Check if hearing our own state changes */ +- if (n->nlmsg_type == RTM_NEWLINK && tb[IFLA_PROTINFO]) { +- uint8_t state = *(uint8_t *)RTA_DATA(tb[IFLA_PROTINFO]); +- +- if (state != BR_STATE_DISABLED) +- return 0; +- } +- + if (tb[IFLA_IFNAME] == NULL) { + fprintf(stderr, "BUG: nil ifname\n"); + return -1; +@@ -87,10 +72,10 @@ static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, + fprintf(fp, "\n"); + fflush(fp); + +- +- bridge_notify(master, ifi->ifi_index, +- (n->nlmsg_type == RTM_NEWLINK), +- ifi->ifi_flags); ++ if(get_topology_mode() == AUTO_TOPOLOGY) ++ bridge_notify(master, ifi->ifi_index, (n->nlmsg_type == RTM_NEWLINK), ifi->ifi_flags); ++ else ++ bridge_notify_simple(master, ifi->ifi_index, (n->nlmsg_type == RTM_NEWLINK), ifi->ifi_flags); + + return 0; + } +diff --git a/ctl_cli_wrap.c b/ctl_cli_wrap.c +index 72665a8..8ad65c4 100644 +--- a/ctl_cli_wrap.c ++++ b/ctl_cli_wrap.c +@@ -33,6 +33,8 @@ CLIENT_SIDE_FUNCTION(enable_bridge_rstp) + CLIENT_SIDE_FUNCTION(get_port_state) + CLIENT_SIDE_FUNCTION(set_port_config) + CLIENT_SIDE_FUNCTION(set_debug_level) ++ CLIENT_SIDE_FUNCTION(add_bridge) ++ CLIENT_SIDE_FUNCTION(add_bridge_port) + #include <base.h> + const char *CTL_error_explanation(int err_no) + { +diff --git a/ctl_functions.h b/ctl_functions.h +index 9d630f6..4a04d62 100644 +--- a/ctl_functions.h ++++ b/ctl_functions.h +@@ -42,6 +42,10 @@ int CTL_set_port_config(int br_index, int port_index, UID_STP_PORT_CFG_T * cfg); + + int CTL_set_debug_level(int level); + ++int CTL_add_bridge(char *name); ++ ++int CTL_add_bridge_port(char *br_name, char *pt_name); ++ + #define CTL_ERRORS \ + CHOOSE(Err_Interface_not_a_bridge), \ + CHOOSE(Err_Bridge_RSTP_not_enabled), \ +diff --git a/ctl_main.c b/ctl_main.c +index 83dee9f..a90e185 100644 +--- a/ctl_main.c ++++ b/ctl_main.c +@@ -728,6 +728,16 @@ static int cmd_debuglevel(int argc, char *const *argv) + return CTL_set_debug_level(getuint(argv[1])); + } + ++static int cmd_addBridge(int argc, char *const *argv) ++{ ++ return CTL_add_bridge(argv[1]); ++} ++ ++static int cmd_addBridgePort(int argc, char *const *argv) ++{ ++ return CTL_add_bridge_port(argv[1], argv[2]); ++} ++ + struct command { + int nargs; + int optargs; +@@ -770,6 +780,10 @@ static const struct command commands[] = { + {2, 0, "portmcheck", cmd_portmcheck, + "<bridge> <port>\ttry to get back from STP to RSTP mode"}, + {1, 0, "debuglevel", cmd_debuglevel, "<level>\t\tLevel of verbosity"}, ++ {1, 0, "addBridge", cmd_addBridge, ++ "<bridge>\tadd new bridge"}, ++ {2, 0, "addBridgePort", cmd_addBridgePort, ++ "<bridge> <port>\tadd new bridge port in an existed bridge"}, + }; + + const struct command *command_lookup(const char *cmd) +diff --git a/ctl_socket.c b/ctl_socket.c +index f37e8b1..1438e5f 100644 +--- a/ctl_socket.c ++++ b/ctl_socket.c +@@ -68,6 +68,8 @@ int handle_message(int cmd, void *inbuf, int lin, void *outbuf, int *lout) + SERVER_MESSAGE_CASE(get_port_state); + SERVER_MESSAGE_CASE(set_port_config); + SERVER_MESSAGE_CASE(set_debug_level); ++ SERVER_MESSAGE_CASE(add_bridge); ++ SERVER_MESSAGE_CASE(add_bridge_port); + + default: + ERROR("CTL: Unknown command %d", cmd); +diff --git a/ctl_socket.h b/ctl_socket.h +index 089a717..a4b7c7a 100644 +--- a/ctl_socket.h ++++ b/ctl_socket.h +@@ -149,6 +149,37 @@ struct set_debug_level_OUT { + #define set_debug_level_COPY_OUT ({ (void)0; }) + #define set_debug_level_CALL (in->level) + ++#if 0 ++int CTL_add_bridge(char *name); ++#endif ++#define CMD_CODE_add_bridge 107 ++#define add_bridge_ARGS (char *name) ++struct add_bridge_IN { ++ char name[64]; ++}; ++struct add_bridge_OUT { ++}; ++#define add_bridge_COPY_IN \ ++ ({ strncpy(in->name, name, sizeof(in->name)); }) ++#define add_bridge_COPY_OUT ({ (void)0; }) ++#define add_bridge_CALL (in->name) ++ ++#if 0 ++int CTL_add_bridge_port(char *br_name, char *pt_name); ++#endif ++#define CMD_CODE_add_bridge_port 108 ++#define add_bridge_port_ARGS (char *br_name, char *pt_name) ++struct add_bridge_port_IN { ++ char br_name[64]; ++ char pt_name[64]; ++}; ++struct add_bridge_port_OUT { ++}; ++#define add_bridge_port_COPY_IN \ ++ ({ strncpy(in->br_name, br_name, sizeof(in->br_name)); strncpy(in->pt_name, pt_name, sizeof(in->pt_name)); }) ++#define add_bridge_port_COPY_OUT ({ (void)0; }) ++#define add_bridge_port_CALL (in->br_name, in->pt_name) ++ + /* General case part in ctl command server switch */ + #define SERVER_MESSAGE_CASE(name) \ + case CMD_CODE_ ## name : do { \ +diff --git a/main.c b/main.c +index a8329b3..33eebec 100644 +--- a/main.c ++++ b/main.c +@@ -41,6 +41,17 @@ + static int become_daemon = 1; + static int is_daemon = 0; + int log_level = LOG_LEVEL_DEFAULT; ++static topology_mode_t topology_mode = MANUAL_TOPOLOGY; ++ ++void set_topology_mode(topology_mode_t mode) ++{ ++ topology_mode = mode; ++} ++ ++topology_mode_t get_topology_mode(void) ++{ ++ return topology_mode; ++} + + static void handle_signal(int signo) + { +@@ -63,8 +74,11 @@ static int setup_signals(void) + int main(int argc, char *argv[]) + { + int c,ret; +- while ((c = getopt(argc, argv, "dv:")) != -1) { ++ while ((c = getopt(argc, argv, "adv:")) != -1) { + switch (c) { ++ case 'a': ++ set_topology_mode(AUTO_TOPOLOGY); ++ break; + case 'd': + become_daemon = 0; + break; +diff --git a/netif_utils.c b/netif_utils.c +index 719581c..b3e7baa 100644 +--- a/netif_utils.c ++++ b/netif_utils.c +@@ -86,6 +86,27 @@ int ethtool_get_speed_duplex(char *ifname, int *speed, int *duplex) + return 0; + } + ++int get_link_status(const char *name) ++{ ++ int s = -1; ++ struct ifreq ifr = {}; ++ ++ if(!name) return 0; ++ ++ if((s = socket(AF_INET, SOCK_DGRAM, 0)) <= 0) return 0; ++ ++ strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); ++ ++ if(0 != ioctl(s, SIOCGIFFLAGS, &ifr)) { ++ close(s); ++ return 0; ++ } ++ ++ close(s); ++ ++ return ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING)); ++} ++ + /********* Sysfs based utility functions *************/ + + /* This sysfs stuff might break with interface renames */ +diff --git a/netif_utils.h b/netif_utils.h +index 99c99d5..cc45e02 100644 +--- a/netif_utils.h ++++ b/netif_utils.h +@@ -32,6 +32,8 @@ int get_hwaddr(char *ifname, unsigned char *hwaddr); + + int ethtool_get_speed_duplex(char *ifname, int *speed, int *duplex); + ++int get_link_status(const char *name); ++ + /********* Sysfs based utility functions *************/ + int is_bridge(char *if_name); + diff --git a/rstp/patches/50-support-qca-switch.patch b/rstp/patches/50-support-qca-switch.patch new file mode 100644 index 0000000000000000000000000000000000000000..57e0c9207a5d100c75bc1b516f48ac293709a7dc --- /dev/null +++ b/rstp/patches/50-support-qca-switch.patch @@ -0,0 +1,1815 @@ +diff --git a/Makefile b/Makefile +index f903f91..1cbc40b 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + + DSOURCES = brstate.c libnetlink.c epoll_loop.c bridge_track.c \ +- packet.c ctl_socket.c netif_utils.c main.c brmon.c ++ packet.c ctl_socket.c netif_utils.c main.c brmon.c switch_api.c qca_switch.c + + DOBJECTS = $(DSOURCES:.c=.o) + +diff --git a/bridge_track.c b/bridge_track.c +index 2967d08..4db8914 100644 +--- a/bridge_track.c ++++ b/bridge_track.c +@@ -44,6 +44,8 @@ + + #include "log.h" + ++#include "switch_api.h" ++ + /*------------------------------------------------------------*/ + + struct ifdata { +@@ -162,11 +164,13 @@ void update_port_stp_config(struct ifdata *ifc, UID_STP_PORT_CFG_T * cfg) + ifc->admin_point2point = cfg->admin_point2point; + } + ++int get_bridge_port_num(struct ifdata *ifc); ++ + /**************************************************************/ + + int add_port_stp(struct ifdata *ifc) + { /* Bridge is ifc->master */ +- TST((ifc->port_index = get_bridge_portno(ifc->name)) >= 0, -1); ++ TST((ifc->port_index = get_bridge_port_num(ifc)) >= 0, -1); + + /* Add port to STP */ + instance_begin(ifc->master); +@@ -320,7 +324,7 @@ struct ifdata *create_if(int if_index, struct ifdata *br) + p->is_bridge = (br == NULL); + + /* TODO: purge use of name, due to issue with renameing */ +- if_indextoname(if_index, p->name); ++ rstp_if_indextoname(if_index, p->name); + + if (p->is_bridge) { + INFO("Add bridge %s", p->name); +@@ -351,6 +355,8 @@ struct ifdata *create_if(int if_index, struct ifdata *br) + /* Add to interface list */ + ADD_TO_LIST(if_head, next, p); + ++ switch_port_attach_if(if_index); ++ + return p; + } + +@@ -380,9 +386,32 @@ void delete_if(struct ifdata *ifc) + REMOVE_FROM_LIST(if_head, next, ifc, + "Can't find interface ifindex %d on iflist", + ifc->if_index); ++ ++ switch_port_detach_if(ifc->if_index); ++ + free(ifc); + } + ++int get_bridge_port_num(struct ifdata *ifc) ++{ ++ struct ifdata *p; ++ unsigned int bitmap = 1; ++ int index = 0; ++ ++ if(ifc->is_bridge) ++ return -1; ++ ++ if(ifc->port_index > 0) ++ return ifc->port_index; ++ ++ for(p = if_head; p && (p->master == ifc->master); p = p->next) ++ bitmap = bitmap | (1 << p->port_index); ++ ++ while(bitmap & (1 << index)) ++index; ++ ++ return index; ++} ++ + static int stp_enabled(struct ifdata *br) + { + char path[40 + IFNAMSIZ]; +@@ -503,6 +532,9 @@ int bridge_notify(int br_index, int if_index, int newlink, + { + struct ifdata *br = NULL; + ++ if(!switch_notify(br_index, if_index, newlink, flags)) ++ return 0; ++ + LOG("br_index %d, if_index %d, up %d running %d", + br_index, if_index, (flags & IFF_UP), flags & IFF_RUNNING); + +@@ -573,7 +605,7 @@ int bridge_notify(int br_index, int if_index, int newlink, + } else { /* This may be a new link */ + if (!ifc) { + char ifname[IFNAMSIZ]; +- if (if_indextoname(if_index, ifname) ++ if (rstp_if_indextoname(if_index, ifname) + && is_bridge(ifname)) { + ifc = create_if(if_index, NULL); + if (!ifc) { +@@ -653,6 +685,20 @@ void bridge_bpdu_rcv(int if_index, const unsigned char *data, int len) + instance_end(); + } + ++void update_switch_port_link_status(struct switch_port *sw_port) ++{ ++ struct ifdata *br_port; ++ int up; ++ ++ br_port = find_if(sw_port->if_index); ++ if(!br_port) ++ return; ++ ++ up = switch_port_get_link_status(sw_port); ++ if(br_port->up != up) ++ set_if_up(br_port, up); ++} ++ + void bridge_one_second(void) + { + // LOG(""); +@@ -672,6 +718,7 @@ void bridge_one_second(void) + if (count % 60 == 0) + bridge_get_configuration(); + ++ switch_port_one_second(); + } + + /* Implementing STP_OUT functions */ +@@ -696,23 +743,32 @@ STP_OUT_flush_lt(IN int port_index, IN int vlan_id, + + char fname[128]; + if (port_index == 0) { /* i.e. passed port_index was 0 */ ++ struct ifdata *port; + sprintf(fname, "/sys/class/net/%s/bridge/flush", + current_br->name); + flush_port(fname); ++ ++ for (port = current_br->port_list; port; port = port->port_next) { ++ switch_port_flush_fdb(port->name); ++ } + } else if (type == LT_FLASH_ONLY_THE_PORT) { + struct ifdata *port = find_port(port_index); + TST(port != NULL, 0); +- sprintf(fname, "/sys/class/net/%s/brif/%s/flush", +- current_br->name, port->name); +- flush_port(fname); ++ if(switch_port_flush_fdb(port->name)) { ++ sprintf(fname, "/sys/class/net/%s/brif/%s/flush", ++ current_br->name, port->name); ++ flush_port(fname); ++ } + } else if (type == LT_FLASH_ALL_PORTS_EXCLUDE_THIS) { + struct ifdata *port; + for (port = current_br->port_list; port; port = port->port_next) { + if (port->port_index != port_index) { +- sprintf(fname, +- "/sys/class/net/%s/brif/%s/flush", +- current_br->name, port->name); +- flush_port(fname); ++ if(switch_port_flush_fdb(port->name)) { ++ sprintf(fname, ++ "/sys/class/net/%s/brif/%s/flush", ++ current_br->name, port->name); ++ flush_port(fname); ++ } + } + } + } else +@@ -782,8 +838,8 @@ STP_OUT_set_port_state(IN int port_index, IN int vlan_id, + fprintf(stderr, "set_port_state: Unexpected state %d\n", state); + return -1; + } +- if (port->up) +- bridge_set_state(port->if_index, br_state); ++ /*if (port->up)*/ /*always block port when it become down, then avoid loop when it become up again*/ ++ bridge_set_state(port->if_index, br_state); + return 0; + } + +@@ -881,7 +937,7 @@ int CTL_enable_bridge_rstp(int br_index, int enable) + struct ifdata *br = find_if(br_index); + if (br == NULL) { + char ifname[IFNAMSIZ]; +- if (if_indextoname(br_index, ifname) && is_bridge(ifname)) ++ if (rstp_if_indextoname(br_index, ifname) && is_bridge(ifname)) + br = create_if(br_index, NULL); + } + if (br == NULL || !br->is_bridge) +@@ -1003,7 +1059,7 @@ int CTL_add_bridge(char *name) + int br_index, up; + struct ifdata *br = NULL; + +- br_index = if_nametoindex(name); ++ br_index = rstp_if_nametoindex(name); + if(br_index == 0) { + ERROR("bridge %s not exist", name); + return 0; +@@ -1036,13 +1092,13 @@ int CTL_add_bridge_port(char *br_name, char *pt_name) + int br_index, if_index, up; + struct ifdata *br, *br_port; + +- br_index = if_nametoindex(br_name); ++ br_index = rstp_if_nametoindex(br_name); + if(br_index == 0) { + ERROR("bridge %s not exist", br_name); + return 0; + } + +- if_index = if_nametoindex(pt_name); ++ if_index = rstp_if_nametoindex(pt_name); + if(if_index == 0) { + ERROR("bridge port %s not exist", pt_name); + return 0; +@@ -1090,5 +1146,17 @@ int CTL_add_bridge_port(char *br_name, char *pt_name) + return 0; + } + ++int CTL_if_indextoname(unsigned int ifindex, char *ifname) ++{ ++ rstp_if_indextoname(ifindex, ifname); ++ return 0; ++} ++ ++int CTL_if_nametoindex(const char *ifname, unsigned int *ifindex) ++{ ++ *ifindex = rstp_if_nametoindex(ifname); ++ return 0; ++} ++ + #undef CTL_CHECK_BRIDGE_PORT + #undef CTL_CHECK_BRIDGE +diff --git a/brmon.c b/brmon.c +index 96a1113..1a6eeb3 100644 +--- a/brmon.c ++++ b/brmon.c +@@ -27,6 +27,7 @@ + #include "libnetlink.h" + + #include "bridge_ctl.h" ++#include "netif_utils.h" + + static const char SNAPSHOT[] = "v0.1"; + +@@ -66,7 +67,7 @@ static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, + + if (tb[IFLA_MASTER]) { + master = *(int*)RTA_DATA(tb[IFLA_MASTER]); +- fprintf(fp, "master %s ", if_indextoname(master, b1)); ++ fprintf(fp, "master %s ", rstp_if_indextoname(master, b1)); + } + + fprintf(fp, "\n"); +diff --git a/brstate.c b/brstate.c +index 889c2ea..e63519d 100644 +--- a/brstate.c ++++ b/brstate.c +@@ -25,6 +25,7 @@ + #include <string.h> + + #include "libnetlink.h" ++#include "switch_api.h" + + static int br_set_state(struct rtnl_handle *rth, unsigned ifindex, __u8 state) + { +@@ -53,7 +54,11 @@ extern struct rtnl_handle rth_state; + + int bridge_set_state(int ifindex, int brstate) + { +- int err = br_set_state(&rth_state, ifindex, brstate); ++ int err = switch_port_set_stp_state(ifindex, brstate); ++ if(!err) ++ return 0; ++ ++ err = br_set_state(&rth_state, ifindex, brstate); + if (err < 0) { + fprintf(stderr, + "Couldn't set bridge state, ifindex %d, state %d\n", +diff --git a/ctl_cli_wrap.c b/ctl_cli_wrap.c +index 8ad65c4..b7c5985 100644 +--- a/ctl_cli_wrap.c ++++ b/ctl_cli_wrap.c +@@ -35,6 +35,9 @@ CLIENT_SIDE_FUNCTION(enable_bridge_rstp) + CLIENT_SIDE_FUNCTION(set_debug_level) + CLIENT_SIDE_FUNCTION(add_bridge) + CLIENT_SIDE_FUNCTION(add_bridge_port) ++ CLIENT_SIDE_FUNCTION(if_indextoname) ++ CLIENT_SIDE_FUNCTION(if_nametoindex) ++ + #include <base.h> + const char *CTL_error_explanation(int err_no) + { +diff --git a/ctl_functions.h b/ctl_functions.h +index 4a04d62..33afae4 100644 +--- a/ctl_functions.h ++++ b/ctl_functions.h +@@ -46,6 +46,10 @@ int CTL_add_bridge(char *name); + + int CTL_add_bridge_port(char *br_name, char *pt_name); + ++int CTL_if_indextoname(unsigned int ifindex, char *ifname); ++ ++int CTL_if_nametoindex(const char *ifname, unsigned int *ifindex); ++ + #define CTL_ERRORS \ + CHOOSE(Err_Interface_not_a_bridge), \ + CHOOSE(Err_Bridge_RSTP_not_enabled), \ +diff --git a/ctl_main.c b/ctl_main.c +index a90e185..d3b2714 100644 +--- a/ctl_main.c ++++ b/ctl_main.c +@@ -80,7 +80,7 @@ static char *stp_state2str(RSTP_PORT_STATE stp_port_state, int detail) + static void CLI_out_port_id(int port, unsigned char cr) + { + static char ifname[IFNAMSIZ]; +- if (if_indextoname(port, ifname)) ++ if (CTL_if_indextoname(port, ifname)) + printf("%s", ifname); + else + printf("Ifindex %02d", port); +@@ -90,7 +90,9 @@ static void CLI_out_port_id(int port, unsigned char cr) + + int get_index_die(const char *ifname, const char *doc, int die) + { +- int r = if_nametoindex(ifname); ++ int r = 0; ++ ++ CTL_if_nametoindex(ifname, (unsigned int *)&r); + if (r == 0) { + fprintf(stderr, + "Can't find index for %s %s. Not a valid interface.\n", +diff --git a/ctl_socket.c b/ctl_socket.c +index 1438e5f..301d410 100644 +--- a/ctl_socket.c ++++ b/ctl_socket.c +@@ -70,6 +70,8 @@ int handle_message(int cmd, void *inbuf, int lin, void *outbuf, int *lout) + SERVER_MESSAGE_CASE(set_debug_level); + SERVER_MESSAGE_CASE(add_bridge); + SERVER_MESSAGE_CASE(add_bridge_port); ++ SERVER_MESSAGE_CASE(if_indextoname); ++ SERVER_MESSAGE_CASE(if_nametoindex); + + default: + ERROR("CTL: Unknown command %d", cmd); +diff --git a/ctl_socket.h b/ctl_socket.h +index a4b7c7a..d931b1e 100644 +--- a/ctl_socket.h ++++ b/ctl_socket.h +@@ -180,6 +180,38 @@ struct add_bridge_port_OUT { + #define add_bridge_port_COPY_OUT ({ (void)0; }) + #define add_bridge_port_CALL (in->br_name, in->pt_name) + ++#if 0 ++int CTL_if_indextoname(unsigned int ifindex, char *ifname); ++#endif ++#define CMD_CODE_if_indextoname 110 ++#define if_indextoname_ARGS (unsigned int ifindex, char *ifname) ++struct if_indextoname_IN { ++ unsigned int ifindex; ++}; ++struct if_indextoname_OUT { ++ char ifname[64]; ++}; ++#define if_indextoname_COPY_IN \ ++ ({ in->ifindex = ifindex; }) ++#define if_indextoname_COPY_OUT ({ strcpy(ifname, out->ifname); }) ++#define if_indextoname_CALL (in->ifindex, out->ifname) ++ ++#if 0 ++int CTL_if_nametoindex(const char *ifname, unsigned int *ifindex); ++#endif ++#define CMD_CODE_if_nametoindex 111 ++#define if_nametoindex_ARGS (const char *ifname, unsigned int *ifindex) ++struct if_nametoindex_IN { ++ char ifname[64]; ++}; ++struct if_nametoindex_OUT { ++ unsigned int ifindex; ++}; ++#define if_nametoindex_COPY_IN \ ++ ({ strncpy(in->ifname, ifname, sizeof(in->ifname)); }) ++#define if_nametoindex_COPY_OUT ({ *ifindex = out->ifindex; }) ++#define if_nametoindex_CALL (in->ifname, &out->ifindex) ++ + /* General case part in ctl command server switch */ + #define SERVER_MESSAGE_CASE(name) \ + case CMD_CODE_ ## name : do { \ +diff --git a/main.c b/main.c +index 33eebec..311dc7d 100644 +--- a/main.c ++++ b/main.c +@@ -27,6 +27,7 @@ + #include "ctl_socket_server.h" + #include "netif_utils.h" + #include "packet.h" ++#include "switch_api.h" + #include "log.h" + + #include <stdio.h> +@@ -55,6 +56,7 @@ topology_mode_t get_topology_mode(void) + + static void handle_signal(int signo) + { ++ switch_port_final(); + epoll_end_loop(); + } + +@@ -105,6 +107,7 @@ int main(int argc, char *argv[]) + TST(ctl_socket_init() == 0, -1); + TST(packet_sock_init() == 0, -1); + TST(netsock_init() == 0, -1); ++ TST(switch_port_init() == 0, -1); + TST(init_bridge_ops() == 0, -1); + if (become_daemon) { + FILE *f = fopen("/var/run/rstpd.pid", "w"); +diff --git a/netif_utils.c b/netif_utils.c +index b3e7baa..4e96d5a 100644 +--- a/netif_utils.c ++++ b/netif_utils.c +@@ -40,6 +40,7 @@ + #include <linux/sockios.h> + + #include "log.h" ++#include "switch_api.h" + + int netsock = -1; + +@@ -57,6 +58,10 @@ int netsock_init(void) + int get_hwaddr(char *ifname, unsigned char *hwaddr) + { + struct ifreq ifr; ++ ++ if(0 == switch_port_get_hwaddr(ifname, hwaddr)) ++ return 0; ++ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + if (ioctl(netsock, SIOCGIFHWADDR, &ifr) < 0) { +@@ -74,6 +79,9 @@ int ethtool_get_speed_duplex(char *ifname, int *speed, int *duplex) + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + struct ethtool_cmd ecmd; + ++ if(0 == switch_port_get_speed_duplex(ifname, speed, duplex)) ++ return 0; ++ + ecmd.cmd = ETHTOOL_GSET; + ifr.ifr_data = (caddr_t) & ecmd; + if (ioctl(netsock, SIOCETHTOOL, &ifr) < 0) { +@@ -89,10 +97,16 @@ int ethtool_get_speed_duplex(char *ifname, int *speed, int *duplex) + int get_link_status(const char *name) + { + int s = -1; ++ struct switch_port *sw_port; + struct ifreq ifr = {}; + + if(!name) return 0; + ++ sw_port = find_switch_port_by_name(name); ++ if(sw_port) { ++ return switch_port_get_link_status(sw_port); ++ } ++ + if((s = socket(AF_INET, SOCK_DGRAM, 0)) <= 0) return 0; + + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); +@@ -107,6 +121,36 @@ int get_link_status(const char *name) + return ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING)); + } + ++char *rstp_if_indextoname(unsigned int ifindex, char *ifname) ++{ ++ struct switch_port *sw_port; ++ ++ if(!ifname) ++ return NULL; ++ ++ sw_port = find_switch_port_by_index(ifindex); ++ if(sw_port) { ++ strcpy(ifname, sw_port->name); ++ return ifname; ++ } ++ else ++ return if_indextoname(ifindex, ifname); ++} ++ ++unsigned int rstp_if_nametoindex(const char *ifname) ++{ ++ struct switch_port *sw_port; ++ ++ if(!ifname) ++ return 0; ++ ++ sw_port = find_switch_port_by_name(ifname); ++ if(sw_port) ++ return sw_port->if_index; ++ else ++ return if_nametoindex(ifname); ++} ++ + /********* Sysfs based utility functions *************/ + + /* This sysfs stuff might break with interface renames */ +@@ -122,6 +166,10 @@ int is_bridge(char *if_name) + */ + int is_bridge_slave(char *br_name, char *if_name) + { ++ int ret = switch_port_is_bridge_slave(br_name, if_name); ++ if(ret >= 0) ++ return ret; ++ + char path[32 + 2 * IFNAMSIZ]; + sprintf(path, "/sys/class/net/%s/brif/%s", br_name, if_name); + return (access(path, R_OK) == 0); +diff --git a/netif_utils.h b/netif_utils.h +index cc45e02..3319341 100644 +--- a/netif_utils.h ++++ b/netif_utils.h +@@ -34,6 +34,10 @@ int ethtool_get_speed_duplex(char *ifname, int *speed, int *duplex); + + int get_link_status(const char *name); + ++char *rstp_if_indextoname(unsigned int ifindex, char *ifname); ++ ++unsigned int rstp_if_nametoindex(const char *ifname); ++ + /********* Sysfs based utility functions *************/ + int is_bridge(char *if_name); + +diff --git a/packet.c b/packet.c +index 001f6d4..09b06c0 100644 +--- a/packet.c ++++ b/packet.c +@@ -45,6 +45,7 @@ + #include <linux/filter.h> + + #include "log.h" ++#include "switch_api.h" + + static struct epoll_event_handler packet_event; + +@@ -76,6 +77,10 @@ void packet_send(int ifindex, const unsigned char *data, int len) + .sll_halen = ETH_ALEN, + }; + ++ if(switch_port_send_bpdu(ifindex, data, len) == 0) { ++ return; ++ } ++ + memcpy(&sl.sll_addr, data, ETH_ALEN); + + #ifdef PACKET_DEBUG +diff --git a/qca_switch.c b/qca_switch.c +new file mode 100644 +index 0000000..038d04e +--- /dev/null ++++ b/qca_switch.c +@@ -0,0 +1,409 @@ ++#include <stdarg.h> ++#include <unistd.h> ++#include <net/if.h> ++#include <linux/if_bridge.h> ++#include <sys/types.h> ++#include <arpa/inet.h> ++#include <stdlib.h> ++#include <stdio.h> ++#include <string.h> ++#include <fcntl.h> ++#include <sys/ioctl.h> ++#include <api/sw_ioctl.h> ++ ++#include "bridge_ctl.h" ++#include "netif_utils.h" ++#include "switch_api.h" ++#include "qca_switch.h" ++#include "log.h" ++ ++struct rxAtherosHeader ++{ ++ unsigned short src_port:3; ++ unsigned short with_tag:1; ++ unsigned short reserved:2; ++ unsigned short reason:5; ++ unsigned short priority:3; ++ unsigned short version:2; ++}; ++ ++struct txAtherosHeader ++{ ++ unsigned short dst_port:7; ++ unsigned short from_cpu:1; ++ unsigned short action:3; ++ unsigned short priority:3; ++ unsigned short version:2; ++}; ++ ++#define ATHEROS_HEADER_OFFSET 12 ++#define ATHEROS_HEADER_TYPE_OFFSET ATHEROS_HEADER_OFFSET ++#define ATHEROS_HEADER_INFO_OFFSET (ATHEROS_HEADER_OFFSET + 2) ++ ++#define ATHEROS_HEADER_TYPE_SIZE 2 ++#define ATHEROS_HEADER_INFO_SIZE 2 ++#define ATHEROS_HEADER_SIZE (ATHEROS_HEADER_TYPE_SIZE + ATHEROS_HEADER_INFO_SIZE) ++ ++#define ATHEROS_HEADER_VERSION 0X2 ++#define ATHEROS_HEADER_REASON_BPDU 0X4 ++ ++static unsigned short atheros_header_type; ++ ++ ++/*switch driver API start*/ ++int switch_driver_fd = -1; ++ ++a_uint32_t sw_api_param_nums(a_uint32_t api_id) ++{ ++ switch(api_id) { ++ case SW_API_MIRROR_ANALY_PT_SET: ++ case SW_API_FDB_RESV_ADD: ++ case SW_API_FDB_RESV_DEL: ++ return 2; ++ case SW_API_FDB_DELPORT: ++ case SW_API_PT_SPEED_GET: ++ case SW_API_PT_DUPLEX_GET: ++ case SW_API_PT_LINK_STATUS_GET: ++ case SW_API_HEADER_TYPE_SET: ++ case SW_API_PT_RXHDR_SET: ++ case SW_API_PT_TXHDR_SET: ++ return 3; ++ case SW_API_STP_PT_STATE_SET: ++ return 4; ++ } ++ ++ return 0; ++} ++ ++static sw_error_t sw_uk_exec(a_uint32_t api_id, ...) ++{ ++ a_uint32_t value[SW_MAX_API_PARAM] = { 0 }; ++ a_uint32_t rtn = SW_OK, i; ++ sw_error_t rv; ++ va_list arg_ptr; ++ a_uint32_t nr_param = 0; ++ ++ if((nr_param = sw_api_param_nums(api_id)) == 0) ++ return SW_FAIL; ++ ++ if(switch_driver_fd < 0) { ++ switch_driver_fd = open("/dev/switch_ssdk", O_RDWR); ++ if(switch_driver_fd < 0) ++ return SW_FAIL; ++ } ++ ++ value[0] = api_id; ++ value[1] = (a_uint32_t)&rtn; ++ ++ va_start(arg_ptr, api_id); ++ for (i = 0; i < nr_param; i++) { ++ value[i + 2] = va_arg(arg_ptr, a_uint32_t); ++ } ++ va_end(arg_ptr); ++ ++ rv = ioctl(switch_driver_fd, SIOCDEVPRIVATE, value); ++ if (SW_OK != rv) ++ return rv; ++ ++ return rtn; ++} ++/*switch driver API end*/ ++ ++int qca_switch_get_port_link_status(struct switch_port *sw_port) ++{ ++ int ret, status; ++ ++ ret = sw_uk_exec(SW_API_PT_LINK_STATUS_GET, 0, sw_port->priv.port_num, (a_uint32_t)(&status)); ++ if(!ret) ++ return status; ++ else ++ return 0; ++} ++ ++unsigned short qca_switch_get_atheros_header_type(void) ++{ ++ char cmd[128]; ++ char result[128]; ++ ++ if(!atheros_header_type) ++ { ++ snprintf(cmd, sizeof(cmd), "%s get_atheros_header_type", RSTP_CMD_PATH); ++ if(run_cmd(cmd, result, sizeof(result))) ++ atheros_header_type = strtol(result, NULL, 16); ++ else ++ atheros_header_type = 0xfefe; ++ } ++ ++ return atheros_header_type; ++} ++ ++unsigned char *qca_switch_recv_bpdu(struct switch_port **sw_port, struct sockaddr_ll *sl, unsigned char *origin_data, int origin_len, unsigned char *new_data, int *new_len) ++{ ++ unsigned short raw; ++ struct rxAtherosHeader *rxhd; ++ char control_channel[SW_NAME_SIZE]; ++ ++ if(!sw_port || !sl || !origin_data || !new_data || !new_len) ++ return NULL; ++ ++ raw = ntohs(*((unsigned short *)(origin_data + ATHEROS_HEADER_INFO_OFFSET))); ++ rxhd = (struct rxAtherosHeader *)&raw; ++ if((rxhd->version != ATHEROS_HEADER_VERSION) || (rxhd->reason != ATHEROS_HEADER_REASON_BPDU)) { ++ /*isn't what we wanted, skip*/ ++ *new_len = origin_len; ++ return origin_data; ++ } ++ ++ if(NULL == rstp_if_indextoname(sl->sll_ifindex, control_channel)) ++ return NULL; ++ ++ *sw_port = find_switch_port_by_num(control_channel, rxhd->src_port); ++ if((*sw_port) == NULL) ++ return NULL; ++ ++ memcpy(new_data, origin_data, ATHEROS_HEADER_OFFSET); ++ memcpy(new_data + ATHEROS_HEADER_OFFSET, origin_data + ATHEROS_HEADER_OFFSET + ATHEROS_HEADER_SIZE, (origin_len - ATHEROS_HEADER_OFFSET - ATHEROS_HEADER_SIZE)); ++ ++ *new_len = origin_len - ATHEROS_HEADER_SIZE; ++ return new_data; ++} ++ ++unsigned char *qca_switch_send_bpdu(struct switch_port *sw_port, struct sockaddr_ll *sl, unsigned char *origin_data, int origin_len, unsigned char *new_data, int *new_len) ++{ ++ unsigned short type, raw; ++ struct txAtherosHeader *txhd; ++ ++ if(!sw_port || !sl || !origin_data || !new_data || !new_len) ++ return NULL; ++ ++ type = htons(qca_switch_get_atheros_header_type()); ++ sl->sll_protocol = type; ++ raw = 0; ++ txhd = (struct txAtherosHeader *)&raw; ++ ++ txhd->dst_port = (1 << sw_port->priv.port_num); ++ txhd->from_cpu = 1; ++ txhd->priority = 7; ++ txhd->version = ATHEROS_HEADER_VERSION; ++ raw = htons(raw); ++ ++ /*copy dst mac*/ ++ memcpy(new_data, origin_data, HWADDR_SIZE); ++ /*use mac address of control channel*/ ++ get_hwaddr(sw_port->priv.control_channel, (new_data + HWADDR_SIZE)); ++ /*because of hardware limitation, BPDU will be rebounded back to linux, and this will result in repeated warning like ++ * "received packet on eth1 with own address as source address", so to avoid this warning, here crack the source mac of BPDU ++ * to let it not same with eth1. ++ */ ++ new_data[HWADDR_SIZE] = (new_data[HWADDR_SIZE] ^ 0x08); ++ /*copy atheros header type*/ ++ memcpy(new_data + ATHEROS_HEADER_TYPE_OFFSET, &type, sizeof(type)); ++ /*copy atheros header information*/ ++ memcpy(new_data + ATHEROS_HEADER_INFO_OFFSET, &raw, sizeof(raw)); ++ /*copy other data*/ ++ memcpy(new_data + (ATHEROS_HEADER_OFFSET + ATHEROS_HEADER_SIZE), origin_data + (2 * HWADDR_SIZE), (origin_len - (2 * HWADDR_SIZE))); ++ ++ *new_len = origin_len + ATHEROS_HEADER_SIZE; ++ return new_data; ++} ++ ++static int qca_stp_state_map[5] = {QCA_STP_STATE_DISABLE, QCA_STP_STATE_LISTEN, QCA_STP_STATE_LEARN, QCA_STP_STATE_FORWARD, QCA_STP_STATE_BLOCK}; ++ ++/*return value : 0 successful, other failed*/ ++int qca_switch_set_stp_state(struct switch_port *sw_port, int state) ++{ ++ if(!sw_port) ++ return -1; ++ ++ if(state >= (sizeof(qca_stp_state_map)/sizeof(qca_stp_state_map[0]))) ++ return -1; ++ ++ return sw_uk_exec(SW_API_STP_PT_STATE_SET, 0, 0, sw_port->priv.port_num, (a_uint32_t)qca_stp_state_map[state]); ++} ++ ++int qca_switch_get_speed(struct switch_port *sw_port) ++{ ++ int speed = 10; ++ ++ if(!sw_port) ++ return speed; ++ ++ sw_uk_exec(SW_API_PT_SPEED_GET, 0, sw_port->priv.port_num, (a_uint32_t)&speed); ++ ++ return speed; ++} ++ ++int qca_switch_get_duplex(struct switch_port *sw_port) ++{ ++ int duplex = 0; ++ ++ if(!sw_port) ++ return duplex; ++ ++ sw_uk_exec(SW_API_PT_DUPLEX_GET, 0, sw_port->priv.port_num, (a_uint32_t)&duplex); ++ ++ return duplex; ++} ++ ++int qca_switch_flush_fdb(struct switch_port *sw_port) ++{ ++ if(!sw_port) ++ return -1; ++ ++ return sw_uk_exec(SW_API_FDB_DELPORT, 0, sw_port->priv.port_num, 0); ++} ++ ++int qca_switch_destroy_port(struct switch_port *sw_port) ++{ ++ qca_switch_set_stp_state(sw_port, BR_STATE_FORWARDING); ++ return 0; ++} ++ ++int qca_switch_socket_init(void) ++{ ++ return socket(PF_PACKET, SOCK_RAW, htons(qca_switch_get_atheros_header_type())); ++} ++ ++void qca_switch_load_ports(void) ++{ ++ char cmd[128]; ++ char result[1024]; ++ char switch_type[SW_NAME_SIZE], control_channel[SW_NAME_SIZE], data_channel[SW_NAME_SIZE], port_name[SW_NAME_SIZE]; ++ char *index; ++ int port_num, result_len, match; ++ ++ snprintf(cmd, sizeof(cmd), "%s get_switch_ports", RSTP_CMD_PATH); ++ result_len = run_cmd(cmd, result, sizeof(result)); ++ if(result_len) ++ { ++ for(index = result; index < (result + result_len);) { ++ while((*index) && (*index != '='))++index; ++ if(!(*index)) ++ break; ++ ++ ++index; ++ match = sscanf(index, "%s %s %s %d %s", switch_type, control_channel, data_channel, &port_num, port_name); ++ if(match > 0) { ++ create_switch_port(switch_type, control_channel, data_channel, port_num, port_name); ++ } ++ else ++ break; ++ } ++ } ++} ++ ++fal_fdb_entry_t resv_entry = ++{ ++ {{0x01,0x80,0xc2,0x0,0x0,0x0}}, /*addr*/ ++ 65535, /*fid*/ ++ FAL_MAC_RDT_TO_CPU, /*dacmd*/ ++ FAL_MAC_FRWRD, /*sacmd*/ ++ {0}, /*port.map*/ ++ A_TRUE, /*portmap_en*/ ++ A_TRUE, /*is_multicast*/ ++ A_TRUE, /*static_en*/ ++ A_FALSE, /*leaky_en*/ ++ A_TRUE, /*mirror_en*/ ++ A_FALSE, /*clone_en*/ ++ A_TRUE, /*cross_pt_state*/ ++ A_FALSE, /*da_pri_en*/ ++ A_FALSE, /*da_queue*/ ++ A_FALSE, /*white_list_en*/ ++}; ++ ++static int cpu_port = -1; ++static int mirrot_port = -1; ++ ++/*configure switch to allow sending/receiving bpdu on switch*/ ++int qca_switch_enable_rx_tx_bpdu(void) ++{ ++ char cmd[128]; ++ char result[128]; ++ ++ snprintf(cmd, sizeof(cmd), "%s get_cpu_mirror_port", RSTP_CMD_PATH); ++ if(run_cmd(cmd, result, sizeof(result)) <= 0) ++ return -1; ++ ++ if(sscanf(result, "%d %d", &cpu_port, &mirrot_port) <= 0) ++ return -1; ++ ++ /*set atheros header type, a raw socket will listen on this ethernet type to receive bpdu from switch*/ ++ sw_uk_exec(SW_API_HEADER_TYPE_SET, 0, 1, qca_switch_get_atheros_header_type()); ++ ++ if(cpu_port >= 0) { ++ /*accept management packet with atheros header on cpu port(0)*/ ++ sw_uk_exec(SW_API_PT_RXHDR_SET, 0, cpu_port, 1); ++ /*when output management packet on cpu port(0), insert atheros header*/ ++ sw_uk_exec(SW_API_PT_TXHDR_SET, 0, cpu_port, 1); ++ } ++ ++ if(mirrot_port >= 0) { ++ /*accept management packet with atheros header on cpu port(6)*/ ++ sw_uk_exec(SW_API_PT_RXHDR_SET, 0, mirrot_port, 1); ++ /*when output management packet on cpu port(6), insert atheros header*/ ++ sw_uk_exec(SW_API_PT_TXHDR_SET, 0, mirrot_port, 1); ++ /*set mirror port to cpu port(6)*/ ++ sw_uk_exec(SW_API_MIRROR_ANALY_PT_SET, 0, mirrot_port); ++ } ++ ++ /*add a reserved fdb entry to capture bpdu on switch, then redirect it to Linux*/ ++ sw_uk_exec(SW_API_FDB_RESV_ADD, 0, (a_uint32_t)&resv_entry); ++ ++ return 0; ++} ++ ++/*remove configuration which is done in qca_switch_initialize*/ ++int qca_switch_disable_rx_tx_bpdu(void) ++{ ++ sw_uk_exec(SW_API_HEADER_TYPE_SET, 0, 0, 0); ++ ++ if(cpu_port >= 0) { ++ sw_uk_exec(SW_API_PT_RXHDR_SET, 0, cpu_port, 0); ++ sw_uk_exec(SW_API_PT_TXHDR_SET, 0, cpu_port, 0); ++ } ++ ++ if(mirrot_port >= 0) { ++ sw_uk_exec(SW_API_PT_RXHDR_SET, 0, mirrot_port, 0); ++ sw_uk_exec(SW_API_PT_TXHDR_SET, 0, mirrot_port, 0); ++ } ++ ++ sw_uk_exec(SW_API_FDB_RESV_DEL, 0, (a_uint32_t)&resv_entry); ++ ++ return 0; ++} ++ ++int qca_switch_initialize(void) ++{ ++ qca_switch_enable_rx_tx_bpdu(); ++ qca_switch_load_ports(); ++ ++ return 0; ++} ++ ++int qca_switch_finalize(void) ++{ ++ qca_switch_disable_rx_tx_bpdu(); ++ return 0; ++} ++ ++struct switch_ops qca_switch_ops = ++{ ++ .switch_type = "qca", ++ .get_link_status = qca_switch_get_port_link_status, ++ .get_speed = qca_switch_get_speed, ++ .get_duplex = qca_switch_get_duplex, ++ .get_hwaddr = switch_port_get_hwaddr_default, ++ .set_stp_state = qca_switch_set_stp_state, ++ .flush_fdb = qca_switch_flush_fdb, ++ .destroy_port = qca_switch_destroy_port, ++ .socket_init = qca_switch_socket_init, ++ .send_bpdu_hook = qca_switch_send_bpdu, ++ .recv_bpdu_hook = qca_switch_recv_bpdu, ++ .initialize = qca_switch_initialize, ++ .finalize = qca_switch_finalize ++}; ++ ++void qca_switch_init(void) ++{ ++ register_switch_ops(&qca_switch_ops); ++} +diff --git a/qca_switch.h b/qca_switch.h +new file mode 100644 +index 0000000..4f581ee +--- /dev/null ++++ b/qca_switch.h +@@ -0,0 +1,69 @@ ++ ++#ifndef QCA_SWITCH_H ++#define QCA_SWITCH_H ++ ++/*ssdk API start*/ ++#define SW_MAX_API_PARAM 12 ++typedef unsigned int a_uint32_t; ++typedef unsigned short a_uint16_t; ++typedef unsigned char a_uint8_t; ++ ++typedef enum ++{ ++ A_FALSE, ++ A_TRUE ++} a_bool_t; ++ ++typedef enum { ++ SW_OK = 0, /* Operation succeeded */ ++ SW_FAIL = -1, /* Operation failed */ ++} sw_error_t; ++ ++typedef struct ++{ ++ a_uint8_t uc[6]; ++} fal_mac_addr_t; ++ ++typedef enum ++{ ++ FAL_MAC_FRWRD = 0, /**< packets are normally forwarded */ ++ FAL_MAC_DROP, /**< packets are dropped */ ++ FAL_MAC_CPY_TO_CPU, /**< packets are copyed to cpu */ ++ FAL_MAC_RDT_TO_CPU /**< packets are redirected to cpu */ ++} fal_fwd_cmd_t; ++ ++typedef a_uint32_t fal_pbmp_t; ++ ++typedef struct ++{ ++ fal_mac_addr_t addr; ++ a_uint16_t fid; ++ fal_fwd_cmd_t dacmd; ++ fal_fwd_cmd_t sacmd; ++ union ++ { ++ a_uint32_t id; ++ fal_pbmp_t map; ++ } port; ++ a_bool_t portmap_en; ++ a_bool_t is_multicast; ++ a_bool_t static_en; ++ a_bool_t leaky_en; ++ a_bool_t mirror_en; ++ a_bool_t clone_en; ++ a_bool_t cross_pt_state; ++ a_bool_t da_pri_en; ++ a_uint8_t da_queue; ++ a_bool_t white_list_en; ++} fal_fdb_entry_t; ++/*ssdk API end*/ ++ ++enum ++{ ++ QCA_STP_STATE_DISABLE, ++ QCA_STP_STATE_BLOCK, ++ QCA_STP_STATE_LISTEN, ++ QCA_STP_STATE_LEARN, ++ QCA_STP_STATE_FORWARD ++}; ++#endif /* QCA_SWITCH_H */ +diff --git a/switch_api.c b/switch_api.c +new file mode 100644 +index 0000000..9e5a6fc +--- /dev/null ++++ b/switch_api.c +@@ -0,0 +1,590 @@ ++#include "switch_api.h" ++#include "bridge_ctl.h" ++#include "netif_utils.h" ++#include "epoll_loop.h" ++#include "log.h" ++ ++#include <linux/if_ether.h> ++#include <net/if.h> ++#include <linux/if_bridge.h> ++ ++static struct epoll_event_handler switch_port_packet_event; ++ ++/* ++ * return value : length of string in result ++ */ ++int run_cmd(const char *cmd, char *result, int max_len) ++{ ++ FILE *fp = NULL; ++ int result_len = 0; ++ ++ memset(result, 0, max_len); ++ fp = popen(cmd, "r"); ++ if (!fp) ++ return 0; ++ ++ while(fgets(result + result_len, max_len - result_len - 1, fp)) { ++ result_len += strlen(result + result_len); ++ if(result_len + 1 == max_len) ++ break; ++ } ++ ++ pclose(fp); ++ return result_len; ++} ++ ++struct switch_ops *switchOpsList = NULL; ++ ++int register_switch_ops(struct switch_ops *ops) ++{ ++ struct switch_ops *sw_ops; ++ ++ if(!ops || !ops->switch_type) ++ return -1; ++ ++ if(!ops->get_link_status || !ops->get_speed || !ops->get_duplex || !ops->get_hwaddr || !ops->set_stp_state || !ops->flush_fdb) ++ return -1; ++ ++ for(sw_ops = switchOpsList; sw_ops; sw_ops = sw_ops->next) { ++ if(strcmp(sw_ops->switch_type, ops->switch_type) == 0) { ++ return 0; ++ } ++ } ++ ++ ops->next = switchOpsList; ++ switchOpsList = ops; ++ ++ return 0; ++} ++ ++struct switch_ops *find_switch_ops(const char *switch_type) ++{ ++ struct switch_ops *sw_ops; ++ ++ if(!switch_type) ++ return NULL; ++ ++ for(sw_ops = switchOpsList; sw_ops; sw_ops = sw_ops->next) { ++ if(strcmp(sw_ops->switch_type, switch_type) == 0) { ++ return sw_ops; ++ } ++ } ++ ++ return NULL; ++} ++ ++/* Instances */ ++static struct switch_port *switchPortList = NULL; ++static unsigned int switch_port_if_index_latest = SWITCH_PORT_IFINDEX_MIN; ++ ++struct switch_port *find_switch_port_by_index(int index) ++{ ++ struct switch_port *sw_port; ++ for(sw_port = switchPortList; sw_port; sw_port = sw_port->next) { ++ if(sw_port->if_index == index) { ++ return sw_port; ++ } ++ } ++ ++ return NULL; ++} ++ ++struct switch_port *find_switch_port_by_name(const char *name) ++{ ++ struct switch_port *sw_port; ++ ++ if(!name) ++ return NULL; ++ ++ for(sw_port = switchPortList; sw_port; sw_port = sw_port->next) { ++ if(strcmp(sw_port->name, name) == 0) { ++ return sw_port; ++ } ++ } ++ ++ return NULL; ++} ++ ++struct switch_port *find_switch_port_by_num(char *control_channel, unsigned int port_num) ++{ ++ struct switch_port *sw_port; ++ ++ if(!control_channel) ++ return NULL; ++ ++ for(sw_port = switchPortList; sw_port; sw_port = sw_port->next) { ++ if((strcmp(sw_port->priv.control_channel, control_channel) == 0) && (sw_port->priv.port_num == port_num)) { ++ return sw_port; ++ } ++ } ++ ++ return NULL; ++} ++ ++/*add switch port to list, and sort by port_num*/ ++void switch_port_insert_to_list(struct switch_port *new) ++{ ++ struct switch_port *sw_port; ++ ++ if(!new) ++ return; ++ ++ for(sw_port = switchPortList; sw_port; sw_port = sw_port->next) { ++ if(new->priv.port_num > sw_port->priv.port_num) { ++ if(!sw_port->next || (new->priv.port_num < sw_port->next->priv.port_num)) { ++ break; ++ } ++ } ++ } ++ ++ if(sw_port) { ++ new->next = sw_port->next; ++ sw_port->next = new; ++ } ++ else { ++ new->next = switchPortList; ++ switchPortList = new; ++ } ++} ++ ++/*remove switch port from list*/ ++void switch_port_remove_from_list(struct switch_port *old) ++{ ++ struct switch_port *sw_port, *prev; ++ ++ if(!old) ++ return; ++ ++ for(prev = sw_port = switchPortList; sw_port; prev = sw_port, sw_port = sw_port->next) { ++ if(sw_port == old) ++ break; ++ } ++ ++ if(!sw_port) ++ return; ++ ++ if(prev == sw_port) { ++ switchPortList = sw_port->next; ++ } ++ else { ++ prev->next = sw_port->next; ++ } ++ ++ sw_port->next = NULL; ++} ++ ++void destroy_switch_port(struct switch_port *sw_port) ++{ ++ if(!sw_port) ++ return; ++ ++ if(sw_port->priv.ops && sw_port->priv.ops->destroy_port) ++ sw_port->priv.ops->destroy_port(sw_port); ++ ++ switch_port_remove_from_list(sw_port); ++ ++ if(sw_port->priv.control_channel) ++ free(sw_port->priv.control_channel); ++ if(sw_port->priv.data_channel) ++ free(sw_port->priv.data_channel); ++ ++ free(sw_port); ++} ++ ++struct switch_port *create_switch_port(char *switch_type, char *control_channel, char *data_channel, unsigned int port_num, char *port_name) ++{ ++ struct switch_ops *ops; ++ struct switch_port *new; ++ ++ if(!switch_type || !control_channel || !data_channel || !port_name) { ++ ERROR("parameter error."); ++ return NULL; ++ } ++ ++ if(NULL == (ops = find_switch_ops(switch_type))) { ++ ERROR("no such type of switch."); ++ return NULL; ++ } ++ ++ if(switch_port_if_index_latest >= SWITCH_PORT_IFINDEX_MAX) { ++ ERROR("Too many switch port."); ++ return NULL; ++ } ++ ++ new = (struct switch_port *)malloc(sizeof(struct switch_port)); ++ if(!new) { ++ ERROR("Allocate memory for struct switch_port failed."); ++ return NULL; ++ } ++ ++ snprintf(new->name, sizeof(new->name), "%s.%s", control_channel, port_name); ++ new->if_index = ++switch_port_if_index_latest; ++ ++ new->priv.control_channel = strdup(control_channel); ++ new->priv.data_channel = strdup(data_channel); ++ if(strcmp(control_channel, data_channel) != 0) ++ new->priv.type = SWITCH_PORT_TYPE_EXPORTED; ++ else ++ new->priv.type = SWITCH_PORT_TYPE_HIDDEN; ++ ++ new->priv.port_num = port_num; ++ new->priv.hwaddr_cache_valid = 0; ++ new->priv.ops = ops; ++ ++ switch_port_insert_to_list(new); ++ ++ if(new->priv.ops->create_port && (new->priv.ops->create_port(new) != 0)) { ++ destroy_switch_port(new); ++ new = NULL; ++ } ++ ++ return new; ++} ++ ++void switch_port_recv_bpdu(uint32_t events, struct epoll_event_handler *h) ++{ ++ int cc; ++ unsigned char buf[512]; ++ struct sockaddr_ll sl; ++ socklen_t salen = sizeof(sl); ++ struct switch_ops *sw_ops; ++ struct switch_port *sw_port = NULL; ++ unsigned char *new_data, *data; ++ int new_len, len; ++ ++ cc = recvfrom(h->fd, &buf, sizeof(buf), 0, (struct sockaddr *) &sl, &salen); ++ if (cc <= 0) { ++ ERROR("recvfrom failed: %m"); ++ return; ++ } ++ ++ new_len = cc + SWITCH_BPDU_MAX_EXTRA_SIZE; ++ new_data = (unsigned char *)malloc(new_len); ++ if(!new_data) { ++ ERROR("malloc failed."); ++ return; ++ } ++ ++ data = buf; ++ len = cc; ++ for(sw_ops = switchOpsList; sw_ops; sw_ops = sw_ops->next) { ++ if(!sw_ops->recv_bpdu_hook) ++ continue; ++ ++ data = sw_ops->recv_bpdu_hook(&sw_port, &sl, buf, cc, new_data, &new_len); ++ if(data) { ++ len = new_len; ++ break; ++ } ++ } ++ ++ if(!data) { ++ /*can't be processed, drop it*/ ++ goto recv_exit; ++ } ++ ++ bridge_bpdu_rcv((sw_port ? sw_port->if_index : sl.sll_ifindex), data, len); ++ ++recv_exit: ++ if(new_data) ++ free(new_data); ++} ++ ++/* ++ * return value : 0 successful, !=0 failed ++ */ ++int switch_port_send_bpdu(int ifindex, const unsigned char *data, int len) ++{ ++ int l; ++ struct sockaddr_ll sl; ++ struct switch_port *sw_port; ++ int control_channel_ifindex; ++ unsigned char *new_data = NULL, *send_data = (unsigned char *)data; ++ int new_len = len + SWITCH_BPDU_MAX_EXTRA_SIZE, send_len = len; ++ ++ sw_port = find_switch_port_by_index(ifindex); ++ if(!sw_port) { ++ /*not switch port, let function packet_send process*/ ++ return -1; ++ } ++ ++ control_channel_ifindex = rstp_if_nametoindex(sw_port->priv.control_channel); ++ if(!control_channel_ifindex) { ++ /*no linux network device connect to switch*/ ++ return 0; ++ } ++ ++ memset(&sl, 0, sizeof(sl)); ++ sl.sll_family = AF_PACKET; ++ sl.sll_protocol = htons(ETH_P_802_2); ++ sl.sll_ifindex = control_channel_ifindex; ++ sl.sll_halen = HWADDR_SIZE; ++ memcpy(&sl.sll_addr, data, HWADDR_SIZE); ++ ++ if(sw_port->priv.ops->send_bpdu_hook) { ++ new_data = (unsigned char *)malloc(new_len); ++ if(!new_data) ++ return 0; ++ ++ send_data = sw_port->priv.ops->send_bpdu_hook(sw_port, &sl, (unsigned char *)data, len, new_data, &new_len); ++ if(!send_data) { ++ free(new_data); ++ return 0; ++ } ++ ++ send_len = new_len; ++ } ++ ++ l = sendto(switch_port_packet_event.fd, send_data, send_len, 0, ++ (struct sockaddr *) &sl, sizeof(sl)); ++ ++ if (l < 0) { ++ if (errno != EWOULDBLOCK) ++ ERROR("send failed"); ++ } else if (l != send_len) ++ ERROR("short write in sendto: %d instead of %d", l, send_len); ++ ++ if(new_data) ++ free(new_data); ++ ++ return 0; ++} ++ ++int switch_port_get_link_status(struct switch_port *sw_port) ++{ ++ return sw_port->priv.ops->get_link_status(sw_port); ++} ++ ++/*return value : 0 successful, other failed*/ ++int switch_port_set_stp_state(int ifindex, int brstate) ++{ ++ struct switch_port *sw_port = find_switch_port_by_index(ifindex); ++ if(!sw_port) { ++ return -1; ++ } ++ ++ sw_port->priv.ops->set_stp_state(sw_port, brstate); ++ ++ if(sw_port->priv.type == SWITCH_PORT_TYPE_EXPORTED) ++ { ++ /*if switch port was exported as a Linux network device, we also need set its stp state in Linux bridge ++ * here is a trick : we don't use rstp_if_nametoindex because we konw it is a linux network device rather than a switch port ++ * a loop will take place if we don't do like this ++ */ ++ bridge_set_state(if_nametoindex(sw_port->priv.data_channel), brstate); ++ } ++ ++ return 0; ++} ++ ++int switch_port_get_speed_duplex(char *ifname, int *speed, int *duplex) ++{ ++ struct switch_port *sw_port = find_switch_port_by_name(ifname); ++ if(!sw_port) { ++ return -1; ++ } ++ ++ *speed = sw_port->priv.ops->get_speed(sw_port); ++ *duplex = sw_port->priv.ops->get_duplex(sw_port); ++ ++ return 0; ++} ++ ++int switch_port_get_hwaddr_default(struct switch_port *sw_port, unsigned char *hwaddr) ++{ ++ int ret; ++ ++ if(!sw_port || sw_port->priv.hwaddr_cache_valid || !hwaddr) ++ return -1; ++ ++ if(sw_port->priv.type == SWITCH_PORT_TYPE_EXPORTED) ++ ret = get_hwaddr(sw_port->priv.data_channel, hwaddr); ++ else ++ ret = get_hwaddr(sw_port->priv.control_channel, hwaddr); ++ ++ if(!ret && (sw_port->priv.type != SWITCH_PORT_TYPE_EXPORTED)) { ++ hwaddr[5] = (hwaddr[5] & 0xf0) | sw_port->priv.port_num; ++ } ++ ++ return ret; ++} ++ ++int switch_port_get_hwaddr(char *ifname, unsigned char *hwaddr) ++{ ++ struct switch_port *sw_port; ++ int ret; ++ ++ sw_port = find_switch_port_by_name(ifname); ++ if(!sw_port) { ++ return -1; ++ } ++ ++ if(!sw_port->priv.hwaddr_cache_valid) { ++ ret = sw_port->priv.ops->get_hwaddr(sw_port, sw_port->priv.hwaddr_cache); ++ if(!ret) { ++ sw_port->priv.hwaddr_cache_valid = 1; ++ } ++ else ++ return -1; ++ } ++ ++ memcpy(hwaddr, sw_port->priv.hwaddr_cache, HWADDR_SIZE); ++ return 0; ++} ++ ++int switch_port_flush_fdb(char *ifname) ++{ ++ struct switch_port *sw_port = find_switch_port_by_name(ifname); ++ if(!sw_port) { ++ return -1; ++ } ++ ++ return sw_port->priv.ops->flush_fdb(sw_port); ++} ++ ++/*call this API when a rstp bridge port created*/ ++int switch_port_attach_if(int ifindex) ++{ ++ return 0; ++} ++ ++/*call this API when a rstp bridge port deleted*/ ++int switch_port_detach_if(int ifindex) ++{ ++ switch_port_set_stp_state(ifindex, BR_STATE_FORWARDING); ++ return 0; ++} ++ ++static int interval = 0; ++static int elapse = 0; ++ ++void switch_port_one_second(void) ++{ ++ char cmd[128]; ++ char result[128]; ++ struct switch_port *sw_port; ++ ++ if(interval == 0) ++ { ++ snprintf(cmd, sizeof(cmd), "%s get_linkstatus_check_interval", RSTP_CMD_PATH); ++ if(run_cmd(cmd, result, sizeof(result))) { ++ sscanf(result, "%d", &interval); ++ } ++ else { ++ return; ++ } ++ } ++ ++ if((++elapse) != interval) ++ return; ++ ++ elapse = 0; ++ ++ for(sw_port = switchPortList; sw_port; sw_port = sw_port->next) ++ { ++ update_switch_port_link_status(sw_port); ++ } ++} ++ ++int switch_port_is_bridge_slave(char *br_name, char *if_name) ++{ ++ char *new_if_name; ++ struct switch_port *sw_port = find_switch_port_by_name(if_name); ++ if(!sw_port) ++ return -1; ++ ++ if(sw_port->priv.type == SWITCH_PORT_TYPE_HIDDEN) ++ new_if_name = sw_port->priv.control_channel; ++ else if(sw_port->priv.type == SWITCH_PORT_TYPE_EXPORTED) ++ new_if_name = sw_port->priv.data_channel; ++ else ++ return -1; ++ ++ if(!strcmp(if_name, new_if_name)) ++ return -1; ++ ++ return is_bridge_slave(br_name, new_if_name); ++} ++ ++int switch_notify(int br_index, int if_index, int newlink, unsigned flags) ++{ ++ char sw_name[64]; ++ struct switch_port *sw_port; ++ int ret = -1; ++ ++ if(is_switch_port_ifindex(if_index)) ++ return -1; ++ ++ if(NULL == rstp_if_indextoname(if_index, sw_name)) { ++ return -1; ++ } ++ ++ for(sw_port = switchPortList; sw_port; sw_port = sw_port->next) { ++ if((sw_port->priv.type == SWITCH_PORT_TYPE_HIDDEN) && strcmp(sw_port->priv.control_channel, sw_name)) ++ continue; ++ ++ if((sw_port->priv.type == SWITCH_PORT_TYPE_EXPORTED) && strcmp(sw_port->priv.data_channel, sw_name)) ++ continue; ++ ++ if(switch_port_get_link_status(sw_port)) ++ flags = (IFF_UP|IFF_RUNNING); ++ else ++ flags = 0; ++ ++ bridge_notify(br_index, sw_port->if_index, newlink, flags); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++extern void qca_switch_init(void); ++ ++int switch_port_init(void) ++{ ++ struct switch_ops *sw_ops; ++ ++ qca_switch_init(); ++ ++ for(sw_ops = switchOpsList; sw_ops; sw_ops = sw_ops->next) { ++ switch_port_packet_event.fd = sw_ops->socket_init(); ++ if(switch_port_packet_event.fd >= 0) { ++ if (fcntl(switch_port_packet_event.fd, F_SETFL, O_NONBLOCK) < 0) ++ ERROR("fcntl set nonblock failed: %m"); ++ ++ switch_port_packet_event.handler = switch_port_recv_bpdu; ++ add_epoll(&switch_port_packet_event); ++ ++ break; ++ } ++ } ++ ++ if(switch_port_packet_event.fd < 0) { ++ ERROR("init switch port socket failed"); ++ return -1; ++ } ++ ++ for(sw_ops = switchOpsList; sw_ops; sw_ops = sw_ops->next) { ++ if(sw_ops->initialize) ++ sw_ops->initialize(); ++ } ++ ++ return 0; ++} ++ ++int switch_port_final(void) ++{ ++ struct switch_port *sw_port; ++ struct switch_ops *sw_ops; ++ ++ while((sw_port = switchPortList) != NULL) { ++ destroy_switch_port(sw_port); ++ } ++ ++ for(sw_ops = switchOpsList; sw_ops; sw_ops = sw_ops->next) { ++ if(sw_ops->finalize) ++ sw_ops->finalize(); ++ } ++ ++ return 0; ++} +diff --git a/switch_api.h b/switch_api.h +new file mode 100644 +index 0000000..c982b0c +--- /dev/null ++++ b/switch_api.h +@@ -0,0 +1,162 @@ ++ ++#ifndef SWITCH_API_H ++#define SWITCH_API_H ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <stdarg.h> ++#include <string.h> ++#include <unistd.h> ++#include <sys/socket.h> ++#include <sys/ioctl.h> ++#include <fcntl.h> ++#include <netinet/in.h> ++ ++#include <linux/if_packet.h> ++ ++#define SWITCH_PORT_IFINDEX_MIN 0x2bcd0000 ++#define SWITCH_PORT_IFINDEX_MAX 0x2bcdffff ++#define SWITCH_PORT_IFINDEX_MASK 0xffff0000 ++#define is_switch_port_ifindex(x) (((x) & SWITCH_PORT_IFINDEX_MASK) == SWITCH_PORT_IFINDEX_MIN) ++ ++#define SW_NAME_SIZE 64 ++#define HWADDR_SIZE 6 ++#define SWITCH_BPDU_MAX_EXTRA_SIZE 16 ++#define RSTP_CMD_PATH "/lib/functions/rstp.sh" ++ ++struct switch_ops; ++ ++typedef enum ++{ ++ SWITCH_PORT_TYPE_HIDDEN, ++ SWITCH_PORT_TYPE_EXPORTED ++}switch_port_type_t; ++ ++struct switch_port_private ++{ ++ switch_port_type_t type; ++ /*name of Linux network device ++ *1, use this channel to send and receive BPDU for this switch port ++ *2, use this channel to manage hardware attributes of this switch port ++ */ ++ char *control_channel; ++ /*name of Linux network device ++ *data traffic of this switch port will go through this Linux network device ++ *1, when 'data_channel == control_channel', we define this switch port as hidden switch port ++ * because it hasn't an independent mapped Linux network device ++ *2, when 'data_channel != control_channel', we define this switch port as exported switch port ++ * because it has an independent mapped Linux network device ++ */ ++ char *data_channel; ++ ++ /*which hardware port this switch port represent*/ ++ unsigned int port_num; ++ ++ /*getting mac address of switch port is too frequent, so cache it*/ ++ unsigned short hwaddr_cache_valid; ++ unsigned char hwaddr_cache[HWADDR_SIZE]; ++ ++ struct switch_ops *ops; ++ ++ /*hardware specific field, should only be accessed by hardware specific code*/ ++ void *dev_priv; ++}; ++ ++struct switch_port ++{ ++ struct switch_port *next; ++ ++ /*section name of port in configuration file "/etc/config/rstp"*/ ++ char name[SW_NAME_SIZE]; ++ ++ /*if_index of switch port always start with a magic "0x2bcd" ++ * when be involved in Linux OS related operations, such as sending/receiving BPDU packets ++ * this switch port will use the if_index of switch_name ++ */ ++ int if_index; ++ ++ /*private field should only be accessed in switch_api.c*/ ++ struct switch_port_private priv; ++}; ++ ++typedef struct switch_ops ++{ ++ struct switch_ops *next; ++ char *switch_type; ++ ++ /*these API must be provided by hardware specific code*/ ++ int (*get_link_status)(struct switch_port *sw_port); ++ int (*get_speed)(struct switch_port *sw_port); ++ int (*get_duplex)(struct switch_port *sw_port); ++ int (*get_hwaddr)(struct switch_port *sw_port, unsigned char *hwaddr); ++ int (*set_stp_state)(struct switch_port *sw_port, int state); ++ int (*flush_fdb)(struct switch_port *sw_port); ++ ++ /*do some hardware specific initiation when create switch port*/ ++ int (*create_port)(struct switch_port *sw_port); ++ /*do some hardware specific finalization when destroy switch port*/ ++ int (*destroy_port)(struct switch_port *sw_port); ++ ++ /*create socket to send and receive BPDU*/ ++ int (*socket_init)(void); ++ /*hardware specific code can modify bpdu before sending it ++ *return : the new packet content pointer ++ *parameter : ++ *sw_port, IN, send bpdu on this switch port ++ *sl, OUT, LLC address ++ *origin_data, IN, original bpdu ++ *origin_len, IN, original bpdu length ++ *new_data, IN, buffer to use if modification is needed ++ *new_len, IN OUT, max size of new_data, also carry the real size of returned new packet content ++ */ ++ unsigned char *(*send_bpdu_hook)(struct switch_port *sw_port, struct sockaddr_ll *sl, unsigned char *origin_data, int origin_len, unsigned char *new_data, int *new_len); ++ /*hardware specific code can modify bpdu after receiving it ++ *return : the new packet content pointer ++ *parameter : ++ *sw_port, OUT, receiving switch port ++ *sl, IN, LLC address ++ *origin_data, IN, original bpdu ++ *origin_len, IN, original bpdu length ++ *new_data, IN, buffer to use if modification is needed ++ *new_len, IN OUT, max size of new_data, also carry the real size of returned new packet content ++ */ ++ unsigned char *(*recv_bpdu_hook)(struct switch_port **sw_port, struct sockaddr_ll *sl, unsigned char *origin_data, int origin_len, unsigned char *new_data, int *new_len); ++ ++ void (*one_second_callback)(void); ++ ++ /*hardware specific initiation when rstp start*/ ++ int (*initialize)(void); ++ /*hardware specific finalization when rstp stop*/ ++ int (*finalize)(void); ++}switch_ops_t; ++ ++/*public API start, these API can be used everywhere*/ ++int run_cmd(const char *cmd, char *result, int max_len); ++struct switch_port *find_switch_port_by_index(int index); ++struct switch_port *find_switch_port_by_name(const char *name); ++int switch_port_send_bpdu(int ifindex, const unsigned char *data, int len); ++int switch_port_get_link_status(struct switch_port *sw_port); ++int switch_port_set_stp_state(int ifindex, int brstate); ++int switch_port_get_speed_duplex(char *ifname, int *speed, int *duplex); ++int switch_port_get_hwaddr(char *ifname, unsigned char *hwaddr); ++int switch_port_flush_fdb(char *ifname); ++int switch_port_attach_if(int ifindex); ++int switch_port_detach_if(int ifindex); ++void switch_port_one_second(void); ++void update_switch_port_link_status(struct switch_port *sw_port); ++int switch_port_is_bridge_slave(char *br_name, char *if_name); ++int switch_notify(int br_index, int if_index, int newlink, unsigned flags); ++int switch_port_init(void); ++int switch_port_final(void); ++/*public API end*/ ++ ++/*private API start, these API can only be used in switch module*/ ++int register_switch_ops(struct switch_ops *ops); ++struct switch_ops *find_switch_ops(const char *switch_type); ++struct switch_port *find_switch_port_by_num(char *control_channel, unsigned int port_num); ++void destroy_switch_port(struct switch_port *sw_port); ++struct switch_port *create_switch_port(char *switch_type, char *control_channel, char *data_channel, unsigned int port_num, char *port_name); ++int switch_port_get_hwaddr_default(struct switch_port *sw_port, unsigned char *hwaddr); ++/*private API end*/ ++ ++#endif /* SWITCH_API_H */ diff --git a/rstp/patches/60-fix-hang-when-start-with-eth0-in-bridge.patch b/rstp/patches/60-fix-hang-when-start-with-eth0-in-bridge.patch new file mode 100644 index 0000000000000000000000000000000000000000..a5498578aa8456fc380a09953886176fedddce4c --- /dev/null +++ b/rstp/patches/60-fix-hang-when-start-with-eth0-in-bridge.patch @@ -0,0 +1,47 @@ +diff --git a/ctl_socket.c b/ctl_socket.c +index 301d410..dafc86f 100644 +--- a/ctl_socket.c ++++ b/ctl_socket.c +@@ -89,7 +89,7 @@ void ctl_rcv_handler(uint32_t events, struct epoll_event_handler *p) + struct msghdr msg; + struct sockaddr_un sa; + struct iovec iov[2]; +- int l; ++ int l, cmd; + + msg.msg_name = &sa; + msg.msg_namelen = sizeof(sa); +@@ -110,12 +110,15 @@ void ctl_rcv_handler(uint32_t events, struct epoll_event_handler *p) + return; + } + +- if (mhdr.lout) +- mhdr.res = handle_message(mhdr.cmd, msg_inbuf, mhdr.lin, +- msg_outbuf, &mhdr.lout); +- else +- mhdr.res = handle_message(mhdr.cmd, msg_inbuf, mhdr.lin, +- NULL, NULL); ++ cmd = mhdr.cmd; ++ if(cmd != CMD_CODE_enable_bridge_rstp) { ++ if (mhdr.lout) ++ mhdr.res = handle_message(mhdr.cmd, msg_inbuf, mhdr.lin, ++ msg_outbuf, &mhdr.lout); ++ else ++ mhdr.res = handle_message(mhdr.cmd, msg_inbuf, mhdr.lin, ++ NULL, NULL); ++ } + + if (mhdr.res < 0) + mhdr.lout = 0; +@@ -129,6 +132,11 @@ void ctl_rcv_handler(uint32_t events, struct epoll_event_handler *p) + ("CTL: Couldn't send full response, sent %d bytes instead of %zd.", + l, sizeof(mhdr) + mhdr.lout); + } ++ ++ if(cmd == CMD_CODE_enable_bridge_rstp){ ++ handle_message(cmd, msg_inbuf, mhdr.lin, ++ NULL, NULL); ++ } + } + + struct epoll_event_handler ctl_handler; diff --git a/rstp/patches/70-fix-if-bridge-header-not-selfcontain.patch b/rstp/patches/70-fix-if-bridge-header-not-selfcontain.patch new file mode 100644 index 0000000000000000000000000000000000000000..7f1d4a3e3664695326f3a9b8d62ed3c603937251 --- /dev/null +++ b/rstp/patches/70-fix-if-bridge-header-not-selfcontain.patch @@ -0,0 +1,22 @@ +diff -Nur a/bridge_track.c b/bridge_track.c +--- a/bridge_track.c 2015-04-03 16:13:27.109884142 -0700 ++++ b/bridge_track.c 2015-04-03 16:13:54.125884822 -0700 +@@ -29,6 +29,7 @@ + #include <unistd.h> + #include <net/if.h> + #include <stdlib.h> ++#include <netinet/in.h> + #include <linux/if_bridge.h> + #include <arpa/inet.h> + #include <sys/types.h> +diff -Nur a/qca_switch.c b/qca_switch.c +--- a/qca_switch.c 2015-04-03 16:13:27.109884142 -0700 ++++ b/qca_switch.c 2015-04-03 16:14:04.325885079 -0700 +@@ -1,6 +1,7 @@ + #include <stdarg.h> + #include <unistd.h> + #include <net/if.h> ++#include <netinet/in.h> + #include <linux/if_bridge.h> + #include <sys/types.h> + #include <arpa/inet.h> diff --git a/rstp/patches/80-rstp-bring-up-failed.patch b/rstp/patches/80-rstp-bring-up-failed.patch new file mode 100644 index 0000000000000000000000000000000000000000..32132c22e298efa4b061162a3b55ffde45a68a47 --- /dev/null +++ b/rstp/patches/80-rstp-bring-up-failed.patch @@ -0,0 +1,11 @@ +diff -Nur a/ctl_socket_client.c b/ctl_socket_client.c +--- a/ctl_socket_client.c 2015-05-20 16:17:57.458267282 -0700 ++++ b/ctl_socket_client.c 2015-05-20 16:18:23.270267932 -0700 +@@ -96,6 +96,7 @@ + msg.msg_control = NULL; + msg.msg_controllen = 0; + ++ mhdr.res = 0; + mhdr.cmd = cmd; + mhdr.lin = lin; + mhdr.lout = lout != NULL ? *lout : 0;