Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
 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!"
Ejemplo n.º 4
0
    def calcrxwaveform(self, p, bandwidth=None):
        """Pre-compute receive waveform and set 'dot11n-rxwaveform'.

        Use 'dot11n-channel' and 'dot11n-txwaveform' annotations to pre-compute
        the received waveform (modulo intereference and noise).
        """
        if bandwidth is None: bandwidth = DOT11N_BANDWIDTH
        # check for annotations
        for a in ['rxpower', 'dot11n-txwaveform', 'dot11n-channel']:
            errmsg = "[DOT11N_DSP]: cannot find '%s' annotation!"%(a)
            assert ANNO.supports(p,a), errmsg
        A = db2linear(p.getanno('rxpower'))
        H = p.getanno('dot11n-channel')
        x = p.getanno('dot11n-txwaveform')
        # check that channel dimensions match Ntx
        nrx = H.rows()
        ntx, hcols = x.rows(), H.cols()
        assert (hcols == ntx), "[DOT11N]: Got channel with invalid dimensions!"
        z = sqrt(A)*H.conv(x)
        # apply local frequency offset (and doppler) if annotations are found
        cfo = 0
        if p.hasanno('tx-cfo') and p.hasanno('rx-cfo'):
            cfo += p.getanno('tx-cfo') - p.getanno('rx-cfo')
        if p.hasanno('doppler'):
            cfo += p.getanno('doppler')
        z.apply_offset(cfo, bandwidth)
        # set rxwaveform annotation
        p.setanno('dot11n-rxwaveform', z)
        return p
Ejemplo n.º 5
0
 def delrxwaveform(self, p):
     """Remove waveform annotations from packet `p`."""
     wanno = ['dot11n-txwaveform', 'dot11n-rxwaveform', \
              'dot11n-rxnoise', 'dot11n-rxadded', 'dot11n-channel']
     for a in [w for w in wanno if ANNO.supports(p,w)]:
         if p.hasanno(a): p.delanno(a)
     return p
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
    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
Ejemplo n.º 9
0
 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)
Ejemplo n.º 10
0
 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)
Ejemplo n.º 11
0
    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
Ejemplo n.º 12
0
    def cleananno(self, p):
        """Remove unwanted annotations from packet `p`.

        Removes any annotations that could cause cyclic references.
        """
        if ANNO.supports(p, 'cif-collision'):
            coll = strcollision(p)
            p.delanno('cif-collision')
            p.setanno('cif-collision', coll, priv=True)
        return p
Ejemplo n.º 13
0
 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
Ejemplo n.º 14
0
 def DECODE(self, fsm, pkt):
     """DECODE state; monitor `radio` and manage packet decoding."""
     r = self.radio
     assert isinstance(r, Radio), "[DOT11A]: Cannot find radio in DECODE!"
     assert self.isbusy, "[DOT11A]: Carrier sense *not* busy in DECODE!"
     while fsm.active():
         # monitor events and RXD port
         yield self.RXD.recv(fsm, 1, renege=(r.rxdata, r.rxdone, r.txdata, r.txdone, self.detect))
         # receive pkt -> apply error model and forward to upper layers
         if fsm.acquired(self.RXD):
             assert len(fsm.got) == 1, (
                 "[DOT11A]: Received unexpected " + "number of packets from 'RXD' port in DECODE state!"
             )
             p = fsm.got[0]
             if p is pkt:
                 payload = self.decode(p)
                 if payload:
                     self.log_recv(p)
                     self.cleananno(p)  # replace/remove unwanted annotations
                     p.remove_payload()
                     yield self.TXU.send(fsm, [payload])
                     yield hold, fsm, const.EPSILON  # pause before resuming
                 pkt = None
         # rxdone received before RXD -> interface dropped packet?
         if r.rxdone in fsm.eventsFired:
             p = r.rxdone.signalparam
             if p is pkt:
                 qlen = self.RXD.length
                 drop = ANNO.supports(p, "cif-drp") and p.getanno("cif-drp")
                 errmsg = "[DOT11A]: Unexpected rxdone received in DECODE!"
                 assert (qlen == 0) and drop, errmsg
                 self.log_drop(p, drop="interface dropped packet")
                 pkt = None
         # rxdata -> drop new packets
         if r.rxdata in fsm.eventsFired:
             p = r.rxdata.signalparam
             assert p is not pkt, "[DOT11A]: Unexpected rxdata for pkt in DECODE!"
             self.log_drop(p, drop="ignore rxdata in DECODE")
         # detect -> drop detected packets
         if self.detect in fsm.eventsFired:
             p = r.rxdata.signalparam
             assert p is not pkt, "[DOT11A]: Unexpected detect for pkt in DECODE!"
             self.log_drop(p, drop="ignore detect in DECODE", decode=pkt.traceid)
         # ignore otherwise
         ignore = r.txdata in fsm.eventsFired
         ignore = ignore or (r.txdone in fsm.eventsFired)
         if ignore:
             pass
         # check if DECODE is done
         if pkt is None:
             yield fsm.goto(self.LISTEN)
     return
