summaryrefslogtreecommitdiff
path: root/usr/src/lib/librstp/common/stpm.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/librstp/common/stpm.c')
-rw-r--r--usr/src/lib/librstp/common/stpm.c360
1 files changed, 360 insertions, 0 deletions
diff --git a/usr/src/lib/librstp/common/stpm.c b/usr/src/lib/librstp/common/stpm.c
new file mode 100644
index 0000000000..af1e4aa70e
--- /dev/null
+++ b/usr/src/lib/librstp/common/stpm.c
@@ -0,0 +1,360 @@
+/************************************************************************
+ * RSTP library - Rapid Spanning Tree (802.1t, 802.1w)
+ * Copyright (C) 2001-2003 Optical Access
+ * Author: Alex Rozin
+ *
+ * This file is part of RSTP library.
+ *
+ * RSTP library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; version 2.1
+ *
+ * RSTP library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with RSTP library; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ **********************************************************************/
+
+ /* STP machine instance : bridge per VLAN: 17.17 */
+
+#include "base.h"
+#include "stpm.h"
+#include "stp_to.h" /* for STP_OUT_flush_lt */
+
+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;
+
+ /* state machines per bridge */
+ for (stater = this->machines; stater; stater = stater->next) {
+ iret = (*iter_callb) (stater);
+ if (exit_on_non_zero_ret && iret)
+ return iret;
+ else
+ mret += iret;
+ }
+
+ /* state machines per port */
+ 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
+ /* this->rolesel->debug = 2; */
+#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) {
+ /* nothing to do :) */
+ 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) { /* there are not any ports :( */
+ return STP_There_Are_No_Ports;
+ }
+
+ if (! STP_compute_bridge_id (this)) {/* can't compute bridge id ? :( */
+ return STP_Cannot_Compute_Bridge_Prio;
+ }
+
+ /* check, that the stpm has unique bridge Id */
+ if (0 != STP_stpm_check_bridge_priority (this)) {
+ /* there is an enabled bridge with same ID :( */
+ 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
+ /* A. see comment near STRONGLY_SPEC_802_1W in topoch.c */
+ /* B. port=0 here means: delete for all ports */
+#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;
+}
+
+/* ARGSUSED */
+void
+STP_stpm_stop (STPM_T* this)
+{
+}
+
+int
+STP_stpm_update (STPM_T* this) /* returns number of loops */
+{
+ register Bool need_state_change;
+ register int number_of_loops = 0;
+
+ need_state_change = False;
+
+ for (;;) {/* loop until not need changes */
+ need_state_change = _stp_stpm_iterate_machines (this,
+ STP_check_condition,
+ True);
+ if (! need_state_change) break;
+
+ number_of_loops++;
+ /* here we know, that at least one stater must be
+ updated (it has changed state) */
+ 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; /* IMHO, it may not be */
+
+ 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?";
+}
+
+
+
+
+