* 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
datalink_send_datagram(net_protocol* protocol, net_domain* domain,
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*
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) {

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, 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);

View File

@ -12,6 +12,7 @@
#include "link.h"
#include <net/if_dl.h>
#include <net/if_types.h>
#include <new>
#include <stdlib.h>
@ -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()
};