www.pudn.com > 802.16jModule.rar > mac802_16BS.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.
 * 
* 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. *

* @author rouil */ #include "mac802_16BS.h" #include "scheduling/bsscheduler.h" #include "destclassifier.h" /** * TCL Hooks for the simulator for wimax mac */ static class Mac802_16BSClass : public TclClass { public: Mac802_16BSClass() : TclClass("Mac/802_16/BS") {} TclObject* create(int, const char*const*) { return (new Mac802_16BS()); } } class_mac802_16BS; /** * Creates a Mac 802.16 */ Mac802_16BS::Mac802_16BS() : Mac802_16 (), cl_head_(0), cl_tail_(0), ctrlagent_(0) { type_ = STA_BS; //type of MAC. In this case it is for SS //Default configuration addClassifier (new DestClassifier ()); Tcl& tcl = Tcl::instance(); tcl.evalf ("new WimaxScheduler/BS"); scheduler_ = (WimaxScheduler*) TclObject::lookup(tcl.result()); scheduler_->setMac (this); //register the mac init_default_connections (); LIST_INIT (&t17_head_); LIST_INIT (&scan_stations_); LIST_INIT (&fast_ranging_head_); bw_peer_ = NULL; bw_node_index_ = 0; sendDCD = false; dlccc_ = 0; sendUCD = false; ulccc_ = 0; sendR_DCD = false; sendR_UCD = false; map_ = new FrameMap (this); //create timers for DL/UL boundaries dl_timer_ = new DlTimer (this); ul_timer_ = new UlTimer (this); //create timer for DL/UL relay boundaries dl_relay_timer_ = new DlRelayTimer (this); ul_relay_timer_ = new UlRelayTimer (this); } /* * Interface with the TCL script * @param argc The number of parameter * @param argv The list of parameters */ int Mac802_16BS::command(int argc, const char*const* argv) { return Mac802_16::command(argc, argv); } /** * Initialize default connections */ void Mac802_16BS::init_default_connections () { Connection * con; //create initial ranging and padding connection con = new Connection (CONN_INIT_RANGING); connectionManager_->add_connection (con, IN_CONNECTION); //uplink con = new Connection (CONN_INIT_RANGING); connectionManager_->add_connection (con, OUT_CONNECTION); //downlink con = new Connection (CONN_PADDING); connectionManager_->add_connection (con, IN_CONNECTION); con = new Connection (CONN_PADDING); connectionManager_->add_connection (con, OUT_CONNECTION); //we need to create a Broadcast connection and AAS init ranging CIDs con = new Connection (CONN_BROADCAST); connectionManager_->add_connection (con, OUT_CONNECTION); con = new Connection (CONN_RELAY_BROADCAST); connectionManager_->add_connection (con, OUT_CONNECTION); con = new Connection (CONN_AAS_INIT_RANGING); connectionManager_->add_connection (con, IN_CONNECTION); } /** * Initialize the MAC */ void Mac802_16BS::init () { //init the scheduler scheduler_->init(); //schedule the first frame by using a random backoff to avoid //synchronization between BSs. // double stime = getFrameDuration () + Random::uniform(0, getFrameDuration ()); double stime = getFrameDuration (); dl_timer_->sched (stime); //also start the DCD and UCD timer dcdtimer_ = new WimaxDCDTimer (this); ucdtimer_ = new WimaxUCDTimer (this); nbradvtimer_ = new WimaxMobNbrAdvTimer (this); dcdtimer_->start (macmib_.dcd_interval); ucdtimer_->start (macmib_.ucd_interval); nbradvtimer_->start (macmib_.nbr_adv_interval+stime); } /** * Set the control agent */ void Mac802_16BS::setCtrlAgent (WimaxCtrlAgent *agent) { assert (agent); ctrlagent_ = agent; } /**** Packet processing methods ****/ /* * Process packets going out * @param p The packet to send out */ void Mac802_16BS::sendDown(Packet *p) { #ifdef DEBUG_WIMAX debug("at %f BS 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("\tBS send ARP which macDA=%d and CID=%d \n", HDR_MAC(p)->macDA(), classify(p)); getchar(); } else { if (strcmp("cbr", packet_info.name(HDR_CMN(p)->ptype()))==0){ int cidd = -1; cidd = classify(p); debug ("BS send the message(type=%s) which CID = %d\n",packet_info.name(HDR_CMN(p)->ptype()), cidd); } } #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) { debug ("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); // the broadcasted message needs to be transmitd to STA_RS if (cid == BROADCAST_CID){ debug("BROADCAST CID = %d", BROADCAST_CID); // copy the packet Packet *cp = p->copy(); wimaxHdr = HDR_MAC802_16(cp); wimaxHdr->header.cid = RELAY_BROADCAST_CID; connection = getCManager()->get_connection(RELAY_BROADCAST_CID, OUT_CONNECTION); if (connection != NULL){ connection->enqueue(cp); debug("\tBS insert the brocasted message into the RELAY_BROADCAST_CID's queue\n"); } } //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_16BS::transmit(Packet *p) { #ifdef DEBUG_WIMAX debug("at %f BS 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){ mac802_16_dl_map_frame *frame = (mac802_16_dl_map_frame *) p->accessdata(); if (frame->type == MAC_REG_RSP){ debug("BS transmit the message which type = %d\n", frame->type); getchar(); } } else debug ("bwreq\n"); } else { debug ("BS transmit the message which CID = %d\n", HDR_MAC802_16(p)->header.cid); } #endif if (NOW < last_tx_time_+last_tx_duration_) { //still sending printf ("At %f in Mac %d is already transmitting (endTX=%.9f). Drop packet.\n", NOW, addr(),last_tx_time_+last_tx_duration_); Packet::free (p); return; } struct hdr_cmn *ch = HDR_CMN(p); //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_16BS::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 == 1 && HDR_MAC802_16(p)->header.ec == 1) { //debug ("mngt=%d\n", ((mac802_16_dl_map_frame*) p->accessdata())->type); printf("\tBS receives a packet that ht=1 and ec=1\n"); } else debug ("bwreq\n"); } else if (ch->ptype() == PT_ARP) { debug("\tBS receive a ARP message \n"); } else { debug ("BS 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_16BS::receive () { assert (pktRx_); struct hdr_cmn *ch = HDR_CMN(pktRx_); #ifdef DEBUG_WIMAX debug ("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 == 1 && HDR_MAC802_16(pktRx_)->header.ec == 1) { printf("\tBS receives a header (ht=1, ec=1)\n"); //debug ("mngt=%d\n", ((mac802_16_dl_map_frame*) pktRx_->accessdata())->type); } else debug ("bwreq\n"); } else { debug ("\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; } //update rx time of last packet received PeerNode *peer; if (type_ == STA_MN) peer = getPeerNode_head(); //MN only has one peer else peer = con->getPeerNode(); //BS can have multiple peers 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_)) { if (peer->getPrimary(IN_CONNECTION)!=NULL) { //check if node registered 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\n",wimaxHdr->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; } } //check if this is a bandwidth request if ((header.ht == 0 || (header.ht==1 && header.ec==1)) && con->getBw() >0) { debug2 ("At %f Connection %d, old=%d, rcv=%d, left=%d\n", NOW, con->get_cid(), con->getBw(), ch->size(), con->getBw()-ch->size()); con->setBw(con->getBw()-ch->size()); } //We check if it is a MAC packet or not if (HDR_CMN(pktRx_)->ptype()==PT_MAC) { process_mac_packet (con, pktRx_); update_throughput (&rx_traffic_watch_, 8*ch->size()); mac_log(pktRx_); Packet::free(pktRx_); } else { 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); } update_watch (&loss_watch_, 0); pktRx_=NULL; } /** * Process a packet received by the Mac. Only scheduling related packets should be sent here (BW request, UL_MAP...) * @param con The connection by which it arrived * @param p The packet to process */ void Mac802_16BS::process_mac_packet (Connection *con, Packet * p) { //debug2 ("Mac802_16BS received packet to process\n"); assert (HDR_CMN(p)->ptype()==PT_MAC); debug2 ("Mac802_16BS received packet to process\n"); hdr_mac802_16 *wimaxHdr = HDR_MAC802_16(p); gen_mac_header_t header = wimaxHdr->header; if (header.ht == 0 && header.esf == 1) { //check if this header has extended subheader field process_ext_subheader(con, pktRx_); return; } else if (header.ht == 1 && header.ec == 0) { // Signaling header type I //check if this is a bandwidth request process_bw_req (p); return; } else if (header.ht == 1 && header.ec == 1) { // Signaling header type II process_header_typeII(con, p); 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_RNG_REQ: process_ranging_req (p); break; case MAC_REG_REQ: process_reg_req (p); break; case MAC_MOB_SCN_REQ: if (ctrlagent_) ctrlagent_->process_scan_request (p); else fprintf (stderr, "Warning: no controler to handle scan request in BS %d\n", addr()); break; case MAC_MOB_MSHO_REQ: process_msho_req (p); break; case MAC_MOB_HO_IND: process_ho_ind (p); break; case MAC_DSA_REQ: case MAC_DSA_RSP: case MAC_DSA_ACK: serviceFlowHandler_->process (pktRx_); break; default: debug ("unknown packet in BS\n"); } //Packet::free (p); } /** * Process a signal header type II * @param con The connection by which it arrived * @param p The packet to process */ void Mac802_16BS::process_header_typeII (Connection *con, Packet *p) { printf ("\tprocess header typeII\n"); hdr_mac802_16 *wimaxHdr = HDR_MAC802_16(p); dl_flow_control_header_t *header = (dl_flow_control_header_t *)&(wimaxHdr->header); switch (header->extended_type){ case 7: printf("\tcredit = %d\n", header->credit); ((BSScheduler*)scheduler_)->setDlCredit(header->credit); break; } } /** * Process a extended subheader field * @param con The connection by which it arrived * @param p The packet to process */ void Mac802_16BS::process_ext_subheader (Connection *con, Packet *p) { hdr_cmn *ch = HDR_CMN(p); hdr_mac802_16 *wimaxHdr = HDR_MAC802_16(p); esf_con_state *esf = (esf_con_state *)&wimaxHdr->esf_con_subheader; switch (esf->esf_type){ case CONGESTION_AWARE: process_esf_congestion(p); break; default: debug ("\tunknown subheader type\n"); break; } } /** * Process a extended subheader field for congestion-aware mechanism * @param con The connection by which it arrived * @param p The packet to process */ void Mac802_16BS::process_esf_congestion (Packet *p) { debug("\tCONGESTION_AWARE\n"); hdr_cmn *ch = HDR_CMN(p); hdr_mac802_16 *wimaxHdr = HDR_MAC802_16(p); switch (wimaxHdr->esf_con_subheader.con_state){ case NORMAL: debug("\tNORMAL\n"); break; case PRE_CONGESTION: debug("\tPRE_CONGESTION\n"); break; case CONGESTION: debug("\tCONGESTION\n"); break; default: break; } } /** * Process a RNG-REQ message * @param p The packet containing the ranging request information */ void Mac802_16BS::process_ranging_req (Packet *p) { int cid = HDR_MAC802_16(p)->header.cid; mac802_16_rng_req_frame *req = (mac802_16_rng_req_frame *) p->accessdata(); debug ("\tBS process RNG-REQ for node(%d) which cid is %d\n", req->ss_mac_address, cid); if (cid != getCManager()->get_connection(cid, IN_CONNECTION)->get_cid()) { //if (cid != INITIAL_RANGING_CID) { } else { //here we can make decision to accept the SS or not. //for now, accept everybody //check if CID already assigned for the SS PeerNode *peer = getPeerNode (req->ss_mac_address); if (peer==NULL) { debug ("In MAC %d, new peer node requesting ranging (%d)\n", addr(), req->ss_mac_address); //Assign Management CIDs Connection *basic = new Connection (CONN_BASIC); Connection *upbasic = new Connection (CONN_BASIC, basic->get_cid()); Connection *primary = new Connection (CONN_PRIMARY); Connection *upprimary = new Connection (CONN_PRIMARY, primary->get_cid()); //Create Peer information peer = new PeerNode (req->ss_mac_address); peer->setBasic (upbasic, basic); peer->setPrimary (upprimary, primary); peer->setDIUC (req->req_dl_burst_profile); peer->setDefaultDIUC(req->req_dl_burst_profile); // set the type of this peer node if (getRelayStatus()==RELAY_ZONE){ if (req->ms_rng_indicator == 1) peer->setMacType(STA_MN); else peer->setMacType(STA_RS); // set the connections to RELAY_LINK basic->setLinkType(RELAY_LINK); upbasic->setLinkType(RELAY_LINK); primary->setLinkType(RELAY_LINK); upprimary->setLinkType(RELAY_LINK); } else { peer->setMacType(STA_MN); //set the connections to ACCESS_LINK basic->setLinkType(ACCESS_LINK); upbasic->setLinkType(ACCESS_LINK); primary->setLinkType(ACCESS_LINK); upprimary->setLinkType(ACCESS_LINK); } addPeerNode (peer); getCManager()->add_connection (upbasic, IN_CONNECTION); getCManager()->add_connection (basic, OUT_CONNECTION); getCManager()->add_connection (upprimary, IN_CONNECTION); getCManager()->add_connection (primary, OUT_CONNECTION); //schedule timer in case the node never register addtimer17 (req->ss_mac_address); //create packet for answers Packet *rep = getPacket (); struct hdr_cmn *ch = HDR_CMN(rep); hdr_mac802_16 *wimaxHdr = HDR_MAC802_16(rep); if (getRelayStatus() == RELAY_ZONE){ if (req->ms_rng_indicator == 1) wimaxHdr->header.cid = cid; // using RS's basic CID else wimaxHdr->header.cid = RELAY_BROADCAST_CID; } else { wimaxHdr->header.cid = BROADCAST_CID; } rep->allocdata (sizeof (struct mac802_16_rng_rsp_frame)); mac802_16_rng_rsp_frame *frame = (mac802_16_rng_rsp_frame*) rep->accessdata(); frame->type = MAC_RNG_RSP; frame->rng_status = RNG_SUCCESS; frame->ss_mac_address = req->ss_mac_address; frame->basic_cid = basic->get_cid(); frame->primary_cid = primary->get_cid(); frame->ms_rng_indicator = req->ms_rng_indicator; ch->size() = RNG_RSP_SIZE; //enqueue packet if (getRelayStatus()==RELAY_ZONE){ getCManager()->get_connection (RELAY_BROADCAST_CID, OUT_CONNECTION)->enqueue (rep); } else { getCManager()->get_connection (BROADCAST_CID, OUT_CONNECTION)->enqueue (rep); } if (cl_head_==NULL) { cl_head_ = (new_client_t*)malloc (sizeof (new_client_t)); cl_tail_ = cl_head_; } else { cl_tail_->next = (new_client_t*)malloc (sizeof (new_client_t)); cl_tail_=cl_tail_->next; } cl_tail_->cid = primary->get_cid(); cl_tail_->next = NULL; } else { debug ("Received ranging for known station (%d)\n", req->ss_mac_address); //reset invited ranging retries for SS //create packet for answers Connection *basic = peer->getBasic(IN_CONNECTION); Connection *primary = peer->getPrimary(IN_CONNECTION); Packet *rep = getPacket (); struct hdr_cmn *ch = HDR_CMN(rep); hdr_mac802_16 *wimaxHdr = HDR_MAC802_16(rep); if (getRelayStatus() == RELAY_ZONE){ if (req->ms_rng_indicator == 1) wimaxHdr->header.cid = cid; // using RS's basic CID else wimaxHdr->header.cid = RELAY_BROADCAST_CID; } else { wimaxHdr->header.cid = BROADCAST_CID; } rep->allocdata (sizeof (struct mac802_16_rng_rsp_frame)); mac802_16_rng_rsp_frame *frame = (mac802_16_rng_rsp_frame*) rep->accessdata(); frame->type = MAC_RNG_RSP; frame->rng_status = RNG_SUCCESS; frame->ss_mac_address = req->ss_mac_address; frame->basic_cid = basic->get_cid(); frame->primary_cid = primary->get_cid(); frame->ms_rng_indicator = req->ms_rng_indicator; ch->size() = RNG_RSP_SIZE; //enqueue packet if (getRelayStatus()==RELAY_ZONE){ getCManager()->get_connection (RELAY_BROADCAST_CID, OUT_CONNECTION)->enqueue (rep); } else { getCManager()->get_connection (BROADCAST_CID, OUT_CONNECTION)->enqueue (rep); } } } } /** * Process bandwidth request * @param p The request */ void Mac802_16BS::process_bw_req (Packet *p) { hdr_mac802_16 *wimaxHdr = HDR_MAC802_16(p); gen_mac_header_t header = wimaxHdr->header; bw_req_header_t *req; req = (bw_req_header_t *)&header; debug ("at %f received bandwidth request of %d bytes from %d\n", NOW, req->br, req->cid); //retrieve the CID and update bandwidth request information Connection *c = getCManager()->get_connection (req->cid, IN_CONNECTION); assert (c); if ( (req->type & 0x7) == 0x001) { //aggregate c->setBw (req->br & 0x7FFFF); //masks 19 bits debug2 ("Aggregate request on connection %d of %d\n", c->get_cid(), c->getBw()); } else if ( (req->type & 0x7) == 0x000) { //incremental c->setBw (c->getBw() + (req->br & 0x7FFFF)); } } /** * Process registration request * @param p The request */ void Mac802_16BS::process_reg_req (Packet *req) { hdr_mac802_16 *wimaxHdr_req = HDR_MAC802_16(req); gen_mac_header_t header_req = wimaxHdr_req->header; debug ("at %f BS received registration request from %d\n", NOW, header_req.cid); Packet *p; struct hdr_cmn *ch; hdr_mac802_16 *wimaxHdr; mac802_16_reg_rsp_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_rsp_frame)); reg_frame = (mac802_16_reg_rsp_frame*) p->accessdata(); reg_frame->type = MAC_REG_RSP; reg_frame->response = 0; //OK peer = getCManager()->get_connection (header_req.cid, IN_CONNECTION)->getPeerNode(); Connection *secondary = peer->getSecondary (OUT_CONNECTION); if (secondary==NULL) { //first time secondary = new Connection (CONN_SECONDARY); Connection *upsecondary = new Connection (CONN_SECONDARY, secondary->get_cid()); // set the link type according to the Peernode's type if (getRelayStatus() == RELAY_ZONE){ secondary->setLinkType(RELAY_LINK); upsecondary->setLinkType(RELAY_LINK); } else { secondary->setLinkType(ACCESS_LINK); upsecondary->setLinkType(RELAY_LINK); } getCManager()->add_connection (upsecondary, IN_CONNECTION); getCManager()->add_connection (secondary, OUT_CONNECTION); peer->setSecondary (upsecondary, secondary); } reg_frame->sec_mngmt_cid = secondary->get_cid(); wimaxHdr->header.cid = header_req.cid; ch->size() = REG_RSP_SIZE; //enqueue packet..must be replaced with second line later //getCManager()->get_connection (BROADCAST_CID, OUT_CONNECTION)->enqueue (p); peer->getPrimary(OUT_CONNECTION)->enqueue (p); //clear t17 timer for this node removetimer17 (peer->getAddr()); } /** * Send a neighbor advertisement message */ void Mac802_16BS::send_nbr_adv () { debug ("At %f in BS %d send_nbr_adv (nb_neighbor=%d)\n", NOW, addr(), nbr_db_->getNbNeighbor()); Packet *p; struct hdr_cmn *ch; hdr_mac802_16 *wimaxHdr; mac802_16_mob_nbr_adv_frame *frame; //PeerNode *peer; //create packet for request p = getPacket (); ch = HDR_CMN(p); wimaxHdr = HDR_MAC802_16(p); p->allocdata (sizeof (struct mac802_16_mob_nbr_adv_frame)); frame = (mac802_16_mob_nbr_adv_frame*) p->accessdata(); frame->type = MAC_MOB_NBR_ADV; frame->n_neighbors = nbr_db_->getNbNeighbor(); frame->skip_opt_field = 0; for (int i = 0 ; i < frame->n_neighbors ; i++) { frame->nbr_info[i].phy_profile_id.FAindex = 0; frame->nbr_info[i].phy_profile_id.bs_eirp = 0; frame->nbr_info[i].nbr_bsid= nbr_db_->getNeighbors()[i]->getID(); frame->nbr_info[i].dcd_included = true; memcpy (&(frame->nbr_info[i].dcd_settings), nbr_db_->getNeighbors ()[i]->getDCD(), sizeof(mac802_16_dcd_frame)); frame->nbr_info[i].ucd_included = true; memcpy (&(frame->nbr_info[i].ucd_settings), nbr_db_->getNeighbors ()[i]->getUCD(), sizeof(mac802_16_ucd_frame)); frame->nbr_info[i].phy_included = false; } ch->size() = Mac802_16pkt::getMOB_NBR_ADV_size(frame); getCManager()->get_connection (BROADCAST_CID, OUT_CONNECTION)->enqueue (p); } /** * Process handover request * @param p The request */ void Mac802_16BS::process_msho_req (Packet *req) { hdr_mac802_16 *wimaxHdr_req = HDR_MAC802_16(req); gen_mac_header_t header_req = wimaxHdr_req->header; mac802_16_mob_msho_req_frame *req_frame = (mac802_16_mob_msho_req_frame*) req->accessdata(); debug ("At %f in Mac %d received handover request from %d\n", NOW, addr(), header_req.cid); //check the BS that has stronger power int maxIndex = 0; int maxRssi = 0; //max value for (int i = 0; i < req_frame->n_new_bs_full ; i++) { if (req_frame->bs_full[i].bs_rssi_mean >= maxRssi) { maxIndex = i; maxRssi = req_frame->bs_full[i].bs_rssi_mean; } } //reply with one recommended BS Packet *p; struct hdr_cmn *ch; hdr_mac802_16 *wimaxHdr; mac802_16_mob_bsho_rsp_frame *rsp_frame; send_nbr_adv (); //to force update with latest information //create packet for request p = getPacket (); ch = HDR_CMN(p); wimaxHdr = HDR_MAC802_16(p); p->allocdata (sizeof (struct mac802_16_mob_bsho_rsp_frame)+sizeof (mac802_16_mob_bsho_rsp_rec)); rsp_frame = (mac802_16_mob_bsho_rsp_frame*) p->accessdata(); rsp_frame->type = MAC_MOB_BSHO_RSP; rsp_frame->mode = 0; //HO request rsp_frame->ho_operation_mode = 1; //mandatory handover response rsp_frame->n_recommended = 1; rsp_frame->resource_retain_flag = 0; //release connection information rsp_frame->n_rec[0].neighbor_bsid = req_frame->bs_full[maxIndex].neighbor_bs_index; rsp_frame->n_rec[0].ho_process_optimization=0; //no optimization ch->size() += Mac802_16pkt::getMOB_BSHO_RSP_size(rsp_frame); wimaxHdr->header.cid = header_req.cid; getCManager()->get_connection (header_req.cid, OUT_CONNECTION)->enqueue (p); } /** * Process handover indication * @param p The indication */ void Mac802_16BS::process_ho_ind (Packet *p) { hdr_mac802_16 *wimaxHdr_req = HDR_MAC802_16(p); gen_mac_header_t header_req = wimaxHdr_req->header; //mac802_16_mob_ho_ind_frame *req_frame = // (mac802_16_mob_ho_ind_frame*) p->accessdata(); debug ("At %f in Mac %d received handover indication from %d\n", NOW, addr(), header_req.cid); } /** * Send a scan response to the MN * @param rsp The response from the control */ void Mac802_16BS::send_scan_response (mac802_16_mob_scn_rsp_frame *rsp, int cid) { //create packet for request Packet *p = getPacket (); struct hdr_cmn *ch = HDR_CMN(p); hdr_mac802_16 *wimaxHdr = HDR_MAC802_16(p); p->allocdata (sizeof (struct mac802_16_mob_scn_rsp_frame)); mac802_16_mob_scn_rsp_frame* rsp_frame = (mac802_16_mob_scn_rsp_frame*) p->accessdata(); memcpy (rsp_frame, rsp, sizeof (mac802_16_mob_scn_rsp_frame)); rsp_frame->type = MAC_MOB_SCN_RSP; wimaxHdr->header.cid = cid; ch->size() += Mac802_16pkt::getMOB_SCN_RSP_size(rsp_frame); //add scanning station to the list PeerNode *peer = getCManager()->get_connection (cid, false)->getPeerNode(); /* The request is received in frame i, the reply is sent in frame i+1 * so the frame at which the scanning start is start_frame+2 */ ScanningStation *sta = new ScanningStation (peer->getAddr(), rsp_frame->scan_duration & 0xFF, rsp_frame->start_frame+frame_number_+2, rsp_frame->interleaving_interval & 0xFF, rsp_frame->scan_iteration & 0xFF); sta->insert_entry_head (&scan_stations_); //enqueue packet getCManager()->get_connection (cid, OUT_CONNECTION)->enqueue (p); } /**** Internal methods ****/ /** * Update the given timer and check if thresholds are crossed * @param watch the stat watch to update * @param value the stat value */ void Mac802_16BS::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_16BS::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()); } 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()); } /** * Called when a timer expires * @param The timer ID */ void Mac802_16BS::expire (timer_id id) { switch (id) { case WimaxDCDTimerID: sendDCD = true; //sendR_DCD = true; debug ("At %f in Mac %d DCDtimer expired\n", NOW, addr()); dcdtimer_->start (macmib_.dcd_interval); break; case WimaxUCDTimerID: sendUCD = true; //sendR_UCD = true; debug ("At %f in Mac %d UCDtimer expired\n", NOW, addr()); ucdtimer_->start (macmib_.ucd_interval); break; case WimaxMobNbrAdvTimerID: send_nbr_adv(); nbradvtimer_->start (macmib_.nbr_adv_interval); break; default: debug ("Warning: unknown timer expired in Mac802_16BS\n"); } } /** * Start a new frame */ void Mac802_16BS::start_ulsubframe () { start_ul_accesszone(); } /** * Start a new frame */ void Mac802_16BS::start_dlsubframe () { start_dl_accesszone(); } /** * Start a new access zone of DL subframe */ void Mac802_16BS::start_dl_accesszone() { debug ("At %f in Mac %d BS scheduler dl access zone expires (frame=%d)\n", NOW, addr(), frame_number_++); setRelayStatus(ACCESS_ZONE); assert (map_); map_->setStarttime(NOW); ((BSScheduler*)scheduler_)->schedule(); //update some information if (sendDCD || map_->getDlSubframe()->getCCC()!= dlccc_) { sendDCD = false; dlccc_ = map_->getDlSubframe()->getCCC(); //reschedule timer dcdtimer_->stop(); dcdtimer_->start (macmib_.dcd_interval); } if (sendUCD || map_->getUlSubframe()->getCCC()!= ulccc_) { sendUCD = false; ulccc_ = map_->getUlSubframe()->getCCC(); //reschedule timer ucdtimer_->stop(); ucdtimer_->start (macmib_.ucd_interval); } //change PHY state getPhy()->setMode (OFDM_SEND); //start handler of dlsubframe getMap()->getDlSubframe()->getTimer()->sched (0); //reschedule for next time (frame duration) dl_timer_->resched (getFrameDuration()); ul_timer_->resched (map_->getUlSubframe()->getStarttime()*getPhy()->getPS()); dl_relay_timer_->resched (map_->getDlSubframe()->getRelayStarttime() * getPhy()->getPS()); } /** * Start a new relay zone of DL subframe */ void Mac802_16BS::start_dl_relayzone() { debug ("At %f in MAC %d BS scheduler dl relay zone expires\n", NOW, addr()); setRelayStatus(RELAY_ZONE); ((BSScheduler *) scheduler_)->relay_schedule(); //update some information if (sendR_DCD) { sendR_DCD = false; } if (sendR_UCD) { sendR_UCD = false; } getMap()->getDlSubframe()->getTimer()->sched (0); dl_relay_timer_->resched(getFrameDuration()); } /** * Start a new access zone of UL subframe */ void Mac802_16BS::start_ul_accesszone() { debug ("At %f in Mac %d BS scheduler ul access zone expires\n", NOW, addr()); setRelayStatus(ACCESS_ZONE); //change PHY state getPhy()->setMode (OFDM_RECV); //start handler of ulsubframe getMap()->getUlSubframe()->getTimer()->sched (0); //reschedule for next frame ul_timer_->resched (getFrameDuration()); ul_relay_timer_->resched(map_->getUlSubframe()->getRelayStarttime()*getPhy()->getPS()); // debug("\t at %f PS dur. = %f\n", NOW, getPhy()->getPS()); } /** * Start a new relay zone of UL subframe */ void Mac802_16BS::start_ul_relayzone() { debug ("At %f in MAC %d BS scheduler ul relay zone expires\n", NOW, addr()); setRelayStatus(RELAY_ZONE); //change PHY state getPhy()->setMode (OFDM_RECV); //start handler of ulsubframe getMap()->getRUlSubframe()->getTimer()->sched(0); ul_relay_timer_->resched(getFrameDuration()); } /** Add a new Fast Ranging allocation * @param time The time when to allocate data * @param macAddr The MN address */ void Mac802_16BS::addNewFastRanging (double time, int macAddr) { //compute the frame where the allocation will be located int frame = int ((time-NOW)/getFrameDuration()) +2 ; frame += getFrameNumber(); //printf ("Added fast RA for frame %d (current=%d) for time (%f)\n", // frame, getFrameNumber(), time); FastRangingInfo *info= new FastRangingInfo (frame, macAddr); info->insert_entry(&fast_ranging_head_); } /** * Add a new timer17 in the list. It also performs cleaning of the list * @param index The client address */ void Mac802_16BS::addtimer17 (int index) { //clean expired timers T17Element *entry; for (entry = t17_head_.lh_first; entry ; ) { if (entry->paused ()) { T17Element *tmp = entry; entry = entry->next_entry(); tmp->remove_entry(); free (tmp); } entry = entry->next_entry(); } entry = new T17Element (this, index); entry->insert_entry (&t17_head_); } /** * Cancel and remove the timer17 associated with the node * @param index The client address */ void Mac802_16BS::removetimer17 (int index) { //clean expired timers T17Element *entry; for (entry = t17_head_.lh_first; entry ; entry = entry->next_entry()) { if (entry->index ()==index) { entry->cancel(); entry->remove_entry(); delete (entry); break; } } } /** * Finds out if the given station is currently scanning * @param nodeid The MS id */ bool Mac802_16BS::isPeerScanning (int nodeid) { ScanningStation *sta; for (sta = scan_stations_.lh_first; sta ; sta = sta->next_entry()) { if (sta->getNodeId()==nodeid && sta->isScanning(frame_number_)) { //printf ("station %d scanning\n", nodeid); return true; } } return false; }