Example #1
0
 def RXDATA(self, fsm, pkt):
     """RXDATA state; process received DATA message."""
     crcerror = self.haserror(pkt)
     if crcerror:
         self.log_drop(pkt, drop="CRC error")
         yield fsm.goto(self.RESUME)
     assert self.isdot11data(pkt), "[DCF]: Cannot find DATA in RXDATA!"
     data = self.get_dot11data(pkt)
     isbroadcast = (data.addr1==self.broadcast)
     isforme     = (data.addr1==self.address)
     promiscuous = self.promiscuous
     src, dst    = data.addr2, data.addr1
     iseth =  isinstance(data, Packet) and data.haslayer(Ether)
     # isbroadcast or isforme -> send to RXU
     if (isforme or isbroadcast or promiscuous) and iseth:
         self.recv_data(data)
         eth = data[Ether]
         p = crcremove(eth)
         self.log_recv(data, src=src, dst=dst, promiscuous=promiscuous)
         data.remove_payload()
         yield self.TXU.send(fsm, [p])
         assert fsm.stored(self.TXU), \
                 "[DCF]: Error sending packet to 'TXU'!"
         if isforme: yield fsm.goto(self.TXACK, data)
     # non-Ethernet packets or not for me -> drop
     else:
         drop = "non-Ethernet packet"
         if not isforme: drop = "not for me"
         self.log_drop(pkt, src=src, dst=dst, drop=drop)
     # go to RESUME
     yield fsm.goto(self.RESUME)
Example #2
0
 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!"
Example #3
0
 def recv_ack(self, ack):
     """Additional processing for incoming ACK."""
     errmsg = "[DCF]: Cannot process non-ACK in recv_ack()!"
     assert self.isdot11ack(ack), errmsg
     # Expecting ACK?
     if self.isdot11data(self.datatosend):
         data = self.get_dot11data(self.datatosend)
         dst, src = data.addr1, data.addr2
         # ACK for me? -> received ACK -> signal ackdata
         if (src==ack.addr1):
             pkt = self.datatosend.payload
             self.datatosend.remove_payload()
             p = crcremove(pkt)
             self.ackdata.signal(p)
Example #4
0
    def ETHRECV(self, fsm, net, mac, p):
        """ETHRECV state; classify incoming Ethernet packets and pass to
        corrseponding message handler based on ethertype.

        :param net: Associated `NET`.
        :param mac: Associated `MAC`.
        :param p: Ethernet packet to handle.

        If `p` is an ARP Request or Reply, this method will forward the packet
        to `ARPRECV` for handling. Otherwise, this method forwards all other
        received packets to their appropriate message handler based on the
        protocol type of `net` and the ethertype of `p`.

        If `USE_ARPCACHE` is turned on this method will cache ARP information
        using incoming packets.

        :note: If `p` is not an Ethernet frame, this state execution method will
               drop the incoming packet and return to `RECV`.
        """
        errmsg = "[ARP]: In ETHRECV with non-Ethernet htype (%s)!"%(mac.htype)
        assert (mac.htype==const.ARP_HTYPE_ETHERNET), errmsg
        iseth =  isinstance(p,Packet) and p.haslayer(Ether)
        if not iseth:
            self.log_drop(p, drop="non-Ethernet packet in ETHRECV")
            yield fsm.stop()    # HALT packet handler
        # get ethernet frame and payload
        eth = p[Ether]
        hsrc, hdst, ethertype = eth.src, eth.dst, eth.type
        # remove CRC and get payload
        pkt = eth
        if USE_CRC32: pkt = crcremove(eth)
        payload = pkt.payload
        pkt.remove_payload()
        # set MAC annotations from ethernet packet
        payload.setanno('mac-src', eth.src)
        payload.setanno('mac-dst', eth.dst)
        payload.setanno('mac-addr', mac.addr)
        # classify and handle
        if (ethertype==const.ETHERTYPE_IP):
            yield fsm.goto(self.IPRECV, net, mac, payload)
        elif (ethertype==const.ETHERTYPE_ARP):
            yield fsm.goto(self.ARPRECV, net, mac, payload)
        else:
            yield fsm.goto(self.HERRRECV, net, mac, payload)
Example #5
0
    def ETHRECV(self, fsm, p):
        """ETHRECV state; receive ethernet frames.

        By default, this method will find ethernet frames, check for CRC errors
        (if available), and forward error-free packets upstream. All other
        packets will be dropped.

        Packets forwarded upstream will be Ethernet frames stripped of their
        CRC-32 using `crcremove()`. Upon completion, this state execution method
        returns to the `RECV` state.

        :note: If no `CRC32` layer (or 'crcerror' annotation) is available, the
               packet is assumed to be error-free (see `MAC.haserror()`).
        """
        assert (self.htype==const.ARP_HTYPE_ETHERNET), "[ALOHA]: In ETHRECV," +\
                " non-Ethernet hardware type (%s) not allowed!"%(self.htype)
        # drop non-Ethernet packet
        addr = self.address
        iseth = isinstance(p, Packet) and p.haslayer(Ether)
        if not iseth:
            self.log_drop(p, addr=addr, drop="non-Ethernet packet")
            yield fsm.goto(self.RECV)
        # set condition flags
        eth = p[Ether]
        addr, src, dst, etype = self.address, eth.src, eth.dst, eth.type
        crcerror = self.haserror(eth)   # check for errors
        isforme  = (dst==addr) or (dst==self.broadcast)
        promiscuous = self.promiscuous
        kwargs = {'addr':addr,'src':src,'dst':dst,'type':etype} 
        # handle packet
        if (isforme or promiscuous) and (not crcerror):
            pkt = crcremove(eth)
            self.log_recv(pkt,promiscuous=promiscuous,**kwargs)
            yield self.TXU.send(fsm, [pkt])
        elif isforme and crcerror:
            self.log_drop(eth, drop="CRC error", **kwargs)
        else:
            self.log_drop(eth, drop="not for me", **kwargs)
        # return to RECV
        yield fsm.goto(self.RECV)