* 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
This commit is contained in:
Axel Dörfler
2010-08-03 15:51:54 +00:00
parent a7faa05822
commit 2b1c0755dd
10 changed files with 303 additions and 174 deletions
+8 -2
View File
@@ -61,6 +61,7 @@ struct ifaliasreq {
struct sockaddr_storage ifra_destination; struct sockaddr_storage ifra_destination;
}; };
struct sockaddr_storage ifra_mask; struct sockaddr_storage ifra_mask;
uint32_t ifra_flags;
}; };
/* interface flags */ /* interface flags */
@@ -74,10 +75,15 @@ struct ifaliasreq {
#define IFF_ALLMULTI 0x0200 /* receive all multicast packets */ #define IFF_ALLMULTI 0x0200 /* receive all multicast packets */
#define IFF_SIMPLEX 0x0800 /* doesn't receive own transmissions */ #define IFF_SIMPLEX 0x0800 /* doesn't receive own transmissions */
#define IFF_LINK 0x1000 /* has link */ #define IFF_LINK 0x1000 /* has link */
#define IFF_AUTO_CONFIGURED 0x2000 /* has been automatically configured */ #define IFF_AUTO_CONFIGURED 0x2000
#define IFF_CONFIGURING 0x4000 /* auto configuration in progress */ #define IFF_CONFIGURING 0x4000
#define IFF_MULTICAST 0x8000 /* supports multicast */ #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 */ /* used with SIOCGIFCOUNT, and SIOCGIFCONF */
struct ifconf { struct ifconf {
int ifc_len; /* size of buffer */ int ifc_len; /* size of buffer */
+9 -6
View File
@@ -6,7 +6,9 @@
#define _SYS_SOCKIO_H #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 */ #define SIOCADDRT 8900 /* add route */
@@ -66,11 +68,12 @@
#define SIOCSIFGENERIC 8945 /* generic IF set op */ #define SIOCSIFGENERIC 8945 /* generic IF set op */
#define SIOCGIFGENERIC 8946 /* generic IF get op */ #define SIOCGIFGENERIC 8946 /* generic IF get op */
#define SIOC_IF_ALIAS_REMOVE 8918 /* synonym for SIOCDIFADDR */ /* Haiku specific extensions */
#define SIOC_IF_ALIAS_ADD 8919 /* synonym for SIOCAIFADDR */ #define B_SOCKET_REMOVE_ALIAS 8918 /* synonym for SIOCDIFADDR */
#define SIOC_IF_ALIAS_SET 8947 /* set interface alias, ifaliasreq */ #define B_SOCKET_ADD_ALIAS 8919 /* synonym for SIOCAIFADDR */
#define SIOC_IF_ALIAS_GET 8948 /* get interface alias, ifaliasreq */ #define B_SOCKET_SET_ALIAS 8947 /* set interface alias, ifaliasreq */
#define SIOC_IF_ALIAS_COUNT 8959 /* count interface aliases */ #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* */ #define SIOCEND 9000 /* SIOCEND >= highest SIOC* */
+1
View File
@@ -38,6 +38,7 @@ typedef struct net_interface_address {
struct sockaddr* local; struct sockaddr* local;
struct sockaddr* destination; struct sockaddr* destination;
struct sockaddr* mask; struct sockaddr* mask;
uint32_t flags;
} net_interface_address; } net_interface_address;
typedef struct net_interface { typedef struct net_interface {
+15 -13
View File
@@ -110,9 +110,9 @@ option_to_string(int32 option)
CODE(SIOCSIFGENERIC) /* generic IF set op */ CODE(SIOCSIFGENERIC) /* generic IF set op */
CODE(SIOCGIFGENERIC) /* generic IF get op */ CODE(SIOCGIFGENERIC) /* generic IF get op */
CODE(SIOC_IF_ALIAS_SET) /* set interface alias, ifaliasreq */ CODE(B_SOCKET_SET_ALIAS) /* set interface alias, ifaliasreq */
CODE(SIOC_IF_ALIAS_GET) /* get interface alias, ifaliasreq */ CODE(B_SOCKET_GET_ALIAS) /* get interface alias, ifaliasreq */
CODE(SIOC_IF_ALIAS_COUNT) /* count interface aliases */ CODE(B_SOCKET_COUNT_ALIASES) /* count interface aliases */
default: default:
static char buffer[24]; 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) if (user_memcpy(&request, value, expected) < B_OK)
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
net_interface* interface = NULL; Interface* interface = NULL;
if (option == SIOCGIFINDEX) if (option == SIOCGIFINDEX)
interface = get_interface(domain, request.ifr_name); interface = get_interface(domain, request.ifr_name);
else 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); strlcpy(request.ifr_name, interface->name, IF_NAMESIZE);
*_length = sizeof(ifreq); *_length = sizeof(ifreq);
interface->ReleaseReference();
return user_memcpy(value, &request, sizeof(ifreq)); return user_memcpy(value, &request, sizeof(ifreq));
} }
@@ -200,14 +201,14 @@ datalink_control(net_domain* _domain, int32 option, void* value,
case SIOCGIFNAME: case SIOCGIFNAME:
return get_interface_name_or_index(domain, option, value, _length); 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 // add new interface address
if (*_length < sizeof(struct ifaliasreq)) if (*_length < sizeof(struct ifaliasreq))
return B_BAD_VALUE; return B_BAD_VALUE;
struct ifaliasreq request; 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; return B_BAD_ADDRESS;
Interface* interface = get_interface(domain, request.ifra_name); 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, status_t status = add_interface_address(interface, domain,
request); request);
notify_interface_changed(interface); notify_interface_changed(interface);
interface->ReleaseReference();
return status; return status;
} }
@@ -232,11 +235,11 @@ datalink_control(net_domain* _domain, int32 option, void* value,
return status; return status;
} }
case SIOCDIFADDR: /* same as SIOC_IF_ALIAS_REMOVE */ case SIOCDIFADDR: /* same as B_SOCKET_REMOVE_ALIAS */
{ {
// remove interface (address) // remove interface (address)
struct ifreq request; 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; return B_BAD_ADDRESS;
Interface* interface = get_interface(domain, request.ifr_name); Interface* interface = get_interface(domain, request.ifr_name);
@@ -246,8 +249,7 @@ datalink_control(net_domain* _domain, int32 option, void* value,
status_t status; status_t status;
if (request.ifr_addr.sa_family != AF_UNSPEC if (request.ifr_addr.sa_family != AF_UNSPEC
|| request.ifr_addr.sa_len != 0) { && request.ifr_addr.sa_len != 0) {
// TODO: remove interface if this was the last address?
status = interface->Control(domain, SIOCDIFADDR, request, status = interface->Control(domain, SIOCDIFADDR, request,
(ifreq*)value, *_length); (ifreq*)value, *_length);
} else } else
@@ -675,7 +677,7 @@ interface_protocol_down(net_datalink_protocol* _protocol)
deviceInterface->up_count--; deviceInterface->up_count--;
interface_went_down(interface); interface->WentDown();
if (deviceInterface->up_count > 0) if (deviceInterface->up_count > 0)
return; return;
@@ -745,7 +747,7 @@ interface_protocol_control(net_datalink_protocol* _protocol, int32 option,
&((struct ifreq*)argument)->ifr_addr, maxLength); &((struct ifreq*)argument)->ifr_addr, maxLength);
} }
case SIOC_IF_ALIAS_COUNT: case B_SOCKET_COUNT_ALIASES:
{ {
ifreq request; ifreq request;
request.ifr_count = interface->CountAddresses(); 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)); &request.ifr_count, sizeof(request.ifr_count));
} }
case SIOC_IF_ALIAS_GET: case B_SOCKET_GET_ALIAS:
{ {
ifaliasreq request; ifaliasreq request;
if (user_memcpy(&request, argument, sizeof(ifaliasreq)) != B_OK) if (user_memcpy(&request, argument, sizeof(ifaliasreq)) != B_OK)
+161 -115
View File
@@ -170,6 +170,10 @@ InterfaceAddress::InterfaceAddress(net_interface* netInterface,
InterfaceAddress::~InterfaceAddress() 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) { switch (option) {
case SIOCSIFADDR: case SIOCSIFADDR:
case SIOCGIFADDR: case SIOCGIFADDR:
case SIOCDIFADDR:
return &local; return &local;
case SIOCSIFNETMASK: 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 #if ENABLE_DEBUGGER_COMMANDS
@@ -331,11 +384,18 @@ InterfaceAddress::Prepare(sockaddr** _address, size_t size)
void void
InterfaceAddress::_Init(net_interface* netInterface, net_domain* netDomain) InterfaceAddress::_Init(net_interface* netInterface, net_domain* netDomain)
{ {
TRACE("InterfaceAddress %p: init interface %p, domain %p\n", this,
netInterface, netDomain);
interface = netInterface; interface = netInterface;
domain = netDomain; domain = netDomain;
local = NULL; local = NULL;
destination = NULL; destination = NULL;
mask = NULL; mask = NULL;
flags = 0;
if (interface != NULL)
((Interface*)interface)->AcquireReference();
} }
@@ -370,6 +430,27 @@ Interface::Interface(const char* interfaceName,
Interface::~Interface() 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); recursive_lock_destroy(&fLock);
// Release reference of the stack - at this point, our stack may be unloaded // Release reference of the stack - at this point, our stack may be unloaded
@@ -477,10 +558,6 @@ Interface::RemoveAddress(InterfaceAddress* address)
fAddresses.Remove(address); fAddresses.Remove(address);
address->GetDoublyLinkedListLink()->next = NULL; address->GetDoublyLinkedListLink()->next = NULL;
// TODO!
// if (_FirstForFamily(domain->family) == NULL)
// put_domain_datalink_protocols(this, domain);
locker.Unlock(); locker.Unlock();
MutexLocker hashLocker(sHashLock); 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 /*! This is called in order to call the correct methods of the datalink
protocols, ie. it will translate address changes to protocols, ie. it will translate address changes to
net_datalink_protocol::change_address(), and IFF_UP 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) if ((requestFlags & IFF_UP) != 0)
status = _SetUp(); status = _SetUp();
else else
_SetDown(); SetDown();
} }
if (status == B_OK) { if (status == B_OK) {
@@ -581,7 +669,7 @@ Interface::Control(net_domain* domain, int32 option, ifreq& request,
return status; return status;
} }
case SIOC_IF_ALIAS_SET: case B_SOCKET_SET_ALIAS:
{ {
RecursiveLocker locker(fLock); 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 status_t
Interface::CreateDomainDatalinkIfNeeded(net_domain* domain) Interface::CreateDomainDatalinkIfNeeded(net_domain* domain)
{ {
@@ -713,6 +834,7 @@ Interface::CreateDomainDatalinkIfNeeded(net_domain* domain)
datalink->direct_address.mask = NULL; datalink->direct_address.mask = NULL;
datalink->direct_address.domain = domain; datalink->direct_address.domain = domain;
datalink->direct_address.interface = this; datalink->direct_address.interface = this;
datalink->direct_address.flags = IFAF_DIRECT_ADDRESS;
fDatalinkTable.Insert(datalink); fDatalinkTable.Insert(datalink);
@@ -785,7 +907,7 @@ Interface::_SetUp()
if (status != B_OK) if (status != B_OK)
return status; return status;
// propagate flag to all datalink protocols // Propagate flag to all datalink protocols
RecursiveLocker locker(fLock); RecursiveLocker locker(fLock);
@@ -810,26 +932,15 @@ Interface::_SetUp()
} }
} }
flags |= IFF_UP; // Add default routes for the existing addresses
return B_OK;
}
AddressList::Iterator addressIterator = fAddresses.GetIterator();
void while (InterfaceAddress* address = addressIterator.Next()) {
Interface::_SetDown() address->AddDefaultRoutes(SIOCSIFADDR);
{
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);
} }
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 - // #pragma mark -
@@ -1000,47 +1061,17 @@ add_interface(const char* name, net_domain_private* domain,
status_t status_t
remove_interface(Interface* interface) remove_interface(Interface* interface)
{ {
return B_ERROR; interface->SetDown();
#if 0 interface->RemoveAddresses();
// deleting an interface is fairly complex as we need
// to clear all references to it throughout the stack
// this will possibly call (if IFF_UP): MutexLocker locker(sLock);
// interface_protocol_down() sInterfaces.Remove(interface);
// domain_interface_went_down() locker.Unlock();
// invalidate_routes()
// remove_route()
// update_route_infos()
// get_route_internal()
// down_device_interface() -- if upcount reaches 0
interface_set_down(interface);
// 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); notify_interface_removed(interface);
delete_interface((net_interface_private*)interface);
#endif interface->ReleaseReference();
} return B_OK;
void
interface_went_down(Interface* interface)
{
TRACE("interface_went_down(%s)\n", interface->name);
// TODO!
//invalidate_routes(domain, interface);
} }
@@ -1100,7 +1131,22 @@ update_interface_address(InterfaceAddress* interfaceAddress, int32 option,
if (_address == NULL) if (_address == NULL)
return B_BAD_VALUE; 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); sAddressTable.Remove(interfaceAddress);
// Copy new address over // Copy new address over
@@ -1135,8 +1181,8 @@ update_interface_address(InterfaceAddress* interfaceAddress, int32 option,
interfaceAddress->local, oldNetmask); interfaceAddress->local, oldNetmask);
} }
add_default_routes(interfaceAddress, option); interfaceAddress->AddDefaultRoutes(option);
notify_interface_changed(interfaceAddress->interface); notify_interface_changed(interface);
} }
sAddressTable.Insert(interfaceAddress); sAddressTable.Insert(interfaceAddress);
+11 -1
View File
@@ -25,6 +25,10 @@
struct net_device_interface; struct net_device_interface;
// Additional address flags
#define IFAF_DIRECT_ADDRESS 0x1000
struct InterfaceAddress : DoublyLinkedListLinkImpl<InterfaceAddress>, struct InterfaceAddress : DoublyLinkedListLinkImpl<InterfaceAddress>,
net_interface_address, Referenceable { net_interface_address, Referenceable {
InterfaceAddress(); InterfaceAddress();
@@ -40,6 +44,9 @@ struct InterfaceAddress : DoublyLinkedListLinkImpl<InterfaceAddress>,
sockaddr** AddressFor(int32 option); sockaddr** AddressFor(int32 option);
void AddDefaultRoutes(int32 option);
void RemoveDefaultRoutes(int32 option);
InterfaceAddress*& HashTableLink() { return fLink; } InterfaceAddress*& HashTableLink() { return fLink; }
#if ENABLE_DEBUGGER_COMMANDS #if ENABLE_DEBUGGER_COMMANDS
@@ -121,11 +128,15 @@ public:
bool GetNextAddress(InterfaceAddress** _address); bool GetNextAddress(InterfaceAddress** _address);
InterfaceAddress* AddressAt(size_t index); InterfaceAddress* AddressAt(size_t index);
size_t CountAddresses(); size_t CountAddresses();
void RemoveAddresses();
status_t Control(net_domain* domain, int32 option, status_t Control(net_domain* domain, int32 option,
ifreq& request, ifreq* userRequest, ifreq& request, ifreq* userRequest,
size_t length); size_t length);
void SetDown();
void WentDown();
recursive_lock& Lock() { return fLock; } recursive_lock& Lock() { return fLock; }
net_device_interface* DeviceInterface() { return fDeviceInterface; } net_device_interface* DeviceInterface() { return fDeviceInterface; }
@@ -142,7 +153,6 @@ public:
private: private:
status_t _SetUp(); status_t _SetUp();
void _SetDown();
InterfaceAddress* _FirstForFamily(int family); InterfaceAddress* _FirstForFamily(int family);
status_t _ChangeAddress(RecursiveLocker& locker, status_t _ChangeAddress(RecursiveLocker& locker,
InterfaceAddress* address, int32 option, InterfaceAddress* address, int32 option,
+25 -2
View File
@@ -411,6 +411,8 @@ status_t
control_routes(struct net_interface* _interface, net_domain* domain, control_routes(struct net_interface* _interface, net_domain* domain,
int32 option, void* argument, size_t length) 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; Interface* interface = (Interface*)_interface;
switch (option) { switch (option) {
@@ -447,7 +449,8 @@ control_routes(struct net_interface* _interface, net_domain* domain,
else else
status = remove_route(domain, &route); status = remove_route(domain, &route);
address->ReleaseReference(); if (address != NULL)
address->ReleaseReference();
return status; return status;
} }
} }
@@ -601,7 +604,7 @@ invalidate_routes(net_domain* _domain, net_interface* interface)
net_domain_private* domain = (net_domain_private*)_domain; net_domain_private* domain = (net_domain_private*)_domain;
RecursiveLocker locker(domain->lock); 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(); RouteList::Iterator iterator = domain->routes.GetIterator();
while (iterator.HasNext()) { 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* struct net_route*
get_route(struct net_domain* _domain, const struct sockaddr* address) get_route(struct net_domain* _domain, const struct sockaddr* address)
{ {
@@ -15,6 +15,9 @@
#include <util/DoublyLinkedList.h> #include <util/DoublyLinkedList.h>
class InterfaceAddress;
struct net_route_private struct net_route_private
: net_route, DoublyLinkedListLinkImpl<net_route_private> { : net_route, DoublyLinkedListLinkImpl<net_route_private> {
int32 ref_count; 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, status_t get_route_information(struct net_domain* domain, void* buffer,
size_t length); size_t length);
void invalidate_routes(net_domain* domain, net_interface* interface); void invalidate_routes(net_domain* domain, net_interface* interface);
void invalidate_routes(InterfaceAddress* address);
struct net_route* get_route(struct net_domain* domain, struct net_route* get_route(struct net_domain* domain,
const struct sockaddr* address); const struct sockaddr* address);
status_t get_device_route(struct net_domain* domain, uint32 index, status_t get_device_route(struct net_domain* domain, uint32 index,
+3 -3
View File
@@ -106,9 +106,9 @@ static const ioctl_info kIOCtls[] = {
IOCTL_INFO_ENTRY(SIOCATMARK), IOCTL_INFO_ENTRY(SIOCATMARK),
IOCTL_INFO_ENTRY(SIOCSPGRP), IOCTL_INFO_ENTRY(SIOCSPGRP),
IOCTL_INFO_ENTRY_TYPE(SIOC_IF_ALIAS_SET, struct ifaliasreq *), IOCTL_INFO_ENTRY_TYPE(B_SOCKET_SET_ALIAS, struct ifaliasreq *),
IOCTL_INFO_ENTRY_TYPE(SIOC_IF_ALIAS_GET, struct ifaliasreq *), IOCTL_INFO_ENTRY_TYPE(B_SOCKET_GET_ALIAS, struct ifaliasreq *),
IOCTL_INFO_ENTRY_TYPE(SIOC_IF_ALIAS_COUNT, struct ifaliasreq *), IOCTL_INFO_ENTRY_TYPE(B_SOCKET_COUNT_ALIASES, struct ifreq *),
// termios ioctls // termios ioctls
IOCTL_INFO_ENTRY(TCGETA), IOCTL_INFO_ENTRY(TCGETA),
+66 -32
View File
@@ -393,6 +393,7 @@ prepare_request(struct ifreq& request, const char* name)
return false; return false;
} }
memset(&request, 0, sizeof(ifreq));
strcpy(request.ifr_name, name); strcpy(request.ifr_name, name);
return true; 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 void
delete_interface(const char* name) delete_interface(const char* name, char* const* args, int32 argCount)
{ {
ifreq request; ifreq request;
if (!prepare_request(request, name)) if (!prepare_request(request, name))
return; return;
int socket = find_socket(request, -1); for (int32 i = 0; i < argCount; i++) {
if (socket == -1) int32 familyIndex;
return; if (get_address_family(args[i], familyIndex))
i++;
if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) { // TODO: be smart enough to detect the family by the address
fprintf(stderr, "%s: Could not delete interface %s: %s\n",
kProgramName, name, strerror(errno)); 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) { if (index == 0) {
// the interface does not exist yet, we have to add it first // the interface does not exist yet, we have to add it first
ifaliasreq request; ifaliasreq request;
memset(&request, 0, sizeof(ifaliasreq));
strlcpy(request.ifra_name, name, IF_NAMESIZE); 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) { if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) {
fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName, fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName,
strerror(errno)); strerror(errno));
@@ -1052,32 +1086,32 @@ main(int argc, char** argv)
if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
usage(0); usage(0);
bool deleteInterfaces = false; if (!initialize_address_families()) {
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) {
fprintf(stderr, "%s: The networking stack doesn't seem to be " fprintf(stderr, "%s: The networking stack doesn't seem to be "
"available.\n", kProgramName); "available.\n", kProgramName);
return 1; return 1;
} }
if (deleteInterfaces) { if (argc > 1
for (int i = 2; i < argc; i++) { && (!strcmp(argv[1], "--delete")
delete_interface(argv[i]); || !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; 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) if (argc > 2)
usage(1); usage(1);
@@ -1087,7 +1121,7 @@ main(int argc, char** argv)
const char* name = argv[1]; const char* name = argv[1];
if (argc > 2) { if (argc > 2) {
// add or configure an interface // Add or configure an interface
configure_interface(name, argv + 2, argc - 2); configure_interface(name, argv + 2, argc - 2);
return 0; return 0;