Author: axeld Date: 2010-08-05 09:56:23 +0200 (Thu, 05 Aug 2010) New Revision: 37916 Changeset: http://dev.haiku-os.org/changeset/37916 Modified: haiku/trunk/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp Log: * We need to call arp_remove_local_entry() from arp_change_address() even if the old address is NULL for anything but SIOCAIFADDR. Hopefully, this fixes the problem Rene is seeing. * Make sure that arp_entry::protocol is not NULL before using it. This is necessary because of the possibility to manually set ARP entries. * Further improved debug output. * Minor cleanup. Modified: haiku/trunk/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp 2010-08-05 03:16:18 UTC (rev 37915) +++ haiku/trunk/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp 2010-08-05 07:56:23 UTC (rev 37916) @@ -127,6 +127,35 @@ static bool sIgnoreReplies; +#ifdef TRACE_ARP + + +const char* +mac_to_string(uint8* address) +{ + static char buffer[20]; + snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x", + address[0], address[1], address[2], address[3], address[4], address[5]); + return buffer; +} + + +const char* +inet_to_string(in_addr_t address) +{ + static char buffer[20]; + + unsigned int hostAddress = ntohl(address); + snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d", + hostAddress >> 24, (hostAddress >> 16) & 0xff, + (hostAddress >> 8) & 0xff, hostAddress & 0xff); + return buffer; +} + + +#endif // TRACE_ARP + + static net_buffer* get_request_buffer(arp_entry* entry) { @@ -165,6 +194,33 @@ } +static void +ipv4_to_ether_multicast(sockaddr_dl *destination, const sockaddr_in *source) +{ + // RFC 1112 - Host extensions for IP multicasting + // + // ``An IP host group address is mapped to an Ethernet multicast + // address by placing the low-order 23-bits of the IP address into + // the low-order 23 bits of the Ethernet multicast address + // 01-00-5E-00-00-00 (hex).'' + + destination->sdl_len = sizeof(sockaddr_dl); + destination->sdl_family = AF_LINK; + destination->sdl_index = 0; + destination->sdl_type = IFT_ETHER; + destination->sdl_e_type = ETHER_TYPE_IP; + destination->sdl_nlen = destination->sdl_slen = 0; + destination->sdl_alen = ETHER_ADDRESS_LENGTH; + + memcpy(LLADDR(destination) + 2, &source->sin_addr, sizeof(in_addr)); + uint32 *data = (uint32 *)LLADDR(destination); + data[0] = (data[0] & htonl(0x7f)) | htonl(0x01005e00); +} + + +// #pragma mark - + + /*static*/ int arp_entry::Compare(void *_entry, const void *_key) { @@ -316,33 +372,6 @@ // #pragma mark - -static void -ipv4_to_ether_multicast(sockaddr_dl *destination, const sockaddr_in *source) -{ - // RFC 1112 - Host extensions for IP multicasting - // - // ``An IP host group address is mapped to an Ethernet multicast - // address by placing the low-order 23-bits of the IP address into - // the low-order 23 bits of the Ethernet multicast address - // 01-00-5E-00-00-00 (hex).'' - - destination->sdl_len = sizeof(sockaddr_dl); - destination->sdl_family = AF_LINK; - destination->sdl_index = 0; - destination->sdl_type = IFT_ETHER; - destination->sdl_e_type = ETHER_TYPE_IP; - destination->sdl_nlen = destination->sdl_slen = 0; - destination->sdl_alen = ETHER_ADDRESS_LENGTH; - - memcpy(LLADDR(destination) + 2, &source->sin_addr, sizeof(in_addr)); - uint32 *data = (uint32 *)LLADDR(destination); - data[0] = (data[0] & htonl(0x7f)) | htonl(0x01005e00); -} - - -// #pragma mark - - - /*! Updates the entry determined by \a protocolAddress with the specified \a hardwareAddress. If such an entry does not exist yet, a new entry is added. If you try @@ -379,6 +408,7 @@ entry->hardware_address = *hardwareAddress; entry->timestamp = system_time(); + entry->protocol = NULL; } else { entry = arp_entry::Add(protocolAddress, hardwareAddress, flags); if (entry == NULL) @@ -393,7 +423,7 @@ sStackModule->set_timer(&entry->timer, ARP_STALE_TIMEOUT); } - if (entry->flags & ARP_FLAG_REJECT) + if ((entry->flags & ARP_FLAG_REJECT) != 0) entry->MarkFailed(); else entry->MarkValid(); @@ -409,10 +439,16 @@ arp_remove_local_entry(arp_protocol* protocol, const sockaddr* local, bool updateLocalAddress) { - in_addr_t inetAddress = ((sockaddr_in*)local)->sin_addr.s_addr; + in_addr_t inetAddress; - TRACE(("%s(): address %x\n", __FUNCTION__, inetAddress)); + if (local == NULL) { + // interface has not yet been set + inetAddress = INADDR_ANY; + } else + inetAddress = ((sockaddr_in*)local)->sin_addr.s_addr; + TRACE(("%s(): address %s\n", __FUNCTION__, inet_to_string(inetAddress))); + MutexLocker locker(sCacheLock); arp_entry* entry = arp_entry::Lookup(inetAddress); @@ -462,17 +498,17 @@ arp_set_local_entry(arp_protocol* protocol, const sockaddr* local) { MutexLocker locker(sCacheLock); - + net_interface* interface = protocol->interface; in_addr_t inetAddress; - + if (local == NULL) { // interface has not yet been set inetAddress = INADDR_ANY; } else inetAddress = ((sockaddr_in*)local)->sin_addr.s_addr; - TRACE(("%s(): address %x\n", __FUNCTION__, inetAddress)); + TRACE(("%s(): address %s\n", __FUNCTION__, inet_to_string(inetAddress))); if (protocol->local_address == 0) protocol->local_address = inetAddress; @@ -545,7 +581,7 @@ // check if this request is for us arp_entry *entry = arp_entry::Lookup(header.protocol_target); - if (entry == NULL + if (entry == NULL || entry->protocol == NULL || (entry->flags & (ARP_FLAG_LOCAL | ARP_FLAG_PUBLISH)) == 0) { // We're not the one to answer this request // TODO: instead of letting the other's request time-out, can we reply @@ -603,21 +639,11 @@ uint16 opcode = ntohs(header.opcode); #ifdef TRACE_ARP - dprintf(" hw sender: %02x:%02x:%02x:%02x:%02x:%02x\n", - header.hardware_sender[0], header.hardware_sender[1], - header.hardware_sender[2], header.hardware_sender[3], - header.hardware_sender[4], header.hardware_sender[5]); - unsigned int addr = ntohl(header.protocol_sender); - dprintf(" proto sender: %d.%d.%d.%d\n", addr >> 24, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff); - dprintf(" hw target: %02x:%02x:%02x:%02x:%02x:%02x\n", - header.hardware_target[0], header.hardware_target[1], - header.hardware_target[2], header.hardware_target[3], - header.hardware_target[4], header.hardware_target[5]); - addr = ntohl(header.protocol_target); - dprintf(" proto target: %d.%d.%d.%d\n", addr >> 24, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff); -#endif + dprintf(" hw sender: %s\n", mac_to_string(header.hardware_sender)); + dprintf(" proto sender: %s\n", inet_to_string(header.protocol_sender)); + dprintf(" hw target: %s\n", mac_to_string(header.hardware_target));; + dprintf(" proto target: %s\n", inet_to_string(header.protocol_target)); +#endif // TRACE_ARP if (ntohs(header.protocol_type) != ETHER_TYPE_IP || ntohs(header.hardware_type) != ARP_HARDWARE_TYPE_ETHER) @@ -698,7 +724,8 @@ default: { - if (entry->timer_state > ARP_STATE_LAST_REQUEST) + if (entry->timer_state > ARP_STATE_LAST_REQUEST + || entry->protocol == NULL) break; TRACE((" send request for ARP entry %p!\n", entry)); @@ -946,7 +973,7 @@ } -// #pragma mark - +// #pragma mark - net_datalink_protocol status_t @@ -1023,7 +1050,7 @@ if ((entry->flags & ARP_FLAG_REJECT) != 0) return EHOSTUNREACH; - + if ((entry->flags & ARP_FLAG_VALID) == 0) { // entry is still being resolved. TRACE(("ARP Queuing packet %p, entry still being resolved.\n", @@ -1086,16 +1113,17 @@ // Those are the options we handle if ((protocol->interface->flags & IFF_UP) != 0) { // Update ARP entry for the local address - + if (newAddress != NULL && newAddress->sa_family == AF_INET) { status_t status = arp_set_local_entry(protocol, newAddress); if (status != B_OK) return status; } - if (oldAddress != NULL && oldAddress->sa_family == AF_INET) + if (option != SIOCAIFADDR + && (oldAddress == NULL || oldAddress->sa_family == AF_INET)) arp_remove_local_entry(protocol, oldAddress, true); - } + } break; default: