- Implement ACL Segmentation and Reassembly

- Kernel traces for bluetooth devices
- Register connections helper funcs



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28739 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Oliver Ruiz Dorantes 2008-11-27 19:44:19 +00:00
parent 7cc7cada6a
commit d8de43897a
4 changed files with 361 additions and 60 deletions

View File

@ -15,6 +15,7 @@ UsePrivateHeaders net bluetooth ;
KernelAddon bluetooth :
bluetooth.cpp
acl.cpp
;
# Installation

View File

@ -0,0 +1,174 @@
/*
* Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <KernelExport.h>
#include <string.h>
#include <NetBufferUtilities.h>
#include <net_protocol.h>
#include <bluetooth/HCI/btHCI_acl.h>
#include <bluetooth/HCI/btHCI_transport.h>
#include <bluetooth/HCI/btHCI_event.h>
#include <bluetooth/bdaddrUtils.h>
//#define BT_DEBUG_THIS_MODULE
#define SUBMODULE_NAME "ACL"
#define SUBMODULE_COLOR 34
#include <btDebug.h>
#include <btCoreData.h>
#include <btModules.h>
#include <l2cap.h>
#include "acl.h"
extern struct bluetooth_core_data_module_info* btCoreData;
struct net_protocol_module_info* L2cap = NULL;
extern void RegisterConnection(hci_id hid, uint16 handle);
extern void unRegisterConnection(hci_id hid, uint16 handle);
status_t PostToUpper(HciConnection* conn, net_buffer* buf);
status_t
AclAssembly(net_buffer* nbuf, hci_id hid)
{
status_t error = B_OK;
/* Check ACL data packet. Driver should ensure report complete ACL packets */
if (nbuf->size < sizeof(struct hci_acl_header)) {
debugf("Transport driver has reported invalid ACL data packet, too small, length=%ld\n", nbuf->size);
gBufferModule->free(nbuf);
return (EMSGSIZE);
}
/* Strip ACL data packet header */
NetBufferHeaderReader<struct hci_acl_header> aclHeader(nbuf);
status_t status = aclHeader.Status();
if (status < B_OK) {
gBufferModule->free(nbuf);
return ENOBUFS;
}
/* Get ACL connection handle, PB flag and payload length */
aclHeader->handle = le16toh(aclHeader->handle);
uint16 con_handle = get_acl_handle(aclHeader->handle);
uint16 pb = get_acl_pb_flag(aclHeader->handle);
uint16 length = le16toh(aclHeader->alen);
aclHeader.Remove();
debugf("got ACL data packet, con_handle=%#x, PB=%#x, length=%d\n", con_handle, pb, length);
/* a) Ensure there is HCI connection
b) Get connection descriptor
c) veryfy the status of the connection
*/
HciConnection* conn = btCoreData->ConnectionByHandle(con_handle, hid);
if (conn == NULL) {
//debugf("unexpected ACL!Connection does not exist!schedule! con_handle=%#x\n", con_handle);
panic("unexpected ACL!Connection does not exist!schedule!\n");
conn = btCoreData->AddConnection(con_handle, BT_ACL, BDADDR_NULL, hid);
}
// Verify connection state
if (conn->status!= HCI_CONN_OPEN) {
flowf("unexpected ACL data packet. Connection not open\n");
gBufferModule->free(nbuf);
return EHOSTDOWN;
}
/* Process packet */
if (pb == HCI_ACL_PACKET_START) {
if (conn->currentRxPacket != NULL) {
debugf("dropping incomplete L2CAP packet, got %ld bytes, want %d bytes\n", conn->currentRxPacket->size, length );
gBufferModule->free(conn->currentRxPacket);
conn->currentRxPacket = NULL;
conn->currentRxExpectedLength = 0;
}
// Get L2CAP header, ACL header was dimissed
if (nbuf->size < sizeof(l2cap_hdr_t)) {
debugf("invalid L2CAP packet start fragment. Packet too small, length=%ld\n", nbuf->size);
gBufferModule->free(nbuf);
return (EMSGSIZE);
}
NetBufferHeaderReader<l2cap_hdr_t> l2capHeader(nbuf);
status_t status = l2capHeader.Status();
if (status < B_OK) {
gBufferModule->free(nbuf);
return ENOBUFS;
}
l2capHeader->length = le16toh(l2capHeader->length);
l2capHeader->dcid = le16toh(l2capHeader->dcid);
debugf("staring new L2CAP packet, con_handle=%#x, length=%d\n", con_handle, le16toh(l2capHeader->length));
/* Start new L2CAP packet */
conn->currentRxPacket = nbuf;
conn->currentRxExpectedLength = l2capHeader->length + sizeof(l2cap_hdr_t);
} else if (pb == HCI_ACL_PACKET_FRAGMENT) {
if (conn->currentRxPacket == NULL) {
gBufferModule->free(nbuf);
return (EINVAL);
}
/* Add fragment to the L2CAP packet */
gBufferModule->merge(conn->currentRxPacket, nbuf, true);
} else {
debugf("invalid ACL data packet. Invalid PB flag=%#x\n", pb);
gBufferModule->free(nbuf);
return (EINVAL);
}
conn->currentRxExpectedLength -= length; /* substract the length of content of the ACL packet*/
if (conn->currentRxExpectedLength < 0) {
debugf("packet length mismatch. Got %ld bytes, expected %ld bytes\n", conn->currentRxPacket->size,
conn->currentRxExpectedLength);
gBufferModule->free(conn->currentRxPacket);
conn->currentRxPacket = NULL;
conn->currentRxExpectedLength = 0;
} else if (conn->currentRxExpectedLength == 0) {
// OK, we have got complete L2CAP packet, so process it
debugf("L2cap packet ready %ld bytes\n", conn->currentRxPacket->size);
error = PostToUpper(conn, conn->currentRxPacket);
// clean
conn->currentRxPacket = NULL;
conn->currentRxExpectedLength = 0;
} else {
debugf("Expected %ld current acl apports %d\n", conn->currentRxExpectedLength, length);
}
return error;
}
status_t
PostToUpper(HciConnection* conn, net_buffer* buf)
{
if (L2cap == NULL)
if (get_module(NET_BLUETOOTH_L2CAP_NAME,(module_info**)&L2cap) != B_OK) {
debugf("cannot get module \"%s\"\n", NET_BLUETOOTH_L2CAP_NAME);
return B_ERROR;
} // TODO: someone put it
return L2cap->receive_data((net_buffer*)conn);// XXX:HACK -> pass handle in type
}

