error_t mldSendListenerDone(NetInterface *interface, Ipv6Addr *ipAddr) { error_t error; size_t offset; MldMessage *message; ChunkedBuffer *buffer; Ipv6PseudoHeader pseudoHeader; //Make sure the specified address is a valid multicast address if(!ipv6IsMulticastAddr(ipAddr)) return ERROR_INVALID_ADDRESS; //The link-scope all-nodes address (FF02::1) is handled as a special //case. The host never sends a report for that address if(ipv6CompAddr(ipAddr, &IPV6_LINK_LOCAL_ALL_NODES_ADDR)) return ERROR_INVALID_ADDRESS; //Allocate a memory buffer to hold a MLD message buffer = ipAllocBuffer(sizeof(MldMessage), &offset); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the beginning of the MLD message message = chunkedBufferAt(buffer, offset); //Format the Multicast Listener Done message message->type = ICMPV6_TYPE_MULTICAST_LISTENER_DONE_V1; message->code = 0; message->checksum = 0; message->maxRespDelay = 0; message->reserved = 0; message->multicastAddr = *ipAddr; //Format IPv6 pseudo header pseudoHeader.srcAddr = interface->ipv6Config.linkLocalAddr; pseudoHeader.destAddr = IPV6_LINK_LOCAL_ALL_ROUTERS_ADDR; pseudoHeader.length = HTONS(sizeof(MldMessage)); pseudoHeader.reserved = 0; pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER; //Message checksum calculation message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader, sizeof(Ipv6PseudoHeader), buffer, offset, sizeof(MldMessage)); //Debug message TRACE_INFO("Sending MLD message (%" PRIuSIZE " bytes)...\r\n", sizeof(MldMessage)); //Dump message contents for debugging purpose mldDumpMessage(message); //The Multicast Listener Done message is sent to the all-routers multicast address error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, MLD_HOP_LIMIT); //Free previously allocated memory chunkedBufferFree(buffer); //Return status code return error; }
error_t ndpSendNeighborAdv(NetInterface *interface, const Ipv6Addr *targetIpAddr, const Ipv6Addr *destIpAddr) { error_t error; size_t offset; size_t length; ChunkedBuffer *buffer; NdpNeighborAdvMessage *message; Ipv6PseudoHeader pseudoHeader; //Allocate a memory buffer to hold the Neighbor Advertisement //message and the Target Link-Layer Address option buffer = ipAllocBuffer(sizeof(NdpNeighborAdvMessage) + sizeof(NdpLinkLayerAddrOption), &offset); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the beginning of the message message = chunkedBufferAt(buffer, offset); //Format Neighbor Advertisement message message->type = ICMPV6_TYPE_NEIGHBOR_ADV; message->code = 0; message->checksum = 0; message->reserved1 = 0; message->o = TRUE; message->s = FALSE; message->r = FALSE; message->reserved2 = 0; message->targetAddr = *targetIpAddr; //Length of the message, excluding any option length = sizeof(NdpNeighborAdvMessage); //Add Target Link-Layer Address option ndpAddOption(message, &length, NDP_OPT_TARGET_LINK_LAYER_ADDR, &interface->macAddr, sizeof(MacAddr)); //Adjust the length of the multi-part buffer chunkedBufferSetLength(buffer, offset + length); //Format IPv6 pseudo header pseudoHeader.srcAddr = *targetIpAddr; pseudoHeader.destAddr = *destIpAddr; pseudoHeader.length = htonl(length); pseudoHeader.reserved = 0; pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER; //Destination IP address is the unspecified address? if(ipv6CompAddr(destIpAddr, &IPV6_UNSPECIFIED_ADDR)) { //If the destination is the unspecified address, the node //must set the Solicited flag to zero and multicast the //advertisement to the all-nodes address pseudoHeader.destAddr = IPV6_LINK_LOCAL_ALL_NODES_ADDR; } else { //Otherwise, the node must set the Solicited flag to one and //unicast the advertisement to the destination IP address message->s = TRUE; } //Calculate ICMPv6 header checksum message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader, sizeof(Ipv6PseudoHeader), buffer, offset, length); //Debug message TRACE_INFO("Sending Neighbor Advertisement message (%" PRIuSIZE " bytes)...\r\n", length); //Dump message contents for debugging purpose ndpDumpNeighborAdvMessage(message); //Send Neighbor Advertisement message error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, NDP_HOP_LIMIT); //Free previously allocated memory chunkedBufferFree(buffer); //Return status code return error; }
error_t ndpSendNeighborSol(NetInterface *interface, const Ipv6Addr *targetIpAddr) { error_t error; size_t offset; size_t length; ChunkedBuffer *buffer; NdpNeighborSolMessage *message; Ipv6PseudoHeader pseudoHeader; //Allocate a memory buffer to hold the Neighbor Solicitation //message and the Source Link-Layer Address option buffer = ipAllocBuffer(sizeof(NdpNeighborSolMessage) + sizeof(NdpLinkLayerAddrOption), &offset); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the beginning of the message message = chunkedBufferAt(buffer, offset); //Format Neighbor Solicitation message message->type = ICMPV6_TYPE_NEIGHBOR_SOL; message->code = 0; message->checksum = 0; message->reserved = 0; message->targetAddr = *targetIpAddr; //Length of the message, excluding any option length = sizeof(NdpNeighborSolMessage); //Check whether the target address is a tentative address if(ipv6IsTentativeAddr(interface, targetIpAddr)) { //The IPv6 source is set to the unspecified address pseudoHeader.srcAddr = IPV6_UNSPECIFIED_ADDR; } else { //The Source Link-Layer Address option must not be included //when the host IPv6 address is unspecified if(!ipv6CompAddr(&interface->ipv6Config.linkLocalAddr, &IPV6_UNSPECIFIED_ADDR)) { //Add Source Link-Layer Address option ndpAddOption(message, &length, NDP_OPT_SOURCE_LINK_LAYER_ADDR, &interface->macAddr, sizeof(MacAddr)); } //Set the IPv6 source address pseudoHeader.srcAddr = interface->ipv6Config.linkLocalAddr; } //Adjust the length of the multi-part buffer chunkedBufferSetLength(buffer, offset + length); //Compute the solicited-node multicast address that //corresponds to the target IPv6 address ipv6ComputeSolicitedNodeAddr(targetIpAddr, &pseudoHeader.destAddr); //Format IPv6 pseudo header pseudoHeader.length = htonl(length); pseudoHeader.reserved = 0; pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER; //Calculate ICMPv6 header checksum message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader, sizeof(Ipv6PseudoHeader), buffer, offset, length); //Debug message TRACE_INFO("Sending Neighbor Solicitation message (%" PRIuSIZE " bytes)...\r\n", length); //Dump message contents for debugging purpose ndpDumpNeighborSolMessage(message); //Send Neighbor Solicitation message error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, NDP_HOP_LIMIT); //Free previously allocated memory chunkedBufferFree(buffer); //Return status code return error; }
error_t icmpv6SendErrorMessage(NetInterface *interface, uint8_t type, uint8_t code, uint32_t parameter, const ChunkedBuffer *ipPacket) { error_t error; size_t offset; size_t length; Ipv6Header *ipHeader; ChunkedBuffer *icmpMessage; Icmpv6ErrorMessage *icmpHeader; Ipv6PseudoHeader pseudoHeader; //Retrieve the length of the invoking IPv6 packet length = chunkedBufferGetLength(ipPacket); //Check the length of the IPv6 packet if(length < sizeof(Ipv6Header)) return ERROR_INVALID_LENGTH; //Point to the header of the invoking packet ipHeader = chunkedBufferAt(ipPacket, 0); //Sanity check if(!ipHeader) return ERROR_FAILURE; //Never respond to a packet destined to an IPv6 multicast address if(ipv6IsMulticastAddr(&ipHeader->destAddr)) return ERROR_INVALID_ADDRESS; //Return as much of invoking IPv6 packet as possible without //the ICMPv6 packet exceeding the minimum IPv6 MTU length = MIN(length, IPV6_DEFAULT_MTU - sizeof(Ipv6Header) - sizeof(Icmpv6ErrorMessage)); //Allocate a memory buffer to hold the ICMPv6 message icmpMessage = ipAllocBuffer(sizeof(Icmpv6ErrorMessage), &offset); //Failed to allocate memory? if(!icmpMessage) return ERROR_OUT_OF_MEMORY; //Point to the ICMPv6 header icmpHeader = chunkedBufferAt(icmpMessage, offset); //Format ICMPv6 Error message icmpHeader->type = type; icmpHeader->code = code; icmpHeader->checksum = 0; icmpHeader->parameter = htonl(parameter); //Copy incoming IPv6 packet contents error = chunkedBufferConcat(icmpMessage, ipPacket, 0, length); //Any error to report? if(error) { //Clean up side effects chunkedBufferFree(icmpMessage); //Exit immediately return error; } //Get the length of the resulting message length = chunkedBufferGetLength(icmpMessage) - offset; //Format IPv6 pseudo header pseudoHeader.srcAddr = ipHeader->destAddr; pseudoHeader.destAddr = ipHeader->srcAddr; pseudoHeader.length = htonl(length); pseudoHeader.reserved = 0; pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER; //Message checksum calculation icmpHeader->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader, sizeof(Ipv6PseudoHeader), icmpMessage, offset, length); //Debug message TRACE_INFO("Sending ICMPv6 Error message (%" PRIuSIZE " bytes)...\r\n", length); //Dump message contents for debugging purpose icmpv6DumpErrorMessage(icmpHeader); //Send ICMPv6 Error message error = ipv6SendDatagram(interface, &pseudoHeader, icmpMessage, offset, IPV6_DEFAULT_HOP_LIMIT); //Free previously allocated memory chunkedBufferFree(icmpMessage); //Return status code return error; }
void icmpv6ProcessEchoRequest(NetInterface *interface, Ipv6PseudoHeader *requestPseudoHeader, const ChunkedBuffer *request, size_t requestOffset) { error_t error; size_t requestLength; size_t replyOffset; size_t replyLength; ChunkedBuffer *reply; Icmpv6EchoMessage *requestHeader; Icmpv6EchoMessage *replyHeader; Ipv6PseudoHeader replyPseudoHeader; //Retrieve the length of the Echo Request message requestLength = chunkedBufferGetLength(request) - requestOffset; //Ensure the packet length is correct if(requestLength < sizeof(Icmpv6EchoMessage)) return; //Point to the Echo Request header requestHeader = chunkedBufferAt(request, requestOffset); //Sanity check if(!requestHeader) return; //Debug message TRACE_INFO("ICMPv6 Echo Request message received (%" PRIuSIZE " bytes)...\r\n", requestLength); //Dump message contents for debugging purpose icmpv6DumpEchoMessage(requestHeader); //Allocate memory to hold the Echo Reply message reply = ipAllocBuffer(sizeof(Icmpv6EchoMessage), &replyOffset); //Failed to allocate memory? if(!reply) return; //Point to the Echo Reply header replyHeader = chunkedBufferAt(reply, replyOffset); //Format Echo Reply header replyHeader->type = ICMPV6_TYPE_ECHO_REPLY; replyHeader->code = 0; replyHeader->checksum = 0; replyHeader->identifier = requestHeader->identifier; replyHeader->sequenceNumber = requestHeader->sequenceNumber; //Point to the first data byte requestOffset += sizeof(Icmpv6EchoMessage); requestLength -= sizeof(Icmpv6EchoMessage); //Copy data error = chunkedBufferConcat(reply, request, requestOffset, requestLength); //Any error to report? if(error) { //Clean up side effects chunkedBufferFree(reply); //Exit immediately return; } //Get the length of the resulting message replyLength = chunkedBufferGetLength(reply) - replyOffset; //Format IPv6 pseudo header replyPseudoHeader.srcAddr = requestPseudoHeader->destAddr; replyPseudoHeader.destAddr = requestPseudoHeader->srcAddr; replyPseudoHeader.length = htonl(replyLength); replyPseudoHeader.reserved = 0; replyPseudoHeader.nextHeader = IPV6_ICMPV6_HEADER; //Message checksum calculation replyHeader->checksum = ipCalcUpperLayerChecksumEx(&replyPseudoHeader, sizeof(Ipv6PseudoHeader), reply, replyOffset, replyLength); //Debug message TRACE_INFO("Sending ICMPv6 Echo Reply message (%" PRIuSIZE " bytes)...\r\n", replyLength); //Dump message contents for debugging purpose icmpv6DumpEchoMessage(replyHeader); //Send Echo Reply message ipv6SendDatagram(interface, &replyPseudoHeader, reply, replyOffset, IPV6_DEFAULT_HOP_LIMIT); //Free previously allocated memory block chunkedBufferFree(reply); }