diff --git a/src/inet/linklayer/configurator/Ieee8021dInterfaceData.cc b/src/inet/linklayer/configurator/Ieee8021dInterfaceData.cc index 793a9df0353..b0382a61541 100644 --- a/src/inet/linklayer/configurator/Ieee8021dInterfaceData.cc +++ b/src/inet/linklayer/configurator/Ieee8021dInterfaceData.cc @@ -23,7 +23,6 @@ namespace inet { Ieee8021dInterfaceData::PortInfo::PortInfo() { - priority = 0; linkCost = 1; edge = false; @@ -47,17 +46,17 @@ Ieee8021dInterfaceData::Ieee8021dInterfaceData() std::string Ieee8021dInterfaceData::str() const { - std::stringstream out; - out << "role:" << getRoleName() << " state:" << getStateName(); - return out.str(); + return detailedInfo(); } std::string Ieee8021dInterfaceData::detailedInfo() const { std::stringstream out; - out << "role:" << getRoleName() << "\tstate:" << getStateName() << "\n"; - out << "priority:" << getPriority() << "\n"; - out << "linkCost:" << getLinkCost() << "\n"; + out << "role:" << getRoleName(); + out << " state:" << getStateName(); + out << " priority:" << getPortPriority(); + out << " linkCost:" << getLinkCost(); + out << " isEdge:" << isEdge(); return out.str(); } @@ -65,43 +64,46 @@ std::string Ieee8021dInterfaceData::detailedInfo() const const char *Ieee8021dInterfaceData::getRoleName(PortRole role) { switch (role) { - case ALTERNATE: - return "ALTERNATE"; + case NOTASSIGNED: + return "NOTASSIGNED"; - case NOTASSIGNED: - return "NOTASSIGNED"; + case ROOT: + return "ROOT"; - case DISABLED: - return "DISABLED"; + case DESIGNATED: + return "DESIGNATED"; - case DESIGNATED: - return "DESIGNATED"; + case ALTERNATE: + return "ALTERNATE"; - case BACKUP: - return "BACKUP"; + case DISABLED: + return "DISABLED"; - case ROOT: - return "ROOT"; + case BACKUP: + return "BACKUP"; - default: - throw cRuntimeError("Unknown port role %d", role); + default: + throw cRuntimeError("Unknown port role %d", role); } } const char *Ieee8021dInterfaceData::getStateName(PortState state) { switch (state) { - case DISCARDING: - return "DISCARDING"; + case BLOCKING: + return "BLOCKING"; + + case LEARNING: + return "LEARNING"; - case LEARNING: - return "LEARNING"; + case FORWARDING: + return "FORWARDING"; - case FORWARDING: - return "FORWARDING"; + case DISCARDING: + return "DISCARDING"; - default: - throw cRuntimeError("Unknown port state %d", state); + default: + throw cRuntimeError("Unknown port state %d", state); } } diff --git a/src/inet/linklayer/configurator/Ieee8021dInterfaceData.h b/src/inet/linklayer/configurator/Ieee8021dInterfaceData.h index e79e7038a56..9999f3bcdd1 100644 --- a/src/inet/linklayer/configurator/Ieee8021dInterfaceData.h +++ b/src/inet/linklayer/configurator/Ieee8021dInterfaceData.h @@ -34,9 +34,9 @@ namespace inet { class INET_API Ieee8021dInterfaceData : public InterfaceProtocolData { public: - enum PortRole { ALTERNATE, NOTASSIGNED, DISABLED, DESIGNATED, BACKUP, ROOT }; + enum PortRole { NOTASSIGNED, ROOT, DESIGNATED, ALTERNATE, DISABLED, BACKUP /*rstp only*/ }; - enum PortState { DISCARDING, LEARNING, FORWARDING }; + enum PortState { BLOCKING /*stp only*/, LEARNING, FORWARDING, DISCARDING /*rstp only*/ }; class PortInfo { @@ -44,7 +44,6 @@ class INET_API Ieee8021dInterfaceData : public InterfaceProtocolData /* The following values have same meaning in both STP and RSTP. * See Ieee8021dBDPU for more info. */ - unsigned int priority; unsigned int linkCost; bool edge; @@ -131,13 +130,14 @@ class INET_API Ieee8021dInterfaceData : public InterfaceProtocolData void setPortPriority(unsigned int portPriority) { portData.portPriority = portPriority; } - unsigned int getPriority() const { return portData.priority; } - - void setPriority(unsigned int priority) { portData.priority = priority; } - PortRole getRole() const { return portData.role; } - void setRole(PortRole role) { portData.role = role; } + void setRole(PortRole role) { + EV_DETAIL << getInterfaceEntry()->getFullName() + << ": role changed " << getRoleName(portData.role) + << " --> " << getRoleName(role) << std::endl; + portData.role = role; + } const MacAddress& getRootAddress() const { return portData.rootAddress; } @@ -153,7 +153,12 @@ class INET_API Ieee8021dInterfaceData : public InterfaceProtocolData PortState getState() const { return portData.state; } - void setState(PortState state) { portData.state = state; } + void setState(PortState state) { + EV_DETAIL << getInterfaceEntry()->getFullName() + << ": state changed " << getStateName(portData.state) + << " --> " << getStateName(state) << std::endl; + portData.state = state; + } bool isEdge() const { return portData.edge; } diff --git a/src/inet/linklayer/configurator/L2NetworkConfigurator.cc b/src/inet/linklayer/configurator/L2NetworkConfigurator.cc index 06f8551509e..fb5690433d0 100644 --- a/src/inet/linklayer/configurator/L2NetworkConfigurator.cc +++ b/src/inet/linklayer/configurator/L2NetworkConfigurator.cc @@ -46,15 +46,30 @@ void L2NetworkConfigurator::initialize(int stage) { if (stage == INITSTAGE_LOCAL) configuration = par("config"); - else if (stage == INITSTAGE_NETWORK_CONFIGURATION) + else if (stage == INITSTAGE_LINK_LAYER) ensureConfigurationComputed(topology); } -L2NetworkConfigurator::InterfaceInfo::InterfaceInfo(Node *node, Node *childNode, InterfaceEntry *interfaceEntry) +void L2NetworkConfigurator::ensureConfigurationComputed(L2Topology& topology) { - this->node = node; - this->interfaceEntry = interfaceEntry; - this->childNode = childNode; + if (topology.getNumNodes() == 0) + computeConfiguration(); +} + +void L2NetworkConfigurator::computeConfiguration() +{ + long initializeStartTime = clock(); + + // extract topology into the L2Topology object + TIME(extractTopology(topology)); + + // read the configuration from XML; it will serve as input for port assignment + TIME(readInterfaceConfiguration(rootNode)); + + for(auto &entry : interfaces) + configureInterface(entry); + + printElapsedTime("initialize", initializeStartTime); } void L2NetworkConfigurator::extractTopology(L2Topology& topology) @@ -113,6 +128,15 @@ void L2NetworkConfigurator::extractTopology(L2Topology& topology) } } +Topology::LinkOut *L2NetworkConfigurator::findLinkOut(Node *node, int gateId) +{ + for (int i = 0; i < node->getNumOutLinks(); i++) + if (node->getLinkOut(i)->getLocalGateId() == gateId) + return node->getLinkOut(i); + + return nullptr; +} + void L2NetworkConfigurator::readInterfaceConfiguration(Node *rootNode) { std::set matchedBefore; @@ -129,8 +153,8 @@ void L2NetworkConfigurator::readInterfaceConfiguration(Node *rootNode) const char *portsAttr = interfaceElement->getAttribute("ports"); // switch gate indices, like "0 1 2" // Begin RSTP properties, for more information see RSTP module - const char *cost = interfaceElement->getAttribute("cost"); - const char *priority = interfaceElement->getAttribute("priority"); + const char *cost = interfaceElement->getAttribute("portCost"); + const char *priority = interfaceElement->getAttribute("portPriority"); const char *edge = interfaceElement->getAttribute("edge"); // End RSTP properties @@ -183,14 +207,25 @@ void L2NetworkConfigurator::readInterfaceConfiguration(Node *rootNode) // cost if (isNotEmpty(cost)) currentNode->interfaceInfos[i]->portData.linkCost = atoi(cost); + else { + unsigned int defaultPortCost = getRecommendedPortCost(currentNode, currentNode->interfaceInfos[i]->interfaceEntry); + currentNode->interfaceInfos[i]->portData.linkCost = defaultPortCost; + } // priority if (isNotEmpty(priority)) - currentNode->interfaceInfos[i]->portData.priority = atoi(priority); + currentNode->interfaceInfos[i]->portData.portPriority = atoi(priority); + else { + currentNode->interfaceInfos[i]->portData.portPriority = 128; + } - //edge + // edge if (isNotEmpty(edge)) currentNode->interfaceInfos[i]->portData.edge = strcmp(edge, "true") ? false : true; + else { + currentNode->interfaceInfos[i]->portData.edge = false; + } + EV_DEBUG << hostModule->getFullPath() << ":" << ifEntry->getInterfaceName() << endl; matchedBefore.insert(ifEntry); @@ -210,32 +245,6 @@ void L2NetworkConfigurator::readInterfaceConfiguration(Node *rootNode) } } -void L2NetworkConfigurator::computeConfiguration() -{ - long initializeStartTime = clock(); - // extract topology into the L2Topology object - TIME(extractTopology(topology)); - // read the configuration from XML; it will serve as input for port assignment - TIME(readInterfaceConfiguration(rootNode)); - printElapsedTime("initialize", initializeStartTime); -} - -void L2NetworkConfigurator::ensureConfigurationComputed(L2Topology& topology) -{ - if (topology.getNumNodes() == 0) - computeConfiguration(); -} - -Topology::LinkOut *L2NetworkConfigurator::findLinkOut(Node *node, int gateId) -{ - for (int i = 0; i < node->getNumOutLinks(); i++) - if (node->getLinkOut(i)->getLocalGateId() == gateId) - return node->getLinkOut(i); - - - return nullptr; -} - bool L2NetworkConfigurator::linkContainsMatchingHostExcept(InterfaceInfo *currentInfo, Matcher& hostMatcher, cModule *exceptModule) { @@ -258,6 +267,11 @@ bool L2NetworkConfigurator::linkContainsMatchingHostExcept(InterfaceInfo *curren return false; } +void L2NetworkConfigurator::addToConfigureInterface(InterfaceEntry *interfaceEntry) +{ + interfaces.push_back(interfaceEntry); +} + void L2NetworkConfigurator::configureInterface(InterfaceEntry *interfaceEntry) { ensureConfigurationComputed(topology); @@ -281,10 +295,36 @@ void L2NetworkConfigurator::configureInterface(InterfaceInfo *interfaceInfo) Ieee8021dInterfaceData *interfaceData = interfaceEntry->getProtocolData(); interfaceData->setLinkCost(interfaceInfo->portData.linkCost); - interfaceData->setPriority(interfaceInfo->portData.priority); + interfaceData->setPortPriority(interfaceInfo->portData.portPriority); interfaceData->setEdge(interfaceInfo->portData.edge); } +unsigned int L2NetworkConfigurator::getRecommendedPortCost(Node *node, InterfaceEntry *ie) +{ + Topology::LinkOut *linkOut = findLinkOut(node, ie->getNodeOutputGateId()); + double datarate = linkOut->getLocalGate()->getChannel()->getNominalDatarate(); // in bps + + // based on Table 17-3 in IEEE 802.1D-2004 + if(datarate <= 100000) + return 200000000; + else if(datarate > 100000 && datarate <= 1000000) + return 20000000; + else if(datarate > 1000000 && datarate <= 10000000) + return 2000000; + else if(datarate > 10000000 && datarate <= 100000000) + return 200000; + else if(datarate > 100000000 && datarate <= 1000000000) + return 20000; + else if(datarate > 1000000000 && datarate <= 10000000000) + return 2000; + else if(datarate > 10000000000 && datarate <= 100000000000) + return 200; + else if(datarate > 100000000000 && datarate <= 1000000000000) + return 20; + + return 2; +} + L2NetworkConfigurator::Matcher::~Matcher() { for (auto & elem : matchers) @@ -313,9 +353,15 @@ bool L2NetworkConfigurator::Matcher::matches(const char *s) if (elem->matches(s)) return true; - return false; } +L2NetworkConfigurator::InterfaceInfo::InterfaceInfo(Node *node, Node *childNode, InterfaceEntry *interfaceEntry) +{ + this->node = node; + this->interfaceEntry = interfaceEntry; + this->childNode = childNode; +} + } // namespace inet diff --git a/src/inet/linklayer/configurator/L2NetworkConfigurator.h b/src/inet/linklayer/configurator/L2NetworkConfigurator.h index 5ef3de5418c..882e6910d93 100644 --- a/src/inet/linklayer/configurator/L2NetworkConfigurator.h +++ b/src/inet/linklayer/configurator/L2NetworkConfigurator.h @@ -108,6 +108,7 @@ class INET_API L2NetworkConfigurator : public cSimpleModule cXMLElement *configuration = nullptr; L2Topology topology; Node *rootNode = nullptr; + std::vector interfaces; protected: virtual void initialize(int stage) override; @@ -131,7 +132,9 @@ class INET_API L2NetworkConfigurator : public cSimpleModule virtual bool linkContainsMatchingHostExcept(InterfaceInfo *currentInfo, Matcher& hostMatcher, cModule *exceptModule); void ensureConfigurationComputed(L2Topology& topology); virtual Topology::LinkOut *findLinkOut(Node *node, int gateId); + virtual void configureInterface(InterfaceEntry *interfaceEntry); void configureInterface(InterfaceInfo *interfaceInfo); + unsigned int getRecommendedPortCost(Node *node, InterfaceEntry *ie); public: /** @@ -142,7 +145,7 @@ class INET_API L2NetworkConfigurator : public cSimpleModule /** * Configures the provided interface based on the current network configuration. */ - virtual void configureInterface(InterfaceEntry *interfaceEntry); + void addToConfigureInterface(InterfaceEntry *interfaceEntry); }; } // namespace inet diff --git a/src/inet/linklayer/configurator/L2NetworkConfigurator.ned b/src/inet/linklayer/configurator/L2NetworkConfigurator.ned index 5f4eedcd53b..0516615ace8 100644 --- a/src/inet/linklayer/configurator/L2NetworkConfigurator.ned +++ b/src/inet/linklayer/configurator/L2NetworkConfigurator.ned @@ -29,7 +29,7 @@ package inet.linklayer.configurator; // priority 32768: //
 // 
-//   
+//   
 // 
 // 
 //
@@ -39,6 +39,6 @@ simple L2NetworkConfigurator
 {
     parameters:
         @display("i=block/cogwheel");
-        xml config = default(xml(""));
+        xml config = default(xml("  "));
 }
 
diff --git a/src/inet/linklayer/configurator/L2NodeConfigurator.cc b/src/inet/linklayer/configurator/L2NodeConfigurator.cc
index 8aebabbe33e..e699b67033c 100644
--- a/src/inet/linklayer/configurator/L2NodeConfigurator.cc
+++ b/src/inet/linklayer/configurator/L2NodeConfigurator.cc
@@ -43,6 +43,7 @@ void L2NodeConfigurator::initialize(int stage)
 bool L2NodeConfigurator::handleOperationStage(LifecycleOperation *operation, IDoneCallback *doneCallback)
 {
     Enter_Method_Silent();
+
     if (dynamic_cast(operation)) {
         if (static_cast(operation->getCurrentStage()) == ModuleStartOperation::STAGE_LINK_LAYER) {
             prepareNode();
@@ -55,6 +56,7 @@ bool L2NodeConfigurator::handleOperationStage(LifecycleOperation *operation, IDo
         /*nothing to do*/;
     else
         throw cRuntimeError("Unsupported lifecycle operation '%s'", operation->getClassName());
+
     return true;
 }
 
@@ -73,9 +75,8 @@ void L2NodeConfigurator::prepareInterface(InterfaceEntry *interfaceEntry)
 void L2NodeConfigurator::configureNode()
 {
     ASSERT(networkConfigurator);
-    // std::cout << "configureNode(): " << interfaceTable->getNumInterfaces() << endl;
     for (int i = 0; i < interfaceTable->getNumInterfaces(); i++)
-        networkConfigurator->configureInterface(interfaceTable->getInterface(i));
+        networkConfigurator->addToConfigureInterface(interfaceTable->getInterface(i));
 }
 
 void L2NodeConfigurator::receiveSignal(cComponent *source, simsignal_t signalID, cObject *obj, cObject *details)
@@ -87,7 +88,7 @@ void L2NodeConfigurator::receiveSignal(cComponent *source, simsignal_t signalID,
         InterfaceEntry *ie = check_and_cast(obj);
         prepareInterface(ie);
         if (networkConfigurator)
-            networkConfigurator->configureInterface(ie);
+            networkConfigurator->addToConfigureInterface(ie);
     }
 }
 
diff --git a/src/inet/linklayer/ethernet/switch/MacAddressTable.cc b/src/inet/linklayer/ethernet/switch/MacAddressTable.cc
index 47731404b97..1ce2678e467 100644
--- a/src/inet/linklayer/ethernet/switch/MacAddressTable.cc
+++ b/src/inet/linklayer/ethernet/switch/MacAddressTable.cc
@@ -170,6 +170,8 @@ bool MacAddressTable::updateTableWithAddress(int interfaceId, const MacAddress&
         if (vid == 0)
             addressTable = table;
 
+        WATCH_MAP(*addressTable);
+
         vlanAddressTable[vid] = table;
         iter = table->end();
     }
diff --git a/src/inet/linklayer/ieee8021d/common/Ieee8021dBpdu.msg b/src/inet/linklayer/ieee8021d/common/Ieee8021dBpdu.msg
index 1a931816e39..ef73caab266 100644
--- a/src/inet/linklayer/ieee8021d/common/Ieee8021dBpdu.msg
+++ b/src/inet/linklayer/ieee8021d/common/Ieee8021dBpdu.msg
@@ -19,6 +19,32 @@ import inet.linklayer.common.MacAddress;
 
 namespace inet;
 
+struct BpduFlags  // flags: 1 byte
+{                                      
+    bool tcaFlag;           //   Topology Change Acknowledgment flag
+    uint8_t reserved = 0;   //   unused 6 bits of Flags
+    bool tcFlag;            //   Topology Change flag
+}
+
+struct RootIdentifier
+{
+    uint16_t rootPriority;  // 2 bytes, priority of the tree root
+    MacAddress rootAddress; // 6 bytes, address of the tree root
+}
+
+struct BridgeIdentifier
+{
+    uint16_t bridgePriority;  // 2 bytes, priority of sender bridge
+    MacAddress bridgeAddress; // 6 bytes, address of sender bridge
+}
+
+struct PortIdentifier
+{
+    uint8_t portPriority;  // 1 byte, priority of sender port
+    uint8_t portNum;       // 1 byte, port number (ethg[] gate index) of sender port
+                           // (or 4 bit priority (shifted with 4 bit) and 12 bit portnum (in 802.1D-2004))
+}
+
 //
 // Represents a BPDU (Bridge PDU) used by the STP and RSTP protocols,
 // as defined in the 802.1D-1998 specification.
@@ -26,30 +52,17 @@ namespace inet;
 class Bpdu extends FieldsChunk
 {
     chunkLength = B(35);
-    uint16_t protocolIdentifier;              // 2 bytes, 0 for STP, 1 for RSTP (TODO use them)
-    unsigned int protocolVersionIdentifier;   // 1 byte, version ID, currently 0
-
-    unsigned int bpduType;                    // 1 byte, 0 for Configuration BPDU, 1 for Topology Change Notification BPDU
-
-                                              // flags: 1 byte
-    bool tcaFlag;                             //   Topology Change Acknowledgment flag
-    uint8_t reserved = 0;                     //   unused 6 bits of Flags
-    bool tcFlag;                              //   Topology Change flag
-
-    uint16_t rootPriority;                    // 2 bytes, priority of the tree root (part of Root Identifier)
-    MacAddress rootAddress;                   // 6 bytes, address of the tree root (part of Root Identifier)
-    uint32_t rootPathCost;                    // 4 bytes, cost to the root
-
-    uint16_t bridgePriority;                  // 2 bytes, priority of sender bridge (part of Bridge Identifier)
-    MacAddress bridgeAddress;                 // 6 bytes, address of sender bridge (part of Bridge Identifier)
-
-    unsigned int portPriority;                // 1 byte, priority of sender port (part of Port Identifier)
-    unsigned int portNum;                     // 1 byte, port number (ethg[] gate index) of sender port (part of Port Identifier)
-                                              // (or 4 bit priority (shifted with 4 bit) and 12 bit portnum (in 802.1D-2004))
-
-    simtime_t messageAge;                     // 2 bytes, Message Age (in 256ths of a second)
-    simtime_t maxAge;                         // 2 bytes, maximum lifetime of the BPDU (in 256ths of a second)
-    simtime_t helloTime;                      // 2 bytes, Hello Time of the sender bridge (in 256ths of a second)
-    simtime_t forwardDelay;                   // 2 bytes, Forward Delay timer of the sender bridge (in 256ths of a second)
+    
+    uint16_t protocolIdentifier;        // 2 bytes, 0 for STP, 1 for RSTP (TODO use them)
+    uint8_t protocolVersionIdentifier;  // 1 byte, version ID, currently 0
+    uint8_t bpduType;                   // 1 byte, 0 for Configuration BPDU, 1 for Topology Change Notification BPDU
+	BpduFlags bpduFlags;
+    RootIdentifier rootIdentifier;    
+    uint32_t rootPathCost;              // 4 bytes, cost to the root
+    BridgeIdentifier bridgeIdentifier;
+    PortIdentifier portIdentifier;    
+    simtime_t messageAge;               // 2 bytes, Message Age (in 256ths of a second)
+    simtime_t maxAge;                   // 2 bytes, maximum lifetime of the BPDU (in 256ths of a second)
+    simtime_t helloTime;                // 2 bytes, Hello Time of the sender bridge (in 256ths of a second)
+    simtime_t forwardDelay;             // 2 bytes, Forward Delay timer of the sender bridge (in 256ths of a second)
 }
-
diff --git a/src/inet/linklayer/ieee8021d/common/Ieee8021dBpduSerializer.cc b/src/inet/linklayer/ieee8021d/common/Ieee8021dBpduSerializer.cc
new file mode 100644
index 00000000000..59f6c08cd94
--- /dev/null
+++ b/src/inet/linklayer/ieee8021d/common/Ieee8021dBpduSerializer.cc
@@ -0,0 +1,90 @@
+//
+// This program 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, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program 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 this program.  If not, see http://www.gnu.org/licenses/.
+//
+
+#include "inet/common/packet/serializer/ChunkSerializerRegistry.h"
+#include "inet/linklayer/ieee8021d/common/Ieee8021dBpdu_m.h"
+#include "inet/linklayer/ieee8021d/common/Ieee8021dBpduSerializer.h"
+
+namespace inet {
+
+Register_Serializer(Bpdu, Ieee8021dBpduSerializer);
+
+void Ieee8021dBpduSerializer::serialize(MemoryOutputStream& stream, const Ptr& chunk) const
+{
+    B startPos = B(stream.getLength());
+    const auto& bpdu = staticPtrCast(chunk);
+    stream.writeUint16Be(bpdu->getProtocolIdentifier());
+    stream.writeByte(bpdu->getProtocolVersionIdentifier());
+    stream.writeByte(bpdu->getBpduType());
+    stream.writeBit(bpdu->getBpduFlags().tcaFlag);
+    stream.writeNBitsOfUint64Be(bpdu->getBpduFlags().reserved, 6);
+    stream.writeBit(bpdu->getBpduFlags().tcFlag);
+    stream.writeUint16Be(bpdu->getRootIdentifier().rootPriority);
+    stream.writeMacAddress(bpdu->getRootIdentifier().rootAddress);
+    stream.writeUint32Be(bpdu->getRootPathCost());
+    stream.writeUint16Be(bpdu->getBridgeIdentifier().bridgePriority);
+    stream.writeMacAddress(bpdu->getBridgeIdentifier().bridgeAddress);
+    stream.writeByte(bpdu->getPortIdentifier().portPriority);
+    stream.writeByte(bpdu->getPortIdentifier().portNum);
+    stream.writeUint16Be(bpdu->getMessageAge().inUnit(SIMTIME_S) * 256);
+    stream.writeUint16Be(bpdu->getMaxAge().inUnit(SIMTIME_S) * 256);
+    stream.writeUint16Be(bpdu->getHelloTime().inUnit(SIMTIME_S) * 256);
+    stream.writeUint16Be(bpdu->getForwardDelay().inUnit(SIMTIME_S) * 256);
+    // because of the KLUDGE in Rstp.cc (line 593) padding is added
+    while (B(stream.getLength()) - startPos < B(bpdu->getChunkLength()))
+        stream.writeByte('?');
+}
+
+const Ptr Ieee8021dBpduSerializer::deserialize(MemoryInputStream& stream) const
+{
+    auto bpdu = makeShared();
+    bpdu->setProtocolIdentifier(stream.readUint16Be());
+    bpdu->setProtocolVersionIdentifier(stream.readByte());
+    bpdu->setBpduType(stream.readByte());
+
+    BpduFlags bpduFlags;
+    bpduFlags.tcaFlag = stream.readBit();
+    bpduFlags.reserved = stream.readNBitsToUint64Be(6);
+    bpduFlags.tcFlag = stream.readBit();
+    bpdu->setBpduFlags(bpduFlags);
+
+    RootIdentifier rootId;
+    rootId.rootPriority = stream.readUint16Be();
+    rootId.rootAddress = stream.readMacAddress();
+    bpdu->setRootIdentifier(rootId);
+
+    bpdu->setRootPathCost(stream.readUint32Be());
+
+    BridgeIdentifier bridgeId;
+    bridgeId.bridgePriority = stream.readUint16Be();
+    bridgeId.bridgeAddress = stream.readMacAddress();
+    bpdu->setBridgeIdentifier(bridgeId);
+
+    PortIdentifier portId;
+    portId.portPriority = stream.readByte();
+    portId.portNum = stream.readByte();
+    bpdu->setPortIdentifier(portId);
+
+    bpdu->setMessageAge(SimTime(stream.readUint16Be() / 256, SIMTIME_S));
+    bpdu->setMaxAge(SimTime(stream.readUint16Be() / 256, SIMTIME_S));
+    bpdu->setHelloTime(SimTime(stream.readUint16Be() / 256, SIMTIME_S));
+    bpdu->setForwardDelay(SimTime(stream.readUint16Be() / 256, SIMTIME_S));
+    // because of the KLUDGE in Rstp.cc (line 593) padding is added
+    while (B(stream.getRemainingLength()) > B(0))
+        stream.readByte();
+    return bpdu;
+}
+
+} // namespace inet
diff --git a/src/inet/linklayer/ieee8021d/common/Ieee8021dBpduSerializer.h b/src/inet/linklayer/ieee8021d/common/Ieee8021dBpduSerializer.h
new file mode 100644
index 00000000000..4eb19ccb45e
--- /dev/null
+++ b/src/inet/linklayer/ieee8021d/common/Ieee8021dBpduSerializer.h
@@ -0,0 +1,38 @@
+//
+// This program 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, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program 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 this program.  If not, see http://www.gnu.org/licenses/.
+//
+
+#ifndef INET_LINKLAYER_IEEE8021D_COMMON_IEEE8021DBPDUSERIALIZER_H_
+#define INET_LINKLAYER_IEEE8021D_COMMON_IEEE8021DBPDUSERIALIZER_H_
+
+#include "inet/common/packet/serializer/FieldsChunkSerializer.h"
+
+namespace inet {
+
+/**
+ * Converts between Bpdu and binary (network byte order) Ieee 802.1d BPDU packets.
+ */
+class INET_API Ieee8021dBpduSerializer : public FieldsChunkSerializer
+{
+protected:
+    virtual void serialize(MemoryOutputStream& stream, const Ptr& chunk) const override;
+    virtual const Ptr deserialize(MemoryInputStream& stream) const override;
+
+public:
+    Ieee8021dBpduSerializer() : FieldsChunkSerializer() {}
+};
+
+} // namespace inet
+
+#endif /* INET_LINKLAYER_IEEE8021D_COMMON_IEEE8021DBPDUSERIALIZER_H_ */
diff --git a/src/inet/linklayer/ieee8021d/common/StpBase.cc b/src/inet/linklayer/ieee8021d/common/StpBase.cc
index 5bb73499582..782466924e4 100644
--- a/src/inet/linklayer/ieee8021d/common/StpBase.cc
+++ b/src/inet/linklayer/ieee8021d/common/StpBase.cc
@@ -23,12 +23,9 @@
 
 namespace inet {
 
-static const char *ENABLED_LINK_COLOR = "#000000";
-static const char *DISABLED_LINK_COLOR = "#bbbbbb";
-static const char *ROOT_SWITCH_COLOR = "#a5ffff";
-
 StpBase::StpBase()
 {
+
 }
 
 void StpBase::initialize(int stage)
@@ -42,6 +39,10 @@ void StpBase::initialize(int stage)
 
     if (stage == INITSTAGE_LOCAL) {
         visualize = par("visualize");
+        colorLinkEnabled = par("colorLinkEnabled").stdstringValue();
+        colorLinkDisabled = par("colorLinkDisabled").stdstringValue();
+        colorRootBridge = par("colorRootBridge").stdstringValue();
+
         bridgePriority = par("bridgePriority");
 
         maxAge = par("maxAge");
@@ -56,17 +57,13 @@ void StpBase::initialize(int stage)
 
 void StpBase::start()
 {
-    ie = chooseInterface();
-
-    if (ie)
-        bridgeAddress = ie->getMacAddress(); // get the bridge's MAC address
-    else
-        throw cRuntimeError("No non-loopback interface found!");
+    bridgeAddress = ifTable->getBaseMacAddress();
+    ASSERT(bridgeAddress != MacAddress::UNSPECIFIED_ADDRESS);
 }
 
 void StpBase::stop()
 {
-    ie = nullptr;
+
 }
 
 void StpBase::colorLink(InterfaceEntry *ie, bool forwarding) const
@@ -81,21 +78,21 @@ void StpBase::colorLink(InterfaceEntry *ie, bool forwarding) const
 
         if (outGate && inGate && inGatePrev && outGateNext && outGatePrev && inGatePrev2) {
             if (forwarding) {
-                outGatePrev->getDisplayString().setTagArg("ls", 0, ENABLED_LINK_COLOR);
-                inGate->getDisplayString().setTagArg("ls", 0, ENABLED_LINK_COLOR);
+                outGatePrev->getDisplayString().setTagArg("ls", 0, colorLinkEnabled.c_str());
+                inGate->getDisplayString().setTagArg("ls", 0, colorLinkEnabled.c_str());
             }
             else {
-                outGatePrev->getDisplayString().setTagArg("ls", 0, DISABLED_LINK_COLOR);
-                inGate->getDisplayString().setTagArg("ls", 0, DISABLED_LINK_COLOR);
+                outGatePrev->getDisplayString().setTagArg("ls", 0, colorLinkDisabled.c_str());
+                inGate->getDisplayString().setTagArg("ls", 0, colorLinkDisabled.c_str());
             }
 
-            if ((!inGatePrev2->getDisplayString().containsTag("ls") || strcmp(inGatePrev2->getDisplayString().getTagArg("ls", 0), ENABLED_LINK_COLOR) == 0) && forwarding) {
-                outGate->getDisplayString().setTagArg("ls", 0, ENABLED_LINK_COLOR);
-                inGatePrev->getDisplayString().setTagArg("ls", 0, ENABLED_LINK_COLOR);
+            if ((!inGatePrev2->getDisplayString().containsTag("ls") || strcmp(inGatePrev2->getDisplayString().getTagArg("ls", 0), colorLinkEnabled.c_str()) == 0) && forwarding) {
+                outGate->getDisplayString().setTagArg("ls", 0, colorLinkEnabled.c_str());
+                inGatePrev->getDisplayString().setTagArg("ls", 0, colorLinkEnabled.c_str());
             }
             else {
-                outGate->getDisplayString().setTagArg("ls", 0, DISABLED_LINK_COLOR);
-                inGatePrev->getDisplayString().setTagArg("ls", 0, DISABLED_LINK_COLOR);
+                outGate->getDisplayString().setTagArg("ls", 0, colorLinkDisabled.c_str());
+                inGatePrev->getDisplayString().setTagArg("ls", 0, colorLinkDisabled.c_str());
             }
         }
     }
@@ -133,7 +130,7 @@ void StpBase::refreshDisplay() const
 
         // mark root switch
         if (isUp() && getRootInterfaceId() == -1)
-            switchModule->getDisplayString().setTagArg("i", 1, ROOT_SWITCH_COLOR);
+            switchModule->getDisplayString().setTagArg("i", 1, colorRootBridge.c_str());
         else
             switchModule->getDisplayString().setTagArg("i", 1, "");
     }
@@ -168,20 +165,6 @@ int StpBase::getRootInterfaceId() const
     return -1;
 }
 
-InterfaceEntry *StpBase::chooseInterface()
-{
-    // TODO: Currently, we assume that the first non-loopback interface is an Ethernet interface
-    //       since STP and RSTP work on EtherSwitches.
-    //       NOTE that, we doesn't check if the returning interface is an Ethernet interface!
-    for (int i = 0; i < ifTable->getNumInterfaces(); i++) {
-        InterfaceEntry *current = ifTable->getInterface(i);
-        if (!current->isLoopback())
-            return current;
-    }
-
-    return nullptr;
-}
-
 void StpBase::handleStartOperation(LifecycleOperation *operation)
 {
     start();
diff --git a/src/inet/linklayer/ieee8021d/common/StpBase.h b/src/inet/linklayer/ieee8021d/common/StpBase.h
index ac97f3e5cbf..94332e6d3d3 100644
--- a/src/inet/linklayer/ieee8021d/common/StpBase.h
+++ b/src/inet/linklayer/ieee8021d/common/StpBase.h
@@ -32,8 +32,22 @@ namespace inet {
  */
 class INET_API StpBase : public OperationalBase, public cListener
 {
+public:
+    enum BdpuType { BPDU_TYPE_CONFIG = 0x00,
+        BPDU_TYPE_TCN = 0x80,
+        BPDU_TYPE_RSTP = 0x02 };
+
+    enum ProtocolVersion { PROTO_VERSION_STP = 0,
+        PROTO_VERSION_RSTP = 2,
+        PROTO_VERSION_MSTP = 3,
+        PROTO_VERSION_SPB = 4 };
+
   protected:
     bool visualize = false;    // if true it visualize the spanning tree
+    std::string colorLinkEnabled = "";
+    std::string colorLinkDisabled = "";
+    std::string colorRootBridge = "";
+
     unsigned int numPorts = 0;    // number of ports
 
     unsigned int bridgePriority = 0;    // bridge's priority
@@ -46,7 +60,6 @@ class INET_API StpBase : public OperationalBase, public cListener
     cModule *switchModule = nullptr;
     IMacAddressTable *macTable = nullptr;
     IInterfaceTable *ifTable = nullptr;
-    InterfaceEntry *ie = nullptr;
 
   public:
     StpBase();
@@ -96,11 +109,6 @@ class INET_API StpBase : public OperationalBase, public cListener
      * @return The port's InterfaceEntry, throws error if it doesn't exist.
      */
     InterfaceEntry *getPortInterfaceEntry(unsigned int interfaceId);
-
-    /*
-     * Returns the first non-loopback interface.
-     */
-    virtual InterfaceEntry *chooseInterface();
 };
 
 } // namespace inet
diff --git a/src/inet/linklayer/ieee8021d/relay/Ieee8021dRelay.cc b/src/inet/linklayer/ieee8021d/relay/Ieee8021dRelay.cc
index bc3b0d902e2..8a93231ded4 100644
--- a/src/inet/linklayer/ieee8021d/relay/Ieee8021dRelay.cc
+++ b/src/inet/linklayer/ieee8021d/relay/Ieee8021dRelay.cc
@@ -262,32 +262,13 @@ Ieee8021dInterfaceData *Ieee8021dRelay::getPortInterfaceData(unsigned int interf
 
 void Ieee8021dRelay::start()
 {
-    ie = chooseInterface();
-    if (ie) {
-        bridgeAddress = ie->getMacAddress(); // get the bridge's MAC address
-        registerAddress(bridgeAddress); // register bridge's MAC address
-    }
-    else
-        throw cRuntimeError("No non-loopback interface found!");
+    bridgeAddress = ifTable->getBaseMacAddress();
+    registerAddress(bridgeAddress);
 }
 
 void Ieee8021dRelay::stop()
 {
-    ie = nullptr;
-}
-
-InterfaceEntry *Ieee8021dRelay::chooseInterface()
-{
-    // TODO: Currently, we assume that the first non-loopback interface is an Ethernet interface
-    //       since relays work on EtherSwitches.
-    //       NOTE that, we don't check if the returning interface is an Ethernet interface!
-    for (int i = 0; i < ifTable->getNumInterfaces(); i++) {
-        InterfaceEntry *current = ifTable->getInterface(i);
-        if (!current->isLoopback())
-            return current;
-    }
 
-    return nullptr;
 }
 
 void Ieee8021dRelay::finish()
diff --git a/src/inet/linklayer/ieee8021d/relay/Ieee8021dRelay.h b/src/inet/linklayer/ieee8021d/relay/Ieee8021dRelay.h
index dba1d127613..a07a87c5891 100644
--- a/src/inet/linklayer/ieee8021d/relay/Ieee8021dRelay.h
+++ b/src/inet/linklayer/ieee8021d/relay/Ieee8021dRelay.h
@@ -53,7 +53,6 @@ class INET_API Ieee8021dRelay : public LayeredProtocolBase
     MacAddress bridgeAddress;
     IInterfaceTable *ifTable = nullptr;
     IMacAddressTable *macTable = nullptr;
-    InterfaceEntry *ie = nullptr;
     bool isStpAware = false;
 
     typedef std::pair MacAddressPair;
@@ -127,10 +126,6 @@ class INET_API Ieee8021dRelay : public LayeredProtocolBase
 
     bool isForwardingInterface(InterfaceEntry *ie);
 
-    /*
-     * Returns the first non-loopback interface.
-     */
-    virtual InterfaceEntry *chooseInterface();
     virtual void finish() override;
 };
 
diff --git a/src/inet/linklayer/ieee8021d/rstp/Rstp.cc b/src/inet/linklayer/ieee8021d/rstp/Rstp.cc
index 881e940dbf6..f4da1e2c92a 100644
--- a/src/inet/linklayer/ieee8021d/rstp/Rstp.cc
+++ b/src/inet/linklayer/ieee8021d/rstp/Rstp.cc
@@ -31,6 +31,7 @@ Define_Module(Rstp);
 
 Rstp::Rstp()
 {
+
 }
 
 Rstp::~Rstp()
@@ -56,9 +57,54 @@ void Rstp::initialize(int stage)
     }
 }
 
+void Rstp::start()
+{
+    StpBase::start();
+    initPorts();
+    scheduleAt(simTime(), helloTimer);
+}
+
+void Rstp::initPorts()
+{
+    for (unsigned int j = 0; j < numPorts; j++) {
+        int interfaceId = ifTable->getInterface(j)->getInterfaceId();
+        Ieee8021dInterfaceData *jPort = getPortInterfaceData(interfaceId);
+        if (!jPort->isEdge()) {
+            jPort->setRole(Ieee8021dInterfaceData::NOTASSIGNED);
+            jPort->setState(Ieee8021dInterfaceData::DISCARDING);
+            jPort->setNextUpgrade(simTime() + migrateTime);
+        }
+        else {
+            jPort->setRole(Ieee8021dInterfaceData::DESIGNATED);
+            jPort->setState(Ieee8021dInterfaceData::FORWARDING);
+        }
+
+        initInterfacedata(interfaceId);
+        macTable->flush(interfaceId);
+    }
+
+    scheduleNextUpgrade();
+}
+
+void Rstp::initInterfacedata(unsigned int interfaceId)
+{
+    // note: port cost and port priority are configured by the L2NetworkConfigurator
+
+    Ieee8021dInterfaceData *ifd = getPortInterfaceData(interfaceId);
+    ifd->setRootPriority(bridgePriority);
+    ifd->setRootAddress(bridgeAddress);
+    ifd->setRootPathCost(0);
+    ifd->setAge(0);
+    ifd->setBridgePriority(bridgePriority);
+    ifd->setBridgeAddress(bridgeAddress);
+    ifd->setPortNum(-1);
+    ifd->setLostBPDU(0);
+}
+
 void Rstp::scheduleNextUpgrade()
 {
     cancelEvent(upgradeTimer);
+
     Ieee8021dInterfaceData *nextInterfaceData = nullptr;
     for (unsigned int i = 0; i < numPorts; i++) {
         int interfaceId = ifTable->getInterface(i)->getInterfaceId();
@@ -86,6 +132,7 @@ void Rstp::scheduleNextUpgrade()
             }
         }
     }
+
     if (nextInterfaceData != nullptr)
         scheduleAt(nextInterfaceData->getNextUpgrade(), upgradeTimer);
 }
@@ -114,38 +161,10 @@ void Rstp::handleMessageWhenUp(cMessage *msg)
     }
 }
 
-void Rstp::handleUpgrade(cMessage *msg)
-{
-    for (unsigned int i = 0; i < numPorts; i++) {
-        int interfaceId = ifTable->getInterface(i)->getInterfaceId();
-        Ieee8021dInterfaceData *iPort = getPortInterfaceData(interfaceId);
-        if (getPortInterfaceEntry(interfaceId)->hasCarrier() && iPort->getNextUpgrade() == simTime()) {
-            if (iPort->getRole() == Ieee8021dInterfaceData::NOTASSIGNED) {
-                EV_DETAIL << "MigrateTime. Setting port " << interfaceId << "to designated." << endl;
-                iPort->setRole(Ieee8021dInterfaceData::DESIGNATED);
-                iPort->setState(Ieee8021dInterfaceData::DISCARDING);    // contest to become forwarding.
-                iPort->setNextUpgrade(simTime() + forwardDelay);
-            }
-            else if (iPort->getRole() == Ieee8021dInterfaceData::DESIGNATED) {
-                if (iPort->getState() == Ieee8021dInterfaceData::DISCARDING) {
-                    EV_INFO << "UpgradeTime. Setting port " << interfaceId << " state to learning." << endl;
-                    iPort->setState(Ieee8021dInterfaceData::LEARNING);
-                    iPort->setNextUpgrade(simTime() + forwardDelay);
-                }
-                else if (iPort->getState() == Ieee8021dInterfaceData::LEARNING) {
-                    EV_INFO << "UpgradeTime. Setting port " << interfaceId << " state to forwarding." << endl;
-                    iPort->setState(Ieee8021dInterfaceData::FORWARDING);
-                    flushOtherPorts(interfaceId);
-                }
-            }
-        }
-    }
-    scheduleNextUpgrade();
-}
-
 void Rstp::handleHelloTime(cMessage *msg)
 {
     EV_DETAIL << "Hello time." << endl;
+
     for (unsigned int i = 0; i < numPorts; i++) {
         // sends hello through all active (learning, forwarding or not assigned) ports
         // increments LostBPDU just from ROOT, ALTERNATE and BACKUP
@@ -205,15 +224,71 @@ void Rstp::handleHelloTime(cMessage *msg)
             }
         }
     }
+
     sendBPDUs();    // generating and sending new BPDUs
     sendTCNtoRoot();
     scheduleAt(simTime() + helloTime, msg);    // programming next hello time
 }
 
+void Rstp::handleUpgrade(cMessage *msg)
+{
+    for (unsigned int i = 0; i < numPorts; i++) {
+        int interfaceId = ifTable->getInterface(i)->getInterfaceId();
+        Ieee8021dInterfaceData *iPort = getPortInterfaceData(interfaceId);
+        if (getPortInterfaceEntry(interfaceId)->hasCarrier() && iPort->getNextUpgrade() == simTime()) {
+            if (iPort->getRole() == Ieee8021dInterfaceData::NOTASSIGNED) {
+                EV_DETAIL << "MigrateTime. Setting port " << interfaceId << "to designated." << endl;
+                iPort->setRole(Ieee8021dInterfaceData::DESIGNATED);
+                iPort->setState(Ieee8021dInterfaceData::DISCARDING);    // contest to become forwarding.
+                iPort->setNextUpgrade(simTime() + forwardDelay);
+            }
+            else if (iPort->getRole() == Ieee8021dInterfaceData::DESIGNATED) {
+                if (iPort->getState() == Ieee8021dInterfaceData::DISCARDING) {
+                    EV_INFO << "UpgradeTime. Setting port " << interfaceId << " state to learning." << endl;
+                    iPort->setState(Ieee8021dInterfaceData::LEARNING);
+                    iPort->setNextUpgrade(simTime() + forwardDelay);
+                }
+                else if (iPort->getState() == Ieee8021dInterfaceData::LEARNING) {
+                    EV_INFO << "UpgradeTime. Setting port " << interfaceId << " state to forwarding." << endl;
+                    iPort->setState(Ieee8021dInterfaceData::FORWARDING);
+                    flushOtherPorts(interfaceId);
+                }
+            }
+        }
+    }
+
+    scheduleNextUpgrade();
+}
+
+void Rstp::handleIncomingFrame(Packet *packet)
+{
+    int arrivalInterfaceId = packet->getTag()->getInterfaceId();
+    EV_INFO << "BPDU received at port " << arrivalInterfaceId << "." << endl;
+
+    MacAddress src = packet->getTag()->getSrcAddress();
+    const Ptr& frame = packet->peekAtFront();
+
+    // checking message age
+    if (frame->getMessageAge() < maxAge) {
+
+        checkTC(frame, arrivalInterfaceId);    // sets TCWhile if arrival port was FORWARDING
+
+        // checking possible backup
+        if (sameSwitch(src)) // more than one port in the same LAN segment
+            handleBackup(frame, arrivalInterfaceId);
+        else
+            processBPDU(frame, arrivalInterfaceId);
+    }
+    else
+        EV_DETAIL << "Expired BPDU" << endl;
+
+    delete packet;
+}
+
 void Rstp::checkTC(const Ptr& frame, int arrivalInterfaceId)
 {
     Ieee8021dInterfaceData *port = getPortInterfaceData(arrivalInterfaceId);
-    if ((frame->getTcFlag() == true) && (port->getState() == Ieee8021dInterfaceData::FORWARDING)) {
+    if ((frame->getBpduFlags().tcFlag == true) && (port->getState() == Ieee8021dInterfaceData::FORWARDING)) {
         EV_DETAIL << "TCN received" << endl;
         findContainingNode(this)->bubble("TCN received");
         for (unsigned int i = 0; i < numPorts; i++) {
@@ -233,8 +308,9 @@ void Rstp::handleBackup(const Ptr& frame, unsigned int arrivalInterf
 {
     EV_DETAIL << "More than one port in the same LAN" << endl;
     Ieee8021dInterfaceData *port = getPortInterfaceData(arrivalInterfaceId);
-    if ((frame->getPortPriority() < port->getPortPriority())
-        || ((frame->getPortPriority() == port->getPortPriority()) && (frame->getPortNum() < arrivalInterfaceId)))
+    if ((frame->getPortIdentifier().portPriority < port->getPortPriority())
+        || ((frame->getPortIdentifier().portPriority == port->getPortPriority())
+                && (frame->getPortIdentifier().portNum < arrivalInterfaceId)))
     {
         // flushing arrival port
         macTable->flush(arrivalInterfaceId);
@@ -243,51 +319,38 @@ void Rstp::handleBackup(const Ptr& frame, unsigned int arrivalInterf
         port->setLostBPDU(0);
         EV_DETAIL << "Setting port " << arrivalInterfaceId << "to backup" << endl;
     }
-    else if (frame->getPortPriority() > port->getPortPriority()
-             || (frame->getPortPriority() == port->getPortPriority() && frame->getPortNum() > arrivalInterfaceId))
+    else if (frame->getPortIdentifier().portPriority > port->getPortPriority()
+             || (frame->getPortIdentifier().portPriority == port->getPortPriority()
+                     && frame->getPortIdentifier().portNum > arrivalInterfaceId))
     {
-        Ieee8021dInterfaceData *port2 = getPortInterfaceData(frame->getPortNum());
-        // flushing sender port
-        macTable->flush(frame->getPortNum());    // portNum is sender port number, it is not arrival port
+        // portNum is sender port number, it is not arrival port
+        unsigned int portNum = frame->getPortIdentifier().portNum;
+
+        Ieee8021dInterfaceData *port2 = getPortInterfaceData(portNum);
+        macTable->flush(portNum);
+
+        EV_DETAIL << "Setting port " << portNum << "to backup" << endl;
+
         port2->setRole(Ieee8021dInterfaceData::BACKUP);
         port2->setState(Ieee8021dInterfaceData::DISCARDING);
         port2->setLostBPDU(0);
-        EV_DETAIL << "Setting port " << frame->getPortNum() << "to backup" << endl;
     }
     else {
-        Ieee8021dInterfaceData *port2 = getPortInterfaceData(frame->getPortNum());
-        // unavoidable loop, received its own message at the same port
-        // switch to disabled
-        EV_DETAIL << "Unavoidable loop. Received its own message at the same port. Setting port " << frame->getPortNum() << " to disabled." << endl;
-        // flushing that port
-        macTable->flush(frame->getPortNum());    // portNum is sender port number, it is not arrival port
+        // portNum is sender port number, it is not arrival port
+        unsigned int portNum = frame->getPortIdentifier().portNum;
+
+        Ieee8021dInterfaceData *port2 = getPortInterfaceData(portNum);
+        macTable->flush(portNum);
+
+        // unavoidable loop, received its own message at the same port switch to disabled
+        EV_DETAIL << "Unavoidable loop. Received its own message at the same port. "
+                "Setting port " << portNum << " to disabled." << endl;
+
         port2->setRole(Ieee8021dInterfaceData::DISABLED);
         port2->setState(Ieee8021dInterfaceData::DISCARDING);
     }
 }
 
-void Rstp::handleIncomingFrame(Packet *packet)
-{
-    const Ptr& frame = packet->peekAtFront();
-    // incoming BPDU handling
-    // checking message age
-    int arrivalInterfaceId = packet->getTag()->getInterfaceId();
-    MacAddress src = packet->getTag()->getSrcAddress();
-    EV_INFO << "BPDU received at port " << arrivalInterfaceId << "." << endl;
-    if (frame->getMessageAge() < maxAge) {
-        // checking TC
-        checkTC(frame, arrivalInterfaceId);    // sets TCWhile if arrival port was FORWARDING
-        // checking possible backup
-        if (src.compareTo(bridgeAddress) == 0) // more than one port in the same LAN
-            handleBackup(frame, arrivalInterfaceId);
-        else
-            processBPDU(frame, arrivalInterfaceId);
-    }
-    else
-        EV_DETAIL << "Expired BPDU" << endl;
-    delete packet;
-}
-
 void Rstp::processBPDU(const Ptr& frame, unsigned int arrivalInterfaceId)
 {
     //three challenges.
@@ -295,16 +358,18 @@ void Rstp::processBPDU(const Ptr& frame, unsigned int arrivalInterfa
     //first:  vs best received BPDU for that port --------->case
     //second: vs root BPDU--------------------------------->case1
     //third:  vs BPDU that would be sent from this Bridge.->case2
+
     Ieee8021dInterfaceData *arrivalPort = getPortInterfaceData(arrivalInterfaceId);
     bool flood = false;
     if (compareInterfacedata(arrivalInterfaceId, frame, arrivalPort->getLinkCost()) > 0    //better root
-        && frame->getRootAddress().compareTo(bridgeAddress) != 0) // root will not participate in a loop with its own address
+        && frame->getRootIdentifier().rootAddress.compareTo(bridgeAddress) != 0) // root will not participate in a loop with its own address
         flood = processBetterSource(frame, arrivalInterfaceId);
-    else if (frame->getBridgeAddress().compareTo(arrivalPort->getBridgeAddress()) == 0    // worse or similar, but the same source
-             && frame->getRootAddress().compareTo(bridgeAddress) != 0) // root will not participate
+    else if (frame->getBridgeIdentifier().bridgeAddress.compareTo(arrivalPort->getBridgeAddress()) == 0    // worse or similar, but the same source
+             && frame->getRootIdentifier().rootAddress.compareTo(bridgeAddress) != 0) // root will not participate
         flood = processSameSource(frame, arrivalInterfaceId);
+
     if (flood) {
-        sendBPDUs();    //expedited BPDU
+        sendBPDUs();    // expedited BPDU
         sendTCNtoRoot();
     }
 }
@@ -442,6 +507,7 @@ bool Rstp::processBetterSource(const Ptr& frame, unsigned int arriva
                 break;
         }
     }
+
     return false;
 }
 
@@ -562,6 +628,7 @@ bool Rstp::processSameSource(const Ptr& frame, unsigned int arrivalI
             updateInterfacedata(frame, arrivalInterfaceId);
             break;
     }
+
     return false;
 }
 
@@ -577,15 +644,33 @@ void Rstp::sendTCNtoRoot()
             if (simTime() < rootPort->getTCWhile()) {
                 Packet *packet = new Packet("BPDU");
                 const auto& frame = makeShared();
-                frame->setRootPriority(rootPort->getRootPriority());
-                frame->setRootAddress(rootPort->getRootAddress());
-                frame->setMessageAge(rootPort->getAge());
+
+                frame->setProtocolIdentifier(0);
+                frame->setProtocolVersionIdentifier(PROTO_VERSION_RSTP);
+                frame->setBpduType(BPDU_TYPE_RSTP); // todo: check
+
+                BpduFlags bpduFlags;
+                bpduFlags.tcaFlag = false;
+                bpduFlags.tcFlag = true;
+                frame->setBpduFlags(bpduFlags);
+
+                RootIdentifier rootId;
+                rootId.rootPriority = rootPort->getRootPriority();
+                rootId.rootAddress = rootPort->getRootAddress();
+                frame->setRootIdentifier(rootId);
+
                 frame->setRootPathCost(rootPort->getRootPathCost());
-                frame->setBridgePriority(bridgePriority);
-                frame->setTcaFlag(false);
-                frame->setPortNum(r);
-                frame->setBridgeAddress(bridgeAddress);
-                frame->setTcFlag(true);
+
+                BridgeIdentifier bridgeId;
+                bridgeId.bridgePriority = bridgePriority;
+                bridgeId.bridgeAddress = bridgeAddress;
+                frame->setBridgeIdentifier(bridgeId);
+
+                PortIdentifier portId;
+                portId.portNum = r;
+                frame->setPortIdentifier(portId);
+
+                frame->setMessageAge(rootPort->getAge());
                 frame->setMaxAge(maxAge);
                 frame->setHelloTime(helloTime);
                 frame->setForwardDelay(forwardDelay);
@@ -596,7 +681,7 @@ void Rstp::sendTCNtoRoot()
                 packet->insertAtBack(frame);
 
                 auto macAddressReq = packet->addTag();
-                macAddressReq->setSrcAddress(bridgeAddress);
+                macAddressReq->setSrcAddress(rootPort->getInterfaceEntry()->getMacAddress());
                 macAddressReq->setDestAddress(MacAddress::STP_MULTICAST_ADDRESS);
                 packet->addTag()->setInterfaceId(r);
 
@@ -625,35 +710,55 @@ void Rstp::sendBPDUs()
 
 void Rstp::sendBPDU(int interfaceId)
 {
-    // send a BPDU throuth port
+    // send a BPDU through port
     Ieee8021dInterfaceData *iport = getPortInterfaceData(interfaceId);
     int r = getRootInterfaceId();
     Ieee8021dInterfaceData *rootPort;
     if (r != -1)
         rootPort = getPortInterfaceData(r);
+
     if (iport->getRole() != Ieee8021dInterfaceData::DISABLED) {
         Packet *packet = new Packet("BPDU");
         const auto& frame = makeShared();
+
+        frame->setProtocolIdentifier(0);
+        frame->setProtocolVersionIdentifier(PROTO_VERSION_RSTP);
+        frame->setBpduType(BPDU_TYPE_RSTP);
+
         if (r != -1) {
-            frame->setRootPriority(rootPort->getRootPriority());
-            frame->setRootAddress(rootPort->getRootAddress());
+            RootIdentifier rootId;
+            rootId.rootPriority = rootPort->getRootPriority();
+            rootId.rootAddress = rootPort->getRootAddress();
+            frame->setRootIdentifier(rootId);
+
             frame->setMessageAge(rootPort->getAge());
             frame->setRootPathCost(rootPort->getRootPathCost());
         }
         else {
-            frame->setRootPriority(bridgePriority);
-            frame->setRootAddress(bridgeAddress);
+            RootIdentifier rootId;
+            rootId.rootPriority = bridgePriority;
+            rootId.rootAddress = bridgeAddress;
+            frame->setRootIdentifier(rootId);
+
             frame->setMessageAge(0);
             frame->setRootPathCost(0);
         }
-        frame->setBridgePriority(bridgePriority);
-        frame->setTcaFlag(false);
-        frame->setPortNum(interfaceId);
-        frame->setBridgeAddress(bridgeAddress);
-        if (simTime() < iport->getTCWhile())
-            frame->setTcFlag(true);
-        else
-            frame->setTcFlag(false);
+
+        BridgeIdentifier bridgeId;
+        bridgeId.bridgePriority = bridgePriority;
+        bridgeId.bridgeAddress = bridgeAddress;
+        frame->setBridgeIdentifier(bridgeId);
+
+        BpduFlags bpduFlags;
+        bpduFlags.tcaFlag = false;
+        bpduFlags.tcFlag = (simTime() < iport->getTCWhile()) ? true : false;
+        frame->setBpduFlags(bpduFlags);
+
+        PortIdentifier portId;
+        portId.portPriority = getPortInterfaceData(interfaceId)->getPortPriority();
+        portId.portNum = interfaceId;
+        frame->setPortIdentifier(portId);
+
         frame->setMaxAge(maxAge);
         frame->setHelloTime(helloTime);
         frame->setForwardDelay(forwardDelay);
@@ -664,7 +769,7 @@ void Rstp::sendBPDU(int interfaceId)
         packet->insertAtBack(frame);
 
         auto macAddressReq = packet->addTag();
-        macAddressReq->setSrcAddress(bridgeAddress);
+        macAddressReq->setSrcAddress(getPortInterfaceData(interfaceId)->getInterfaceEntry()->getMacAddress());
         macAddressReq->setDestAddress(MacAddress::STP_MULTICAST_ADDRESS);
         packet->addTag()->setInterfaceId(interfaceId);
         packet->addTag()->setProtocol(&Protocol::stp);
@@ -673,84 +778,22 @@ void Rstp::sendBPDU(int interfaceId)
     }
 }
 
-void Rstp::printState()
-{
-    //  prints current database info
-    EV_DETAIL << "Switch " << findContainingNode(this)->getFullName() << " state:" << endl;
-    int rootIndex = getRootInterfaceId();
-    EV_DETAIL << "  Priority: " << bridgePriority << endl;
-    EV_DETAIL << "  Local MAC: " << bridgeAddress << endl;
-    if (rootIndex >= 0) {
-        Ieee8021dInterfaceData *rootPort = getPortInterfaceData(rootIndex);
-        EV_DETAIL << "  Root Priority: " << rootPort->getRootPriority() << endl;
-        EV_DETAIL << "  Root Address: " << rootPort->getRootAddress().str() << endl;
-        EV_DETAIL << "  Cost: " << rootPort->getRootPathCost() << endl;
-        EV_DETAIL << "  Age:  " << rootPort->getAge() << endl;
-        EV_DETAIL << "  Bridge Priority: " << rootPort->getBridgePriority() << endl;
-        EV_DETAIL << "  Bridge Address: " << rootPort->getBridgeAddress().str() << endl;
-        EV_DETAIL << "  Src TxGate Priority: " << rootPort->getPortPriority() << endl;
-        EV_DETAIL << "  Src TxGate: " << rootPort->getPortNum() << endl;
-    }
-    EV_DETAIL << "Port State/Role:" << endl;
-    for (unsigned int i = 0; i < numPorts; i++) {
-        int interfaceId = ifTable->getInterface(i)->getInterfaceId();
-        Ieee8021dInterfaceData *iPort = getPortInterfaceData(interfaceId);
-        EV_DETAIL << "  " << i << ": " << iPort->getStateName() << "/" << iPort->getRoleName() << (iPort->isEdge() ? " (Client)" : "") << endl;
-    }
-    EV_DETAIL << "Per-port best sources, Root/Src:" << endl;
-    for (unsigned int i = 0; i < numPorts; i++) {
-        int interfaceId = ifTable->getInterface(i)->getInterfaceId();
-        Ieee8021dInterfaceData *iPort = getPortInterfaceData(interfaceId);
-        EV_DETAIL << "  " << interfaceId << ": " << iPort->getRootAddress().str() << "/" << iPort->getBridgeAddress().str() << endl;
-    }
-    EV_DETAIL << endl;
-}
-
-void Rstp::initInterfacedata(unsigned int interfaceId)
-{
-    Ieee8021dInterfaceData *ifd = getPortInterfaceData(interfaceId);
-    ifd->setRootPriority(bridgePriority);
-    ifd->setRootAddress(bridgeAddress);
-    ifd->setRootPathCost(0);
-    ifd->setAge(0);
-    ifd->setBridgePriority(bridgePriority);
-    ifd->setBridgeAddress(bridgeAddress);
-    ifd->setPortPriority(-1);
-    ifd->setPortNum(-1);
-    ifd->setLostBPDU(0);
-}
-
-void Rstp::initPorts()
-{
-    for (unsigned int j = 0; j < numPorts; j++) {
-        int interfaceId = ifTable->getInterface(j)->getInterfaceId();
-        Ieee8021dInterfaceData *jPort = getPortInterfaceData(interfaceId);
-        if (!jPort->isEdge()) {
-            jPort->setRole(Ieee8021dInterfaceData::NOTASSIGNED);
-            jPort->setState(Ieee8021dInterfaceData::DISCARDING);
-            jPort->setNextUpgrade(simTime() + migrateTime);
-        }
-        else {
-            jPort->setRole(Ieee8021dInterfaceData::DESIGNATED);
-            jPort->setState(Ieee8021dInterfaceData::FORWARDING);
-        }
-        initInterfacedata(interfaceId);
-        macTable->flush(interfaceId);
-    }
-    scheduleNextUpgrade();
-}
-
 void Rstp::updateInterfacedata(const Ptr& frame, unsigned int portNum)
 {
     Ieee8021dInterfaceData *ifd = getPortInterfaceData(portNum);
-    ifd->setRootPriority(frame->getRootPriority());
-    ifd->setRootAddress(frame->getRootAddress());
+
+    ifd->setRootPriority(frame->getRootIdentifier().rootPriority);
+    ifd->setRootAddress(frame->getRootIdentifier().rootAddress);
+
     ifd->setRootPathCost(frame->getRootPathCost() + ifd->getLinkCost());
+
+    ifd->setBridgePriority(frame->getBridgeIdentifier().bridgePriority);
+    ifd->setBridgeAddress(frame->getBridgeIdentifier().bridgeAddress);
+
+    ifd->setPortPriority(frame->getPortIdentifier().portPriority);
+    ifd->setPortNum(frame->getPortIdentifier().portNum);
+
     ifd->setAge(frame->getMessageAge() + 1);
-    ifd->setBridgePriority(frame->getBridgePriority());
-    ifd->setBridgeAddress(frame->getBridgeAddress());
-    ifd->setPortPriority(frame->getPortPriority());
-    ifd->setPortNum(frame->getPortNum());
     ifd->setLostBPDU(0);
 }
 
@@ -775,26 +818,26 @@ Rstp::CompareResult Rstp::contestInterfacedata(const Ptr& msg, unsig
     Ieee8021dInterfaceData *rootPort = getPortInterfaceData(r);
     Ieee8021dInterfaceData *ifd = getPortInterfaceData(interfaceId);
 
-    return compareRSTPData(rootPort->getRootPriority(), msg->getRootPriority(),
-            rootPort->getRootAddress(), msg->getRootAddress(),
+    return compareRSTPData(rootPort->getRootPriority(), msg->getRootIdentifier().rootPriority,
+            rootPort->getRootAddress(), msg->getRootIdentifier().rootAddress,
             rootPort->getRootPathCost(), msg->getRootPathCost(),
-            bridgePriority, msg->getBridgePriority(),
-            bridgeAddress, msg->getBridgeAddress(),
-            ifd->getPortPriority(), msg->getPortPriority(),
-            interfaceId, msg->getPortNum());
+            bridgePriority, msg->getBridgeIdentifier().bridgePriority,
+            bridgeAddress, msg->getBridgeIdentifier().bridgeAddress,
+            ifd->getPortPriority(), msg->getPortIdentifier().portPriority,
+            interfaceId, msg->getPortIdentifier().portNum);
 }
 
 Rstp::CompareResult Rstp::compareInterfacedata(unsigned int interfaceId, const Ptr& msg, int linkCost)
 {
     Ieee8021dInterfaceData *ifd = getPortInterfaceData(interfaceId);
 
-    return compareRSTPData(ifd->getRootPriority(), msg->getRootPriority(),
-            ifd->getRootAddress(), msg->getRootAddress(),
+    return compareRSTPData(ifd->getRootPriority(), msg->getRootIdentifier().rootPriority,
+            ifd->getRootAddress(), msg->getRootIdentifier().rootAddress,
             ifd->getRootPathCost(), msg->getRootPathCost() + linkCost,
-            ifd->getBridgePriority(), msg->getBridgePriority(),
-            ifd->getBridgeAddress(), msg->getBridgeAddress(),
-            ifd->getPortPriority(), msg->getPortPriority(),
-            ifd->getPortNum(), msg->getPortNum());
+            ifd->getBridgePriority(), msg->getBridgeIdentifier().bridgePriority,
+            ifd->getBridgeAddress(), msg->getBridgeIdentifier().bridgeAddress,
+            ifd->getPortPriority(), msg->getPortIdentifier().portPriority,
+            ifd->getPortNum(), msg->getPortIdentifier().portNum);
 }
 
 Rstp::CompareResult Rstp::compareRSTPData(int rootPriority1, int rootPriority2,
@@ -870,7 +913,20 @@ void Rstp::flushOtherPorts(unsigned int portId)
     }
 }
 
-//void Rstp::receiveChangeNotification(int signalID, const cObject *obj)
+bool Rstp::sameSwitch(MacAddress src)
+{
+    for (int i = 0; i < ifTable->getNumInterfaces(); i++) {
+        InterfaceEntry *current = ifTable->getInterface(i);
+        if (!current->isLoopback()) {
+            if(src.compareTo(current->getMacAddress()) == 0) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
 void Rstp::receiveSignal(cComponent *source, simsignal_t signalID, cObject *obj, cObject *details)
 {
     Enter_Method_Silent();
@@ -895,11 +951,43 @@ void Rstp::receiveSignal(cComponent *source, simsignal_t signalID, cObject *obj,
     }
 }
 
-void Rstp::start()
+void Rstp::printState()
 {
-    StpBase::start();
-    initPorts();
-    scheduleAt(simTime(), helloTimer);
+    //  prints current database info
+    EV_DETAIL << "Switch " << findContainingNode(this)->getFullName() << " state:" << endl;
+    EV_DETAIL << "  Priority: " << bridgePriority << endl;
+    EV_DETAIL << "  Local MAC: " << bridgeAddress << endl;
+
+    int rootIndex = getRootInterfaceId();
+    if (rootIndex >= 0) {
+        Ieee8021dInterfaceData *rootPort = getPortInterfaceData(rootIndex);
+        EV_DETAIL << "  Root Priority: " << rootPort->getRootPriority() << endl;
+        EV_DETAIL << "  Root Address: " << rootPort->getRootAddress().str() << endl;
+        EV_DETAIL << "  Cost: " << rootPort->getRootPathCost() << endl;
+        EV_DETAIL << "  Age:  " << rootPort->getAge() << endl;
+        EV_DETAIL << "  Bridge Priority: " << rootPort->getBridgePriority() << endl;
+        EV_DETAIL << "  Bridge Address: " << rootPort->getBridgeAddress().str() << endl;
+        EV_DETAIL << "  Src TxGate Priority: " << rootPort->getPortPriority() << endl;
+        EV_DETAIL << "  Src TxGate: " << rootPort->getPortNum() << endl;
+    }
+
+    EV_DETAIL << "Port State/Role:" << endl;
+
+    for (unsigned int i = 0; i < numPorts; i++) {
+        int interfaceId = ifTable->getInterface(i)->getInterfaceId();
+        Ieee8021dInterfaceData *iPort = getPortInterfaceData(interfaceId);
+        EV_DETAIL << "  " << i << ": " << iPort->getStateName() << "/" << iPort->getRoleName() << (iPort->isEdge() ? " (Client)" : "") << endl;
+    }
+
+    EV_DETAIL << "Per-port best sources, Root/Src:" << endl;
+
+    for (unsigned int i = 0; i < numPorts; i++) {
+        int interfaceId = ifTable->getInterface(i)->getInterfaceId();
+        Ieee8021dInterfaceData *iPort = getPortInterfaceData(interfaceId);
+        EV_DETAIL << "  " << interfaceId << ": " << iPort->getRootAddress().str() << "/" << iPort->getBridgeAddress().str() << endl;
+    }
+
+    EV_DETAIL << endl;
 }
 
 void Rstp::stop()
@@ -910,4 +998,3 @@ void Rstp::stop()
 }
 
 } // namespace inet
-
diff --git a/src/inet/linklayer/ieee8021d/rstp/Rstp.h b/src/inet/linklayer/ieee8021d/rstp/Rstp.h
index c70b3277856..08e2295d00b 100644
--- a/src/inet/linklayer/ieee8021d/rstp/Rstp.h
+++ b/src/inet/linklayer/ieee8021d/rstp/Rstp.h
@@ -169,6 +169,11 @@ class INET_API Rstp : public StpBase
      */
     virtual void handleBackup(const Ptr& frame, unsigned int arrivalInterfaceId);
 
+    /**
+     * @brief checks if the src MAC address belongs to this switch
+     */
+    virtual bool sameSwitch(MacAddress src);
+
     /**
      * @brief schedule next upgrade self-message
      */
diff --git a/src/inet/linklayer/ieee8021d/rstp/Rstp.ned b/src/inet/linklayer/ieee8021d/rstp/Rstp.ned
index 606c6955f10..30990c8c0b2 100644
--- a/src/inet/linklayer/ieee8021d/rstp/Rstp.ned
+++ b/src/inet/linklayer/ieee8021d/rstp/Rstp.ned
@@ -75,6 +75,11 @@ simple Rstp like ISpanningTree
         // Label ethernet interface with port role and status. Mark root switch
         bool visualize = default(false);
 
+        // only when visualize is true
+        string colorLinkEnabled = default("#000000");
+        string colorLinkDisabled = default("#bbbbbb");
+        string colorRootBridge = default("#cc3300");
+        
         // If true, edge ports immediately become designated/forwarding, else it will have to wait to get designated.
         bool autoEdge = default(true);
 
diff --git a/src/inet/linklayer/ieee8021d/stp/Stp.cc b/src/inet/linklayer/ieee8021d/stp/Stp.cc
index 1d039e99c56..d5e6b274c77 100644
--- a/src/inet/linklayer/ieee8021d/stp/Stp.cc
+++ b/src/inet/linklayer/ieee8021d/stp/Stp.cc
@@ -34,6 +34,12 @@ const double Stp::tickInterval = 1;
 
 Stp::Stp()
 {
+
+}
+
+Stp::~Stp()
+{
+    cancelAndDelete(tick);
 }
 
 void Stp::initialize(int stage)
@@ -42,7 +48,8 @@ void Stp::initialize(int stage)
 
     if (stage == INITSTAGE_LOCAL) {
         tick = new cMessage("STP_TICK", 0);
-        WATCH(bridgeAddress);
+        disabledInterfaces = par("disabledInterfaces").stdstringValue();
+        disabledInterfaceMatcher.setPattern(disabledInterfaces.c_str(), false, true, false);
     }
     else if (stage == INITSTAGE_LINK_LAYER) {
         registerService(Protocol::stp, nullptr, gate("relayIn"));
@@ -50,9 +57,37 @@ void Stp::initialize(int stage)
     }
 }
 
-Stp::~Stp()
+void Stp::start()
 {
-    cancelAndDelete(tick);
+    StpBase::start();
+
+    initPortTable();
+
+    currentBridgePriority = bridgePriority;
+    isRoot = true;
+    topologyChangeNotification = true;
+    topologyChangeRecvd = true;
+    rootPriority = bridgePriority;
+    rootAddress = bridgeAddress;
+    rootPathCost = 0;
+    rootInterfaceId = ifTable->getInterface(0)->getInterfaceId();
+    currentHelloTime = helloTime;
+    currentMaxAge = maxAge;
+    currentFwdDelay = forwardDelay;
+    helloTime = 0;
+
+    setAllDesignated();
+
+    WATCH(bridgePriority);
+    WATCH(bridgeAddress);
+    WATCH(isRoot);
+    WATCH(rootPriority);
+    WATCH(rootAddress);
+    WATCH(rootPathCost);
+    WATCH(topologyChangeNotification);
+    WATCH(topologyChangeRecvd);
+
+    scheduleAt(simTime() + tickInterval, tick);
 }
 
 void Stp::initPortTable()
@@ -63,238 +98,78 @@ void Stp::initPortTable()
     }
 }
 
-void Stp::handleMessageWhenUp(cMessage *msg)
+void Stp::initInterfacedata(unsigned int interfaceId)
 {
-    if (!msg->isSelfMessage()) {
-        Packet *packet = check_and_cast(msg);
-        const auto& bpdu = packet->peekAtFront();
+    Ieee8021dInterfaceData *ifd = getPortInterfaceData(interfaceId);
 
-        if (bpdu->getBpduType() == CONFIG_BDPU)
-            handleBPDU(packet, bpdu);
-        else if (bpdu->getBpduType() == TCN_BPDU)
-            handleTCN(packet, bpdu);
+    if( disabledInterfaceMatcher.matches(ifd->getInterfaceEntry()->getInterfaceName()) ||
+            disabledInterfaceMatcher.matches(ifd->getInterfaceEntry()->getInterfaceFullPath().c_str())) {
+        ifd->setRole(Ieee8021dInterfaceData::DISABLED);
     }
     else {
-        if (msg == tick) {
-            handleTick();
-            scheduleAt(simTime() + 1, tick);
-        }
-        else
-            throw cRuntimeError("Unknown self-message received");
-    }
-}
-
-void Stp::handleBPDU(Packet *packet, const Ptr& bpdu)
-{
-    int arrivalGate = packet->getTag()->getInterfaceId();
-    Ieee8021dInterfaceData *port = getPortInterfaceData(arrivalGate);
-
-    if (bpdu->getTcaFlag()) {
-        topologyChangeRecvd = true;
-        topologyChangeNotification = false;
+        ifd->setRole(Ieee8021dInterfaceData::NOTASSIGNED);
     }
 
-    // get inferior BPDU, reply with superior
-    if (!isSuperiorBPDU(arrivalGate, bpdu)) {
-        if (port->getRole() == Ieee8021dInterfaceData::DESIGNATED) {
-            EV_DETAIL << "Inferior Configuration BPDU " << bpdu << " arrived on port=" << arrivalGate << " responding to it with a superior BPDU." << endl;
-            generateBPDU(arrivalGate);
-        }
-    }
-    // BPDU from root
-    else if (port->getRole() == Ieee8021dInterfaceData::ROOT) {
-        EV_INFO << "Configuration BPDU " << bpdu << " arrived from Root Switch." << endl;
-
-        if (bpdu->getTcFlag()) {
-            EV_DEBUG << "MacAddressTable aging time set to " << currentFwdDelay << "." << endl;
-            macTable->setAgingTime(currentFwdDelay);
-
-            // config BPDU with TC flag
-            for (auto & elem : desPorts)
-                generateBPDU(elem, MacAddress::STP_MULTICAST_ADDRESS, true, false);
-        }
-        else {
-            macTable->resetDefaultAging();
-
-            EV_INFO << "Sending BPDUs on all designated ports." << endl;
+    // note: port cost and port priority are configured by the L2NetworkConfigurator
 
-            // BPDUs are sent on all designated ports
-            for (auto & elem : desPorts)
-                generateBPDU(elem);
-        }
-    }
-
-    tryRoot();
-    delete packet;
+    ifd->setState(Ieee8021dInterfaceData::BLOCKING);
+    ifd->setRootPriority(bridgePriority);
+    ifd->setRootAddress(bridgeAddress);
+    ifd->setRootPathCost(0);
+    ifd->setAge(0);
+    ifd->setBridgePriority(bridgePriority);
+    ifd->setBridgeAddress(bridgeAddress);
+    ifd->setPortNum(-1);
+    ifd->setLostBPDU(0);
 }
 
-void Stp::handleTCN(Packet *packet, const Ptr& tcn)
+void Stp::setAllDesignated()
 {
-    EV_INFO << "Topology Change Notification BDPU " << tcn << " arrived." << endl;
-    topologyChangeNotification = true;
-
-    int arrivalGate = packet->getTag()->getInterfaceId();
-    MacAddressInd *addressInd = packet->getTag();
-    MacAddress srcAddress = addressInd->getSrcAddress();
-    MacAddress destAddress = addressInd->getDestAddress();
+    // all ports of the root switch are designated ports
+    EV_DETAIL << "All ports become designated." << endl;    // todo
 
-    // send ACK to the sender
-    EV_INFO << "Sending Topology Change Notification ACK." << endl;
-    generateBPDU(arrivalGate, srcAddress, false, true);
+    desPorts.clear();
+    for (unsigned int i = 0; i < numPorts; i++) {
+        InterfaceEntry *ie = ifTable->getInterface(i);
+        Ieee8021dInterfaceData *portData = ie->getProtocolData();
+        ASSERT(portData != nullptr);
+        if (portData->getRole() == Ieee8021dInterfaceData::DISABLED)
+            continue;
 
-    if (!isRoot) {
-        Packet *outPacket = new Packet(packet->getName());
-        outPacket->insertAtBack(tcn);
-        outPacket->addTag()->setInterfaceId(rootInterfaceId);
-        auto macAddressReq = outPacket->addTag();
-        macAddressReq->setSrcAddress(bridgeAddress);
-        macAddressReq->setDestAddress(destAddress);
-        outPacket->addTag()->setProtocol(&Protocol::stp);
-        outPacket->addTag()->setProtocol(&Protocol::ethernetMac);
-        send(outPacket, "relayOut");
+        int interfaceId = ie->getInterfaceId();
+        portData->setRole(Ieee8021dInterfaceData::DESIGNATED);
+        desPorts.push_back(interfaceId);
     }
-    delete packet;
 }
 
-void Stp::generateBPDU(int interfaceId, const MacAddress& address, bool tcFlag, bool tcaFlag)
+void Stp::handleMessageWhenUp(cMessage *msg)
 {
-    Packet *packet = new Packet("BPDU");
-    const auto& bpdu = makeShared();
-    auto macAddressReq = packet->addTag();
-    macAddressReq->setSrcAddress(bridgeAddress);
-    macAddressReq->setDestAddress(address);
-    packet->addTag()->setInterfaceId(interfaceId);
-    packet->addTag()->setProtocol(&Protocol::stp);
-    packet->addTag()->setProtocol(&Protocol::ethernetMac);
-
-    bpdu->setProtocolIdentifier(0);
-    bpdu->setProtocolVersionIdentifier(0);
-    bpdu->setBpduType(0);    // 0 if configuration BPDU
-
-    bpdu->setBridgeAddress(bridgeAddress);
-    bpdu->setBridgePriority(bridgePriority);
-    bpdu->setRootPathCost(rootPathCost);
-    bpdu->setRootAddress(rootAddress);
-    bpdu->setRootPriority(rootPriority);
-    bpdu->setPortNum(interfaceId);
-    bpdu->setPortPriority(getPortInterfaceData(interfaceId)->getPriority());
-    bpdu->setMessageAge(0);
-    bpdu->setMaxAge(currentMaxAge);
-    bpdu->setHelloTime(currentHelloTime);
-    bpdu->setForwardDelay(currentFwdDelay);
-
-    if (topologyChangeNotification) {
-        if (isRoot || tcFlag) {
-            bpdu->setTcFlag(true);
-            bpdu->setTcaFlag(false);
-        }
-        else if (tcaFlag) {
-            bpdu->setTcFlag(false);
-            bpdu->setTcaFlag(true);
+    if (msg->isSelfMessage()) {
+        if (msg == tick) {
+            handleTick();
+            scheduleAt(simTime() + 1, tick);
         }
+        else
+            throw cRuntimeError("Unknown self-message received");
     }
+    else {
+        Packet *packet = check_and_cast(msg);
+        const auto& bpdu = packet->peekAtFront();
 
-    packet->insertAtBack(bpdu);
-    send(packet, "relayOut");
-}
-
-void Stp::generateTCN()
-{
-    // there is something to notify
-    if (topologyChangeNotification || !topologyChangeRecvd) {
-        if (getPortInterfaceData(rootInterfaceId)->getRole() == Ieee8021dInterfaceData::ROOT) {
-            // exist root port to notifying
-            topologyChangeNotification = false;
-            Packet *packet = new Packet("BPDU");
-            const auto& tcn = makeShared();
-            tcn->setProtocolIdentifier(0);
-            tcn->setProtocolVersionIdentifier(0);
-
-            // 1 if Topology Change Notification BPDU
-            tcn->setBpduType(1);
-
-            auto macAddressReq = packet->addTag();
-            macAddressReq->setSrcAddress(bridgeAddress);
-            macAddressReq->setDestAddress(MacAddress::STP_MULTICAST_ADDRESS);
-            packet->addTag()->setInterfaceId(rootInterfaceId);
-            packet->addTag()->setProtocol(&Protocol::stp);
-            packet->addTag()->setProtocol(&Protocol::ethernetMac);
-
-            packet->insertAtBack(tcn);
-            EV_INFO << "The topology has changed. Sending Topology Change Notification BPDU " << tcn << " to the Root Switch." << endl;
-            send(packet, "relayOut");
+        // IEEE 802.1D-1998 (Section 8.4.5)
+        // BPDUs received on a disabled port shall not be processed by the STP
+        int arrivalGate = packet->getTag()->getInterfaceId();
+        Ieee8021dInterfaceData *port = getPortInterfaceData(arrivalGate);
+        if(port->getRole() == Ieee8021dInterfaceData::DISABLED) {
+            EV_DETAIL << "Incoming port is disabled. Discarding the received BPDU." << endl;
+            delete packet;
+            return;
         }
-    }
-}
-
-bool Stp::isSuperiorBPDU(int interfaceId, const Ptr& bpdu)
-{
-    Ieee8021dInterfaceData *port = getPortInterfaceData(interfaceId);
-    Ieee8021dInterfaceData *xBpdu = new Ieee8021dInterfaceData();
-
-    int result;
-
-    xBpdu->setRootPriority(bpdu->getRootPriority());
-    xBpdu->setRootAddress(bpdu->getRootAddress());
-    xBpdu->setRootPathCost(bpdu->getRootPathCost() + port->getLinkCost());
-    xBpdu->setBridgePriority(bpdu->getBridgePriority());
-    xBpdu->setBridgeAddress(bpdu->getBridgeAddress());
-    xBpdu->setPortPriority(bpdu->getPortPriority());
-    xBpdu->setPortNum(bpdu->getPortNum());
-
-    result = comparePorts(port, xBpdu);
-
-    // port is superior
-    if (result > 0) {
-        delete xBpdu;
-        return false;
-    }
-
-    if (result < 0) {
-        // BPDU is superior
-        port->setFdWhile(0);    // renew info
-        port->setState(Ieee8021dInterfaceData::DISCARDING);
-        setSuperiorBPDU(interfaceId, bpdu);    // renew information
-        delete xBpdu;
-        return true;
-    }
-
-    setSuperiorBPDU(interfaceId, bpdu);    // renew information
-    delete xBpdu;
-    return true;
-}
-
-void Stp::setSuperiorBPDU(int interfaceId, const Ptr& bpdu)
-{
-    // BDPU is out-of-date
-    if (bpdu->getMessageAge() >= bpdu->getMaxAge())
-        return;
-
-    Ieee8021dInterfaceData *portData = getPortInterfaceData(interfaceId);
-
-    portData->setRootPriority(bpdu->getRootPriority());
-    portData->setRootAddress(bpdu->getRootAddress());
-    portData->setRootPathCost(bpdu->getRootPathCost() + portData->getLinkCost());
-    portData->setBridgePriority(bpdu->getBridgePriority());
-    portData->setBridgeAddress(bpdu->getBridgeAddress());
-    portData->setPortPriority(bpdu->getPortPriority());
-    portData->setPortNum(bpdu->getPortNum());
-    portData->setMaxAge(bpdu->getMaxAge());
-    portData->setFwdDelay(bpdu->getForwardDelay());
-    portData->setHelloTime(bpdu->getHelloTime());
-
-    // we just set new port info so reset the age timer
-    portData->setAge(0);
-}
-
-void Stp::generateHelloBDPUs()
-{
-    EV_INFO << "It is hello time. Root switch sending hello BDPUs on all its ports." << endl;
 
-    // send hello BDPUs on all ports
-    for (unsigned int i = 0; i < numPorts; i++) {
-        int interfaceId = ifTable->getInterface(i)->getInterfaceId();
-        generateBPDU(interfaceId);
+        if (bpdu->getBpduType() == BPDU_TYPE_CONFIG)
+            handleBPDU(packet, bpdu);
+        else if (bpdu->getBpduType() == BPDU_TYPE_TCN)
+            handleTCN(packet, bpdu);
     }
 }
 
@@ -319,11 +194,13 @@ void Stp::handleTick()
             EV_DEBUG << "Message Age timer incremented on port=" << interfaceId << endl;
             port->setAge(port->getAge() + tickInterval);
         }
+
         if (port->getRole() == Ieee8021dInterfaceData::ROOT || port->getRole() == Ieee8021dInterfaceData::DESIGNATED) {
             EV_DEBUG << "Forward While timer incremented on port=" << interfaceId << endl;
             port->setFdWhile(port->getFdWhile() + tickInterval);
         }
     }
+
     checkTimers();
     checkParametersChange();
     generateTCN();
@@ -351,11 +228,13 @@ void Stp::checkTimers()
             EV_DETAIL << "Port=" << i << " reached its maximum age. Setting it to the default port info." << endl;
             if (port->getRole() == Ieee8021dInterfaceData::ROOT) {
                 initInterfacedata(interfaceId);
-                lostRoot();
+                topologyChangeNotification = true;
+                tryRoot();
             }
             else {
                 initInterfacedata(interfaceId);
-                lostAlternate();
+                selectDesignatedPorts();
+                topologyChangeNotification = true;
             }
         }
     }
@@ -369,7 +248,7 @@ void Stp::checkTimers()
         if (port->getRole() == Ieee8021dInterfaceData::ROOT || port->getRole() == Ieee8021dInterfaceData::DESIGNATED) {
             if (port->getFdWhile() >= currentFwdDelay) {
                 switch (port->getState()) {
-                    case Ieee8021dInterfaceData::DISCARDING:
+                    case Ieee8021dInterfaceData::BLOCKING:
                         EV_DETAIL << "Port=" << interfaceId << " goes into learning state." << endl;
                         port->setState(Ieee8021dInterfaceData::LEARNING);
                         port->setFdWhile(0);
@@ -388,11 +267,85 @@ void Stp::checkTimers()
             }
         }
         else {
-            EV_DETAIL << "Port=" << interfaceId << " goes into discarding state." << endl;
+            EV_DETAIL << "Port=" << interfaceId << " goes into BLOCKING state." << endl;
             port->setFdWhile(0);
-            port->setState(Ieee8021dInterfaceData::DISCARDING);
+            port->setState(Ieee8021dInterfaceData::BLOCKING);
+        }
+    }
+}
+
+void Stp::generateHelloBDPUs()
+{
+    EV_INFO << "It is hello time. Root switch sending hello BDPUs on all its ports." << endl;
+
+    // send hello BDPUs on all ports
+    for (unsigned int i = 0; i < numPorts; i++) {
+        int interfaceId = ifTable->getInterface(i)->getInterfaceId();
+        generateBPDU(interfaceId);
+    }
+}
+
+void Stp::generateBPDU(int interfaceId, const MacAddress& address, bool tcFlag, bool tcaFlag)
+{
+    Ieee8021dInterfaceData *ifd = getPortInterfaceData(interfaceId);
+    if(ifd && ifd->getRole() == Ieee8021dInterfaceData::DISABLED)
+        return;
+
+    Packet *packet = new Packet("BPDU");
+    const auto& bpdu = makeShared();
+    auto macAddressReq = packet->addTag();
+    macAddressReq->setSrcAddress(ifd->getInterfaceEntry()->getMacAddress());
+    macAddressReq->setDestAddress(address);
+    packet->addTag()->setInterfaceId(interfaceId);
+    packet->addTag()->setProtocol(&Protocol::stp);
+    packet->addTag()->setProtocol(&Protocol::ethernetMac);
+
+    bpdu->setProtocolIdentifier(0);
+    bpdu->setProtocolVersionIdentifier(PROTO_VERSION_STP);
+    bpdu->setBpduType(BPDU_TYPE_CONFIG);
+
+    BpduFlags bpduFlags;
+    if (topologyChangeNotification) {
+        if (isRoot || tcFlag) {
+            EV_INFO << "Sending CONFIG BPDU with Topology Change (TC) flag to port "
+                    << ifd->getInterfaceEntry()->getFullName() << endl;
+            bpduFlags.tcFlag = true;
+            bpduFlags.tcaFlag = false;
+            bpdu->setBpduFlags(bpduFlags);
+        }
+        else if (tcaFlag) {
+            EV_INFO << "Sending CONFIG BPDU with Topology Change ACK (TCA) flag to port "
+                    << ifd->getInterfaceEntry()->getFullName() << endl;
+            bpduFlags.tcFlag = false;
+            bpduFlags.tcaFlag = true;
+            bpdu->setBpduFlags(bpduFlags);
         }
     }
+
+    RootIdentifier rootId;
+    rootId.rootPriority = rootPriority;
+    rootId.rootAddress = rootAddress;
+    bpdu->setRootIdentifier(rootId);
+
+    bpdu->setRootPathCost(rootPathCost);
+
+    BridgeIdentifier bridgeId;
+    bridgeId.bridgePriority = bridgePriority;
+    bridgeId.bridgeAddress = bridgeAddress;
+    bpdu->setBridgeIdentifier(bridgeId);
+
+    PortIdentifier portId;
+    portId.portPriority = getPortInterfaceData(interfaceId)->getPortPriority();
+    portId.portNum = interfaceId;
+    bpdu->setPortIdentifier(portId);
+
+    bpdu->setMessageAge(0);
+    bpdu->setMaxAge(currentMaxAge);
+    bpdu->setHelloTime(currentHelloTime);
+    bpdu->setForwardDelay(currentFwdDelay);
+
+    packet->insertAtBack(bpdu);
+    send(packet, "relayOut");
 }
 
 void Stp::checkParametersChange()
@@ -402,23 +355,97 @@ void Stp::checkParametersChange()
         currentMaxAge = maxAge;
         currentFwdDelay = forwardDelay;
     }
+
     if (currentBridgePriority != bridgePriority) {
         currentBridgePriority = bridgePriority;
-        reset();
+
+        // upon booting all switches believe themselves to be the root
+        isRoot = true;
+        rootPriority = bridgePriority;
+        rootAddress = bridgeAddress;
+        rootPathCost = 0;
+        currentHelloTime = helloTime;
+        currentMaxAge = maxAge;
+        currentFwdDelay = forwardDelay;
+
+        setAllDesignated();
     }
 }
 
-bool Stp::checkRootEligibility()
+void Stp::generateTCN()
 {
-    for (unsigned int i = 0; i < numPorts; i++) {
-        int interfaceId = ifTable->getInterface(i)->getInterfaceId();
-        Ieee8021dInterfaceData *port = getPortInterfaceData(interfaceId);
+    // there is something to notify
+    if (topologyChangeNotification || !topologyChangeRecvd) {
+        if (getPortInterfaceData(rootInterfaceId)->getRole() == Ieee8021dInterfaceData::ROOT) {
 
-        if (compareBridgeIDs(port->getRootPriority(), port->getRootAddress(), bridgePriority, bridgeAddress) > 0)
-            return false;
+            EV_INFO << "Sending TCN BPDU to the root Switch (the topology has changed)." << endl;
+            topologyChangeNotification = false;
+
+            Packet *packet = new Packet("BPDU");
+
+            auto macAddressReq = packet->addTag();
+            macAddressReq->setSrcAddress(getPortInterfaceData(rootInterfaceId)->getInterfaceEntry()->getMacAddress());
+            macAddressReq->setDestAddress(MacAddress::STP_MULTICAST_ADDRESS);
+
+            packet->addTag()->setInterfaceId(rootInterfaceId);
+            packet->addTag()->setProtocol(&Protocol::stp);
+            packet->addTag()->setProtocol(&Protocol::ethernetMac);
+
+            const auto& tcn = makeShared();
+            tcn->setProtocolIdentifier(0);
+            tcn->setProtocolVersionIdentifier(PROTO_VERSION_STP);
+            tcn->setBpduType(BPDU_TYPE_TCN);
+
+            packet->insertAtBack(tcn);
+            send(packet, "relayOut");
+        }
+    }
+}
+
+void Stp::handleBPDU(Packet *packet, const Ptr& bpdu)
+{
+    int arrivalGate = packet->getTag()->getInterfaceId();
+    Ieee8021dInterfaceData *port = getPortInterfaceData(arrivalGate);
+
+    EV_DETAIL << switchModule->getFullName() << " received a CONFIG BPDU on port=" << port->getInterfaceEntry()->getFullName() << endl;
+
+    if (bpdu->getBpduFlags().tcaFlag) {
+        topologyChangeRecvd = true;
+        topologyChangeNotification = false;
     }
 
-    return true;
+    // get inferior BPDU, reply with superior
+    if (!isSuperiorBPDU(arrivalGate, bpdu)) {
+        if (port->getRole() == Ieee8021dInterfaceData::DESIGNATED) {
+            EV_DETAIL << "Inferior Configuration BPDU " << bpdu << " arrived on port=" << arrivalGate << " responding to it with a superior BPDU." << endl;
+            generateBPDU(arrivalGate);
+        }
+    }
+    // BPDU from root
+    else if (port->getRole() == Ieee8021dInterfaceData::ROOT) {
+        EV_INFO << "Configuration BPDU " << bpdu << " arrived from Root Switch." << endl;
+
+        if (bpdu->getBpduFlags().tcFlag) {
+            EV_DEBUG << "MacAddressTable aging time set to " << currentFwdDelay << "." << endl;
+            macTable->setAgingTime(currentFwdDelay);
+
+            // config BPDU with TC flag
+            for (auto & elem : desPorts)
+                generateBPDU(elem, MacAddress::STP_MULTICAST_ADDRESS, true, false);
+        }
+        else {
+            macTable->resetDefaultAging();
+
+            EV_INFO << "Sending BPDUs on all designated ports." << endl;
+
+            // BPDUs are sent on all designated ports
+            for (auto & elem : desPorts)
+                generateBPDU(elem);
+        }
+    }
+
+    tryRoot();
+    delete packet;
 }
 
 void Stp::tryRoot()
@@ -441,6 +468,19 @@ void Stp::tryRoot()
     }
 }
 
