/*! Returns a reference to the first InterfaceAddress that is from the same as the specified \a family. */ InterfaceAddress* Interface::FirstForFamily(int family) { RecursiveLocker locker(fLock); InterfaceAddress* address = _FirstForFamily(family); if (address != NULL) { address->AcquireReference(); return address; } return NULL; }
InterfaceAddress* get_interface_address(const sockaddr* local) { if (local->sa_family == AF_UNSPEC) return NULL; MutexLocker locker(sHashLock); InterfaceAddress* address = sAddressTable.Lookup(local); if (address == NULL) return NULL; address->AcquireReference(); return address; }
bool Interface::GetNextAddress(InterfaceAddress** _address) { RecursiveLocker locker(fLock); InterfaceAddress* address = *_address; if (address == NULL) { // get first address address = fAddresses.First(); } else { // get next, if possible InterfaceAddress* next = fAddresses.GetNext(address); address->ReleaseReference(); address = next; } *_address = address; if (address == NULL) return false; address->AcquireReference(); return true; }
/*! 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) { switch (option) { case SIOCSIFFLAGS: { if (length != sizeof(ifreq)) return B_BAD_VALUE; uint32 requestFlags = request.ifr_flags; uint32 oldFlags = flags; status_t status = B_OK; request.ifr_flags &= ~(IFF_UP | IFF_LINK | IFF_BROADCAST); if ((requestFlags & IFF_UP) != (flags & IFF_UP)) { if ((requestFlags & IFF_UP) != 0) status = _SetUp(); else SetDown(); } if (status == B_OK) { // TODO: maybe allow deleting IFF_BROADCAST on the interface // level? flags &= IFF_UP | IFF_LINK | IFF_BROADCAST; flags |= request.ifr_flags; } if (oldFlags != flags) { TRACE("Interface %p: flags changed from %" B_PRIx32 " to %" B_PRIx32 "\n", this, oldFlags, flags); notify_interface_changed(this, oldFlags, flags); } return status; } case B_SOCKET_SET_ALIAS: { if (length != sizeof(ifaliasreq)) return B_BAD_VALUE; RecursiveLocker locker(fLock); ifaliasreq aliasRequest; if (user_memcpy(&aliasRequest, userRequest, sizeof(ifaliasreq)) != B_OK) return B_BAD_ADDRESS; InterfaceAddress* address = NULL; if (aliasRequest.ifra_index < 0) { if (!domain->address_module->is_empty_address( (const sockaddr*)&aliasRequest.ifra_addr, false)) { // Find first address that matches the local address address = AddressForLocal(domain, (const sockaddr*)&aliasRequest.ifra_addr); } if (address == NULL) { // Find first address for family address = FirstForFamily(domain->family); } if (address == NULL) { // Create new on the fly address = new(std::nothrow) InterfaceAddress(this, domain); if (address == NULL) return B_NO_MEMORY; status_t status = AddAddress(address); if (status != B_OK) { delete address; return status; } // Note, even if setting the address failed, the empty // address added here will still be added to the interface. address->AcquireReference(); } } else address = AddressAt(aliasRequest.ifra_index); if (address == NULL) return B_BAD_VALUE; status_t status = B_OK; 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) && !domain->address_module->is_empty_address( (sockaddr*)&aliasRequest.ifra_mask, false)) { 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) && !domain->address_module->is_empty_address( (sockaddr*)&aliasRequest.ifra_destination, false)) { 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: case SIOCSIFDSTADDR: case SIOCDIFADDR: { if (length != sizeof(ifreq)) return B_BAD_VALUE; RecursiveLocker locker(fLock); InterfaceAddress* address = NULL; sockaddr_storage newAddress; size_t size = max_c(request.ifr_addr.sa_len, sizeof(sockaddr)); if (size > sizeof(sockaddr_storage)) size = sizeof(sockaddr_storage); if (user_memcpy(&newAddress, &userRequest->ifr_addr, size) != B_OK) return B_BAD_ADDRESS; if (option == SIOCDIFADDR) { // Find referring address - we can't use the hash, as another // interface might use the same address. AddressList::Iterator iterator = fAddresses.GetIterator(); while ((address = iterator.Next()) != NULL) { if (address->domain == domain && domain->address_module->equal_addresses( address->local, (sockaddr*)&newAddress)) break; } if (address == NULL) return B_BAD_VALUE; } else { // Just use the first address for this family address = _FirstForFamily(domain->family); if (address == NULL) { // Create new on the fly address = new(std::nothrow) InterfaceAddress(this, domain); if (address == NULL) return B_NO_MEMORY; status_t status = AddAddress(address); if (status != B_OK) { delete address; return status; } // Note, even if setting the address failed, the empty // address added here will still be added to the interface. } } return _ChangeAddress(locker, address, option, *address->AddressFor(option), option != SIOCDIFADDR ? (sockaddr*)&newAddress : NULL); } default: // pass the request into the datalink protocol stack domain_datalink* datalink = DomainDatalink(domain->family); if (datalink->first_info != NULL) { return datalink->first_info->control( datalink->first_protocol, option, userRequest, length); } break; } return B_BAD_VALUE; }