diff --git a/headers/posix/net/if.h b/headers/posix/net/if.h index 846de13cbc..04bdcaec4a 100644 --- a/headers/posix/net/if.h +++ b/headers/posix/net/if.h @@ -61,6 +61,7 @@ struct ifaliasreq { struct sockaddr_storage ifra_destination; }; struct sockaddr_storage ifra_mask; + uint32_t ifra_flags; }; /* interface flags */ @@ -74,10 +75,15 @@ struct ifaliasreq { #define IFF_ALLMULTI 0x0200 /* receive all multicast packets */ #define IFF_SIMPLEX 0x0800 /* doesn't receive own transmissions */ #define IFF_LINK 0x1000 /* has link */ -#define IFF_AUTO_CONFIGURED 0x2000 /* has been automatically configured */ -#define IFF_CONFIGURING 0x4000 /* auto configuration in progress */ +#define IFF_AUTO_CONFIGURED 0x2000 +#define IFF_CONFIGURING 0x4000 #define IFF_MULTICAST 0x8000 /* supports multicast */ +/* interface alias flags */ +#define IFAF_AUTO_CONFIGURED 0x0001 /* has been automatically configured */ +#define IFAF_CONFIGURING 0x0002 /* auto configuration in progress */ + + /* used with SIOCGIFCOUNT, and SIOCGIFCONF */ struct ifconf { int ifc_len; /* size of buffer */ diff --git a/headers/posix/sys/sockio.h b/headers/posix/sys/sockio.h index 6464232b37..de463d11b2 100644 --- a/headers/posix/sys/sockio.h +++ b/headers/posix/sys/sockio.h @@ -6,7 +6,9 @@ #define _SYS_SOCKIO_H -/*! Socket I/O control codes, usually via struct ifreq */ +/*! Socket I/O control codes, usually via struct ifreq, most of them should + be compatible with the BSDs. +*/ #define SIOCADDRT 8900 /* add route */ @@ -66,11 +68,12 @@ #define SIOCSIFGENERIC 8945 /* generic IF set op */ #define SIOCGIFGENERIC 8946 /* generic IF get op */ -#define SIOC_IF_ALIAS_REMOVE 8918 /* synonym for SIOCDIFADDR */ -#define SIOC_IF_ALIAS_ADD 8919 /* synonym for SIOCAIFADDR */ -#define SIOC_IF_ALIAS_SET 8947 /* set interface alias, ifaliasreq */ -#define SIOC_IF_ALIAS_GET 8948 /* get interface alias, ifaliasreq */ -#define SIOC_IF_ALIAS_COUNT 8959 /* count interface aliases */ +/* Haiku specific extensions */ +#define B_SOCKET_REMOVE_ALIAS 8918 /* synonym for SIOCDIFADDR */ +#define B_SOCKET_ADD_ALIAS 8919 /* synonym for SIOCAIFADDR */ +#define B_SOCKET_SET_ALIAS 8947 /* set interface alias, ifaliasreq */ +#define B_SOCKET_GET_ALIAS 8948 /* get interface alias, ifaliasreq */ +#define B_SOCKET_COUNT_ALIASES 8949 /* count interface aliases */ #define SIOCEND 9000 /* SIOCEND >= highest SIOC* */ diff --git a/headers/private/net/net_datalink.h b/headers/private/net/net_datalink.h index 074231a72f..5d01473560 100644 --- a/headers/private/net/net_datalink.h +++ b/headers/private/net/net_datalink.h @@ -38,6 +38,7 @@ typedef struct net_interface_address { struct sockaddr* local; struct sockaddr* destination; struct sockaddr* mask; + uint32_t flags; } net_interface_address; typedef struct net_interface { diff --git a/src/add-ons/kernel/network/stack/datalink.cpp b/src/add-ons/kernel/network/stack/datalink.cpp index a8796cd1f7..73399a8c14 100644 --- a/src/add-ons/kernel/network/stack/datalink.cpp +++ b/src/add-ons/kernel/network/stack/datalink.cpp @@ -110,9 +110,9 @@ option_to_string(int32 option) CODE(SIOCSIFGENERIC) /* generic IF set op */ CODE(SIOCGIFGENERIC) /* generic IF get op */ - CODE(SIOC_IF_ALIAS_SET) /* set interface alias, ifaliasreq */ - CODE(SIOC_IF_ALIAS_GET) /* get interface alias, ifaliasreq */ - CODE(SIOC_IF_ALIAS_COUNT) /* count interface aliases */ + CODE(B_SOCKET_SET_ALIAS) /* set interface alias, ifaliasreq */ + CODE(B_SOCKET_GET_ALIAS) /* get interface alias, ifaliasreq */ + CODE(B_SOCKET_COUNT_ALIASES) /* count interface aliases */ default: static char buffer[24]; @@ -142,7 +142,7 @@ get_interface_name_or_index(net_domain* domain, int32 option, void* value, if (user_memcpy(&request, value, expected) < B_OK) return B_BAD_ADDRESS; - net_interface* interface = NULL; + Interface* interface = NULL; if (option == SIOCGIFINDEX) interface = get_interface(domain, request.ifr_name); else @@ -157,6 +157,7 @@ get_interface_name_or_index(net_domain* domain, int32 option, void* value, strlcpy(request.ifr_name, interface->name, IF_NAMESIZE); *_length = sizeof(ifreq); + interface->ReleaseReference(); return user_memcpy(value, &request, sizeof(ifreq)); } @@ -200,14 +201,14 @@ datalink_control(net_domain* _domain, int32 option, void* value, case SIOCGIFNAME: return get_interface_name_or_index(domain, option, value, _length); - case SIOCAIFADDR: /* same as SIOC_IF_ALIAS_ADD */ + case SIOCAIFADDR: /* same as B_SOCKET_ADD_ALIAS */ { // add new interface address if (*_length < sizeof(struct ifaliasreq)) return B_BAD_VALUE; struct ifaliasreq request; - if (user_memcpy(&request, value, sizeof(struct ifaliasreq)) < B_OK) + if (user_memcpy(&request, value, sizeof(struct ifaliasreq)) != B_OK) return B_BAD_ADDRESS; Interface* interface = get_interface(domain, request.ifra_name); @@ -216,6 +217,8 @@ datalink_control(net_domain* _domain, int32 option, void* value, status_t status = add_interface_address(interface, domain, request); notify_interface_changed(interface); + interface->ReleaseReference(); + return status; } @@ -232,11 +235,11 @@ datalink_control(net_domain* _domain, int32 option, void* value, return status; } - case SIOCDIFADDR: /* same as SIOC_IF_ALIAS_REMOVE */ + case SIOCDIFADDR: /* same as B_SOCKET_REMOVE_ALIAS */ { // remove interface (address) struct ifreq request; - if (user_memcpy(&request, value, sizeof(struct ifreq)) < B_OK) + if (user_memcpy(&request, value, sizeof(struct ifreq)) != B_OK) return B_BAD_ADDRESS; Interface* interface = get_interface(domain, request.ifr_name); @@ -246,8 +249,7 @@ datalink_control(net_domain* _domain, int32 option, void* value, status_t status; if (request.ifr_addr.sa_family != AF_UNSPEC - || request.ifr_addr.sa_len != 0) { - // TODO: remove interface if this was the last address? + && request.ifr_addr.sa_len != 0) { status = interface->Control(domain, SIOCDIFADDR, request, (ifreq*)value, *_length); } else @@ -675,7 +677,7 @@ interface_protocol_down(net_datalink_protocol* _protocol) deviceInterface->up_count--; - interface_went_down(interface); + interface->WentDown(); if (deviceInterface->up_count > 0) return; @@ -745,7 +747,7 @@ interface_protocol_control(net_datalink_protocol* _protocol, int32 option, &((struct ifreq*)argument)->ifr_addr, maxLength); } - case SIOC_IF_ALIAS_COUNT: + case B_SOCKET_COUNT_ALIASES: { ifreq request; request.ifr_count = interface->CountAddresses(); @@ -754,7 +756,7 @@ interface_protocol_control(net_datalink_protocol* _protocol, int32 option, &request.ifr_count, sizeof(request.ifr_count)); } - case SIOC_IF_ALIAS_GET: + case B_SOCKET_GET_ALIAS: { ifaliasreq request; if (user_memcpy(&request, argument, sizeof(ifaliasreq)) != B_OK) diff --git a/src/add-ons/kernel/network/stack/interfaces.cpp b/src/add-ons/kernel/network/stack/interfaces.cpp index 4f8b0a74b6..0aadbaa13d 100644 --- a/src/add-ons/kernel/network/stack/interfaces.cpp +++ b/src/add-ons/kernel/network/stack/interfaces.cpp @@ -170,6 +170,10 @@ InterfaceAddress::InterfaceAddress(net_interface* netInterface, InterfaceAddress::~InterfaceAddress() { + TRACE("InterfaceAddress %p: destructor\n", this); + + if (interface != NULL && (flags & IFAF_DIRECT_ADDRESS) == 0) + ((Interface*)interface)->ReleaseReference(); } @@ -213,6 +217,7 @@ InterfaceAddress::AddressFor(int32 option) switch (option) { case SIOCSIFADDR: case SIOCGIFADDR: + case SIOCDIFADDR: return &local; case SIOCSIFNETMASK: @@ -231,6 +236,54 @@ InterfaceAddress::AddressFor(int32 option) } +/*! Adds the default routes that every interface address needs, ie. the local + host route, and one for the subnet (if set). +*/ +void +InterfaceAddress::AddDefaultRoutes(int32 option) +{ + net_route route; + route.destination = local; + route.gateway = NULL; + route.interface_address = this; + + if (mask != NULL && (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) { + route.mask = mask; + route.flags = 0; + add_route(domain, &route); + } + + if (option == SIOCSIFADDR) { + route.mask = NULL; + route.flags = RTF_LOCAL | RTF_HOST; + add_route(domain, &route); + } +} + + +/*! Removes the default routes as set by AddDefaultRoutes() again. */ +void +InterfaceAddress::RemoveDefaultRoutes(int32 option) +{ + net_route route; + route.destination = local; + route.gateway = NULL; + route.interface_address = this; + + if (mask != NULL && (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) { + route.mask = mask; + route.flags = 0; + remove_route(domain, &route); + } + + if (option == SIOCSIFADDR) { + route.mask = NULL; + route.flags = RTF_LOCAL | RTF_HOST; + remove_route(domain, &route); + } +} + + #if ENABLE_DEBUGGER_COMMANDS @@ -331,11 +384,18 @@ InterfaceAddress::Prepare(sockaddr** _address, size_t size) void InterfaceAddress::_Init(net_interface* netInterface, net_domain* netDomain) { + TRACE("InterfaceAddress %p: init interface %p, domain %p\n", this, + netInterface, netDomain); + interface = netInterface; domain = netDomain; local = NULL; destination = NULL; mask = NULL; + flags = 0; + + if (interface != NULL) + ((Interface*)interface)->AcquireReference(); } @@ -370,6 +430,27 @@ Interface::Interface(const char* interfaceName, Interface::~Interface() { + TRACE("Interface %p: destructor\n", this); + + put_device_interface(fDeviceInterface); + + // Uninitialize the domain datalink protocols + + DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator(); + while (domain_datalink* datalink = iterator.Next()) { + put_domain_datalink_protocols(this, datalink->domain); + } + + // Free domain datalink objects + + domain_datalink* next = fDatalinkTable.Clear(true); + while (next != NULL) { + domain_datalink* datalink = next; + next = next->hash_link; + + delete datalink; + } + recursive_lock_destroy(&fLock); // Release reference of the stack - at this point, our stack may be unloaded @@ -477,10 +558,6 @@ Interface::RemoveAddress(InterfaceAddress* address) fAddresses.Remove(address); address->GetDoublyLinkedListLink()->next = NULL; -// TODO! -// if (_FirstForFamily(domain->family) == NULL) -// put_domain_datalink_protocols(this, domain); - locker.Unlock(); MutexLocker hashLocker(sHashLock); @@ -541,6 +618,17 @@ Interface::CountAddresses() } +void +Interface::RemoveAddresses() +{ + RecursiveLocker locker(fLock); + + while (InterfaceAddress* address = fAddresses.RemoveHead()) { + address->ReleaseReference(); + } +} + + /*! This is called in order to call the correct methods of the datalink protocols, ie. it will translate address changes to net_datalink_protocol::change_address(), and IFF_UP changes to @@ -565,7 +653,7 @@ Interface::Control(net_domain* domain, int32 option, ifreq& request, if ((requestFlags & IFF_UP) != 0) status = _SetUp(); else - _SetDown(); + SetDown(); } if (status == B_OK) { @@ -581,7 +669,7 @@ Interface::Control(net_domain* domain, int32 option, ifreq& request, return status; } - case SIOC_IF_ALIAS_SET: + case B_SOCKET_SET_ALIAS: { RecursiveLocker locker(fLock); @@ -681,6 +769,39 @@ Interface::Control(net_domain* domain, int32 option, ifreq& request, } +void +Interface::SetDown() +{ + if ((flags & IFF_UP) == 0) + return; + + RecursiveLocker locker(fLock); + + DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator(); + while (domain_datalink* datalink = iterator.Next()) { + datalink->first_info->interface_down(datalink->first_protocol); + } + + flags &= ~IFF_UP; +} + + +/*! Called when a device lost its IFF_UP status. We will invalidate all + interface routes here. +*/ +void +Interface::WentDown() +{ + RecursiveLocker locker(fLock); + + AddressList::Iterator iterator = fAddresses.GetIterator(); + while (InterfaceAddress* address = iterator.Next()) { + if (address->domain != NULL) + invalidate_routes(address->domain, this); + } +} + + status_t Interface::CreateDomainDatalinkIfNeeded(net_domain* domain) { @@ -713,6 +834,7 @@ Interface::CreateDomainDatalinkIfNeeded(net_domain* domain) datalink->direct_address.mask = NULL; datalink->direct_address.domain = domain; datalink->direct_address.interface = this; + datalink->direct_address.flags = IFAF_DIRECT_ADDRESS; fDatalinkTable.Insert(datalink); @@ -785,7 +907,7 @@ Interface::_SetUp() if (status != B_OK) return status; - // propagate flag to all datalink protocols + // Propagate flag to all datalink protocols RecursiveLocker locker(fLock); @@ -810,26 +932,15 @@ Interface::_SetUp() } } - flags |= IFF_UP; - return B_OK; -} + // Add default routes for the existing addresses - -void -Interface::_SetDown() -{ - if ((flags & IFF_UP) == 0) - return; - - RecursiveLocker locker(fLock); - - DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator(); - while (domain_datalink* datalink = iterator.Next()) { - datalink->first_info->interface_down(datalink->first_protocol); + AddressList::Iterator addressIterator = fAddresses.GetIterator(); + while (InterfaceAddress* address = addressIterator.Next()) { + address->AddDefaultRoutes(SIOCSIFADDR); } - down_device_interface(fDeviceInterface); - flags &= ~IFF_UP; + flags |= IFF_UP; + return B_OK; } @@ -912,56 +1023,6 @@ find_interface(uint32 index) } -/*! Removes the default routes as set by add_default_routes() again. */ -static void -remove_default_routes(InterfaceAddress* address, int32 option) -{ - net_route route; - route.destination = address->local; - route.gateway = NULL; - route.interface_address = address; - - if (address->mask != NULL - && (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) { - route.mask = address->mask; - route.flags = 0; - remove_route(address->domain, &route); - } - - if (option == SIOCSIFADDR) { - route.mask = NULL; - route.flags = RTF_LOCAL | RTF_HOST; - remove_route(address->domain, &route); - } -} - - -/*! Adds the default routes that every interface address needs, ie. the local - host route, and one for the subnet (if set). -*/ -static void -add_default_routes(InterfaceAddress* address, int32 option) -{ - net_route route; - route.destination = address->local; - route.gateway = NULL; - route.interface_address = address; - - if (address->mask != NULL - && (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) { - route.mask = address->mask; - route.flags = 0; - add_route(address->domain, &route); - } - - if (option == SIOCSIFADDR) { - route.mask = NULL; - route.flags = RTF_LOCAL | RTF_HOST; - add_route(address->domain, &route); - } -} - - // #pragma mark - @@ -1000,47 +1061,17 @@ add_interface(const char* name, net_domain_private* domain, status_t remove_interface(Interface* interface) { - return B_ERROR; -#if 0 - // deleting an interface is fairly complex as we need - // to clear all references to it throughout the stack + interface->SetDown(); + interface->RemoveAddresses(); - // this will possibly call (if IFF_UP): - // interface_protocol_down() - // domain_interface_went_down() - // invalidate_routes() - // remove_route() - // update_route_infos() - // get_route_internal() - // down_device_interface() -- if upcount reaches 0 - interface_set_down(interface); + MutexLocker locker(sLock); + sInterfaces.Remove(interface); + locker.Unlock(); - // This call requires the RX Lock to be a recursive - // lock since each uninit_protocol() call may call - // again into the stack to unregister a reader for - // instance, which tries to obtain the RX lock again. - put_domain_datalink_protocols(interface); - - put_device_interface(interface->device_interface); - - delete interface; -#endif -#if 0 - invalidate_routes(domain, interface); - - list_remove_item(&domain->interfaces, interface); notify_interface_removed(interface); - delete_interface((net_interface_private*)interface); -#endif -} - - -void -interface_went_down(Interface* interface) -{ - TRACE("interface_went_down(%s)\n", interface->name); - // TODO! - //invalidate_routes(domain, interface); + + interface->ReleaseReference(); + return B_OK; } @@ -1100,7 +1131,22 @@ update_interface_address(InterfaceAddress* interfaceAddress, int32 option, if (_address == NULL) return B_BAD_VALUE; - remove_default_routes(interfaceAddress, option); + Interface* interface = (Interface*)interfaceAddress->interface; + + interfaceAddress->RemoveDefaultRoutes(option); + + if (option == SIOCDIFADDR) { + // Remove address, and release its reference (causing our caller to + // delete it) + locker.Unlock(); + + invalidate_routes(interfaceAddress); + + interface->RemoveAddress(interfaceAddress); + interfaceAddress->ReleaseReference(); + return B_OK; + } + sAddressTable.Remove(interfaceAddress); // Copy new address over @@ -1135,8 +1181,8 @@ update_interface_address(InterfaceAddress* interfaceAddress, int32 option, interfaceAddress->local, oldNetmask); } - add_default_routes(interfaceAddress, option); - notify_interface_changed(interfaceAddress->interface); + interfaceAddress->AddDefaultRoutes(option); + notify_interface_changed(interface); } sAddressTable.Insert(interfaceAddress); diff --git a/src/add-ons/kernel/network/stack/interfaces.h b/src/add-ons/kernel/network/stack/interfaces.h index 078f8bd636..749a9b0f69 100644 --- a/src/add-ons/kernel/network/stack/interfaces.h +++ b/src/add-ons/kernel/network/stack/interfaces.h @@ -25,6 +25,10 @@ struct net_device_interface; +// Additional address flags +#define IFAF_DIRECT_ADDRESS 0x1000 + + struct InterfaceAddress : DoublyLinkedListLinkImpl, net_interface_address, Referenceable { InterfaceAddress(); @@ -40,6 +44,9 @@ struct InterfaceAddress : DoublyLinkedListLinkImpl, sockaddr** AddressFor(int32 option); + void AddDefaultRoutes(int32 option); + void RemoveDefaultRoutes(int32 option); + InterfaceAddress*& HashTableLink() { return fLink; } #if ENABLE_DEBUGGER_COMMANDS @@ -121,11 +128,15 @@ public: bool GetNextAddress(InterfaceAddress** _address); InterfaceAddress* AddressAt(size_t index); size_t CountAddresses(); + void RemoveAddresses(); status_t Control(net_domain* domain, int32 option, ifreq& request, ifreq* userRequest, size_t length); + void SetDown(); + void WentDown(); + recursive_lock& Lock() { return fLock; } net_device_interface* DeviceInterface() { return fDeviceInterface; } @@ -142,7 +153,6 @@ public: private: status_t _SetUp(); - void _SetDown(); InterfaceAddress* _FirstForFamily(int family); status_t _ChangeAddress(RecursiveLocker& locker, InterfaceAddress* address, int32 option, diff --git a/src/add-ons/kernel/network/stack/routes.cpp b/src/add-ons/kernel/network/stack/routes.cpp index 659a11583e..5df3d52681 100644 --- a/src/add-ons/kernel/network/stack/routes.cpp +++ b/src/add-ons/kernel/network/stack/routes.cpp @@ -411,6 +411,8 @@ status_t control_routes(struct net_interface* _interface, net_domain* domain, int32 option, void* argument, size_t length) { + TRACE("control_routes(interface %p, domain %p, option %" B_PRId32 ")\n", + _interface, domain, option); Interface* interface = (Interface*)_interface; switch (option) { @@ -447,7 +449,8 @@ control_routes(struct net_interface* _interface, net_domain* domain, else status = remove_route(domain, &route); - address->ReleaseReference(); + if (address != NULL) + address->ReleaseReference(); return status; } } @@ -601,7 +604,7 @@ invalidate_routes(net_domain* _domain, net_interface* interface) net_domain_private* domain = (net_domain_private*)_domain; RecursiveLocker locker(domain->lock); - dprintf("invalidate_routes(%i, %s)\n", domain->family, interface->name); + TRACE("invalidate_routes(%i, %s)\n", domain->family, interface->name); RouteList::Iterator iterator = domain->routes.GetIterator(); while (iterator.HasNext()) { @@ -613,6 +616,26 @@ invalidate_routes(net_domain* _domain, net_interface* interface) } +void +invalidate_routes(InterfaceAddress* address) +{ + net_domain_private* domain = (net_domain_private*)address->domain; + + TRACE("invalidate_routes(%s)\n", + AddressString(domain, address->local).Data()); + + RecursiveLocker locker(domain->lock); + + RouteList::Iterator iterator = domain->routes.GetIterator(); + while (iterator.HasNext()) { + net_route* route = iterator.Next(); + + if (route->interface_address == address) + remove_route(domain, route); + } +} + + struct net_route* get_route(struct net_domain* _domain, const struct sockaddr* address) { diff --git a/src/add-ons/kernel/network/stack/routes.h b/src/add-ons/kernel/network/stack/routes.h index c1bc6f742a..90d2dea083 100644 --- a/src/add-ons/kernel/network/stack/routes.h +++ b/src/add-ons/kernel/network/stack/routes.h @@ -15,6 +15,9 @@ #include +class InterfaceAddress; + + struct net_route_private : net_route, DoublyLinkedListLinkImpl { int32 ref_count; @@ -41,6 +44,7 @@ status_t remove_route(struct net_domain* domain, status_t get_route_information(struct net_domain* domain, void* buffer, size_t length); void invalidate_routes(net_domain* domain, net_interface* interface); +void invalidate_routes(InterfaceAddress* address); struct net_route* get_route(struct net_domain* domain, const struct sockaddr* address); status_t get_device_route(struct net_domain* domain, uint32 index, diff --git a/src/bin/debug/strace/ioctl.cpp b/src/bin/debug/strace/ioctl.cpp index ae7b91825c..a348e1f585 100644 --- a/src/bin/debug/strace/ioctl.cpp +++ b/src/bin/debug/strace/ioctl.cpp @@ -106,9 +106,9 @@ static const ioctl_info kIOCtls[] = { IOCTL_INFO_ENTRY(SIOCATMARK), IOCTL_INFO_ENTRY(SIOCSPGRP), - IOCTL_INFO_ENTRY_TYPE(SIOC_IF_ALIAS_SET, struct ifaliasreq *), - IOCTL_INFO_ENTRY_TYPE(SIOC_IF_ALIAS_GET, struct ifaliasreq *), - IOCTL_INFO_ENTRY_TYPE(SIOC_IF_ALIAS_COUNT, struct ifaliasreq *), + IOCTL_INFO_ENTRY_TYPE(B_SOCKET_SET_ALIAS, struct ifaliasreq *), + IOCTL_INFO_ENTRY_TYPE(B_SOCKET_GET_ALIAS, struct ifaliasreq *), + IOCTL_INFO_ENTRY_TYPE(B_SOCKET_COUNT_ALIASES, struct ifreq *), // termios ioctls IOCTL_INFO_ENTRY(TCGETA), diff --git a/src/bin/network/ifconfig/ifconfig.cpp b/src/bin/network/ifconfig/ifconfig.cpp index b686724618..99b744f6b4 100644 --- a/src/bin/network/ifconfig/ifconfig.cpp +++ b/src/bin/network/ifconfig/ifconfig.cpp @@ -393,6 +393,7 @@ prepare_request(struct ifreq& request, const char* name) return false; } + memset(&request, 0, sizeof(ifreq)); strcpy(request.ifr_name, name); return true; } @@ -723,20 +724,56 @@ list_interfaces(const char* name) } +/*! If there are any arguments given, this will remove only the specified + addresses from the interface named \a name. + If there are no arguments, it will remove the complete interface with all + of its addresses. +*/ void -delete_interface(const char* name) +delete_interface(const char* name, char* const* args, int32 argCount) { ifreq request; if (!prepare_request(request, name)) return; - int socket = find_socket(request, -1); - if (socket == -1) - return; + for (int32 i = 0; i < argCount; i++) { + int32 familyIndex; + if (get_address_family(args[i], familyIndex)) + i++; - if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) { - fprintf(stderr, "%s: Could not delete interface %s: %s\n", - kProgramName, name, strerror(errno)); + // TODO: be smart enough to detect the family by the address + + int socket = find_socket(request, kFamilies[familyIndex].family); + if (socket == -1) { + fprintf(stderr, "%s: Address family \"%s\" is not available.\n", + kProgramName, kFamilies[familyIndex].name); + exit(1); + } + + if (!parse_address(familyIndex, args[i], request.ifr_addr)) { + fprintf(stderr, "%s: Could not parse address \"%s\".\n", + kProgramName, args[i]); + exit(1); + } + + if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) { + fprintf(stderr, "%s: Could not delete address %s from interface %s:" + " %s\n", kProgramName, args[i], name, strerror(errno)); + } + } + + if (argCount == 0) { + // Delete interface + int socket = find_socket(request, -1); + if (socket < 0) + exit(1); + + request.ifr_addr.sa_family = AF_UNSPEC; + + if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) { + fprintf(stderr, "%s: Could not delete interface %s: %s\n", + kProgramName, name, strerror(errno)); + } } } @@ -776,12 +813,9 @@ configure_interface(const char* name, char* const* args, if (index == 0) { // the interface does not exist yet, we have to add it first ifaliasreq request; + memset(&request, 0, sizeof(ifaliasreq)); strlcpy(request.ifra_name, name, IF_NAMESIZE); - request.ifra_addr.ss_family = AF_UNSPEC; - request.ifra_mask.ss_family = AF_UNSPEC; - request.ifra_broadaddr.ss_family = AF_UNSPEC; - if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) { fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName, strerror(errno)); @@ -1052,32 +1086,32 @@ main(int argc, char** argv) if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) usage(0); - bool deleteInterfaces = false; - - if (argc > 1 - && (!strcmp(argv[1], "--delete") - || !strcmp(argv[1], "--del") - || !strcmp(argv[1], "-d"))) { - // delete interfaces - if (argc < 3) - usage(1); - - deleteInterfaces = true; - } - - if (initialize_address_families() == false) { + if (!initialize_address_families()) { fprintf(stderr, "%s: The networking stack doesn't seem to be " "available.\n", kProgramName); return 1; } - if (deleteInterfaces) { - for (int i = 2; i < argc; i++) { - delete_interface(argv[i]); - } + if (argc > 1 + && (!strcmp(argv[1], "--delete") + || !strcmp(argv[1], "--del") + || !strcmp(argv[1], "-d") + || !strcmp(argv[1], "del") + || !strcmp(argv[1], "delete"))) { + // Delete interface (addresses) + + if (argc < 3) + usage(1); + + const char* name = argv[2]; + delete_interface(name, argv + 3, argc - 3); return 0; - } else if (argc > 1 && !strcmp(argv[1], "-a")) { - // accept -a option for those that are used to it from other platforms + } + + if (argc > 1 && !strcmp(argv[1], "-a")) { + // Accept an optional "-a" option to list all interfaces for those + // that are used to it from other platforms. + if (argc > 2) usage(1); @@ -1087,7 +1121,7 @@ main(int argc, char** argv) const char* name = argv[1]; if (argc > 2) { - // add or configure an interface + // Add or configure an interface configure_interface(name, argv + 2, argc - 2); return 0;