From cd08b9f7bcc33dc652bffd344aeb9155540bebae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 2 Aug 2010 21:21:16 +0000 Subject: [PATCH] * Work in progress of extending the AF_LINK protocol to be able to send and receive raw packets (only without the ethernet framing). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37853 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/network/stack/datalink.cpp | 4 + .../kernel/network/stack/interfaces.cpp | 51 +++- src/add-ons/kernel/network/stack/interfaces.h | 5 +- src/add-ons/kernel/network/stack/link.cpp | 220 +++++++++++++----- 4 files changed, 222 insertions(+), 58 deletions(-) diff --git a/src/add-ons/kernel/network/stack/datalink.cpp b/src/add-ons/kernel/network/stack/datalink.cpp index 01e62cb1f3..a0b8d4986b 100644 --- a/src/add-ons/kernel/network/stack/datalink.cpp +++ b/src/add-ons/kernel/network/stack/datalink.cpp @@ -374,6 +374,10 @@ datalink_send_data(struct net_route* route, net_buffer* buffer) } +/*! Finds a route for the given \a buffer in the given \a domain, and calls + net_protocol_info::send_routed_data() on either the \a protocol (if + non-NULL), or the domain. +*/ static status_t datalink_send_datagram(net_protocol* protocol, net_domain* domain, net_buffer* buffer) diff --git a/src/add-ons/kernel/network/stack/interfaces.cpp b/src/add-ons/kernel/network/stack/interfaces.cpp index def3127cce..4f8b0a74b6 100644 --- a/src/add-ons/kernel/network/stack/interfaces.cpp +++ b/src/add-ons/kernel/network/stack/interfaces.cpp @@ -1201,6 +1201,40 @@ get_interface_for_device(net_domain* domain, uint32 index) } +/*! Returns a reference to an Interface that matches the given \a linkAddress. + The link address is checked against its hardware address, or its interface + name, or finally the interface index. +*/ +Interface* +get_interface_for_link(net_domain* domain, const sockaddr* _linkAddress) +{ + sockaddr_dl& linkAddress = *(sockaddr_dl*)_linkAddress; + + MutexLocker locker(sLock); + + InterfaceList::Iterator iterator = sInterfaces.GetIterator(); + while (Interface* interface = iterator.Next()) { + // Test if the hardware address matches, or if the given interface + // matches, or if at least the index matches. + if ((linkAddress.sdl_alen == interface->device->address.length + && memcmp(LLADDR(&linkAddress), interface->device->address.data, + linkAddress.sdl_alen) == 0) + || (linkAddress.sdl_nlen > 0 + && !strcmp(interface->name, (const char*)linkAddress.sdl_data)) + || (linkAddress.sdl_nlen == 0 && linkAddress.sdl_alen == 0 + && linkAddress.sdl_index == interface->index)) { + if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK) + return NULL; + + interface->AcquireReference(); + return interface; + } + } + + return NULL; +} + + InterfaceAddress* get_interface_address(const sockaddr* local) { @@ -1220,7 +1254,7 @@ get_interface_address(const sockaddr* local) InterfaceAddress* get_interface_address_for_destination(net_domain* domain, - const struct sockaddr* destination) + const sockaddr* destination) { MutexLocker locker(sLock); @@ -1236,16 +1270,25 @@ get_interface_address_for_destination(net_domain* domain, } +/*! Returns a reference to an InterfaceAddress of the specified \a domain that + belongs to the interface identified via \a linkAddress. Only the hardware + address is matched. + + If \a unconfiguredOnly is set, the interface address must not yet be + configured, or must currently be in the process of being configured. +*/ InterfaceAddress* -get_interface_address_for_link(net_domain* domain, - const struct sockaddr* _linkAddress, bool unconfiguredOnly) +get_interface_address_for_link(net_domain* domain, const sockaddr* address, + bool unconfiguredOnly) { - sockaddr_dl& linkAddress = *(sockaddr_dl*)_linkAddress; + sockaddr_dl& linkAddress = *(sockaddr_dl*)address; MutexLocker locker(sLock); InterfaceList::Iterator iterator = sInterfaces.GetIterator(); while (Interface* interface = iterator.Next()) { + // Test if the hardware address matches, or if the given interface + // matches, or if at least the index matches. if (linkAddress.sdl_alen == interface->device->address.length && memcmp(LLADDR(&linkAddress), interface->device->address.data, linkAddress.sdl_alen) == 0) { diff --git a/src/add-ons/kernel/network/stack/interfaces.h b/src/add-ons/kernel/network/stack/interfaces.h index 8105c911f0..078f8bd636 100644 --- a/src/add-ons/kernel/network/stack/interfaces.h +++ b/src/add-ons/kernel/network/stack/interfaces.h @@ -176,11 +176,12 @@ status_t update_interface_address(InterfaceAddress* interfaceAddress, Interface* get_interface(net_domain* domain, uint32 index); Interface* get_interface(net_domain* domain, const char* name); Interface* get_interface_for_device(net_domain* domain, uint32 index); +Interface* get_interface_for_link(net_domain* domain, const sockaddr* address); InterfaceAddress* get_interface_address(const struct sockaddr* address); InterfaceAddress* get_interface_address_for_destination(net_domain* domain, - const struct sockaddr* destination); + const sockaddr* destination); InterfaceAddress* get_interface_address_for_link(net_domain* domain, - const struct sockaddr* linkAddress, bool unconfiguredOnly); + const sockaddr* linkAddress, bool unconfiguredOnly); uint32 count_interfaces(); status_t list_interfaces(int family, void* buffer, size_t* _bufferSize); diff --git a/src/add-ons/kernel/network/stack/link.cpp b/src/add-ons/kernel/network/stack/link.cpp index fd803f076d..0294ccac21 100644 --- a/src/add-ons/kernel/network/stack/link.cpp +++ b/src/add-ons/kernel/network/stack/link.cpp @@ -12,6 +12,7 @@ #include "link.h" +#include #include #include #include @@ -28,6 +29,7 @@ #include "device_interfaces.h" #include "domains.h" +#include "interfaces.h" #include "stack_private.h" #include "utility.h" @@ -48,6 +50,13 @@ public: status_t StartMonitoring(const char* deviceName); status_t StopMonitoring(const char* deviceName); + status_t Bind(const sockaddr* address); + status_t Unbind(); + bool IsBound() const + { return fBoundToDevice != NULL; } + + size_t MTU(); + protected: status_t SocketStatus(bool peek) const; @@ -58,10 +67,14 @@ private: net_buffer* buffer); static void _MonitorEvent(net_device_monitor* monitor, int32 event); + static status_t _ReceiveData(void* cookie, net_device* device, + net_buffer* buffer); private: net_device_monitor fMonitor; net_device_interface* fMonitoredDevice; + net_device_interface* fBoundToDevice; + uint32 fBoundType; }; @@ -69,28 +82,31 @@ struct net_domain* sDomain; LinkProtocol::LinkProtocol(net_socket* socket) - : LocalDatagramSocket("packet capture", socket) + : + LocalDatagramSocket("packet capture", socket), + fMonitoredDevice(NULL), + fBoundToDevice(NULL) { fMonitor.cookie = this; fMonitor.receive = _MonitorData; fMonitor.event = _MonitorEvent; - fMonitoredDevice = NULL; } LinkProtocol::~LinkProtocol() { - if (fMonitoredDevice) { + if (fMonitoredDevice != NULL) { unregister_device_monitor(fMonitoredDevice->device, &fMonitor); put_device_interface(fMonitoredDevice); - } + } else + Unbind(); } status_t LinkProtocol::StartMonitoring(const char* deviceName) { - MutexLocker _(fLock); + MutexLocker locker(fLock); if (fMonitoredDevice != NULL) return B_BUSY; @@ -113,7 +129,7 @@ LinkProtocol::StartMonitoring(const char* deviceName) status_t LinkProtocol::StopMonitoring(const char* deviceName) { - MutexLocker _(fLock); + MutexLocker locker(fLock); if (fMonitoredDevice == NULL || strcmp(fMonitoredDevice->device->name, deviceName) != 0) @@ -123,6 +139,81 @@ LinkProtocol::StopMonitoring(const char* deviceName) } +status_t +LinkProtocol::Bind(const sockaddr* address) +{ + // Only root is allowed to bind to a link layer interface + if (address == NULL || geteuid() != 0) + return B_NOT_ALLOWED; + + MutexLocker locker(fLock); + + if (fMonitoredDevice != NULL) + return B_BUSY; + + Interface* interface = get_interface_for_link(sDomain, address); + if (interface == NULL) + return B_BAD_VALUE; + + net_device_interface* boundTo + = acquire_device_interface(interface->DeviceInterface()); + + interface->ReleaseReference(); + + if (boundTo == NULL) + return B_BAD_VALUE; + + sockaddr_dl& linkAddress = *(sockaddr_dl*)address; + + if (linkAddress.sdl_type != 0) { + fBoundType = ((uint32)linkAddress.sdl_type << 16) + | linkAddress.sdl_e_type; + // Bind to the type requested - this is needed in order to + // receive any buffers + // TODO: this could be easily changed by introducing catch all or rule + // based handlers! + status_t status = register_device_handler(boundTo->device, fBoundType, + &LinkProtocol::_ReceiveData, this); + if (status != B_OK) + return status; + } else + fBoundType = 0; + + fBoundToDevice = boundTo; + socket->bound_to_device = boundTo->device->index; + + return B_OK; +} + + +status_t +LinkProtocol::Unbind() +{ + MutexLocker locker(fLock); + + if (fBoundToDevice == NULL) + return B_BAD_VALUE; + + unregister_device_handler(fBoundToDevice->device, fBoundType); + put_device_interface(fBoundToDevice); + + socket->bound_to_device = 0; + return B_OK; +} + + +size_t +LinkProtocol::MTU() +{ + MutexLocker locker(fLock); + + if (!IsBound()) + return 0; + + return fBoundToDevice->device->mtu; +} + + status_t LinkProtocol::SocketStatus(bool peek) const { @@ -148,14 +239,14 @@ LinkProtocol::_Unregister() } -status_t +/*static*/ status_t LinkProtocol::_MonitorData(net_device_monitor* monitor, net_buffer* packet) { return ((LinkProtocol*)monitor->cookie)->SocketEnqueue(packet); } -void +/*static*/ void LinkProtocol::_MonitorEvent(net_device_monitor* monitor, int32 event) { LinkProtocol* protocol = (LinkProtocol*)monitor->cookie; @@ -172,6 +263,15 @@ LinkProtocol::_MonitorEvent(net_device_monitor* monitor, int32 event) } +/*static*/ status_t +LinkProtocol::_ReceiveData(void* cookie, net_device* device, net_buffer* buffer) +{ + LinkProtocol* protocol = (LinkProtocol*)cookie; + + return protocol->Enqueue(buffer); +} + + // #pragma mark - @@ -187,10 +287,10 @@ user_request_get_device_interface(void* value, struct ifreq& request, } -// #pragma mark - +// #pragma mark - net_protocol module -net_protocol* +static net_protocol* link_init_protocol(net_socket* socket) { LinkProtocol* protocol = new (std::nothrow) LinkProtocol(socket); @@ -203,7 +303,7 @@ link_init_protocol(net_socket* socket) } -status_t +static status_t link_uninit_protocol(net_protocol* protocol) { delete (LinkProtocol*)protocol; @@ -211,42 +311,42 @@ link_uninit_protocol(net_protocol* protocol) } -status_t +static status_t link_open(net_protocol* protocol) { return B_OK; } -status_t +static status_t link_close(net_protocol* protocol) { return B_OK; } -status_t +static status_t link_free(net_protocol* protocol) { return B_OK; } -status_t +static status_t link_connect(net_protocol* protocol, const struct sockaddr* address) { return B_NOT_SUPPORTED; } -status_t +static status_t link_accept(net_protocol* protocol, struct net_socket** _acceptedSocket) { return B_NOT_SUPPORTED; } -status_t +static status_t link_control(net_protocol* _protocol, int level, int option, void* value, size_t* _length) { @@ -374,7 +474,7 @@ link_control(net_protocol* _protocol, int level, int option, void* value, } -status_t +static status_t link_getsockopt(net_protocol* protocol, int level, int option, void* value, int* length) { @@ -388,7 +488,7 @@ link_getsockopt(net_protocol* protocol, int level, int option, void* value, } -status_t +static status_t link_setsockopt(net_protocol* protocol, int level, int option, const void* value, int length) { @@ -402,62 +502,69 @@ link_setsockopt(net_protocol* protocol, int level, int option, } -status_t -link_bind(net_protocol* protocol, const struct sockaddr* address) +static status_t +link_bind(net_protocol* _protocol, const struct sockaddr* address) { - // TODO: bind to a specific interface and ethernet type - return B_ERROR; + LinkProtocol* protocol = (LinkProtocol*)_protocol; + return protocol->Bind(address); } -status_t -link_unbind(net_protocol* protocol, struct sockaddr* address) +static status_t +link_unbind(net_protocol* _protocol, struct sockaddr* address) { - return B_ERROR; + LinkProtocol* protocol = (LinkProtocol*)_protocol; + return protocol->Unbind(); } -status_t +static status_t link_listen(net_protocol* protocol, int count) { return B_NOT_SUPPORTED; } -status_t +static status_t link_shutdown(net_protocol* protocol, int direction) { return B_NOT_SUPPORTED; } -status_t +static status_t link_send_data(net_protocol* protocol, net_buffer* buffer) { - // Only root is allowed to send link protocol packets - if (geteuid() != 0) - return B_NOT_ALLOWED; - - return B_NOT_SUPPORTED; + return gNetDatalinkModule.send_datagram(protocol, sDomain, buffer); } -status_t +static status_t link_send_routed_data(net_protocol* protocol, struct net_route* route, net_buffer* buffer) { - return B_NOT_SUPPORTED; + if (buffer->destination->sa_family != buffer->source->sa_family + || buffer->destination->sa_family != AF_LINK) + return B_BAD_VALUE; + + // The datalink layer will take care of the framing + + return gNetDatalinkModule.send_data(route, buffer); } -ssize_t -link_send_avail(net_protocol* protocol) +static ssize_t +link_send_avail(net_protocol* _protocol) { - return B_ERROR; + LinkProtocol* protocol = (LinkProtocol*)_protocol; + if (!protocol->IsBound()) + return B_ERROR; + + return protocol->socket->send.buffer_size; } -status_t +static status_t link_read_data(net_protocol* protocol, size_t numBytes, uint32 flags, net_buffer** _buffer) { @@ -465,46 +572,49 @@ link_read_data(net_protocol* protocol, size_t numBytes, uint32 flags, } -ssize_t +static ssize_t link_read_avail(net_protocol* protocol) { return ((LinkProtocol*)protocol)->AvailableData(); } -struct net_domain* +static struct net_domain* link_get_domain(net_protocol* protocol) { return sDomain; } -size_t -link_get_mtu(net_protocol* protocol, const struct sockaddr* address) +static size_t +link_get_mtu(net_protocol* _protocol, const struct sockaddr* address) { - // TODO: for now - return 0; + LinkProtocol* protocol = (LinkProtocol*)_protocol; + return protocol->MTU(); } -status_t +static status_t link_receive_data(net_buffer* buffer) { + // We never receive any data this way return B_ERROR; } -status_t -link_error(uint32 code, net_buffer* data) +static status_t +link_error_received(uint32 code, net_buffer* data) { + // We don't do any error processing return B_ERROR; } -status_t +static status_t link_error_reply(net_protocol* protocol, net_buffer* causedError, uint32 code, void* errorData) { + // We don't do any error processing return B_ERROR; } @@ -535,6 +645,7 @@ link_init() register_domain_protocols(AF_LINK, SOCK_DGRAM, 0, "network/stack/link/v1", NULL); + // TODO: this should actually be registered for all types (besides local) register_domain_datalink_protocols(AF_LINK, IFT_ETHER, "network/datalink_protocols/ethernet_frame/v1", NULL); @@ -571,7 +682,12 @@ net_protocol_module_info gLinkModule = { link_get_domain, link_get_mtu, link_receive_data, - NULL, - link_error, + NULL, // deliver_data + link_error_received, link_error_reply, + NULL, // add_ancillary_data() + NULL, // process_ancillary_data() + NULL, // process_ancillary_data_no_container() + NULL, // send_data_no_buffer() + NULL // read_data_no_buffer() };