* 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
This commit is contained in:
Axel Dörfler 2010-08-02 21:21:16 +00:00
parent 67678a989e
commit cd08b9f7bc
4 changed files with 222 additions and 58 deletions

View File

@ -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 static status_t
datalink_send_datagram(net_protocol* protocol, net_domain* domain, datalink_send_datagram(net_protocol* protocol, net_domain* domain,
net_buffer* buffer) net_buffer* buffer)

View File

@ -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* InterfaceAddress*
get_interface_address(const sockaddr* local) get_interface_address(const sockaddr* local)
{ {
@ -1220,7 +1254,7 @@ get_interface_address(const sockaddr* local)
InterfaceAddress* InterfaceAddress*
get_interface_address_for_destination(net_domain* domain, get_interface_address_for_destination(net_domain* domain,
const struct sockaddr* destination) const sockaddr* destination)
{ {
MutexLocker locker(sLock); 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* InterfaceAddress*
get_interface_address_for_link(net_domain* domain, get_interface_address_for_link(net_domain* domain, const sockaddr* address,
const struct sockaddr* _linkAddress, bool unconfiguredOnly) bool unconfiguredOnly)
{ {
sockaddr_dl& linkAddress = *(sockaddr_dl*)_linkAddress; sockaddr_dl& linkAddress = *(sockaddr_dl*)address;
MutexLocker locker(sLock); MutexLocker locker(sLock);
InterfaceList::Iterator iterator = sInterfaces.GetIterator(); InterfaceList::Iterator iterator = sInterfaces.GetIterator();
while (Interface* interface = iterator.Next()) { 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 if (linkAddress.sdl_alen == interface->device->address.length
&& memcmp(LLADDR(&linkAddress), interface->device->address.data, && memcmp(LLADDR(&linkAddress), interface->device->address.data,
linkAddress.sdl_alen) == 0) { linkAddress.sdl_alen) == 0) {

View File

@ -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, uint32 index);
Interface* get_interface(net_domain* domain, const char* name); Interface* get_interface(net_domain* domain, const char* name);
Interface* get_interface_for_device(net_domain* domain, uint32 index); 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(const struct sockaddr* address);
InterfaceAddress* get_interface_address_for_destination(net_domain* domain, 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, InterfaceAddress* get_interface_address_for_link(net_domain* domain,
const struct sockaddr* linkAddress, bool unconfiguredOnly); const sockaddr* linkAddress, bool unconfiguredOnly);
uint32 count_interfaces(); uint32 count_interfaces();
status_t list_interfaces(int family, void* buffer, size_t* _bufferSize); status_t list_interfaces(int family, void* buffer, size_t* _bufferSize);

View File

@ -12,6 +12,7 @@
#include "link.h" #include "link.h"
#include <net/if_dl.h>
#include <net/if_types.h> #include <net/if_types.h>
#include <new> #include <new>
#include <stdlib.h> #include <stdlib.h>
@ -28,6 +29,7 @@
#include "device_interfaces.h" #include "device_interfaces.h"
#include "domains.h" #include "domains.h"
#include "interfaces.h"
#include "stack_private.h" #include "stack_private.h"
#include "utility.h" #include "utility.h"
@ -48,6 +50,13 @@ public:
status_t StartMonitoring(const char* deviceName); status_t StartMonitoring(const char* deviceName);
status_t StopMonitoring(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: protected:
status_t SocketStatus(bool peek) const; status_t SocketStatus(bool peek) const;
@ -58,10 +67,14 @@ private:
net_buffer* buffer); net_buffer* buffer);
static void _MonitorEvent(net_device_monitor* monitor, static void _MonitorEvent(net_device_monitor* monitor,
int32 event); int32 event);
static status_t _ReceiveData(void* cookie, net_device* device,
net_buffer* buffer);
private: private:
net_device_monitor fMonitor; net_device_monitor fMonitor;
net_device_interface* fMonitoredDevice; net_device_interface* fMonitoredDevice;
net_device_interface* fBoundToDevice;
uint32 fBoundType;
}; };
@ -69,28 +82,31 @@ struct net_domain* sDomain;
LinkProtocol::LinkProtocol(net_socket* socket) LinkProtocol::LinkProtocol(net_socket* socket)
: LocalDatagramSocket("packet capture", socket) :
LocalDatagramSocket("packet capture", socket),
fMonitoredDevice(NULL),
fBoundToDevice(NULL)
{ {
fMonitor.cookie = this; fMonitor.cookie = this;
fMonitor.receive = _MonitorData; fMonitor.receive = _MonitorData;
fMonitor.event = _MonitorEvent; fMonitor.event = _MonitorEvent;
fMonitoredDevice = NULL;
} }
LinkProtocol::~LinkProtocol() LinkProtocol::~LinkProtocol()
{ {
if (fMonitoredDevice) { if (fMonitoredDevice != NULL) {
unregister_device_monitor(fMonitoredDevice->device, &fMonitor); unregister_device_monitor(fMonitoredDevice->device, &fMonitor);
put_device_interface(fMonitoredDevice); put_device_interface(fMonitoredDevice);
} } else
Unbind();
} }
status_t status_t
LinkProtocol::StartMonitoring(const char* deviceName) LinkProtocol::StartMonitoring(const char* deviceName)
{ {
MutexLocker _(fLock); MutexLocker locker(fLock);
if (fMonitoredDevice != NULL) if (fMonitoredDevice != NULL)
return B_BUSY; return B_BUSY;
@ -113,7 +129,7 @@ LinkProtocol::StartMonitoring(const char* deviceName)
status_t status_t
LinkProtocol::StopMonitoring(const char* deviceName) LinkProtocol::StopMonitoring(const char* deviceName)
{ {
MutexLocker _(fLock); MutexLocker locker(fLock);
if (fMonitoredDevice == NULL if (fMonitoredDevice == NULL
|| strcmp(fMonitoredDevice->device->name, deviceName) != 0) || 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 status_t
LinkProtocol::SocketStatus(bool peek) const 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) LinkProtocol::_MonitorData(net_device_monitor* monitor, net_buffer* packet)
{ {
return ((LinkProtocol*)monitor->cookie)->SocketEnqueue(packet); return ((LinkProtocol*)monitor->cookie)->SocketEnqueue(packet);
} }
void /*static*/ void
LinkProtocol::_MonitorEvent(net_device_monitor* monitor, int32 event) LinkProtocol::_MonitorEvent(net_device_monitor* monitor, int32 event)
{ {
LinkProtocol* protocol = (LinkProtocol*)monitor->cookie; 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 - // #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) link_init_protocol(net_socket* socket)
{ {
LinkProtocol* protocol = new (std::nothrow) LinkProtocol(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) link_uninit_protocol(net_protocol* protocol)
{ {
delete (LinkProtocol*)protocol; delete (LinkProtocol*)protocol;
@ -211,42 +311,42 @@ link_uninit_protocol(net_protocol* protocol)
} }
status_t static status_t
link_open(net_protocol* protocol) link_open(net_protocol* protocol)
{ {
return B_OK; return B_OK;
} }
status_t static status_t
link_close(net_protocol* protocol) link_close(net_protocol* protocol)
{ {
return B_OK; return B_OK;
} }
status_t static status_t
link_free(net_protocol* protocol) link_free(net_protocol* protocol)
{ {
return B_OK; return B_OK;
} }
status_t static status_t
link_connect(net_protocol* protocol, const struct sockaddr* address) link_connect(net_protocol* protocol, const struct sockaddr* address)
{ {
return B_NOT_SUPPORTED; return B_NOT_SUPPORTED;
} }
status_t static status_t
link_accept(net_protocol* protocol, struct net_socket** _acceptedSocket) link_accept(net_protocol* protocol, struct net_socket** _acceptedSocket)
{ {
return B_NOT_SUPPORTED; return B_NOT_SUPPORTED;
} }
status_t static status_t
link_control(net_protocol* _protocol, int level, int option, void* value, link_control(net_protocol* _protocol, int level, int option, void* value,
size_t* _length) 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, link_getsockopt(net_protocol* protocol, int level, int option, void* value,
int* length) 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, link_setsockopt(net_protocol* protocol, int level, int option,
const void* value, int length) const void* value, int length)
{ {
@ -402,62 +502,69 @@ link_setsockopt(net_protocol* protocol, int level, int option,
} }
status_t static status_t
link_bind(net_protocol* protocol, const struct sockaddr* address) link_bind(net_protocol* _protocol, const struct sockaddr* address)
{ {
// TODO: bind to a specific interface and ethernet type LinkProtocol* protocol = (LinkProtocol*)_protocol;
return B_ERROR; return protocol->Bind(address);
} }
status_t static status_t
link_unbind(net_protocol* protocol, struct sockaddr* address) 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) link_listen(net_protocol* protocol, int count)
{ {
return B_NOT_SUPPORTED; return B_NOT_SUPPORTED;
} }
status_t static status_t
link_shutdown(net_protocol* protocol, int direction) link_shutdown(net_protocol* protocol, int direction)
{ {
return B_NOT_SUPPORTED; return B_NOT_SUPPORTED;
} }
status_t static status_t
link_send_data(net_protocol* protocol, net_buffer* buffer) link_send_data(net_protocol* protocol, net_buffer* buffer)
{ {
// Only root is allowed to send link protocol packets return gNetDatalinkModule.send_datagram(protocol, sDomain, buffer);
if (geteuid() != 0)
return B_NOT_ALLOWED;
return B_NOT_SUPPORTED;
} }
status_t static status_t
link_send_routed_data(net_protocol* protocol, struct net_route* route, link_send_routed_data(net_protocol* protocol, struct net_route* route,
net_buffer* buffer) 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 static ssize_t
link_send_avail(net_protocol* protocol) 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, link_read_data(net_protocol* protocol, size_t numBytes, uint32 flags,
net_buffer** _buffer) 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) link_read_avail(net_protocol* protocol)
{ {
return ((LinkProtocol*)protocol)->AvailableData(); return ((LinkProtocol*)protocol)->AvailableData();
} }
struct net_domain* static struct net_domain*
link_get_domain(net_protocol* protocol) link_get_domain(net_protocol* protocol)
{ {
return sDomain; return sDomain;
} }
size_t static size_t
link_get_mtu(net_protocol* protocol, const struct sockaddr* address) link_get_mtu(net_protocol* _protocol, const struct sockaddr* address)
{ {
// TODO: for now LinkProtocol* protocol = (LinkProtocol*)_protocol;
return 0; return protocol->MTU();
} }
status_t static status_t
link_receive_data(net_buffer* buffer) link_receive_data(net_buffer* buffer)
{ {
// We never receive any data this way
return B_ERROR; return B_ERROR;
} }
status_t static status_t
link_error(uint32 code, net_buffer* data) link_error_received(uint32 code, net_buffer* data)
{ {
// We don't do any error processing
return B_ERROR; return B_ERROR;
} }
status_t static status_t
link_error_reply(net_protocol* protocol, net_buffer* causedError, uint32 code, link_error_reply(net_protocol* protocol, net_buffer* causedError, uint32 code,
void* errorData) void* errorData)
{ {
// We don't do any error processing
return B_ERROR; return B_ERROR;
} }
@ -535,6 +645,7 @@ link_init()
register_domain_protocols(AF_LINK, SOCK_DGRAM, 0, "network/stack/link/v1", register_domain_protocols(AF_LINK, SOCK_DGRAM, 0, "network/stack/link/v1",
NULL); NULL);
// TODO: this should actually be registered for all types (besides local)
register_domain_datalink_protocols(AF_LINK, IFT_ETHER, register_domain_datalink_protocols(AF_LINK, IFT_ETHER,
"network/datalink_protocols/ethernet_frame/v1", "network/datalink_protocols/ethernet_frame/v1",
NULL); NULL);
@ -571,7 +682,12 @@ net_protocol_module_info gLinkModule = {
link_get_domain, link_get_domain,
link_get_mtu, link_get_mtu,
link_receive_data, link_receive_data,
NULL, NULL, // deliver_data
link_error, link_error_received,
link_error_reply, 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()
}; };