Example #1
0
 def run(self):
     try:
         p =[]
         
         while self.goOn:
             
             # wait for data
             p =  os.read(self.tunIf,self.ETHERNET_MTU)
        
             # convert input from a string to a byte list
             p = [ord(b) for b in p]
             
             # debug info
             if log.isEnabledFor(logging.DEBUG):
                 log.debug('packet captured on tun interface: {0}'.format(u.formatBuf(p)))
 
             # remove tun ID octets
             p = p[4:]
             
             # make sure it's an IPv6 packet (i.e., starts with 0x6x)
             if (p[0]&0xf0) != 0x60:
                 log.info('this is not an IPv6 packet')
                 continue
             
             # because of the nature of tun for Windows, p contains ETHERNET_MTU
             # bytes. Cut at length of IPv6 packet.
             p = p[:self.IPv6_HEADER_LENGTH+256*p[4]+p[5]]
             
             # call the callback
             self.callback(p)
     except Exception as err:
         errMsg=u.formatCrashMessage(self.name,err)
         print errMsg
         log.critical(errMsg)
         sys.exit(1)
Example #2
0
 def _format_IPv6(self, ipv6, ipv6_bytes):
     output = []
     output += ['']
     output += ['']
     output += [
         '============================= IPv6 packet ====================================='
     ]
     output += ['']
     output += ['Version:           {0}'.format(ipv6['version'])]
     output += ['Traffic class:     {0}'.format(ipv6['traffic_class'])]
     output += ['Flow label:        {0}'.format(ipv6['flow_label'])]
     output += ['Payload length:    {0}'.format(ipv6['payload_length'])]
     output += ['Hop Limit:         {0}'.format(ipv6['hop_limit'])]
     output += ['Next header:       {0}'.format(ipv6['next_header'])]
     output += [
         'Source Addr.:      {0}'.format(u.formatIPv6Addr(ipv6['src_addr']))
     ]
     output += [
         'Destination Addr.: {0}'.format(u.formatIPv6Addr(ipv6['dst_addr']))
     ]
     output += [
         'Payload:           {0}'.format(u.formatBuf(ipv6['payload']))
     ]
     output += ['']
     output += [self._formatWireshark(ipv6_bytes)]
     output += ['']
     return '\n'.join(output)
Example #3
0
    def run(self):
        try:
            p = []

            while self.goOn:

                # wait for data
                p = os.read(self.tunIf, self.ETHERNET_MTU)

                # convert input from a string to a byte list
                p = [ord(b) for b in p]

                # debug info
                if log.isEnabledFor(logging.DEBUG):
                    log.debug('packet captured on tun interface: {0}'.format(
                        u.formatBuf(p)))

                # make sure it's an IPv6 packet (i.e., starts with 0x6x)
                if (p[0] & 0xf0) != 0x60:
                    log.info('this is not an IPv6 packet')
                    continue

                # because of the nature of tun for Windows, p contains ETHERNET_MTU
                # bytes. Cut at length of IPv6 packet.
                p = p[:self.IPv6_HEADER_LENGTH + 256 * p[4] + p[5]]

                # call the callback
                self.callback(p)
        except Exception as err:
            errMsg = u.formatCrashMessage(self.name, err)
            print errMsg
            log.critical(errMsg)
            sys.exit(1)
