#include "base.h"
#include "stpm.h"
#include "stp_to.h"
#define STATES { \
CHOOSE(INIT), \
CHOOSE(INACTIVE), \
CHOOSE(TCACTIVE), \
CHOOSE(DETECTED), \
CHOOSE(NOTIFIED_TC), \
CHOOSE(PROPAGATING), \
CHOOSE(ACKNOWLEDGED), \
CHOOSE(NOTIFIED_TCN) \
}
#define GET_STATE_NAME STP_topoch_get_state_name
#include "choose.h"
#ifndef STRONGLY_SPEC_802_1W
#else
static Bool
flush (STATE_MACH_T *this, char* reason)
{
register PORT_T* port = this->owner.port;
Bool bret;
if (port->operEdge) return True;
if (this->debug) {
stp_trace("%s (%s, %s, %s, '%s')",
"flush", port->port_name, port->owner->name,
LT_FLASH_ONLY_THE_PORT == type ? "this port" : "other ports",
reason);
}
bret = STP_OUT_flush_lt (port->port_index, port->owner->vlan_id,
LT_FLASH_ONLY_THE_PORT, reason);
}
#endif
static void
setTcPropBridge (STATE_MACH_T* this, char* reason)
{
register PORT_T* port = this->owner.port;
register PORT_T* tmp;
for (tmp = port->owner->ports; tmp; tmp = tmp->next) {
if (tmp->port_index != port->port_index)
tmp->tcProp = True;
}
#ifndef STRONGLY_SPEC_802_1W
#ifdef STP_DBG
if (this->debug) {
stp_trace("%s (%s, %s, %s, '%s')",
"clearFDB", port->port_name, port->owner->name,
"other ports", reason);
}
#endif
STP_OUT_flush_lt (port->port_index, port->owner->vlan_id,
LT_FLASH_ALL_PORTS_EXCLUDE_THIS, reason);
#endif
}
static unsigned int
newTcWhile (STATE_MACH_T* this)
{
register PORT_T* port = this->owner.port;
if (port->sendRSTP && port->operPointToPointMac) {
return 2 * port->owner->rootTimes.HelloTime;
}
return port->owner->rootTimes.MaxAge;
}
void
STP_topoch_enter_state (STATE_MACH_T* this)
{
register PORT_T* port = this->owner.port;
switch (this->State) {
case BEGIN:
case INIT:
#ifdef STRONGLY_SPEC_802_1W
flush (this, "topoch INIT");
#endif
port->tcWhile = 0;
port->tc =
port->tcProp =
port->tcAck = False;
break;
case INACTIVE:
port->rcvdTc =
port->rcvdTcn =
port->rcvdTcAck = port->tc = port->tcProp = False;
break;
case TCACTIVE:
break;
case DETECTED:
port->tcWhile = newTcWhile (this);
#ifdef STP_DBG
if (this->debug)
stp_trace("DETECTED: tcWhile=%d on port %s",
port->tcWhile, port->port_name);
#endif
setTcPropBridge (this, "DETECTED");
port->tc = False;
break;
case NOTIFIED_TC:
port->rcvdTcn = port->rcvdTc = False;
if (port->role == DesignatedPort) {
port->tcAck = True;
}
setTcPropBridge (this, "NOTIFIED_TC");
break;
case PROPAGATING:
port->tcWhile = newTcWhile (this);
#ifdef STP_DBG
if (this->debug)
stp_trace("PROPAGATING: tcWhile=%d on port %s",
port->tcWhile, port->port_name);
#endif
#ifdef STRONGLY_SPEC_802_1W
flush (this, "topoch PROPAGATING");
#endif
port->tcProp = False;
break;
case ACKNOWLEDGED:
port->tcWhile = 0;
#ifdef STP_DBG
if (this->debug)
stp_trace("ACKNOWLEDGED: tcWhile=%d on port %s",
port->tcWhile, port->port_name);
#endif
port->rcvdTcAck = False;
break;
case NOTIFIED_TCN:
port->tcWhile = newTcWhile (this);
#ifdef STP_DBG
if (this->debug)
stp_trace("NOTIFIED_TCN: tcWhile=%d on port %s",
port->tcWhile, port->port_name);
#endif
break;
};
}
Bool
STP_topoch_check_conditions (STATE_MACH_T* this)
{
register PORT_T* port = this->owner.port;
if (BEGIN == this->State) {
return STP_hop_2_state (this, INIT);
}
switch (this->State) {
case INIT:
return STP_hop_2_state (this, INACTIVE);
case INACTIVE:
if (port->role == RootPort || port->role == DesignatedPort)
return STP_hop_2_state (this, TCACTIVE);
if (port->rcvdTc || port->rcvdTcn || port->rcvdTcAck ||
port->tc || port->tcProp)
return STP_hop_2_state (this, INACTIVE);
break;
case TCACTIVE:
if (port->role != RootPort && (port->role != DesignatedPort))
return STP_hop_2_state (this, INIT);
if (port->tc)
return STP_hop_2_state (this, DETECTED);
if (port->rcvdTcn)
return STP_hop_2_state (this, NOTIFIED_TCN);
if (port->rcvdTc)
return STP_hop_2_state (this, NOTIFIED_TC);
if (port->tcProp && !port->operEdge)
return STP_hop_2_state (this, PROPAGATING);
if (port->rcvdTcAck)
return STP_hop_2_state (this, ACKNOWLEDGED);
break;
case DETECTED:
return STP_hop_2_state (this, TCACTIVE);
case NOTIFIED_TC:
return STP_hop_2_state (this, TCACTIVE);
case PROPAGATING:
return STP_hop_2_state (this, TCACTIVE);
case ACKNOWLEDGED:
return STP_hop_2_state (this, TCACTIVE);
case NOTIFIED_TCN:
return STP_hop_2_state (this, NOTIFIED_TC);
};
return False;
}