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)
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 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)
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)
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)