Author: axeld Date: 2010-08-15 12:39:39 +0200 (Sun, 15 Aug 2010) New Revision: 38110 Changeset: http://dev.haiku-os.org/changeset/38110 Modified: haiku/trunk/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp Log: * On change_address(), arp_remove_local_enty() must not switch to the address that caused the change (but that has not actually been changed yet). * Also, it will now reset the INADDR_ANY local address in case there is no other address configured. This should help with automatic configuring after deletion of an interface address (though it doesn't seem to work yet for some other reason, at least in VMware). 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-15 10:17:42 UTC (rev 38109) +++ haiku/trunk/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp 2010-08-15 10:39:39 UTC (rev 38110) @@ -436,9 +436,51 @@ } +static status_t +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 %s\n", __FUNCTION__, inet_to_string(inetAddress))); + + if (protocol->local_address == 0) + protocol->local_address = inetAddress; + + sockaddr_dl address; + address.sdl_len = sizeof(sockaddr_dl); + address.sdl_family = AF_LINK; + address.sdl_type = IFT_ETHER; + address.sdl_e_type = ETHER_TYPE_IP; + address.sdl_nlen = 0; + address.sdl_slen = 0; + address.sdl_alen = interface->device->address.length; + memcpy(LLADDR(&address), interface->device->address.data, address.sdl_alen); + + memcpy(&protocol->hardware_address, &address, sizeof(sockaddr_dl)); + // cache the address in our protocol + + arp_entry* entry; + status_t status = arp_update_entry(inetAddress, &address, + ARP_FLAG_LOCAL | ARP_FLAG_PERMANENT, &entry); + if (status == B_OK) + entry->protocol = protocol; + + return status; +} + + static void arp_remove_local_entry(arp_protocol* protocol, const sockaddr* local, - bool updateLocalAddress) + net_interface_address* updateLocalAddress = NULL) { in_addr_t inetAddress; @@ -458,14 +500,15 @@ entry->flags |= ARP_FLAG_REMOVED; } - if (updateLocalAddress && protocol->local_address == inetAddress) { + if (updateLocalAddress != NULL && protocol->local_address == inetAddress) { // find new local sender address protocol->local_address = 0; net_interface_address* address = NULL; while (sDatalinkModule->get_next_interface_address(protocol->interface, &address)) { - if (address->local == NULL || address->local->sa_family != AF_INET) + if (address == updateLocalAddress || address->local == NULL + || address->local->sa_family != AF_INET) continue; protocol->local_address @@ -475,6 +518,11 @@ locker.Unlock(); delete entry; + + if (protocol->local_address == 0 && updateLocalAddress) { + // Try to keep the interface operational + arp_set_local_entry(protocol, NULL); + } } @@ -490,53 +538,11 @@ if (address->local == NULL || address->local->sa_family != AF_INET) continue; - arp_remove_local_entry(protocol, address->local, false); + arp_remove_local_entry(protocol, address->local); } } -static status_t -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 %s\n", __FUNCTION__, inet_to_string(inetAddress))); - - if (protocol->local_address == 0) - protocol->local_address = inetAddress; - - sockaddr_dl address; - address.sdl_len = sizeof(sockaddr_dl); - address.sdl_family = AF_LINK; - address.sdl_type = IFT_ETHER; - address.sdl_e_type = ETHER_TYPE_IP; - address.sdl_nlen = 0; - address.sdl_slen = 0; - address.sdl_alen = interface->device->address.length; - memcpy(LLADDR(&address), interface->device->address.data, address.sdl_alen); - - memcpy(&protocol->hardware_address, &address, sizeof(sockaddr_dl)); - // cache the address in our protocol - - arp_entry* entry; - status_t status = arp_update_entry(inetAddress, &address, - ARP_FLAG_LOCAL | ARP_FLAG_PERMANENT, &entry); - if (status == B_OK) - entry->protocol = protocol; - - return status; -} - - /*! Creates permanent local entries for all addresses of the interface belonging to this protocol. Returns an error if no entry could be added. @@ -1130,7 +1136,7 @@ if (option != SIOCAIFADDR && (oldAddress == NULL || oldAddress->sa_family == AF_INET)) - arp_remove_local_entry(protocol, oldAddress, true); + arp_remove_local_entry(protocol, oldAddress, address); } break;