📄 bridgestp.c
字号:
bstp_topology_change_detection(sc);
}
bridge_rtdelete(sc, bif->ifp, 1);
}
bstp_set_port_state(bif, BSTP_IFSTATE_BLOCKING);
bstp_timer_stop(&bif->bif_forward_delay_timer);
}
}
void
bstp_set_port_state(bif, state)
struct bridge_iflist *bif;
u_int8_t state;
{
bif->bif_state = state;
}
void
bstp_topology_change_detection(sc)
struct bridge_softc *sc;
{
if (bstp_root_bridge(sc)) {
STPLOG ((" -> %s : Root Bridge\n", __FUNCTION__));
sc->sc_topology_change = 1;
bstp_timer_start(&sc->sc_topology_change_timer, 0);
} else if (!sc->sc_topology_change_detected) {
STPLOG ((" -> %s : NOT Root Bridge, Tx TCN\n", __FUNCTION__));
bstp_transmit_tcn(sc);
bstp_timer_start(&sc->sc_tcn_timer, 0);
}
sc->sc_topology_change_detected = 1;
}
void
bstp_topology_change_acknowledged(sc)
struct bridge_softc *sc;
{
sc->sc_topology_change_detected = 0;
bstp_timer_stop(&sc->sc_tcn_timer);
}
void
bstp_acknowledge_topology_change(sc, bif)
struct bridge_softc *sc;
struct bridge_iflist *bif;
{
bif->bif_topology_change_acknowledge = 1;
bstp_transmit_config(sc, bif);
}
struct mbuf *
bstp_input(sc, ifp, eh, m)
struct bridge_softc *sc;
struct ifnet *ifp;
struct ether_header *eh;
struct mbuf *m;
{
struct bridge_iflist *bif = NULL;
struct bstp_tbpdu tpdu;
struct bstp_cbpdu cpdu;
struct bstp_config_unit cu;
struct bstp_tcn_unit tu;
u_int16_t len;
LIST_FOREACH(bif, &sc->sc_iflist, next) {
if (!(bif->bif_flags & IFBIF_STP))
continue;
if (bif->ifp == ifp)
break;
}
if (bif == NULL)
goto out;
len = ntohs(eh->ether_type);
if (len < sizeof(tpdu)) {
goto out;
}
if (m->m_pkthdr.len > len)
m_adj(m, len - m->m_pkthdr.len);
if ((m = m_pullup(m, sizeof(tpdu))) == NULL) {
goto out;
}
bcopy(mtod(m, struct tpdu *), &tpdu, sizeof(tpdu));
if (tpdu.tbu_dsap != LLC_8021D_LSAP ||
tpdu.tbu_ssap != LLC_8021D_LSAP ||
tpdu.tbu_ctl != LLC_UI) {
goto out;
}
if (tpdu.tbu_protoid != 0 || tpdu.tbu_protover != 0) {
goto out;
}
switch (tpdu.tbu_bpdutype) {
case BSTP_MSGTYPE_TCN:
STPLOG (("STP : Rx TCN on <%s> from %02X:%02X:%02X:%02X:%02X:%02X \n", bif->ifp->if_xname,
eh->ether_shost[0], eh->ether_shost[1], eh->ether_shost[2],
eh->ether_shost[3], eh->ether_shost[4], eh->ether_shost[5]));
tu.tu_message_type = tpdu.tbu_bpdutype;
bstp_received_tcn_bpdu(sc, bif, &tu);
break;
case BSTP_MSGTYPE_CFG:
STPLOG (("STP : Rx CFG on <%s> from %02X:%02X:%02X:%02X:%02X:%02X \n", bif->ifp->if_xname,
eh->ether_shost[0], eh->ether_shost[1], eh->ether_shost[2],
eh->ether_shost[3], eh->ether_shost[4], eh->ether_shost[5]));
if ((m = m_pullup(m, sizeof(cpdu))) == NULL)
goto out;
bcopy(mtod(m, struct bstp_cpdu *), &cpdu, sizeof(cpdu));
cu.cu_rootid =
(((u_int64_t)ntohs(cpdu.cbu_rootpri)) << 48) |
(((u_int64_t)cpdu.cbu_rootaddr[0]) << 40) |
(((u_int64_t)cpdu.cbu_rootaddr[1]) << 32) |
(((u_int64_t)cpdu.cbu_rootaddr[2]) << 24) |
(((u_int64_t)cpdu.cbu_rootaddr[3]) << 16) |
(((u_int64_t)cpdu.cbu_rootaddr[4]) << 8) |
(((u_int64_t)cpdu.cbu_rootaddr[5]) << 0);
cu.cu_bridge_id =
(((u_int64_t)ntohs(cpdu.cbu_bridgepri)) << 48) |
(((u_int64_t)cpdu.cbu_bridgeaddr[0]) << 40) |
(((u_int64_t)cpdu.cbu_bridgeaddr[1]) << 32) |
(((u_int64_t)cpdu.cbu_bridgeaddr[2]) << 24) |
(((u_int64_t)cpdu.cbu_bridgeaddr[3]) << 16) |
(((u_int64_t)cpdu.cbu_bridgeaddr[4]) << 8) |
(((u_int64_t)cpdu.cbu_bridgeaddr[5]) << 0);
cu.cu_root_path_cost = ntohl(cpdu.cbu_rootpathcost);
cu.cu_message_age = ntohs(cpdu.cbu_messageage);
cu.cu_max_age = ntohs(cpdu.cbu_maxage);
cu.cu_hello_time = ntohs(cpdu.cbu_hellotime);
cu.cu_forward_delay = ntohs(cpdu.cbu_forwarddelay);
cu.cu_port_id = ntohs(cpdu.cbu_portid);
cu.cu_message_type = cpdu.cbu_bpdutype;
cu.cu_topology_change_acknowledgment =
(cpdu.cbu_flags & BSTP_FLAG_TCA) ? 1 : 0;
cu.cu_topology_change =
(cpdu.cbu_flags & BSTP_FLAG_TC) ? 1 : 0;
bstp_received_config_bpdu(sc, bif, &cu);
break;
default:
goto out;
}
out:
if (m)
m_freem(m);
return (NULL);
}
void
bstp_received_config_bpdu(sc, bif, cu)
struct bridge_softc *sc;
struct bridge_iflist *bif;
struct bstp_config_unit *cu;
{
int root;
root = bstp_root_bridge(sc);
if (bif->bif_state != BSTP_IFSTATE_DISABLED) {
if (bstp_supersedes_port_info(sc, bif, cu)) {
STPLOG ((" Rx CFG on <%s> superseds port info; RE-Evaluating...\n", bif->ifp->if_xname));
bstp_record_config_information(sc, bif, cu);
bstp_configuration_update(sc);
bstp_port_state_selection(sc);
if ((!bstp_root_bridge(sc)) && root) {
bstp_timer_stop(&sc->sc_hello_timer);
if (sc->sc_topology_change_detected) {
bstp_timer_stop(&sc->sc_topology_change_timer);
bstp_transmit_tcn(sc);
bstp_timer_start(&sc->sc_tcn_timer, 0);
}
}
if (bif == sc->sc_root_port) {
bstp_record_config_timeout_values(sc, cu);
bstp_config_bpdu_generation(sc);
if (cu->cu_topology_change_acknowledgment) {
bstp_topology_change_acknowledged(sc);
}
}
} else if (bstp_designated_port(sc, bif)) {
STPLOG ((" Port <%s> supersedes Rx CFG info\n", bif->ifp->if_xname));
bstp_transmit_config(sc, bif);
}
}
}
void
bstp_received_tcn_bpdu(sc, bif, tcn)
struct bridge_softc *sc;
struct bridge_iflist *bif;
struct bstp_tcn_unit *tcn;
{
if (bif->bif_state != BSTP_IFSTATE_DISABLED &&
bstp_designated_port(sc, bif)) {
bstp_topology_change_detection(sc);
bstp_acknowledge_topology_change(sc, bif);
}
}
void
bstp_hello_timer_expiry(sc)
struct bridge_softc *sc;
{
bstp_config_bpdu_generation(sc);
bstp_timer_start(&sc->sc_hello_timer, 0);
}
void
bstp_message_age_timer_expiry(sc, bif)
struct bridge_softc *sc;
struct bridge_iflist *bif;
{
int root;
root = bstp_root_bridge(sc);
bstp_become_designated_port(sc, bif);
bstp_configuration_update(sc);
bstp_port_state_selection(sc);
if ((bstp_root_bridge(sc)) && (!root)) {
sc->sc_max_age = sc->sc_bridge_max_age;
sc->sc_hello_time = sc->sc_bridge_hello_time;
sc->sc_forward_delay = sc->sc_bridge_forward_delay;
bstp_topology_change_detection(sc);
bstp_timer_stop(&sc->sc_tcn_timer);
bstp_config_bpdu_generation(sc);
bstp_timer_start(&sc->sc_hello_timer, 0);
}
}
void
bstp_forward_delay_timer_expiry(sc, bif)
struct bridge_softc *sc;
struct bridge_iflist *bif;
{
if (bif->bif_state == BSTP_IFSTATE_LISTENING) {
bstp_set_port_state(bif, BSTP_IFSTATE_LEARNING);
bstp_timer_start(&bif->bif_forward_delay_timer, 0);
} else if (bif->bif_state == BSTP_IFSTATE_LEARNING) {
bstp_set_port_state(bif, BSTP_IFSTATE_FORWARDING);
if (bstp_designated_for_some_port(sc) &&
bif->bif_change_detection_enabled)
bstp_topology_change_detection(sc);
}
}
int
bstp_designated_for_some_port(sc)
struct bridge_softc *sc;
{
struct bridge_iflist *bif;
LIST_FOREACH(bif, &sc->sc_iflist, next) {
if (!(bif->bif_flags & IFBIF_STP))
continue;
if (bif->bif_designated_bridge == sc->sc_bridge_id)
return (1);
}
return (0);
}
void
bstp_tcn_timer_expiry(sc)
struct bridge_softc *sc;
{
STPLOG ((" STP: tcn timer expired \n"));
bstp_transmit_tcn(sc);
bstp_timer_start(&sc->sc_tcn_timer, 0);
}
void
bstp_topology_change_timer_expiry(sc)
struct bridge_softc *sc;
{
STPLOG ((" STP: topology change timer expired \n"));
sc->sc_topology_change_detected = 0;
sc->sc_topology_change = 0;
}
void
bstp_hold_timer_expiry(sc, bif)
struct bridge_softc *sc;
struct bridge_iflist *bif;
{
if (bif->bif_config_pending)
bstp_transmit_config(sc, bif);
}
void
bstp_initialization(sc)
struct bridge_softc *sc;
{
struct bridge_iflist *bif, *mif;
struct arpcom *ac, *mac;
mif = NULL; mac = NULL;
/* Browse through the ethernet address of each interface and pick the
* one which has lowest value
*/
LIST_FOREACH(bif, &sc->sc_iflist, next) {
if (!(bif->bif_flags & IFBIF_STP)) {
continue;
}
if (bif->ifp->if_type != IFT_ETHER) {
continue;
}
bif->bif_port_id = (bif->bif_priority << 8) |
(bif->ifp->if_index & 0xff);
if (mif == NULL) {
mif = bif;
mac = (struct arpcom *)bif->ifp;
continue;
}
ac = (struct arpcom *)bif->ifp;
if (memcmp(ac->ac_enaddr, mac->ac_enaddr, ETHER_ADDR_LEN) < 0) {
mif = bif;
mac = (struct arpcom *)bif->ifp;
continue;
}
}
if (mif == NULL) {
bstp_stop(sc);
return;
}
/* Configure bridge-id as specified in standards
*/
sc->sc_bridge_id =
(((u_int64_t)sc->sc_bridge_priority) << 48) |
(((u_int64_t)mac->ac_enaddr[0]) << 40) |
(((u_int64_t)mac->ac_enaddr[1]) << 32) |
(mac->ac_enaddr[2] << 24) | (mac->ac_enaddr[3] << 16) |
(mac->ac_enaddr[4] << 8) | (mac->ac_enaddr[5]);
/* Configure self as root bridge
*/
sc->sc_designated_root = sc->sc_bridge_id;
sc->sc_root_path_cost = 0;
sc->sc_root_port = NULL;
sc->sc_max_age = sc->sc_bridge_max_age;
sc->sc_hello_time = sc->sc_bridge_hello_time;
sc->sc_forward_delay = sc->sc_bridge_forward_delay;
sc->sc_topology_change_detected = 0;
sc->sc_topology_change = 0;
bstp_timer_stop(&sc->sc_tcn_timer);
bstp_timer_stop(&sc->sc_topology_change_timer);
/* If there is a timeout already set on this, cancel it and restart.
* The intent is to avoid setting duplicate timeouts. If the timeout
* is already set, untimeout would cancel it.
*/
#ifdef __ECOS
if (!bstp_init_done) {
untimeout(bstp_tick, sc);
timeout(bstp_tick, sc, hz);
bstp_init_done = 1;
}
#else
if (!timeout_initialized(&sc->sc_bstptimeout))
timeout_set(&sc->sc_bstptimeout, bstp_tick, sc);
if (!timeout_pending(&sc->sc_bstptimeout))
timeout_add(&sc->sc_bstptimeout, hz);
#endif // __ECOS
LIST_FOREACH(bif, &sc->sc_iflist, next) {
if (bif->bif_flags & IFBIF_STP) {
STPLOG (("%s:%s ..(en). \n", __FUNCTION__, bif->ifp->if_xname));
bstp_enable_port(sc, bif);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -