#include "base.h"
#include "stpm.h"
#include "stp_to.h"
static STPM_T *bridges = NULL;
static int
_stp_stpm_init_machine (STATE_MACH_T* this)
{
this->State = BEGIN;
(*(this->concreteEnterState)) (this);
return 0;
}
static int
_stp_stpm_iterate_machines (STPM_T* this,
int (*iter_callb) (STATE_MACH_T*),
Bool exit_on_non_zero_ret)
{
register STATE_MACH_T* stater;
register PORT_T* port;
int iret, mret = 0;
for (stater = this->machines; stater; stater = stater->next) {
iret = (*iter_callb) (stater);
if (exit_on_non_zero_ret && iret)
return iret;
else
mret += iret;
}
for (port = this->ports; port; port = port->next) {
for (stater = port->machines; stater; stater = stater->next) {
iret = (*iter_callb) (stater);
if (exit_on_non_zero_ret && iret)
return iret;
else
mret += iret;
}
}
return mret;
}
void
_stp_stpm_init_data (STPM_T* this)
{
STP_VECT_create (&this->rootPrio,
&this->BrId,
0,
&this->BrId,
0, 0);
this->BrTimes.MessageAge = 0;
STP_copy_times (&this->rootTimes, &this->BrTimes);
}
static unsigned char
_check_topoch (STPM_T* this)
{
register PORT_T* port;
for (port = this->ports; port; port = port->next) {
if (port->tcWhile) {
return 1;
}
}
return 0;
}
void
STP_stpm_one_second (STPM_T* param)
{
STPM_T* this = (STPM_T*) param;
register PORT_T* port;
register int iii;
if (STP_ENABLED != this->admin_state) return;
for (port = this->ports; port; port = port->next) {
for (iii = 0; iii < TIMERS_NUMBER; iii++) {
if (*(port->timers[iii]) > 0) {
(*port->timers[iii])--;
}
}
port->uptime++;
}
(void) STP_stpm_update (this);
this->Topo_Change = _check_topoch (this);
if (this->Topo_Change) {
this->Topo_Change_Count++;
this->timeSince_Topo_Change = 0;
} else {
this->Topo_Change_Count = 0;
this->timeSince_Topo_Change++;
}
}
STPM_T*
STP_stpm_create (int vlan_id, char* name)
{
STPM_T* this;
STP_NEW_IN_LIST(this, STPM_T, bridges, "stp instance");
this->admin_state = STP_DISABLED;
this->vlan_id = vlan_id;
if (name) {
STP_STRDUP(this->name, name, "stp bridge name");
}
this->machines = NULL;
this->ports = NULL;
STP_STATE_MACH_IN_LIST(rolesel);
#ifdef STP_DBG
#endif
return this;
}
int
STP_stpm_enable (STPM_T* this, UID_STP_MODE_T admin_state)
{
int rc = 0;
if (admin_state == this->admin_state) {
return 0;
}
if (STP_ENABLED == admin_state) {
if (this->ports)
rc = STP_stpm_start (this);
this->admin_state = admin_state;
} else {
this->admin_state = admin_state;
STP_stpm_stop (this);
}
return rc;
}
void
STP_stpm_delete (STPM_T* this)
{
register STPM_T* tmp;
register STPM_T* prev;
register STATE_MACH_T* stater;
register PORT_T* port;
register void* pv;
(void) STP_stpm_enable (this, STP_DISABLED);
for (stater = this->machines; stater; ) {
pv = (void*) stater->next;
STP_state_mach_delete (stater);
this->machines = stater = (STATE_MACH_T*) pv;
}
for (port = this->ports; port; ) {
pv = (void*) port->next;
STP_port_delete (port);
this->ports = port = (PORT_T*) pv;
}
prev = NULL;
for (tmp = bridges; tmp; tmp = tmp->next) {
if (tmp->vlan_id == this->vlan_id) {
if (prev) {
prev->next = this->next;
} else {
bridges = this->next;
}
if (this->name)
STP_FREE(this->name, "stp bridge name");
STP_FREE(this, "stp instance");
break;
}
prev = tmp;
}
}
int
STP_stpm_start (STPM_T* this)
{
register PORT_T* port;
if (! this->ports) {
return STP_There_Are_No_Ports;
}
if (! STP_compute_bridge_id (this)) {
return STP_Cannot_Compute_Bridge_Prio;
}
if (0 != STP_stpm_check_bridge_priority (this)) {
return STP_Invalid_Bridge_Priority;
}
_stp_stpm_init_data (this);
for (port = this->ports; port; port = port->next) {
STP_port_init (port, this, True);
}
#ifndef STRONGLY_SPEC_802_1W
#ifdef STP_DBG
stp_trace("%s (all, start stpm)",
"clearFDB");
#endif
STP_OUT_flush_lt (0, this->vlan_id, LT_FLASH_ONLY_THE_PORT, "start stpm");
#endif
(void) _stp_stpm_iterate_machines (this, _stp_stpm_init_machine, False);
(void) STP_stpm_update (this);
return 0;
}
void
STP_stpm_stop (STPM_T* this)
{
}
int
STP_stpm_update (STPM_T* this)
{
register Bool need_state_change;
register int number_of_loops = 0;
need_state_change = False;
for (;;) {
need_state_change = _stp_stpm_iterate_machines (this,
STP_check_condition,
True);
if (! need_state_change) break;
number_of_loops++;
number_of_loops += _stp_stpm_iterate_machines (this,
STP_change_state,
False);
}
return number_of_loops;
}
BRIDGE_ID *
STP_compute_bridge_id (STPM_T* this)
{
register PORT_T* port;
register PORT_T* min_num_port = NULL;
int port_index = 0;
for (port = this->ports; port; port = port->next) {
if (! port_index || port->port_index < port_index) {
min_num_port = port;
port_index = port->port_index;
}
}
if (! min_num_port) return NULL;
STP_OUT_get_port_mac (min_num_port->port_index, this->BrId.addr);
return &this->BrId;
}
STPM_T*
STP_stpm_get_the_list (void)
{
return bridges;
}
void
STP_stpm_update_after_bridge_management (STPM_T* this)
{
register PORT_T* port;
for (port = this->ports; port; port = port->next) {
port->reselect = True;
port->selected = False;
}
}
int
STP_stpm_check_bridge_priority (STPM_T* this)
{
register STPM_T* oth;
for (oth = bridges; oth; oth = oth->next) {
if (STP_ENABLED == oth->admin_state && oth != this &&
! STP_VECT_compare_bridge_id (&this->BrId, &oth->BrId)) {
return STP_Invalid_Bridge_Priority;
}
}
return 0;
}
const char*
STP_stpm_get_port_name_by_id (STPM_T* this, PORT_ID port_id)
{
register PORT_T* port;
for (port = this->ports; port; port = port->next) {
if (port_id == port->port_id) {
return port->port_name;
}
}
return "Undef?";
}