//========================================================================== // FDDI_MAC.CC - Simple module definitions of the FDDI MAC model for // Discrete System Simulation in OMNeT++ // // Author: Gabor.Lencse@hit.bme.hu //========================================================================== /*--------------------------------------------------------------* Copyright (C) 1996,97 Gabor Lencse, Technical University of Budapest, Dept. of Telecommunications, Stoczek u.2, H-1111 Budapest, Hungary. This file is distributed WITHOUT ANY WARRANTY. See the file `license' for details on this and other legal matters. *--------------------------------------------------------------*/ #include #include #include "fddi_def.h" #include "fddi_mac.h" #define TRACE_MSG // turn on output messages // #define STATE_CHK // turn on E-FSM state checking static bool accelerated = false; Define_Module( FDDI_MAC ) Define_Module( FDDI_MAC4Ring ) Define_Module( FDDI_MAC4Sniffer ) char *mysimtimeToStr(simtime_t t, char *dest=0) { // place result either into dest static char buf[64]; // or into a static buffer if (dest==NULL) dest=buf; double ts = (double)t+0.000000005; // ts: sim.time(secs)+0.005us long h; int m,s,ms; double us; h = (long) (ts/3600); ts -= h*3600; m = (int) (ts/60); ts -= m*60; s = (int) (ts); ts -= s; ms = (int) (ts*1000); ts -= ms/1000.0; us = (ts*1000000L); us=( (long) (100L*us))/100.0; sprintf(dest,"%ds %dms %.2fu", s,ms,us); return dest; } void printMsg(cMessage &msg) { char time1[64],time2[64]; char msgname[32]; const char *s=msg.fullName(); const int LEN = 21; strncpy(msgname,s,LEN); int i; for (i=strlen(s); ipar("restricted"); // ?? the address of the 2 stations, who have the restr. token ... // capture the token if it is usable, repeat it otherwise: if ( !sync_buf.empty() || (!async_buf.empty()&&!LateCounter&&((double)TRT>token_time)) ) { // according to the STANDARD, it should be: TRT>token_time+station_latency State |= TOKEN_CAPTURE; m = new cMessage("TOKEN_CAPTURE_END",TOKEN_CAPTURE_END,0); scheduleAt(simTime()+token_time,m); } else { State |= TOKEN_RECEIVE | BEFORE_TOKEN_REPEAT; m = new cMessage("TOKEN_RECEIVE_END",TOKEN_RECEIVE_END,0); scheduleAt(simTime()+token_time,m); m = new cMessage("TOKEN_REPEAT_BEGIN",TOKEN_REPEAT_BEGIN,0); scheduleAt(simTime()+station_latency,m); } delete msg; } void FDDI_MAC::TokenRepeatBegin(cMessage *msg) { CurrentEvent=TOKEN_REPEAT_BEGIN; #ifdef STATE_CHK //Required State: BEFORE_TOKEN_REPEAT //Also Good State: TOKEN_RECEIVE StateCheck(BEFORE_TOKEN_REPEAT,TOKEN_RECEIVE); #endif State &= ~BEFORE_TOKEN_REPEAT; State |= TOKEN_REPEAT; cMessage *tok = new cMessage("FDDI_TOKEN", FDDI_TOKEN); tok->setLength(TokenLength); tok->addPar("restricted") = (bool)RestrictedToken; send( tok, "out"); cMessage *m = new cMessage("TOKEN_REPEAT_END",TOKEN_REPEAT_END,0); scheduleAt(simTime()+token_time,m); delete msg; } void FDDI_MAC::TokenRepeatEnd(cMessage *msg) { CurrentEvent=TOKEN_REPEAT_END; #ifdef STATE_CHK //Required State: TOKEN_REPEAT //Also Good State: - StateCheck(TOKEN_REPEAT,IDLE); #endif State &= ~TOKEN_REPEAT; delete msg; } void FDDI_MAC::TokenReceiveEnd(cMessage *msg) { CurrentEvent=TOKEN_RECEIVE_END; #ifdef STATE_CHK //Required State: TOKEN_RECEIVE //Also Good State: TOKEN_REPEAT StateCheck(TOKEN_RECEIVE,TOKEN_REPEAT); #endif State &= ~TOKEN_RECEIVE; if ( (EarlyToken=!LateCounter) != 0 ) { TRT=T_Opr; // it is auto enabled cancelEvent(TRTExpire); scheduleAt(simTime()+T_Opr,TRTExpire); } else LateCounter=0; delete msg; } void FDDI_MAC::TokenCaptureEnd(cMessage *msg) { CurrentEvent=TOKEN_CAPTURE_END; #ifdef STATE_CHK //Required State: TOKEN_CAPTURE //Also Good State: - StateCheck(TOKEN_CAPTURE,IDLE); #endif State &= ~TOKEN_CAPTURE; State |= BEFORE_TRANSMIT_OWN; scheduleAt(simTime()+station_latency,new cMessage("TRANSMIT_OWN_BEGIN",TRANSMIT_OWN_BEGIN,0)); if ( (EarlyToken=!LateCounter) != 0 ) { THT=(double)TRT; // it is auto enabled THT.disable(); // only BeforeTransmitEnd should disable it! see STANDARD TRT=T_Opr; // it is auto enabled cancelEvent(TRTExpire); scheduleAt(simTime()+T_Opr,TRTExpire); } else LateCounter=0; SyncFinished=false; UsedSyncBandwidth=0; delete msg; } void FDDI_MAC::TransmitOwnBegin(cMessage *msg) { CurrentEvent=TRANSMIT_OWN_BEGIN; #ifdef STATE_CHK //Required State: BEFORE_TRANSMIT_OWN //Also Good State: - StateCheck(BEFORE_TRANSMIT_OWN,IDLE); #endif State &= ~BEFORE_TRANSMIT_OWN; // this must be unset here, PlayTTRP unsets only TRANSMIT_OWN // do the actions on the basis of the protocol, set the new state too: PlayTTRP(); delete msg; } void FDDI_MAC::TransmissionEnd(cMessage *msg) { CurrentEvent=TRANSMISSION_END; #ifdef STATE_CHK //Required State: TRANSMIT_OWN //Also Good State: FRAME_STRIP StateCheck(TRANSMIT_OWN,FRAME_STRIP); #endif // do the actions on the basis of the protocol, set the new state too: PlayTTRP(); delete msg; } void FDDI_MAC::TokenSendEnd(cMessage *msg) { CurrentEvent=TOKEN_SEND_END; #ifdef STATE_CHK //Required State: TOKEN_SEND //Also Good State: FRAME_STRIP StateCheck(TOKEN_SEND,FRAME_STRIP); #endif State &= ~TOKEN_SEND; delete msg; } void FDDI_MAC::OwnFrameArrived(cMessage *msg) { CurrentEvent=OWN_FRAME_ARRIVED; #ifdef STATE_CHK //Required State: - //Also Good State: TRANSMIT_OWN,TOKEN_SEND StateCheck(IDLE,TRANSMIT_OWN|TOKEN_SEND); #endif State |= FRAME_STRIP; cMessage *m = new cMessage("FRAME_STRIP_END",FRAME_STRIP_END,0); scheduleAt(simTime()+msg->length()*byte_tr_time-inorder_epsilon, m); delete msg; } void FDDI_MAC::FrameStripEnd(cMessage *msg) { CurrentEvent=FRAME_STRIP_END; #ifdef STATE_CHK //Required State: FRAME_STRIP //Also Good State: TRANSMIT_OWN,TOKEN_SEND StateCheck(FRAME_STRIP,TRANSMIT_OWN|TOKEN_SEND); #endif State &= ~FRAME_STRIP; delete msg; } void FDDI_MAC::Frame2MeArrived(cMessage *msg) { CurrentEvent=FR2ME_ARRIVED; #ifdef STATE_CHK //Required State: - //Also Good State: REPEAT StateCheck(IDLE,REPEAT); #endif State |= FR2ME_RECEIVE; cMessage *m = new cMessage("FR2ME_RECEIVE_END",FR2ME_RECEIVE_END,0); scheduleAt(simTime()+msg->length()*byte_tr_time-inorder_epsilon, m); msg_being_recd = msg; if ( !accelerated ) { State |= BEFORE_REPEAT; //msg_to_repeat = new cMessage(*msg); <-- this may cause segmentation fault msg_to_repeat = (cMessage *) msg->dup(); scheduleAt(simTime()+station_latency,new cMessage("REPEAT_BEGIN",REPEAT_BEGIN,0)); } } void FDDI_MAC::FrameToMeReceiveEnd(cMessage *msg) { CurrentEvent=FR2ME_RECEIVE_END; #ifdef STATE_CHK //Required State: FR2ME_RECEIVE //Also Good State: REPEAT StateCheck(FR2ME_RECEIVE,REPEAT); #endif State &= ~FR2ME_RECEIVE; send(msg_being_recd,"to_LLC"); delete msg; } void FDDI_MAC::Frame2RepArrived(cMessage *msg) { CurrentEvent=FR2REP_ARRIVED; #ifdef STATE_CHK //Required State: - //Also Good State: REPEAT StateCheck(IDLE,REPEAT); #endif State |= BEFORE_REPEAT; msg_to_repeat=msg; scheduleAt(simTime()+station_latency,new cMessage("REPEAT_BEGIN",REPEAT_BEGIN,0)); } void FDDI_MAC::RepeatEnd(cMessage *msg) { CurrentEvent=REPEAT_END; #ifdef STATE_CHK //Required State: REPEAT //Also Good State: BEFORE_REPEAT,FR2ME_RECEIVE,TOKEN_RECEIVE,BEFORE_TOKEN_REPEAT,TOKEN_CAPTURE (but NOT at the same time ...) StateCheck(REPEAT,BEFORE_REPEAT|FR2ME_RECEIVE|TOKEN_RECEIVE|BEFORE_TOKEN_REPEAT|TOKEN_CAPTURE); #endif State &= ~REPEAT; delete msg; } void FDDI_MAC::RepeatBegin(cMessage *msg) { CurrentEvent=REPEAT_BEGIN; #ifdef STATE_CHK //Required State: BEFORE_REPEAT //Also Good State: FR2ME_RECEIVE StateCheck(BEFORE_REPEAT,FR2ME_RECEIVE); #endif State &= ~BEFORE_REPEAT; State |= REPEAT; RepeatEndsAt = simTime()+msg_to_repeat->length()*byte_tr_time; scheduleAt(RepeatEndsAt-inorder_epsilon, new cMessage("REPEAT_END",REPEAT_END,0)); send(msg_to_repeat,"out"); delete msg; IdleTimes=0; // a packet is repeated => not idle } void FDDI_MAC::TRTExpired(cMessage *msg) { CurrentEvent=TRT_EXPIRED; if ( LateCounter == 0 ) { LateCounter++; TRT=T_Opr; // it is auto enabled scheduleAt(simTime()+T_Opr,msg); // Recycling: *msg is reused } else { State = TOKEN_LOST; delete msg; error("FDDI_MAC Error: Token was lost (TRT expired twice in %s)\n",fullPath()); } } void FDDI_MAC::PlayTTRP() // Play the Timed Token Ring Protocol { if ( !SyncFinished && !sync_buf.empty() ) { // try to ransmit the first sync. packet cMessage *m=(cMessage *)sync_buf.pop(); int length = m->length(); if ( AllocatedSyncBandwidth >= UsedSyncBandwidth+length ) { // this packet can be transmitted UsedSyncBandwidth+=length; m->addPar("sendtime") = simTime(); send(m,"out"); State |= TRANSMIT_OWN; double sending_time=length*byte_tr_time; scheduleAt(simTime()+sending_time, new cMessage("TRANSMISSION_END",TRANSMISSION_END,0)); IdleTimes=0; // a packet is transmitted => not idle return; // !! HEY there is a RETURN here! // ^ the next sync may be transmitted by the next call of this function } } // the function didn't return => no more sync could be transmitted if ( !SyncFinished ) { SyncFinished=true; if ( EarlyToken ) { THT.enable(); priority_i=7; } } // here SyncFinished is true if ( EarlyToken && !async_buf.empty() && (!RestrictedToken || IAmRestrictedOwner) && ((double)THT)>0 ) { // the 1st packet can be transmitted cMessage *m = (cMessage *)async_buf.pop(); m->addPar("sendtime") = simTime(); send(m,"out"); State |= TRANSMIT_OWN; int length=m->length(); double tr_time=length*byte_tr_time; scheduleAt(simTime()+tr_time, new cMessage("TRANSMISSION_END",TRANSMISSION_END,0)); IdleTimes=0; // a packet is transmitted => not idle return; // !! HEY there is a RETURN here! // ^ the next async may be transmitted by the next call of this function } // the function didn't return => no more async could be transmitted // now the token must be passed cMessage *tok = new cMessage("FDDI_TOKEN", FDDI_TOKEN); tok->setLength(TokenLength); tok->addPar("restricted") = RestrictedToken; send( tok, "out"); State &= ~TRANSMIT_OWN; State |= TOKEN_SEND; scheduleAt(simTime()+TokenLength*byte_tr_time, new cMessage("TOKEN_SEND_END",TOKEN_SEND_END,0)); } FDDI_MAC::FDDI_MAC(const char *namestr, cModule *parentmod) : cSimpleModule(namestr, parentmod, FDDI_MAC_HEAPSIZE), sync_buf("sync_buf"), async_buf("async_buf") { State=IDLE; CurrentEvent=0; msg_being_recd=0; // message is currently being received msg_to_repeat=0; // this msg will be repeated when REPEAT_BEGIN event arrives RepeatEndsAt=-1; // the current repeating will end at this time EarlyToken=0; // Token is early RestrictedToken=0; // Token is restricted LateCounter=0; // TRT expired LateCounter times since last TOKEN_ARRIVE TRTExpire=0; // holds a pointer to the TRT expire event AllocatedSyncBandwidth=0; // Allocated Synchronous Bandwidth (in bytes) UsedSyncBandwidth=0; // Used Synchronous Bandwidth (in bytes) RingID=-1; // To cause error, if not set later IdleTimes=0; // # of tokens arrived since packet was transmitted for the last time IAmRestrictedOwner=false; // This station is a/the ResrictedToken owner SyncFinished=false; // transm. of sync. packets is already finished } FDDI_MAC4Ring::FDDI_MAC4Ring(const char *namestr, cModule *parentmod) : FDDI_MAC(namestr,parentmod) { } void FDDI_MAC::activity() { RingID = (short) (long) parentModule()->parentModule()->par("RingID"); T_Opr = parentModule()->parentModule()->par("TTRT"); if ( findPar("StationID") < 0 ) my_station_id = parentModule()->index(); // RO: use only in a ring made by indexing ... else my_station_id = par("StationID"); IAmRestrictedOwner=false; TRT=T_Opr; // it is auto enabled TRTExpire = new cMessage("TRT_EXPIRED",TRT_EXPIRED,0); scheduleAt(simTime()+T_Opr,TRTExpire); if (my_station_id == 0) { // Issue a token: cMessage *tok = new cMessage("FDDI_TOKEN", FDDI_TOKEN); tok->setLength(TokenLength); tok->addPar("restricted") = false; send( tok, "out"); } for(;;) { cMessage *msg = receive(); #ifdef TRACE_MSG ev.printf("0x%04x ",State); printMsg(*msg); #endif if ( msg->arrivedOn("from_LLC") ) // new message from the generator async_buf.insert( msg ); // insert message into the asynchronous send buffer else { int msgkind = msg->kind(); if ( msgkind >= FDDI_MAC_MSG2SELF ) // if it is just a self message switch ( msgkind ) { case TOKEN_RECEIVE_END : TokenReceiveEnd(msg); break; case TRANSMISSION_END : TransmissionEnd(msg); break; case TOKEN_SEND_END : TokenSendEnd(msg); break; case FRAME_STRIP_END : FrameStripEnd(msg); break; case FR2ME_RECEIVE_END : FrameToMeReceiveEnd(msg); break; case REPEAT_END : RepeatEnd(msg); break; case TRT_EXPIRED : TRTExpired(msg); break; case REPEAT_BEGIN : RepeatBegin(msg); break; case TOKEN_REPEAT_BEGIN : TokenRepeatBegin(msg); break; case TOKEN_REPEAT_END : TokenRepeatEnd(msg); break; case TOKEN_CAPTURE_END : TokenCaptureEnd(msg); break; case TRANSMIT_OWN_BEGIN : TransmitOwnBegin(msg); break; default: error("FDDI_MAC Error: Bad msgkind: %i in %s", msgkind, fullPath()); } else if ( msgkind == FDDI_TOKEN ) TokenArrived(msg); else if ( msgkind == FDDI_FRAME ) { int source = (long) msg->par ("source"); if ( source == my_station_id ) OwnFrameArrived(msg); else { int dest = (long) msg->par ("dest"); if ( dest == my_station_id ) Frame2MeArrived(msg); else Frame2RepArrived(msg); } } else { ev.printf("Msg pointer=%p\n", msg); error("(2)FDDI_MAC Error: Bad msgkind: %i in %s", msgkind, fullPath()); } } } // endfor } void FDDI_MAC4Sniffer::OwnFrameArrived(cMessage *msg) { // The code is taken from: virtual void FDDI_MAC::OwnFrameArrived(cMessage *) CurrentEvent=OWN_FRAME_ARRIVED; #ifdef STATE_CHK //Required State: - //Also Good State: TRANSMIT_OWN,TOKEN_SEND StateCheck(IDLE,TRANSMIT_OWN|TOKEN_SEND); #endif State |= FRAME_STRIP; cMessage *m = new cMessage("FRAME_STRIP_END",FRAME_STRIP_END,0); scheduleAt(simTime()+msg->length()*byte_tr_time-inorder_epsilon, m); // delete msg; // CHANGE: the message is not deleted, but it is forwarded to the Monitor sendDelayed(msg,msg->length()*byte_tr_time,"to_LLC"); } void FDDI_MAC4Sniffer::Frame2RepArrived(cMessage *msg) { // The code is taken from: virtual void FDDI_MAC::Frame2RepArrived(cMessage *msg) CurrentEvent=FR2REP_ARRIVED; #ifdef STATE_CHK //Required State: - //Also Good State: REPEAT StateCheck(IDLE,REPEAT); #endif State |= BEFORE_REPEAT; // CHANGE: msg is copied and sent to LLC: cMessage *msgcpy = (cMessage *) msg->dup(); sendDelayed(msgcpy,msg->length()*byte_tr_time,"to_LLC"); // END OF CHANGE msg_to_repeat=msg; scheduleAt(simTime()+station_latency,new cMessage("REPEAT_BEGIN",REPEAT_BEGIN,0)); }