+bool Stp::checkRootEligibility()
+{
+    for (unsigned int i = 0; i < numPorts; i++) {
+        int interfaceId = ifTable->getInterface(i)->getInterfaceId();
+        Ieee8021dInterfaceData *port = getPortInterfaceData(interfaceId);
+
+        if (compareBridgeIDs(port->getRootPriority(), port->getRootAddress(), bridgePriority, bridgeAddress) > 0)
+            return false;
+    }
+
+    return true;
+}
+
 int Stp::compareBridgeIDs(unsigned int aPriority, MacAddress aAddress, unsigned int bPriority, MacAddress bAddress)
 {
     if (aPriority < bPriority)
@@ -460,6 +500,98 @@ int Stp::compareBridgeIDs(unsigned int aPriority, MacAddress aAddress, unsigned
     return 0;
 }
 
+void Stp::handleTCN(Packet *packet, const Ptr& tcn)
+{
+    int arrivalGate = packet->getTag()->getInterfaceId();
+    Ieee8021dInterfaceData *port = getPortInterfaceData(arrivalGate);
+
+    EV_DETAIL << switchModule->getFullName() << " received a TCN BPDU on port="
+            << port->getInterfaceEntry()->getFullName() << endl;
+
+    topologyChangeNotification = true;
+
+    MacAddressInd *addressInd = packet->getTag();
+    MacAddress srcAddress = addressInd->getSrcAddress();
+    MacAddress destAddress = addressInd->getDestAddress();
+
+    // send TC/TCA to the sender
+    generateBPDU(arrivalGate, srcAddress, false, true);
+
+    if (!isRoot) {
+        Packet *outPacket = new Packet(packet->getName());
+        outPacket->insertAtBack(tcn);
+        outPacket->addTag()->setInterfaceId(rootInterfaceId);
+        auto macAddressReq = outPacket->addTag();
+        macAddressReq->setSrcAddress(getPortInterfaceData(rootInterfaceId)->getInterfaceEntry()->getMacAddress());
+        macAddressReq->setDestAddress(destAddress);
+        outPacket->addTag()->setProtocol(&Protocol::stp);
+        outPacket->addTag()->setProtocol(&Protocol::ethernetMac);
+        EV_DETAIL << switchModule->getFullName() << " forwards the received TCN BPDU on port="
+                << getPortInterfaceData(rootInterfaceId)->getInterfaceEntry()->getFullName() << endl;
+        send(outPacket, "relayOut");
+    }
+
+    delete packet;
+}
+
+bool Stp::isSuperiorBPDU(int interfaceId, const Ptr& bpdu)
+{
+    Ieee8021dInterfaceData *port = getPortInterfaceData(interfaceId);
+    Ieee8021dInterfaceData *xBpdu = new Ieee8021dInterfaceData();
+
+    xBpdu->setRootPriority(bpdu->getRootIdentifier().rootPriority);
+    xBpdu->setRootAddress(bpdu->getRootIdentifier().rootAddress);
+    xBpdu->setRootPathCost(bpdu->getRootPathCost() + port->getLinkCost());
+    xBpdu->setBridgePriority(bpdu->getBridgeIdentifier().bridgePriority);
+    xBpdu->setBridgeAddress(bpdu->getBridgeIdentifier().bridgeAddress);
+    xBpdu->setPortPriority(bpdu->getPortIdentifier().portPriority);
+    xBpdu->setPortNum(bpdu->getPortIdentifier().portNum);
+
+    int result = comparePorts(port, xBpdu);
+
+    // port is superior
+    if (result > 0) {
+        delete xBpdu;
+        return false;
+    }
+
+    // BPDU is superior
+    if (result < 0) {
+        port->setFdWhile(0);    // renew info
+        port->setState(Ieee8021dInterfaceData::BLOCKING);
+        setSuperiorBPDU(interfaceId, bpdu);    // renew information
+        delete xBpdu;
+        return true;
+    }
+
+    setSuperiorBPDU(interfaceId, bpdu);    // renew information
+    delete xBpdu;
+    return true;
+}
+
+void Stp::setSuperiorBPDU(int interfaceId, const Ptr& bpdu)
+{
+    // BDPU is out-of-date
+    if (bpdu->getMessageAge() >= bpdu->getMaxAge())
+        return;
+
+    Ieee8021dInterfaceData *portData = getPortInterfaceData(interfaceId);
+
+    portData->setRootPriority(bpdu->getRootIdentifier().rootPriority);
+    portData->setRootAddress(bpdu->getRootIdentifier().rootAddress);
+    portData->setRootPathCost(bpdu->getRootPathCost() + portData->getLinkCost());
+    portData->setBridgePriority(bpdu->getBridgeIdentifier().bridgePriority);
+    portData->setBridgeAddress(bpdu->getBridgeIdentifier().bridgeAddress);
+    portData->setPortPriority(bpdu->getPortIdentifier().portPriority);
+    portData->setPortNum(bpdu->getPortIdentifier().portNum);
+    portData->setMaxAge(bpdu->getMaxAge());
+    portData->setFwdDelay(bpdu->getForwardDelay());
+    portData->setHelloTime(bpdu->getHelloTime());
+
+    // we just set new port info so reset the age timer
+    portData->setAge(0);
+}
+
 int Stp::comparePortIDs(unsigned int aPriority, unsigned int aNum, unsigned int bPriority, unsigned int bNum)
 {
     if (aPriority < bPriority)
@@ -524,6 +656,8 @@ void Stp::selectRootPort()
 
     for (unsigned int i = 0; i < numPorts; i++) {
         currentPort = ifTable->getInterface(i)->getProtocolData();
+        if(currentPort->getRole() == Ieee8021dInterfaceData::DISABLED)
+            continue;
         currentPort->setRole(Ieee8021dInterfaceData::NOTASSIGNED);
         result = comparePorts(currentPort, best);
         if (result > 0) {
@@ -531,10 +665,12 @@ void Stp::selectRootPort()
             best = currentPort;
             continue;
         }
+
         if (result < 0) {
             continue;
         }
-        if (currentPort->getPriority() < best->getPriority()) {
+
+        if (currentPort->getPortPriority() < best->getPortPriority()) {
             xRootIdx = i;
             best = currentPort;
             continue;
@@ -542,10 +678,9 @@ void Stp::selectRootPort()
     }
 
     unsigned int xRootInterfaceId = ifTable->getInterface(xRootIdx)->getInterfaceId();
-    if (rootInterfaceId != xRootInterfaceId) {
-        EV_DETAIL << "Port=" << xRootInterfaceId << " selected as root port." << endl;
+    if (rootInterfaceId != xRootInterfaceId)
         topologyChangeNotification = true;
-    }
+
     rootInterfaceId = xRootInterfaceId;
     getPortInterfaceData(rootInterfaceId)->setRole(Ieee8021dInterfaceData::ROOT);
     rootPathCost = best->getRootPathCost();
@@ -577,7 +712,7 @@ void Stp::selectDesignatedPorts()
         if (portData->getRole() == Ieee8021dInterfaceData::ROOT || portData->getRole() == Ieee8021dInterfaceData::DISABLED)
             continue;
 
-        bridgeGlobal->setPortPriority(portData->getPriority());
+        bridgeGlobal->setPortPriority(portData->getPortPriority());
         int interfaceId = ie->getInterfaceId();
         bridgeGlobal->setPortNum(interfaceId);
 
@@ -586,84 +721,19 @@ void Stp::selectDesignatedPorts()
         result = comparePorts(bridgeGlobal, portData);
 
         if (result > 0) {
-            EV_DETAIL << "Port=" << ie->getFullName() << " is elected as designated portData." << endl;
             desPorts.push_back(interfaceId);
             portData->setRole(Ieee8021dInterfaceData::DESIGNATED);
             continue;
         }
+
         if (result < 0) {
             EV_DETAIL << "Port=" << ie->getFullName() << " goes into alternate role." << endl;
             portData->setRole(Ieee8021dInterfaceData::ALTERNATE);
             continue;
         }
     }
-    delete bridgeGlobal;
-}
-
-void Stp::setAllDesignated()
-{
-    // all ports of the root switch are designated ports
-    EV_DETAIL << "All ports become designated." << endl;    // todo
-
-    desPorts.clear();
-    for (unsigned int i = 0; i < numPorts; i++) {
-        InterfaceEntry *ie = ifTable->getInterface(i);
-        Ieee8021dInterfaceData *portData = ie->getProtocolData();
-        ASSERT(portData != nullptr);
-        if (portData->getRole() == Ieee8021dInterfaceData::DISABLED)
-            continue;
-
-        int interfaceId = ie->getInterfaceId();
-        portData->setRole(Ieee8021dInterfaceData::DESIGNATED);
-        desPorts.push_back(interfaceId);
-    }
-}
-
-void Stp::lostRoot()
-{
-    topologyChangeNotification = true;
-    tryRoot();
-}
-
-void Stp::lostAlternate()
-{
-    selectDesignatedPorts();
-    topologyChangeNotification = true;
-}
-
-void Stp::reset()
-{
-    // upon booting all switches believe themselves to be the root
-    isRoot = true;
-    rootPriority = bridgePriority;
-    rootAddress = bridgeAddress;
-    rootPathCost = 0;
-    currentHelloTime = helloTime;
-    currentMaxAge = maxAge;
-    currentFwdDelay = forwardDelay;
-    setAllDesignated();
-}
-
-void Stp::start()
-{
-    StpBase::start();
-
-    initPortTable();
-    currentBridgePriority = bridgePriority;
-    isRoot = true;
-    topologyChangeNotification = true;
-    topologyChangeRecvd = true;
-    rootPriority = bridgePriority;
-    rootAddress = bridgeAddress;
-    rootPathCost = 0;
-    rootInterfaceId = ifTable->getInterface(0)->getInterfaceId();
-    currentHelloTime = helloTime;
-    currentMaxAge = maxAge;
-    currentFwdDelay = forwardDelay;
-    helloTime = 0;
-    setAllDesignated();
 
-    scheduleAt(simTime() + tickInterval, tick);
+    delete bridgeGlobal;
 }
 
 void Stp::stop()
@@ -674,21 +744,4 @@ void Stp::stop()
     cancelEvent(tick);
 }
 
-void Stp::initInterfacedata(unsigned int interfaceId)
-{
-    Ieee8021dInterfaceData *ifd = getPortInterfaceData(interfaceId);
-    ifd->setRole(Ieee8021dInterfaceData::NOTASSIGNED);
-    ifd->setState(Ieee8021dInterfaceData::DISCARDING);
-    ifd->setRootPriority(bridgePriority);
-    ifd->setRootAddress(bridgeAddress);
-    ifd->setRootPathCost(0);
-    ifd->setAge(0);
-    ifd->setBridgePriority(bridgePriority);
-    ifd->setBridgeAddress(bridgeAddress);
-    ifd->setPortPriority(-1);
-    ifd->setPortNum(-1);
-    ifd->setLostBPDU(0);
-}
-
 } // namespace inet
