From 2b1c0755dd452db665050fdbbe06549e7e8c9c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 3 Aug 2010 15:51:54 +0000 Subject: [PATCH] * Renamed the proprietary SIOC_* ioctls to B_SOCKET_* - no reason to pollute global name space, and have ugly identifiers for nothing :-) * Added a flags field to struct ifaliasreq. Added flags to mark an alias that is currently being configured, or has been automatically configured. Those flags aren't used yet, but they will replace IFF_CONFIGURING and friends. * Implemented deleting addresses only from interfaces via ifconfig. * Added more command aliases for delete to ifconfig ("del", and "delete", for more consistency with route). * Fixed control_routes() to only release a reference to an address if it actually got one before. * If an interface address is deleted, its routes are now removed as well. * InterfaceAddress now holds a reference to its interface as planned. * Implemented removing interfaces. Works quite nicely. * When downing an interface, all of its routes are now removed. When upping it again, at least the default routes are added. * datalink.cpp's get_interface_name_or_index() leaked a reference to the interface found. * SIOCAIFADDR would also leak a reference when new addresses were added. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37872 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/posix/net/if.h | 10 +- headers/posix/sys/sockio.h | 15 +- headers/private/net/net_datalink.h | 1 + src/add-ons/kernel/network/stack/datalink.cpp | 28 +- .../kernel/network/stack/interfaces.cpp | 276 ++++++++++-------- src/add-ons/kernel/network/stack/interfaces.h | 12 +- src/add-ons/kernel/network/stack/routes.cpp | 27 +- src/add-ons/kernel/network/stack/routes.h | 4 + src/bin/debug/strace/ioctl.cpp | 6 +- src/bin/network/ifconfig/ifconfig.cpp | 98 +++++-- 10 files changed, 303 insertions(+), 174 deletions(-) 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;