void ndpSendQueuedPackets(NetInterface *interface, NdpCacheEntry *entry) { uint_t i; //Check current state if(entry->state == NDP_STATE_INCOMPLETE) { //Loop through queued packets for(i = 0; i < entry->queueSize; i++) { //Send current packet ethSendFrame(interface, &entry->macAddr, entry->queue[i].buffer, entry->queue[i].offset, ETH_TYPE_IPV6); //Release previously allocated memory chunkedBufferFree(entry->queue[i].buffer); } } //The queue is now empty entry->queueSize = 0; }
error_t arpSendReply(NetInterface *interface, Ipv4Addr targetIpAddr, const MacAddr *targetMacAddr, const MacAddr *destMacAddr) { error_t error; size_t offset; ChunkedBuffer *buffer; ArpPacket *arpReply; //Allocate a memory buffer to hold an ARP packet buffer = ethAllocBuffer(sizeof(ArpPacket), &offset); //Failed to allocate buffer? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the beginning of the ARP packet arpReply = chunkedBufferAt(buffer, offset); //Format ARP reply arpReply->hrd = htons(ARP_HARDWARE_TYPE_ETH); arpReply->pro = htons(ETH_TYPE_IPV4); arpReply->hln = sizeof(MacAddr); arpReply->pln = sizeof(Ipv4Addr); arpReply->op = htons(ARP_OPCODE_ARP_REPLY); arpReply->sha = interface->macAddr; arpReply->spa = interface->ipv4Config.addr; arpReply->tha = *targetMacAddr; arpReply->tpa = targetIpAddr; //Debug message TRACE_INFO("Sending ARP Reply (%u bytes)...\r\n", sizeof(ArpPacket)); //Dump ARP packet contents for debugging purpose arpDumpPacket(arpReply); //Send ARP reply error = ethSendFrame(interface, destMacAddr, buffer, offset, ETH_TYPE_ARP); //Free previously allocated memory chunkedBufferFree(buffer); //Return status code return error; }
error_t ndpEnqueuePacket(NetInterface *interface, const Ipv6Addr *ipAddr, ChunkedBuffer *buffer, size_t offset) { error_t error; uint_t i; size_t length; NdpCacheEntry *entry; //Retrieve the length of the multi-part buffer length = chunkedBufferGetLength(buffer); //Acquire exclusive access to Neighbor cache osAcquireMutex(&interface->ndpCacheMutex); //Search the Neighbor cache for the specified Ipv6 address entry = ndpFindEntry(interface, ipAddr); //No matching entry in Neighbor cache? if(!entry) { //Release exclusive access to Neighbor cache osReleaseMutex(&interface->ndpCacheMutex); //Report an error to the calling function return ERROR_FAILURE; } //Check current state if(entry->state == NDP_STATE_INCOMPLETE) { //Check whether the packet queue is full if(entry->queueSize >= NDP_MAX_PENDING_PACKETS) { //When the queue overflows, the new arrival should replace the oldest entry chunkedBufferFree(entry->queue[0].buffer); //Make room for the new packet for(i = 1; i < NDP_MAX_PENDING_PACKETS; i++) entry->queue[i - 1] = entry->queue[i]; //Adjust the number of pending packets entry->queueSize--; } //Index of the entry to be filled in i = entry->queueSize; //Allocate a memory buffer to store the packet entry->queue[i].buffer = chunkedBufferAlloc(length); //Failed to allocate memory? if(!entry->queue[i].buffer) { //Release exclusive access to Neighbor cache osReleaseMutex(&interface->ndpCacheMutex); //Report an error to the calling function return ERROR_OUT_OF_MEMORY; } //Copy packet contents chunkedBufferCopy(entry->queue[i].buffer, 0, buffer, 0, length); //Offset to the first byte of the IPv6 header entry->queue[i].offset = offset; //Increment the number of queued packets entry->queueSize++; //The packet was successfully enqueued error = NO_ERROR; } else { //Send immediately the packet since the address is already resolved error = ethSendFrame(interface, &entry->macAddr, buffer, offset, ETH_TYPE_IPV6); } //Release exclusive access to Neighbor cache osReleaseMutex(&interface->ndpCacheMutex); //Return status code return error; }
error_t ipv4SendPacket(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader, uint16_t fragId, uint16_t fragOffset, ChunkedBuffer *buffer, size_t offset, uint8_t timeToLive) { error_t error; size_t length; Ipv4Addr destIpAddr = 0; MacAddr destMacAddr; Ipv4Header *packet; //Is there enough space for the IPv4 header? if(offset < sizeof(Ipv4Header)) return ERROR_INVALID_PARAMETER; //Make room for the header offset -= sizeof(Ipv4Header); //Calculate the size of the entire packet, including header and data length = chunkedBufferGetLength(buffer) - offset; //Point to the IPv4 header packet = chunkedBufferAt(buffer, offset); //Format IPv4 header packet->version = IPV4_VERSION; packet->headerLength = 5; packet->typeOfService = 0; packet->totalLength = htons(length); packet->identification = htons(fragId); packet->fragmentOffset = htons(fragOffset); packet->timeToLive = timeToLive; packet->protocol = pseudoHeader->protocol; packet->headerChecksum = 0; packet->srcAddr = pseudoHeader->srcAddr; packet->destAddr = pseudoHeader->destAddr; //Calculate IP header checksum packet->headerChecksum = ipCalcChecksumEx(buffer, offset, packet->headerLength * 4); //Ensure the source address is valid error = ipv4CheckSourceAddr(interface, pseudoHeader->srcAddr); //Invalid source address? if(error) return error; //Destination address is the unspecified address? if(pseudoHeader->destAddr == IPV4_UNSPECIFIED_ADDR) { //Destination address is not acceptable error = ERROR_INVALID_ADDRESS; } //Destination address is the loopback address? else if(pseudoHeader->destAddr == IPV4_LOOPBACK_ADDR) { //Not yet implemented... error = ERROR_NOT_IMPLEMENTED; } //Destination address is a broadcast address? else if(ipv4IsBroadcastAddr(interface, pseudoHeader->destAddr)) { //Destination IPv4 address destIpAddr = pseudoHeader->destAddr; //Make use of the broadcast MAC address destMacAddr = MAC_BROADCAST_ADDR; //No error to report error = NO_ERROR; } //Destination address is a multicast address? else if(ipv4IsMulticastAddr(pseudoHeader->destAddr)) { //Destination IPv4 address destIpAddr = pseudoHeader->destAddr; //Map IPv4 multicast address to MAC-layer multicast address error = ipv4MapMulticastAddrToMac(pseudoHeader->destAddr, &destMacAddr); } //Destination host is in the local subnet? else if(ipv4IsInLocalSubnet(interface, pseudoHeader->destAddr)) { //Destination IPv4 address destIpAddr = pseudoHeader->destAddr; //Resolve host address before sending the packet error = arpResolve(interface, pseudoHeader->destAddr, &destMacAddr); } //Destination host is outside the local subnet? else { //Make sure the default gateway is properly set if(interface->ipv4Config.defaultGateway != IPV4_UNSPECIFIED_ADDR) { //Use the default gateway to forward the packet destIpAddr = interface->ipv4Config.defaultGateway; //Perform address resolution error = arpResolve(interface, interface->ipv4Config.defaultGateway, &destMacAddr); } else { //There is no route to the outside world... error = ERROR_NO_ROUTE; } } //Successful address resolution? if(!error) { //Debug message TRACE_INFO("Sending IPv4 packet (%u bytes)...\r\n", length); //Dump IP header contents for debugging purpose ipv4DumpHeader(packet); //Send Ethernet frame error = ethSendFrame(interface, &destMacAddr, buffer, offset, ETH_TYPE_IPV4); } //Address resolution is in progress? else if(error == ERROR_IN_PROGRESS) { //Debug message TRACE_INFO("Enqueuing IPv4 packet (%u bytes)...\r\n", length); //Dump IP header contents for debugging purpose ipv4DumpHeader(packet); //Enqueue packets waiting for address resolution error = arpEnqueuePacket(interface, destIpAddr, buffer, offset); } //Address resolution failed? else { //Debug message TRACE_WARNING("Cannot map IPv4 address to Ethernet address!\r\n"); } //Return status code return error; }