-
diff --git a/src/inet/linklayer/ieee8021d/stp/Stp.h b/src/inet/linklayer/ieee8021d/stp/Stp.h
index 1531f636adf..e0f6846b430 100644
--- a/src/inet/linklayer/ieee8021d/stp/Stp.h
+++ b/src/inet/linklayer/ieee8021d/stp/Stp.h
@@ -40,13 +40,14 @@ class INET_API Stp : public StpBase
 {
   public:
     typedef Ieee8021dInterfaceData::PortInfo PortInfo;
-    enum BdpuType { CONFIG_BDPU = 0, TCN_BPDU = 1 };
 
   protected:
     static const double tickInterval;    // interval between two ticks
     bool isRoot = false;
     unsigned int rootInterfaceId = 0;
     std::vector desPorts;    // set of designated ports
+    std::string disabledInterfaces = "";
+    cPatternMatcher disabledInterfaceMatcher;
 
     // Discovered values
     unsigned int rootPathCost = 0;
@@ -135,13 +136,6 @@ class INET_API Stp : public StpBase
      */
     void setAllDesignated();
 
-    /*
-     * Helper functions to handle state changes
-     */
-    void lostRoot();
-    void lostAlternate();
-    void reset();
-
     /*
      * Determine who is eligible to become the root switch
      */
@@ -226,7 +220,7 @@ inline std::ostream& operator<<(std::ostream& os, Ieee8021dInterfaceData *p)
 
     os << " " << p->getRole() << " " << p->getState() << " ";
     os << p->getLinkCost() << " ";
-    os << p->getPriority() << " ";
+    os << p->getPortPriority() << " ";
 
     return os;
 }
