def strcollision(p): """Get string representation of 'cif-collision' list from packet `p`.""" coll = None if ANNO.supports(p, 'cif-collision'): coll = [] for c in p.getanno('cif-collision'): try: s = c.traceid assert ANNO.supported(c), "s = %s, coll = %s"%(s, coll) except: s = c assert not ANNO.supported(c), "s = %s, coll = %s"%(s, coll) coll.append(s) return coll
def RECV(self, fsm): """RECV state; monitor traffic from lower layer. This state receives packets on `Port` 'RXD'. It then uses `ptype` to determine which packet handler should process the new data packet, and spawns a new thread to run the handler. :note: Currently, IPv4 is the only protocol type supported. Non-IPv4 packets are passed to `ERRRECV` for handling. """ # error messages rxderror = "[ROUTING]: Error occurred while receiving " + \ "traffic from RXD port!" pkterror = "[ROUTING]: Invalid packet from lower layer!" # get packet from lower layer yield self.RXD.recv(fsm, 1) assert fsm.acquired(self.RXD) and (len(fsm.got)==1), rxderror p = fsm.got[0] if isinstance(p, Reference): p = p._deref assert ANNO.supported(p), pkterror # use appropriate recv function based on ptype if (self.ptype == const.ARP_PTYPE_IP): f = FSM.launch(self.IPRECV, p) # IP ptype else: f = FSM.launch(self.ERRRECV, p) # unknown ptype # continue in RECV yield fsm.goto(self.RECV)
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): """Manage downstream (or outgoing traffic.""" yield self.RXU.recv(fsm, 1) assert fsm.acquired(self.RXU) and (len(fsm.got)==1), \ "[CHANNELIF]: SEND() error occurred during recv() from RXU!" # get packet and set annotations p, duration = fsm.got[0], 0 errmsg = "[CHANNELIF]: Cannot send packet that does not support ANNO!" assert ANNO.supported(p), errmsg self.set_sendanno(p) if p.hasanno('cif-duration'): duration = p.getanno('cif-duration') # min-time is const.EPSILON if duration<const.EPSILON: duration = const.EPSILON p.setanno('cif-duration', duration) self.log_send(p) # send and simulate duration self.__ifstate = CHANNELIF_TX # start TX self.drop("all") # drop all packet in rxbuffer self.txdata.signal(p) yield self.TXD.send(fsm, [p]) yield hold, fsm, duration # simulate duration self.drop("all") # drop all packet in rxbuffer self.__ifstate = CHANNELIF_RX # resume RX self.txdone.signal(p) # continue in SEND yield fsm.goto(self.SEND)
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 framedetect(self, p, thresh=None): """Apply packet detection model for detecting training sequence; based on signal-to-interference-and-noise ratio (SINR). :param p: `Dot11A` packet being received. :param thresh: Packet detection SINR threshold (in dB) [default=`DOT11A_FDTHRESHOLD`]. :return: Boolean flag; if true, packet detection was successful. This method checks to make sure `p` is a `Dot11A` packet, and that the received SINR is greater than the receiver detection threshold `thresh`. This method will also mark the 'dot11a-detect' annotation to indicate the success (or failure) of the frame detection. **Overload this method to change how frame detection works.** :note: If `p` is not a `Dot11A` packet, this method will set the 'dot11a-detect' annotation to false and return false. """ if not isinstance(p, Dot11A): if ANNO.supported(p): p.setanno("dot11a-detect", False) return False # check SINR if thresh is None: thresh = DOT11A_FDTHRESHOLD sinr = self.sinr(p) detect = True if sinr < thresh: detect = False # mark annotations p.setanno("dot11a-detect", detect) return detect
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 cleananno(self, p): """Clean up annotations before passing to upper layers.""" assert ANNO.supported(p), "[PHY]: ANNO not supported!" # replace/remove unwanted annotations if p.hasanno('cif-collision'): coll = strcollision(p) assert (coll is not None) p.delanno('cif-collision') p.setanno('cif-collision', coll, priv=True) return p
def _apply_fixed_delay(cm, *args, **kwargs): """Internal method to implement `FixedDelay` `ChannelModel` wrapper.""" assert isinstance(cm, ChannelModel) assert hasattr(cm, '__subclass__') assert hasattr(cm, '__fixed_delay__') subclass = cm.__subclass__ delay = cm.__fixed_delay__ r = subclass.apply(cm, *args, **kwargs) if ANNO.supports(r, 'cm-delay'): r.delanno('cm-delay') if ANNO.supported(r) and (delay>0): r.setanno('cm-delay', delay) return r
def set_recvanno(self, p, src, dst): """Set relevant annotations for received data to upper layer. :param p: Packet to modify. :param src: Network address of source. :param dst: Network address of destination. :return: Modified packet. This method sets the 'net-src' and 'net-dst' annotations. """ errmsg = "[ROUTING]: Got non-Packet data from upper layer()!" assert ANNO.supported(p), errmsg # set address annotations p.setanno('net-src', src) p.setanno('net-dst', dst) return p
def set_sendanno(self, p, src, dst): """Set relevant annotations for outgoing packet. :param p: Packet to modify. :param src: Network address of source. :param dst: Network address of destination. :return: Modified packet. This method sets the 'net-src' and 'net-dst' annotations. """ errmsg = "[ROUTING]: Got non-Packet data from upper layer()!" assert ANNO.supported(p), errmsg # set address annotations p.setanno('net-src', src) p.setanno('net-dst', dst) # set annotations used just for logging p.setanno('net-root', str(p.traceid)) return p
def sinr_heap(self, p, force=True): """Calculate signal-to-interference-and noise ratio (SINR) for each partition created by `interval_heap()`. :param p: Packet to inspect. :param force: If true, recalculate interval heap, else use existing annotation if it exists. :return: SINR heap. SINR heap has looks like this: [(t0, t1, sinr0), (t1, t2, sinr1), ... ] Note: This method uses the 'rxpower' and 'noisepower' annotations. """ # check packet errmsg = "[CHANNELIF]: sinr_heap() cannot process non-Packet!" assert ANNO.supported(p), errmsg for a in ['rxpower', 'noisepower']: errmsg = "[CHANNELIF]: sinr_heap() cannot find '%s' annotation!"%(a) assert ANNO.supports(p, a), errmsg # get parameters rxpower = p.getanno('rxpower') # in dBm noisepower = p.getanno('noisepower') # in dBm npow = db2linear(noisepower) # get interval heap if p.hasanno('cif-iheap') and not force: iheap = p.getanno('cif-iheap') else: iheap = self.interval_heap(p) # start creating sinr heap sinrheap = [] #print "%s: SINR heap for %s @ %.8f"%(self.traceid, p.traceid, now()) for ta,tb,coll in iheap: ipow = 0 for c in coll: errmsg = "[CHANNELIF]: sinr_heap() cannot find 'rxpower' " + \ "annotation in collision list!" assert ANNO.supports(c, 'rxpower'), errmsg ipow += db2linear(c.getanno('rxpower') ) sinr = rxpower - linear2db(ipow + npow) sinrheap.append((ta,tb,sinr) ) #print " --> (%.8f, %.8f): %.3f dB, coll = %s"%(ta,tb, sinr, [c.traceid for c in coll]) return sinrheap
def seterror(self, p): """Convenience method to set error annotation (or parameters) in `p`. :return: Modified packet with updated parameters/annotations. By default, if packet `p` has a `CRC32` layer, this method will set the 'crcerror' field, otherwise this method will set the 'crcerror' annotation to 1. **Overload this method as needed.** """ hascrc = CRC32.supported(p) hasanno = ANNO.supported(p) if hascrc: p[CRC32].crcerror = 1 elif hasanno: p.setanno('crcerror', 1) else: raise RuntimeError, "[PHY]: seterror() failed to find packet!"
def SEND(self, fsm): """SEND state; monitor traffic from upstream protocol and pass to routing algorithm. This state uses the 'net-src' and 'net-dst' annotations to determine the addresses of the source and destination. If not available, these values default to the local `address` and `broadcast` address. This state then uses `ptype` to determine which packet handler should process the new data packet, and spawns a new thread to run the handler. :note: Currently, IPv4 is the only protocol type supported. Non-IPv4 packets are passed to `ERRSEND` for handling. Also, this state will check for loopback addresses and send them back to the upper layer protocol. """ # error messages rxuerror = "[ROUTING]: Error occurred receiving from RXU port!" pkterror = "[ROUTING]: Invalid packet from upper layer!" # get packet to send from upperlayer yield self.RXU.recv(fsm, 1) assert fsm.acquired(self.RXU) and (len(fsm.got)==1), rxuerror p = fsm.got[0] if isinstance(p, Reference): p = p._deref assert ANNO.supported(p), pkterror # process new data packet addr = self.address src, dst = addr, self.broadcast if p.hasanno('net-src'): src = p.getanno('net-src') if p.hasanno('net-dst'): dst = p.getanno('net-dst') r = self.set_sendanno(p, src, dst) # send loopback back to upper layer if (dst==addr): self.log_loopback(p, src=src, dst=dst) yield self.TXU.send(fsm, [p]) yield fsm.goto(self.SEND) # continue in SEND # otherwise -> use appropriate send function based on ptype if (self.ptype == const.ARP_PTYPE_IP): f = FSM.launch(self.IPSEND, r, src, dst) # IP ptype else: f = FSM.launch(self.ERRSEND, r, src, dst) # unknown ptype # continue in SEND yield fsm.goto(self.SEND)
def haserror(self, p, *args, **kwargs): """Convenience method to determine if packet `p` has an error. :param args: Additional arguments passed to `CRC32.haserror()`. :param kwargs: Keyword arguments passed to `CRC32.haserror()`. :return: Boolean; true if error is found; false otherwise. By default, this method calls `CRC32.haserror()`. If no `CRC32` layer is found, or no 'crcerror' annotation is found the packet is assumed to be error-free. **Overload this method as needed to change this operation.** :note: This method ignores the CRC when `checkcrc` is set to false. """ hascrc = isinstance(p, Packet) and p.haslayer(CRC32) hasanno = ANNO.supported(p) and p.hasanno('crcerror') crcerror = (hascrc or hasanno) and CRC32.haserror(p,*args,**kwargs) if not self.checkcrc: crcerror = False # assume no error when checkcrc is false return crcerror