From 18c7aa0c9d1c6593c7c5d14a322562bb2fad3721 Mon Sep 17 00:00:00 2001 From: Oliver Ruiz Dorantes Date: Tue, 25 Nov 2008 18:20:40 +0000 Subject: [PATCH] - Add bluetooth kernel module intented to manage all internal data structures -Managing for HCI connections -Managing of L2cap Channels -Pending frames -Interface with KDL git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28726 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/bluetooth/Jamfile | 3 + .../bluetooth/btCoreData/BTCoreData.cpp | 183 +++++++++++++++ .../bluetooth/btCoreData/ChannelInterface.cpp | 122 ++++++++++ .../bluetooth/btCoreData/ChannelInterface.h | 21 ++ .../btCoreData/ConnectionInterface.cpp | 211 ++++++++++++++++++ .../btCoreData/ConnectionInterface.h | 34 +++ .../bluetooth/btCoreData/FrameInterface.cpp | 107 +++++++++ .../bluetooth/btCoreData/FrameInterface.h | 28 +++ .../kernel/bluetooth/btCoreData/Jamfile | 18 ++ 9 files changed, 727 insertions(+) create mode 100644 src/add-ons/kernel/bluetooth/Jamfile create mode 100644 src/add-ons/kernel/bluetooth/btCoreData/BTCoreData.cpp create mode 100644 src/add-ons/kernel/bluetooth/btCoreData/ChannelInterface.cpp create mode 100644 src/add-ons/kernel/bluetooth/btCoreData/ChannelInterface.h create mode 100644 src/add-ons/kernel/bluetooth/btCoreData/ConnectionInterface.cpp create mode 100644 src/add-ons/kernel/bluetooth/btCoreData/ConnectionInterface.h create mode 100644 src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.cpp create mode 100644 src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.h create mode 100644 src/add-ons/kernel/bluetooth/btCoreData/Jamfile diff --git a/src/add-ons/kernel/bluetooth/Jamfile b/src/add-ons/kernel/bluetooth/Jamfile new file mode 100644 index 0000000000..6e50736c62 --- /dev/null +++ b/src/add-ons/kernel/bluetooth/Jamfile @@ -0,0 +1,3 @@ +SubDir HAIKU_TOP src add-ons kernel bluetooth ; + +SubInclude HAIKU_TOP src add-ons kernel bluetooth btCoreData ; diff --git a/src/add-ons/kernel/bluetooth/btCoreData/BTCoreData.cpp b/src/add-ons/kernel/bluetooth/btCoreData/BTCoreData.cpp new file mode 100644 index 0000000000..2c3e839332 --- /dev/null +++ b/src/add-ons/kernel/bluetooth/btCoreData/BTCoreData.cpp @@ -0,0 +1,183 @@ +/* + * Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * All rights reserved. Distributed under the terms of the MIT License. + */ +#include "ConnectionInterface.h" +#include "ChannelInterface.h" +#include "FrameInterface.h" + + +#include +#include +#include + +#define BT_DEBUG_THIS_MODULE +#include + +DoublyLinkedList sConnectionList; +net_buffer_module_info *gBufferModule = NULL; + +inline bool +ExistConnectionByDestination(bdaddr_t *destination, hci_id hid = -1) +{ + return (ConnectionByDestination(destination, hid) != NULL); +} + + +inline bool +ExistConnectionByHandle(uint16 handle, hci_id hid) +{ + return (ConnectionByHandle(handle,hid)); +} + + +static int +DumpHciConnections(int argc, char** argv) +{ + HciConnection* conn; + L2capChannel* chan; + DoublyLinkedList::Iterator iterator = sConnectionList.GetIterator(); + + while (iterator.HasNext()) { + conn = iterator.Next(); + kprintf("\tLocalDevice=%lx Destination=%s handle=%#x type=%d outqueue=%ld expected=%ld\n", + conn->Hid, bdaddrUtils::ToString(conn->destination), + conn->handle, conn->type, conn->OutGoingFrames.Size() , conn->ExpectedResponses.Size()); + + // each channel + DoublyLinkedList::Iterator channelIterator = conn->ChannelList.GetIterator(); + while (channelIterator.HasNext()) { + chan = channelIterator.Next(); + kprintf("\t\tscid=%x dcid=%x state=%x cfg=%x\n", chan->scid, + chan->dcid, chan->state, chan->cfgState); + } + + } + + return 0; +} + + +status_t +PostEvent(net_device* ndev, void* event, size_t size) +{ + struct hci_event_header* outgoingEvent = (struct hci_event_header*) event; + status_t err; + + // Take actions on certain type of events. + switch (outgoingEvent->ecode) { + case HCI_EVENT_CONN_COMPLETE: + { + struct hci_ev_conn_complete* data = (struct hci_ev_conn_complete*)(outgoingEvent+1); + //TODO: XXX parse handle field + HciConnection* conn = AddConnection(data->handle, BT_ACL, &data->bdaddr, ndev->index); + if (conn == NULL) + panic("no mem for conn desc"); + conn->ndevice = ndev; + debugf("Registered connection handle=%#x\n",data->handle); + + } break; + + case HCI_EVENT_DISCONNECTION_COMPLETE: + { + struct hci_ev_disconnection_complete_reply* data = + (struct hci_ev_disconnection_complete_reply*)(outgoingEvent+1); + RemoveConnection(data->handle, ndev->index); + debugf("unRegistered connection handle=%#x\n",data->handle); + } break; + } + + // forward to bluetooth server + port_id port = find_port(BT_USERLAND_PORT_NAME); + if (port != B_NAME_NOT_FOUND) { + + err = write_port_etc(port, PACK_PORTCODE(BT_EVENT, ndev->index, -1), + event, size, B_TIMEOUT, 1*1000*1000); + + if (err != B_OK) + debugf("Error posting userland %s\n", strerror(err)); + + } else { + flowf("ERROR:bluetooth_server not found for posting\n"); + err = B_NAME_NOT_FOUND; + } + + + return err; +} + + +static status_t +bcd_std_ops(int32 op, ...) +{ + status_t status; + + switch (op) { + case B_MODULE_INIT: + new (&sConnectionList) DoublyLinkedList; + add_debugger_command("btConnections", &DumpHciConnections, + "Lists Bluetooth Connections with RemoteDevices & channels"); + + status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule); + if (status < B_OK) { + return status; + } + + return B_OK; + + break; + + case B_MODULE_UNINIT: + + remove_debugger_command("btConnections", &DumpHciConnections); + put_module(NET_BUFFER_MODULE_NAME); + + return B_OK; + break; + } + + return B_ERROR; +} + +bluetooth_core_data_module_info sBCDModule = { + { + BT_CORE_DATA_MODULE_NAME, + 0, + bcd_std_ops + }, + PostEvent, + AddConnection, +/* RemoveConnection,*/ + RemoveConnection, + + RouteConnection, + + SetAclBuffer, + SetAclExpectedSize, + AclPutting, + AclComplete, + AclOverFlowed, + + ConnectionByHandle, + ConnectionByDestination, + + AddChannel, + RemoveChannel, + ChannelBySourceID, + ChannelAllocateCid, + ChannelAllocateIdent, + + SignalByIdent, + TimeoutSignal, + unTimeoutSignal, + SpawmFrame, + SpawmSignal, + AcknowledgeSignal + +}; + + +module_info *modules[] = { + (module_info *)&sBCDModule, + NULL +}; diff --git a/src/add-ons/kernel/bluetooth/btCoreData/ChannelInterface.cpp b/src/add-ons/kernel/bluetooth/btCoreData/ChannelInterface.cpp new file mode 100644 index 0000000000..19b1840992 --- /dev/null +++ b/src/add-ons/kernel/bluetooth/btCoreData/ChannelInterface.cpp @@ -0,0 +1,122 @@ +/* + * Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * All rights reserved. Distributed under the terms of the MIT License. + */ +#include + +#include +#include + +#define BT_DEBUG_THIS_MODULE +#define SUBMODULE_NAME "Channel" +#define SUBMODULE_COLOR 31 +#include + +#include "ChannelInterface.h" +#include "FrameInterface.h" + +L2capChannel* +ChannelBySourceID(HciConnection *conn, uint16 scid) +{ + L2capChannel* channel = NULL; + + DoublyLinkedList::Iterator iterator = conn->ChannelList.GetIterator(); + + while (iterator.HasNext()) { + channel = iterator.Next(); + if (channel->scid == scid) + return channel; + } + + return NULL; +} + + +uint16 +ChannelAllocateCid(HciConnection* conn) +{ + uint16 cid = conn->lastCid ; + debugf("Starting search cid %d\n",cid); + do { + cid = (cid == L2CAP_LAST_CID)?L2CAP_FIRST_CID : cid + 1; + + if(ChannelBySourceID(conn, cid) == NULL) { + conn->lastCid = cid; + return cid; + } + + } while (cid != conn->lastCid); + + return L2CAP_NULL_CID; +} + + +uint16 +ChannelAllocateIdent(HciConnection* conn) +{ + uint8 ident = conn->lastIdent + 1; + + if (ident < L2CAP_FIRST_IDENT) + ident = L2CAP_FIRST_IDENT; + + while (ident != conn->lastIdent) { + if (SignalByIdent(conn, ident) == NULL) { + conn->lastIdent = ident; + + return ident; + } + + ident ++; + if (ident < L2CAP_FIRST_IDENT) + ident = L2CAP_FIRST_IDENT; + } + + return L2CAP_NULL_IDENT; +} + + +L2capChannel* +AddChannel(HciConnection* conn, uint16 psm) +{ + L2capChannel* channel = new (std::nothrow) L2capChannel; + + if (channel == NULL) { + flowf ("no mem for channel"); + return (NULL); + } + + /* Get a new Source CID */ + channel->scid = ChannelAllocateCid(conn); + + if (channel->scid != L2CAP_NULL_CID) { + /* Initialize channel */ + channel->psm = psm; + channel->conn = conn; + channel->state = L2CAP_CHAN_CLOSED; + channel->cfgState = 0; + channel->endpoint = NULL; + + // the last assigned CID should be the last in the list + // Think if keeping an ordered list will improve the search method + // as it is called in every reception + conn->ChannelList.Add(channel); + //conn->num_channels++; + + // Any constance of the new channel created ...? ng_l2cap_con_ref(con); + + } else { + flowf("no CID available\n"); + delete channel; + channel = NULL; + } + + return (channel); +} + + +void +RemoveChannel(HciConnection* conn, uint16 scid) +{ + //TODO make it safer + conn->ChannelList.Remove(ChannelBySourceID(conn, scid)); +} diff --git a/src/add-ons/kernel/bluetooth/btCoreData/ChannelInterface.h b/src/add-ons/kernel/bluetooth/btCoreData/ChannelInterface.h new file mode 100644 index 0000000000..c329f96eb1 --- /dev/null +++ b/src/add-ons/kernel/bluetooth/btCoreData/ChannelInterface.h @@ -0,0 +1,21 @@ +/* + * Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef _CHANNEL_INTERFACE_H +#define _CHANNEL_INTERFACE_H + +#include + +#include +#include + +L2capChannel* AddChannel(HciConnection* conn, uint16 psm); +void RemoveChannel(HciConnection* conn, uint16 scid); + +L2capChannel* ChannelBySourceID(HciConnection* conn, uint16 scid); +uint16 ChannelAllocateCid(HciConnection* conn); +uint16 ChannelAllocateIdent(HciConnection* conn); + + +#endif // _CHANNELINTERFACE_H diff --git a/src/add-ons/kernel/bluetooth/btCoreData/ConnectionInterface.cpp b/src/add-ons/kernel/bluetooth/btCoreData/ConnectionInterface.cpp new file mode 100644 index 0000000000..6f1e8ae3b4 --- /dev/null +++ b/src/add-ons/kernel/bluetooth/btCoreData/ConnectionInterface.cpp @@ -0,0 +1,211 @@ +/* + * Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +#include + +#include +#include + +#define BT_DEBUG_THIS_MODULE +#define SUBMODULE_NAME "Connection" +#define SUBMODULE_COLOR 31 +#include + +#include + +#include "ConnectionInterface.h" + +void PurgeChannels(HciConnection* conn); + +HciConnection* +AddConnection(uint16 handle, int type, bdaddr_t* dst, hci_id hid) +{ + // Create connection descriptor + + HciConnection* conn = ConnectionByHandle(handle, hid); + if (conn != NULL) + goto update; + + conn = new (std::nothrow) HciConnection; + if (conn == NULL) + goto bail; + + memset(conn, 0, sizeof(HciConnection)); + + conn->currentRxPacket = NULL; + conn->currentRxExpectedLength = 0; +update: + // fill values + bacpy(&conn->destination, dst); + conn->type = type; + conn->handle = handle; + conn->Hid = hid; + conn->status = HCI_CONN_OPEN; + conn->mtu = L2CAP_MTU_MINIMUM; // TODO: give the mtu to the connection + conn->lastCid = L2CAP_FIRST_CID; + conn->lastIdent = L2CAP_FIRST_IDENT; + + sConnectionList.Add(conn); + +bail: + return conn; +} + + +status_t +RemoveConnection(bdaddr_t* destination, hci_id hid) +{ + HciConnection* conn; + + DoublyLinkedList::Iterator iterator = sConnectionList.GetIterator(); + while (iterator.HasNext()) { + + conn = iterator.Next(); + if (conn->Hid == hid && bacmp(&conn->destination, destination)==0) { + + // if the device is still part of the list, remove it + if (conn->GetDoublyLinkedListLink()->next != NULL + || conn->GetDoublyLinkedListLink()->previous != NULL + || conn == sConnectionList.Head()) { + sConnectionList.Remove(conn); + + delete conn; + return B_OK; + } + } + } + return B_ERROR; +} + + +status_t +RemoveConnection(uint16 handle, hci_id hid) +{ + HciConnection* conn; + + DoublyLinkedList::Iterator iterator = sConnectionList.GetIterator(); + while (iterator.HasNext()) { + + conn = iterator.Next(); + if (conn->Hid == hid && conn->handle == handle) { + + // if the device is still part of the list, remove it + if (conn->GetDoublyLinkedListLink()->next != NULL + || conn->GetDoublyLinkedListLink()->previous != NULL + || conn == sConnectionList.Head()) { + sConnectionList.Remove(conn); + + PurgeChannels(conn); + delete conn; + return B_OK; + } + } + } + return B_ERROR; +} + + +hci_id +RouteConnection(bdaddr_t* destination) { + + HciConnection* conn; + + DoublyLinkedList::Iterator iterator = sConnectionList.GetIterator(); + while (iterator.HasNext()) { + + conn = iterator.Next(); + if (bacmp(&conn->destination, destination)==0) { + return conn->Hid; + } + } + + return -1; +} + + +HciConnection* +ConnectionByHandle(uint16 handle, hci_id hid) +{ + HciConnection* conn; + + DoublyLinkedList::Iterator iterator = sConnectionList.GetIterator(); + while (iterator.HasNext()) { + + conn = iterator.Next(); + if (conn->Hid == hid && conn->handle==handle) { + return conn; + } + } + + return NULL; +} + + +HciConnection* +ConnectionByDestination(bdaddr_t* destination, hci_id hid) +{ + HciConnection* conn; + + DoublyLinkedList::Iterator iterator = sConnectionList.GetIterator(); + while (iterator.HasNext()) { + + conn = iterator.Next(); + if (conn->Hid == hid && bacmp(&conn->destination, destination)==0) { + return conn; + } + } + + return NULL; +} + +#if 0 +#pragma mark - ACL helper funcs +#endif + +void +SetAclBuffer(HciConnection* conn, net_buffer* nbuf) +{ + conn->currentRxPacket = nbuf; +} + + +void +SetAclExpectedSize(HciConnection* conn, size_t size) +{ + conn->currentRxExpectedLength = size; +} + + +void +AclPutting(HciConnection* conn, size_t size) +{ + conn->currentRxExpectedLength -= size; +} + + +bool +AclComplete(HciConnection* conn) +{ + return conn->currentRxExpectedLength == 0; +} + + +bool +AclOverFlowed(HciConnection* conn) +{ + return conn->currentRxExpectedLength < 0; +} + +#if 0 +#pragma mark - private funcs +#endif + +void +PurgeChannels(HciConnection* conn) +{ + +} diff --git a/src/add-ons/kernel/bluetooth/btCoreData/ConnectionInterface.h b/src/add-ons/kernel/bluetooth/btCoreData/ConnectionInterface.h new file mode 100644 index 0000000000..acb696d444 --- /dev/null +++ b/src/add-ons/kernel/bluetooth/btCoreData/ConnectionInterface.h @@ -0,0 +1,34 @@ +/* + * Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef _CONNECTION_INTERFACE_H +#define _CONNECTION_INTERFACE_H + +#include + +#include +#include + +#include + +extern DoublyLinkedList sConnectionList; + +HciConnection* ConnectionByHandle(uint16 handle, hci_id hid); +HciConnection* ConnectionByDestination(bdaddr_t *destination, hci_id hid); + + +HciConnection* AddConnection(uint16 handle, int type, bdaddr_t *dst, hci_id hid); +status_t RemoveConnection(bdaddr_t *destination, hci_id hid); +status_t RemoveConnection(uint16 handle, hci_id hid); + +hci_id RouteConnection(bdaddr_t *destination); + +void SetAclBuffer(HciConnection* conn, net_buffer* nbuf); +void SetAclExpectedSize(HciConnection* conn, size_t size); +void AclPutting(HciConnection* conn, size_t size); +bool AclComplete(HciConnection* conn); +bool AclOverFlowed(HciConnection* conn); + + +#endif // _CONNECTION_INTERFACE_H diff --git a/src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.cpp b/src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.cpp new file mode 100644 index 0000000000..84061ba1dd --- /dev/null +++ b/src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.cpp @@ -0,0 +1,107 @@ +#include "FrameInterface.h" + +#define BT_DEBUG_THIS_MODULE +#define SUBMODULE_NAME "Frame" +#define SUBMODULE_COLOR 31 +#include + + +L2capFrame* +SignalByIdent(HciConnection* conn, uint8 ident) +{ + L2capFrame* frame; + + DoublyLinkedList::Iterator iterator = conn->ExpectedResponses.GetIterator(); + + while (iterator.HasNext()) { + + frame = iterator.Next(); + if (frame->type == L2CAP_C_FRAME && frame->ident == ident) { + return frame; + } + } + + return NULL; +} + +status_t +TimeoutSignal(L2capFrame* frame, uint32 timeo) +{ + if (frame != NULL) + return B_OK; + + return B_ERROR; +} + + +status_t +unTimeoutSignal(L2capFrame* frame) +{ + if (frame != NULL) + return B_OK; + + return B_ERROR; +} + + +L2capFrame* +SpawmFrame(HciConnection* conn, net_buffer* buffer, frame_type type) +{ + if (buffer == NULL) + panic("Null Buffer to outgoing queue"); + + L2capFrame* frame = new (std::nothrow) L2capFrame; + + frame->conn = conn; + frame->channel = NULL; // TODO: needed? + + frame->buffer = buffer; + frame->type = type; + + conn->OutGoingFrames.Add(frame, true); + + return frame; +} + + +L2capFrame* +SpawmSignal(HciConnection* conn, L2capChannel* channel, net_buffer* buffer, uint8 ident, uint8 code) +{ + if (buffer == NULL) + panic("Null Buffer to outgoing queue"); + + L2capFrame* frame = new (std::nothrow) L2capFrame; + + frame->conn = conn; + frame->channel = channel; // TODO: needed? + + frame->buffer = buffer; + frame->type = L2CAP_C_FRAME; + frame->ident = ident; + frame->code = code; + + conn->OutGoingFrames.Add(frame, true); + + return frame; +} + + +status_t +AcknowledgeSignal(L2capFrame* frame) +{ + + if (frame != NULL) { + + if (frame->type == L2CAP_C_FRAME) { + unTimeoutSignal(frame); + frame->conn->ExpectedResponses.Remove(frame); + } + + gBufferModule->free(frame->buffer); + delete frame; + + return B_OK; + } + + return B_ERROR; +} diff --git a/src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.h b/src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.h new file mode 100644 index 0000000000..84c1c3ea25 --- /dev/null +++ b/src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.h @@ -0,0 +1,28 @@ +#ifndef _FRAME_INTERFACE_H +#define _FRAME_INTERFACE_H + +#include + +#include + +extern net_buffer_module_info* gBufferModule; + +L2capFrame* +SignalByIdent(HciConnection* conn, uint8 ident); + +status_t +TimeoutSignal(L2capFrame* frame, uint32 timeo); + +status_t +unTimeoutSignal(L2capFrame* frame); + +L2capFrame* +SpawmFrame(HciConnection* conn, net_buffer* buffer, frame_type frame); + +L2capFrame* +SpawmSignal(HciConnection* conn, L2capChannel* channel, net_buffer* buffer, uint8 ident, uint8 code); + +status_t +AcknowledgeSignal(L2capFrame* frame); + +#endif diff --git a/src/add-ons/kernel/bluetooth/btCoreData/Jamfile b/src/add-ons/kernel/bluetooth/btCoreData/Jamfile new file mode 100644 index 0000000000..c5ea92268b --- /dev/null +++ b/src/add-ons/kernel/bluetooth/btCoreData/Jamfile @@ -0,0 +1,18 @@ +SubDir HAIKU_TOP src add-ons kernel bluetooth btCoreData ; + +UsePrivateHeaders kernel net bluetooth ; +UsePrivateHeaders [ FDirName kernel arch $(TARGET_ARCH) ] ; +UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ; + +# disable debug output, if debugging is disabled +if $(DEBUG) = 0 { + SubDirCcFlags [ FDefines DEBUG_MAX_LEVEL_FLOW=0 DEBUG_MAX_LEVEL_INFO=0 ] ; +} + +KernelAddon btCoreData : + ConnectionInterface.cpp + ChannelInterface.cpp + FrameInterface.cpp + BTCoreData.cpp + ; +