diff --git a/src/inet/linklayer/ieee8021d/stp/Stp.ned b/src/inet/linklayer/ieee8021d/stp/Stp.ned
index d66a6bdc500..632e418264e 100644
--- a/src/inet/linklayer/ieee8021d/stp/Stp.ned
+++ b/src/inet/linklayer/ieee8021d/stp/Stp.ned
@@ -65,6 +65,15 @@ simple Stp like ISpanningTree
         // Shows the spanning tree by coloring connections in the network graphics.
         // Label ethernet interface with port role and status. Mark root switch
         bool visualize = default(false);
+        
+        // only when visualize is true
+        string colorLinkEnabled = default("#000000");
+        string colorLinkDisabled = default("#bbbbbb");
+        string colorRootBridge = default("#cc3300");
+        
+        // excluded interfaces from the spanning tree algorithms.
+        // default is empty and all ports are included in the STP
+        string disabledInterfaces = default("");
 
         @display("i=block/network2");
     gates:
diff --git a/src/inet/networklayer/common/InterfaceTable.cc b/src/inet/networklayer/common/InterfaceTable.cc
index f2b59ded96a..3d7fcb5e8c7 100644
--- a/src/inet/networklayer/common/InterfaceTable.cc
+++ b/src/inet/networklayer/common/InterfaceTable.cc
@@ -72,6 +72,17 @@ void InterfaceTable::initialize(int stage)
         host = getContainingNode(this);
         WATCH_PTRVECTOR(idToInterface);
     }