View File

@ -0,0 +1,17 @@
/*
* Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _ACL_PROC_H_
#define _ACL_PROC_H_
#include <net_buffer.h>
#include <bluetooth/HCI/btHCI.h>
status_t AclAssembly(net_buffer* buffer, hci_id hid);
status_t InitializeAclConnectionThread();
status_t QuitAclConnectionThread();
#endif

View File

@ -6,7 +6,6 @@
* Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
*/
#include <net_buffer.h>
#include <net_device.h>
#include <net_stack.h>
@ -18,53 +17,109 @@
#include <KernelExport.h>
#include <errno.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
#include <new>
#include <new>
#include <stdlib.h>
#include <string.h>
#include <NetBufferUtilities.h>
#include <bluetooth/HCI/btHCI.h>
#include <bluetooth/bdaddrUtils.h>
#define BT_DEBUG_THIS_MODULE
#define SUBMODULE_NAME "bluetooth_device"
#define SUBMODULE_COLOR 34
#include <btDebug.h>
#include <btCoreData.h>
#include <btModules.h>
#include <bluetooth/HCI/btHCI_acl.h>
#include "acl.h"
#include <bluetooth/HCI/btHCI.h>
struct bluetooth_device : net_device, DoublyLinkedListLinkImpl<bluetooth_device> {
DoublyLinkedList<HciConnection> sConnectionList;
int fd;
uint16 frame_size;
uint16 mtu;
};
/* Modules references */
net_buffer_module_info *gBufferModule = NULL;
static net_stack_module_info *sStackModule = NULL;
net_buffer_module_info* gBufferModule = NULL;
static net_stack_module_info* sStackModule = NULL;
struct bluetooth_core_data_module_info* btCoreData = NULL;
static mutex sListLock;
static DoublyLinkedList<bluetooth_device> sDeviceList;
static sem_id sLinkChangeSemaphore;
bluetooth_device*
FindDeviceByID(hci_id hid)
{
bluetooth_device* device;
DoublyLinkedList<bluetooth_device>::Iterator iterator = sDeviceList.GetIterator();
while (iterator.HasNext()) {
device = iterator.Next();
if (device->index == (uint32 )hid)
return device;
}
return NULL;
}
// TODO: keeping this list might not be strictily needed
void
RegisterConnection(hci_id hid, uint16 handle)
{
bluetooth_device* device = FindDeviceByID(hid);
HciConnection* conn = btCoreData->ConnectionByHandle(handle, hid);
if (device != NULL && conn != NULL) {
conn->ndevice = (struct net_device*)device;
device->sConnectionList.Add(conn);
} else {
panic("problem registering connection");
}
}
void
unRegisterConnection(hci_id hid, uint16 handle)
{
bluetooth_device* device;
device = FindDeviceByID(hid);
if (device != NULL) {
device->sConnectionList.Remove(btCoreData->ConnectionByHandle(handle, hid));
}
}
// #pragma mark -
status_t
bluetooth_init(const char *name, net_device **_device)
bluetooth_init(const char* name, net_device** _device)
{
debugf("Initializing bluetooth device %s\n",name);
// TODO: make sure this is a device in /dev/bluetooth
if (strncmp(name, "bluetooth/h", 11))
return B_BAD_VALUE;
if (gBufferModule == NULL) { // lazy allocation
status_t status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule);
status_t status = get_module(NET_BUFFER_MODULE_NAME, (module_info**)&gBufferModule);
if (status < B_OK)
return status;
}
bluetooth_device *device = new (std::nothrow) bluetooth_device;
bluetooth_device* device = new (std::nothrow) bluetooth_device;
if (device == NULL) {
put_module(NET_BUFFER_MODULE_NAME);
return B_NO_MEMORY;
@ -76,7 +131,7 @@ bluetooth_init(const char *name, net_device **_device)
strcpy(device->name, name);
MutexLocker _(&sListLock);
if (sDeviceList.IsEmpty())
device->index = HCI_DEVICE_INDEX_OFFSET; // REVIEW: dev index
else
@ -93,9 +148,9 @@ bluetooth_init(const char *name, net_device **_device)
status_t
bluetooth_uninit(net_device *_device)
bluetooth_uninit(net_device* _device)
{
bluetooth_device *device = (bluetooth_device *)_device;
bluetooth_device* device = (bluetooth_device *)_device;
debugf("index %lx\n",device->index);
@ -113,9 +168,9 @@ bluetooth_uninit(net_device *_device)
status_t
bluetooth_up(net_device *_device)
{
bluetooth_device *device = (bluetooth_device *)_device;
bluetooth_up(net_device* _device)
{
bluetooth_device* device = (bluetooth_device*)_device;
debugf("index %ld\n",device->index);
@ -133,9 +188,9 @@ err:
void
bluetooth_down(net_device *_device)
{
bluetooth_device *device = (bluetooth_device *)_device;
bluetooth_down(net_device* _device)
{
bluetooth_device *device = (bluetooth_device*)_device;
debugf("index %ld\n",device->index);
@ -145,60 +200,94 @@ bluetooth_down(net_device *_device)
status_t
bluetooth_control(net_device *_device, int32 op, void *argument,
bluetooth_control(net_device* _device, int32 op, void* argument,
size_t length)
{
bluetooth_device *device = (bluetooth_device *)_device;
{
bluetooth_device* device = (bluetooth_device*)_device;
debugf("index %ld\n",device->index);
// Forward the call to the driver
return ioctl(device->fd, op, argument, length);
}
status_t
bluetooth_send_data(net_device *_device, net_buffer *buffer)
bluetooth_send_data(net_device *_device, net_buffer* buffer)
{
bluetooth_device *device = (bluetooth_device *)_device;
bluetooth_device* device = (bluetooth_device*)_device;
net_buffer* curr_frame = NULL;
net_buffer* next_frame = buffer;
uint16 handle = buffer->type; //TODO: net_routes??
uint8 flag = HCI_ACL_PACKET_START;
debugf("index %ld try to send bt packet of %lu bytes (flags %ld):\n",device->index, buffer->size, buffer->flags);
/* TODO:
*/
//TODO: ATOMIC!!! any other thread should stop here
do {
// Divide packet if big enough
curr_frame = next_frame;
// MTU and size possiblities to be checked in l2cap....
// if (buffer->size > device->frame_size)
// return B_BAD_VALUE;
if (next_frame->size > device->mtu) {
next_frame = gBufferModule->split(curr_frame, device->mtu);
} else {
next_frame = NULL;
}
// Attach acl header
NetBufferPrepend<struct hci_acl_header> bufferHeader(curr_frame);
status_t status = bufferHeader.Status();
if (status < B_OK) {
// free the buffer
continue;
}
bufferHeader->handle = pack_acl_handle_flags(handle, flag, 0); /* Handle & Flags(PB, BC) */
bufferHeader->alen = curr_frame->size - sizeof(struct hci_acl_header);
bufferHeader.Sync();
// Send to driver XXX: another inter-layer trick
debugf("tolower nbuf %p\n",curr_frame);
curr_frame->protocol = BT_ACL;
((status_t(*)(hci_id id, net_buffer* nbuf))device->media)(device->index, curr_frame);
flag = HCI_ACL_PACKET_FRAGMENT;
} while (next_frame == NULL);
return B_OK;
}
status_t
bluetooth_receive_data(net_device *_device, net_buffer **_buffer)
bluetooth_receive_data(net_device* _device, net_buffer** _buffer)
{
bluetooth_device *device = (bluetooth_device *)_device;
status_t status = B_OK;
debugf("index %ld try to send bt packet of %lu bytes (flags %ld):\n", device->index, (*_buffer)->size, (*_buffer)->flags);
debugf("index %ld packet of %lu bytes (flags %ld):\n", device->index, (*_buffer)->size, (*_buffer)->flags);
if (device->fd == -1)
return B_FILE_ERROR;
/* TODO:
*/
switch ((*_buffer)->protocol) {
case BT_ACL:
status = AclAssembly(*_buffer, device->index);
break;
default:
panic("Protocol not supported");
break;
}
return status;
}
status_t
bluetooth_set_mtu(net_device *_device, size_t mtu)
bluetooth_set_mtu(net_device* _device, size_t mtu)
{
bluetooth_device *device = (bluetooth_device *)_device;
bluetooth_device* device = (bluetooth_device*)_device;
debugf("index %ld mtu %ld\n",device->index, mtu);
@ -209,9 +298,9 @@ bluetooth_set_mtu(net_device *_device, size_t mtu)
status_t
bluetooth_set_promiscuous(net_device *_device, bool promiscuous)
bluetooth_set_promiscuous(net_device* _device, bool promiscuous)
{
bluetooth_device *device = (bluetooth_device *)_device;
bluetooth_device* device = (bluetooth_device*)_device;
debugf("index %ld promiscuous %d\n",device->index, promiscuous);
@ -220,18 +309,18 @@ bluetooth_set_promiscuous(net_device *_device, bool promiscuous)
status_t
bluetooth_set_media(net_device *device, uint32 media)
bluetooth_set_media(net_device* device, uint32 media)
{
debugf("index %ld media %ld\n",device->index, media);
return EOPNOTSUPP;
}
status_t
bluetooth_add_multicast(struct net_device *_device, const sockaddr *_address)
bluetooth_add_multicast(struct net_device* _device, const sockaddr* _address)
{
bluetooth_device* device = (bluetooth_device *)_device;
bluetooth_device* device = (bluetooth_device*)_device;
debugf("index %ld\n",device->index);
@ -239,9 +328,9 @@ bluetooth_add_multicast(struct net_device *_device, const sockaddr *_address)
}
status_t
bluetooth_remove_multicast(struct net_device *_device, const sockaddr *_address)
bluetooth_remove_multicast(struct net_device* _device, const sockaddr* _address)
{
bluetooth_device* device = (bluetooth_device *)_device;
bluetooth_device* device = (bluetooth_device*)_device;
debugf("index %ld\n",device->index);
@ -259,9 +348,14 @@ dump_bluetooth_devices(int argc, char** argv)
while (iterator.HasNext()) {
device = iterator.Next();
kprintf("\tname=%s index=%#lx\n",device->name, device->index);
kprintf("\tname=%s index=%#lx @%p\n",device->name, device->index, device);
DoublyLinkedList<HciConnection>::Iterator connIterator = device->sConnectionList.GetIterator();
while (connIterator.HasNext()) {
HciConnection* conn = connIterator.Next();
kprintf("\t\t handle=%#x destination=%s @%p\n", conn->handle, bdaddrUtils::ToString(conn->destination), conn);
}
}
return 0;
}
@ -271,14 +365,23 @@ bluetooth_std_ops(int32 op, ...)
{
flowf("\n");
switch (op) {
case B_MODULE_INIT:
{
status_t status = get_module(NET_STACK_MODULE_NAME,
(module_info **)&sStackModule);
if (status < B_OK)
status_t status;
status = get_module(NET_STACK_MODULE_NAME,(module_info**)&sStackModule);
if (status < B_OK) {
flowf("problem getting netstack module\n");
return status;
}
status = get_module(BT_CORE_DATA_MODULE_NAME,(module_info**)&btCoreData);
if (status < B_OK) {
flowf("problem getting datacore\n");
return status;
}
new (&sDeviceList) DoublyLinkedList<bluetooth_device>;
// static C++ objects are not initialized in the module startup
@ -286,11 +389,15 @@ bluetooth_std_ops(int32 op, ...)
sLinkChangeSemaphore = create_sem(0, "bt sem");
if (sLinkChangeSemaphore < B_OK) {
put_module(NET_STACK_MODULE_NAME);
flowf("sem failed\n");
return sLinkChangeSemaphore;
}
mutex_init(&sListLock, "bluetooth devices");
//status = InitializeAclConnectionThread();
debugf("Connection Thread error=%lx\n", status);
add_debugger_command("btLocalDevices", &dump_bluetooth_devices, "Lists Bluetooth LocalDevices registered in the Stack");
return B_OK;
@ -302,9 +409,10 @@ bluetooth_std_ops(int32 op, ...)
mutex_destroy(&sListLock);
put_module(NET_STACK_MODULE_NAME);
put_module(BT_CORE_DATA_MODULE_NAME);
remove_debugger_command("btLocalDevices", &dump_bluetooth_devices);
//status_t status = QuitAclConnectionThread();
return B_OK;
}
@ -316,8 +424,8 @@ bluetooth_std_ops(int32 op, ...)
net_device_module_info sBluetoothModule = {
{
"network/devices/bluetooth/v1",
0,
NET_BLUETOOTH_DEVICE_NAME,
B_KEEP_LOADED,
bluetooth_std_ops
},
bluetooth_init,
@ -334,8 +442,9 @@ net_device_module_info sBluetoothModule = {
bluetooth_remove_multicast,
};
module_info *modules[] = {
(module_info *)&sBluetoothModule,
NULL
};