/** \brief Send a packet originating at this mote. This function is called by an upper layer, and only concerns packets originated at this mote. \param[in,out] msg Packet to send. */ owerror_t forwarding_send(OpenQueueEntry_t* msg) { ipv6_header_iht ipv6_header; rpl_option_ht rpl_option; open_addr_t* myprefix; open_addr_t* myadd64; uint32_t flow_label = 0; // take ownership over the packet msg->owner = COMPONENT_FORWARDING; // retrieve my prefix and EUI64 myprefix = idmanager_getMyID(ADDR_PREFIX); myadd64 = idmanager_getMyID(ADDR_64B); // set source address (me) msg->l3_sourceAdd.type=ADDR_128B; memcpy(&(msg->l3_sourceAdd.addr_128b[0]),myprefix->prefix,8); memcpy(&(msg->l3_sourceAdd.addr_128b[8]),myadd64->addr_64b,8); // initialize IPv6 header memset(&ipv6_header,0,sizeof(ipv6_header_iht)); // Set hop limit to the default in-network value as this packet is being // sent from upper layer. This is done here as send_internal() is used by // forwarding of packets as well which carry a hlim. This value is required // to be set to a value as the following function can decrement it. ipv6_header.hop_limit = IPHC_DEFAULT_HOP_LIMIT; // create the RPL hop-by-hop option forwarding_createRplOption( &rpl_option, // rpl_option to fill in 0x00 // flags ); #ifdef FLOW_LABEL_RPL_DOMAIN forwarding_createFlowLabel(&flow_label,0x00); #endif return forwarding_send_internal_RoutingTable( msg, &ipv6_header, &rpl_option, &flow_label, PCKTSEND ); }
/** \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 Send a packet originating at this mote. This function is called by an upper layer, and only concerns packets originated at this mote. \param[in,out] msg Packet to send. */ owerror_t forwarding_send(OpenMote* self, OpenQueueEntry_t* msg) { ipv6_header_iht ipv6_outer_header; ipv6_header_iht ipv6_inner_header; rpl_option_ht rpl_option; open_addr_t* myprefix; open_addr_t* myadd64; uint32_t flow_label = 0; open_addr_t temp_dest_prefix; open_addr_t temp_dest_mac64b; open_addr_t* p_dest; open_addr_t* p_src; open_addr_t temp_src_prefix; open_addr_t temp_src_mac64b; uint8_t sam; uint8_t m; uint8_t dam; // take ownership over the packet msg->owner = COMPONENT_FORWARDING; m = IPHC_M_NO; // retrieve my prefix and EUI64 myprefix = idmanager_getMyID(self, ADDR_PREFIX); myadd64 = idmanager_getMyID(self, ADDR_64B); // set source address (me) msg->l3_sourceAdd.type=ADDR_128B; memcpy(&(msg->l3_sourceAdd.addr_128b[0]),myprefix->prefix,8); memcpy(&(msg->l3_sourceAdd.addr_128b[8]),myadd64->addr_64b,8); // initialize IPv6 header memset(&ipv6_outer_header,0,sizeof(ipv6_header_iht)); memset(&ipv6_inner_header,0,sizeof(ipv6_header_iht)); // Set hop limit to the default in-network value as this packet is being // sent from upper layer. This is done here as send_internal() is used by // forwarding of packets as well which carry a hlim. This value is required // to be set to a value as the following function can decrement it. ipv6_inner_header.hop_limit = IPHC_DEFAULT_HOP_LIMIT; // create the RPL hop-by-hop option forwarding_createRplOption(self, &rpl_option, // rpl_option to fill in 0x00 // flags ); packetfunctions_ip128bToMac64b(self, &(msg->l3_destinationAdd),&temp_dest_prefix,&temp_dest_mac64b); //xv poipoi -- get the src prefix as well packetfunctions_ip128bToMac64b(self, &(msg->l3_sourceAdd),&temp_src_prefix,&temp_src_mac64b); //XV -poipoi we want to check if the source address prefix is the same as destination prefix if ( packetfunctions_sameAddress(self, &temp_dest_prefix,&temp_src_prefix)) { // same prefix use 64B address sam = IPHC_SAM_64B; dam = IPHC_DAM_64B; p_dest = &temp_dest_mac64b; p_src = &temp_src_mac64b; } else { //not the same prefix. so the packet travels to another network //check if this is a source routing pkt. in case it is then the DAM is elided as it is in the SrcRouting header. if ( packetfunctions_isBroadcastMulticast(self, &(msg->l3_destinationAdd))==FALSE){ sam = IPHC_SAM_128B; dam = IPHC_DAM_128B; p_dest = &(msg->l3_destinationAdd); p_src = &(msg->l3_sourceAdd); ipv6_outer_header.src.type = ADDR_128B; memcpy(&ipv6_outer_header.src,p_src,sizeof(open_addr_t)); ipv6_outer_header.hop_limit = IPHC_DEFAULT_HOP_LIMIT; } else { // this is DIO, source address elided, multicast bit is set sam = IPHC_SAM_ELIDED; m = IPHC_M_YES; dam = IPHC_DAM_ELIDED; p_dest = &(msg->l3_destinationAdd); p_src = &(msg->l3_sourceAdd); } } //IPHC inner header and NHC IPv6 header will be added at here iphc_prependIPv6Header(self, msg, IPHC_TF_ELIDED, flow_label, // value_flowlabel IPHC_NH_INLINE, msg->l4_protocol, IPHC_HLIM_64, ipv6_outer_header.hop_limit, IPHC_CID_NO, IPHC_SAC_STATELESS, sam, m, IPHC_DAC_STATELESS, dam, p_dest, p_src, PCKTSEND ); // both of them are compressed ipv6_outer_header.next_header_compressed = TRUE; return forwarding_send_internal_RoutingTable(self, msg, &ipv6_outer_header, &ipv6_inner_header, &rpl_option, &flow_label, PCKTSEND ); }
/** \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 ); } } } }