Ejemplo n.º 15
0
 def LISTEN(self, fsm, cif, rxport):
     """Listen to traffic sent by `ChannelInterface` on `rxport`."""
     assert (self.hasport(rxport) is not None), \
             "[CHANNEL]: Cannot listen on invalid Port!"
     # get data from rxport
     yield rxport.recv(fsm, 1)
     assert fsm.acquired(rxport) and (len(fsm.got)==1), \
             "[CHANNEL]: Error occurred during LISTEN on %s!"%(rxport)
     # forward on all outgoing edge
     p, u = fsm.got[0], cif
     neighbors = [str(c.traceid) for c in self.graph.neighbors(u) ]
     errmsg = "[CHANNEL]: Cannot forward non-Packet!"
     assert isinstance(p, Packet), errmsg
     for v in self.graph[u]:
         cmodel = self.graph[u][v]['model']
         errmsg = "[CHANNEL]: Cannot find corresponding TX Port!"
         assert (self.hasport((v, "TX") ) is not None)
         # if channel model for link is not active -> ignore packet
         if not cmodel.active: continue
         # filter packets using channel model
         drop = self.apply_filter(cmodel, p, u, v)
         if drop:
             self.log("drp",p,drop=drop,src=u.traceid,dst=v.traceid)
             continue            # continue with next link
         # copy and mark annotations
         c, txport = p.copy(), self.getport((v, "TX") )
         c.setanno('cif-src', u, ref=True)
         c.setanno('cif-dst', v, ref=True)
         # apply channel model
         propdelay = None
         r = self.apply_model(cmodel, c, u, v)
         if cmodel.verbose>CHANNEL_VERBOSE:
             cmodel.log_forward(c, src=u.traceid, dst=v.traceid)
         if ANNO.supports(r, 'cm-delay'):
             propdelay = r.getanno('cm-delay')
         # forward to destination
         if (r is None):
             self.log("drp",c,action="dropped by %s"%(cmodel.traceid) )
         elif (propdelay>0):
             # apply propagation delay
             f = FSM()
             f.goto(self.FORWARD, txport, [r])
             f.start(delay=propdelay)
         else:
             # send immediately (no delay)
             yield txport.send(fsm, [r])
     if self.verbose>CHANNEL_VERBOSE:
         self.log("fwd", p, dest="%s"%(neighbors) )
     # continue in LISTEN
     yield fsm.goto(self.LISTEN, cif, rxport)
Ejemplo n.º 16
0
    def set_recvanno(self, p):
        """Overloaded to modify noisepower with noise figure.

        :return: Modified packet `p`.

        This method adds the `DOT11A_NOISEFIGURE` to the noisepower specified by
        `Radio`.
        """
        r = Radio.set_recvanno(self, p)
        if ANNO.supports(r, "noisepower"):
            noisepower = r.getanno("noisepower")
            noisepower += DOT11A_NOISEFIGURE
            r.setanno("noisepower", noisepower)
        return r
