From 3e248012835bd421230236f862462140722cc1bb Mon Sep 17 00:00:00 2001 From: Oliver Ruiz Dorantes Date: Mon, 2 Jun 2008 20:16:00 +0000 Subject: [PATCH] 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 --- headers/os/bluetooth/L2CAP/btL2CAP.h | 21 + .../kernel/network/protocols/l2cap/Jamfile | 26 ++ .../kernel/network/protocols/l2cap/l2cap.cpp | 304 +++++++++++++ .../network/protocols/l2cap/l2cap_address.cpp | 416 ++++++++++++++++++ .../network/protocols/l2cap/l2cap_address.h | 15 + 5 files changed, 782 insertions(+) create mode 100644 headers/os/bluetooth/L2CAP/btL2CAP.h create mode 100644 src/add-ons/kernel/network/protocols/l2cap/Jamfile create mode 100644 src/add-ons/kernel/network/protocols/l2cap/l2cap.cpp create mode 100644 src/add-ons/kernel/network/protocols/l2cap/l2cap_address.cpp create mode 100644 src/add-ons/kernel/network/protocols/l2cap/l2cap_address.h diff --git a/headers/os/bluetooth/L2CAP/btL2CAP.h b/headers/os/bluetooth/L2CAP/btL2CAP.h new file mode 100644 index 0000000000..01970c31c4 --- /dev/null +++ b/headers/os/bluetooth/L2CAP/btL2CAP.h @@ -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 + +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 \ No newline at end of file diff --git a/src/add-ons/kernel/network/protocols/l2cap/Jamfile b/src/add-ons/kernel/network/protocols/l2cap/Jamfile new file mode 100644 index 0000000000..da58ac0940 --- /dev/null +++ b/src/add-ons/kernel/network/protocols/l2cap/Jamfile @@ -0,0 +1,26 @@ +SubDir HAIKU_TOP src add-ons kernel network protocols l2cap ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +if $(TARGET_PLATFORM) != haiku { + UseHeaders [ FStandardOSHeaders ] : true ; + # Needed for 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 ; diff --git a/src/add-ons/kernel/network/protocols/l2cap/l2cap.cpp b/src/add-ons/kernel/network/protocols/l2cap/l2cap.cpp new file mode 100644 index 0000000000..c0caea3fff --- /dev/null +++ b/src/add-ons/kernel/network/protocols/l2cap/l2cap.cpp @@ -0,0 +1,304 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + + +typedef NetBufferField 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 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 +}; diff --git a/src/add-ons/kernel/network/protocols/l2cap/l2cap_address.cpp b/src/add-ons/kernel/network/protocols/l2cap/l2cap_address.cpp new file mode 100644 index 0000000000..a42db22022 --- /dev/null +++ b/src/add-ons/kernel/network/protocols/l2cap/l2cap_address.cpp @@ -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 + +#include +#include + +#include + +#include +#include +#include + +#include + +#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 ''). + 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, "", 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, +}; diff --git a/src/add-ons/kernel/network/protocols/l2cap/l2cap_address.h b/src/add-ons/kernel/network/protocols/l2cap/l2cap_address.h new file mode 100644 index 0000000000..9f4e1f847b --- /dev/null +++ b/src/add-ons/kernel/network/protocols/l2cap/l2cap_address.h @@ -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