+    else if (stage == INITSTAGE_NETWORK_INTERFACE_CONFIGURATION) {
+        if(host && host->hasPar("baseMacAddress")) {
+            std::string baseMac = host->par("baseMacAddress");
+            if(baseMac.empty())
+                baseMacAddr = MacAddress::generateAutoAddress();
+            else
+                baseMacAddr.setAddress(baseMac.c_str());
+
+            WATCH(baseMacAddr);
+        }
+    }
 }
 
 void InterfaceTable::refreshDisplay() const
@@ -553,5 +564,10 @@ MulticastGroupList InterfaceTable::collectMulticastGroups() const
     return mglist;
 }
 
+MacAddress InterfaceTable::getBaseMacAddress() const
+{
+    return baseMacAddr;
+}
+
 } // namespace inet
 
diff --git a/src/inet/networklayer/common/InterfaceTable.h b/src/inet/networklayer/common/InterfaceTable.h
index ef6ff9c4978..2f5215e52f1 100644
--- a/src/inet/networklayer/common/InterfaceTable.h
+++ b/src/inet/networklayer/common/InterfaceTable.h
@@ -70,6 +70,7 @@ class INET_API InterfaceTable : public OperationalBase, public IInterfaceTable,
 {
   protected:
     cModule *host;    // cached pointer
+    MacAddress baseMacAddr;
 
     // primary storage for interfaces: vector indexed by id; may contain NULLs;
     // slots are never reused to ensure id uniqueness
@@ -241,6 +242,8 @@ class INET_API InterfaceTable : public OperationalBase, public IInterfaceTable,
      * Returns all multicast group address, with it's interfaceId
      */
     virtual MulticastGroupList collectMulticastGroups() const override;
+
+    virtual MacAddress getBaseMacAddress() const override;
 };
 
 } // namespace inet
