void openudp_receive(OpenQueueEntry_t* msg) { uint8_t temp_8b; msg->owner = COMPONENT_OPENUDP; if (msg->l4_protocol_compressed==TRUE) { // get the UDP header encoding byte temp_8b = *((uint8_t*)(msg->payload)); packetfunctions_tossHeader(msg,sizeof(temp_8b)); switch (temp_8b & NHC_UDP_PORTS_MASK) { case NHC_UDP_PORTS_INLINE: // source port: 16 bits in-line // dest port: 16 bits in-line msg->l4_sourcePortORicmpv6Type = msg->payload[0]*256+msg->payload[1]; msg->l4_destination_port = msg->payload[2]*256+msg->payload[3]; packetfunctions_tossHeader(msg,2+2); break; case NHC_UDP_PORTS_16S_8D: // source port: 16 bits in-line // dest port: 0xf0 + 8 bits in-line msg->l4_sourcePortORicmpv6Type = msg->payload[0]*256+msg->payload[1]; msg->l4_destination_port = 0xf000 + msg->payload[2]; packetfunctions_tossHeader(msg,2+1); break; case NHC_UDP_PORTS_8S_8D: // source port: 0xf0 + 8 bits in-line // dest port: 0xf0 + 8 bits in-line msg->l4_sourcePortORicmpv6Type = 0xf000 + msg->payload[0]; msg->l4_destination_port = 0xf000 + msg->payload[1]; packetfunctions_tossHeader(msg,1+1); break; case NHC_UDP_PORTS_4S_4D: // source port: 0xf0b + 4 bits in-line // dest port: 0xf0b + 4 bits in-line msg->l4_sourcePortORicmpv6Type = 0xf0b0 + (msg->payload[0] >> 4) & 0x0f; msg->l4_destination_port = 0xf0b0 + (msg->payload[0] >> 0) & 0x0f; packetfunctions_tossHeader(msg,1); break; } } else {
/** \brief Send a packet using the routing table to find the next hop. \param[in,out] msg The packet to send. \param[in] ipv6_header The packet's IPv6 header. \param[in] rpl_option The hop-by-hop option to add in this packet. \param[in] flow_label The flowlabel to add in the 6LoWPAN header. \param[in] fw_SendOrfw_Rcv The packet is originating from this mote (PCKTSEND), or forwarded (PCKTFORWARD). */ owerror_t forwarding_send_internal_RoutingTable(OpenMote* self, OpenQueueEntry_t* msg, ipv6_header_iht* ipv6_outer_header, ipv6_header_iht* ipv6_inner_header, rpl_option_ht* rpl_option, uint32_t* flow_label, uint8_t fw_SendOrfw_Rcv ) { // retrieve the next hop from the routing table forwarding_getNextHop(self, &(msg->l3_destinationAdd),&(msg->l2_nextORpreviousHop)); if (msg->l2_nextORpreviousHop.type==ADDR_NONE) { openserial_printError(self, COMPONENT_FORWARDING, ERR_NO_NEXTHOP, (errorparameter_t)0, (errorparameter_t)0 ); return E_FAIL; } if (ipv6_outer_header->src.type != ADDR_NONE){ packetfunctions_tossHeader(self, msg,ipv6_outer_header->header_length); } // send to next lower layer return iphc_sendFromForwarding(self, msg, ipv6_outer_header, ipv6_inner_header, rpl_option, flow_label, NULL, // no rh3 0, fw_SendOrfw_Rcv ); }
/** \brief Called when RPL message received. \param[in] msg Pointer to the received message. */ void icmpv6rpl_receive(OpenQueueEntry_t* msg) { uint8_t icmpv6code; open_addr_t myPrefix; // take ownership msg->owner = COMPONENT_ICMPv6RPL; // retrieve ICMPv6 code icmpv6code = (((ICMPv6_ht*)(msg->payload))->code); // toss ICMPv6 header packetfunctions_tossHeader(msg,sizeof(ICMPv6_ht)); // handle message switch (icmpv6code) { case IANA_ICMPv6_RPL_DIO: if (idmanager_getIsBridge()==TRUE) { // stop here if I'm in bridge mode break; // break, don't return } // update neighbor table neighbors_indicateRxDIO(msg); // update DODAGID in DIO/DAO memcpy( &(icmpv6rpl_vars.dio.DODAGID[0]), &(((icmpv6rpl_dio_ht*)(msg->payload))->DODAGID[0]), sizeof(icmpv6rpl_vars.dio.DODAGID) ); memcpy( &(icmpv6rpl_vars.dao.DODAGID[0]), &(((icmpv6rpl_dio_ht*)(msg->payload))->DODAGID[0]), sizeof(icmpv6rpl_vars.dao.DODAGID) ); // remember I got a DODAGID icmpv6rpl_vars.DODAGIDFlagSet=1; // update my prefix myPrefix.type = ADDR_PREFIX; memcpy( myPrefix.prefix, &((icmpv6rpl_dio_ht*)(msg->payload))->DODAGID[0], sizeof(myPrefix.prefix) ); idmanager_setMyID(&myPrefix); break; case IANA_ICMPv6_RPL_DAO: // this should never happen openserial_printCritical(COMPONENT_ICMPv6RPL,ERR_UNEXPECTED_DAO, (errorparameter_t)0, (errorparameter_t)0); break; default: // this should never happen openserial_printCritical(COMPONENT_ICMPv6RPL,ERR_MSG_UNKNOWN_TYPE, (errorparameter_t)icmpv6code, (errorparameter_t)0); break; } // free message openqueue_freePacketBuffer(msg); }
/** \brief Indicate a CoAP messages was received. A "CoAP message" is simply a UDP datagram received on the CoAP UDP port. This function will call the appropriate resource, and send back its answer. The received packetbuffer is reused to contain the response (or error code). \param[in] msg The received CoAP message. */ void opencoap_receive(OpenQueueEntry_t* msg) { uint16_t temp_l4_destination_port; uint8_t i; uint8_t index; coap_option_t last_option; coap_resource_desc_t* temp_desc; bool found; owerror_t outcome; // local variables passed to the handlers (with msg) coap_header_iht coap_header; coap_option_iht coap_options[MAX_COAP_OPTIONS]; // take ownership over the received packet msg->owner = COMPONENT_OPENCOAP; //=== step 1. parse the packet // parse the CoAP header and remove from packet index = 0; coap_header.Ver = (msg->payload[index] & 0xc0) >> 6; coap_header.T = (coap_type_t)((msg->payload[index] & 0x30) >> 4); coap_header.TKL = (msg->payload[index] & 0x0f); index++; coap_header.Code = (coap_code_t)(msg->payload[index]); index++; coap_header.messageID = msg->payload[index]*256+msg->payload[index+1]; index+=2; // reject unsupported header if (coap_header.Ver!=COAP_VERSION || coap_header.TKL>COAP_MAX_TKL) { openserial_printError( COMPONENT_OPENCOAP,ERR_WRONG_TRAN_PROTOCOL, (errorparameter_t)0, (errorparameter_t)coap_header.Ver ); openqueue_freePacketBuffer(msg); return; } // record the token memcpy(&coap_header.token[0], &msg->payload[index], coap_header.TKL); index += coap_header.TKL; // initialize the coap_options for (i=0;i<MAX_COAP_OPTIONS;i++) { coap_options[i].type = COAP_OPTION_NONE; } // fill in the coap_options last_option = COAP_OPTION_NONE; for (i=0;i<MAX_COAP_OPTIONS;i++) { // detect when done parsing options if (msg->payload[index]==COAP_PAYLOAD_MARKER){ // found the payload marker, done parsing options. index++; // skip marker and stop parsing options break; } // parse this option coap_options[i].type = (coap_option_t)((uint8_t)last_option+(uint8_t)((msg->payload[index] & 0xf0) >> 4)); last_option = coap_options[i].type; coap_options[i].length = (msg->payload[index] & 0x0f); index++; coap_options[i].pValue = &(msg->payload[index]); index += coap_options[i].length; //includes length as well } // remove the CoAP header+options packetfunctions_tossHeader(msg,index); //=== step 2. find the resource to handle the packet // find the resource this applies to found = FALSE; if ( coap_header.Code>=COAP_CODE_REQ_GET && coap_header.Code<=COAP_CODE_REQ_DELETE ) { // this is a request: target resource is indicated as COAP_OPTION_LOCATIONPATH option(s) // find the resource which matches // start with the first resource in the linked list temp_desc = opencoap_vars.resources; // iterate until matching resource found, or no match while (found==FALSE) { if ( coap_options[0].type==COAP_OPTION_NUM_URIPATH && coap_options[1].type==COAP_OPTION_NUM_URIPATH && temp_desc->path0len>0 && temp_desc->path0val!=NULL && temp_desc->path1len>0 && temp_desc->path1val!=NULL ) { // resource has a path of form path0/path1 if ( coap_options[0].length==temp_desc->path0len && memcmp(coap_options[0].pValue,temp_desc->path0val,temp_desc->path0len)==0 && coap_options[1].length==temp_desc->path1len && memcmp(coap_options[1].pValue,temp_desc->path1val,temp_desc->path1len)==0 ) { found = TRUE; }; } else if ( coap_options[0].type==COAP_OPTION_NUM_URIPATH && temp_desc->path0len>0 && temp_desc->path0val!=NULL ) { // resource has a path of form path0 if ( coap_options[0].length==temp_desc->path0len && memcmp(coap_options[0].pValue,temp_desc->path0val,temp_desc->path0len)==0 ) { found = TRUE; }; }; // iterate to next resource, if not found if (found==FALSE) { if (temp_desc->next!=NULL) { temp_desc = temp_desc->next; } else { break; } } } } else { // this is a response: target resource is indicated by message ID // find the resource which matches // start with the first resource in the linked list temp_desc = opencoap_vars.resources; // iterate until matching resource found, or no match while (found==FALSE) { if (coap_header.messageID==temp_desc->messageID) { found=TRUE; // call the resource's callback if (temp_desc->callbackRx!=NULL) { temp_desc->callbackRx(msg,&coap_header,&coap_options[0]); } } // iterate to next resource, if not found if (found==FALSE) { if (temp_desc->next!=NULL) { temp_desc = temp_desc->next; } else { break; } } }; // free the received packet openqueue_freePacketBuffer(msg); // stop here: will will not respond to a response return; } //=== step 3. ask the resource to prepare response if (found==TRUE) { // call the resource's callback outcome = temp_desc->callbackRx(msg,&coap_header,&coap_options[0]); } else { // reset packet payload (DO NOT DELETE, we will reuse same buffer for response) msg->payload = &(msg->packet[127]); msg->length = 0; // set the CoAP header coap_header.TKL = 0; coap_header.Code = COAP_CODE_RESP_NOTFOUND; } if (outcome==E_FAIL) { // reset packet payload (DO NOT DELETE, we will reuse same buffer for response) msg->payload = &(msg->packet[127]); msg->length = 0; // set the CoAP header coap_header.TKL = 0; coap_header.Code = COAP_CODE_RESP_METHODNOTALLOWED; } //=== step 4. send that packet back // fill in packet metadata if (found==TRUE) { msg->creator = temp_desc->componentID; } else { msg->creator = COMPONENT_OPENCOAP; } msg->l4_protocol = IANA_UDP; temp_l4_destination_port = msg->l4_destination_port; msg->l4_destination_port = msg->l4_sourcePortORicmpv6Type; msg->l4_sourcePortORicmpv6Type = temp_l4_destination_port; // set destination address as the current source msg->l3_destinationAdd.type = ADDR_128B; memcpy(&msg->l3_destinationAdd.addr_128b[0],&msg->l3_sourceAdd.addr_128b[0],LENGTH_ADDR128b); // fill in CoAP header packetfunctions_reserveHeaderSize(msg,4+coap_header.TKL); msg->payload[0] = (COAP_VERSION << 6) | (COAP_TYPE_ACK << 4) | (coap_header.TKL << 0); msg->payload[1] = coap_header.Code; msg->payload[2] = coap_header.messageID/256; msg->payload[3] = coap_header.messageID%256; memcpy(&msg->payload[4], &coap_header.token[0], coap_header.TKL); if ((openudp_send(msg))==E_FAIL) { openqueue_freePacketBuffer(msg); } }
void task_sixtopNotifReceive() { OpenQueueEntry_t* msg; uint16_t lenIE; // get received packet from openqueue msg = openqueue_sixtopGetReceivedPacket(); if (msg==NULL) { openserial_printCritical( COMPONENT_SIXTOP, ERR_NO_RECEIVED_PACKET, (errorparameter_t)0, (errorparameter_t)0 ); return; } // take ownership msg->owner = COMPONENT_SIXTOP; // process the header IEs lenIE=0; if( msg->l2_frameType==IEEE154_TYPE_DATA && msg->l2_IEListPresent==IEEE154_IELIST_YES && sixtop_processIEs(msg, &lenIE) == FALSE ) { // free the packet's RAM memory openqueue_freePacketBuffer(msg); //log error return; } // toss the header IEs packetfunctions_tossHeader(msg,lenIE); // update neighbor statistics neighbors_indicateRx( &(msg->l2_nextORpreviousHop), msg->l1_rssi, &msg->l2_asn, msg->l2_joinPriorityPresent, msg->l2_joinPriority ); // reset it to avoid race conditions with this var. msg->l2_joinPriorityPresent = FALSE; // send the packet up the stack, if it qualifies switch (msg->l2_frameType) { case IEEE154_TYPE_BEACON: case IEEE154_TYPE_DATA: case IEEE154_TYPE_CMD: if (msg->length>0) { // send to upper layer iphc_receive(msg); } else { // free up the RAM openqueue_freePacketBuffer(msg); } break; case IEEE154_TYPE_ACK: default: // free the packet's RAM memory openqueue_freePacketBuffer(msg); // log the error openserial_printError( COMPONENT_SIXTOP, ERR_MSG_UNKNOWN_TYPE, (errorparameter_t)msg->l2_frameType, (errorparameter_t)0 ); break; } }
void opentcp_receive(OpenQueueEntry_t* msg) { OpenQueueEntry_t* tempPkt; bool shouldIlisten; msg->owner = COMPONENT_OPENTCP; msg->l4_protocol = IANA_TCP; msg->l4_payload = msg->payload; msg->l4_length = msg->length; msg->l4_sourcePortORicmpv6Type = packetfunctions_ntohs((uint8_t*)&(((tcp_ht*)msg->payload)->source_port)); msg->l4_destination_port = packetfunctions_ntohs((uint8_t*)&(((tcp_ht*)msg->payload)->destination_port)); if ( tcp_vars.state!=TCP_STATE_CLOSED && ( msg->l4_destination_port != tcp_vars.myPort || msg->l4_sourcePortORicmpv6Type != tcp_vars.hisPort || packetfunctions_sameAddress(&(msg->l3_destinationAdd),&tcp_vars.hisIPv6Address)==FALSE ) ) { openqueue_freePacketBuffer(msg); return; } if (containsControlBits(msg,TCP_ACK_WHATEVER,TCP_RST_YES,TCP_SYN_WHATEVER,TCP_FIN_WHATEVER)) { //I receive RST[+*], I reset opentcp_reset(); openqueue_freePacketBuffer(msg); } switch (tcp_vars.state) { case TCP_STATE_CLOSED: //[receive] establishement switch(msg->l4_destination_port) { case WKP_TCP_HTTP: shouldIlisten = ohlone_shouldIlisten(); break; case WKP_TCP_ECHO: shouldIlisten = tcpecho_shouldIlisten(); break; case WKP_TCP_INJECT: shouldIlisten = tcpinject_shouldIlisten(); break; case WKP_TCP_DISCARD: shouldIlisten = tcpprint_shouldIlisten(); break; default: openserial_printError(COMPONENT_OPENTCP,ERR_UNSUPPORTED_PORT_NUMBER, (errorparameter_t)msg->l4_sourcePortORicmpv6Type, (errorparameter_t)2); shouldIlisten = FALSE; break; } if ( containsControlBits(msg,TCP_ACK_NO,TCP_RST_NO,TCP_SYN_YES,TCP_FIN_NO) && shouldIlisten==TRUE ) { tcp_vars.myPort = msg->l4_destination_port; //I receive SYN, I send SYN+ACK tcp_vars.hisNextSeqNum = (packetfunctions_ntohl((uint8_t*)&(((tcp_ht*)msg->payload)->sequence_number)))+1; tcp_vars.hisPort = msg->l4_sourcePortORicmpv6Type; memcpy(&tcp_vars.hisIPv6Address,&(msg->l3_destinationAdd),sizeof(open_addr_t)); tempPkt = openqueue_getFreePacketBuffer(COMPONENT_OPENTCP); if (tempPkt==NULL) { openserial_printError(COMPONENT_OPENTCP,ERR_NO_FREE_PACKET_BUFFER, (errorparameter_t)0, (errorparameter_t)0); openqueue_freePacketBuffer(msg); return; } tempPkt->creator = COMPONENT_OPENTCP; tempPkt->owner = COMPONENT_OPENTCP; memcpy(&(tempPkt->l3_destinationAdd),&tcp_vars.hisIPv6Address,sizeof(open_addr_t)); prependTCPHeader(tempPkt, TCP_ACK_YES, TCP_PSH_NO, TCP_RST_NO, TCP_SYN_YES, TCP_FIN_NO); tcp_vars.mySeqNum++; tcp_change_state(TCP_STATE_ALMOST_SYN_RECEIVED); forwarding_send(tempPkt); } else { opentcp_reset(); openserial_printError(COMPONENT_OPENTCP,ERR_TCP_RESET, (errorparameter_t)tcp_vars.state, (errorparameter_t)0); } openqueue_freePacketBuffer(msg); break; case TCP_STATE_SYN_SENT: //[receive] establishement if (containsControlBits(msg,TCP_ACK_YES,TCP_RST_NO,TCP_SYN_YES,TCP_FIN_NO)) { //I receive SYN+ACK, I send ACK tcp_vars.hisNextSeqNum = (packetfunctions_ntohl((uint8_t*)&(((tcp_ht*)msg->payload)->sequence_number)))+1; tempPkt = openqueue_getFreePacketBuffer(COMPONENT_OPENTCP); if (tempPkt==NULL) { openserial_printError(COMPONENT_OPENTCP,ERR_NO_FREE_PACKET_BUFFER, (errorparameter_t)0, (errorparameter_t)0); openqueue_freePacketBuffer(msg); return; } tempPkt->creator = COMPONENT_OPENTCP; tempPkt->owner = COMPONENT_OPENTCP; memcpy(&(tempPkt->l3_destinationAdd),&tcp_vars.hisIPv6Address,sizeof(open_addr_t)); prependTCPHeader(tempPkt, TCP_ACK_YES, TCP_PSH_NO, TCP_RST_NO, TCP_SYN_NO, TCP_FIN_NO); tcp_change_state(TCP_STATE_ALMOST_ESTABLISHED); forwarding_send(tempPkt); } else if (containsControlBits(msg,TCP_ACK_NO,TCP_RST_NO,TCP_SYN_YES,TCP_FIN_NO)) { //I receive SYN, I send SYN+ACK tcp_vars.hisNextSeqNum = (packetfunctions_ntohl((uint8_t*)&(((tcp_ht*)msg->payload)->sequence_number)))+1; tempPkt = openqueue_getFreePacketBuffer(COMPONENT_OPENTCP); if (tempPkt==NULL) { openserial_printError(COMPONENT_OPENTCP,ERR_NO_FREE_PACKET_BUFFER, (errorparameter_t)0, (errorparameter_t)0); openqueue_freePacketBuffer(msg); return; } tempPkt->creator = COMPONENT_OPENTCP; tempPkt->owner = COMPONENT_OPENTCP; memcpy(&(tempPkt->l3_destinationAdd),&tcp_vars.hisIPv6Address,sizeof(open_addr_t)); prependTCPHeader(tempPkt, TCP_ACK_YES, TCP_PSH_NO, TCP_RST_NO, TCP_SYN_YES, TCP_FIN_NO); tcp_vars.mySeqNum++; tcp_change_state(TCP_STATE_ALMOST_SYN_RECEIVED); forwarding_send(tempPkt); } else { opentcp_reset(); openserial_printError(COMPONENT_OPENTCP,ERR_TCP_RESET, (errorparameter_t)tcp_vars.state, (errorparameter_t)1); } openqueue_freePacketBuffer(msg); break; case TCP_STATE_SYN_RECEIVED: //[receive] establishement if (containsControlBits(msg,TCP_ACK_YES,TCP_RST_NO,TCP_SYN_NO,TCP_FIN_NO)) { //I receive ACK, the virtual circuit is established tcp_change_state(TCP_STATE_ESTABLISHED); } else { opentcp_reset(); openserial_printError(COMPONENT_OPENTCP,ERR_TCP_RESET, (errorparameter_t)tcp_vars.state, (errorparameter_t)2); } openqueue_freePacketBuffer(msg); break; case TCP_STATE_ESTABLISHED: //[receive] data/teardown if (containsControlBits(msg,TCP_ACK_WHATEVER,TCP_RST_NO,TCP_SYN_NO,TCP_FIN_YES)) { //I receive FIN[+ACK], I send ACK tcp_vars.hisNextSeqNum = (packetfunctions_ntohl((uint8_t*)&(((tcp_ht*)msg->payload)->sequence_number)))+msg->length-sizeof(tcp_ht)+1; tempPkt = openqueue_getFreePacketBuffer(COMPONENT_OPENTCP); if (tempPkt==NULL) { openserial_printError(COMPONENT_OPENTCP,ERR_NO_FREE_PACKET_BUFFER, (errorparameter_t)0, (errorparameter_t)0); openqueue_freePacketBuffer(msg); return; } tempPkt->creator = COMPONENT_OPENTCP; tempPkt->owner = COMPONENT_OPENTCP; memcpy(&(tempPkt->l3_destinationAdd),&tcp_vars.hisIPv6Address,sizeof(open_addr_t)); prependTCPHeader(tempPkt, TCP_ACK_YES, TCP_PSH_NO, TCP_RST_NO, TCP_SYN_NO, TCP_FIN_NO); forwarding_send(tempPkt); tcp_change_state(TCP_STATE_ALMOST_CLOSE_WAIT); } else if (containsControlBits(msg,TCP_ACK_WHATEVER,TCP_RST_NO,TCP_SYN_NO,TCP_FIN_NO)) { //I receive data, I send ACK tcp_vars.hisNextSeqNum = (packetfunctions_ntohl((uint8_t*)&(((tcp_ht*)msg->payload)->sequence_number)))+msg->length-sizeof(tcp_ht); tempPkt = openqueue_getFreePacketBuffer(COMPONENT_OPENTCP); if (tempPkt==NULL) { openserial_printError(COMPONENT_OPENTCP,ERR_NO_FREE_PACKET_BUFFER, (errorparameter_t)0, (errorparameter_t)0); openqueue_freePacketBuffer(msg); return; } tempPkt->creator = COMPONENT_OPENTCP; tempPkt->owner = COMPONENT_OPENTCP; memcpy(&(tempPkt->l3_destinationAdd),&tcp_vars.hisIPv6Address,sizeof(open_addr_t)); prependTCPHeader(tempPkt, TCP_ACK_YES, TCP_PSH_NO, TCP_RST_NO, TCP_SYN_NO, TCP_FIN_NO); forwarding_send(tempPkt); packetfunctions_tossHeader(msg,sizeof(tcp_ht)); tcp_vars.dataReceived = msg; tcp_change_state(TCP_STATE_ALMOST_DATA_RECEIVED); } else { opentcp_reset(); openserial_printError(COMPONENT_OPENTCP,ERR_TCP_RESET, (errorparameter_t)tcp_vars.state, (errorparameter_t)3); openqueue_freePacketBuffer(msg); } break; case TCP_STATE_DATA_SENT: //[receive] data if (containsControlBits(msg,TCP_ACK_YES,TCP_RST_NO,TCP_SYN_NO,TCP_FIN_NO)) { //I receive ACK, data message sent switch(tcp_vars.myPort) { case WKP_TCP_HTTP: ohlone_sendDone(tcp_vars.dataToSend,E_SUCCESS); break; case WKP_TCP_ECHO: tcpecho_sendDone(tcp_vars.dataToSend,E_SUCCESS); break; case WKP_TCP_INJECT: tcpinject_sendDone(tcp_vars.dataToSend,E_SUCCESS); break; case WKP_TCP_DISCARD: tcpprint_sendDone(tcp_vars.dataToSend,E_SUCCESS); break; default: openserial_printError(COMPONENT_OPENTCP,ERR_UNSUPPORTED_PORT_NUMBER, (errorparameter_t)tcp_vars.myPort, (errorparameter_t)3); break; } tcp_vars.dataToSend = NULL; tcp_change_state(TCP_STATE_ESTABLISHED); } else if (containsControlBits(msg,TCP_ACK_WHATEVER,TCP_RST_NO,TCP_SYN_NO,TCP_FIN_YES)) { //I receive FIN[+ACK], I send ACK switch(tcp_vars.myPort) { case WKP_TCP_HTTP: ohlone_sendDone(tcp_vars.dataToSend,E_SUCCESS); break; case WKP_TCP_ECHO: tcpecho_sendDone(tcp_vars.dataToSend,E_SUCCESS); break; case WKP_TCP_INJECT: tcpinject_sendDone(tcp_vars.dataToSend,E_SUCCESS); break; case WKP_TCP_DISCARD: tcpprint_sendDone(tcp_vars.dataToSend,E_SUCCESS); break; default: openserial_printError(COMPONENT_OPENTCP,ERR_UNSUPPORTED_PORT_NUMBER, (errorparameter_t)tcp_vars.myPort, (errorparameter_t)4); break; } tcp_vars.dataToSend = NULL; tcp_vars.hisNextSeqNum = (packetfunctions_ntohl((uint8_t*)&(((tcp_ht*)msg->payload)->sequence_number)))+msg->length-sizeof(tcp_ht)+1; tempPkt = openqueue_getFreePacketBuffer(COMPONENT_OPENTCP); if (tempPkt==NULL) { openserial_printError(COMPONENT_OPENTCP,ERR_NO_FREE_PACKET_BUFFER, (errorparameter_t)0, (errorparameter_t)0); openqueue_freePacketBuffer(msg); return; } tempPkt->creator = COMPONENT_OPENTCP; tempPkt->owner = COMPONENT_OPENTCP; memcpy(&(tempPkt->l3_destinationAdd),&tcp_vars.hisIPv6Address,sizeof(open_addr_t)); prependTCPHeader(tempPkt, TCP_ACK_YES, TCP_PSH_NO, TCP_RST_NO, TCP_SYN_NO, TCP_FIN_NO); forwarding_send(tempPkt); tcp_change_state(TCP_STATE_ALMOST_CLOSE_WAIT); } else { opentcp_reset(); openserial_printError(COMPONENT_OPENTCP,ERR_TCP_RESET, (errorparameter_t)tcp_vars.state, (errorparameter_t)4); } openqueue_freePacketBuffer(msg); break; case TCP_STATE_FIN_WAIT_1: //[receive] teardown if (containsControlBits(msg,TCP_ACK_NO,TCP_RST_NO,TCP_SYN_NO,TCP_FIN_YES)) { //I receive FIN, I send ACK tcp_vars.hisNextSeqNum = (packetfunctions_ntohl((uint8_t*)&(((tcp_ht*)msg->payload)->sequence_number)))+1; tempPkt = openqueue_getFreePacketBuffer(COMPONENT_OPENTCP); if (tempPkt==NULL) { openserial_printError(COMPONENT_OPENTCP,ERR_NO_FREE_PACKET_BUFFER, (errorparameter_t)0, (errorparameter_t)0); openqueue_freePacketBuffer(msg); return; } tempPkt->creator = COMPONENT_OPENTCP; tempPkt->owner = COMPONENT_OPENTCP; memcpy(&(tempPkt->l3_destinationAdd),&tcp_vars.hisIPv6Address,sizeof(open_addr_t)); prependTCPHeader(tempPkt, TCP_ACK_YES, TCP_PSH_NO, TCP_RST_NO, TCP_SYN_NO, TCP_FIN_NO); forwarding_send(tempPkt); tcp_change_state(TCP_STATE_ALMOST_CLOSING); } else if (containsControlBits(msg,TCP_ACK_YES,TCP_RST_NO,TCP_SYN_NO,TCP_FIN_YES)) { //I receive FIN+ACK, I send ACK tcp_vars.hisNextSeqNum = (packetfunctions_ntohl((uint8_t*)&(((tcp_ht*)msg->payload)->sequence_number)))+1; tempPkt = openqueue_getFreePacketBuffer(COMPONENT_OPENTCP); if (tempPkt==NULL) { openserial_printError(COMPONENT_OPENTCP,ERR_NO_FREE_PACKET_BUFFER, (errorparameter_t)0, (errorparameter_t)0); openqueue_freePacketBuffer(msg); return; } tempPkt->creator = COMPONENT_OPENTCP; tempPkt->owner = COMPONENT_OPENTCP; memcpy(&(tempPkt->l3_destinationAdd),&tcp_vars.hisIPv6Address,sizeof(open_addr_t)); prependTCPHeader(tempPkt, TCP_ACK_YES, TCP_PSH_NO, TCP_RST_NO, TCP_SYN_NO, TCP_FIN_NO); forwarding_send(tempPkt); tcp_change_state(TCP_STATE_ALMOST_TIME_WAIT); } else if (containsControlBits(msg,TCP_ACK_YES,TCP_RST_NO,TCP_SYN_NO,TCP_FIN_NO)) { //I receive ACK, I will receive FIN later tcp_change_state(TCP_STATE_FIN_WAIT_2); } else { opentcp_reset(); openserial_printError(COMPONENT_OPENTCP,ERR_TCP_RESET, (errorparameter_t)tcp_vars.state, (errorparameter_t)5); } openqueue_freePacketBuffer(msg); break; case TCP_STATE_FIN_WAIT_2: //[receive] teardown if (containsControlBits(msg,TCP_ACK_WHATEVER,TCP_RST_NO,TCP_SYN_NO,TCP_FIN_YES)) { //I receive FIN[+ACK], I send ACK tcp_vars.hisNextSeqNum = (packetfunctions_ntohl((uint8_t*)&(((tcp_ht*)msg->payload)->sequence_number)))+1; tempPkt = openqueue_getFreePacketBuffer(COMPONENT_OPENTCP); if (tempPkt==NULL) { openserial_printError(COMPONENT_OPENTCP,ERR_NO_FREE_PACKET_BUFFER, (errorparameter_t)0, (errorparameter_t)0); openqueue_freePacketBuffer(msg); return; } tempPkt->creator = COMPONENT_OPENTCP; tempPkt->owner = COMPONENT_OPENTCP; memcpy(&(tempPkt->l3_destinationAdd),&tcp_vars.hisIPv6Address,sizeof(open_addr_t)); prependTCPHeader(tempPkt, TCP_ACK_YES, TCP_PSH_NO, TCP_RST_NO, TCP_SYN_NO, TCP_FIN_NO); forwarding_send(tempPkt); tcp_change_state(TCP_STATE_ALMOST_TIME_WAIT); } openqueue_freePacketBuffer(msg); break; case TCP_STATE_CLOSING: //[receive] teardown if (containsControlBits(msg,TCP_ACK_YES,TCP_RST_NO,TCP_SYN_NO,TCP_FIN_NO)) { //I receive ACK, I do nothing tcp_change_state(TCP_STATE_TIME_WAIT); //TODO implement waiting timer opentcp_reset(); } openqueue_freePacketBuffer(msg); break; case TCP_STATE_LAST_ACK: //[receive] teardown if (containsControlBits(msg,TCP_ACK_YES,TCP_RST_NO,TCP_SYN_NO,TCP_FIN_NO)) { //I receive ACK, I reset opentcp_reset(); } openqueue_freePacketBuffer(msg); break; default: openserial_printError(COMPONENT_OPENTCP,ERR_WRONG_TCP_STATE, (errorparameter_t)tcp_vars.state, (errorparameter_t)4); break; } }
error_t fowarding_send_internal_SourceRouting(OpenQueueEntry_t *msg, ipv6_header_iht ipv6_header) { // It has to be forwarded to dest. so, next hop should be extracted from the message. uint8_t local_CmprE; uint8_t local_CmprI,numAddr,hlen; uint8_t addressposition; uint8_t* runningPointer; uint8_t octetsAddressSize; ipv6_Source_Routing_Header_t * ipv6_Source_Routing_Header; open_addr_t* prefix=idmanager_getMyID(ADDR_PREFIX); ipv6_Source_Routing_Header=(ipv6_Source_Routing_Header_t*)(msg->payload); runningPointer=(msg->payload) + sizeof(ipv6_Source_Routing_Header_t); // getting local_CmprE and CmprI; local_CmprE=ipv6_Source_Routing_Header->CmprICmprE & 0xf; local_CmprI= ipv6_Source_Routing_Header->CmprICmprE & 0xf0; //local_CmprI>>4; // shifting it by 4. local_CmprI=local_CmprI>>4; // shifting it by 4. // foundFlag=0; //see processing header algorithm in RFC6554 page 9 numAddr=(((ipv6_Source_Routing_Header->HdrExtLen*8)-ipv6_Source_Routing_Header->PadRes -(16-local_CmprE))/(16-local_CmprI))+1; if(ipv6_Source_Routing_Header->SegmentsLeft==0){ //we are there!.. //process the next header in the pkt.. i.e push stack up.. msg->l4_protocol=ipv6_Source_Routing_Header->nextHeader; hlen=ipv6_Source_Routing_Header->HdrExtLen; //toss header packetfunctions_tossHeader(msg,sizeof(ipv6_Source_Routing_Header_t)); //toss list of addresses. if(local_CmprE==0) { octetsAddressSize=2; //remove packetfunctions_tossHeader(msg,octetsAddressSize*hlen); } else if(local_CmprE==8) { octetsAddressSize=8; packetfunctions_tossHeader(msg,octetsAddressSize*hlen); } else if(local_CmprE==2) { octetsAddressSize=16; packetfunctions_tossHeader(msg,octetsAddressSize*hlen); } else { msg->l2_nextORpreviousHop.type = ADDR_NONE; //error! while(1); } 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: openserial_printError(COMPONENT_FORWARDING,ERR_WRONG_TRAN_PROTOCOL, (errorparameter_t)msg->l4_protocol, (errorparameter_t)1); } return E_SUCCESS; }else{ if(ipv6_Source_Routing_Header->SegmentsLeft>numAddr){ //not good.. error. //send and ICMPv6 parameter problem, code 0, to the src address //then discard the packet. //TODO while (1); }else{ //still hops remaining ipv6_Source_Routing_Header->SegmentsLeft--; //find the address in the vector. addressposition=numAddr-(ipv6_Source_Routing_Header->SegmentsLeft); if(local_CmprE==0) { msg->l2_nextORpreviousHop.type = ADDR_16B; msg->l3_destinationAdd.type = ADDR_16B; octetsAddressSize=2; memcpy(&(msg->l2_nextORpreviousHop.addr_16b),runningPointer+((addressposition-1)*octetsAddressSize),octetsAddressSize); memcpy(&(msg->l3_destinationAdd.addr_16b),runningPointer+((addressposition-1)*octetsAddressSize),octetsAddressSize); } else if(local_CmprE==8) { msg->l2_nextORpreviousHop.type = ADDR_64B; msg->l3_destinationAdd.type = ADDR_128B; octetsAddressSize=8; memcpy(&(msg->l2_nextORpreviousHop.addr_64b),runningPointer+((addressposition-1)*octetsAddressSize),octetsAddressSize); memcpy(&(msg->l3_destinationAdd.addr_128b[0]),prefix->prefix,8); memcpy(&(msg->l3_destinationAdd.addr_128b[8]),runningPointer+((addressposition-1)*octetsAddressSize),octetsAddressSize); } else if(local_CmprE==2) { msg->l2_nextORpreviousHop.type = ADDR_128B; msg->l3_destinationAdd.type = ADDR_128B; octetsAddressSize=16; memcpy(&(msg->l2_nextORpreviousHop.addr_128b),runningPointer+((addressposition-1)*octetsAddressSize),octetsAddressSize); memcpy(&(msg->l3_destinationAdd.addr_128b),runningPointer+((addressposition-1)*octetsAddressSize),octetsAddressSize); } else { msg->l2_nextORpreviousHop.type = ADDR_NONE; //error! while(1); } } } if (msg->l2_nextORpreviousHop.type==ADDR_NONE) { openserial_printError(COMPONENT_FORWARDING,ERR_NO_NEXTHOP, (errorparameter_t)0, (errorparameter_t)0); return E_FAIL; } return iphc_sendFromForwarding(msg, ipv6_header,PCKTFORWARD); }
/** \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 ); } } } }