Example #4
0
 def parseInput(self,input):
     
     # log
     if log.isEnabledFor(logging.DEBUG):
         log.debug("received input={0}".format(input))
     
     # ensure input not short longer than header
     self._checkLength(input)
     
     headerBytes = input[:3]
     
     # extract moteId and statusElem
     try:
        (moteId,statusElem) = struct.unpack('<HB',''.join([chr(c) for c in headerBytes]))
     except struct.error:
         raise ParserException(ParserException.DESERIALIZE,"could not extract moteId and statusElem from {0}".format(headerBytes))
     
     # log
     if log.isEnabledFor(logging.DEBUG):
         log.debug("moteId={0} statusElem={1}".format(moteId,statusElem))
     
     # jump the header bytes
     input = input[3:]
     
     # call the next header parser
     for key in self.fieldsParsingKeys:
         if statusElem==key.val:
         
             # log
             if log.isEnabledFor(logging.DEBUG):
                 log.debug("parsing {0}, ({1} bytes) as {2}".format(input,len(input),key.name))
             
             # parse byte array
             try:
                 fields = struct.unpack(key.structure,''.join([chr(c) for c in input]))                     
             except struct.error as err:
                 raise ParserException(
                         ParserException.DESERIALIZE,
                         "could not extract tuple {0} by applying {1} to {2}; error: {3}".format(
                             key.name,
                             key.structure,
                             u.formatBuf(input),
                             str(err)
                         )
                     )
             
             # map to name tuple
             returnTuple = self.named_tuple[key.name](*fields)
             
             # log
             if log.isEnabledFor(logging.DEBUG):
                 log.debug("parsed into {0}".format(returnTuple))
             
             # map to name tuple
             return 'status', returnTuple
     
     # if you get here, no key was found
     raise ParserException(ParserException.NO_KEY, "type={0} (\"{1}\")".format(
         input[0],
         chr(input[0])))
Example #5
0
 def parseInput(self,input):
     
     # log
     if log.isEnabledFor(logging.DEBUG):
         log.debug("received input={0}".format(input))
     
     # ensure input not short longer than header
     self._checkLength(input)
     
     headerBytes = input[:3]
     
     # extract moteId and statusElem
     try:
        (moteId,statusElem) = struct.unpack('<HB',''.join([chr(c) for c in headerBytes]))
     except struct.error:
         raise ParserException(ParserException.DESERIALIZE,"could not extract moteId and statusElem from {0}".format(headerBytes))
     
     # log
     if log.isEnabledFor(logging.DEBUG):
         log.debug("moteId={0} statusElem={1}".format(moteId,statusElem))
     
     # jump the header bytes
     input = input[3:]
     
     # call the next header parser
     for key in self.fieldsParsingKeys:
         if statusElem==key.val:
         
             # log
             if log.isEnabledFor(logging.DEBUG):
                 log.debug("parsing {0}, ({1} bytes) as {2}".format(input,len(input),key.name))
             
             # parse byte array
             try:
                 fields = struct.unpack(key.structure,''.join([chr(c) for c in input]))                     
             except struct.error as err:
                 raise ParserException(
                         ParserException.DESERIALIZE,
                         "could not extract tuple {0} by applying {1} to {2}; error: {3}".format(
                             key.name,
                             key.structure,
                             u.formatBuf(input),
                             str(err)
                         )
                     )
             
             # map to name tuple
             returnTuple = self.named_tuple[key.name](*fields)
             
             # log
             if log.isEnabledFor(logging.DEBUG):
                 log.debug("parsed into {0}".format(returnTuple))
             
             # map to name tuple
             return ('status',returnTuple)
     
     # if you get here, no key was found
     raise ParserException(ParserException.NO_KEY, "type={0} (\"{1}\")".format(
         input[0],
         chr(input[0])))
Example #6
0
 def _format_lowpan(self, lowpan, lowpan_bytes):
     output = []
     output += ['']
     output += ['']
     output += [
         '============================= lowpan packet ==================================='
     ]
     output += ['']
     output += ['tf:                {0}'.format(u.formatBuf(lowpan['tf']))]
     output += ['nh:                {0}'.format(u.formatBuf(lowpan['nh']))]
     output += [
         'hlim:              {0}'.format(u.formatBuf(lowpan['hlim']))
     ]
     output += ['cid:               {0}'.format(u.formatBuf(lowpan['cid']))]
     output += [
         'src_addr:          {0}'.format(u.formatBuf(lowpan['src_addr']))
     ]
     output += [
         'dst_addr:          {0}'.format(u.formatBuf(lowpan['dst_addr']))
     ]
     if 'route' in lowpan:
         output += ['source route:']
         for hop in lowpan['route']:
             output += [' - {0}'.format(u.formatAddr(hop))]
     output += [
         'payload:           {0}'.format(u.formatBuf(lowpan['payload']))
     ]
     output += ['']
     output += [self._formatWireshark(lowpan_bytes)]
     output += ['']
     return '\n'.join(output)
