void icmpv6echo_trigger() { uint8_t number_bytes_from_input_buffer; uint8_t input_buffer[16]; OpenQueueEntry_t* msg; //get command from OpenSerial (16B IPv6 destination address) number_bytes_from_input_buffer = openserial_getInputBuffer(&(input_buffer[0]),sizeof(input_buffer)); if (number_bytes_from_input_buffer!=sizeof(input_buffer)) { openserial_printError(COMPONENT_ICMPv6ECHO,ERR_INPUTBUFFER_LENGTH, (errorparameter_t)number_bytes_from_input_buffer, (errorparameter_t)0); return; }; icmpv6echo_vars.hisAddress.type = ADDR_128B; memcpy(&(icmpv6echo_vars.hisAddress.addr_128b[0]),&(input_buffer[0]),16); //send if (icmpv6echo_vars.busySending==TRUE) { openserial_printError(COMPONENT_ICMPv6ECHO,ERR_BUSY_SENDING, (errorparameter_t)0, (errorparameter_t)0); } else { icmpv6echo_vars.busySending = TRUE; msg = openqueue_getFreePacketBuffer(COMPONENT_ICMPv6ECHO); if (msg==NULL) { openserial_printError(COMPONENT_ICMPv6ECHO,ERR_NO_FREE_PACKET_BUFFER, (errorparameter_t)0, (errorparameter_t)0); icmpv6echo_vars.busySending = FALSE; return; } //admin msg->creator = COMPONENT_ICMPv6ECHO; msg->owner = COMPONENT_ICMPv6ECHO; //l4 msg->l4_protocol = IANA_ICMPv6; msg->l4_sourcePortORicmpv6Type = IANA_ICMPv6_ECHO_REQUEST; //l3 memcpy(&(msg->l3_destinationAdd),&icmpv6echo_vars.hisAddress,sizeof(open_addr_t)); //payload packetfunctions_reserveHeaderSize(msg,4); packetfunctions_htonl(0x789abcde,(uint8_t*)(msg->payload)); //ICMPv6 header packetfunctions_reserveHeaderSize(msg,sizeof(ICMPv6_ht)); ((ICMPv6_ht*)(msg->payload))->type = msg->l4_sourcePortORicmpv6Type; ((ICMPv6_ht*)(msg->payload))->code = 0; // Below Identifier might need to be replaced by the identifier used by icmpv6rpl // packetfunctions_htons(0x1234 ,(uint8_t*)&((ICMPv6_ht*)(msg->payload))->identifier); // Below sequence_number might need to be removed // packetfunctions_htons(icmpv6echo_vars.seq++ ,(uint8_t*)&((ICMPv6_ht*)(msg->payload))->sequence_number); packetfunctions_calculateChecksum(msg,(uint8_t*)&(((ICMPv6_ht*)(msg->payload))->checksum));//do last //send if (icmpv6_send(msg)!=E_SUCCESS) { icmpv6echo_vars.busySending = FALSE; openqueue_freePacketBuffer(msg); } } }
error_t openudp_send(OpenQueueEntry_t* msg) { msg->owner = COMPONENT_OPENUDP; msg->l4_protocol = IANA_UDP; msg->l4_payload = msg->payload; msg->l4_length = msg->length; packetfunctions_reserveHeaderSize(msg,sizeof(udp_ht)); packetfunctions_htons(msg->l4_sourcePortORicmpv6Type,&(msg->payload[0])); packetfunctions_htons(msg->l4_destination_port,&(msg->payload[2])); packetfunctions_htons(msg->length,&(msg->payload[4])); packetfunctions_calculateChecksum(msg,(uint8_t*)&(((udp_ht*)msg->payload)->checksum)); return forwarding_send(msg); }
void icmpv6echo_receive(OpenQueueEntry_t* msg) { OpenQueueEntry_t* reply; msg->owner = COMPONENT_ICMPv6ECHO; switch(msg->l4_sourcePortORicmpv6Type) { case IANA_ICMPv6_ECHO_REQUEST: openserial_printInfo(COMPONENT_ICMPv6ECHO,ERR_RCVD_ECHO_REQUEST, (errorparameter_t)0, (errorparameter_t)0); // get a new openqueuEntry_t for the echo reply reply = openqueue_getFreePacketBuffer(COMPONENT_ICMPv6ECHO); if (reply==NULL) { openserial_printError(COMPONENT_ICMPv6ECHO,ERR_NO_FREE_PACKET_BUFFER, (errorparameter_t)1, (errorparameter_t)0); openqueue_freePacketBuffer(msg); return; } // take ownership over reply reply->creator = COMPONENT_ICMPv6ECHO; reply->owner = COMPONENT_ICMPv6ECHO; // copy payload from msg to (end of) reply packetfunctions_reserveHeaderSize(reply,msg->length); memcpy(reply->payload,msg->payload,msg->length); // copy source of msg in destination of reply memcpy(&(reply->l3_destinationAdd),&(msg->l3_sourceAdd),sizeof(open_addr_t)); // free up msg openqueue_freePacketBuffer(msg); msg = NULL; // administrative information for reply reply->l4_protocol = IANA_ICMPv6; reply->l4_sourcePortORicmpv6Type = IANA_ICMPv6_ECHO_REPLY; ((ICMPv6_ht*)(reply->payload))->type = reply->l4_sourcePortORicmpv6Type; packetfunctions_calculateChecksum(reply,(uint8_t*)&(((ICMPv6_ht*)(reply->payload))->checksum));//do last icmpv6echo_vars.busySending = TRUE; if (icmpv6_send(reply)!=E_SUCCESS) { icmpv6echo_vars.busySending = FALSE; openqueue_freePacketBuffer(reply); } break; case IANA_ICMPv6_ECHO_REPLY: openserial_printInfo(COMPONENT_ICMPv6ECHO,ERR_RCVD_ECHO_REPLY, (errorparameter_t)0, (errorparameter_t)0); openqueue_freePacketBuffer(msg); break; default: openserial_printError(COMPONENT_ICMPv6ECHO,ERR_UNSUPPORTED_ICMPV6_TYPE, (errorparameter_t)msg->l4_sourcePortORicmpv6Type, (errorparameter_t)2); openqueue_freePacketBuffer(msg); break; } }
void prependTCPHeader(OpenQueueEntry_t* msg, bool ack, bool push, bool rst, bool syn, bool fin) { msg->l4_protocol = IANA_TCP; packetfunctions_reserveHeaderSize(msg,sizeof(tcp_ht)); packetfunctions_htons(tcp_vars.myPort ,(uint8_t*)&(((tcp_ht*)msg->payload)->source_port)); packetfunctions_htons(tcp_vars.hisPort ,(uint8_t*)&(((tcp_ht*)msg->payload)->destination_port)); packetfunctions_htonl(tcp_vars.mySeqNum ,(uint8_t*)&(((tcp_ht*)msg->payload)->sequence_number)); packetfunctions_htonl(tcp_vars.hisNextSeqNum ,(uint8_t*)&(((tcp_ht*)msg->payload)->ack_number)); ((tcp_ht*)msg->payload)->data_offset = TCP_DEFAULT_DATA_OFFSET; ((tcp_ht*)msg->payload)->control_bits = 0; if (ack==TCP_ACK_YES) { ((tcp_ht*)msg->payload)->control_bits |= 1 << TCP_ACK; } else { packetfunctions_htonl(0,(uint8_t*)&(((tcp_ht*)msg->payload)->ack_number)); } if (push==TCP_PSH_YES) { ((tcp_ht*)msg->payload)->control_bits |= 1 << TCP_PSH; } if (rst==TCP_RST_YES) { ((tcp_ht*)msg->payload)->control_bits |= 1 << TCP_RST; } if (syn==TCP_SYN_YES) { ((tcp_ht*)msg->payload)->control_bits |= 1 << TCP_SYN; } if (fin==TCP_FIN_YES) { ((tcp_ht*)msg->payload)->control_bits |= 1 << TCP_FIN; } packetfunctions_htons(TCP_DEFAULT_WINDOW_SIZE ,(uint8_t*)&(((tcp_ht*)msg->payload)->window_size)); packetfunctions_htons(TCP_DEFAULT_URGENT_POINTER ,(uint8_t*)&(((tcp_ht*)msg->payload)->urgent_pointer)); //calculate checksum last to take all header fields into account packetfunctions_calculateChecksum(msg,(uint8_t*)&(((tcp_ht*)msg->payload)->checksum)); }
/** \brief Prepare and a send a RPL DAO. */ void sendDAO() { OpenQueueEntry_t* msg; // pointer to DAO messages uint8_t nbrIdx; // running neighbor index uint8_t numTransitParents,numTargetParents; // the number of parents indicated in transit option open_addr_t address; open_addr_t* prefix; if (ieee154e_isSynch()==FALSE) { // I'm not sync'ed // delete packets genereted by this module (DIO and DAO) from openqueue openqueue_removeAllCreatedBy(COMPONENT_ICMPv6RPL); // I'm not busy sending a DIO/DAO icmpv6rpl_vars.busySending = FALSE; // stop here return; } // dont' send a DAO if you're in bridge mode if (idmanager_getIsBridge()==TRUE) { return; } // dont' send a DAO if you did not acquire a DAGrank if (neighbors_getMyDAGrank()==DEFAULTDAGRANK) { return; } // dont' send a DAO if you're still busy sending the previous one if (icmpv6rpl_vars.busySending==TRUE) { return; } // if you get here, you start construct DAO // reserve a free packet buffer for DAO msg = openqueue_getFreePacketBuffer(COMPONENT_ICMPv6RPL); if (msg==NULL) { openserial_printError(COMPONENT_ICMPv6RPL,ERR_NO_FREE_PACKET_BUFFER, (errorparameter_t)0, (errorparameter_t)0); return; } // take ownership msg->creator = COMPONENT_ICMPv6RPL; msg->owner = COMPONENT_ICMPv6RPL; // set transport information msg->l4_protocol = IANA_ICMPv6; msg->l4_sourcePortORicmpv6Type = IANA_ICMPv6_RPL; // set DAO destination msg->l3_destinationAdd.type=ADDR_128B; memcpy(msg->l3_destinationAdd.addr_128b,icmpv6rpl_vars.dio.DODAGID,sizeof(icmpv6rpl_vars.dio.DODAGID)); //===== fill in packet //NOTE: limit to preferrred parent only the number of DAO transit addresses to send //=== transit option -- from RFC 6550, page 55 - 1 transit information header per parent is required. //getting only preferred parent as transit numTransitParents=0; neighbors_getPreferredParentEui64(&address); packetfunctions_writeAddress(msg,&address,OW_BIG_ENDIAN); prefix=idmanager_getMyID(ADDR_PREFIX); packetfunctions_writeAddress(msg,prefix,OW_BIG_ENDIAN); // update transit info fields // from rfc6550 p.55 -- Variable, depending on whether or not the DODAG ParentAddress subfield is present. // poipoi xv: it is not very clear if this includes all fields in the header. or as target info 2 bytes are removed. // using the same pattern as in target information. icmpv6rpl_vars.dao_transit.optionLength = LENGTH_ADDR128b + sizeof(icmpv6rpl_dao_transit_ht)-2; icmpv6rpl_vars.dao_transit.PathControl=0; //todo. this is to set the preference of this parent. icmpv6rpl_vars.dao_transit.type=OPTION_TRANSIT_INFORMATION_TYPE; // write transit info in packet packetfunctions_reserveHeaderSize(msg,sizeof(icmpv6rpl_dao_transit_ht)); memcpy( ((icmpv6rpl_dao_transit_ht*)(msg->payload)), &(icmpv6rpl_vars.dao_transit), sizeof(icmpv6rpl_dao_transit_ht) ); numTransitParents++; //target information is required. RFC 6550 page 55. /* One or more Transit Information options MUST be preceded by one or more RPL Target options. */ numTargetParents = 0; for (nbrIdx=0;nbrIdx<MAXNUMNEIGHBORS;nbrIdx++) { if ((neighbors_isNeighborWithHigherDAGrank(nbrIdx))==TRUE) { // this neighbor is of higher DAGrank as I am. so it is my child // write it's address in DAO RFC6550 page 80 check point 1. neighbors_getNeighbor(&address,ADDR_64B,nbrIdx); packetfunctions_writeAddress(msg,&address,OW_BIG_ENDIAN); prefix=idmanager_getMyID(ADDR_PREFIX); packetfunctions_writeAddress(msg,prefix,OW_BIG_ENDIAN); // update target info fields // from rfc6550 p.55 -- Variable, length of the option in octets excluding the Type and Length fields. // poipoi xv: assuming that type and length fields refer to the 2 first bytes of the header icmpv6rpl_vars.dao_target.optionLength = LENGTH_ADDR128b +sizeof(icmpv6rpl_dao_target_ht) - 2; //no header type and length icmpv6rpl_vars.dao_target.type = OPTION_TARGET_INFORMATION_TYPE; icmpv6rpl_vars.dao_target.flags = 0; //must be 0 icmpv6rpl_vars.dao_target.prefixLength = 128; //128 leading bits -- full address. // write transit info in packet packetfunctions_reserveHeaderSize(msg,sizeof(icmpv6rpl_dao_target_ht)); memcpy( ((icmpv6rpl_dao_target_ht*)(msg->payload)), &(icmpv6rpl_vars.dao_target), sizeof(icmpv6rpl_dao_target_ht) ); // remember I found it numTargetParents++; } //limit to MAX_TARGET_PARENTS the number of DAO target addresses to send //section 8.2.1 pag 67 RFC6550 -- using a subset // poipoi TODO base selection on ETX rather than first X. if (numTargetParents>=MAX_TARGET_PARENTS) break; } // stop here if no parents found if (numTransitParents==0) { openqueue_freePacketBuffer(msg); return; } icmpv6rpl_vars.dao_transit.PathSequence++; //increment path sequence. // if you get here, you will send a DAO //=== DAO header packetfunctions_reserveHeaderSize(msg,sizeof(icmpv6rpl_dao_ht)); memcpy( ((icmpv6rpl_dao_ht*)(msg->payload)), &(icmpv6rpl_vars.dao), sizeof(icmpv6rpl_dao_ht) ); //=== ICMPv6 header packetfunctions_reserveHeaderSize(msg,sizeof(ICMPv6_ht)); ((ICMPv6_ht*)(msg->payload))->type = msg->l4_sourcePortORicmpv6Type; ((ICMPv6_ht*)(msg->payload))->code = IANA_ICMPv6_RPL_DAO; packetfunctions_calculateChecksum(msg,(uint8_t*)&(((ICMPv6_ht*)(msg->payload))->checksum)); //call last //===== send if (icmpv6_send(msg)==E_SUCCESS) { icmpv6rpl_vars.busySending = TRUE; } else { openqueue_freePacketBuffer(msg); } }
/** \brief Prepare and a send a RPL DIO. */ void sendDIO() { OpenQueueEntry_t* msg; // stop if I'm not sync'ed if (ieee154e_isSynch()==FALSE) { // remove packets genereted by this module (DIO and DAO) from openqueue openqueue_removeAllCreatedBy(COMPONENT_ICMPv6RPL); // I'm not busy sending a DIO/DAO icmpv6rpl_vars.busySending = FALSE; // stop here return; } // do not send DIO if I'm in in bridge mode if (idmanager_getIsBridge()==TRUE) { return; } // do not send DIO if I have the default DAG rank if (neighbors_getMyDAGrank()==DEFAULTDAGRANK) { return; } // do not send DIO if I'm already busy sending if (icmpv6rpl_vars.busySending==TRUE) { return; } // if you get here, all good to send a DIO // I'm now busy sending icmpv6rpl_vars.busySending = TRUE; // reserve a free packet buffer for DIO msg = openqueue_getFreePacketBuffer(COMPONENT_ICMPv6RPL); if (msg==NULL) { openserial_printError(COMPONENT_ICMPv6RPL,ERR_NO_FREE_PACKET_BUFFER, (errorparameter_t)0, (errorparameter_t)0); icmpv6rpl_vars.busySending = FALSE; return; } // take ownership msg->creator = COMPONENT_ICMPv6RPL; msg->owner = COMPONENT_ICMPv6RPL; // set transport information msg->l4_protocol = IANA_ICMPv6; msg->l4_sourcePortORicmpv6Type = IANA_ICMPv6_RPL; // set DIO destination memcpy(&(msg->l3_destinationAdd),&icmpv6rpl_vars.dioDestination,sizeof(open_addr_t)); //===== DIO payload // note: DIO is already mostly populated icmpv6rpl_vars.dio.rank = neighbors_getMyDAGrank(); packetfunctions_reserveHeaderSize(msg,sizeof(icmpv6rpl_dio_ht)); memcpy( ((icmpv6rpl_dio_ht*)(msg->payload)), &(icmpv6rpl_vars.dio), sizeof(icmpv6rpl_dio_ht) ); //===== ICMPv6 header packetfunctions_reserveHeaderSize(msg,sizeof(ICMPv6_ht)); ((ICMPv6_ht*)(msg->payload))->type = msg->l4_sourcePortORicmpv6Type; ((ICMPv6_ht*)(msg->payload))->code = IANA_ICMPv6_RPL_DIO; packetfunctions_calculateChecksum(msg,(uint8_t*)&(((ICMPv6_ht*)(msg->payload))->checksum));//call last //send if (icmpv6_send(msg)!=E_SUCCESS) { icmpv6rpl_vars.busySending = FALSE; openqueue_freePacketBuffer(msg); } else { icmpv6rpl_vars.busySending = FALSE; } }