* 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
+108 -20
View File
@@ -18,9 +18,7 @@
#include <KernelExport.h>
#include <lock.h>
#include <net_device.h>
#include <util/AutoLock.h>
#include "device_interfaces.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
Interface::Control(net_domain* domain, int32 option, ifreq& request,
ifreq* userRequest, size_t length)
@@ -549,6 +581,51 @@ Interface::Control(net_domain* domain, int32 option, ifreq& request,
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 SIOCSIFNETMASK:
case SIOCSIFBRDADDR:
@@ -558,7 +635,6 @@ Interface::Control(net_domain* domain, int32 option, ifreq& request,
RecursiveLocker locker(fLock);
InterfaceAddress* address = NULL;
sockaddr_storage oldAddress;
sockaddr_storage newAddress;
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)
return B_BAD_VALUE;
if (*address->AddressFor(option) != NULL)
memcpy(&oldAddress, *address->AddressFor(option), size);
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,
return _ChangeAddress(locker, address, option,
*address->AddressFor(option),
option != SIOCDIFADDR ? (sockaddr*)&newAddress : NULL);
address->ReleaseReference();
return status;
}
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 -