Ejemplo n.º 17
0
 def LISTEN(self, fsm):
     """LISTEN state; monitor `radio` and manage packet detection."""
     r = self.radio
     assert isinstance(r, Radio), "[DOT11A]: Cannot find radio in LISTEN!"
     while fsm.active():
         # check rxenergy -> set csbusy?
         rxenergy = r.rxenergy()
         rxhigh = r.inreceive and (r.rxenergy() > DOT11A_CSTHRESHOLD)
         if rxhigh:
             self.set_csbusy(rxenergy="high, %.2f dBm" % (rxenergy), rxbuffer=[x.traceid for x in r.rxbuffer])
         else:
             self.set_csidle(rxenergy="%.2f dBm" % (rxenergy))
         # monitor events and RXD port
         yield self.RXD.recv(fsm, 1, renege=(r.rxdata, r.rxdone, r.txdata, r.txdone, self.detect))
         # RXD -> ignore incoming packets in LISTEN
         if fsm.acquired(self.RXD):
             assert len(fsm.got) == 1, (
                 "[DOT11A]: Received unexpected " + "number of packets from 'RXD' port in LISTEN state!"
             )
             p = fsm.got[0]
             self.log_drop(p, drop="not detected in LISTEN")
         # rxdata -> start DETECT thread
         if r.rxdata in fsm.eventsFired:
             p = r.rxdata.signalparam
             fname = "detect(%s)" % (p._id)
             ### XXX ####
             f = FSM()
             # f = self.newchild(fname, FSM, tracename=fname.upper() )
             f.goto(self.DETECT, p)
             f.start()
         # detect -> set csbusy -> goto DECODE
         if self.detect in fsm.eventsFired:
             p = self.detect.signalparam
             rxenergy = "%.2f dBm" % (r.rxenergy())
             sinr = "%.2f dB" % (self.sinr(p))
             self.set_csbusy(p, detect=True, rxenergy=rxenergy)
             danno = "dot11a-detect"
             errmsg = "[DOT11A]: Cannot find 'dot11a-detect' " + "annotation in detected packet!"
             assert ANNO.supports(p, danno) and p.getanno(danno), errmsg
             # yield hold, fsm, 0
             self.log("detect", p, rxenergy=rxenergy, sinr=sinr, rxbuffer=[x.traceid for x in r.rxbuffer])
             yield fsm.goto(self.DECODE, p)
         # ignore otherwise
         ignore = r.txdata in fsm.eventsFired
         ignore = ignore or (r.txdone in fsm.eventsFired)
         ignore = ignore or (r.rxdone in fsm.eventsFired)
         if ignore:
             pass
     return
Ejemplo n.º 18
0
    def rxenergy(self):
        """Calculate total receive energy of packets in `rxbuffer`.

        :return: Receive power (in dBm), or -Inf if nothing is in `rxbuffer`.

        This method uses the 'rxpower' annotation of packets in `rxbuffer` to
        determine the total receive power. Any packets that do not support this
        annotation will not contribute to the total power calculated.
        """
        tot = 0     # sum total in milliwatts
        for p in self.rxbuffer:
            if ANNO.supports(p, 'rxpower'):
                prx = p.getanno('rxpower')  # rxpower in dBm
                tot += db2linear(prx)
        tot_dbm = linear2db(tot)
        return tot_dbm
Ejemplo n.º 19
0
    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
