Example #1
0
status_t
control_routes(struct net_interface* _interface, net_domain* domain,
	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;

	switch (option) {
		case SIOCADDRT:
		case SIOCDELRT:
		{
			// add or remove a route
			if (length != sizeof(struct ifreq))
				return B_BAD_VALUE;

			route_entry entry;
			if (user_memcpy(&entry, &((ifreq*)argument)->ifr_route,
					sizeof(route_entry)) != B_OK)
				return B_BAD_ADDRESS;

			net_route_private route;
			status_t status;
			if ((status = user_copy_address(entry.destination,
					&route.destination)) != B_OK
				|| (status = user_copy_address(entry.mask, &route.mask)) != B_OK
				|| (status = user_copy_address(entry.gateway, &route.gateway))
					!= B_OK)
				return status;

			InterfaceAddress* address
				= interface->FirstForFamily(domain->family);

			route.mtu = entry.mtu;
			route.flags = entry.flags;
			route.interface_address = address;

			if (option == SIOCADDRT)
				status = add_route(domain, &route);
			else
				status = remove_route(domain, &route);

			if (address != NULL)
				address->ReleaseReference();
			return status;
		}
	}
	return B_BAD_VALUE;
}
Example #2
0
/*!	Dumps a list of all interfaces into the supplied userland buffer.
	If the interfaces don't fit into the buffer, an error (\c ENOBUFS) is
	returned.
*/
status_t
list_interfaces(int family, void* _buffer, size_t* bufferSize)
{
	RecursiveLocker locker(sLock);

	UserBuffer buffer(_buffer, *bufferSize);

	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
	while (Interface* interface = iterator.Next()) {
		// Copy name
		buffer.Push(interface->name, IF_NAMESIZE);

		// Copy address
		InterfaceAddress* address = interface->FirstForFamily(family);
		size_t length = 0;

		if (address != NULL && address->local != NULL) {
			// Actual address
			buffer.Push(address->local, length = address->local->sa_len);
		} else {
			// Empty address
			sockaddr empty;
			empty.sa_len = 2;
			empty.sa_family = AF_UNSPEC;
			buffer.Push(&empty, length = empty.sa_len);
		}

		if (address != NULL)
			address->ReleaseReference();

		if (IF_NAMESIZE + length < sizeof(ifreq)) {
			// Make sure at least sizeof(ifreq) bytes are written for each
			// interface for compatibility with other platforms
			buffer.Pad(sizeof(ifreq) - IF_NAMESIZE - length);
		}

		if (buffer.Status() != B_OK)
			return buffer.Status();
	}

	*bufferSize = buffer.BytesConsumed();
	return B_OK;
}
Example #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;
}
Example #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;
}