L2CAP, without functionality, for the moment my playground in the netstack

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25768 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Oliver Ruiz Dorantes 2008-06-02 20:16:00 +00:00
parent 2ebec00b97
commit 3e24801283
5 changed files with 782 additions and 0 deletions

View File

@ -0,0 +1,21 @@
/*
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
*
* All rights reserved. Distributed under the terms of the MIT License.
*
*/
#ifndef _BTL2CAP_H_
#define _BTL2CAP_H_
#include <bluetooth/bluetooth.h>
struct sockaddr_l2cap {
uint8 l2cap_len; /* total length */
uint8 l2cap_family; /* address family */
uint16 l2cap_psm; /* PSM (Protocol/Service Multiplexor) */
bdaddr_t l2cap_bdaddr; /* address */
};
#endif

View File

@ -0,0 +1,26 @@
SubDir HAIKU_TOP src add-ons kernel network protocols l2cap ;
SetSubDirSupportedPlatformsBeOSCompatible ;
if $(TARGET_PLATFORM) != haiku {
UseHeaders [ FStandardOSHeaders ] : true ;
# Needed for <support/Errors.h> and maybe other stuff.
UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ;
# We need the public network headers also when not compiling for Haiku.
# Unfortunately we get more than we want, namely all POSIX headers.
}
UsePrivateHeaders kernel net bluetooth ;
KernelAddon l2cap :
l2cap.cpp
l2cap_address.cpp
;
# Installation
HaikuInstall install-networking : /boot/home/config/add-ons/kernel/haiku_network/protocols
: l2cap ;
Package haiku-networkingkit-cvs :
haiku :
boot home config add-ons kernel haiku_network protocols ;

View File

