From 625f8abdb0727a48a790acd226b3a6becece6022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 8 Jan 2007 16:04:16 +0000 Subject: [PATCH] * The networking stack now removes all invalid interfaces during startup (those where there is either no address or MAC address [ethernet only]). * _ConfigureInterfaces() now notices if a network device that has a configuration is gone and memorizes this configuration. * If a new device pops up, and there is an existing configuration for a device no longer available, that configuration will be used for the new device, allowing you to easily move your Haiku image to a new system without losing its network settings - it does not yet test if the IP address is already in use in the local network, though (in which case a configuration using DHCP would be preferrable). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19742 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/net/NetServer.cpp | 150 +++++++++++++++++++++++++++++++--- 1 file changed, 137 insertions(+), 13 deletions(-) diff --git a/src/servers/net/NetServer.cpp b/src/servers/net/NetServer.cpp index 45a30ccb00..6337932b55 100644 --- a/src/servers/net/NetServer.cpp +++ b/src/servers/net/NetServer.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -48,14 +48,17 @@ class NetServer : public BApplication { virtual void MessageReceived(BMessage* message); private: + bool _IsValidInterface(int socket, const char* name); + void _RemoveInvalidInterfaces(int socket); bool _TestForInterface(int socket, const char* name); status_t _ConfigureInterface(int socket, BMessage& interface, bool fromMessage = false); bool _QuitLooperForDevice(const char* device); BLooper* _LooperForDevice(const char* device); status_t _ConfigureDevice(int socket, const char* path); - void _ConfigureDevices(int socket, const char* path); - void _ConfigureInterfaces(int socket); + void _ConfigureDevices(int socket, const char* path, + BMessage* suggestedInterface = NULL); + void _ConfigureInterfaces(int socket, BMessage* _missingDevice = NULL); void _BringUpInterfaces(); void _StartServices(); @@ -324,6 +327,111 @@ NetServer::MessageReceived(BMessage* message) } +/*! + Checks if an interface is valid, that is, if it has an address in any + family, and, in case of ethernet, a hardware MAC address. +*/ +bool +NetServer::_IsValidInterface(int socket, const char* name) +{ + ifreq request; + if (!prepare_request(request, name)) + return B_ERROR; + + // check if it has an address + + int32 addresses = 0; + + for (int32 i = 0; kFamilies[i].family >= 0; i++) { + int familySocket = ::socket(kFamilies[i].family, SOCK_DGRAM, 0); + if (familySocket < 0) + continue; + + if (ioctl(familySocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) == 0) { + if (request.ifr_addr.sa_family == kFamilies[i].family) + addresses++; + } + + close(familySocket); + } + + if (addresses == 0) + return false; + + // check if it has a hardware address, too, in case of ethernet + + if (ioctl(socket, SIOCGIFPARAM, &request, sizeof(struct ifreq)) < 0) + return false; + + int linkSocket = ::socket(AF_LINK, SOCK_DGRAM, 0); + if (linkSocket < 0) + return false; + + prepare_request(request, request.ifr_parameter.device); + if (ioctl(linkSocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) < 0) { + close(linkSocket); + return false; + } + + close(linkSocket); + + sockaddr_dl &link = *(sockaddr_dl *)&request.ifr_addr; + if (link.sdl_type == IFT_ETHER && link.sdl_alen < 6) + return false; + + return true; +} + + +void +NetServer::_RemoveInvalidInterfaces(int socket) +{ + // get a list of all interfaces + + ifconf config; + config.ifc_len = sizeof(config.ifc_value); + if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0) + return; + + uint32 count = (uint32)config.ifc_value; + if (count == 0) { + // there are no interfaces yet + return; + } + + void *buffer = malloc(count * sizeof(struct ifreq)); + if (buffer == NULL) { + fprintf(stderr, "%s: Out of memory.\n", Name()); + return; + } + + config.ifc_len = count * sizeof(struct ifreq); + config.ifc_buf = buffer; + if (ioctl(socket, SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0) + return; + + ifreq *interface = (ifreq *)buffer; + + for (uint32 i = 0; i < count; i++) { + if (!_IsValidInterface(socket, interface->ifr_name)) { + // remove invalid interface + ifreq request; + if (!prepare_request(request, interface->ifr_name)) + return; + + if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) { + fprintf(stderr, "%s: Could not delete interface %s: %s\n", + Name(), interface->ifr_name, strerror(errno)); + } + } + + interface = (ifreq *)((addr_t)interface + IF_NAMESIZE + interface->ifr_addr.sa_len); + } + + free(buffer); +} + + bool NetServer::_TestForInterface(int socket, const char* name) { @@ -642,7 +750,6 @@ NetServer::_LooperForDevice(const char* device) status_t NetServer::_ConfigureDevice(int socket, const char* path) { - // bring interface up, but don't configure it just yet BMessage interface; interface.AddString("device", path); @@ -656,7 +763,8 @@ NetServer::_ConfigureDevice(int socket, const char* path) void -NetServer::_ConfigureDevices(int socket, const char* startPath) +NetServer::_ConfigureDevices(int socket, const char* startPath, + BMessage* suggestedInterface) { BDirectory directory(startPath); BEntry entry; @@ -670,19 +778,26 @@ NetServer::_ConfigureDevices(int socket, const char* startPath) || entry.GetStat(&stat) != B_OK) continue; - if (S_ISBLK(stat.st_mode) || S_ISCHR(stat.st_mode)) - _ConfigureDevice(socket, path.Path()); - else if (entry.IsDirectory()) - _ConfigureDevices(socket, path.Path()); + if (S_ISBLK(stat.st_mode) || S_ISCHR(stat.st_mode)) { + if (suggestedInterface != NULL + && suggestedInterface->RemoveName("device") == B_OK + && suggestedInterface->AddString("device", path.Path()) == B_OK + && _ConfigureInterface(socket, *suggestedInterface) == B_OK) + suggestedInterface = NULL; + else + _ConfigureDevice(socket, path.Path()); + } else if (entry.IsDirectory()) + _ConfigureDevices(socket, path.Path(), suggestedInterface); } } void -NetServer::_ConfigureInterfaces(int socket) +NetServer::_ConfigureInterfaces(int socket, BMessage* _missingDevice) { BMessage interface; uint32 cookie = 0; + bool missing = false; while (fSettings.GetNextInterface(cookie, interface) == B_OK) { const char *device; if (interface.FindString("device", &device) != B_OK) @@ -691,8 +806,13 @@ NetServer::_ConfigureInterfaces(int socket) if (!strncmp(device, "/dev/net/", 9)) { // it's a kernel device, check if it's present BEntry entry(device); - if (!entry.Exists()) + if (!entry.Exists()) { + if (!missing && _missingDevice != NULL) { + *_missingDevice = interface; + missing = true; + } continue; + } } _ConfigureInterface(socket, interface); @@ -712,9 +832,12 @@ NetServer::_BringUpInterfaces() return; } + _RemoveInvalidInterfaces(socket); + // First, we look into the settings, and try to bring everything up from there - _ConfigureInterfaces(socket); + BMessage missingDevice; + _ConfigureInterfaces(socket, &missingDevice); // check configuration @@ -735,7 +858,8 @@ NetServer::_BringUpInterfaces() if (!_TestForInterface(socket, "/dev/net/")) { // there is no driver configured - see if there is one and try to use it - _ConfigureDevices(socket, "/dev/net"); + _ConfigureDevices(socket, "/dev/net", + missingDevice.HasString("device") ? &missingDevice : NULL); } close(socket);