Example #7
0
 def _format_IPv6(self,ipv6,ipv6_bytes):
     output  = []
     output += ['']
     output += ['']
     output += ['============================= IPv6 packet =====================================']
     output += ['']
     output += ['Version:           {0}'.format(ipv6['version'])]
     output += ['Traffic class:     {0}'.format(ipv6['traffic_class'])]
     output += ['Flow label:        {0}'.format(ipv6['flow_label'])]
     output += ['Payload length:    {0}'.format(ipv6['payload_length'])]
     output += ['Hop Limit:         {0}'.format(ipv6['hop_limit'])]
     output += ['Next header:       {0}'.format(ipv6['next_header'])]
     output += ['Source Addr.:      {0}'.format(u.formatIPv6Addr(ipv6['src_addr']))]
     output += ['Destination Addr.: {0}'.format(u.formatIPv6Addr(ipv6['dst_addr']))]
     output += ['Payload:           {0}'.format(u.formatBuf(ipv6['payload']))]
     output += ['']
     output += [self._formatWireshark(ipv6_bytes)]
     output += ['']
     return '\n'.join(output)
Example #8
0
 def _format_lowpan(self,lowpan,lowpan_bytes):
     output          = []
     output         += ['']
     output         += ['']
     output         += ['============================= lowpan packet ===================================']
     output         += ['']
     output         += ['tf:                {0}'.format(u.formatBuf(lowpan['tf']))]
     output         += ['nh:                {0}'.format(u.formatBuf(lowpan['nh']))]
     output         += ['hlim:              {0}'.format(u.formatBuf(lowpan['hlim']))]
     output         += ['cid:               {0}'.format(u.formatBuf(lowpan['cid']))]
     output         += ['src_addr:          {0}'.format(u.formatBuf(lowpan['src_addr']))]
     output         += ['dst_addr:          {0}'.format(u.formatBuf(lowpan['dst_addr']))]
     if 'route' in lowpan:
         output     += ['source route:']
         for hop in lowpan['route']:
             output += [' - {0}'.format(u.formatAddr(hop))]
     output         += ['payload:           {0}'.format(u.formatBuf(lowpan['payload']))]
     output += ['']
     output += [self._formatWireshark(lowpan_bytes)]
     output += ['']
     return '\n'.join(output)
Example #9
0
    def _eventBusNotification(self,signal,sender,data):
        '''
        Adds the signal to stats log and performs signal-specific handling
        '''
        
        with self.dataLock:
            key = (sender,signal)
            if key not in self.stats:
                self.stats[key] = 0
            self.stats[key] += 1
        
        if signal=='infoDagRoot' and data['isDAGroot']==1:
            self.dagRootEui64 = data['eui64'][:]
        
        if signal=='wirelessTxStart':
            # this signal only exists is simulation mode
            self.simMode = True
        
        if self.wiresharkDebugEnabled:
            
            if self.simMode:
                # simulation mode
                
                if signal=='wirelessTxStart':
                    # Forwards a copy of the packet exchanged between simulated motes
                    # to the tun interface for debugging.
                    
                    (moteId,frame,frequency) = data
                    
                    if log.isEnabledFor(logging.DEBUG):
                        output  = []
                        output += ['']
                        output += ['- moteId:    {0}'.format(moteId)]
                        output += ['- frame:     {0}'.format(u.formatBuf(frame))]
                        output += ['- frequency: {0}'.format(frequency)]
                        output  = '\n'.join(output)
                        log.debug(output)
                        print output # poipoi
                    
                    assert len(frame)>=1+2 # 1 for length byte, 2 for CRC
                    
                    # cut frame in pieces
                    length = frame[0]
                    body   = frame[1:-2]
                    crc    = frame[-2:]
                    
                    # wrap with zep header
                    zep   = self._wrapZepCrc(body,frequency)
                    self._dispatchMeshDebugPacket(zep)
            
            else:
                # non-simulation mode
                
                if signal=='fromMote.data':
                    # Forwards a copy of the data received from a mode
                    # to the Internet interface for debugging.
                    (previousHop,lowpan) = data
                    
                    zep = self._wrapMacAndZep(
                        previousHop  = previousHop,
                        nextHop      = self.dagRootEui64,
                        lowpan       = lowpan,
                    )
                    self._dispatchMeshDebugPacket(zep)

                if signal=='fromMote.sniffedPacket':
                    body      = data[0:-3]
                    crc       = data[-3:-1]
                    frequency = data[-1]

                    # wrap with zep header
                    zep   = self._wrapZepCrc(body,frequency)
                    self._dispatchMeshDebugPacket(zep)
                    
                if signal=='bytesToMesh':
                    # Forwards a copy of the 6LoWPAN packet destined for the mesh 
                    # to the tun interface for debugging.
                    (nextHop,lowpan) = data
                    
                    zep = self._wrapMacAndZep(
                        previousHop  = self.dagRootEui64,
                        nextHop      = nextHop,
                        lowpan       = lowpan,
                    )
                    self._dispatchMeshDebugPacket(zep)