Ejemplo n.º 20
0
    def calcper_data(self, p, **kwargs):
        """Calculate probability of error for data decoding.

        :param p: Packet being decoded.
        :param kwargs: Additional keywords arguments passed to `sinr_heap()`
                       (or `sinr()`).
        :return: PER for decoding packet payload.

        This method sets the 'dot11a-sinr' and 'dot11a-per' annotations. The
        operation of this method depends on `DOT11A_USE_PIECEWISE_PER`.
        """
        for a in ["cif-rxts", "cif-duration"]:
            errmsg = "[DOT11APHY]: calcper_data() cannot find " + "'%s' annotation!" % (a)
            assert ANNO.supports(p, a), errmsg
        # verify header parameters
        plen = len(p.payload)
        rate, length = p.rate, p.length
        assert 0 <= rate < len(DOT11A_DATARATE), "[DOT11A]: Invalid rate option (%s)!" % (rate)
        assert p.length == plen, "[DOT11A]: Header length reported " + "does not equal payload length; %s!=%s" % (
            p.length,
            plen,
        )
        # calculate PER using appropriate method
        if DOT11A_USE_PIECEWISE_PER:
            sinrheap = self.sinr_heap(p, **kwargs)
            t1 = p.getanno("cif-rxts") + p.getanno("cif-duration")
            t0 = t1 - self.calcnofdm(plen, rate) * DOT11A_TSYM
            xheap = [(max(ta, t0), min(tb, t1), sinr) for (ta, tb, sinr) in sinrheap if (ta < t1) and (tb > t0)]
            errmsg = "[DOT11APHY]: Unable to find valid data from SINR heap!"
            assert len(xheap) > 0, errmsg
            # calculate piecewise PER and average SINR
            psuccess, stot = 1.0, 0.0
            for ta, tb, sinr in xheap:
                alpha = (tb - ta) / (t1 - t0)
                dlen = plen * alpha
                stot += db2linear(sinr) * alpha
                psuccess *= 1.0 - self.calcper(dlen, rate, sinr)
            per = 1.0 - psuccess
            sinr = linear2db(stot)
        else:
            # configure modulation and coding to calculate PER
            sinr, plen = self.sinr(p, **kwargs), length
            per = self.calcper(plen, rate, sinr)
        # set annotations and return PER
        p.setanno("dot11a-sinr", sinr)
        p.setanno("dot11a-per", per)
        return per
Ejemplo n.º 21
0
    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
Ejemplo n.º 22
0
    def decode_header(self, p, checkcrc=False):
        """Waveform-level decoding of header.

        :param p: Packet to decode.
        :param checkcrc: If true, check header CRC.

        Set `checkcrc` to false when using `decode_header()` to just do
        detection. By default, the PHY does detection & decoding in the same
        functions, so this method is allows for some slight variation in usage.
        """
        # check annotations
        assert isinstance(p, Dot11N)
        for a in ['cif-rxts', 'dot11n-rxadded']:
            errmsg = "[DOT11N]: Cannot find '%s' annotation!"%(a)
            assert ANNO.supports(p, a), errmsg
        errmsg = "[DOT11N]: Packet was not added to input!"
        assert p.hasanno('dot11n-rxadded'), errmsg
        # get rx input stream
        y = self.getrxinput(p)
        detect = self.receiver.decode_header(y, checkcrc)   # check header crc?
        prepad = int(self.MINPAD + DOT11N_TSHORT*DOT11N_BANDWIDTH)
        startidx = self.receiver.start_index() - prepad
        crcok = detect
        # check header parameters
        plen = len(p.payload)
        # get header parameters from receiver after decoding
        rate, length = self.receiver.mcs(), self.receiver.length()
        okrate = (0<=rate<len(DOT11N_DATARATE) )
        oklen  = (length == plen)
        okpar  = crcok
        # calculate start time
        tstart = p.getanno('cif-rxts')
        tstart  += startidx/DOT11N_BANDWIDTH
        p.setanno('dot11n-start-index', startidx)
        p.setanno('dot11n-cfo', self.receiver.get_cfo() )
        # return decoding parameters
        if detect: header = "detect success"
        else:      header = "detect failed"
        if checkcrc:
            if crcok: header = "success"
            else:     header = "decoding failed"
        param = {'status':header, 'detect':detect, 'crcok':crcok, \
                 'rate':rate, 'length':length, 'start':tstart}
        return param
Ejemplo n.º 23
0
    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)
