error_t ipv4FragmentDatagram(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader, uint16_t id, const ChunkedBuffer *payload, size_t payloadOffset, uint8_t timeToLive) { error_t error; size_t offset; size_t length; size_t payloadLength; size_t fragmentOffset; ChunkedBuffer *fragment; //Retrieve the length of the payload payloadLength = chunkedBufferGetLength(payload) - payloadOffset; //Allocate a memory buffer to hold IP fragments fragment = ipAllocBuffer(0, &fragmentOffset); //Failed to allocate memory? if(!fragment) return ERROR_OUT_OF_MEMORY; //Split the payload into multiple IP fragments for(offset = 0; offset < payloadLength; offset += length) { //Flush the contents of the fragment error = chunkedBufferSetLength(fragment, fragmentOffset); //Sanity check if(error) break; //Process the last fragment? if((payloadLength - offset) <= IPV4_MAX_FRAG_SIZE) { //Size of the current fragment length = payloadLength - offset; //Copy fragment data chunkedBufferConcat(fragment, payload, payloadOffset + offset, length); //Do not set the MF flag for the last fragment error = ipv4SendPacket(interface, pseudoHeader, id, offset / 8, fragment, fragmentOffset, timeToLive); } else { //Size of the current fragment (must be a multiple of 8-byte blocks) length = IPV4_MAX_FRAG_SIZE; //Copy fragment data chunkedBufferConcat(fragment, payload, payloadOffset + offset, length); //Fragmented packets must have the MF flag set error = ipv4SendPacket(interface, pseudoHeader, id, IPV4_FLAG_MF | (offset / 8), fragment, fragmentOffset, timeToLive); } //Failed to send current IP packet? if(error) break; } //Free previously allocated memory chunkedBufferFree(fragment); //Return status code return error; }
error_t ipv4SendDatagram(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader, NetBuffer *buffer, size_t offset, uint8_t ttl) { error_t error; size_t length; uint16_t id; //Retrieve the length of payload length = netBufferGetLength(buffer) - offset; //Check whether the TTL value is zero if(ttl == 0) { //Use default Time-To-Live value ttl = IPV4_DEFAULT_TTL; } //Identification field is primarily used to identify //fragments of an original IP datagram id = osAtomicInc16(&interface->ipv4Identification); //If the payload length is smaller than the network //interface MTU then no fragmentation is needed if((length + sizeof(Ipv4Header)) <= interface->ipv4Config.mtu) { //Send data as is error = ipv4SendPacket(interface, pseudoHeader, id, 0, buffer, offset, ttl); } //If the payload length exceeds the network interface MTU //then the device must fragment the data else { #if (IPV4_FRAG_SUPPORT == ENABLED) //Fragment IP datagram into smaller packets error = ipv4FragmentDatagram(interface, pseudoHeader, id, buffer, offset, ttl); #else //Fragmentation is not supported error = ERROR_MESSAGE_TOO_LONG; #endif } //Return status code return error; }
error_t ipv4SendDatagram(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader, ChunkedBuffer *buffer, size_t offset, uint8_t timeToLive) { error_t error; size_t length; uint16_t id; //Retrieve the length of payload length = chunkedBufferGetLength(buffer) - offset; //Identification field is primarily used to identify //fragments of an original IP datagram id = osAtomicInc16(&interface->ipv4Identification); //If the payload length is smaller than the network //interface MTU then no fragmentation is needed if(length <= IPV4_MAX_PAYLOAD_SIZE) { //Send data as is error = ipv4SendPacket(interface, pseudoHeader, id, 0, buffer, offset, timeToLive); } //If the payload length exceeds the network interface MTU //then the device must fragment the data else { #if (IPV4_FRAG_SUPPORT == ENABLED) //Fragment IP datagram into smaller packets error = ipv4FragmentDatagram(interface, pseudoHeader, id, buffer, offset, timeToLive); #else //Fragmentation is not supported error = ERROR_MESSAGE_TOO_LONG; #endif } //Return status code return error; }