Example #10
0
 def _indicateDAO(self,tup):
     '''
     Indicate a new DAO was received.
     
     This function parses the received packet, and if valid, updates the
     information needed to compute source routes.
     '''
     
     # retrieve source and destination
     try:
         source                = tup[0]
         if len(source)>8: 
             source=source[len(source)-8:]
         dao                   = tup[1]
     except IndexError:
         log.warning("DAO too short ({0} bytes), no space for destination and source".format(len(dao)))
         return
     
     # log
     if log.isEnabledFor(logging.DEBUG):
         output                = []
         output               += ['received DAO:']
         output               += ['- source :      {0}'.format(u.formatAddr(source))]
         output               += ['- dao :         {0}'.format(u.formatBuf(dao))]
         output                = '\n'.join(output)
         log.debug(output)
     
     # retrieve DAO header
     dao_header                = {}
     dao_transit_information   = {}
     dao_target_information    = {}
     
     try:
         # RPL header
         dao_header['RPL_InstanceID']    = dao[0]
         dao_header['RPL_flags']         = dao[1]
         dao_header['RPL_Reserved']      = dao[2]
         dao_header['RPL_DAO_Sequence']  = dao[3]
         # DODAGID
         dao_header['DODAGID']           = dao[4:20]
        
         dao                             = dao[20:]
         # retrieve transit information header and parents
         parents                         = []
         children                        = []
                       
         while len(dao)>0:
             if   dao[0]==self._TRANSIT_INFORMATION_TYPE: 
                 # transit information option
                 dao_transit_information['Transit_information_type']             = dao[0]
                 dao_transit_information['Transit_information_length']           = dao[1]
                 dao_transit_information['Transit_information_flags']            = dao[2]
                 dao_transit_information['Transit_information_path_control']     = dao[3]
                 dao_transit_information['Transit_information_path_sequence']    = dao[4]
                 dao_transit_information['Transit_information_path_lifetime']    = dao[5]
                 # address of the parent
                 prefix        =  dao[6:14]
                 parents      += [dao[14:22]]
                 dao           = dao[22:]
             elif dao[0]==self._TARGET_INFORMATION_TYPE:
                 dao_target_information['Target_information_type']               = dao[0]
                 dao_target_information['Target_information_length']             = dao[1]
                 dao_target_information['Target_information_flags']              = dao[2]
                 dao_target_information['Target_information_prefix_length']      = dao[3]
                 # address of the child
                 prefix        =  dao[4:12]
                 children     += [dao[12:20]]
                 dao           = dao[20:]
             else:
                 log.warning("DAO with wrong Option {0}. Neither Transit nor Target.".format(dao[0]))
                 return
     except IndexError:
         log.warning("DAO too short ({0} bytes), no space for DAO header".format(len(dao)))
         return
     
     # log
     output               = []
     output              += ['']
     output              += ['received RPL DAO from {0}:{1}'.format(u.formatIPv6Addr(self.networkPrefix),u.formatIPv6Addr(source))]
     output              += ['- parents:']
     for p in parents:
         output          += ['   {0}:{1}'.format(u.formatIPv6Addr(self.networkPrefix),u.formatIPv6Addr(p))]
     output              += ['- children:']
     for p in children:
         output          += ['   {0}:{1}'.format(u.formatIPv6Addr(self.networkPrefix),u.formatIPv6Addr(p))]
     output               = '\n'.join(output)
     if log.isEnabledFor(logging.DEBUG):
         log.debug(output)
     print output
     
     node = u.formatIPv6Addr(source)
     if not (node in self.parentsDaoSeq.keys()):
         self.parentsDaoSeq[node] = [dao_header['RPL_DAO_Sequence']]
     else:
         self.parentsDaoSeq[node].append(dao_header['RPL_DAO_Sequence'])
     
     with open('dao_sequence.txt','a') as f:
         f.write(str(self.parentsDaoSeq)+'\n')
     
     # if you get here, the DAO was parsed correctly
     
     # update parents information with parents collected -- calls topology module.
     self.dispatch(          
         signal          = 'updateParents',
         data            =  (tuple(source),parents)  
     )