@ -0,0 +1,304 @@
#include <net_datalink.h>
#include <net_protocol.h>
#include <net_stack.h>
#include <NetBufferUtilities.h>
#include <KernelExport.h>
#include <util/list.h>
#include <netinet/in.h>
#include <new>
#include <stdlib.h>
#include <string.h>
#include <bluetooth/HCI/btHCI_acl.h>
#include <btDebug.h>
typedef NetBufferField<uint16, offsetof(hci_acl_header, alen)> ICMPChecksumField;
#define ICMP_TYPE_ECHO_REPLY 0
#define ICMP_TYPE_UNREACH 3
#define ICMP_TYPE_REDIRECT 5
#define ICMP_TYPE_ECHO_REQUEST 8
// type unreach codes
#define ICMP_CODE_UNREACH_NEED_FRAGMENT 4 // this is used for path MTU discovery
struct l2cap_protocol : net_protocol {
};
net_buffer_module_info *gBufferModule;
static net_stack_module_info *sStackModule;
net_protocol *
l2cap_init_protocol(net_socket *socket)
{
l2cap_protocol *protocol = new (std::nothrow) l2cap_protocol;
if (protocol == NULL)
return NULL;
return protocol;
}
status_t
l2cap_uninit_protocol(net_protocol *protocol)
{
delete protocol;
return B_OK;
}
status_t
l2cap_open(net_protocol *protocol)
{
return B_OK;
}
status_t
l2cap_close(net_protocol *protocol)
{
return B_OK;
}
status_t
l2cap_free(net_protocol *protocol)
{
return B_OK;
}
status_t
l2cap_connect(net_protocol *protocol, const struct sockaddr *address)
{
return B_ERROR;
}
status_t
l2cap_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
{
return EOPNOTSUPP;
}
status_t
l2cap_control(net_protocol *protocol, int level, int option, void *value,
size_t *_length)
{
return protocol->next->module->control(protocol->next, level, option,
value, _length);
}
status_t
l2cap_getsockopt(net_protocol *protocol, int level, int option,
void *value, int *length)
{
return protocol->next->module->getsockopt(protocol->next, level, option,
value, length);
}
status_t
l2cap_setsockopt(net_protocol *protocol, int level, int option,
const void *value, int length)
{
return protocol->next->module->setsockopt(protocol->next, level, option,
value, length);
}
status_t
l2cap_bind(net_protocol *protocol, const struct sockaddr *address)
{
return B_ERROR;
}
status_t
l2cap_unbind(net_protocol *protocol, struct sockaddr *address)
{
return B_ERROR;
}
status_t
l2cap_listen(net_protocol *protocol, int count)
{
return EOPNOTSUPP;
}
status_t
l2cap_shutdown(net_protocol *protocol, int direction)
{
return EOPNOTSUPP;
}
status_t
l2cap_send_data(net_protocol *protocol, net_buffer *buffer)
{
return protocol->next->module->send_data(protocol->next, buffer);
}
status_t
l2cap_send_routed_data(net_protocol *protocol, struct net_route *route,
net_buffer *buffer)
{
return protocol->next->module->send_routed_data(protocol->next, route, buffer);
}
ssize_t
l2cap_send_avail(net_protocol *protocol)
{
return B_ERROR;
}
status_t
l2cap_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
net_buffer **_buffer)
{
return B_ERROR;
}
ssize_t
l2cap_read_avail(net_protocol *protocol)
{
return B_ERROR;
}
struct net_domain *
l2cap_get_domain(net_protocol *protocol)
{
return protocol->next->module->get_domain(protocol->next);
}
size_t
l2cap_get_mtu(net_protocol *protocol, const struct sockaddr *address)
{
return protocol->next->module->get_mtu(protocol->next, address);
}
status_t
l2cap_receive_data(net_buffer *buffer)
{
debugf("ICMP received some data, buffer length %lu\n", buffer->size);
NetBufferHeaderReader<hci_acl_header> bufferHeader(buffer);
if (bufferHeader.Status() < B_OK)
return bufferHeader.Status();
hci_acl_header &header = bufferHeader.Data();
debugf(" got type %u, code %u, checksum %u\n", header.type, header.code, ntohs(header.checksum));
debugf(" computed checksum: %ld\n", gBufferModule->checksum(buffer, 0, buffer->size, true));
if (gBufferModule->checksum(buffer, 0, buffer->size, true) != 0)
return B_BAD_DATA;
gBufferModule->free(buffer);
return B_OK;
}
status_t
l2cap_error(uint32 code, net_buffer *data)
{
return B_ERROR;
}
status_t
l2cap_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
void *errorData)
{
return B_ERROR;
}
// #pragma mark -
static status_t
l2cap_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
{
sStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_ICMP,
"network/protocols/l2cap/v1",
NULL);
sStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_ICMP,
"network/protocols/l2cap/v1");
return B_OK;
}
case B_MODULE_UNINIT:
return B_OK;
default:
return B_ERROR;
}
}
net_protocol_module_info sL2CAPModule = {
{
"network/protocols/l2cap/v1",
0,
l2cap_std_ops
},
NET_PROTOCOL_ATOMIC_MESSAGES,
l2cap_init_protocol,
l2cap_uninit_protocol,
l2cap_open,
l2cap_close,
l2cap_free,
l2cap_connect,
l2cap_accept,
l2cap_control,
l2cap_getsockopt,
l2cap_setsockopt,
l2cap_bind,
l2cap_unbind,
l2cap_listen,
l2cap_shutdown,
l2cap_send_data,
l2cap_send_routed_data,
l2cap_send_avail,
l2cap_read_data,
l2cap_read_avail,
l2cap_get_domain,
l2cap_get_mtu,
l2cap_receive_data,
NULL,
l2cap_error,
l2cap_error_reply,
};
module_dependency module_dependencies[] = {
{NET_STACK_MODULE_NAME, (module_info **)&sStackModule},
{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
{}
};
module_info *modules[] = {
(module_info *)&sL2CAPModule,
NULL
};

View File

@ -0,0 +1,416 @@
/*
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Oliver Ruiz Dorantes, oliver-ruiz.dorantes_at_gmail.com
*/
#include <net_datalink.h>
#include <ByteOrder.h>
#include <KernelExport.h>
#include <NetUtilities.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <bluetooth/L2CAP/btL2CAP.h>
#define L2CAP_CHECKSUM(address) (address.b[0]+\
address.b[1]+\
address.b[2]+\
address.b[3]+\
address.b[4]+\
address.b[5])
/*!
Routing utility function: copies address \a from into a new address
that is put into \a to.
If \a replaceWithZeros is set \a from will be replaced by an empty
address.
If a \a mask is given it is applied to \a from (such that \a to is the
result of \a from & \a mask).
\return B_OK if the address could be copied
\return B_NO_MEMORY if the new address could not be allocated
\return B_MISMATCHED_VALUES if \a address does not match family AF_INET
*/
static status_t
l2cap_copy_address(const sockaddr *from, sockaddr **to,
bool replaceWithZeros = false, const sockaddr *mask = NULL)
{
if (replaceWithZeros) {
*to = (sockaddr *)malloc(sizeof(sockaddr_in));
if (*to == NULL)
return B_NO_MEMORY;
memset(*to, 0, sizeof(sockaddr_in));
(*to)->sa_family = AF_INET;
(*to)->sa_len = sizeof(sockaddr_in);
} else {
if (from == NULL)
return B_OK;
if (from->sa_family != AF_INET)
return B_MISMATCHED_VALUES;
*to = (sockaddr *)malloc(sizeof(sockaddr_in));
if (*to == NULL)
return B_NO_MEMORY;
memcpy(*to, from, sizeof(sockaddr_l2cap));
}
return B_OK;
}
/*!
Routing utility function: applies \a mask to given \a address and puts
the resulting address into \a result.
\return B_OK if the mask has been applied
\return B_BAD_VALUE if \a address or \a mask is NULL
*/
static status_t
l2cap_mask_address(const sockaddr *address, const sockaddr *mask, sockaddr *result)
{
if (address == NULL || result == NULL)
return B_BAD_VALUE;
return B_OK;
}
/*!
Checks if the given \a address is the empty address. By default, the port
is checked, too, but you can avoid that by passing \a checkPort = false.
\return true if \a address is NULL, uninitialized or the empty address,
false if not
*/
static bool
l2cap_is_empty_address(const sockaddr *address, bool checkPort)
{
if (address == NULL || address->sa_len == 0)
return true;
return ((bacmp(&((sockaddr_l2cap *)address)->l2cap_bdaddr, BDADDR_NULL)==0)
&& (!checkPort || ((sockaddr_l2cap *)address)->l2cap_psm == 0) );
}
/*!
Compares the IP-addresses of the two given address structures \a a and \a b.
\return true if IP-addresses of \a a and \a b are equal, false if not
*/
static bool
l2cap_equal_addresses(const sockaddr *a, const sockaddr *b)
{
if (a == NULL && b == NULL)
return true;
if (a != NULL && b == NULL)
return l2cap_is_empty_address(a, false);
if (a == NULL && b != NULL)
return l2cap_is_empty_address(b, false);
return (bacmp(&((sockaddr_l2cap*)a)->l2cap_bdaddr,
&((sockaddr_l2cap*)b)->l2cap_bdaddr)==0);
}
/*!
Compares the ports of the two given address structures \a a and \a b.
\return true if ports of \a a and \a b are equal, false if not
*/
static bool
l2cap_equal_ports(const sockaddr *a, const sockaddr *b)
{
uint16 portA = a ? ((sockaddr_l2cap *)a)->l2cap_psm : 0;
uint16 portB = b ? ((sockaddr_l2cap *)b)->l2cap_psm : 0;
return portA == portB;
}
/*!
Compares the IP-addresses and ports of the two given address structures
\a a and \a b.
\return true if IP-addresses and ports of \a a and \a b are equal, false if not
*/
static bool
l2cap_equal_addresses_and_ports(const sockaddr *a, const sockaddr *b)
{
if (a == NULL && b == NULL)
return true;
if (a != NULL && b == NULL)
return l2cap_is_empty_address(a, true);
if (a == NULL && b != NULL)
return l2cap_is_empty_address(b, true);
return (bacmp(&((sockaddr_l2cap*)a)->l2cap_bdaddr,&((sockaddr_l2cap *)b)->l2cap_bdaddr)==0)
&& ((sockaddr_l2cap *)a)->l2cap_psm == ((sockaddr_l2cap *)b)->l2cap_psm;
}
/*!
Applies the given \a mask two \a a and \a b and then checks whether
the masked addresses match.
\return true if \a a matches \a b after masking both, false if not
*/
static bool
l2cap_equal_masked_addresses(const sockaddr *a, const sockaddr *b,
const sockaddr *mask)
{
if (a == NULL && b == NULL)
return true;
return false;
}
/*!
Routing utility function: determines the least significant bit that is set
in the given \a mask.
\return the number of the first bit that is set (0-32, where 32 means
that there's no bit set in the mask).
*/
static int32
l2cap_first_mask_bit(const sockaddr *_mask)
{
if (_mask == NULL)
return 0;
return 0;
}
/*!
Routing utility function: checks the given \a mask for correctness (which
means that (starting with LSB) consists zero or more unset bits, followed
by bits that are all set).
\return true if \a mask is ok, false if not
*/
static bool
l2cap_check_mask(const sockaddr *_mask)
{
return true;
}
/*!
Creates a buffer for the given \a address and prints the address into
it (hexadecimal representation in host byte order or '<none>').
If \a printPort is set, the port is printed, too.
\return B_OK if the address could be printed, \a buffer will point to
the resulting string
\return B_BAD_VALUE if no buffer has been given
\return B_NO_MEMORY if the buffer could not be allocated
*/
static status_t
l2cap_print_address_buffer(const sockaddr *_address, char *buffer,
size_t bufferSize, bool printPort)
{
const sockaddr_l2cap *address = (const sockaddr_l2cap *)_address;
if (buffer == NULL)
return B_BAD_VALUE;
if (address == NULL)
strlcpy(buffer, "<none>", bufferSize);
else {
bdaddr_t addr = address->l2cap_bdaddr;
if (printPort) {
snprintf(buffer, bufferSize, "%2X:%2X:%2X:%2X:%2X:%2X|%u", addr.b[0],
addr.b[1],addr.b[2],addr.b[3],addr.b[4],addr.b[5],address->l2cap_psm);
}
else {
snprintf(buffer, bufferSize, "%2X:%2X:%2X:%2X:%2X:%2X",addr.b[0],
addr.b[1],addr.b[2],addr.b[3],addr.b[4],addr.b[5]);
}
}
return B_OK;
}
static status_t
l2cap_print_address(const sockaddr *_address, char **_buffer, bool printPort)
{
if (_buffer == NULL)
return B_BAD_VALUE;
char tmp[32];
l2cap_print_address_buffer(_address, tmp, sizeof(tmp), printPort);
*_buffer = strdup(tmp);
if (*_buffer == NULL)
return B_NO_MEMORY;
return B_OK;
}
/*!
Determines the port of the given \a address.
\return uint16 representing the port-nr
*/
static uint16
l2cap_get_port(const sockaddr *address)
{
if (address == NULL)
return 0;
return ((sockaddr_l2cap *)address)->l2cap_psm;
}
/*!
Sets the port of the given \a address to \a port.
\return B_OK if the port has been set
\return B_BAD_VALUE if \a address is NULL
*/
static status_t
l2cap_set_port(sockaddr *address, uint16 port)
{
if (address == NULL)
return B_BAD_VALUE;
((sockaddr_l2cap *)address)->l2cap_psm = port;
return B_OK;
}
/*!
Sets \a address to \a from.
\return B_OK if \a from has been copied into \a address
\return B_BAD_VALUE if either \a address or \a from is NULL
\return B_MISMATCHED_VALUES if from is not of family AF_INET
*/
static status_t
l2cap_set_to(sockaddr *address, const sockaddr *from)
{
if (address == NULL || from == NULL)
return B_BAD_VALUE;
if (from->sa_family != AF_BLUETOOTH)
return B_MISMATCHED_VALUES;
memcpy(address, from, sizeof(sockaddr_l2cap));
address->sa_len = sizeof(sockaddr_l2cap);
return B_OK;
}
static status_t
l2cap_update_to(sockaddr *_address, const sockaddr *_from)
{
sockaddr_l2cap *address = (sockaddr_l2cap *)_address;
const sockaddr_l2cap *from = (const sockaddr_l2cap *)_from;
if (address == NULL || from == NULL)
return B_BAD_VALUE;
if (from->l2cap_family != AF_BLUETOOTH)
return B_BAD_VALUE;
address->l2cap_family = AF_INET;
address->l2cap_len = sizeof(sockaddr_l2cap);
if (address->l2cap_psm == 0)
address->l2cap_psm = from->l2cap_psm;
if (bacmp(&address->l2cap_bdaddr, BDADDR_BROADCAST)==0)
address->l2cap_bdaddr = from->l2cap_bdaddr;
return B_OK;
}
/*!
Sets \a address to the empty address (0.0.0.0).
\return B_OK if \a address has been set
\return B_BAD_VALUE if \a address is NULL
*/
static status_t
l2cap_set_to_empty_address(sockaddr *address)
{
if (address == NULL)
return B_BAD_VALUE;
memset(address, 0, sizeof(sockaddr_l2cap));
address->sa_len = sizeof(sockaddr_l2cap);
address->sa_family = AF_BLUETOOTH;
return B_OK;
}
static status_t
l2cap_set_to_defaults(sockaddr *_defaultMask, sockaddr *_defaultBroadcast,
sockaddr *_address, sockaddr *_mask)
{
return B_OK;
}
/*!
Computes a hash-value of the given addresses \a ourAddress
and \a peerAddress.
\return uint32 representing the hash-value
*/
static uint32
l2cap_hash_address_pair(const sockaddr *ourAddress, const sockaddr *peerAddress)
{
const sockaddr_l2cap *our = (const sockaddr_l2cap *)ourAddress;
const sockaddr_l2cap *peer = (const sockaddr_l2cap *)peerAddress;
return ((our ? our->l2cap_psm : 0) | ((peer ? peer->l2cap_psm : 0) << 16))
^ (our ? L2CAP_CHECKSUM(our->l2cap_bdaddr) : 0) ^ (peer ? L2CAP_CHECKSUM(peer->l2cap_bdaddr) : 0);
}
/*!
Adds the given \a address to the IP-checksum \a checksum.
\return B_OK if \a address has been added to the checksum
\return B_BAD_VALUE if either \a address or \a checksum is NULL
*/
static status_t
l2cap_checksum_address(struct Checksum *checksum, const sockaddr *address)
{
if (checksum == NULL || address == NULL)
return B_BAD_VALUE;
for (uint i = 0; i < sizeof(bdaddr_t); i++)
(*checksum) << ((sockaddr_l2cap*)address)->l2cap_bdaddr.b[i];
return B_OK;
}
net_address_module_info gL2cap4AddressModule = {
{
NULL,
0,
NULL
},
l2cap_copy_address,
l2cap_mask_address,
l2cap_equal_addresses,
l2cap_equal_ports,
l2cap_equal_addresses_and_ports,
l2cap_equal_masked_addresses,
l2cap_is_empty_address,
l2cap_first_mask_bit,
l2cap_check_mask,
l2cap_print_address,
l2cap_print_address_buffer,
l2cap_get_port,
l2cap_set_port,
l2cap_set_to,
l2cap_set_to_empty_address,
l2cap_set_to_defaults,
l2cap_update_to,
l2cap_hash_address_pair,
l2cap_checksum_address,
NULL // l2cap_matches_broadcast_address,
};

View File

@ -0,0 +1,15 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Oliver Ruiz Dorantes, oliver-ruiz.dorantes_at_gmail.com
*/
#ifndef L2CAP_ADDRESS_H
#define L2CAP_ADDRESS_H
extern struct net_address_module_info gL2cap4AddressModule;
#endif // L2CAP_ADDRESS_H