Author: phoudoin Date: 2011-04-27 17:04:55 +0200 (Wed, 27 Apr 2011) New Revision: 41285 Changeset: https://dev.haiku-os.org/changeset/41285 Ticket: https://dev.haiku-os.org/ticket/7346 Modified: haiku/trunk/src/servers/net/AutoconfigLooper.cpp haiku/trunk/src/servers/net/DHCPClient.cpp haiku/trunk/src/servers/net/DHCPClient.h haiku/trunk/src/servers/net/NetServer.cpp Log: Implemented INIT-REBOOT DHCP state: as required per DHCP specs, we now request the last address we got from DHCP server, and only on failure we fallback on the whole INIT state (discover, collect offer, etc). This should fix people losing their IP address at each renewal, or far worse, after the link goes up again. Closed #7346. Modified: haiku/trunk/src/servers/net/AutoconfigLooper.cpp =================================================================== --- haiku/trunk/src/servers/net/AutoconfigLooper.cpp 2011-04-27 05:11:21 UTC (rev 41284) +++ haiku/trunk/src/servers/net/AutoconfigLooper.cpp 2011-04-27 15:04:55 UTC (rev 41285) @@ -58,21 +58,19 @@ void AutoconfigLooper::_Configure() { + // start with DHCP + + if (fCurrentClient == NULL) { + fCurrentClient = new DHCPClient(fTarget, fDevice.String()); + AddHandler(fCurrentClient); + } + // set IFF_CONFIGURING flag on interface BNetworkInterface interface(fDevice.String()); int32 flags = interface.Flags() & ~IFF_AUTO_CONFIGURED; interface.SetFlags(flags | IFF_CONFIGURING); - // remove current handler - - _RemoveClient(); - - // start with DHCP - - fCurrentClient = new DHCPClient(fTarget, fDevice.String()); - AddHandler(fCurrentClient); - if (fCurrentClient->Initialize() == B_OK) return; @@ -91,7 +89,7 @@ BMessage message(kMsgConfigureInterface); message.AddString("device", fDevice.String()); - message.AddBool("auto", true); + message.AddBool("auto_configured", true); BNetworkAddress link; uint8 last = 56; Modified: haiku/trunk/src/servers/net/DHCPClient.cpp =================================================================== --- haiku/trunk/src/servers/net/DHCPClient.cpp 2011-04-27 05:11:21 UTC (rev 41284) +++ haiku/trunk/src/servers/net/DHCPClient.cpp 2011-04-27 15:04:55 UTC (rev 41285) @@ -422,6 +422,7 @@ fConfiguration(kMsgConfigureInterface), fResolverConfiguration(kMsgConfigureResolver), fRunner(NULL), + fAssignedAddress(0), fServer(AF_INET, NULL, DHCP_SERVER_PORT), fLeaseTime(0) { @@ -436,6 +437,18 @@ memcpy(fMAC, link.LinkLevelAddress(), sizeof(fMAC)); + if ((interface.Flags() & IFF_AUTO_CONFIGURED) != 0) { + // Check for interface previous auto-configured address, if any. + BNetworkInterfaceAddress interfaceAddress; + int index = interface.FindFirstAddress(AF_INET); + if (index >= 0 + && interface.GetAddressAt(index, interfaceAddress) == B_OK) { + BNetworkAddress address = interfaceAddress.Address(); + const sockaddr_in& addr = (sockaddr_in&)address.SockAddr(); + fAssignedAddress = addr.sin_addr.s_addr; + } + } + openlog_thread("DHCP", 0, LOG_DAEMON); } @@ -466,8 +479,8 @@ status_t DHCPClient::Initialize() { - fStatus = _Negotiate(INIT); - syslog(LOG_DEBUG, "DHCP for %s, status: %s\n", Device(), strerror(fStatus)); + fStatus = _Negotiate(fAssignedAddress == 0 ? INIT : INIT_REBOOT); + syslog(LOG_DEBUG, "%s: DHCP status = %s\n", Device(), strerror(fStatus)); return fStatus; } @@ -527,13 +540,13 @@ // send discover/request message _SendMessage(socket, state == INIT ? discover : request, - state != RENEWAL ? broadcast : fServer); + state != RENEWING ? broadcast : fServer); // no need to check the status; in case of an error we'll just send // the message again // receive loop until we've got an offer and acknowledged it - while (state != ACKNOWLEDGED) { + while (state != BOUND) { char buffer[2048]; struct sockaddr_in from; socklen_t fromLength = sizeof(from); @@ -546,12 +559,8 @@ return B_TIMED_OUT; } - if (state == INIT) - _SendMessage(socket, discover, broadcast); - else { - _SendMessage(socket, request, - state != RENEWAL ? broadcast : fServer); - } + _SendMessage(socket, state == INIT ? discover : request, + state != RENEWING ? broadcast : fServer); continue; } else if (bytesReceived < 0) @@ -566,10 +575,16 @@ continue; } - syslog(LOG_DEBUG, "Received %s from %s for %s\n", - dhcp_message::TypeToString(message->Type()), - _AddressToString(from.sin_addr.s_addr).String(), Device()); + // advance from startup state + if (state == INIT) + state = SELECTING; + else if (state == INIT_REBOOT) + state = REBOOTING; + syslog(LOG_DEBUG, "%s: Received %s from %s\n", + Device(), dhcp_message::TypeToString(message->Type()), + _AddressToString(from.sin_addr.s_addr).String()); + switch (message->Type()) { case DHCP_NONE: default: @@ -579,7 +594,7 @@ case DHCP_OFFER: { // first offer wins - if (state != INIT) + if (state != SELECTING) break; // collect interface options @@ -590,7 +605,7 @@ fConfiguration.MakeEmpty(); fConfiguration.AddString("device", Device()); - fConfiguration.AddBool("auto", true); + fConfiguration.AddBool("auto_configured", true); BMessage address; address.AddString("family", "inet"); @@ -614,8 +629,10 @@ case DHCP_ACK: { - if (state != REQUESTING && state != REBINDING - && state != RENEWAL) + if (state != REQUESTING + && state != REBOOTING + && state != REBINDING + && state != RENEWING) continue; // TODO: we might want to configure the stuff, don't we? @@ -626,7 +643,7 @@ // way // our address request has been acknowledged - state = ACKNOWLEDGED; + state = BOUND; // configure interface BMessage reply; @@ -644,9 +661,18 @@ } case DHCP_NACK: - if (state != REQUESTING) + if (state != REQUESTING + && state != REBOOTING + && state != REBINDING + && state != RENEWING) continue; + if (state == REBOOTING) { + // server reject our request on previous assigned address + // back to square one... + fAssignedAddress = 0; + } + // try again (maybe we should prefer other servers if this // happens more than once) status = _SendMessage(socket, discover, broadcast); @@ -819,7 +845,8 @@ (uint32)server.sin_addr.s_addr); } - if (state == INIT || state == REQUESTING) { + if (state == INIT || state == INIT_REBOOT + || state == REQUESTING) { next = message.PutOption(next, OPTION_REQUEST_IP_ADDRESS, (uint32)fAssignedAddress); } else @@ -866,7 +893,7 @@ if (++tries > 2) return false; } - syslog(LOG_DEBUG, "Timeout shift for %s: %lu secs (try %lu)\n", + syslog(LOG_DEBUG, "%s: Timeout shift: %lu secs (try %lu)\n", Device(), timeout, tries); struct timeval value; @@ -898,9 +925,16 @@ DHCPClient::_SendMessage(int socket, dhcp_message& message, const BNetworkAddress& address) const { - syslog(LOG_DEBUG, "Send %s to %s on %s\n", - dhcp_message::TypeToString(message.Type()), - address.ToString().String(), Device()); + message_type type = message.Type(); + BString text; + text << dhcp_message::TypeToString(type); + + const uint8* requestAddress = message.FindOption(OPTION_REQUEST_IP_ADDRESS); + if (type == DHCP_REQUEST && requestAddress != NULL) + text << " for " << _AddressToString(requestAddress).String(); + + syslog(LOG_DEBUG, "%s: Send %s to %s\n", Device(), text.String(), + address.ToString().String()); ssize_t bytesSent = sendto(socket, &message, message.Size(), address.IsBroadcast() ? MSG_BCAST : 0, address, address.Length()); @@ -921,7 +955,7 @@ if (now >= fRebindingTime) return REBINDING; if (now >= fRenewalTime) - return RENEWAL; + return RENEWING; return BOUND; } @@ -938,7 +972,7 @@ bigtime_t next; if (_Negotiate(state) == B_OK) { switch (state) { - case RENEWAL: + case RENEWING: next = fRebindingTime; break; case REBINDING: @@ -948,7 +982,7 @@ } } else { switch (state) { - case RENEWAL: + case RENEWING: next = (fLeaseTime - fRebindingTime) / 4 + system_time(); break; case REBINDING: Modified: haiku/trunk/src/servers/net/DHCPClient.h =================================================================== --- haiku/trunk/src/servers/net/DHCPClient.h 2011-04-27 05:11:21 UTC (rev 41284) +++ haiku/trunk/src/servers/net/DHCPClient.h 2011-04-27 15:04:55 UTC (rev 41285) @@ -22,11 +22,13 @@ enum dhcp_state { INIT, + SELECTING, + INIT_REBOOT, + REBOOTING, REQUESTING, BOUND, - RENEWAL, + RENEWING, REBINDING, - ACKNOWLEDGED, }; @@ -55,9 +57,9 @@ bool _TimeoutShift(int socket, time_t& timeout, uint32& tries); void _RestartLease(bigtime_t lease); - + static BString _AddressToString(const uint8* data); - static BString _AddressToString(in_addr_t address); + static BString _AddressToString(in_addr_t address); private: BMessage fConfiguration; Modified: haiku/trunk/src/servers/net/NetServer.cpp =================================================================== --- haiku/trunk/src/servers/net/NetServer.cpp 2011-04-27 05:11:21 UTC (rev 41284) +++ haiku/trunk/src/servers/net/NetServer.cpp 2011-04-27 15:04:55 UTC (rev 41285) @@ -443,7 +443,7 @@ flags = IFF_UP; bool autoConfigured; - if (message.FindBool("auto", &autoConfigured) == B_OK && autoConfigured) + if (message.FindBool("auto_configured", &autoConfigured) == B_OK && autoConfigured) flags |= IFF_AUTO_CONFIGURED; int32 mtu; @@ -532,7 +532,7 @@ if (addressMessage.FindString("broadcast", &string) == B_OK) parse_address(family, string, broadcast); } - + if (autoConfig) { _QuitLooperForDevice(name); startAutoConfig = true;