* Added Haiku specific socket ioctls to configure the interface aliases:

SIOC_IF_ALIAS_ADD, SIOC_IF_ALIAS_REMOVE, SIOC_IF_ALIAS_GET, SIOC_ALIAS_SET,
  and SIOC_IF_ALIAS_COUNT.
* Implemented all of those new ioctls, though they are yet untested.
* Added ifreq::ifr_data, and removed the hack in the FreeBSD compat if.h
  header.
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37806 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2010-07-29 09:43:08 +00:00
parent 5b2bb28ea1
commit 9d771afb39
6 changed files with 308 additions and 170 deletions
+9 -1
View File
@@ -46,14 +46,20 @@ struct ifreq {
int ifr_media; int ifr_media;
int ifr_type; int ifr_type;
int ifr_reqcap; int ifr_reqcap;
int ifr_count;
uint8_t* ifr_data;
}; };
}; };
/* used with SIOCAIFADDR */ /* used with SIOC_IF_ALIAS_ADD, SIOC_IF_ALIAS_GET, SIOC_ALIAS_SET */
struct ifaliasreq { struct ifaliasreq {
char ifra_name[IF_NAMESIZE]; char ifra_name[IF_NAMESIZE];
int ifra_index;
struct sockaddr_storage ifra_addr; struct sockaddr_storage ifra_addr;
union {
struct sockaddr_storage ifra_broadaddr; struct sockaddr_storage ifra_broadaddr;
struct sockaddr_storage ifra_destination;
};
struct sockaddr_storage ifra_mask; struct sockaddr_storage ifra_mask;
}; };
@@ -72,6 +78,7 @@ struct ifaliasreq {
#define IFF_CONFIGURING 0x4000 /* auto configuration in progress */ #define IFF_CONFIGURING 0x4000 /* auto configuration in progress */
#define IFF_MULTICAST 0x8000 /* supports multicast */ #define IFF_MULTICAST 0x8000 /* supports multicast */
/* used with SIOCGIFCOUNT, and SIOCGIFCONF */
struct ifconf { struct ifconf {
int ifc_len; /* size of buffer */ int ifc_len; /* size of buffer */
union { union {
@@ -106,4 +113,5 @@ void if_freenameindex(struct if_nameindex *interfaceArray);
} }
#endif #endif
#endif /* _NET_IF_H */ #endif /* _NET_IF_H */
+18 -4
View File
@@ -6,6 +6,9 @@
#define _SYS_SOCKIO_H #define _SYS_SOCKIO_H
/*! Socket I/O control codes, usually via struct ifreq */
#define SIOCADDRT 8900 /* add route */ #define SIOCADDRT 8900 /* add route */
#define SIOCDELRT 8901 /* delete route */ #define SIOCDELRT 8901 /* delete route */
#define SIOCSIFADDR 8902 /* set interface address */ #define SIOCSIFADDR 8902 /* set interface address */
@@ -25,7 +28,8 @@
#define SIOCGIFMETRIC 8916 /* get interface metric */ #define SIOCGIFMETRIC 8916 /* get interface metric */
#define SIOCSIFMETRIC 8917 /* set interface metric */ #define SIOCSIFMETRIC 8917 /* set interface metric */
#define SIOCDIFADDR 8918 /* delete interface address */ #define SIOCDIFADDR 8918 /* delete interface address */
#define SIOCAIFADDR 8919 /* configure interface alias */ #define SIOCAIFADDR 8919
/* configure interface alias, ifaliasreq */
#define SIOCADDMULTI 8920 /* add multicast address */ #define SIOCADDMULTI 8920 /* add multicast address */
#define SIOCDELMULTI 8921 /* delete multicast address */ #define SIOCDELMULTI 8921 /* delete multicast address */
#define SIOCGIFMTU 8922 /* get interface MTU */ #define SIOCGIFMTU 8922 /* get interface MTU */
@@ -35,13 +39,16 @@
#define SIOCGRTSIZE 8926 /* get route table size */ #define SIOCGRTSIZE 8926 /* get route table size */
#define SIOCGRTTABLE 8927 /* get route table */ #define SIOCGRTTABLE 8927 /* get route table */
#define SIOCGETRT 8928 /* get route information for destination */ #define SIOCGETRT 8928
/* get route information for destination */
#define SIOCGIFSTATS 8929 /* get interface stats */ #define SIOCGIFSTATS 8929 /* get interface stats */
#define SIOCGIFTYPE 8931 /* get interface type */ #define SIOCGIFTYPE 8931 /* get interface type */
#define SIOCSPACKETCAP 8932 /* Start capturing packets on an interface */ #define SIOCSPACKETCAP 8932
#define SIOCCPACKETCAP 8933 /* Stop capturing packets on an interface */ /* Start capturing packets on an interface */
#define SIOCCPACKETCAP 8933
/* Stop capturing packets on an interface */
#define SIOCSHIWAT 8934 /* set high watermark */ #define SIOCSHIWAT 8934 /* set high watermark */
#define SIOCGHIWAT 8935 /* get high watermark */ #define SIOCGHIWAT 8935 /* get high watermark */
@@ -59,6 +66,13 @@
#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 */
#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 */
#define SIOCEND 9000 /* SIOCEND >= highest SIOC* */ #define SIOCEND 9000 /* SIOCEND >= highest SIOC* */
#endif /* _SYS_SOCKIO_H */ #endif /* _SYS_SOCKIO_H */
+60 -13
View File
@@ -159,6 +159,23 @@ get_interface_name_or_index(net_domain* domain, int32 option, void* value,
} }
status_t
fill_address(const sockaddr* from, sockaddr* to, size_t maxLength)
{
if (from != NULL) {
// Copy address over
return user_memcpy(to, from, min_c(from->sa_len, maxLength));
}
// Fill in empty address
sockaddr empty;
empty.sa_len = 2;
empty.sa_family = AF_UNSPEC;
return user_memcpy(to, &empty, min_c(2, maxLength));
}
// #pragma mark - datalink module // #pragma mark - datalink module
@@ -180,7 +197,7 @@ 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: case SIOCAIFADDR: /* same as SIOC_IF_ALIAS_ADD */
{ {
// add new interface address // add new interface address
if (*_length < sizeof(struct ifaliasreq)) if (*_length < sizeof(struct ifaliasreq))
@@ -203,7 +220,7 @@ datalink_control(net_domain* _domain, int32 option, void* value,
net_device_interface* deviceInterface net_device_interface* deviceInterface
= get_device_interface(request.ifra_name); = get_device_interface(request.ifra_name);
if (deviceInterface == NULL) if (deviceInterface == NULL)
return ENODEV; return B_DEVICE_NOT_FOUND;
status_t status = add_interface(request.ifra_name, domain, request, status_t status = add_interface(request.ifra_name, domain, request,
deviceInterface); deviceInterface);
@@ -212,7 +229,7 @@ datalink_control(net_domain* _domain, int32 option, void* value,
return status; return status;
} }
case SIOCDIFADDR: case SIOCDIFADDR: /* same as SIOC_IF_ALIAS_REMOVE */
{ {
// remove interface (address) // remove interface (address)
struct ifreq request; struct ifreq request;
@@ -727,18 +744,48 @@ interface_protocol_control(net_datalink_protocol* _protocol, int32 option,
size_t maxLength = length - offsetof(ifreq, ifr_addr); size_t maxLength = length - offsetof(ifreq, ifr_addr);
sockaddr* address = *interfaceAddress->AddressFor(option); return fill_address(*interfaceAddress->AddressFor(option),
if (address != NULL) { &((struct ifreq*)argument)->ifr_addr, maxLength);
// Copy address over
return user_memcpy(&((struct ifreq*)argument)->ifr_addr,
address, min_c(address->sa_len, maxLength));
} }
// Fill in empty address case SIOC_IF_ALIAS_COUNT:
request.ifr_addr.sa_len = 2; {
request.ifr_addr.sa_family = AF_UNSPEC; ifreq request;
return user_memcpy(&((struct ifreq*)argument)->ifr_addr, request.ifr_count = interface->CountAddresses();
&request.ifr_addr, min_c(2, maxLength));
return user_memcpy(&((struct ifreq*)argument)->ifr_count,
&request.ifr_count, sizeof(request.ifr_count));
}
case SIOC_IF_ALIAS_GET:
{
ifaliasreq request;
if (user_memcpy(&request, argument, sizeof(ifaliasreq)) != B_OK)
return B_BAD_ADDRESS;
InterfaceAddress* address
= interface->AddressAt(request.ifra_index);
if (address == NULL)
return B_BAD_VALUE;
status_t status = fill_address(address->local,
(sockaddr*)&((struct ifaliasreq*)argument)->ifra_addr,
sizeof(sockaddr_storage));
if (status == B_OK) {
status = fill_address(address->mask,
(sockaddr*)&((struct ifaliasreq*)argument)->ifra_mask,
sizeof(sockaddr_storage));
}
if (status == B_OK) {
status = fill_address(address->destination,
(sockaddr*)&((struct ifaliasreq*)argument)
->ifra_destination,
sizeof(sockaddr_storage));
}
address->ReleaseReference();
return status;
} }
case SIOCGIFFLAGS: case SIOCGIFFLAGS:
+108 -20
View File
@@ -18,9 +18,7 @@
#include <KernelExport.h> #include <KernelExport.h>
#include <lock.h>
#include <net_device.h> #include <net_device.h>
#include <util/AutoLock.h>
#include "device_interfaces.h" #include "device_interfaces.h"
#include "domains.h" #include "domains.h"
@@ -516,6 +514,40 @@ Interface::GetNextAddress(InterfaceAddress** _address)
} }
InterfaceAddress*
Interface::AddressAt(size_t index)
{
RecursiveLocker locker(fLock);
AddressList::Iterator iterator = fAddresses.GetIterator();
size_t i = 0;
while (InterfaceAddress* address = iterator.Next()) {
if (i++ == index) {
address->AcquireReference();
return address;
}
}
return NULL;
}
size_t
Interface::CountAddresses()
{
RecursiveLocker locker(fLock);
return fAddresses.Count();
}
/*! 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
net_datalink_protocol::interface_up(), and interface_down().
Everything else is passed unchanged to net_datalink_protocol::control().
*/
status_t status_t
Interface::Control(net_domain* domain, int32 option, ifreq& request, Interface::Control(net_domain* domain, int32 option, ifreq& request,
ifreq* userRequest, size_t length) ifreq* userRequest, size_t length)
@@ -549,6 +581,51 @@ Interface::Control(net_domain* domain, int32 option, ifreq& request,
return status; return status;
} }
case SIOC_IF_ALIAS_SET:
{
RecursiveLocker locker(fLock);
ifaliasreq aliasRequest;
if (user_memcpy(&aliasRequest, userRequest, sizeof(ifaliasreq))
!= B_OK)
return B_BAD_ADDRESS;
InterfaceAddress* address = AddressAt(aliasRequest.ifra_index);
if (address == NULL)
return B_BAD_VALUE;
status_t status = B_OK;
address->AcquireReference();
// _ChangeAddress() currently unlocks, so we need another
// reference to make sure "address" is not going away.
if (!domain->address_module->equal_addresses(
(sockaddr*)&aliasRequest.ifra_addr, address->local)) {
status = _ChangeAddress(locker, address, SIOCSIFADDR,
address->local, (sockaddr*)&aliasRequest.ifra_addr);
}
if (status == B_OK && !domain->address_module->equal_addresses(
(sockaddr*)&aliasRequest.ifra_mask, address->mask)) {
status = _ChangeAddress(locker, address, SIOCSIFNETMASK,
address->mask, (sockaddr*)&aliasRequest.ifra_mask);
}
if (status == B_OK && !domain->address_module->equal_addresses(
(sockaddr*)&aliasRequest.ifra_destination,
address->destination)) {
status = _ChangeAddress(locker, address,
(domain->address_module->flags
& NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS) != 0
? SIOCSIFBRDADDR : SIOCSIFDSTADDR,
address->destination,
(sockaddr*)&aliasRequest.ifra_destination);
}
address->ReleaseReference();
return status;
}
case SIOCSIFADDR: case SIOCSIFADDR:
case SIOCSIFNETMASK: case SIOCSIFNETMASK:
case SIOCSIFBRDADDR: case SIOCSIFBRDADDR:
@@ -558,7 +635,6 @@ Interface::Control(net_domain* domain, int32 option, ifreq& request,
RecursiveLocker locker(fLock); RecursiveLocker locker(fLock);
InterfaceAddress* address = NULL; InterfaceAddress* address = NULL;
sockaddr_storage oldAddress;
sockaddr_storage newAddress; sockaddr_storage newAddress;
size_t size = max_c(request.ifr_addr.sa_len, sizeof(sockaddr)); size_t size = max_c(request.ifr_addr.sa_len, sizeof(sockaddr));
@@ -586,24 +662,9 @@ Interface::Control(net_domain* domain, int32 option, ifreq& request,
if (address == NULL) if (address == NULL)
return B_BAD_VALUE; return B_BAD_VALUE;
if (*address->AddressFor(option) != NULL) return _ChangeAddress(locker, address, option,
memcpy(&oldAddress, *address->AddressFor(option), size); *address->AddressFor(option),
else
oldAddress.ss_family = AF_UNSPEC;
// TODO: mark this address busy or call while holding the lock!
address->AcquireReference();
locker.Unlock();
domain_datalink* datalink = DomainDatalink(domain->family);
status_t status = datalink->first_protocol->module->change_address(
datalink->first_protocol, address, option,
oldAddress.ss_family != AF_UNSPEC
? (sockaddr*)&oldAddress : NULL,
option != SIOCDIFADDR ? (sockaddr*)&newAddress : NULL); option != SIOCDIFADDR ? (sockaddr*)&newAddress : NULL);
address->ReleaseReference();
return status;
} }
default: default:
@@ -787,6 +848,33 @@ Interface::_FirstForFamily(int family)
} }
status_t
Interface::_ChangeAddress(RecursiveLocker& locker, InterfaceAddress* address,
int32 option, const sockaddr* originalAddress, const sockaddr* newAddress)
{
// Copy old address over
sockaddr_storage oldAddress;
if (address->domain->address_module->set_to((sockaddr*)&oldAddress,
originalAddress) != B_OK)
oldAddress.ss_family = AF_UNSPEC;
// TODO: mark this address busy or call while holding the lock!
address->AcquireReference();
locker.Unlock();
domain_datalink* datalink = DomainDatalink(address->domain);
status_t status = datalink->first_protocol->module->change_address(
datalink->first_protocol, address, option,
oldAddress.ss_family != AF_UNSPEC ? (sockaddr*)&oldAddress : NULL,
newAddress != NULL && newAddress->sa_family != AF_UNSPEC
? newAddress : NULL);
locker.Lock();
address->ReleaseReference();
return status;
}
// #pragma mark - // #pragma mark -
@@ -17,6 +17,7 @@
#include <Referenceable.h> #include <Referenceable.h>
#include <util/AutoLock.h>
#include <util/DoublyLinkedList.h> #include <util/DoublyLinkedList.h>
#include <util/OpenHashTable.h> #include <util/OpenHashTable.h>
@@ -118,6 +119,8 @@ public:
status_t AddAddress(InterfaceAddress* address); status_t AddAddress(InterfaceAddress* address);
void RemoveAddress(InterfaceAddress* address); void RemoveAddress(InterfaceAddress* address);
bool GetNextAddress(InterfaceAddress** _address); bool GetNextAddress(InterfaceAddress** _address);
InterfaceAddress* AddressAt(size_t index);
size_t CountAddresses();
status_t Control(net_domain* domain, int32 option, status_t Control(net_domain* domain, int32 option,
ifreq& request, ifreq* userRequest, ifreq& request, ifreq* userRequest,
@@ -141,7 +144,10 @@ private:
status_t _SetUp(); status_t _SetUp();
void _SetDown(); void _SetDown();
InterfaceAddress* _FirstForFamily(int family); InterfaceAddress* _FirstForFamily(int family);
status_t _AddDomainDatalink(net_domain* domain); status_t _ChangeAddress(RecursiveLocker& locker,
InterfaceAddress* address, int32 option,
const sockaddr* oldAddress,
const sockaddr* newAddress);
private: private:
recursive_lock fLock; recursive_lock fLock;
@@ -6,11 +6,7 @@
#define _FBSD_COMPAT_NET_IF_H_ #define _FBSD_COMPAT_NET_IF_H_
// Rename the ifreq structure provided by posix/net/if.h
// so that we can add FreeBSD based ifreq parts.
#define ifreq ifreq_haiku_unused
#include <posix/net/if.h> #include <posix/net/if.h>
#undef ifreq
#include <sys/cdefs.h> #include <sys/cdefs.h>
#include <sys/queue.h> #include <sys/queue.h>
@@ -60,28 +56,6 @@
#define IFQ_MAXLEN 50 #define IFQ_MAXLEN 50
struct ifreq {
char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */
union {
struct sockaddr ifr_addr;
struct sockaddr ifr_dstaddr;
struct sockaddr ifr_broadaddr;
struct sockaddr ifr_mask;
struct ifreq_stats ifr_stats;
struct route_entry ifr_route;
int ifr_flags;
int ifr_index;
int ifr_metric;
int ifr_mtu;
int ifr_media;
int ifr_type;
int ifr_reqcap;
// FreeBSD specific Part
caddr_t ifr_data;
};
};
struct ifmediareq { struct ifmediareq {
char ifm_name[IFNAMSIZ]; /* if name, e.g. "en0" */ char ifm_name[IFNAMSIZ]; /* if name, e.g. "en0" */
int ifm_current; /* current media options */ int ifm_current; /* current media options */
@@ -137,8 +111,9 @@ struct ifdrv {
}; };
#ifdef _KERNEL #ifdef _KERNEL
/* XXX - this should go away soon. */ /* TODO: this should go away soon. */
# include <net/if_var.h> # include <net/if_var.h>
#endif #endif
#endif
#endif /* _FBSD_COMPAT_NET_IF_H_ */