Example #11
0
 def _indicateDAO(self,tup):
     '''
     Indicate a new DAO was received.
     
     This function parses the received packet, and if valid, updates the
     information needed to compute source routes.
     '''
     
     # retrieve source and destination
     try:
         source                = tup[0]
         if len(source)>8: 
             source=source[len(source)-8:]
         dao                   = tup[1]
     except IndexError:
         log.warning("DAO too short ({0} bytes), no space for destination and source".format(len(dao)))
         return
     
     # log
     if log.isEnabledFor(logging.DEBUG):
         output                = []
         output               += ['received DAO:']
         output               += ['- source :      {0}'.format(u.formatAddr(source))]
         output               += ['- dao :         {0}'.format(u.formatBuf(dao))]
         output                = '\n'.join(output)
         log.debug(output)
     
     # retrieve DAO header
     dao_header                = {}
     dao_transit_information   = {}
     dao_target_information    = {}
     
     try:
         # RPL header
         dao_header['RPL_InstanceID']    = dao[0]
         dao_header['RPL_flags']         = dao[1]
         dao_header['RPL_Reserved']      = dao[2]
         dao_header['RPL_DAO_Sequence']  = dao[3]
         # DODAGID
         dao_header['DODAGID']           = dao[4:20]
        
         dao                             = dao[20:]
         # retrieve transit information header and parents
         parents                         = []
         children                        = []
                       
         while len(dao)>0:
             if   dao[0]==self._TRANSIT_INFORMATION_TYPE: 
                 # transit information option
                 dao_transit_information['Transit_information_type']             = dao[0]
                 dao_transit_information['Transit_information_length']           = dao[1]
                 dao_transit_information['Transit_information_flags']            = dao[2]
                 dao_transit_information['Transit_information_path_control']     = dao[3]
                 dao_transit_information['Transit_information_path_sequence']    = dao[4]
                 dao_transit_information['Transit_information_path_lifetime']    = dao[5]
                 # address of the parent
                 prefix        =  dao[6:14]
                 parents      += [dao[14:22]]
                 dao           = dao[22:]
             elif dao[0]==self._TARGET_INFORMATION_TYPE:
                 dao_target_information['Target_information_type']               = dao[0]
                 dao_target_information['Target_information_length']             = dao[1]
                 dao_target_information['Target_information_flags']              = dao[2]
                 dao_target_information['Target_information_prefix_length']      = dao[3]
                 # address of the child
                 prefix        =  dao[4:12]
                 children     += [dao[12:20]]
                 dao           = dao[20:]
             else:
                 log.warning("DAO with wrong Option {0}. Neither Transit nor Target.".format(dao[0]))
                 return
     except IndexError:
         log.warning("DAO too short ({0} bytes), no space for DAO header".format(len(dao)))
         return
     
     # log
     output               = []
     output              += ['']
     output              += ['received RPL DAO from {0}:{1}'.format(u.formatIPv6Addr(self.networkPrefix),u.formatIPv6Addr(source))]
     output              += ['- parents:']
     for p in parents:
         output          += ['   {0}:{1}'.format(u.formatIPv6Addr(self.networkPrefix),u.formatIPv6Addr(p))]
     output              += ['- children:']
     for p in children:
         output          += ['   {0}:{1}'.format(u.formatIPv6Addr(self.networkPrefix),u.formatIPv6Addr(p))]
     output               = '\n'.join(output)
     if log.isEnabledFor(logging.DEBUG):
         log.debug(output)
     print output
     
     # if you get here, the DAO was parsed correctly
     
     # update parents information with parents collected -- calls topology module.
     self.dispatch(          
         signal          = 'updateParents',
         data            =  (tuple(source),parents)  
     )
