www.pudn.com > 802.16jModule.rar > mac802_16SS.cc
/* This software was developed at the National Institute of Standards and * Technology by employees of the Federal Government in the course of * their official duties. Pursuant to title 17 Section 105 of the United * States Code this software is not subject to copyright protection and * is in the public domain. * NIST assumes no responsibility whatsoever for its use by other parties, * and makes no guarantees, expressed or implied, about its quality, * reliability, or any other characteristic. ** @author rouil */ #include "mac802_16SS.h" #include "scheduling/wimaxscheduler.h" #include "scheduling/ssscheduler.h" #include "destclassifier.h" /** * TCL Hooks for the simulator for wimax mac */ static class Mac802_16SSClass : public TclClass { public: Mac802_16SSClass() : TclClass("Mac/802_16/SS") {} TclObject* create(int, const char*const*) { return (new Mac802_16SS()); } } class_mac802_16SS; /** * Creates a Mac 802.16 */ Mac802_16SS::Mac802_16SS() : Mac802_16 () { type_ = STA_MN; //type of MAC. In this case it is for SS //Create default configuration addClassifier (new DestClassifier ()); Tcl& tcl = Tcl::instance(); tcl.evalf ("new WimaxScheduler/SS"); scheduler_ = (WimaxScheduler*) TclObject::lookup(tcl.result()); scheduler_->setMac (this); //register the mac init_default_connections (); //We can configure each SS with a different modulation //default transmission profile (64 QAM 3_4. Can be changed by TCL) //The DIUC to use will be determined via an algorithm considering //the channel performance default_diuc_ = DIUC_PROFILE_7; //initialize state state_ = MAC802_16_DISCONNECTED; //At start up, we are not connected. //scanning status scan_info_ = (struct scanning_structure *) malloc (sizeof (struct scanning_structure)); memset (scan_info_, 0, sizeof (struct scanning_structure)); scan_info_->nbr = NULL; scan_info_->substate = SSNORMAL; //no scanning scan_flag_ = false; map_ = new FrameMap (this); //create timers for state machine t1timer_ = new WimaxT1Timer (this); t2timer_ = new WimaxT2Timer (this); t6timer_ = NULL; t12timer_ = new WimaxT12Timer (this); t21timer_ = new WimaxT21Timer (this); lostDLMAPtimer_ = new WimaxLostDLMAPTimer (this); lostULMAPtimer_ = new WimaxLostULMAPTimer (this); //create timers for DL/UL boundaries dl_timer_ = new DlTimer (this); ul_timer_ = new UlTimer (this); //initialize some other variables nb_reg_retry_ = 0; nb_scan_req_ = 0; } /* * Interface with the TCL script * @param argc The number of parameter * @param argv The list of parameters * @return command status */ int Mac802_16SS::command(int argc, const char*const* argv) { if (argc == 3) { if (strcmp(argv[1], "set-diuc") == 0) { int diuc = atoi (argv[2]); if (diuc < DIUC_PROFILE_1 || diuc > DIUC_PROFILE_11) return TCL_ERROR; default_diuc_ = diuc; return TCL_OK; } } return Mac802_16::command(argc, argv); } /** * Initialize default connections * These connections are not linked to a peer node */ void Mac802_16SS::init_default_connections () { Connection * con; //create initial ranging and padding connection con = new Connection (CONN_INIT_RANGING); connectionManager_->add_connection (con, OUT_CONNECTION); con = new Connection (CONN_INIT_RANGING); connectionManager_->add_connection (con, IN_CONNECTION); con = new Connection (CONN_PADDING); connectionManager_->add_connection (con, OUT_CONNECTION); con = new Connection (CONN_PADDING); connectionManager_->add_connection (con, IN_CONNECTION); //create connection to receive broadcast packets from BS con = new Connection (CONN_BROADCAST); connectionManager_->add_connection (con, IN_CONNECTION); } /** * Initialize the MAC */ void Mac802_16SS::init () { //init the scheduler scheduler_->init(); //Set physical layer to receiving mode getPhy()->setMode (OFDM_RECV); //SS is looking for synchronization state_ = MAC802_16_WAIT_DL_SYNCH; //start timer for expiration t21timer_->start (macmib_.t21_timeout); } /** * Called when a timer expires * @param The timer ID */ void Mac802_16SS::expire (timer_id id) { switch (id) { case WimaxT21TimerID: debug ("At %f in Mac %d, synchronization failed\n", NOW, addr()); //go to next channel nextChannel(); t21timer_->start (macmib_.t21_timeout); break; case WimaxLostDLMAPTimerID: debug ("At %f in Mac %d, lost synchronization (DL_MAP)\n", NOW, addr()); lost_synch (); break; case WimaxT1TimerID: debug ("At %f in Mac %d, lost synchronization (DCD)\n", NOW, addr()); lost_synch (); break; case WimaxLostULMAPTimerID: debug ("At %f in Mac %d, lost synchronization (UL_MAP)\n", NOW, addr()); lost_synch (); break; case WimaxT12TimerID: debug ("At %f in Mac %d, lost uplink param (UCD)\n", NOW, addr()); lost_synch (); break; case WimaxT2TimerID: debug ("At %f in Mac %d, lost synchronization (RNG)\n", NOW, addr()); getMap()->getUlSubframe()->getRanging()->removeRequest (); lost_synch (); break; case WimaxT3TimerID: debug ("At %f in Mac %d, no ranging response from BS\n", NOW, addr()); //we reach the maximum number of retries //mark DL channel usuable (i.e we go to next) getMap()->getUlSubframe()->getRanging()->removeRequest (); nextChannel(); lost_synch (); break; case WimaxT6TimerID: debug ("At %f in Mac %d, registration timeout (nbretry=%d)\n", NOW, addr(), nb_reg_retry_); if (nb_reg_retry_ == macmib_.reg_req_retry) { debug ("\tmax retry excedeed\n"); lost_synch (); } else { send_registration(); } break; default: debug ("Trigger unkown\n"); } } /**** Packet processing methods ****/ /* * Process packets going out * @param p The packet to send out */ void Mac802_16SS::sendDown(Packet *p) { #ifdef DEBUG_WIMAX debug("at %f SS transmits a packet (type=%s). \n", NOW, packet_info.name(HDR_CMN(p)->ptype())); if (HDR_CMN(p)->ptype()==PT_MAC) { if (HDR_MAC802_16(p)->header.ht == 0) debug ("mngt=%d\n", ((mac802_16_dl_map_frame*) p->accessdata())->type); else debug ("bwreq\n"); } else if (HDR_CMN(p)->ptype() == PT_ARP) { printf ("\tSS(%d) transmit a ARP message which macDA = %d and targetIP=%x\n", addr(), HDR_MAC(p)->macDA(), HDR_ARP(p)->arp_tpa); } else { if (strcmp("cbr", packet_info.name(HDR_CMN(p)->ptype()) )==0){ debug ("RS send the message(type=%s) which CID = %d\n",packet_info.name(HDR_CMN(p)->ptype()), HDR_MAC802_16(p)->header.cid); } } #endif //We first send it through the CS int cid = -1; if (!notify_upper_) { assert (!pktBuf_); pktBuf_ = p; return; } cid = classify (p); if (cid == -1) { printf ("At %f in Mac %d drop packet because no classification were found\n", \ NOW, index_); drop(p, "CID"); //Packet::free (p); } else { //enqueue the packet Connection *connection = connectionManager_->get_connection (cid, OUT_CONNECTION); if (connection == NULL) { debug ("Warning: At %f in Mac %d connection with cid = %d does not exist. Please check classifiers\n",\ NOW, index_, cid); //Packet::free (p); update_watch (&loss_watch_, 1); drop(p, "CID"); } else { if (connection->queueLength ()==macmib_.queue_length) { //queue full update_watch (&loss_watch_, 1); drop (p, "QWI"); } else { //update mac header information //set header information hdr_mac802_16 *wimaxHdr = HDR_MAC802_16(p); wimaxHdr->header.ht = 0; wimaxHdr->header.ec = 1; wimaxHdr->header.type_mesh = 0; wimaxHdr->header.type_arqfb = 0; wimaxHdr->header.type_ext = 0; wimaxHdr->header.type_frag = 0; wimaxHdr->header.type_pck = 0; wimaxHdr->header.type_fbgm = 0; wimaxHdr->header.esf = 0; wimaxHdr->header.ci = 0; wimaxHdr->header.eks = 0; wimaxHdr->header.cid = cid; //default wimaxHdr->header.hcs = 0; HDR_CMN(p)->size() += HDR_MAC802_16_SIZE; connection ->enqueue (p); //printf ("At %f in Mac %d Enqueue packet to cid=%d queue size=%d(max=%d)\n", NOW, index_, cid,connection->queueLength (), macmib_.queue_length); } } } //inform upper layer that it can send another packet resume (NULL); } /* * Transmit a packet to the physical layer * @param p The packet to send out */ void Mac802_16SS::transmit(Packet *p) { //The following condition is valid for OFDM but in OFDMA //we can send multiple packets using different subcarriers //so we will have to update this. if (NOW < last_tx_time_+last_tx_duration_) { //still sending //printf ("MAC is already transmitting. Drop packet.\n"); Packet::free (p); return; } struct hdr_cmn *ch = HDR_CMN(p); #ifdef DEBUG_WIMAX debug ("At %f in Mac %d sending packet (type=%s, size=%d, txtime=%f) \n", NOW, index_, packet_info.name(ch->ptype()), ch->size(), ch->txtime()); if (ch->ptype()==PT_MAC) { if (HDR_MAC802_16(p)->header.ht == 0){ mac802_16_dl_map_frame *frame = (mac802_16_dl_map_frame*) p->accessdata(); if (frame->type==MAC_REG_REQ){ debug("\tSS transmit the message which type is %d\n", frame->type); } } else debug ("bwreq\n"); } else if (HDR_CMN(p)->ptype() == PT_ARP) { debug("\tSS transmit a ARP message which target IP is %x\n", HDR_ARP(p)->arp_tpa); } else { debug ("\n"); } #endif //update stats for delay and jitter double delay = NOW-ch->timestamp(); update_watch (&delay_watch_, delay); double jitter = fabs (delay - last_tx_delay_); update_watch (&jitter_watch_, jitter); last_tx_delay_ = delay; if (ch->ptype()!=PT_MAC) { update_throughput (&tx_data_watch_, 8*ch->size()); } update_throughput (&tx_traffic_watch_, 8*ch->size()); last_tx_time_ = NOW; last_tx_duration_ = ch->txtime(); //pass it down downtarget_->recv (p, (Handler*)NULL); } /* * Process incoming packets * @param p The incoming packet */ void Mac802_16SS::sendUp (Packet *p) { struct hdr_cmn *ch = HDR_CMN(p); #ifdef DEBUG_WIMAX debug ("At %f in Mac %d receive first bit..over at %f(txtime=%f) (type=%s) ", NOW, index_, NOW+ch->txtime(),ch->txtime(), packet_info.name(ch->ptype())); if (ch->ptype()==PT_MAC) { if (HDR_MAC802_16(p)->header.ht == 0){ mac802_16_dl_map_frame *frame = (mac802_16_dl_map_frame*) p->accessdata(); debug ("mngt=%d\n", ((mac802_16_dl_map_frame*) p->accessdata())->type); if (frame->type == MAC_DSA_RSP){ debug("SS receive the MAC_DSA_RSP\n"); } } else debug ("bwreq\n"); } else if (HDR_CMN(p)->ptype() == PT_ARP) { debug("\tSS receive a ARP message which target IP is %x\n", HDR_ARP(p)->arp_tpa); } else { if (strcmp("cbr", packet_info.name(ch->ptype()))==0){ debug ("SS receive the message(type=%s) which CID = %d\n",packet_info.name(ch->ptype()), HDR_MAC802_16(p)->header.cid); } } #endif if (pktRx_ !=NULL) { /* * If the power of the incoming packet is smaller than the * power of the packet currently being received by at least * the capture threshold, then we ignore the new packet. */ if(pktRx_->txinfo_.RxPr / p->txinfo_.RxPr >= p->txinfo_.CPThresh) { Packet::free(p); } else { /* * Since a collision has occurred, figure out * which packet that caused the collision will * "last" the longest. Make this packet, * pktRx_ and reset the Recv Timer if necessary. */ if(txtime(p) > rxTimer_.expire()) { rxTimer_.stop(); //printf ("\t drop pktRx..collision\n"); drop(pktRx_, "COL"); update_watch (&loss_watch_, 1); pktRx_ = p; //mark the packet with error ch->error() = 1; collision_ = true; rxTimer_.start(ch->txtime()-0.000000001); } else { //printf ("\t drop new packet..collision\n"); drop(p, "COL"); //mark the packet with error HDR_CMN(pktRx_)->error() = 1; collision_ = true; } } return; } assert (pktRx_==NULL); assert (rxTimer_.busy()==0); pktRx_ = p; //create a timer to wait for the end of reception //since the packets are received by burst, the beginning of the new packet //is the same time as the end of this packet..we process this packet 1ns //earlier to make room for the new packet. rxTimer_.start(ch->txtime()-0.000000001); } /** * Process the fully received packet */ void Mac802_16SS::receive () { assert (pktRx_); struct hdr_cmn *ch = HDR_CMN(pktRx_); #ifdef DEBUG_WIMAX printf ("At %f in Mac %d packet received (type=%s) ", NOW, index_, packet_info.name(ch->ptype())); if (ch->ptype()==PT_MAC) { if (HDR_MAC802_16(pktRx_)->header.ht == 0) printf ("mngt=%d\n", ((mac802_16_dl_map_frame*) pktRx_->accessdata())->type); else printf ("bwreq\n"); } else { printf ("\n"); } #endif //drop the packet if corrupted if (ch->error()) { if (collision_) { //printf ("\t drop new pktRx..collision\n"); drop (pktRx_, "COL"); collision_ = false; } else { //error in the packet, the Mac does not process Packet::free(pktRx_); } //update drop stat update_watch (&loss_watch_, 1); pktRx_ = NULL; return; } //process packet hdr_mac802_16 *wimaxHdr = HDR_MAC802_16(pktRx_); gen_mac_header_t header = wimaxHdr->header; int cid = header.cid; Connection *con = connectionManager_->get_connection (cid, IN_CONNECTION); if (con == NULL) { //This packet is not for us //printf ("At %f in Mac %d Connection null\n", NOW, index_); update_watch (&loss_watch_, 1); Packet::free(pktRx_); pktRx_=NULL; return; } //printf ("CID=%d\n", cid); //update rx time of last packet received PeerNode *peer_ = getPeerNode_head(); if (peer_) { peer_->setRxTime (NOW); //collect receive signal strength stats peer_->getStatWatch()->update(10*log10(pktRx_->txinfo_.RxPr*1e3)); //debug ("At %f in Mac %d weighted RXThresh: %e rxp average %e\n", NOW, index_, macmib_.lgd_factor_*macmib_.RXThreshold_, pow(10,peer->getStatWatch()->average()/10)/1e3); double avg_w = pow(10,(peer_->getStatWatch()->average()/10))/1e3; if ( avg_w < (macmib_.lgd_factor_*macmib_.RXThreshold_)) { //Removed the condition on going down to allow sending multiple events with different confidence level if (state_==MAC802_16_CONNECTED) { if (!peer_->isGoingDown ()) //when we don't use 802.21, we only want to send the scan request once peer_->setGoingDown (true); } } else { if (peer_->isGoingDown()) { peer_->setGoingDown (false); } } } //process reassembly if (wimaxHdr->header.type_frag) { bool drop_pkt = true; bool frag_error = false; //printf ("Frag type = %d %d\n",wimaxHdr->frag_subheader.fc,wimaxHdr->frag_subheader.fc & 0x3); switch (wimaxHdr->frag_subheader.fc & 0x3) { case FRAG_NOFRAG: if (con->getFragmentationStatus()!=FRAG_NOFRAG) con->updateFragmentation (FRAG_NOFRAG, 0, 0); //reset drop_pkt = false; break; case FRAG_FIRST: //when it is the first fragment, it does not matter if we previously //received other fragments, since we reset the information assert (wimaxHdr->frag_subheader.fsn == 0); //printf ("\tReceived first fragment\n"); con->updateFragmentation (FRAG_FIRST, 0, ch->size()-(HDR_MAC802_16_SIZE+HDR_MAC802_16_FRAGSUB_SIZE)); break; case FRAG_CONT: if ( (con->getFragmentationStatus()!=FRAG_FIRST && con->getFragmentationStatus()!=FRAG_CONT) || ((wimaxHdr->frag_subheader.fsn&0x7) != (con->getFragmentNumber ()+1)%8) ) { frag_error = true; con->updateFragmentation (FRAG_NOFRAG, 0, 0); //reset } else { //printf ("\tReceived cont fragment\n"); con->updateFragmentation (FRAG_CONT, wimaxHdr->frag_subheader.fsn&0x7, con->getFragmentBytes()+ch->size()-(HDR_MAC802_16_SIZE+HDR_MAC802_16_FRAGSUB_SIZE)); } break; case FRAG_LAST: if ( (con->getFragmentationStatus()==FRAG_FIRST || con->getFragmentationStatus()==FRAG_CONT) && ((wimaxHdr->frag_subheader.fsn&0x7) == (con->getFragmentNumber ()+1)%8) ) { //printf ("\tReceived last fragment\n"); ch->size() += con->getFragmentBytes()-HDR_MAC802_16_FRAGSUB_SIZE; drop_pkt = false; } else { //printf ("Error with last frag seq=%d (expected=%d)\n", wimaxHdr->fsn&0x7, (con->getFragmentNumber ()+1)%8); frag_error = true; } con->updateFragmentation (FRAG_NOFRAG, 0, 0); //reset break; default: fprintf (stderr,"Error, unknown fragmentation type\n"); exit (-1); } //if we got an error, or it is a fragment that is not the last, free the packet if (drop_pkt) { if (frag_error) { //update drop stat update_watch (&loss_watch_, 1); drop (pktRx_, "FRG"); //fragmentation error } else { //silently discard this fragment. Packet::free(pktRx_); } pktRx_=NULL; return; } } //We check if it is a MAC packet or not if (HDR_CMN(pktRx_)->ptype()==PT_MAC) { process_mac_packet (pktRx_); update_throughput (&rx_traffic_watch_, 8*ch->size()); mac_log(pktRx_); Packet::free(pktRx_); } else { //only send to upper layer if connected if (state_ == MAC802_16_CONNECTED) { update_throughput (&rx_data_watch_, 8*ch->size()); update_throughput (&rx_traffic_watch_, 8*ch->size()); ch->size() -= HDR_MAC802_16_SIZE; uptarget_->recv(pktRx_, (Handler*) 0); } else { //update drop stat, could be used to detect disconnect update_watch (&loss_watch_, 1); Packet::free(pktRx_); pktRx_=NULL; return; } } update_watch (&loss_watch_, 0); pktRx_=NULL; } /** * Process a MAC packet * @param p The MAC packet received */ void Mac802_16SS::process_mac_packet (Packet *p) { assert (HDR_CMN(p)->ptype()==PT_MAC); debug2 ("SS %d received MAC packet to process\n", addr()); hdr_mac802_16 *wimaxHdr = HDR_MAC802_16(p); gen_mac_header_t header = wimaxHdr->header; if (header.ht == 1) { debug ("SS %d received bandwitdh request packet..don't process\n", addr()); return; } //we cast to this frame because all management frame start with a type mac802_16_dl_map_frame *frame = (mac802_16_dl_map_frame*) p->accessdata(); switch (frame->type) { case MAC_DL_MAP: getMap()->setStarttime (NOW-HDR_CMN(p)->txtime()); //debug("\tat %f in MAC %d set starttime of this map to %f \n", NOW, addr(), NOW-HDR_CMN(p)->txtime()); process_dl_map (frame); break; case MAC_DCD: process_dcd ((mac802_16_dcd_frame*)frame); break; case MAC_UL_MAP: process_ul_map ((mac802_16_ul_map_frame*)frame); break; case MAC_UCD: process_ucd ((mac802_16_ucd_frame*)frame); break; case MAC_RNG_RSP: process_ranging_rsp ((mac802_16_rng_rsp_frame*) frame); break; case MAC_REG_RSP: process_reg_rsp ((mac802_16_reg_rsp_frame*) frame); break; case MAC_DSA_REQ: case MAC_DSA_RSP: case MAC_DSA_ACK: serviceFlowHandler_->process (pktRx_); break; default: debug ("unknown packet in SS %d\n", addr()); //exit (0); } } /** * Process a DL_MAP message * @param frame The dl_map information */ void Mac802_16SS::process_dl_map (mac802_16_dl_map_frame *frame) { assert (frame); //create an entry for the BS if (getPeerNode_head ()==NULL) addPeerNode (new PeerNode (frame->bsid)); /*else if ( getPeerNode_head()->getAddr() != frame->bsid){ PeerNode *peer = getPeerNode_head(); peer->setAddr(frame->bsid); }*/ debug("At %f in %d, received DL-MAP(BSID=%d)\n", NOW, addr(), frame->bsid); getMap()->parseDLMAPframe (frame); if (getMacState()==MAC802_16_WAIT_DL_SYNCH) { assert (t21timer_->busy()!=0); //synchronization is done t21timer_->stop(); //start lost_dl_map //printf("at %f lost DL-MAP timer interval %f. \n", NOW, macmib_.lost_dlmap_interval); lostDLMAPtimer_->start (macmib_.lost_dlmap_interval); //start T1: DCD t1timer_->start (macmib_.t1_timeout); //start T12: UCD t12timer_->start (macmib_.t12_timeout); setMacState(MAC802_16_WAIT_DL_SYNCH_DCD); } else { //maintain synchronization assert (lostDLMAPtimer_->busy()); lostDLMAPtimer_->stop(); //printf ("update dlmap timer\n"); //printf("at %f lost DL-MAP timer interval %f. \n", NOW, macmib_.lost_dlmap_interval); lostDLMAPtimer_->start (macmib_.lost_dlmap_interval); if (getMacState()!= MAC802_16_WAIT_DL_SYNCH_DCD && getMacState()!=MAC802_16_UL_PARAM) { //since the map may have changed, we need to adjust the timer //for the DLSubframe double stime = getMap()->getStarttime(); stime += getMap()->getDlSubframe()->getPdu()->getBurst(1)->getStarttime()*getPhy()->getSymbolTime(); //printf ("received dl..needs to update expiration to %f, %f,%f\n", stime, NOW,getMap()->getStarttime()); //debug("\tat %f in MAC %d, stime = %f, stime-NOW = %f", NOW, addr(), stime, stime-NOW); getMap()->getDlSubframe()->getTimer()->resched (stime-NOW); dl_timer_->resched (getMap()->getStarttime()+getFrameDuration()-NOW); } } } /** * Process a DCD message * @param frame The dcd information */ void Mac802_16SS::process_dcd (mac802_16_dcd_frame *frame) { if (getMacState()==MAC802_16_WAIT_DL_SYNCH) { //we are waiting for DL_MAP, ignore this message return; } getMap()->parseDCDframe (frame); if (getMacState()==MAC802_16_WAIT_DL_SYNCH_DCD) { debug ("At %f in %d, received DCD for synch\n", NOW, addr()); //now I have all information such as frame duration //adjust timing in case the frame we received the DL_MAP //and the DCD is different while (NOW - getMap()->getStarttime () > getFrameDuration()) { getMap()->setStarttime (getMap()->getStarttime()+getFrameDuration()); } setMacState(MAC802_16_UL_PARAM); //we can schedule next frame //printf ("SS schedule next frame at %f\n", getMap()->getStarttime()+getFrameDuration()); //dl_timer_->sched (getMap()->getStarttime()+getFrameDuration()-NOW); } if (t1timer_->busy()!=0) { //we were waiting for this packet t1timer_->stop(); t1timer_->start (macmib_.t1_timeout); } } /** * Process a UCD message * @param frame The ucd information */ void Mac802_16SS::process_ucd (mac802_16_ucd_frame *frame) { if (getMacState()==MAC802_16_WAIT_DL_SYNCH ||getMacState()==MAC802_16_WAIT_DL_SYNCH_DCD) { //discard the packet return; } assert (t12timer_->busy()!=0); //we are waiting for this packet if (getMacState()==MAC802_16_UL_PARAM) { //check if uplink channel usable debug ("At %f in %d, received UL(UCD) parameters\n", NOW, addr()); //start T2: ranging t2timer_->start (macmib_.t2_timeout); //start Lost UL-MAP lostULMAPtimer_->start (macmib_.lost_ulmap_interval); //change state setMacState (MAC802_16_RANGING); } //reset T12 t12timer_->stop(); t12timer_->start (macmib_.t12_timeout); getMap()->parseUCDframe (frame); } /** * Process a UL_MAP message * @param frame The ul_map information */ void Mac802_16SS::process_ul_map (mac802_16_ul_map_frame *frame) { if (getMacState()==MAC802_16_WAIT_DL_SYNCH || getMacState()==MAC802_16_WAIT_DL_SYNCH_DCD) { //discard the packet return; } debug("At %f in %d, received UL-MAP for synch.\n", NOW, addr()); getMap()->parseULMAPframe (frame); if (getMacState()==MAC802_16_RANGING) { //execute ranging assert (t2timer_->busy()!=0); //we are waiting for this packet init_ranging (); } //schedule when to take care of outgoing packets double start = getMap()->getStarttime(); start += getMap()->getUlSubframe()->getStarttime()*getPhy()->getPS(); //offset for ul subframe start -= NOW; //works with relative time not absolute debug2 ("Uplink starts in %f (framestate=%f) %f %f\n", start, getMap()->getStarttime(), getFrameDuration()/getPhy()->getPS(), getFrameDuration()/getPhy()->getSymbolTime()); ul_timer_->resched (start); //reset Lost UL-Map lostULMAPtimer_->stop(); lostULMAPtimer_->start (macmib_.lost_ulmap_interval); } /** * Process a ranging response message * @param frame The ranging response frame */ void Mac802_16SS::process_ranging_rsp (mac802_16_rng_rsp_frame *frame) { debug("At %f in MAC %d receives the RNG-RSP which addr = %d \n", NOW, addr(), frame->ss_mac_address); //check the destination if (frame->ss_mac_address != addr()) return; Connection *basic, *primary; PeerNode *peer; //TBD: add processing for periodic ranging //check status switch (frame->rng_status) { case RNG_SUCCESS: debug ("Ranging response: status = Success.Basic=%d, Primary=%d\n", frame->basic_cid, frame->primary_cid); peer = getPeerNode_head(); assert (peer); getMap()->getUlSubframe()->getRanging()->removeRequest (); //ranging worked, now we must register basic = peer->getBasic(IN_CONNECTION); primary = peer->getPrimary(IN_CONNECTION); if (basic!=NULL && basic->get_cid ()==frame->basic_cid) { //duplicate response assert (primary->get_cid () == frame->primary_cid); } else { if (basic !=NULL) { //we have been allocated new cids..clear old ones getCManager ()->remove_connection (basic->get_cid()); getCManager ()->remove_connection (primary->get_cid()); if (peer->getSecondary(IN_CONNECTION)!=NULL) { getCManager ()->remove_connection (peer->getSecondary(IN_CONNECTION)); getCManager ()->remove_connection (peer->getSecondary(OUT_CONNECTION)); } if (peer->getOutData()!=NULL) getCManager ()->remove_connection (peer->getOutData()); if (peer->getInData()!=NULL) getCManager ()->remove_connection (peer->getInData()); } basic = new Connection (CONN_BASIC, frame->basic_cid); Connection *upbasic = new Connection (CONN_BASIC, frame->basic_cid); primary = new Connection (CONN_PRIMARY, frame->primary_cid); Connection *upprimary = new Connection (CONN_PRIMARY, frame->primary_cid); //a SS should only have one peer, the BS peer->setBasic (basic, upbasic); //set outgoing peer->setPrimary (primary, upprimary); //set outgoing getCManager()->add_connection (upbasic, OUT_CONNECTION); getCManager()->add_connection (basic, IN_CONNECTION); getCManager()->add_connection (upprimary, OUT_CONNECTION); getCManager()->add_connection (primary, IN_CONNECTION); } //registration must be sent using Primary Management CID setMacState (MAC802_16_REGISTER); //stop timeout timer t2timer_->stop (); nb_reg_retry_ = 0; //first time sending send_registration(); break; case RNG_ABORT: case RNG_CONTINUE: case RNG_RERANGE: break; default: fprintf (stderr, "Unknown status reply\n"); exit (-1); } } /** * Schedule a ranging */ void Mac802_16SS::init_ranging () { //check if there is a ranging opportunity UlSubFrame *ulsubframe = getMap()->getUlSubframe(); DlSubFrame *dlsubframe = getMap()->getDlSubframe(); //check if there is Fast Ranging IE for (PhyPdu *p = getMap()->getUlSubframe ()->getFirstPdu(); p ; p= p ->next_entry()) { UlBurst *b = (UlBurst*) p->getBurst(0); if (b->getIUC() == UIUC_EXT_UIUC && b->getExtendedUIUC ()== UIUC_FAST_RANGING && b->getFastRangingMacAddr ()==addr()) { debug2 ("Found fast ranging\n"); //we should put the ranging request in that burst Packet *p= getPacket(); hdr_cmn* ch = HDR_CMN(p); HDR_MAC802_16(p)->header.cid = INITIAL_RANGING_CID; p->allocdata (sizeof (struct mac802_16_rng_req_frame)); mac802_16_rng_req_frame *frame = (mac802_16_rng_req_frame*) p->accessdata(); frame->type = MAC_RNG_REQ; frame->ms_rng_indicator = 0; frame->ss_mac_address = addr(); //other elements?? frame->req_dl_burst_profile = default_diuc_ & 0xF; //we use lower bits only ch->size() += RNG_REQ_SIZE; //compute when to send message double txtime = getPhy()->getTrxTime (ch->size(), ulsubframe->getProfile (b->getFastRangingUIUC ())->getEncoding()); ch->txtime() = txtime; //starttime+backoff ch->timestamp() = NOW; //add timestamp since it bypasses the queue b->enqueue(p); setMacState(MAC802_16_WAIT_RNG_RSP); return; } } for (PhyPdu *pdu = ulsubframe->getFirstPdu(); pdu ; pdu = pdu->next_entry()) { if (pdu->getBurst(0)->getIUC()==UIUC_INITIAL_RANGING) { debug ("At %f SS Mac %d found ranging opportunity\n", NOW, addr()); Packet *p= getPacket(); hdr_cmn* ch = HDR_CMN(p); HDR_MAC802_16(p)->header.cid = INITIAL_RANGING_CID; p->allocdata (sizeof (struct mac802_16_rng_req_frame)); mac802_16_rng_req_frame *frame = (mac802_16_rng_req_frame*) p->accessdata(); frame->type = MAC_RNG_REQ; frame->ms_rng_indicator = 0; frame->ss_mac_address = addr(); //other elements?? frame->req_dl_burst_profile = default_diuc_ & 0xF; //we use lower bits only ch->size() += RNG_REQ_SIZE; //compute when to send message double txtime = getPhy()->getTrxTime (ch->size(), ulsubframe->getProfile (pdu->getBurst(0)->getIUC())->getEncoding()); ch->txtime() = txtime; //starttime+backoff getMap()->getUlSubframe()->getRanging()->addRequest (p); setMacState(MAC802_16_WAIT_RNG_RSP); return; } } } /** * Prepare to send a registration message */ void Mac802_16SS::send_registration () { debug("at %f in MAC %d send registration message\n", NOW, addr()); Packet *p; struct hdr_cmn *ch; hdr_mac802_16 *wimaxHdr; mac802_16_reg_req_frame *reg_frame; PeerNode *peer; //create packet for request p = getPacket (); ch = HDR_CMN(p); wimaxHdr = HDR_MAC802_16(p); p->allocdata (sizeof (struct mac802_16_reg_req_frame)); reg_frame = (mac802_16_reg_req_frame*) p->accessdata(); reg_frame->type = MAC_REG_REQ; ch->size() += REG_REQ_SIZE; peer = getPeerNode_head(); wimaxHdr->header.cid = peer->getPrimary(OUT_CONNECTION)->get_cid(); peer->getPrimary(OUT_CONNECTION)->enqueue (p); //start reg timeout if (t6timer_==NULL) { t6timer_ = new WimaxT6Timer (this); } t6timer_->start (macmib_.t6_timeout); nb_reg_retry_++; } /** * Process a registration response message * @param frame The registration response frame */ void Mac802_16SS::process_reg_rsp (mac802_16_reg_rsp_frame *frame) { //check the destination PeerNode *peer = getPeerNode_head(); if (frame->response == 0) { //status OK debug ("At %f in Mac %d, registration sucessful (nbretry=%d)\n", NOW, addr(), nb_reg_retry_); Connection *secondary = peer->getSecondary(IN_CONNECTION); if (!secondary) { Connection *secondary = new Connection (CONN_SECONDARY, frame->sec_mngmt_cid); Connection *upsecondary = new Connection (CONN_SECONDARY, frame->sec_mngmt_cid); getCManager()->add_connection (upsecondary, OUT_CONNECTION); getCManager()->add_connection (secondary, IN_CONNECTION); peer->setSecondary (secondary, upsecondary); } //cancel timeout t6timer_->stop (); //update status setMacState(MAC802_16_CONNECTED); //we need to setup a data connection (will be moved to service flow handler) getServiceHandler ()->sendFlowRequest (peer->getAddr(), OUT_CONNECTION); getServiceHandler ()->sendFlowRequest (peer->getAddr(), IN_CONNECTION); } else { //status failure debug ("At %f in Mac %d, registration failed (nbretry=%d)\n", NOW, addr(), nb_reg_retry_); if (nb_reg_retry_ == macmib_.reg_req_retry) { lost_synch (); } else { send_registration(); } } } /** * Update the given timer and check if thresholds are crossed * @param watch the stat watch to update * @param value the stat value */ void Mac802_16SS::update_watch (StatWatch *watch, double value) { char *name; watch->update (value); if (watch == &loss_watch_) { name = "loss"; } else if (watch == &delay_watch_) { name = "delay"; } else if (watch == &jitter_watch_) { name = "jitter"; } else { name = "other"; } if (print_stats_) printf ("At %f in Mac %d, updating stats %s: %f\n", NOW, addr(), name, watch->average()); } /** * Update the given timer and check if thresholds are crossed * @param watch the stat watch to update * @param value the stat value */ void Mac802_16SS::update_throughput (ThroughputWatch *watch, double size) { char *name; watch->update (size, NOW); if (watch == &rx_data_watch_) { name = "rx_data"; rx_data_timer_->resched (watch->get_timer_interval()); //printf ("At %f in SS(%d), %s = %f\n", NOW, addr(), name, watch->average()); } else if (watch == &rx_traffic_watch_) { rx_traffic_timer_->resched (watch->get_timer_interval()); name = "rx_traffic"; } else if (watch == &tx_data_watch_) { tx_data_timer_->resched (watch->get_timer_interval()); name = "tx_data"; } else if (watch == &tx_traffic_watch_) { tx_traffic_timer_->resched (watch->get_timer_interval()); name = "tx_traffic"; } if (print_stats_) printf ("At %f in Mac %d, updating stats %s: %f\n", NOW, addr(), name, watch->average()); } /** * Start a new frame */ void Mac802_16SS::start_dlsubframe () { // modified by polar //debug ("At %f in Mac %d SS scheduler dlsubframe expires \n", NOW, addr()); frame_number_++; //this is the begining of new frame map_->setStarttime (NOW); //start handler of dlsubframe map_->getDlSubframe()->getTimer()->sched (0); //reschedule for next frame dl_timer_->resched (getFrameDuration()); } /** * Start a new frame */ void Mac802_16SS::start_ulsubframe () { //debug ("At %f in Mac %d SS scheduler ulsubframe expires\n", NOW, addr()); //change state of PHY: even though it should have been done before //there are some cases where it does not (during scanning) getPhy()->setMode (OFDM_SEND); scheduler_->schedule(); //start handler for ulsubframe if (getMap()->getUlSubframe()->getNbPdu ()>0) { Burst *b = getMap()->getUlSubframe()->getPhyPdu (0)->getBurst (0); getMap()->getUlSubframe()->getTimer()->sched (b->getStarttime()*getPhy()->getSymbolTime()); }//else there is no uplink phy pdu defined //reschedule for next frame ul_timer_->resched (getFrameDuration()); } /** * Called when lost synchronization */ void Mac802_16SS::lost_synch () { //printf("Lost synch. of Timer at %f.\n", NOW); //reset timers if (t1timer_->busy()!=0) t1timer_->stop(); if (t12timer_->busy()!=0) t12timer_->stop(); if (t21timer_->busy()!=0) t21timer_->stop(); if (lostDLMAPtimer_->busy()!=0) lostDLMAPtimer_->stop(); if (lostULMAPtimer_->busy()!=0) lostULMAPtimer_->stop(); if (t2timer_->busy()!=0) t2timer_->stop(); if (t44timer_ && t44timer_->busy()!=0) t44timer_->stop(); //we need to go to receiving mode //printf ("Set phy to recv %x\n", getPhy()); getPhy()->setMode (OFDM_RECV); if (getMacState()==MAC802_16_CONNECTED) { //remove possible pending requests map_->getUlSubframe()->getBw_req()->removeRequests(); } //remove information about peer node if (getPeerNode_head()) removePeerNode (getPeerNode_head()); //start waiting for DL synch setMacState (MAC802_16_WAIT_DL_SYNCH); t21timer_->start (macmib_.t21_timeout); if (dl_timer_->status()==TIMER_PENDING) dl_timer_->cancel(); map_->getDlSubframe()->getTimer()->reset(); if (ul_timer_->status()==TIMER_PENDING) ul_timer_->cancel(); map_->getUlSubframe()->getTimer()->reset(); } /** * Set the scan flag to true/false * param flag The value for the scan flag */ void Mac802_16SS::setScanFlag(bool flag) { scan_flag_ = flag; } /** * return scan flag * @return the scan flag */ bool Mac802_16SS::isScanRunning() { return scan_flag_; }
* We would appreciate acknowledgement if the software is used. *
* NIST ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND * DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING * FROM THE USE OF THIS SOFTWARE. *