diff --git a/src/inet/networklayer/contract/IInterfaceTable.h b/src/inet/networklayer/contract/IInterfaceTable.h
index e0be417e489..51e94e147a4 100644
--- a/src/inet/networklayer/contract/IInterfaceTable.h
+++ b/src/inet/networklayer/contract/IInterfaceTable.h
@@ -168,6 +168,11 @@ class INET_API IInterfaceTable
      * Returns all multicast group address, with it's interfaceId
      */
     virtual MulticastGroupList collectMulticastGroups() const = 0;
+
+    /**
+     * Returns the base MAC address
+     */
+    virtual MacAddress getBaseMacAddress() const = 0;
 };
 
 } // namespace inet
diff --git a/src/inet/node/ethernet/EtherSwitch.ned b/src/inet/node/ethernet/EtherSwitch.ned
index a77b0aeb009..c6444124127 100644
--- a/src/inet/node/ethernet/EtherSwitch.ned
+++ b/src/inet/node/ethernet/EtherSwitch.ned
@@ -53,6 +53,7 @@ module EtherSwitch
         string spanningTreeProtocol = default("Stp");
         int numEthInterfaces = default(0);  // minimum number of ethernet interfaces
         int numExtInterfaces = default(0);
+        string baseMacAddress = default("");
         eth[*].encap.typename = "EtherEncapDummy";
         eth[*].csmacdSupport = csmacdSupport;
         eth[*].mac.typename = default(csmacdSupport ? "EtherMac" : "EtherMacFullDuplex");