예제 #1
0
파일: security.c 프로젝트: giu7ppe/openwsn
uint8_t keyDescriptorLookup(uint8_t  		KeyIdMode,
					     	open_addr_t*	keySource,
						 	uint8_t 		KeyIndex,
						 	open_addr_t* 	DeviceAddress,
						 	//open_addr_t*	panID,
						 	uint8_t			frameType){

	uint8_t i;

	if(KeyIdMode == 0){
		if(neighbors_haveSomeChild() == TRUE){
			DeviceAddress = idmanager_getMyID(ADDR_64B);
		}else{
			DeviceAddress = keySource;
		}

		for(i=0; i<MAXNUMKEYS; i++ ){
			if(packetfunctions_sameAddress(DeviceAddress,MacKeyTable.KeyDescriptorElement[i].KeyIdLookupList.Address)){
				//match = i;
				return i;
			}
		}

	}

	//commented to SAVE ROM
	/*uint8_t j;
	if (KeyIdMode == 1){


		for(i=0; i<MAXNUMKEYS; i++ ){
			uint8_t j;
			for(j=0; j<MAXNUMNEIGHBORS; j++){

				if(KeyIndex == macKeyTab.KeyDescriptorElement[i].KeyIdLookupList.KeyIndex
							&& packetfunctions_sameAddress(keySource,macDefaultKeySource)){
							return i;
						}
					}
			}
	}*/

	if (KeyIdMode == 3){//even if KeyIdMode == 2, we not explicite this condition to save ROM

		for(i=0; i<MAXNUMKEYS; i++ ){
				if(KeyIndex == MacKeyTable.KeyDescriptorElement[i].KeyIdLookupList.KeyIndex){

				if( packetfunctions_sameAddress(keySource,MacKeyTable.KeyDescriptorElement[i].KeyIdLookupList.KeySource)
						//&& packetfunctions_sameAddress(panID, macKeyTab.KeyDescriptorElement[i].KeyIdLookupList.PANId)
						){
				return i;
				}

			}
		}
	}

	return 25;//no matches

}
예제 #2
0
파일: schedule.c 프로젝트: giu7ppe/openwsn
/**
\brief get the information of a spcific slot.

\param slotOffset
\param neighbor
\param info
*/
void  schedule_getSlotInfo(
   slotOffset_t         slotOffset,
   open_addr_t*         neighbor,
   slotinfo_element_t*  info
){
                           
   scheduleEntry_t* slotContainer;
  
   // find an empty schedule entry container
   slotContainer = &schedule_vars.scheduleBuf[0];
   while (slotContainer->type!=CELLTYPE_OFF && slotContainer<=&schedule_vars.scheduleBuf[MAXACTIVESLOTS-1]) {
       //check that this entry for that neighbour and timeslot is not already scheduled.
       if (packetfunctions_sameAddress(neighbor,&(slotContainer->neighbor))&& (slotContainer->slotOffset==slotOffset)){
               //it exists so this is an update.
               info->link_type                 = slotContainer->type;
               info->shared                    =slotContainer->shared;
               info->channelOffset             = slotContainer->channelOffset;
               return; //as this is an update. No need to re-insert as it is in the same position on the list.
        }
        slotContainer++;
   }
   //return cell type off.
   info->link_type                 = CELLTYPE_OFF;
   info->shared                    = FALSE;
   info->channelOffset             = 0;//set to zero if not set.                          
}
예제 #3
0
 OpenQueueEntry_t* openqueue_macGetDataPacket(open_addr_t* toNeighbor) {
   uint8_t i;
   INTERRUPT_DECLARATION();
   DISABLE_INTERRUPTS();
   if (toNeighbor->type==ADDR_64B) {
      // a neighbor is specified, look for a packet unicast to that neigbhbor
      for (i=0;i<QUEUELENGTH;i++) {
         if (openqueue_vars.queue[i].owner==COMPONENT_RES_TO_IEEE802154E &&
            packetfunctions_sameAddress(toNeighbor,&openqueue_vars.queue[i].l2_nextORpreviousHop)) {
            ENABLE_INTERRUPTS();
            return &openqueue_vars.queue[i];
         }
      }
   } else if (toNeighbor->type==ADDR_ANYCAST) {
      // anycast case: look for a packet which is either not created by RES
      // or an KA (created by RES, but not broadcast)
      for (i=0;i<QUEUELENGTH;i++) {
         if (openqueue_vars.queue[i].owner==COMPONENT_RES_TO_IEEE802154E &&
             ( openqueue_vars.queue[i].creator!=COMPONENT_RES ||
                (
                   openqueue_vars.queue[i].creator==COMPONENT_RES &&
                   packetfunctions_isBroadcastMulticast(&(openqueue_vars.queue[i].l2_nextORpreviousHop))==FALSE
                )
             )
            ) {
            ENABLE_INTERRUPTS();
            return &openqueue_vars.queue[i];
         }
      }
   }
   ENABLE_INTERRUPTS();
   return NULL;
}
예제 #4
0
/**
\brief Calculated how many slots have elapsed since last synchronized.

\param[in] timeCorrection time to be corrected
\param[in] timesource The address of neighbor.

\return the number of slots
*/
void adaptive_sync_preprocess(int16_t timeCorrection, open_addr_t timesource){
   uint8_t array[5];
   
   // stop calculating compensation period when compensateThreshold exceeds KATIMEOUT and drift is not changed
   if(
         adaptive_sync_vars.compensateThreshold  > MAXKAPERIOD &&
         adaptive_sync_vars.driftChanged        == FALSE
      ) {
     if(timeCorrection > LIMITLARGETIMECORRECTION) {
       //once I get a large time correction, it means previous calcluated drift is not accurate yet. The clock drift is changed.
       adaptive_sync_driftChanged();
     }
     return;
   }
   
   // check whether I am synchronized and also check whether it's the same neighbor synchronized to last time?
   if(
         adaptive_sync_vars.driftChanged == FALSE &&
         ieee154e_isSynch()                       &&
         packetfunctions_sameAddress(&timesource, &(adaptive_sync_vars.compensationInfo_vars.neighborID))
      ) {
        // only calcluate when asnDiff > compensateThresholdThreshold. (this is used for guaranteeing accuracy )
        if(ieee154e_asnDiff(&adaptive_sync_vars.oldASN) > adaptive_sync_vars.compensateThreshold) {
          // calculate compensation interval
          adaptive_sync_calculateCompensatedSlots(timeCorrection);
          // reset compensationtTicks and sumOfTC after calculation
          adaptive_sync_vars.compensateTicks             = 0;
          adaptive_sync_vars.sumOfTC                     = 0;
          // update threshold
          adaptive_sync_vars.compensateThreshold        *= 2;
          sixtop_setKaPeriod(adaptive_sync_vars.compensateThreshold);
          // update oldASN
          ieee154e_getAsn(array);
          adaptive_sync_vars.oldASN.bytes0and1           = ((uint16_t) array[1] << 8) | ((uint16_t) array[0]);
          adaptive_sync_vars.oldASN.bytes2and3           = ((uint16_t) array[3] << 8) | ((uint16_t) array[2]);
          adaptive_sync_vars.oldASN.byte4                = array[4]; 
        } else {
          // record the timeCorrection, if not calculate.
          adaptive_sync_vars.sumOfTC                    += timeCorrection;
        }
   } else {
     adaptive_sync_vars.compensateThreshold      = BASIC_COMPENSATION_THRESHOLD;
     sixtop_setKaPeriod(adaptive_sync_vars.compensateThreshold);
     // when I joined the network, or changed my time parent, reset adaptive_sync relative variables
     adaptive_sync_vars.clockState               = S_NONE;
     adaptive_sync_vars.elapsedSlots             = 0;
     adaptive_sync_vars.compensationTimeout      = 0;
     adaptive_sync_vars.compensateTicks          = 0;
     adaptive_sync_vars.sumOfTC                  = 0;
     // update oldASN
     ieee154e_getAsn(array);
     adaptive_sync_vars.oldASN.bytes0and1        = ((uint16_t) array[1] << 8) | ((uint16_t) array[0]);
     adaptive_sync_vars.oldASN.bytes2and3        = ((uint16_t) array[3] << 8) | ((uint16_t) array[2]);
     adaptive_sync_vars.oldASN.byte4             = array[4]; 
     // record this neighbor as my time source
     memcpy(&(adaptive_sync_vars.compensationInfo_vars.neighborID), &timesource, sizeof(open_addr_t));
   }
}
예제 #5
0
bool isThisRowMatching(open_addr_t* address, uint8_t rowNumber) {
   switch (address->type) {
      case ADDR_64B:
         return neighbors_vars.neighbors[rowNumber].used &&
                packetfunctions_sameAddress(address,&neighbors_vars.neighbors[rowNumber].addr_64b);
      default:
         openserial_printError(COMPONENT_NEIGHBORS,ERR_WRONG_ADDR_TYPE,
                               (errorparameter_t)address->type,
                               (errorparameter_t)3);
         return FALSE;
   }
}
예제 #6
0
bool idmanager_isMyAddress(open_addr_t* addr) {
   open_addr_t temp_my128bID;
   bool res;
   INTERRUPT_DECLARATION();
   DISABLE_INTERRUPTS();

   switch (addr->type) {
     case ADDR_16B:
        res= packetfunctions_sameAddress(addr,&idmanager_vars.my16bID);
        ENABLE_INTERRUPTS();
        return res;
     case ADDR_64B:
        res= packetfunctions_sameAddress(addr,&idmanager_vars.my64bID);
        ENABLE_INTERRUPTS();
        return res;
     case ADDR_128B:
        //build temporary my128bID
        temp_my128bID.type = ADDR_128B;
        memcpy(&temp_my128bID.addr_128b[0],&idmanager_vars.myPrefix.prefix,8);
        memcpy(&temp_my128bID.addr_128b[8],&idmanager_vars.my64bID.addr_64b,8);

        res= packetfunctions_sameAddress(addr,&temp_my128bID);
        ENABLE_INTERRUPTS();
        return res;
     case ADDR_PANID:
        res= packetfunctions_sameAddress(addr,&idmanager_vars.myPANID);
        ENABLE_INTERRUPTS();
        return res;
     case ADDR_PREFIX:
        res= packetfunctions_sameAddress(addr,&idmanager_vars.myPrefix);
        ENABLE_INTERRUPTS();
        return res;
     default:
        openserial_printCritical(COMPONENT_IDMANAGER,ERR_WRONG_ADDR_TYPE,
              (errorparameter_t)addr->type,
              (errorparameter_t)2);
        ENABLE_INTERRUPTS();
        return FALSE;
   }
}
예제 #7
0
파일: security.c 프로젝트: giu7ppe/openwsn
uint8_t deviceDescriptorLookup(open_addr_t* Address,
							   //open_addr_t* PANId,
							   m_keyDescriptor* keydescr){


	//commented to save ROM
	/*open_addr_t* aux;
	if(Address->type == IEEE154_ADDR_NONE){ //vado a prendere PANID, ShortAddress o Extended Address dal coordinator

		Address->type = ADDR_PANID;
		memcpy(Address->panid, (idmanager_getMyID(ADDR_PANID)->panid),sizeof(uint8_t)*2);
	}

	aux->addr_16b[1] = 255 ;
	aux->addr_16b[0] = 254 ;
	if(Address->type == IEEE154_ADDR_NONE && idmanager_getMyID(ADDR_16B) == aux){//questo significa che il dispositivo sta usando solo il suo extended address
		Address->type = ADDR_64B;
		memcpy(Address->addr_64b,(idmanager_getMyID(ADDR_64B)->addr_64b),sizeof(uint8_t)*8);
	}

	else{
		aux->addr_16b[1] = 255 ;
		aux->addr_16b[0] = 255 ;
		if(Address->type == IEEE154_ADDR_NONE && idmanager_getMyID(ADDR_16B) == aux){
			return answer;
		}
	}*/

	uint8_t i;

	for(i=0; i<MAXNUMNEIGHBORS; i++){

		if(packetfunctions_sameAddress(Address,keydescr->DeviceTable->DeviceDescriptorEntry[i].deviceAddress)== TRUE){
			return i;
		}
	}

	//return 25;
}
예제 #8
0
파일: schedule.c 프로젝트: giu7ppe/openwsn
owerror_t   schedule_removeActiveSlot(slotOffset_t   slotOffset, open_addr_t*   neighbor){
  
   owerror_t outcome;
   
   scheduleEntry_t* slotContainer;
   scheduleEntry_t* previousSlotWalker;

   INTERRUPT_DECLARATION();
   DISABLE_INTERRUPTS();
   
   
   // find the schedule entry
   slotContainer = &schedule_vars.scheduleBuf[0];
   while (slotContainer->type!=CELLTYPE_OFF && slotContainer<=&schedule_vars.scheduleBuf[MAXACTIVESLOTS-1]) {
          //check that this entry for that neighbour and timeslot is not already scheduled.
           if (packetfunctions_sameAddress(neighbor,&(slotContainer->neighbor))&& (slotContainer->slotOffset==slotOffset)){
               break;
           }
           slotContainer++;
   }
  
   if (slotContainer->next==slotContainer) {
      // this is the last active slot

      // the next slot of this slot is NULL
      slotContainer->next                   = NULL;

      // current slot points to this slot
      schedule_vars.currentScheduleEntry    = NULL;
   } else  {
      // this is NOT the last active slot

      // find the previous in the schedule
      previousSlotWalker                    = schedule_vars.currentScheduleEntry;
      
      while (1) {
        if (previousSlotWalker->next=slotContainer){
            break;
         }
         previousSlotWalker                 = previousSlotWalker->next;
      }
      // remove this element from the linked list
      previousSlotWalker->next              = slotContainer->next;//my next;
      slotContainer->next                   = NULL;
   }

    // clear that schedule entry 
    slotContainer->slotOffset                = 0;
    slotContainer->type                      = CELLTYPE_OFF;
    slotContainer->shared                    = FALSE;
    slotContainer->channelOffset             = 0;
    memset(&slotContainer->neighbor,0,sizeof(open_addr_t));

    // maintain debug stats
    schedule_dbg.numActiveSlotsCur--;
   
    outcome=E_SUCCESS;
    ENABLE_INTERRUPTS();
    
    return outcome;
}
예제 #9
0
파일: schedule.c 프로젝트: giu7ppe/openwsn
/**
\brief Add a new active slot into the schedule.

If udpate param is set then update it in case it exists.

\param slotOffset
\param type
\param shared
\param channelOffset
\param neighbor
\param isUpdate
*/
owerror_t schedule_addActiveSlot(
      slotOffset_t    slotOffset,
      cellType_t      type,
      bool            shared,
      channelOffset_t channelOffset,
      open_addr_t*    neighbor,
      bool            isUpdate
   ) {
   
   owerror_t outcome;
   
   scheduleEntry_t* slotContainer;
   scheduleEntry_t* previousSlotWalker;
   scheduleEntry_t* nextSlotWalker;
   INTERRUPT_DECLARATION();
   DISABLE_INTERRUPTS();
   
   
   // find an empty schedule entry container
   slotContainer = &schedule_vars.scheduleBuf[0];
   while (slotContainer->type!=CELLTYPE_OFF &&
         slotContainer<=&schedule_vars.scheduleBuf[MAXACTIVESLOTS-1]) {
  
           //check that this entry for that neighbour and timeslot is not already scheduled.
           if (type!=CELLTYPE_SERIALRX && type!=CELLTYPE_MORESERIALRX &&  
               (packetfunctions_sameAddress(neighbor,&(slotContainer->neighbor))||
                 (slotContainer->neighbor.type==ADDR_ANYCAST && isUpdate==TRUE))
                 &&(slotContainer->slotOffset==slotOffset)){
               //it exists so this is an update.
               slotContainer->type                      = type;
               slotContainer->shared                    = shared;
               slotContainer->channelOffset             = channelOffset;
               memcpy(&slotContainer->neighbor,neighbor,sizeof(open_addr_t));//update the address too!
               schedule_dbg.numUpdatedSlotsCur++;
               ENABLE_INTERRUPTS();
               return E_SUCCESS; //as this is an update. No need to re-insert as it is in the same position on the list.
           }
           
           slotContainer++;
   }
   
   if (isUpdate==TRUE) {
     //we are trying to update an item that is not in the schedule list.
     ENABLE_INTERRUPTS();
     return E_FAIL;
   }
   if (slotContainer>&schedule_vars.scheduleBuf[MAXACTIVESLOTS-1]) {
      // schedule has overflown
      outcome=E_FAIL;
      openserial_printCritical(COMPONENT_SCHEDULE,ERR_SCHEDULE_OVERFLOWN,
                            (errorparameter_t)0,
                            (errorparameter_t)0);
      
      
   }
   // fill that schedule entry with parameters passed
   slotContainer->slotOffset                = slotOffset;
   slotContainer->type                      = type;
   slotContainer->shared                    = shared;
   slotContainer->channelOffset             = channelOffset;
   memcpy(&slotContainer->neighbor,neighbor,sizeof(open_addr_t));

   if (schedule_vars.currentScheduleEntry==NULL) {
      // this is the first active slot added

      // the next slot of this slot is this slot
      slotContainer->next                   = slotContainer;

      // current slot points to this slot
      schedule_vars.currentScheduleEntry    = slotContainer;
   } else  {
      // this is NOT the first active slot added

      // find position in schedule
      previousSlotWalker                    = schedule_vars.currentScheduleEntry;
      while (1) {
         nextSlotWalker                     = previousSlotWalker->next;
         if (
               (
                     (previousSlotWalker->slotOffset <  slotContainer->slotOffset) &&
                     (slotContainer->slotOffset <  nextSlotWalker->slotOffset)
               )
               ||
               (
                     (previousSlotWalker->slotOffset <  slotContainer->slotOffset) &&
                     (nextSlotWalker->slotOffset <= previousSlotWalker->slotOffset)
               )
               ||
               (
                     (slotContainer->slotOffset <  nextSlotWalker->slotOffset) &&
                     (nextSlotWalker->slotOffset <= previousSlotWalker->slotOffset)
               )
         ) {
            break;
         }
         previousSlotWalker                 = nextSlotWalker;
      }
      // insert between previousSlotWalker and nextSlotWalker
      previousSlotWalker->next              = slotContainer;
      slotContainer->next                   = nextSlotWalker;
   }

   // maintain debug stats
   schedule_dbg.numActiveSlotsCur++;
   if (schedule_dbg.numActiveSlotsCur>schedule_dbg.numActiveSlotsMax) {
      schedule_dbg.numActiveSlotsMax        = schedule_dbg.numActiveSlotsCur;
   }
   outcome=E_SUCCESS;
   ENABLE_INTERRUPTS();
   return outcome;
}
예제 #10
0
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;
   }
}
예제 #11
0
/**
\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
    );
}
예제 #12
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
    );
}