Beispiel #1
0
/*!	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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
/*!	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;
}