/** \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; }
/** \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; }
/** \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; }
/** \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); } }
/** \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; } }
/** \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) {
/** \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 ); }
/** \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 ); } } } }