diff --git a/arch/sim/src/nuttx-names.in b/arch/sim/src/nuttx-names.in index 3117054727..e235c87e00 100644 --- a/arch/sim/src/nuttx-names.in +++ b/arch/sim/src/nuttx-names.in @@ -90,3 +90,4 @@ NXSYMBOLS(tcsetattr) NXSYMBOLS(unlink) NXSYMBOLS(usleep) NXSYMBOLS(write) +NXSYMBOLS(sendmsg) diff --git a/arch/sim/src/sim/up_hcisocket.c b/arch/sim/src/sim/up_hcisocket.c index 2c0ba83760..ff9da37343 100644 --- a/arch/sim/src/sim/up_hcisocket.c +++ b/arch/sim/src/sim/up_hcisocket.c @@ -120,6 +120,8 @@ static int bthcisock_send(FAR const struct bt_driver_s *dev, return -1; } + bt_buf_release(buf); + return buf->len; } @@ -197,7 +199,7 @@ int bthcisock_loop() * to copy from */ - read_buf = bt_buf_alloc(BT_DUMMY, NULL, 0); + read_buf = bt_buf_alloc(BT_DUMMY, NULL, BLUETOOTH_H4_HDRLEN); if (read_buf == NULL) { wlerr("ERROR: Failed to allocate buffer\n"); diff --git a/include/netpacket/bluetooth.h b/include/netpacket/bluetooth.h index ec0c072442..0dda89dba6 100644 --- a/include/netpacket/bluetooth.h +++ b/include/netpacket/bluetooth.h @@ -74,6 +74,9 @@ * is made, the first unused channel for the relevant bdaddr will be * allocated and may be discovered using the getsockname(2) call. * + * BTPROTO_NONE + * This is to be used internally to indicate unconfigured protocol. Not + * to be used on sockets by user. */ #define BTPROTO_L2CAP 0 @@ -84,6 +87,7 @@ #define BTPROTO_CMTP 5 #define BTPROTO_HIDP 6 #define BTPROTO_AVDTP 7 +#define BTPROTO_NONE 255 /* HCI socket options (SOL_HCI, see include/sys/socket.h): * @@ -242,6 +246,19 @@ #define BT_PSM_OTS 0x0025 /* Object Transfer Service (OTS), * Bluetooth SIG */ +/* Channels for a BTPROTO_HCI socket */ + +#define HCI_CHANNEL_RAW 0x0 +#define HCI_CHANNEL_USER 0x1 + +/* Packets types send over the network layer for BTPROTO_HCI */ + +#define HCI_COMMAND_PKT 0x01 +#define HCI_ACLDATA_PKT 0x02 +#define HCI_SCODATA_PKT 0x03 +#define HCI_EVENT_PKT 0x04 +#define HCI_VENDOR_PKT 0xff + /**************************************************************************** * Public Type Definitions ****************************************************************************/ diff --git a/include/nuttx/net/bluetooth.h b/include/nuttx/net/bluetooth.h index 0b9d3bcc02..cd526108a4 100644 --- a/include/nuttx/net/bluetooth.h +++ b/include/nuttx/net/bluetooth.h @@ -71,6 +71,7 @@ struct bluetooth_frame_meta_s { + uint8_t bm_proto; /* Protocol */ bt_addr_t bm_raddr; /* Connected remote address */ uint8_t bm_channel; /* Connection channel */ }; diff --git a/net/bluetooth/bluetooth.h b/net/bluetooth/bluetooth.h index 8f8a1bb92c..4843892be4 100644 --- a/net/bluetooth/bluetooth.h +++ b/net/bluetooth/bluetooth.h @@ -97,6 +97,7 @@ struct bluetooth_conn_s #if CONFIG_NET_BLUETOOTH_BACKLOG > 0 uint8_t bc_backlog; /* Number of frames in RX queue */ #endif + uint8_t bc_proto; /* Protocol */ /* Queue of incoming packets */ diff --git a/net/bluetooth/bluetooth_conn.c b/net/bluetooth/bluetooth_conn.c index bef7fbf0f7..32c0504bb3 100644 --- a/net/bluetooth/bluetooth_conn.c +++ b/net/bluetooth/bluetooth_conn.c @@ -105,8 +105,16 @@ void bluetooth_conn_initialize(void) dq_init(&g_free_bluetooth_connections); dq_init(&g_active_bluetooth_connections); + /* Mark connections as uninitialized */ + + memset(g_bluetooth_connections, 0, sizeof(g_bluetooth_connections)); + for (i = 0; i < CONFIG_NET_BLUETOOTH_NCONNS; i++) { + /* Indicate a connection unbound with BTPROTO_NONE */ + + g_bluetooth_connections[i].bc_proto = BTPROTO_NONE; + /* Link each pre-allocated connection structure into the free list. */ dq_addlast(&g_bluetooth_connections[i].bc_node, @@ -192,6 +200,11 @@ void bluetooth_conn_free(FAR struct bluetooth_conn_s *conn) /* Free the connection */ dq_addlast(&conn->bc_node, &g_free_bluetooth_connections); + + /* Mark as unbound */ + + conn->bc_proto = BTPROTO_NONE; + net_unlock(); } @@ -214,21 +227,52 @@ FAR struct bluetooth_conn_s * DEBUGASSERT(meta != NULL); - for (conn = (FAR struct bluetooth_conn_s *)g_active_bluetooth_connections.head; + for (conn = + (FAR struct bluetooth_conn_s *)g_active_bluetooth_connections.head; conn != NULL; conn = (FAR struct bluetooth_conn_s *)conn->bc_node.flink) { - /* Does the destination address match the bound address of the socket. */ + /* match protocol and channel first */ - if ((BLUETOOTH_ADDRCMP(&conn->bc_raddr, &meta->bm_raddr) || - BLUETOOTH_ADDRCMP(&conn->bc_raddr, &g_any_addr)) && - (meta->bm_channel == conn->bc_channel || - BT_CHANNEL_ANY == conn->bc_channel)) + if (meta->bm_proto != conn->bc_proto || + meta->bm_channel != conn->bc_channel) { continue; } + + switch (meta->bm_proto) + { + /* For BTPROTO_HCI, the socket will not be connected but only + * bound, thus we match for the device directly + */ + + case BTPROTO_HCI: + + /* TODO: handle when multiple devices supported, need to add ID + * to meta and conn structures + */ + + goto stop; + + break; + + /* For BTPROTO_L2CAP, the destination address must match the + * bound address of the socket + */ + + case BTPROTO_L2CAP: + if ((BLUETOOTH_ADDRCMP(&conn->bc_raddr, &meta->bm_raddr) || + BLUETOOTH_ADDRCMP(&conn->bc_raddr, &g_any_addr)) && + (meta->bm_channel == conn->bc_channel)) + { + goto stop; + } + + break; + } } +stop: return conn; } diff --git a/net/bluetooth/bluetooth_sendto.c b/net/bluetooth/bluetooth_sendto.c index 629147d4cd..7223078cf4 100644 --- a/net/bluetooth/bluetooth_sendto.c +++ b/net/bluetooth/bluetooth_sendto.c @@ -66,7 +66,7 @@ struct bluetooth_sendto_s FAR struct socket *is_sock; /* Points to the parent socket structure */ FAR struct devif_callback_s *is_cb; /* Reference to callback instance */ bt_addr_t is_destaddr; /* Frame destination address */ - uint8_t is_channel; /* Frame destination channel */ + uint16_t is_channel; /* Frame destination channel */ sem_t is_sem; /* Used to wake up the waiting thread */ FAR const uint8_t *is_buffer; /* User buffer of data to send */ size_t is_buflen; /* Number of bytes in the is_buffer */ @@ -117,6 +117,7 @@ static uint16_t bluetooth_sendto_eventhandler(FAR struct net_driver_s *dev, BLUETOOTH_ADDRCOPY(&meta.bm_raddr, &pstate->is_destaddr); meta.bm_channel = pstate->is_channel; + meta.bm_proto = pstate->is_sock->s_proto; /* Get the Bluetooth MAC header length */ @@ -235,7 +236,6 @@ ssize_t psock_bluetooth_sendto(FAR struct socket *psock, FAR const void *buf, FAR const struct sockaddr *to, socklen_t tolen) { - FAR struct sockaddr_l2 *destaddr; FAR struct radio_driver_s *radio; FAR struct bluetooth_conn_s *conn; struct bluetooth_sendto_s state; @@ -262,10 +262,31 @@ ssize_t psock_bluetooth_sendto(FAR struct socket *psock, FAR const void *buf, /* Get the device driver that will service this transfer */ - radio = bluetooth_find_device(conn, &conn->bc_laddr); - if (radio == NULL) + if (psock->s_proto == BTPROTO_L2CAP) { - return -ENODEV; + radio = bluetooth_find_device(conn, &conn->bc_laddr); + if (radio == NULL) + { + return -ENODEV; + } + } + else if (psock->s_proto == BTPROTO_HCI) + { + /* TODO: should actually look among BT devices */ + + radio = + (FAR struct radio_driver_s *)netdev_findbyindex(conn->bc_ldev + 1); + + DEBUGASSERT(radio->r_dev.d_lltype == NET_LL_BLUETOOTH); + + if (radio == NULL) + { + return -ENODEV; + } + } + else + { + return -EOPNOTSUPP; } /* Perform the send operation */ @@ -290,9 +311,22 @@ ssize_t psock_bluetooth_sendto(FAR struct socket *psock, FAR const void *buf, /* Copy the destination address */ - destaddr = (FAR struct sockaddr_l2 *)to; - memcpy(&state.is_destaddr, &destaddr->l2_bdaddr, - sizeof(bt_addr_t)); + if (psock->s_proto == BTPROTO_L2CAP) + { + FAR struct sockaddr_l2 *destaddr = (FAR struct sockaddr_l2 *)to; + memcpy(&state.is_destaddr, &destaddr->l2_bdaddr, + sizeof(bt_addr_t)); + } + else if (psock->s_proto == BTPROTO_HCI) + { + FAR struct sockaddr_hci *destaddr = (FAR struct sockaddr_hci *)to; + state.is_channel = destaddr->hci_channel; + } + else + { + ret = -EOPNOTSUPP; + goto err_with_net; + } if (len > 0) { @@ -348,6 +382,12 @@ ssize_t psock_bluetooth_sendto(FAR struct socket *psock, FAR const void *buf, /* Return the number of bytes actually sent */ return state.is_sent; + +err_with_net: + nxsem_destroy(&state.is_sem); + net_unlock(); + + return ret; } #endif /* CONFIG_NET_BLUETOOTH */ diff --git a/net/bluetooth/bluetooth_sockif.c b/net/bluetooth/bluetooth_sockif.c index ba30746e1a..f1829e7ebe 100644 --- a/net/bluetooth/bluetooth_sockif.c +++ b/net/bluetooth/bluetooth_sockif.c @@ -294,6 +294,7 @@ static int bluetooth_connect(FAR struct socket *psock, btaddr = (FAR struct sockaddr_l2 *)addr; memcpy(&conn->bc_raddr, &btaddr->l2_bdaddr, sizeof(bt_addr_t)); conn->bc_channel = btaddr->l2_cid; + conn->bc_proto = psock->s_proto; } else { @@ -485,6 +486,8 @@ static int bluetooth_l2cap_bind(FAR struct socket *psock, conn = (FAR struct bluetooth_conn_s *)psock->s_conn; + conn->bc_proto = psock->s_proto; + /* Find the device associated with the requested address */ radio = bluetooth_find_device(conn, &iaddr->l2_bdaddr); @@ -549,6 +552,7 @@ static int bluetooth_hci_bind(FAR struct socket *psock, conn = (FAR struct bluetooth_conn_s *)psock->s_conn; + conn->bc_proto = psock->s_proto; conn->bc_channel = hciaddr->hci_channel; conn->bc_ldev = hciaddr->hci_dev; @@ -766,6 +770,7 @@ static ssize_t bluetooth_send(FAR struct socket *psock, FAR const void *buf, size_t len, int flags) { ssize_t ret; + DEBUGASSERT(psock != NULL || buf != NULL); /* Only SOCK_RAW is supported */ @@ -871,7 +876,7 @@ static ssize_t bluetooth_hci_send(FAR struct socket *psock, FAR const void *buf, size_t len, int flags) { -#warning Missing logic + /* We only support sendto() for HCI sockets */ return -EPFNOSUPPORT; } @@ -905,9 +910,9 @@ static ssize_t bluetooth_sendto(FAR struct socket *psock, { ssize_t ret; - /* Only SOCK_RAW on L2CAP is supported */ + /* Only SOCK_RAW is supported */ - if (psock->s_type == SOCK_RAW && psock->s_proto == BTPROTO_L2CAP) + if (psock->s_type == SOCK_RAW) { /* Raw packet send */ diff --git a/net/socket/sendmsg.c b/net/socket/sendmsg.c index a188b3ad42..c6513edb5d 100644 --- a/net/socket/sendmsg.c +++ b/net/socket/sendmsg.c @@ -105,7 +105,7 @@ ssize_t psock_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg, return -EBADF; } - /* Let logic specific to this address family handle the sendfrom() + /* Let logic specific to this address family handle the sendmsg() * operation. */ diff --git a/wireless/bluetooth/Kconfig b/wireless/bluetooth/Kconfig index c1cc691791..6bf11936d5 100644 --- a/wireless/bluetooth/Kconfig +++ b/wireless/bluetooth/Kconfig @@ -48,12 +48,19 @@ menuconfig WIRELESS_BLUETOOTH ---help--- This option enables Bluetooth Low Energy support. - NOTE: This selection is marked EXPERIMENTAL. It is incomplete and, - hence, untested. It still lacks any low-level Bluetooth drivers and - is missing the network interface driver. - if WIRELESS_BLUETOOTH +menuconfig WIRELESS_BLUETOOTH_HOST + bool "BLE Host Layer" + default y + ---help--- + This enables support for BLE host layer implementation. This can be + used to interface to a BLE controller via HCI protocol (either to a local + BLE link-layer or to an external device over HCI UART). + +if WIRELESS_BLUETOOTH_HOST +endif # WIRELESS_BLUETOOTH_HOST + config BLUETOOTH_MAX_CONN int "Maximum number of simultaneous connections" default 1 diff --git a/wireless/bluetooth/Make.defs b/wireless/bluetooth/Make.defs index 8ca7edf4f9..3fc56e8759 100644 --- a/wireless/bluetooth/Make.defs +++ b/wireless/bluetooth/Make.defs @@ -37,10 +37,18 @@ ifeq ($(CONFIG_WIRELESS_BLUETOOTH),y) # Include Bluetooth support -CSRCS += bt_atomic.c bt_att.c bt_buf.c bt_conn.c bt_gatt.c bt_hcicore.c -CSRCS += bt_ioctl.c bt_keys.c bt_l2cap.c bt_netdev.c bt_queue.c bt_smp.c +CSRCS += bt_buf.c bt_netdev.c bt_queue.c bt_hcicore.c + +ifeq ($(CONFIG_WIRELESS_BLUETOOTH_HOST),y) + +# Host-layer + +CSRCS += bt_atomic.c bt_att.c bt_conn.c bt_gatt.c +CSRCS += bt_ioctl.c bt_keys.c bt_l2cap.c bt_smp.c CSRCS += bt_uuid.c +endif + DEPPATH += --dep-path bluetooth VPATH += :bluetooth CFLAGS += ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)wireless$(DELIM)bluetooth} diff --git a/wireless/bluetooth/bt_buf.c b/wireless/bluetooth/bt_buf.c index 4c70b88d55..e4d760efde 100644 --- a/wireless/bluetooth/bt_buf.c +++ b/wireless/bluetooth/bt_buf.c @@ -388,9 +388,11 @@ FAR struct bt_buf_s *bt_buf_alloc(enum bt_buf_type_e type, void bt_buf_release(FAR struct bt_buf_s *buf) { +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST enum bt_buf_type_e type; - irqstate_t flags; uint16_t handle; +#endif + irqstate_t flags; wlinfo("buf %p ref %u type %d\n", buf, buf->ref, buf->type); @@ -400,8 +402,10 @@ void bt_buf_release(FAR struct bt_buf_s *buf) return; } +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST handle = buf->u.acl.handle; type = buf->type; +#endif /* Free the contained frame and return the container to the correct memory * pool. @@ -460,6 +464,7 @@ void bt_buf_release(FAR struct bt_buf_s *buf) wlinfo("Buffer freed: %p\n", buf); +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST if (type == BT_ACL_IN) { FAR struct bt_hci_cp_host_num_completed_packets_s *cp; @@ -484,6 +489,7 @@ void bt_buf_release(FAR struct bt_buf_s *buf) bt_hci_cmd_send(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS, buf); } +#endif } /**************************************************************************** diff --git a/wireless/bluetooth/bt_hcicore.c b/wireless/bluetooth/bt_hcicore.c index 859a52b627..e31cca797c 100644 --- a/wireless/bluetooth/bt_hcicore.c +++ b/wireless/bluetooth/bt_hcicore.c @@ -100,8 +100,12 @@ struct bt_dev_s g_btdev; * Private Data ****************************************************************************/ +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST static FAR struct bt_conn_cb_s *g_callback_list; static bt_le_scan_cb_t *g_scan_dev_found_cb; +#else +static struct bt_hci_cb_s *g_hci_cb; +#endif /* Lists of pending received messages. One for low priority input that is * processed on the low priority work queue and one for high priority @@ -229,6 +233,7 @@ static FAR struct bt_buf_s * return buf; } +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST static void bt_connected(FAR struct bt_conn_s *conn) { FAR struct bt_conn_cb_s *cb; @@ -982,6 +987,7 @@ static void hci_event(FAR struct bt_buf_s *buf) bt_buf_release(buf); } +#endif /**************************************************************************** * Name: hci_tx_kthread @@ -1075,6 +1081,7 @@ static void hci_rx_work(FAR void *arg) /* TODO: Hook monitor callback */ +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST switch (buf->type) { case BT_ACL_IN: @@ -1090,6 +1097,9 @@ static void hci_rx_work(FAR void *arg) bt_buf_release(buf); break; } +#else + g_hci_cb->received(buf, g_hci_cb->context); +#endif } } @@ -1131,6 +1141,7 @@ static void priority_rx_work(FAR void *arg) continue; } +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST bt_buf_consume(buf, sizeof(struct bt_hci_evt_hdr_s)); switch (hdr->evt) @@ -1151,11 +1162,15 @@ static void priority_rx_work(FAR void *arg) wlerr("Unknown event 0x%02x\n", hdr->evt); break; } +#else + UNUSED(hdr); - bt_buf_release(buf); + g_hci_cb->received(buf, g_hci_cb->context); +#endif } } +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST static void read_local_features_complete(FAR struct bt_buf_s *buf) { FAR struct bt_hci_rp_read_local_features_s *rp = (FAR void *)buf->data; @@ -1433,6 +1448,7 @@ static int hci_initialize(void) nxsem_init(&g_btdev.le_pkts_sem, 0, g_btdev.le_pkts); return 0; } +#endif /* threads, fifos and semaphores initialization */ @@ -1496,6 +1512,7 @@ int bt_initialize(void) return ret; } +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST ret = hci_initialize(); if (ret < 0) { @@ -1503,7 +1520,10 @@ int bt_initialize(void) return ret; } - return bt_l2cap_init(); + ret = bt_l2cap_init(); +#endif + + return ret; } /**************************************************************************** @@ -1582,6 +1602,8 @@ void bt_driver_unregister(FAR const struct bt_driver_s *btdev) * ****************************************************************************/ +/* TODO: rename to bt_receive? */ + void bt_hci_receive(FAR struct bt_buf_s *buf) { FAR struct bt_hci_evt_hdr_s *hdr; @@ -1652,6 +1674,8 @@ void bt_hci_receive(FAR struct bt_buf_s *buf) } } +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST + /**************************************************************************** * Name: bt_hci_cmd_create * @@ -2143,3 +2167,27 @@ FAR const char *bt_addr_le_str(FAR const bt_addr_le_t *addr) return str; } #endif /* CONFIG_DEBUG_WIRELESS_ERROR */ + +#else + +/**************************************************************************** + * Name: bt_hci_cb_register + * + * Description: + * Register callbacks to handle RAW HCI packets + * + * Input Parameters: + * cb - Instance of the callback structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void bt_hci_cb_register(FAR struct bt_hci_cb_s *cb) +{ + g_hci_cb = cb; +} + +#endif + diff --git a/wireless/bluetooth/bt_hcicore.h b/wireless/bluetooth/bt_hcicore.h index 946137e4c3..343dfc2723 100644 --- a/wireless/bluetooth/bt_hcicore.h +++ b/wireless/bluetooth/bt_hcicore.h @@ -72,10 +72,11 @@ struct bt_dev_s { - /* Local Bluetooth Device Address */ + /* Local Bluetooth Device Address */ - bt_addr_t bdaddr; + bt_addr_t bdaddr; +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST /* Controller version & manufacturer information */ uint8_t hci_version; @@ -104,6 +105,7 @@ struct bt_dev_s uint8_t le_pkts; uint16_t le_mtu; sem_t le_pkts_sem; +#endif /* Number of commands controller can accept */ @@ -127,6 +129,7 @@ struct bt_dev_s FAR const struct bt_driver_s *btdev; }; +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST /* Connection callback structure */ struct bt_conn_s; /* Forward reference */ @@ -138,7 +141,18 @@ struct bt_conn_cb_s CODE void (*connected)(FAR struct bt_conn_s *conn, FAR void *context); CODE void (*disconnected)(FAR struct bt_conn_s *conn, FAR void *context); }; +#else +/* RAW HCI packets callbacks */ +struct bt_hci_cb_s +{ + FAR void *context; + + CODE void (*received)(FAR struct bt_buf_s *buf, FAR void *context); +}; +#endif + +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST /**************************************************************************** * Name: bt_le_scan_cb_t * @@ -160,6 +174,7 @@ struct bt_conn_cb_s typedef CODE void bt_le_scan_cb_t(FAR const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type, FAR const uint8_t *adv_data, uint8_t len); +#endif /**************************************************************************** * Public Data @@ -171,6 +186,7 @@ extern struct bt_dev_s g_btdev; * Inline Functions ****************************************************************************/ +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST static inline int bt_addr_cmp(FAR const bt_addr_t *a, FAR const bt_addr_t *b) { return memcmp(a, b, sizeof(*a)); @@ -231,6 +247,8 @@ static inline bool bt_addr_le_is_identity(FAR const bt_addr_le_t *addr) struct bt_eir_s; /* Forward reference */ +#endif + /**************************************************************************** * Name: bt_initialize * @@ -284,6 +302,7 @@ int bt_driver_register(FAR const struct bt_driver_s *btdev); void bt_driver_unregister(FAR const struct bt_driver_s *btdev); +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST /**************************************************************************** * Name: bt_hci_cmd_create * @@ -409,5 +428,24 @@ int bt_le_scan_update(void); ****************************************************************************/ void bt_conn_cb_register(FAR struct bt_conn_cb_s *cb); +#else + +/**************************************************************************** + * Name: bt_hci_cb_register + * + * Description: + * Register callbacks to handle RAW HCI packets + * + * Input Parameters: + * cb - Instance of the callback structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void bt_hci_cb_register(FAR struct bt_hci_cb_s *cb); + +#endif #endif /* __WIRELESS_BLUETOOTH_BT_HDICORE_H */ diff --git a/wireless/bluetooth/bt_netdev.c b/wireless/bluetooth/bt_netdev.c index bc31c1d46c..bd64d6ea13 100644 --- a/wireless/bluetooth/bt_netdev.c +++ b/wireless/bluetooth/bt_netdev.c @@ -63,10 +63,15 @@ #include #include #include +#include #include "bt_hcicore.h" + +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST #include "bt_l2cap.h" #include "bt_conn.h" +#endif + #include "bt_ioctl.h" #if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_BLUETOOTH) @@ -125,8 +130,13 @@ struct btnet_driver_s bool bd_bifup; /* true:ifup false:ifdown */ struct wdog_s bd_txpoll; /* TX poll timer */ struct work_s bd_pollwork; /* Defer poll work to the work queue */ + +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST struct bt_conn_cb_s bd_hcicb; /* HCI connection status callbacks */ struct bt_l2cap_chan_s bd_l2capcb; /* L2CAP status callbacks */ +#else + struct bt_hci_cb_s bd_hcicb; /* HCI RAW packet callbacks */ +#endif }; /**************************************************************************** @@ -140,6 +150,7 @@ static inline void btnet_netmask(FAR struct net_driver_s *netdev); /* Bluetooth callback functions *********************************************/ +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST /* L2CAP callbacks */ static void btnet_l2cap_connected(FAR struct bt_conn_s *conn, @@ -157,6 +168,9 @@ static void btnet_hci_connected(FAR struct bt_conn_s *conn, FAR void *context); static void btnet_hci_disconnected(FAR struct bt_conn_s *conn, FAR void *context); +#else +static void btnet_hci_received(FAR struct bt_buf_s *buf, FAR void *context); +#endif /* Network interface support ************************************************/ @@ -187,6 +201,16 @@ static int btnet_req_data(FAR struct radio_driver_s *netdev, static int btnet_properties(FAR struct radio_driver_s *netdev, FAR struct radiodev_properties_s *properties); +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST +static int btnet_req_l2cap_data(FAR struct btnet_driver_s *priv, + FAR struct bluetooth_frame_meta_s *meta, + FAR struct iob_s *framelist); +#endif + +static int btnet_req_hci_data(FAR struct btnet_driver_s *priv, + FAR struct bluetooth_frame_meta_s *meta, + FAR struct iob_s *framelist); + /**************************************************************************** * Private Data ****************************************************************************/ @@ -276,6 +300,7 @@ static inline void btnet_netmask(FAR struct net_driver_s *netdev) #endif } +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST /**************************************************************************** * Name: btnet_hci_connect/disconnect/encrypt_change * @@ -475,6 +500,126 @@ static void btnet_hci_disconnected(FAR struct bt_conn_s *conn, wlinfo("Disconnected\n"); #warning Missing logic } +#else + +/**************************************************************************** + * Name: btnet_hci_received + * + * Description: + * This callback is called from the RX queue handling when an HCI + * packet is received from controller. + * + * Input Parameters: + * buf - The packet + * + * Returned Value: + * None + * + * Assumptions: + * No assumption should be made about the thread of execution that these + * are called from + * + ****************************************************************************/ + +static void btnet_hci_received(FAR struct bt_buf_s *buf, FAR void *context) +{ + FAR struct btnet_driver_s *priv; + FAR struct iob_s *frame; + struct bluetooth_frame_meta_s meta; + int ret = -ENODEV; + + wlinfo("Received frame\n"); + + DEBUGASSERT(buf != NULL && buf->frame != NULL); + + /* Detach the IOB frame from the buffer structure */ + + frame = buf->frame; + buf->frame = NULL; + + /* Ignore the frame if the network is not up */ + + priv = (FAR struct btnet_driver_s *)context; + if (!priv->bd_bifup) + { + wlwarn("WARNING: Dropped... Network is down\n"); + goto drop; + } + + /* Make sure that the size/offset data matches the buffer structure data. */ + + DEBUGASSERT(frame->io_offset == BLUETOOTH_H4_HDRLEN); + + /* Rearrange IOB to consider H4 header */ + + frame->io_len = buf->len + frame->io_offset; + frame->io_pktlen = buf->len + frame->io_offset; + frame->io_offset = 0; + + DEBUGASSERT(frame->io_len <= CONFIG_IOB_BUFSIZE); + + /* Write H4 header */ + + switch (buf->type) + { + case BT_EVT: + frame->io_data[0] = HCI_EVENT_PKT; + break; + case BT_ACL_IN: + frame->io_data[0] = HCI_ACLDATA_PKT; + break; + default: + wlerr("Bad HCI type: %i\n", buf->type); + goto drop; + break; + } + + /* Construct the frame meta data. + */ + + meta.bm_channel = HCI_CHANNEL_RAW; + meta.bm_proto = BTPROTO_HCI; + + /* Transfer the frame to the network logic */ + + net_lock(); + +#ifdef CONFIG_NET_BLUETOOTH + /* Invoke the PF_BLUETOOTH tap first. If the frame matches + * with a connected PF_BLUETOOTH socket, it will take the + * frame and return success. + */ + + ret = bluetooth_input(&priv->bd_dev, frame, (FAR void *)&meta); +#endif + +drop: + + /* Handle errors */ + + if (ret < 0) + { + iob_free(frame, IOBUSER_WIRELESS_BLUETOOTH); + + /* Increment statistics */ + + NETDEV_RXDROPPED(&priv->bd_dev.r_dev); + } + else + { + /* Increment statistics */ + + NETDEV_RXPACKETS(&priv->bd_dev.r_dev); + NETDEV_RXIPV6(&priv->bd_dev.r_dev); + } + + /* Release our reference on the buffer */ + + bt_buf_release(buf); + net_unlock(); +} + +#endif /**************************************************************************** * Name: btnet_txpoll_callback @@ -852,7 +997,26 @@ static int btnet_rmmac(FAR struct net_driver_s *netdev, static int btnet_get_mhrlen(FAR struct radio_driver_s *netdev, FAR const void *meta) { - /* Always report the maximum frame length. */ + const struct bluetooth_frame_meta_s *btmeta = meta; + + if (btmeta->bm_proto == BTPROTO_HCI) + { + /* the net device only requires the H4 header, the rest is already + * part of the packet + */ + + return BLUETOOTH_H4_HDRLEN; + } + else if (btmeta->bm_proto == BTPROTO_L2CAP) + { + /* Report the complete header size, since H4 + ACL + L2CAP header + * will not be part of the packet + */ + + /* TODO: correct? */ + + return BLUETOOTH_MAX_HDRLEN; + } return BLUETOOTH_MAX_HDRLEN; } @@ -880,10 +1044,6 @@ static int btnet_req_data(FAR struct radio_driver_s *netdev, { FAR struct btnet_driver_s *priv; FAR struct bluetooth_frame_meta_s *btmeta; - FAR struct bt_conn_s *conn; - FAR struct bt_buf_s *buf; - FAR struct iob_s *iob; - bt_addr_le_t peer; wlinfo("Received framelist\n"); DEBUGASSERT(priv != NULL && meta != NULL && framelist != NULL); @@ -891,6 +1051,52 @@ static int btnet_req_data(FAR struct radio_driver_s *netdev, priv = (FAR struct btnet_driver_s *)netdev; btmeta = (FAR struct bluetooth_frame_meta_s *)meta; + if (btmeta->bm_proto == BTPROTO_HCI) + { + return btnet_req_hci_data(priv, btmeta, framelist); + } +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST + else if (btmeta->bm_proto == BTPROTO_L2CAP) + { + return btnet_req_l2cap_data(priv, btmeta, framelist); + } +#endif + else + { + return -EOPNOTSUPP; + } + + return OK; +} + +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST +/**************************************************************************** + * Name: btnet_req_l2cap_data + * + * Description: + * Requests the transfer of a list of L2CAP frames to the MAC. + * + * Input Parameters: + * priv - Bluetooth network device + * btmeta - Bluetooth frame metadata + * framelist - Head of a list of L2CAP frames to be transferred. + * + * Returned Value: + * Zero (OK) returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +static int btnet_req_l2cap_data(FAR struct btnet_driver_s *priv, + FAR struct bluetooth_frame_meta_s *btmeta, + FAR struct iob_s *framelist) +{ + FAR struct bt_conn_s *conn; + bt_addr_le_t peer; + FAR struct iob_s *iob; + FAR struct bt_buf_s *buf; + UNUSED(priv); + /* Create a connection structure for this peer if one does not already * exist. * @@ -945,7 +1151,84 @@ static int btnet_req_data(FAR struct radio_driver_s *netdev, NETDEV_TXDONE(&priv->bd_dev.r_dev); } - UNUSED(priv); + return OK; +} +#endif + +/**************************************************************************** + * Name: btnet_req_hci_data + * + * Description: + * Requests the transfer of a list of HCI frames to the MAC. + * + * Input Parameters: + * priv - Bluetooth network device + * btmeta - Bluetooth frame metadata + * framelist - Head of a list of HCI frames to be transferred. + * + * Returned Value: + * Zero (OK) returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +static int btnet_req_hci_data(FAR struct btnet_driver_s *priv, + FAR struct bluetooth_frame_meta_s *meta, + FAR struct iob_s *framelist) +{ + FAR struct iob_s *iob; + FAR struct bt_buf_s *buf; + + /* Add the incoming list of frames to the MAC's outgoing queue */ + + for (iob = framelist; iob != NULL; iob = framelist) + { + /* Increment statistics */ + + NETDEV_TXPACKETS(&priv->bd_dev.r_dev); + + /* Remove the IOB from the queue */ + + framelist = iob->io_flink; + iob->io_flink = NULL; + + DEBUGASSERT(iob->io_offset == BLUETOOTH_H4_HDRLEN && + iob->io_len >= BLUETOOTH_H4_HDRLEN); + + /* Allocate a buffer to contain the IOB */ + + switch (iob->io_data[iob->io_offset]) + { + case HCI_ACLDATA_PKT: + iob->io_offset += 1; + buf = bt_buf_alloc(BT_ACL_OUT, iob, 0); + break; + case HCI_COMMAND_PKT: + iob->io_offset += 1; + buf = bt_buf_alloc(BT_CMD, iob, 0); + break; + case HCI_EVENT_PKT: + iob->io_offset += 1; + buf = bt_buf_alloc(BT_EVT, iob, 0); + break; + default: + return -EOPNOTSUPP; + break; + } + + if (buf == NULL) + { + wlerr("ERROR: Failed to allocate buffer container\n"); + return -ENOMEM; + } + + g_btdev.btdev->send(g_btdev.btdev, buf); + + /* Transfer the frame to the Bluetooth stack. */ + + NETDEV_TXDONE(&priv->bd_dev.r_dev); + } + return OK; } @@ -1009,8 +1292,13 @@ int bt_netdev_register(FAR const struct bt_driver_s *btdev) FAR struct btnet_driver_s *priv; FAR struct radio_driver_s *radio; FAR struct net_driver_s *netdev; + +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST FAR struct bt_conn_cb_s *hcicb; FAR struct bt_l2cap_chan_s *l2capcb; +#else + FAR struct bt_hci_cb_s *hcicb; +#endif int ret; /* Get the interface structure associated with this interface number. */ @@ -1035,13 +1323,14 @@ int bt_netdev_register(FAR const struct bt_driver_s *btdev) netdev->d_addmac = btnet_addmac; /* Add multicast MAC address */ netdev->d_rmmac = btnet_rmmac; /* Remove multicast MAC address */ #endif - #ifdef CONFIG_NETDEV_IOCTL +#if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_WIRELESS_BLUETOOTH_HOST) netdev->d_ioctl = btnet_ioctl; /* Handle network IOCTL commands */ #endif netdev->d_private = priv; /* Used to recover private state from netdev */ /* Connection status change callbacks */ +#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST hcicb = &priv->bd_hcicb; hcicb->context = priv; hcicb->connected = btnet_hci_connected; @@ -1059,6 +1348,13 @@ int bt_netdev_register(FAR const struct bt_driver_s *btdev) l2capcb->receive = btnet_l2cap_receive; bt_l2cap_chan_default(l2capcb); +#else + hcicb = &priv->bd_hcicb; + hcicb->context = priv; + hcicb->received = btnet_hci_received; + + bt_hci_cb_register(hcicb); +#endif /* Setup a locking semaphore for exclusive device driver access */