error_t ipv4LeaveMulticastGroup(NetInterface *interface, Ipv4Addr groupAddr) { uint_t i; uint_t j; MacAddr macAddr; //Ensure the specified IPv4 address is a multicast address if(!ipv4IsMulticastAddr(groupAddr)) return ERROR_INVALID_ADDRESS; //Acquire exclusive access to the IPv4 filter table osAcquireMutex(&interface->ipv4FilterMutex); //Loop through filter table entries for(i = 0; i < interface->ipv4FilterSize; i++) { //Specified IPv4 address found? if(interface->ipv4Filter[i].addr == groupAddr) { //Decrement the reference count interface->ipv4Filter[i].refCount--; //Remove the entry if the reference count drops to zero if(interface->ipv4Filter[i].refCount < 1) { #if (IGMP_SUPPORT == ENABLED) //Report group membership termination igmpLeaveGroup(interface, &interface->ipv4Filter[i]); #endif //Map the multicast IPv4 address to a MAC-layer address ipv4MapMulticastAddrToMac(groupAddr, &macAddr); #if (ETH_SUPPORT == ENABLED) //Drop the corresponding address from the MAC filter table ethDropMulticastAddr(interface, &macAddr); #endif //Adjust the size of the IPv4 filter table interface->ipv4FilterSize--; //Remove the corresponding entry for(j = i; j < interface->ipv4FilterSize; j++) interface->ipv4Filter[j] = interface->ipv4Filter[j + 1]; } //Release exclusive access to the IPv4 filter table osReleaseMutex(&interface->ipv4FilterMutex); //No error to report return NO_ERROR; } } //Release exclusive access to the IPv4 filter table osReleaseMutex(&interface->ipv4FilterMutex); //The specified IPv4 address does not exist return ERROR_FAILURE; }
error_t ipv4JoinMulticastGroup(NetInterface *interface, Ipv4Addr groupAddr) { error_t error; uint_t i; MacAddr macAddr; //Ensure the specified IPv4 address is a multicast address if(!ipv4IsMulticastAddr(groupAddr)) return ERROR_INVALID_ADDRESS; //Acquire exclusive access to the IPv4 filter table osMutexAcquire(interface->ipv4FilterMutex); //Loop through filter table entries for(i = 0; i < interface->ipv4FilterSize; i++) { //Check whether the table already contains the specified IPv4 address if(interface->ipv4Filter[i].addr == groupAddr) { //Increment the reference count interface->ipv4Filter[i].refCount++; //Release exclusive access to the IPv4 filter table osMutexRelease(interface->ipv4FilterMutex); //No error to report return NO_ERROR; } } //The IPv4 filter table is full ? if(i >= IPV4_FILTER_MAX_SIZE) { //Release exclusive access to the IPv4 filter table osMutexRelease(interface->ipv4FilterMutex); //A new entry cannot be added return ERROR_FAILURE; } //Map the multicast IPv4 address to a MAC-layer address ipv4MapMulticastAddrToMac(groupAddr, &macAddr); //Add the corresponding address to the MAC filter table error = ethAcceptMulticastAddr(interface, &macAddr); //Ensure the MAC filter table was successfully updated if(!error) { //Now we can safely add a new entry to the table interface->ipv4Filter[i].addr = groupAddr; //Initialize the reference count interface->ipv4Filter[i].refCount = 1; //Adjust the size of the IPv4 filter table interface->ipv4FilterSize++; #if (IGMP_SUPPORT == ENABLED) //Report multicast group membership to the router igmpJoinGroup(interface, &interface->ipv4Filter[i]); #endif } //Release exclusive access to the IPv4 filter table osMutexRelease(interface->ipv4FilterMutex); //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; }