Example #12
0
    def _sendDIO(self):
        """
        Send a DIO.
        """

        # don't send DIO if I didn't discover the DAGroot's EUI64
        if not self.dagRootEui64:
            return

        # the list of bytes to be sent to the DAGroot.
        # - [8B]       destination MAC address
        # - [variable] IPHC+ header
        dio = []

        # next hop: broadcast address
        nextHop = [0xFF] * 8

        # IPHC header
        dio += [0x78]  # dispatch byte
        dio += [0x33]  # dam sam
        idxNH = len(dio)
        dio += [0x3A]  # next header (0x3A=ICMPv6)
        dio += [0x00]  # HLIM

        # ICMPv6 header
        idxICMPv6 = len(dio)  # remember where ICMPv6 starts
        dio += [155]  # ICMPv6 type (155=RPL)
        dio += [0x01]  # ICMPv6 CODE (for RPL 0x01=DIO)
        idxICMPv6CS = len(dio)  # remember where ICMPv6 checksum starts
        dio += [0x00, 0x00]  # placeholder for checksum (filled out later)

        # DIO header
        dio += [0x00]  # instance ID
        dio += [0x00]  # version number
        dio += [0x00, 0x00]  # rank
        dio += [self.DIO_OPT_GROUNDED | self.MOP_DIO_A | self.MOP_DIO_B | self.MOP_DIO_C]  # options: G | 0 | MOP | Prf
        dio += [0x00]  # DTSN
        dio += [0x00]  # flags
        dio += [0x00]  # reserved

        # DODAGID
        with self.stateLock:
            idxSrc = len(dio)  # this is a little hack as the source is the dodag
            dio += self.networkPrefix
            dio += self.dagRootEui64

        # wireshark calculates the IPv6 source and destination from the
        # 6LoWPAN header. It is lot aware of the network prefix and uses
        # link-local addresses. We do the same in this implementation to avoid
        # checksum errors in Wireshark.
        wiresharkSrc = [0xFE, 0x80] + [0x00] * 6 + [dio[idxSrc + 8] | 0x02] + dio[idxSrc + 9 : idxSrc + 16]
        wiresharkDst = [0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0xFF, 0xFF]

        # calculate ICMPv6 checksum over ICMPv6header+ (RFC4443)
        checksum = u.calculatePseudoHeaderCRC(
            src=wiresharkSrc,
            dst=wiresharkDst,
            length=[0x00, 0x00, 0x00, len(dio[idxICMPv6:])],
            nh=[0x00] + dio[idxNH : idxNH + 1],
            payload=dio[idxICMPv6:],
        )

        dio[idxICMPv6CS] = checksum[0]
        dio[idxICMPv6CS + 1] = checksum[1]

        # log
        if log.isEnabledFor(logging.DEBUG):
            log.debug("sending DIO {0}".format(u.formatBuf(dio)))

        # dispatch
        self.dispatch(signal="bytesToMesh", data=(nextHop, dio))
Example #13
0
    def _eventBusNotification(self, signal, sender, data):
        '''
        Adds the signal to stats log and performs signal-specific handling
        '''

        with self.dataLock:
            key = (sender, signal)
            if key not in self.stats:
                self.stats[key] = 0
            self.stats[key] += 1

        if signal == 'infoDagRoot' and data['isDAGroot'] == 1:
            self.dagRootEui64 = data['eui64'][:]

        if signal == 'wirelessTxStart':
            # this signal only exists is simulation mode
            self.simMode = True

        if self.wiresharkDebugEnabled:

            if self.simMode:
                # simulation mode

                if signal == 'wirelessTxStart':
                    # Forwards a copy of the packet exchanged between simulated motes
                    # to the tun interface for debugging.

                    (moteId, frame, frequency) = data

                    if log.isEnabledFor(logging.DEBUG):
                        output = []
                        output += ['']
                        output += ['- moteId:    {0}'.format(moteId)]
                        output += [
                            '- frame:     {0}'.format(u.formatBuf(frame))
                        ]
                        output += ['- frequency: {0}'.format(frequency)]
                        output = '\n'.join(output)
                        log.debug(output)
                        print output  # poipoi

                    assert len(frame) >= 1 + 2  # 1 for length byte, 2 for CRC

                    # cut frame in pieces
                    length = frame[0]
                    body = frame[1:-2]
                    crc = frame[-2:]

                    # wrap with zep header
                    zep = self._wrapZepCrc(body, frequency)
                    self._dispatchMeshDebugPacket(zep)

            else:
                # non-simulation mode

                if signal == 'fromMote.data':
                    # Forwards a copy of the data received from a mode
                    # to the Internet interface for debugging.
                    (previousHop, lowpan) = data

                    zep = self._wrapMacAndZep(
                        previousHop=previousHop,
                        nextHop=self.dagRootEui64,
                        lowpan=lowpan,
                    )
                    self._dispatchMeshDebugPacket(zep)

                if signal == 'bytesToMesh':
                    # Forwards a copy of the 6LoWPAN packet destined for the mesh
                    # to the tun interface for debugging.
                    (nextHop, lowpan) = data

                    zep = self._wrapMacAndZep(
                        previousHop=self.dagRootEui64,
                        nextHop=nextHop,
                        lowpan=lowpan,
                    )
                    self._dispatchMeshDebugPacket(zep)