Ejemplo n.º 24
0
    def decode_data(self, p):
        """Waveform-level decoding of packet payload.

        :param p: Packet to decode.
        :return: Decoded data string.
        """
        # check annotations
        assert isinstance(p, Dot11N)
        for a in ['cif-rxts', 'dot11n-header', 'dot11n-detect', 'dot11n-rxadded']:
            errmsg = "[DOT11N]: Cannot find '%s' annotation!"%(a)
            assert ANNO.supports(p, a), errmsg
        errmsg = "[DOT11N]: Packet was not added to input!"
        assert p.hasanno('dot11n-rxadded'), errmsg
        errmsg = "[DOT11N]: Packet was not detected!"
        assert p.getanno('dot11n-detect'), errmsg
        header = p.getanno('dot11n-header')
        errmsg = "[DOT11N]: Header decoding failed before decode_data()!"
        assert (header=="success"), errmsg
        # get parameters to check startidx
        Ngi      = int(DOT11N_TGI*DOT11N_BANDWIDTH)
        prepad   = int(self.MINPAD + DOT11N_TSHORT*DOT11N_BANDWIDTH)
        startidx = self.receiver.start_index() - prepad
        ## startidx = -8     # overwrite startidx
        ## self.receiver.set_start_index(prepad+startidx)
        # decode payload -> check if startidx is valid
        y = self.getrxinput(p)
        data = self.receiver.decode_data(y)
        # check if decoding error occurred
        #  -> do contents of data match and does CRC pass?
        crcchk, error = "FAIL", True
        if (data == str(p.payload)):
            if not CRC32.haserror(data):
                crcchk = "OK"
                error = False
        # hamming distance between decoded data and packet p
        hdist = hamming_distance(data, str(p.payload) )
        self.log("CRC", p.payload, crcchk=crcchk, error=error, hdist=hdist)
        # clean up waveform annotations
        self.delrxwaveform(p)
        # return decoding parameters
        param = {'data':data, 'error':error, 'nerror':hdist}
        # return decoded data
        return param
Ejemplo n.º 25
0
    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!"
Ejemplo n.º 26
0
    def getrxinput(self, p):
        """Get input to receiver for specified packet.

        :param p: Packet to grab from input stream.

        Get the samples corresponding to the input for a given packet. This uses
        the timestamp annotation 'cif-rxts' and 'cif-duration' annotation to
        find the appropriate input samples from `rxinput`.
        """
        #self.stdout("%s: called getrxinput() on %s @ %.8f\n"%(self.traceid, p.traceid, now()))
        errmsg = "[DOT11N]: in getrxinput(), no input stream found!"
        assert (self.rxinput is not None), errmsg
        # check annotations
        for a in ['cif-rxts', 'cif-duration', 'dot11n-rxadded']:
            errmsg = "[DOT11N]: Cannot find '%s' annotation!"%(a)
            assert ANNO.supports(p, a), errmsg
        assert p.getanno('dot11n-rxadded')
        # calculate start/end of waveform
        tstart = p.getanno('cif-rxts')
        duration = p.getanno('cif-duration')
        tend = tstart + duration
        # pad returned waveform
        minpad = self.MINPAD
        tstart -= minpad/DOT11N_BANDWIDTH
        tend   += minpad/DOT11N_BANDWIDTH
        # extract from input stream
        rxts, w = self.rxinput
        rxend = rxts + w.cols()/DOT11N_BANDWIDTH
        errmsg = "[DOT11N]: in getrxinput(), packet starts before input " + \
                 "stream! tpacket, tbuffer = (%.6f, %.6f)"%(tstart, rxts)
        assert (tstart>=rxts), errmsg
        # calculare indices
        istart = int((tstart-rxts)*DOT11N_BANDWIDTH)
        istop  = int((tend-rxts)*DOT11N_BANDWIDTH)-1
        assert (istart>-1), "[DOT11N]: In getrxinput(), requested " + \
                "packet starting before start of input stream!"
        assert (istop<=w.cols()), "[DOT11N]: In getrxinput(), requested " + \
                "packet beyond end of input stream!"
        # get rxinput
        y = w.get_cols(istart, istop)
        return y
