def CAPTURE(self, fsm, p): """Simulate capture process for a Packet `p`.""" self.log("CAPSTART", p) errmsg = "[CHANNELIF]: Cannot capture packet that doesn't support ANNO!" assert ANNO.supported(p), errmsg duration = const.EPSILON self.rxbuffer.append(p) # add to rxbuffer if self.intransmit: self.drop("all") # drop all packet in rxbuffer # mark/use other annotations self.set_recvanno(p) if p.hasanno('cif-duration'): duration = p.getanno('cif-duration') assert not(duration<const.EPSILON), \ "[CHANNELIF]: Invlaid duration in CAPTURE! (t=%s)"%(duration) # resume operation self.log("rxdata.sig", p) self.rxdata.signal(p) # signal rxdata yield hold, fsm, duration # simulate duration if self.intransmit: self.drop("all") # drop all packet in rxbuffer self.rxbuffer.remove(p) # remove from rxbuffer # drop or forward to upper layer if p.hasanno('cif-drp') and p.getanno('cif-drp'): self.log_drop( p, halfduplex="%s"%(self.halfduplex) ) self.cleananno(p) else: pargs = {'cif-duration':time2usec(duration) } self.log_recv(p, **pargs) yield self.TXU.send(fsm, [p]) # signal rxdone self.log("rxdone.sig", p) self.rxdone.signal(p) yield fsm.stop() assert False, "stop failed!"
def SEND(self, fsm): """SEND state; simulate encoding and send process. This state performs the following tasks: 1. Get packet from 'RXU' port. 2. Call `encode()` to generate waveform for outgoing packet. 3. Mark 'cif-duration' annotation with value returned by `duration()`. 4. Simulate `txproctime` for outgoing packet. 5. Send outgoing waveform to 'TXD'. 6. Simulate `duration` of waveform. """ while fsm.active(): yield self.RXU.recv(fsm, 1) assert fsm.acquired(self.RXU) and ( len(fsm.got) == 1 ), "[DOT11APHY]: Error receiving from RXU port in SEND()!" p = fsm.got[0] # simulate encoding and Tx processing time w = self.encode(p) duration = self.duration(p) if ANNO.supported(w): w.setanno("cif-duration", duration) yield hold, fsm, self.txproctime(p) # send waveform and simulate duration self.log_send(w, duration=time2usec(duration)) yield self.TXD.send(fsm, [w]) assert fsm.stored(self.TXD), "[DOT11APHY]: Error sending to TXD in SEND!" yield hold, fsm, duration return
def HALT(self, fsm, force=True): """Overload `HALT` state to signal `kill` if needed.""" if (force or (self.timeleft>0)): timepassed = self.timepassed if self.verbose>TIMER_VERBOSE: self.log("CANCEL", timepassed=time2usec(timepassed, fmt="%.4g"), \ timeleft=self.timeleft, force=force) self.kill.signal(timepassed) yield hold, fsm, 0
def log_send(self, p, *args, **kwargs): """Convenience method for logging send event.""" if self.verbose>DOT11_VERBOSE: kwargs['addr'] = self.address kwargs['retrycount'] = self.retrycount kwargs['retrylimit'] = self.retrylimit if p.hasanno('cif-duration'): kwargs['cif-duration'] = time2usec(p.getanno('cif-duration') ) if p.hasanno('phy-rate'): kwargs['phy-rate'] = p.getanno('phy-rate') self.log("snd", p, *args, **kwargs)
def log_send(self, p, *args, **kwargs): """Convenience method for logging send event.""" if self.verbose > DOT11A_VERBOSE: if isinstance(p, Dot11A): kwargs["phy-rate"] = p.rate kwargs["length"] = p.length if p.hasanno("cif-txpower"): kwargs["cif-txpower"] = "%.2f dBm" % (p.getanno("cif-txpower")) if p.hasanno("cif-duration"): kwargs["cif-duration"] = time2usec(p.getanno("cif-duration")) self.log("snd", p, *args, **kwargs)
def get_cif_anno(self, p): """Convenience method to extract annotations and convert to strings.""" kwargs = {} if not isinstance(p, Packet): return kwargs if p.hasanno('cif-collision'): kwargs['cif-collision'] = strcollision(p) if p.hasanno('cif-duration'): kwargs['cif-duration'] = time2usec(p.getanno('cif-duration') ) if p.hasanno('cif-src'): kwargs['cif-src'] = "%s"%(p.getanno('cif-src').traceid) if p.hasanno('cif-dst'): kwargs['cif-dst'] = "%s"%(p.getanno('cif-dst').traceid) return kwargs
def BACKOFF(self, fsm): """BACKOFF state; perform backoff operation.""" assert self.isdot11data(self.datatosend), \ "[DCF]: Cannot determine 'datatosend' in BACKOFF!" # retry limit exceeded -> DROP PACKET! -> go to IDLE if self.retrycount>self.retrylimit: self.log_drop(self.datatosend, drop="retry limit exceeded") pkt = self.datatosend.payload self.datatosend.remove_payload() p = crcremove(pkt) self.drpdata.signal(p) yield fsm.goto(self.IDLE) # csbusy -> go to RXBUSY if self.isbusy: yield fsm.goto(self.RXBUSY) # check for nav timer -> start nav backoff if self.navbusy: yield fsm.goto(self.NAVBACKOFF) # start backoff timer backoff = self.difs + self.cslot*self.slottime timer = self.newchild("backofftimer", Timer, backoff, start=True, \ tracename=self.tracename+".BACKOFF") self.log("BACKOFF", self.datatosend, backoff=time2usec(backoff), cslot=self.cslot) yield waitevent, fsm, (timer.done, timer.kill, self.csbusy, self.rxdata) csbusy = (self.csbusy in fsm.eventsFired) rxdata = (self.rxdata in fsm.eventsFired) # timer done -> go to TXRTS or TXBCAST if (timer.done in fsm.eventsFired): isbroadcast = (self.datatosend.addr1==self.broadcast) if isbroadcast: ns = self.TXBCAST elif self.usecsma: ns = self.TXUCAST else: ns = self.TXRTS yield fsm.goto(ns) # timer kill -> raise exception elif (timer.kill in fsm.eventsFired): raise RuntimeError, "[DCF]: Unexpected kill signal " + \ "from timer in BACKOFF!" # csbusy/rxdata -> halt timer -> update cslot -> go to RXBUSY/RXPKT elif csbusy or rxdata: yield timer.pause(fsm) if timer.timepassed>self.difs: rslot = int(timer.timeleft/self.slottime) self.cslot = rslot # update cslot timer.halt() if rxdata: p = self.rxdata.signalparam yield fsm.goto(self.RXPKT, p) else: yield fsm.goto(self.RXBUSY) # otherwise -> raise error! else: raise RuntimeError, "[DCF]: Unexpected interruption in BACKOFF!"
def MONBUSY(self, fsm, t): """MONIDLE state; monitor `timer` when NAV Timer is in BUSY state.""" self.log_busy(duration=time2usec(t.duration) ) yield waitevent, fsm, (t.done, t.kill) # timer fired if (t.done in fsm.eventsFired): pass # timer stopped elif (t.kill in fsm.eventsFired) and t.stopped: pass # otherwise -> raise exception else: raise RuntimeError, "[NAVTIMER]: Monitor indicates " + \ "NAV timer paused unexpectedly!" # done monitoring timer yield fsm.goto(self.MONIDLE)
def TXBCAST(self, fsm): """TXBCAST state; broadcast `datatosend`.""" assert self.isdot11data(self.datatosend), \ "[DCF]: Cannot determine 'datatosend' in TXBCAST!" assert (self.datatosend.addr1==self.broadcast), \ "[DCF]: Non-broadcast 'datatosend' in TXBCAST!" data = self.datatosend self.send_data(data) # send and hold for duration duration = self.duration(data) src, dst = data.addr2, data.addr1 self.log_send(data, src=src, dst=dst, duration=time2usec(duration) ) yield self.TXD.send(fsm, [data]) yield hold, fsm, duration # go back to IDLE yield fsm.goto(self.IDLE)
def get_dcf_anno(self, p): """Convenience method to extract annotations and convert to strings.""" kwargs = {} if not isinstance(p, Packet): return kwargs kwargs['addr'] = self.address if p.hasanno('cif-duration'): kwargs['cif-duration'] = time2usec(p.getanno('cif-duration') ) if p.hasanno('phy-rate'): kwargs['phy-rate'] = p.getanno('phy-rate') if p.hasanno('phy-sinr'): kwargs['phy-sinr'] = "%.4f dB"%(p.getanno('phy-sinr') ) if p.hasanno('net-root'): kwargs['net-root'] = p.getanno('net-root') if p.hasanno('mac-root'): kwargs['mac-root'] = p.getanno('mac-root') if p.hasanno('mac-txts'): kwargs['mac-txts'] = p.getanno('mac-txts') if p.hasanno('mac-rxts'): kwargs['mac-rxts'] = p.getanno('mac-rxts') return kwargs
def log_recv(self, p, *args, **kwargs): """Convenience method for logging receive event.""" if self.verbose > DOT11A_VERBOSE: if isinstance(p, Dot11A): kwargs["phy-rate"] = p.rate kwargs["length"] = p.length if p.hasanno("phy-sinr"): kwargs["phy-sinr"] = "%.2f dB" % (p.getanno("phy-sinr")) if p.hasanno("rxpower"): kwargs["rxpower"] = "%.2f dBm" % (p.getanno("rxpower")) if p.hasanno("noisepower"): kwargs["noisepower"] = "%.2f dBm" % (p.getanno("noisepower")) if p.hasanno("cif-duration"): kwargs["cif-duration"] = time2usec(p.getanno("cif-duration")) if p.hasanno("dot11a-per"): kwargs["dot11a-per"] = "%.5g" % (p.getanno("dot11a-per")) if p.hasanno("crcerror"): crcerror = p.getanno("crcerror") if crcerror: kwargs["crc"] = "FAIL" else: kwargs["crc"] = "OK" self.log("rcv", p, *args, **kwargs)
def ETHSEND(self, fsm, p): """ETHSEND state; send ethernet frame. :param p: Ethernet packet to transmit. By default, this state appends a crc to packet `p` and sends it to `Port` 'TXD' without any address checking. After simulating the duration of the packet as reported by `duration()`, this state execution method returns to `SEND`. """ assert (self.htype==const.ARP_HTYPE_ETHERNET), "[ALOHA]: In ETHSEND," + \ " non-Ethernet hardware type (%s) not allowed!"%(self.htype) assert isinstance(p, Packet) and p.haslayer(Ether), \ "[ALOHA]: ETHSEND cannot handle non-Ether packet!" eth = p[Ether] addr, src, dst, etype = self.address, eth.src, eth.dst, eth.type pkt = crcupdate(eth) duration = self.duration(pkt) self.log_send(pkt, addr=addr, src=src, dst=dst, type=etype, \ duration=time2usec(duration) ) yield self.TXD.send(fsm, [pkt]) yield hold, fsm, duration yield fsm.goto(self.SEND)
def MON(self, fsm): """MON state; monitor `timer` events.""" while fsm.active(): # wait for timer to be set self.log_idle() yield waitevent, fsm, self.__wakeup t = self.__wakeup.signalparam # monitor timer events while isinstance(t, Timer): self.log_busy(duration=time2usec(t.duration) ) yield waitevent, fsm, (t.done, t.kill) # timer fired if (t.done in fsm.eventsFired): pass # timer stopped elif (t.kill in fsm.eventsFired) and t.stopped: pass # otherwise -> raise exception else: raise RuntimeError, "[NAVTIMER]: Monitor indicates " + \ "NAV timer paused unexpectedly!" # done monitoring timer t = None return
def TXRTS(self, fsm): """TXRTS state; send RTS for `datatosend`.""" assert self.isdot11data(self.datatosend), \ "[DCF]: Cannot determine 'datatosend' in TXRTS!" assert not (self.datatosend.addr1==self.broadcast), \ "[DCF]: Cannot send broadcast 'datatosend' in TXRTS!" # create RTS src, dst = self.datatosend.addr2, self.datatosend.addr1 rts = self.dot11rts(addr1=dst, addr2=src) if (self.retrycount>0): rts.FCfield |= DOT11_FC_RETRY # calculate NAV self.send_rts(rts, self.datatosend) nav = self.rtsnav(self.datatosend) rts.ID = nav pkt = crcupdate(rts) # send and hold for duration duration = self.duration(pkt) self.log_send(pkt, src=src, dst=dst, nav=nav, \ duration=time2usec(duration), retry=self.retrycount) yield self.TXD.send(fsm, [pkt]) yield hold, fsm, duration # go to RXCTS yield fsm.goto(self.RXCTS)
def log_forward(self, p, *args, **kwargs): """Convenience method for logging a forward event for packet `p`.""" if p.hasanno('cm-delay'): delay = p.getanno('cm-delay') kwargs['cm-delay'] = time2usec(delay) self.log("fwd", p, *args, **kwargs)