Example #14
0
    def _sendDIO(self):
        '''
        Send a DIO.
        '''

        # don't send DIO if I didn't discover the DAGroot's EUI64
        if not self.dagRootEui64:
            return

        # the list of bytes to be sent to the DAGroot.
        # - [8B]       destination MAC address
        # - [variable] IPHC+ header
        dio = []

        # next hop: broadcast address
        nextHop = [0xff] * 8

        # IPHC header
        dio += [0x78]  # dispatch byte
        dio += [0x33]  # dam sam
        idxNH = len(dio)
        dio += [0x3A]  # next header (0x3A=ICMPv6)
        dio += [0x00]  # HLIM

        # ICMPv6 header
        idxICMPv6 = len(dio)  # remember where ICMPv6 starts
        dio += [155]  # ICMPv6 type (155=RPL)
        dio += [0x01]  # ICMPv6 CODE (for RPL 0x01=DIO)
        idxICMPv6CS = len(dio)  # remember where ICMPv6 checksum starts
        dio += [0x00, 0x00]  # placeholder for checksum (filled out later)

        # DIO header
        dio += [0x00]  # instance ID
        dio += [0x00]  # version number
        dio += [0x00, 0x00]  # rank
        dio += [
            self.DIO_OPT_GROUNDED | self.MOP_DIO_A | self.MOP_DIO_B
            | self.MOP_DIO_C
        ]  # options: G | 0 | MOP | Prf
        dio += [0x00]  # DTSN
        dio += [0x00]  # flags
        dio += [0x00]  # reserved

        # DODAGID
        with self.stateLock:
            idxSrc = len(
                dio)  # this is a little hack as the source is the dodag
            dio += self.networkPrefix
            dio += self.dagRootEui64

        # wireshark calculates the IPv6 source and destination from the
        # 6LoWPAN header. It is lot aware of the network prefix and uses
        # link-local addresses. We do the same in this implementation to avoid
        # checksum errors in Wireshark.
        wiresharkSrc = [0xfe, 0x80] + [0x00] * 6 + [
            dio[idxSrc + 8] | 0x02
        ] + dio[idxSrc + 9:idxSrc + 16]
        wiresharkDst = [
            0xfe,
            0x80,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0xff,
            0xfe,
            0x00,
            0xff,
            0xff,
        ]

        # calculate ICMPv6 checksum over ICMPv6header+ (RFC4443)
        checksum = u.calculatePseudoHeaderCRC(
            src=wiresharkSrc,
            dst=wiresharkDst,
            length=[0x00, 0x00, 0x00, len(dio[idxICMPv6:])],
            nh=[0x00] + dio[idxNH:idxNH + 1],
            payload=dio[idxICMPv6:],
        )

        dio[idxICMPv6CS] = checksum[0]
        dio[idxICMPv6CS + 1] = checksum[1]

        # log
        if log.isEnabledFor(logging.DEBUG):
            log.debug('sending DIO {0}'.format(u.formatBuf(dio)))

        # dispatch
        self.dispatch(signal='bytesToMesh', data=(nextHop, dio))