Ejemplo n.º 27
0
    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
Ejemplo n.º 28
0
    def duration(self, p, *args, **kwargs):
        """Convenience method to get duration of packet `p`.

        :return: Duration of packet `p` in seconds.

        By default, this method calls `PHY.duration()` on the physical layer
        associated with this `MAC` (i.e. `phy`). If `phy` is not a valid `PHY`,
        this method will attempt to find and return the 'cif-duration' annotation.

        Overload this method as needed.

        :note: If duration cannot be determined, this method may raise an
               exception.
        """
        if isinstance(self.phy, PHY):
            return self.phy.duration(p, *args, **kwargs)
        elif ANNO.supports(p, 'cif-duration'):
            return p.getanno('cif-duration')
        else:
            raise RuntimeError, "[MAC]: Could not determine duration! " + \
                    "No valid PHY and 'cif-duration' annotation not found!"
Ejemplo n.º 29
0
    def calcper_header(self, p, **kwargs):
        """Calculate probability of error for header decoding.

        :param p: Packet being decoded.
        :param kwargs: Additional keywords arguments passed to `sinr_heap()`
                       (or `sinr()`).
        :return: PER for header decoding.

        This method sets the 'dot11a-sinr' and 'dot11a-per' annotations. The
        operation of this method depends on `DOT11A_USE_PIECEWISE_PER`.
        """
        for a in ["cif-rxts"]:
            errmsg = "[DOT11APHY]: calcper_header() cannot find " + "'%s' annotation!" % (a)
            assert ANNO.supports(p, a), errmsg
        # calculate PER using appropriate method
        plen = len(p.payload)
        if DOT11A_USE_PIECEWISE_PER:
            sinrheap = self.sinr_heap(p, **kwargs)
            t0 = p.getanno("cif-rxts") + DOT11A_TSHORT + DOT11A_TLONG
            t1 = t0 + DOT11A_TSIGNAL
            xheap = [(max(ta, t0), min(tb, t1), sinr) for (ta, tb, sinr) in sinrheap if (ta < t1) and (tb > t0)]
            errmsg = "[DOT11APHY]: Unable to find valid data from SINR heap!"
            assert len(xheap) > 0, errmsg
            # calculate piecewise PER and average SINR
            psuccess, stot = 1.0, 0.0
            for ta, tb, sinr in xheap:
                alpha = (tb - ta) / (t1 - t0)
                hlen = len(Dot11A()) * alpha
                stot += db2linear(sinr) * alpha
                psuccess *= 1.0 - self.calcper(hlen, 0, sinr)
            per = 1.0 - psuccess
            sinr = linear2db(stot)
        else:
            sinr, hlen = self.sinr(p, **kwargs), len(p) - plen
            # configure modulation and coding to calculate PER
            per = self.calcper(hlen, 0, sinr)
        # set annotations and return PER
        p.setanno("dot11a-sinr", sinr)
        p.setanno("dot11a-per", per)
        return per
Ejemplo n.º 30
0
    def sinr(self, p, **kwargs):
        """Calculate signal-to-interference-and-noise ratio (SINR).

        :param p: Packet to compute SINR for.
        :param kwargs: Additional keyword arguments passed to `sinr_heap()`.

        This method uses the 'rxpower', 'noisepower', and 'cif-collision'
        annotations to calculate the SINR of the received packet p.

        :note: This method sets the 'phy-sinr' annotation indicating the SINR (in dB).
        """
        for a in ["rxpower", "noisepower", "cif-collision"]:
            errmsg = "[DOT11APHY]: sinr() cannot find '%s' annotation!" % (a)
            assert ANNO.supports(p, a), errmsg
        # get SINR heap
        sinrheap = self.sinr_heap(p, **kwargs)
        minsinr = +inf
        # find minimum SINR
        for ta, tb, sinr in sinrheap:
            if sinr < minsinr:
                minsinr = sinr
        # set annotations
        p.setanno("phy-sinr", minsinr)
        return minsinr