Esempio n. 1
0
/**
\brief Trigger this module to print status information, over serial.

debugPrint_* functions are used by the openserial module to continuously print
status information about several modules in the OpenWSN stack.

\returns TRUE if this function printed something, FALSE otherwise.
*/
bool debugPrint_myDAGrank() {
   uint16_t output;
   
   output = 0;
   
   output = neighbors_getMyDAGrank();
   openserial_printStatus(STATUS_DAGRANK,(uint8_t*)&output,sizeof(uint16_t));
   return TRUE;
}
Esempio n. 2
0
/**
\brief Indicate whether some neighbor has a lower DAG rank that me.

\param[in] index The index of that neighbor in the neighbor table.

\returns TRUE if that neighbor has a lower DAG rank than me, FALSE otherwise.
*/
bool neighbors_isNeighborWithHigherDAGrank(uint8_t index) {
   bool    returnVal;
   
   if (neighbors_vars.neighbors[index].used==TRUE &&
       neighbors_vars.neighbors[index].DAGrank >= neighbors_getMyDAGrank()) { 
      returnVal = TRUE;
   } else {
      returnVal = FALSE;
   }
   
   return returnVal;
}
Esempio n. 3
0
/**
\brief Create a RPL option.

\param[out] rpl_option A pointer to the structure to fill in.
\param[in]  flags      The flags to indicate in the RPL option.
*/
void forwarding_createRplOption(OpenMote* self, rpl_option_ht* rpl_option, uint8_t flags) {
    uint8_t I,K;
    rpl_option->optionType         = RPL_HOPBYHOP_HEADER_OPTION_TYPE;
    rpl_option->rplInstanceID      = icmpv6rpl_getRPLIntanceID(self);
    rpl_option->senderRank         = neighbors_getMyDAGrank(self);
   
    if (rpl_option->rplInstanceID == 0){
       I = 1;
    } else {
       I = 0;
    }
    
    if ((rpl_option->senderRank & 0x00FF) == 0){
        K = 1;
    } else {
        K = 0;
    }
    
    rpl_option->flags = (flags & ~I_FLAG & ~K_FLAG) | (I<<1) | K;
}
Esempio n. 4
0
/**
\brief Prepare and a send a RPL DAO.
*/
void sendDAO() {
   OpenQueueEntry_t*    msg;                // pointer to DAO messages
   uint8_t              nbrIdx;             // running neighbor index
   uint8_t              numTransitParents,numTargetParents;  // the number of parents indicated in transit option
   open_addr_t         address;
   open_addr_t*        prefix;
   
   if (ieee154e_isSynch()==FALSE) {
      // I'm not sync'ed 
      
      // delete packets genereted by this module (DIO and DAO) from openqueue
      openqueue_removeAllCreatedBy(COMPONENT_ICMPv6RPL);
      
      // I'm not busy sending a DIO/DAO
      icmpv6rpl_vars.busySending = FALSE;
      
      // stop here
      return;
   }
   
   // dont' send a DAO if you're in bridge mode
   if (idmanager_getIsBridge()==TRUE) {
      return;
   }
   
   // dont' send a DAO if you did not acquire a DAGrank
   if (neighbors_getMyDAGrank()==DEFAULTDAGRANK) {
       return;
   }
   
   // dont' send a DAO if you're still busy sending the previous one
   if (icmpv6rpl_vars.busySending==TRUE) {
      return;
   }
   
   // if you get here, you start construct DAO
   
   // reserve a free packet buffer for DAO
   msg = openqueue_getFreePacketBuffer(COMPONENT_ICMPv6RPL);
   if (msg==NULL) {
      openserial_printError(COMPONENT_ICMPv6RPL,ERR_NO_FREE_PACKET_BUFFER,
                            (errorparameter_t)0,
                            (errorparameter_t)0);
      return;
   }
   
   // take ownership
   msg->creator                             = COMPONENT_ICMPv6RPL;
   msg->owner                               = COMPONENT_ICMPv6RPL;
   
   // set transport information
   msg->l4_protocol                         = IANA_ICMPv6;
   msg->l4_sourcePortORicmpv6Type           = IANA_ICMPv6_RPL;
   
   // set DAO destination
   msg->l3_destinationAdd.type=ADDR_128B;
   memcpy(msg->l3_destinationAdd.addr_128b,icmpv6rpl_vars.dio.DODAGID,sizeof(icmpv6rpl_vars.dio.DODAGID));
   
   //===== fill in packet
   
   //NOTE: limit to preferrred parent only the number of DAO transit addresses to send
   
   //=== transit option -- from RFC 6550, page 55 - 1 transit information header per parent is required. 
   //getting only preferred parent as transit
   numTransitParents=0;
   neighbors_getPreferredParentEui64(&address);
   packetfunctions_writeAddress(msg,&address,OW_BIG_ENDIAN);
   prefix=idmanager_getMyID(ADDR_PREFIX);
   packetfunctions_writeAddress(msg,prefix,OW_BIG_ENDIAN);
   // update transit info fields
   // from rfc6550 p.55 -- Variable, depending on whether or not the DODAG ParentAddress subfield is present.
   // poipoi xv: it is not very clear if this includes all fields in the header. or as target info 2 bytes are removed.
   // using the same pattern as in target information.
   icmpv6rpl_vars.dao_transit.optionLength  = LENGTH_ADDR128b + sizeof(icmpv6rpl_dao_transit_ht)-2;
   icmpv6rpl_vars.dao_transit.PathControl=0; //todo. this is to set the preference of this parent.      
   icmpv6rpl_vars.dao_transit.type=OPTION_TRANSIT_INFORMATION_TYPE;
           
   // write transit info in packet
   packetfunctions_reserveHeaderSize(msg,sizeof(icmpv6rpl_dao_transit_ht));
   memcpy(
          ((icmpv6rpl_dao_transit_ht*)(msg->payload)),
          &(icmpv6rpl_vars.dao_transit),
          sizeof(icmpv6rpl_dao_transit_ht)
   );
   numTransitParents++;
   
   //target information is required. RFC 6550 page 55.
   /*
   One or more Transit Information options MUST be preceded by one or
   more RPL Target options.   
   */
    numTargetParents                        = 0;
    for (nbrIdx=0;nbrIdx<MAXNUMNEIGHBORS;nbrIdx++) {
      if ((neighbors_isNeighborWithHigherDAGrank(nbrIdx))==TRUE) {
         // this neighbor is of higher DAGrank as I am. so it is my child
         
         // write it's address in DAO RFC6550 page 80 check point 1.
         neighbors_getNeighbor(&address,ADDR_64B,nbrIdx); 
         packetfunctions_writeAddress(msg,&address,OW_BIG_ENDIAN);
         prefix=idmanager_getMyID(ADDR_PREFIX);
         packetfunctions_writeAddress(msg,prefix,OW_BIG_ENDIAN);
        
         // update target info fields 
         // from rfc6550 p.55 -- Variable, length of the option in octets excluding the Type and Length fields.
         // poipoi xv: assuming that type and length fields refer to the 2 first bytes of the header
         icmpv6rpl_vars.dao_target.optionLength  = LENGTH_ADDR128b +sizeof(icmpv6rpl_dao_target_ht) - 2; //no header type and length
         icmpv6rpl_vars.dao_target.type  = OPTION_TARGET_INFORMATION_TYPE;
         icmpv6rpl_vars.dao_target.flags  = 0;       //must be 0
         icmpv6rpl_vars.dao_target.prefixLength = 128; //128 leading bits  -- full address.
         
         // write transit info in packet
         packetfunctions_reserveHeaderSize(msg,sizeof(icmpv6rpl_dao_target_ht));
         memcpy(
               ((icmpv6rpl_dao_target_ht*)(msg->payload)),
               &(icmpv6rpl_vars.dao_target),
               sizeof(icmpv6rpl_dao_target_ht)
         );
         
         // remember I found it
         numTargetParents++;
      }  
      //limit to MAX_TARGET_PARENTS the number of DAO target addresses to send
      //section 8.2.1 pag 67 RFC6550 -- using a subset
      // poipoi TODO base selection on ETX rather than first X.
      if (numTargetParents>=MAX_TARGET_PARENTS) break;
   }
   
   
   // stop here if no parents found
   if (numTransitParents==0) {
      openqueue_freePacketBuffer(msg);
      return;
   }
   
   icmpv6rpl_vars.dao_transit.PathSequence++; //increment path sequence.
   // if you get here, you will send a DAO
   
   
   //=== DAO header
   packetfunctions_reserveHeaderSize(msg,sizeof(icmpv6rpl_dao_ht));
   memcpy(
      ((icmpv6rpl_dao_ht*)(msg->payload)),
      &(icmpv6rpl_vars.dao),
      sizeof(icmpv6rpl_dao_ht)
   );
   
   //=== ICMPv6 header
   packetfunctions_reserveHeaderSize(msg,sizeof(ICMPv6_ht));
   ((ICMPv6_ht*)(msg->payload))->type       = msg->l4_sourcePortORicmpv6Type;
   ((ICMPv6_ht*)(msg->payload))->code       = IANA_ICMPv6_RPL_DAO;
   packetfunctions_calculateChecksum(msg,(uint8_t*)&(((ICMPv6_ht*)(msg->payload))->checksum)); //call last
   
   //===== send
   if (icmpv6_send(msg)==E_SUCCESS) {
      icmpv6rpl_vars.busySending = TRUE;
   } else {
      openqueue_freePacketBuffer(msg);
   }
}
Esempio n. 5
0
/**
\brief Prepare and a send a RPL DIO.
*/
void sendDIO() {
   OpenQueueEntry_t*    msg;
   
   // stop if I'm not sync'ed
   if (ieee154e_isSynch()==FALSE) {
      
      // remove packets genereted by this module (DIO and DAO) from openqueue
      openqueue_removeAllCreatedBy(COMPONENT_ICMPv6RPL);
      
      // I'm not busy sending a DIO/DAO
      icmpv6rpl_vars.busySending  = FALSE;
      
      // stop here
      return;
   }
      
   // do not send DIO if I'm in in bridge mode
   if (idmanager_getIsBridge()==TRUE) {
      return;
   }
   
   // do not send DIO if I have the default DAG rank
   if (neighbors_getMyDAGrank()==DEFAULTDAGRANK) {
      return;
   }
   
   // do not send DIO if I'm already busy sending
   if (icmpv6rpl_vars.busySending==TRUE) {
      return;
   }
   
   // if you get here, all good to send a DIO
   
   // I'm now busy sending
   icmpv6rpl_vars.busySending = TRUE;
   
   // reserve a free packet buffer for DIO
   msg = openqueue_getFreePacketBuffer(COMPONENT_ICMPv6RPL);
   if (msg==NULL) {
      openserial_printError(COMPONENT_ICMPv6RPL,ERR_NO_FREE_PACKET_BUFFER,
                            (errorparameter_t)0,
                            (errorparameter_t)0);
      icmpv6rpl_vars.busySending = FALSE;
      
      return;
   }
   
   // take ownership
   msg->creator                             = COMPONENT_ICMPv6RPL;
   msg->owner                               = COMPONENT_ICMPv6RPL;
   
   // set transport information
   msg->l4_protocol                         = IANA_ICMPv6;
   msg->l4_sourcePortORicmpv6Type           = IANA_ICMPv6_RPL;
   
   // set DIO destination
   memcpy(&(msg->l3_destinationAdd),&icmpv6rpl_vars.dioDestination,sizeof(open_addr_t));
   
   //===== DIO payload
   // note: DIO is already mostly populated
   icmpv6rpl_vars.dio.rank                  = neighbors_getMyDAGrank();
   packetfunctions_reserveHeaderSize(msg,sizeof(icmpv6rpl_dio_ht));
   memcpy(
      ((icmpv6rpl_dio_ht*)(msg->payload)),
      &(icmpv6rpl_vars.dio),
      sizeof(icmpv6rpl_dio_ht)
   );
   
   //===== ICMPv6 header
   packetfunctions_reserveHeaderSize(msg,sizeof(ICMPv6_ht));
   ((ICMPv6_ht*)(msg->payload))->type       = msg->l4_sourcePortORicmpv6Type;
   ((ICMPv6_ht*)(msg->payload))->code       = IANA_ICMPv6_RPL_DIO;
   packetfunctions_calculateChecksum(msg,(uint8_t*)&(((ICMPv6_ht*)(msg->payload))->checksum));//call last
   
   //send
   if (icmpv6_send(msg)!=E_SUCCESS) {
      icmpv6rpl_vars.busySending = FALSE;
      openqueue_freePacketBuffer(msg);
   } else {
      icmpv6rpl_vars.busySending = FALSE; 
   }
}
Esempio n. 6
0
/**
\brief Indicates a packet was received.

\param[in,out] msg               The packet just sent.
\param[in]     ipv6_header       The information contained in the IPv6 header.
\param[in]     ipv6_hop_header   The hop-by-hop header present in the packet.
\param[in]     rpl_option        The hop-by-hop options present in the packet.
*/
void forwarding_receive(
      OpenQueueEntry_t*      msg,
      ipv6_header_iht*       ipv6_header,
      ipv6_hopbyhop_iht*     ipv6_hop_header,
      rpl_option_ht*         rpl_option
   ) {
   uint8_t flags;
   uint16_t senderRank;
   
   // take ownership
   msg->owner                     = COMPONENT_FORWARDING;
   
   // determine L4 protocol
   if (ipv6_header->next_header==IANA_IPv6HOPOPT){
      // get information from ipv6_hop_header
      
      msg->l4_protocol            = ipv6_hop_header->nextHeader;
      msg->l4_protocol_compressed = ipv6_hop_header->next_header_compressed;
   } else {
      // get information from ipv6_header
      
      msg->l4_protocol            = ipv6_header->next_header;
      msg->l4_protocol_compressed = ipv6_header->next_header_compressed;
   }
   
   // populate packets metadata with L3 information
   memcpy(&(msg->l3_destinationAdd),&ipv6_header->dest,sizeof(open_addr_t));
   memcpy(&(msg->l3_sourceAdd),     &ipv6_header->src, sizeof(open_addr_t));
   
   if (
         (
            idmanager_isMyAddress(&ipv6_header->dest)
            ||
            packetfunctions_isBroadcastMulticast(&ipv6_header->dest)
         )
         &&
         ipv6_header->next_header!=IANA_IPv6ROUTE
      ) {
      // this packet is for me, no source routing header.

      // indicate received packet to upper layer
      switch(msg->l4_protocol) {
         case IANA_TCP:
            opentcp_receive(msg);
            break;
         case IANA_UDP:
            openudp_receive(msg);
            break;
         case IANA_ICMPv6:
            icmpv6_receive(msg);
            break;
         default:
            
            // log error
            openserial_printError(
               COMPONENT_FORWARDING,ERR_WRONG_TRAN_PROTOCOL,
               (errorparameter_t)msg->l4_protocol,
               (errorparameter_t)1
            );
            
            // free packet
            openqueue_freePacketBuffer(msg);
      }
   } else {
      // this packet is not for me: relay
      
      // change the creator of the packet
      msg->creator = COMPONENT_FORWARDING;
      
      if (ipv6_header->next_header!=IANA_IPv6ROUTE) {
         // no source routing header present
         //check if flow label rpl header
    	 #ifdef FLOW_LABEL_RPL_DOMAIN             
             flags = (uint8_t)((uint32_t)((ipv6_header->flow_label)>>16)&0xFF);
             senderRank = (uint16_t)((uint32_t)(ipv6_header->flow_label)>>8)&0xFFFF;
             senderRank = senderRank*MINHOPRANKINCREASE;//shift it according to HopRank Increase
         #else
    	     flags = rpl_option->flags;
    	     senderRank = rpl_option->senderRank;
    	 #endif

         if ((flags & O_FLAG)!=0){
            // wrong direction
            
            // log error
            openserial_printError(
               COMPONENT_FORWARDING,
               ERR_WRONG_DIRECTION,
               (errorparameter_t)flags,
               (errorparameter_t)senderRank
            );
         }
         

         if (senderRank < neighbors_getMyDAGrank()){
            // loop
            
            // set flag
            #ifdef FLOW_LABEL_RPL_DOMAIN
        	    flags |= R_FLAG;
        	    ipv6_header->flow_label|= ((uint32_t)flags<<16);
            #else
        	    rpl_option->flags |= R_FLAG;
            #endif

            // log error
            openserial_printError(
               COMPONENT_FORWARDING,
               ERR_LOOP_DETECTED,
               (errorparameter_t) senderRank,
               (errorparameter_t) neighbors_getMyDAGrank()
            );
         }
         

         forwarding_createRplOption(rpl_option, rpl_option->flags);
         #ifdef FLOW_LABEL_RPL_DOMAIN
         // do not recreate flow label, relay the same but adding current flags
         //forwarding_createFlowLabel(&(ipv6_header->flow_label),flags);
         #endif
         // resend as if from upper layer
         if (
               forwarding_send_internal_RoutingTable(
                  msg,
                  ipv6_header,
                  rpl_option,
                  &(ipv6_header->flow_label),
                  PCKTFORWARD 
               )==E_FAIL
            ) {
            openqueue_freePacketBuffer(msg);
         }
      } else {
         // source routing header present
         
         if (forwarding_send_internal_SourceRouting(msg, ipv6_header)==E_FAIL) {
Esempio n. 7
0
/**
\brief Send a packet using the source rout to find the next hop.

\note This is always called for packets being forwarded.

How to process the routing header is detailed in
http://tools.ietf.org/html/rfc6554#page-9.

\param[in,out] msg             The packet to send.
\param[in]     ipv6_header     The packet's IPv6 header.
*/
owerror_t forwarding_send_internal_SourceRouting(OpenMote* self, 
    OpenQueueEntry_t* msg,
    ipv6_header_iht*  ipv6_outer_header,
    ipv6_header_iht*  ipv6_inner_header,
    rpl_option_ht*    rpl_option
    ) {
    uint8_t              temp_8b;
    uint8_t              type;
    uint8_t              next_type;
    uint8_t              size;
    uint8_t              next_size;
    uint8_t              hlen;
    open_addr_t          firstAddr;
    open_addr_t          nextAddr;
    open_addr_t          temp_prefix;
    open_addr_t          temp_addr64;
    
    uint8_t              rpi_length;
    uint8_t              flags;
    uint16_t             senderRank;
    
    uint8_t              RH3_copy[127];
    uint8_t              RH3_length;
    
    memset(&RH3_copy[0],0,127);
    RH3_length = 0;
    memcpy(&msg->l3_destinationAdd,&ipv6_inner_header->dest,sizeof(open_addr_t));
    memcpy(&msg->l3_sourceAdd,&ipv6_inner_header->src,sizeof(open_addr_t));
    
    // initial first Address by compression reference
    firstAddr.type = ADDR_128B;
    if (ipv6_outer_header->src.type != ADDR_NONE){
        if (rpl_option->rplInstanceID == 0){
 icmpv6rpl_getRPLDODAGid(self, &firstAddr.addr_128b[0]);
        }
    } else {
        memcpy(&firstAddr,&ipv6_inner_header->src,sizeof(open_addr_t));
    }
    
    hlen = 0;
    
    temp_8b = *((uint8_t*)(msg->payload)+hlen);
    type    = *((uint8_t*)(msg->payload)+hlen+1);
    
    hlen += 2;
    // get the first address
    switch(type){
    case RH3_6LOTH_TYPE_0:
        memcpy(&firstAddr.addr_128b[15],msg->payload+hlen,1);
        hlen += 1;
        break;
    case RH3_6LOTH_TYPE_1:
        memcpy(&firstAddr.addr_128b[14],msg->payload+hlen,2);
        hlen += 2;
        break;
    case RH3_6LOTH_TYPE_2:
        memcpy(&firstAddr.addr_128b[12],msg->payload+hlen,4);
        hlen += 4;
        break;
    case RH3_6LOTH_TYPE_3:
        memcpy(&firstAddr.addr_128b[8],msg->payload+hlen,8);
        hlen += 8;
        break;
    case RH3_6LOTH_TYPE_4:
        memcpy(&firstAddr.addr_128b[0],msg->payload+hlen,16);
        hlen += 16;
        break;
    }
    
 packetfunctions_ip128bToMac64b(self, &firstAddr,&temp_prefix,&temp_addr64);
    if (
 packetfunctions_sameAddress(self, &temp_prefix, idmanager_getMyID(self, ADDR_PREFIX)) &&
 packetfunctions_sameAddress(self, &temp_addr64, idmanager_getMyID(self, ADDR_64B))
    ){
        size = temp_8b & RH3_6LOTH_SIZE_MASK;
        if (size > 0){
            // there are at least 2 entries in the header, 
            // the router removes the first entry and decrements the Size (by 1) 
            size -= 1;
 packetfunctions_tossHeader(self, msg,hlen);
 packetfunctions_reserveHeaderSize(self, msg,2);
            msg->payload[0] = CRITICAL_6LORH | size;
            msg->payload[1] = type;
            // get next hop
            memcpy(&nextAddr,&firstAddr,sizeof(open_addr_t));
            switch(type){
            case RH3_6LOTH_TYPE_0:
                memcpy(&nextAddr.addr_128b[15],msg->payload+2,1);
                break;
            case RH3_6LOTH_TYPE_1:
                memcpy(&nextAddr.addr_128b[14],msg->payload+2,2);
                break;
            case RH3_6LOTH_TYPE_2:
                memcpy(&nextAddr.addr_128b[12],msg->payload+2,4);
                break;
            case RH3_6LOTH_TYPE_3:
                memcpy(&nextAddr.addr_128b[8],msg->payload+2,8);
                break;
            case RH3_6LOTH_TYPE_4:
                memcpy(&nextAddr.addr_128b[0],msg->payload+2,16);
                break;
            }
 packetfunctions_ip128bToMac64b(self, 
                &nextAddr,
                &temp_prefix,
                &msg->l2_nextORpreviousHop
            );
        } else {
            temp_8b   = *((uint8_t*)(msg->payload)+hlen);
            next_type = *((uint8_t*)(msg->payload)+hlen+1);
            if (
                (temp_8b & FORMAT_6LORH_MASK) == CRITICAL_6LORH &&
                next_type<=RH3_6LOTH_TYPE_4
            ) {
                // there is another RH3-6LoRH following, check the type
                if (next_type >= type){
 packetfunctions_tossHeader(self, msg,hlen);
                    // get next hop
                    memcpy(&nextAddr,&firstAddr,sizeof(open_addr_t));
                    switch(next_type){
                    case RH3_6LOTH_TYPE_0:
                        memcpy(&nextAddr.addr_128b[15],msg->payload+2,1);
                        break;
                    case RH3_6LOTH_TYPE_1:
                        memcpy(&nextAddr.addr_128b[14],msg->payload+2,2);
                        break;
                    case RH3_6LOTH_TYPE_2:
                        memcpy(&nextAddr.addr_128b[12],msg->payload+2,4);
                        break;
                    case RH3_6LOTH_TYPE_3:
                        memcpy(&nextAddr.addr_128b[8],msg->payload+2,8);
                        break;
                    case RH3_6LOTH_TYPE_4:
                        memcpy(&nextAddr.addr_128b[0],msg->payload+2,16);
                        break;
                    }
 packetfunctions_ip128bToMac64b(self, 
                        &nextAddr,
                        &temp_prefix,
                        &msg->l2_nextORpreviousHop
                    );
                } else {
                    hlen += 2;
                    switch(next_type){
                    case RH3_6LOTH_TYPE_0:
                        memcpy(&firstAddr.addr_128b[15],msg->payload+hlen,1);
                        hlen += 1;
                        break;
                    case RH3_6LOTH_TYPE_1:
                        memcpy(&firstAddr.addr_128b[14],msg->payload+hlen,2);
                        hlen += 2;
                        break;
                    case RH3_6LOTH_TYPE_2:
                        memcpy(&firstAddr.addr_128b[12],msg->payload+hlen,4);
                        hlen += 4;
                        break;
                    case RH3_6LOTH_TYPE_3:
                        memcpy(&firstAddr.addr_128b[8],msg->payload+hlen,8);
                        hlen += 8;
                        break;
                    }
                    next_size = temp_8b & RH3_6LOTH_SIZE_MASK;
 packetfunctions_tossHeader(self, msg,hlen);
                    if (next_size>0){
                        next_size -= 1;
 packetfunctions_reserveHeaderSize(self, msg,2);
                        msg->payload[0] = CRITICAL_6LORH | next_size;
                        msg->payload[1] = next_type;
                    }
                    // add first address
                    switch(type){
                    case RH3_6LOTH_TYPE_0:
 packetfunctions_reserveHeaderSize(self, msg,1);
                        msg->payload[0] = firstAddr.addr_128b[15];
                        break;
                    case RH3_6LOTH_TYPE_1:
 packetfunctions_reserveHeaderSize(self, msg,2);
                        memcpy(&msg->payload[0],&firstAddr.addr_128b[14],2);
                        break;
                    case RH3_6LOTH_TYPE_2:
 packetfunctions_reserveHeaderSize(self, msg,4);
                        memcpy(&msg->payload[0],&firstAddr.addr_128b[12],4);
                        break;
                    case RH3_6LOTH_TYPE_3:
 packetfunctions_reserveHeaderSize(self, msg,8);
                        memcpy(&msg->payload[0],&firstAddr.addr_128b[8],8);
                        break;
                    case RH3_6LOTH_TYPE_4:
 packetfunctions_reserveHeaderSize(self, msg,16);
                        memcpy(&msg->payload[0],&firstAddr.addr_128b[0],16);
                        break;
                    }
 packetfunctions_reserveHeaderSize(self, msg,2);
                    msg->payload[0] = CRITICAL_6LORH | 0;
                    msg->payload[1] = type;
 packetfunctions_ip128bToMac64b(self, 
                        &firstAddr,
                        &temp_prefix,
                        &msg->l2_nextORpreviousHop
                    );
                }
            } else {
                // there is no next RH3-6loRH, remove current one
 packetfunctions_tossHeader(self, msg,hlen);
 packetfunctions_ip128bToMac64b(self, 
                    &msg->l3_destinationAdd,
                    &temp_prefix,
                    &msg->l2_nextORpreviousHop
                );
            }
        }
    } else {
        // log error
 openserial_printError(self, 
            COMPONENT_IPHC,
            ERR_6LOWPAN_UNSUPPORTED,
            (errorparameter_t)16,
            (errorparameter_t)(temp_addr64.addr_64b[7])
        );
    }
    // copy RH3s before toss them
    if (
        ipv6_outer_header->src.type != ADDR_NONE &&
        ipv6_outer_header->hopByhop_option != NULL
    ){
        // check the length of RH3s
        RH3_length = ipv6_outer_header->hopByhop_option-msg->payload;
        memcpy(&RH3_copy[0],msg->payload,RH3_length);
 packetfunctions_tossHeader(self, msg,RH3_length);
        
        // retrieve hop-by-hop header (includes RPL option)
        rpi_length = iphc_retrieveIPv6HopByHopHeader(self, 
                          msg,
                          rpl_option
                     );
     
        // toss the headers
 packetfunctions_tossHeader(self, 
            msg,
            rpi_length
        );
      
        flags = rpl_option->flags;
        senderRank = rpl_option->senderRank;
        if ((flags & O_FLAG)!=O_FLAG){
            // wrong direction
            // log error
 openserial_printError(self, 
                COMPONENT_FORWARDING,
                ERR_WRONG_DIRECTION,
                (errorparameter_t)flags,
                (errorparameter_t)senderRank
            );
        }
        if (senderRank > neighbors_getMyDAGrank(self)){
            // loop detected
            // set flag
            rpl_option->flags |= R_FLAG;
            // log error
 openserial_printError(self, 
                COMPONENT_FORWARDING,
                ERR_LOOP_DETECTED,
                (errorparameter_t) senderRank,
                (errorparameter_t) neighbors_getMyDAGrank(self)
            );
        }
 forwarding_createRplOption(self, rpl_option, rpl_option->flags);
        // toss the IP in IP 6LoRH
 packetfunctions_tossHeader(self, msg, ipv6_outer_header->header_length);
    } else {
        RH3_length = 0;
    }
    
    // send to next lower layer
    return iphc_sendFromForwarding(self, 
        msg,
        ipv6_outer_header,
        ipv6_inner_header,
        rpl_option,
        &ipv6_outer_header->flow_label,
        &RH3_copy[0],
        RH3_length,
        PCKTFORWARD
    );
}
Esempio n. 8
0
/**
\brief Indicates a packet was received.

\param[in,out] msg               The packet just sent.
\param[in]     ipv6_header       The information contained in the IPv6 header.
\param[in]     ipv6_hop_header   The hop-by-hop header present in the packet.
\param[in]     rpl_option        The hop-by-hop options present in the packet.
*/
void forwarding_receive(OpenMote* self, 
      OpenQueueEntry_t*      msg,
      ipv6_header_iht*       ipv6_outer_header,
      ipv6_header_iht*       ipv6_inner_header,
      rpl_option_ht*         rpl_option
    ) {
    uint8_t flags;
    uint16_t senderRank;
   
    // take ownership
    msg->owner                     = COMPONENT_FORWARDING;
   
    // determine L4 protocol
    // get information from ipv6_header
    msg->l4_protocol            = ipv6_inner_header->next_header;
    msg->l4_protocol_compressed = ipv6_inner_header->next_header_compressed;
   
    // populate packets metadata with L3 information
    memcpy(&(msg->l3_destinationAdd),&ipv6_inner_header->dest, sizeof(open_addr_t));
    memcpy(&(msg->l3_sourceAdd),     &ipv6_inner_header->src,  sizeof(open_addr_t));
   
    if (
        (
 idmanager_isMyAddress(self, &(msg->l3_destinationAdd))
            ||
 packetfunctions_isBroadcastMulticast(self, &(msg->l3_destinationAdd))
        )
        &&
        ipv6_outer_header->next_header!=IANA_IPv6ROUTE
    ) {
        if (ipv6_outer_header->src.type != ADDR_NONE){
 packetfunctions_tossHeader(self, msg,ipv6_outer_header->header_length);
        }
        // this packet is for me, no source routing header // toss iphc inner header
 packetfunctions_tossHeader(self, msg,ipv6_inner_header->header_length);
        // indicate received packet to upper layer
        switch(msg->l4_protocol) {
        case IANA_TCP:
 opentcp_receive(self, msg);
            break;
        case IANA_UDP:
 openudp_receive(self, msg);
            break;
        case IANA_ICMPv6:
 icmpv6_receive(self, msg);
            break;
        default:
            // log error
 openserial_printError(self, 
                COMPONENT_FORWARDING,ERR_WRONG_TRAN_PROTOCOL,
                (errorparameter_t)msg->l4_protocol,
                (errorparameter_t)1
            );
            
            // free packet
 openqueue_freePacketBuffer(self, msg);
        }
    } else {
        // this packet is not for me: relay
      
        // change the creator of the packet
        msg->creator = COMPONENT_FORWARDING;
      
        if (ipv6_outer_header->next_header!=IANA_IPv6ROUTE) {
            flags = rpl_option->flags;
            senderRank = rpl_option->senderRank;
            if ((flags & O_FLAG)!=0){
                // wrong direction
                // log error
 openserial_printError(self, 
                    COMPONENT_FORWARDING,
                    ERR_WRONG_DIRECTION,
                    (errorparameter_t)flags,
                    (errorparameter_t)senderRank
                );
            }
            if (senderRank < neighbors_getMyDAGrank(self)){
                // loop detected
                // set flag
                rpl_option->flags |= R_FLAG;
                // log error
 openserial_printError(self, 
                    COMPONENT_FORWARDING,
                    ERR_LOOP_DETECTED,
                    (errorparameter_t) senderRank,
                    (errorparameter_t) neighbors_getMyDAGrank(self)
                );
            }
 forwarding_createRplOption(self, rpl_option, rpl_option->flags);
            // resend as if from upper layer
            if (
 forwarding_send_internal_RoutingTable(self, 
                    msg,
                    ipv6_outer_header,
                    ipv6_inner_header,
                    rpl_option,
                    &(ipv6_outer_header->flow_label),
                    PCKTFORWARD 
                )==E_FAIL
            ) {
 openqueue_freePacketBuffer(self, msg);
            }
        } else {
            // source routing header present
            if (
 forwarding_send_internal_SourceRouting(self, 
                    msg,
                    ipv6_outer_header,
                    ipv6_inner_header,
                    rpl_option
                )==E_FAIL
            ) {
                // log error
 openserial_printError(self, 
                    COMPONENT_FORWARDING,
                    ERR_INVALID_FWDMODE,
                    (errorparameter_t)0,
                    (errorparameter_t)0
                );
            }
        }
    }
}