def configure(self, base=None, nsuccess=None, nfailure=None, timeout=None, **kwargs): """Configure rate adaptation parameters. :param base: Base rate used to initialize `RateAdapt` component [default=0]. :param nsuccess: Threshold for number of consecutive ACKs that must be received prior to increasing the data rate. :param nfailure: Threshold for number of consecutive ACK failures that will trigger a decrease in the data rate. :param timeout: Timeout that can automatically trigger """ DCF.configure(self, **kwargs) if base is None: base = 0 if nsuccess is None: nsuccess = ARF_NSUCCESS if nfailure is None: nfailure = ARF_NFAILURE if timeout is None: timeout = ARF_TIMEOUT ra = self.newchild("ra", RateAdapt, base=base, tracename=self.tracename+".RA") ra.set_rate(self.broadcast) # use default base rate for broadcast # create FSM to manage ARF fsm = self.newchild("manager", FSM, tracename=self.tracename+".MGR") fsm.goto(self.MGR) # set other parameters self.nsuccess = nsuccess self.nfailure = nfailure self.timeout = timeout self.ackcount = {} self.arftimer = {} self.probation = {}
def log_recv(self, p, *args, **kwargs): """Updated to print `RAI` parameters.""" if ANNO.supported(p): if p.haslayer(RAI): kwargs['rai-rate'] = p[RAI].rate kwargs['rai-length'] = p[RAI].length if p.hasanno('phy-rate'): kwargs['phy-rate'] = p.getanno('phy-rate') DCF.log_recv(self, p, *args, **kwargs)
def send_data(self, data): """Additional processing for outgoing DATA.""" DCF.send_data(self, data) dst = data.addr1 rate = self.ra.get_rate(dst) # allow fixed rate for broadcast packets fixedrate = data.hasanno('phy-fixed-rate') if (data.addr1==self.broadcast) and fixedrate: rate = data.getanno('phy-fixed-rate') data.setanno('phy-rate', rate)
def retry(self, *args, **kwargs): """Overloaded to manage dropped ACKs.""" rc = self.retrycount DCF.retry(self, *args, **kwargs) # Actual retry? if (self.retrycount>rc) and self.isdot11data(self.datatosend): # retry count was increased -> dropped ACK data = self.get_dot11data(self.datatosend) dst, src = data.addr1, data.addr2 #self.log("DROPACK", dst=dst, src=src) self.dropack.signal(dst)
def recv_ack(self, ack): """Additional processing for incoming ACK.""" DCF.recv_ack(self, ack) # Expecting ACK? if self.isdot11data(self.datatosend): data = self.get_dot11data(self.datatosend) dst, src = data.addr1, data.addr2 # ACK for me? -> received ACK if (src==ack.addr1): #self.log("RECVACK", ack, dst=dst, src=src) self.recvack.signal(dst)
def send_rts(self, rts, data): """Additional processing for outgoing RTS.""" DCF.send_rts(self, rts, data) # get rate and length information plen = len(data) dst, src = data.addr1, data.addr2 rate = self.ra.get_rate(dst) data.setanno('phy-rate', rate) # copy info to RTS/RAI rai = rts[RAI] rai.rate = rate rai.length = plen
def configure(self, base=None, thresh=None, **kwargs): """Configure rate adaptation parameters. :param base: Base rate used to initialize `RateAdapt` component [default=0]. :param thresh: Dictionary containing minimum SNR threshold corresponding to rate specific index [default=`RBAR_THRESHOLD`]. """ DCF.configure(self, **kwargs) if base is None: base = 0 if thresh is None: thresh = RBAR_THRESHOLD ra = self.newchild("ra", RateAdapt, base=base, tracename=self.tracename+".RA") ra.set_rate(self.broadcast) # use default base rate for broadcast self.thresh = thresh
def dot11data(self, *args, **kwargs): """Overloaded to add 'phy-rate' annotation to new packet.""" p = DCF.dot11data(self, *args, **kwargs) dst = p.addr1 rate = self.ra.get_rate(dst) p.setanno('phy-rate', rate) return p
def get_dot11data(self, p): """Overloaded to extract DATA or RSH.""" isrsh = self.isdot11rsh(p) if isrsh: return self.get_dot11rsh(p) else: return DCF.get_dot11data(self, p)
def ctsnav(self, rts): """Overloaded to add RSH to NAV and apply rate adaptation.. :param rts: RTS packet. :return: Integer; representing NAV value. This method uses `DCF.ctsnav()`, `calcrate()`, and `duration()` to calculate the new value of the CTS NAV. """ ctsnav = DCF.ctsnav(self, rts) errmsg = "[RBAR]: Invalid RTS! No RAI found in ctsnav()!" assert rts.haslayer(RAI), errmsg errmsg = "[RBAR]: Cannot find 'phy-sinr' annotation in ctsnav()!" assert rts.hasanno('phy-sinr'), errmsg # calculate new rate from SINR sinr = rts.getanno('phy-sinr') newrate = self.calcrate(sinr) # extract info from RTS+RAI rai = rts[RAI] oldrate, length = rai.rate, rai.length # recompute NAV using length and new rate dold = self.duration(length, oldrate) dnew = self.duration(length, newrate) nav = ctsnav - int(dold*1e6) + int(dnew*1e6) return nav
def rtsnav(self, p, *args, **kwargs): """Overloaded to add RSH to NAV.""" nav = DCF.rtsnav(self, p, *args, **kwargs) # add RSH + SIFS d = self.sifs + self.rshduration nav += int(d*1e6) return nav
def TXRSH(self, fsm): """TXRSH state; overloaded to send RSH prior to DATA.""" assert DCF.isdot11data(self, self.datatosend), \ "[RBAR]: Cannot determine 'datatosend' in TXUCAST!" assert not (self.datatosend.addr1==self.broadcast), \ "[RBAR]: Cannot send broadcast 'datatosend' in TXUCAST!" # update rate annotation data = self.get_dot11data(self.datatosend) dst, src = data.addr1, data.addr2 rate = self.ra.get_rate(dst) data.setanno('phy-rate', rate) if not self.usecsma: # send RSH before sending DATA rsh = self.dot11rsh(addr1=dst, addr2=src) self.send_rsh(rsh, self.datatosend) # recalculate NAV from new rate information nav = self.rshnav(self.datatosend) rsh.ID = nav pkt = crcupdate(rsh) # send and hold for duration rate, length = pkt[RAI].rate, pkt[RAI].length self.log("RSH", pkt, nav=nav, rate=rate, length=length) duration = self.duration(pkt) self.log_send(pkt, nav=nav) yield self.TXD.send(fsm, [pkt]) yield hold, fsm, duration # pause for SIFS before continuing yield hold, fsm, self.sifs # go to DCF.TXUCAST state OLDSTATE = lambda *args, **kwargs: DCF.TXUCAST(self, *args, **kwargs) yield fsm.goto(OLDSTATE)
def __init__(self, usecsma=True, **kwargs): """Constructor.""" # create ARF parameters self.nsuccess = None self.nfailure = None self.timeout = None self.ackcount = {} self.arftimer = {} self.probation = {} self._rates = None # create ARF events self.dropack = SimEvent() self.recvack = SimEvent() DCF.__init__(self, usecsma=usecsma, **kwargs) # update event names self.dropack.name = "%s%s"%(self.name, ".dropack") self.recvack.name = "%s%s"%(self.name, ".recvack")
def dot11cts(self, *args, **kwargs): """Overloaded to add 'phy-rate' annotation to new packet.""" rargs = {} for s in ['rate', 'length']: if s in kwargs: rargs[s] = kwargs[s] del kwargs[s] # create CTS + RAI payload p = DCF.dot11cts(self, *args, **kwargs)/RAI(**rargs) p.setanno('phy-rate', self.base) return p
def send_cts(self, cts, rts): """Additional processing for outgoing CTS. :param cts: Outgoing CTS packet. :param rts: Received RTS packet. This method uses the 'phy-sinr' annotation to apply the rate adaptation algorithm used by `RBAR`. """ DCF.send_cts(self, cts, rts) errmsg = "[RBAR]: Invalid RTS! No RAI found in send_cts()!" assert rts.haslayer(RAI), errmsg errmsg = "[RBAR]: Invalid CTS! No RAI found in send_cts()!" assert cts.haslayer(RAI), errmsg errmsg = "[RBAR]: Cannot find 'phy-sinr' annotation in send_cts()!" assert rts.hasanno('phy-sinr'), errmsg # extract info from RTS+RAI sinr = rts.getanno('phy-sinr') newrate = self.calcrate(sinr) cts[RAI].rate = newrate cts[RAI].length = rts[RAI].length
def rshnav(self, data, *args, **kwargs): """Calculate NAV value for RSH. :param data: DATA packet. :param args: Arguments passed on to `DCF.rtsnav()`. :param kwargs: Keywords passed on to `DCF.rtsnav()`. :return: Integer; representing NAV value. This method computes the RSH NAV as follows: NAV = SIFS + DATA + SIFS + ACK :note: This method uses `DCF.rtsnav()` to calculate the new NAV value. """ # Use regular RTS NAV (i.e. from DCF) to compute new NAV value rtsnav = DCF.rtsnav(self, data, *args, **kwargs) d = self.sifs + self.ctsduration nav = rtsnav - int(d*1e6) return nav
def log_recv(self, p, *args, **kwargs): """Updated to print `ARF` related parameters.""" if p.hasanno('phy-rate'): kwargs['phy-rate'] = p.getanno('phy-rate') DCF.log_recv(self, p, *args, **kwargs)
def send_data(self, data): """Additional processing for outgoing DATA.""" DCF.send_data(self, data) dst = data.addr1 rate = self.ra.get_rate(dst) data.setanno('phy-rate', rate)
def isdot11data(self, p): """Overloaded to check for DATA or RSH.""" isdata = DCF.isdot11data(self, p) isrsh = self.isdot11rsh(p) return (isdata or isrsh)
def dot11ack(self, *args, **kwargs): """Overloaded to add 'phy-rate' annotation to new packet.""" p = DCF.dot11ack(self, *args, **kwargs) p.setanno('phy-rate', self.base) return p
def __init__(self, usecsma=None, **kwargs): """Constructor.""" self.thresh = None self._rshduration = None DCF.__init__(self, usecsma=False, **kwargs)