xref: /btstack/port/freebsd-netgraph/hci_transport_netgraph.c (revision de13ba803acdb54c41ebfbca4e795757f719a2dd)
122029648SMatthias Ringwald /*
222029648SMatthias Ringwald  * Copyright (C) 2023 BlueKitchen GmbH
322029648SMatthias Ringwald  *
422029648SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
522029648SMatthias Ringwald  * modification, are permitted provided that the following conditions
622029648SMatthias Ringwald  * are met:
722029648SMatthias Ringwald  *
822029648SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
922029648SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
1022029648SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
1122029648SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
1222029648SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
1322029648SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
1422029648SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
1522029648SMatthias Ringwald  *    from this software without specific prior written permission.
1622029648SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
1722029648SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
1822029648SMatthias Ringwald  *    monetary gain.
1922029648SMatthias Ringwald  *
2022029648SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
2122029648SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2222029648SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2322029648SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
2422029648SMatthias Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2522029648SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2622029648SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
2722029648SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2822029648SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2922029648SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
3022029648SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3122029648SMatthias Ringwald  * SUCH DAMAGE.
3222029648SMatthias Ringwald  *
3322029648SMatthias Ringwald  * Please inquire about commercial licensing options at
3422029648SMatthias Ringwald  * [email protected]
3522029648SMatthias Ringwald  *
3622029648SMatthias Ringwald  */
3722029648SMatthias Ringwald 
3822029648SMatthias Ringwald #define BTSTACK_FILE__ "hci_transport_netgraph.c"
3922029648SMatthias Ringwald 
4022029648SMatthias Ringwald #include "hci_transport_netgraph.h"
4122029648SMatthias Ringwald 
4222029648SMatthias Ringwald #include "btstack_bool.h"
4322029648SMatthias Ringwald #include "btstack_config.h"
4422029648SMatthias Ringwald #include "btstack_debug.h"
4522029648SMatthias Ringwald #include "btstack_event.h"
4622029648SMatthias Ringwald #include "btstack_run_loop.h"
4722029648SMatthias Ringwald #include "hci_transport.h"
4822029648SMatthias Ringwald #include "hci.h"
4922029648SMatthias Ringwald 
5022029648SMatthias Ringwald #include <err.h>
5122029648SMatthias Ringwald #include <errno.h>
5222029648SMatthias Ringwald #include <stdint.h>
5322029648SMatthias Ringwald #include <stdio.h>
5422029648SMatthias Ringwald #include <stdlib.h>
5522029648SMatthias Ringwald #include <string.h>
5622029648SMatthias Ringwald #include <unistd.h>
5722029648SMatthias Ringwald 
5822029648SMatthias Ringwald #include <sys/bitstring.h>
5922029648SMatthias Ringwald #include <sys/types.h>
6022029648SMatthias Ringwald #include <sys/socket.h>
6122029648SMatthias Ringwald 
6222029648SMatthias Ringwald // avoid warning by /usr/include/netgraph/bluetooth/include/ng_btsocket.h
6322029648SMatthias Ringwald #define L2CAP_SOCKET_CHECKED
6422029648SMatthias Ringwald #include <bluetooth.h>
6522029648SMatthias Ringwald #include <netgraph.h>
6622029648SMatthias Ringwald #include <netgraph/bluetooth/include/ng_hci.h>
6722029648SMatthias Ringwald #include <netgraph/bluetooth/include/ng_l2cap.h>
6822029648SMatthias Ringwald #include <netgraph/bluetooth/include/ng_btsocket.h>
6922029648SMatthias Ringwald 
7022029648SMatthias Ringwald // hci packet handler
7122029648SMatthias Ringwald static void (*hci_transport_netgraph_packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size);
7222029648SMatthias Ringwald 
7322029648SMatthias Ringwald // data source for integration with BTstack Runloop
7422029648SMatthias Ringwald static btstack_data_source_t hci_transport_netgraph_data_source_hci_raw;
7522029648SMatthias Ringwald 
7622029648SMatthias Ringwald // block write
7722029648SMatthias Ringwald static uint8_t         hci_transport_netgraph_write_packet_type;
7822029648SMatthias Ringwald static int             hci_transport_netgraph_write_bytes_len;
7922029648SMatthias Ringwald static const uint8_t * hci_transport_netgraph_write_bytes_data;
8022029648SMatthias Ringwald 
8122029648SMatthias Ringwald // assert pre-buffer for packet type is available
8222029648SMatthias Ringwald #if !defined(HCI_OUTGOING_PRE_BUFFER_SIZE) || (HCI_OUTGOING_PRE_BUFFER_SIZE == 0)
8322029648SMatthias Ringwald #error HCI_OUTGOING_PRE_BUFFER_SIZE not defined. Please update hci.h
8422029648SMatthias Ringwald #endif
8522029648SMatthias Ringwald 
8622029648SMatthias Ringwald typedef enum {
8722029648SMatthias Ringwald     TX_OFF,
8822029648SMatthias Ringwald     TX_IDLE,
8922029648SMatthias Ringwald     TX_W4_PACKET_SENT,
9022029648SMatthias Ringwald } TX_STATE;
9122029648SMatthias Ringwald 
9222029648SMatthias Ringwald // write state
9322029648SMatthias Ringwald static TX_STATE hci_transport_netgraph_tx_state;
9422029648SMatthias Ringwald 
9522029648SMatthias Ringwald // incoming packet buffer
9622029648SMatthias Ringwald static uint8_t hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE + HCI_INCOMING_PACKET_BUFFER_SIZE + 1]; // packet type + max(acl header + acl payload, event header + event data)
9722029648SMatthias Ringwald static uint8_t * hci_packet = &hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE];
9822029648SMatthias Ringwald 
9922029648SMatthias Ringwald // Netgraph node
10022029648SMatthias Ringwald const char * hci_node_name = "ubt0hci";
10122029648SMatthias Ringwald 
10222029648SMatthias Ringwald // Control and Data socket for BTstack Netgraph node
10322029648SMatthias Ringwald static int hci_transport_netgraph_hci_raw_control_socket;
10422029648SMatthias Ringwald static int hci_transport_netgraph_hci_raw_data_socket;
10522029648SMatthias Ringwald 
10622029648SMatthias Ringwald // Track HCI Netgraph Initialization
10722029648SMatthias Ringwald #define HCI_TODO_READ_BD_ADDR                   1
10822029648SMatthias Ringwald #define HCI_TODO_READ_LOCAL_SUPPORTED_FEATURES  2
10922029648SMatthias Ringwald #define HCI_TODO_READ_BUFFER_SIZE               4
11022029648SMatthias Ringwald 
11122029648SMatthias Ringwald static uint8_t hci_transport_netgraph_hci_todo_init;
11222029648SMatthias Ringwald 
hci_transport_netgraph_process_write(btstack_data_source_t * ds)11322029648SMatthias Ringwald static void hci_transport_netgraph_process_write(btstack_data_source_t *ds) {
11422029648SMatthias Ringwald 
11522029648SMatthias Ringwald     if (hci_transport_netgraph_write_bytes_len == 0) return;
11622029648SMatthias Ringwald 
11722029648SMatthias Ringwald     const char * hook = NULL;
11822029648SMatthias Ringwald     switch (hci_transport_netgraph_write_packet_type){
11922029648SMatthias Ringwald         case HCI_COMMAND_DATA_PACKET:
12022029648SMatthias Ringwald             hook = "raw";
12122029648SMatthias Ringwald             break;
12222029648SMatthias Ringwald         case HCI_ACL_DATA_PACKET:
12322029648SMatthias Ringwald             hook = "acl";
12422029648SMatthias Ringwald             break;
12522029648SMatthias Ringwald         default:
12622029648SMatthias Ringwald             btstack_unreachable();
12722029648SMatthias Ringwald             break;
12822029648SMatthias Ringwald     }
12922029648SMatthias Ringwald 
13022029648SMatthias Ringwald     int res = NgSendData(ds->source.fd, hook, hci_transport_netgraph_write_bytes_data, hci_transport_netgraph_write_bytes_len);
13122029648SMatthias Ringwald 
13222029648SMatthias Ringwald     if (res < 0){
13322029648SMatthias Ringwald         log_error("send data via hook %s returned error %d", hook, errno);
13422029648SMatthias Ringwald         btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
13522029648SMatthias Ringwald         return;
13622029648SMatthias Ringwald     }
13722029648SMatthias Ringwald 
13822029648SMatthias Ringwald     btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
13922029648SMatthias Ringwald 
14022029648SMatthias Ringwald     hci_transport_netgraph_tx_state = TX_IDLE;
14122029648SMatthias Ringwald     hci_transport_netgraph_write_bytes_len = 0;
14222029648SMatthias Ringwald     hci_transport_netgraph_write_bytes_data = NULL;
14322029648SMatthias Ringwald 
14422029648SMatthias Ringwald     // notify upper stack that it can send again
14522029648SMatthias Ringwald     static const uint8_t packet_sent_event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
14622029648SMatthias Ringwald     hci_transport_netgraph_packet_handler(HCI_EVENT_PACKET, (uint8_t *) &packet_sent_event[0], sizeof(packet_sent_event));
14722029648SMatthias Ringwald }
14822029648SMatthias Ringwald 
hci_transport_netgraph_process_read(btstack_data_source_t * ds)14922029648SMatthias Ringwald static void hci_transport_netgraph_process_read(btstack_data_source_t * ds) {
15022029648SMatthias Ringwald     // read complete HCI packet
15122029648SMatthias Ringwald     char hook[NG_NODESIZ];
15222029648SMatthias Ringwald     int bytes_read = NgRecvData(ds->source.fd, (u_char *)  hci_packet, HCI_INCOMING_PACKET_BUFFER_SIZE + 1, hook);
15322029648SMatthias Ringwald 
15422029648SMatthias Ringwald     if (bytes_read < 0){
15522029648SMatthias Ringwald         log_error("Read failed %d", (int) bytes_read);
15622029648SMatthias Ringwald     } else {
15722029648SMatthias Ringwald 
15822029648SMatthias Ringwald         // ignore 'echo' - only accept hci events from 'raw' hook and acl packet from 'acl' hook
15922029648SMatthias Ringwald         // - HCI CMDs that are received over 'raw' hook are sent back via 'raw' hook
16022029648SMatthias Ringwald         if (strcmp(hook, "raw") == 0){
16122029648SMatthias Ringwald             if (hci_packet[0] != HCI_EVENT_PACKET){
16222029648SMatthias Ringwald                 return;
16322029648SMatthias Ringwald             }
16422029648SMatthias Ringwald         }
16522029648SMatthias Ringwald         // - ACL Packets that are received from driver are also sent via 'raw' hook
16622029648SMatthias Ringwald         if (strcmp(hook, "acl") == 0){
16722029648SMatthias Ringwald             if (hci_packet[0] != HCI_ACL_DATA_PACKET){
16822029648SMatthias Ringwald                 return;
16922029648SMatthias Ringwald             }
17022029648SMatthias Ringwald         }
17122029648SMatthias Ringwald 
17222029648SMatthias Ringwald         // track HCI Event Complete for init commands
17322029648SMatthias Ringwald         if (hci_packet[0] == HCI_EVENT_PACKET){
17422029648SMatthias Ringwald             if (hci_event_packet_get_type(&hci_packet[1]) == HCI_EVENT_COMMAND_COMPLETE){
17522029648SMatthias Ringwald                 uint8_t todos_before = hci_transport_netgraph_hci_todo_init;
17622029648SMatthias Ringwald                 switch (hci_event_command_complete_get_command_opcode(&hci_packet[1])){
17722029648SMatthias Ringwald                     case HCI_OPCODE_HCI_RESET:
17822029648SMatthias Ringwald                         hci_transport_netgraph_hci_todo_init = HCI_TODO_READ_BD_ADDR | HCI_TODO_READ_LOCAL_SUPPORTED_FEATURES | HCI_TODO_READ_BUFFER_SIZE;
17922029648SMatthias Ringwald                         break;
18022029648SMatthias Ringwald                     case HCI_OPCODE_HCI_READ_BD_ADDR:
18122029648SMatthias Ringwald                         hci_transport_netgraph_hci_todo_init &= ~HCI_TODO_READ_BD_ADDR;
18222029648SMatthias Ringwald                         break;
18322029648SMatthias Ringwald                     case HCI_OPCODE_HCI_READ_LOCAL_SUPPORTED_FEATURES:
18422029648SMatthias Ringwald                         hci_transport_netgraph_hci_todo_init &= ~HCI_TODO_READ_LOCAL_SUPPORTED_FEATURES;
18522029648SMatthias Ringwald                         break;
18622029648SMatthias Ringwald                     case HCI_OPCODE_HCI_READ_BUFFER_SIZE:
18722029648SMatthias Ringwald                         hci_transport_netgraph_hci_todo_init &= ~HCI_TODO_READ_BUFFER_SIZE;
18822029648SMatthias Ringwald                         break;
18922029648SMatthias Ringwald                     default:
19022029648SMatthias Ringwald                         break;
19122029648SMatthias Ringwald                 }
19222029648SMatthias Ringwald                 if ((todos_before != 0) && (hci_transport_netgraph_hci_todo_init == 0)){
19322029648SMatthias Ringwald                     // tell ubt0hci to disconnect acl hook to ubt0l2cap
19422029648SMatthias Ringwald                     char path[NG_NODESIZ];
19522029648SMatthias Ringwald                     snprintf(path, sizeof(path), "%s:", hci_node_name);
19622029648SMatthias Ringwald                     if (NgSendAsciiMsg(hci_transport_netgraph_hci_raw_control_socket, path, "%s", "init") < 0) {
19722029648SMatthias Ringwald                         log_error("Failed to send init to %s", path);
19822029648SMatthias Ringwald                     }
19922029648SMatthias Ringwald                 }
20022029648SMatthias Ringwald             }
20122029648SMatthias Ringwald         }
20222029648SMatthias Ringwald 
20322029648SMatthias Ringwald         uint16_t packet_len = bytes_read-1u;
20422029648SMatthias Ringwald         hci_transport_netgraph_packet_handler(hci_packet[0], &hci_packet[1], packet_len);
20522029648SMatthias Ringwald     }
20622029648SMatthias Ringwald }
20722029648SMatthias Ringwald 
hci_transport_netgraph_process(btstack_data_source_t * ds,btstack_data_source_callback_type_t callback_type)20822029648SMatthias Ringwald static void hci_transport_netgraph_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
20922029648SMatthias Ringwald     if (ds->source.fd < 0) return;
21022029648SMatthias Ringwald     switch (callback_type){
21122029648SMatthias Ringwald         case DATA_SOURCE_CALLBACK_READ:
21222029648SMatthias Ringwald             hci_transport_netgraph_process_read(ds);
21322029648SMatthias Ringwald             break;
21422029648SMatthias Ringwald         case DATA_SOURCE_CALLBACK_WRITE:
21522029648SMatthias Ringwald             hci_transport_netgraph_process_write(ds);
21622029648SMatthias Ringwald             break;
21722029648SMatthias Ringwald         default:
21822029648SMatthias Ringwald             break;
21922029648SMatthias Ringwald     }
22022029648SMatthias Ringwald }
22122029648SMatthias Ringwald 
22222029648SMatthias Ringwald // TODO: could pass device name
hci_transport_netgraph_init(const void * transport_config)22322029648SMatthias Ringwald static void hci_transport_netgraph_init (const void *transport_config){
22422029648SMatthias Ringwald     log_info("init");
22522029648SMatthias Ringwald 
22622029648SMatthias Ringwald     btstack_assert(transport_config != NULL);
22722029648SMatthias Ringwald 
22822029648SMatthias Ringwald     // extract netgraph device name
22922029648SMatthias Ringwald     hci_transport_config_netgraph_t * hci_transport_config_netgraph = (hci_transport_config_netgraph_t*) transport_config;
23022029648SMatthias Ringwald     hci_node_name = hci_transport_config_netgraph->device_name;
23122029648SMatthias Ringwald 
23222029648SMatthias Ringwald     // set state to off
23322029648SMatthias Ringwald     hci_transport_netgraph_tx_state = TX_OFF;
234*de13ba80SMatthias Ringwald 
235*de13ba80SMatthias Ringwald     // reset sockets file descriptors
236*de13ba80SMatthias Ringwald     hci_transport_netgraph_hci_raw_control_socket = -1;
237*de13ba80SMatthias Ringwald     hci_transport_netgraph_hci_raw_data_socket    = -1;
23822029648SMatthias Ringwald }
23922029648SMatthias Ringwald 
hci_transport_netgraph_open(void)24022029648SMatthias Ringwald static int hci_transport_netgraph_open(void) {
24122029648SMatthias Ringwald 
24222029648SMatthias Ringwald     log_info("open(%s)", hci_node_name);
24322029648SMatthias Ringwald 
24422029648SMatthias Ringwald     int res;
24522029648SMatthias Ringwald     struct ngm_rmhook rmh;
24622029648SMatthias Ringwald     struct ngm_connect con;
24722029648SMatthias Ringwald     char path[NG_NODESIZ];
24822029648SMatthias Ringwald     char btstack_node_hci_raw_name[NG_NODESIZ];
24922029648SMatthias Ringwald 
25022029648SMatthias Ringwald     // create hci_raw netgraph node
25122029648SMatthias Ringwald     snprintf(btstack_node_hci_raw_name, sizeof(btstack_node_hci_raw_name), "btstack");
25222029648SMatthias Ringwald     if (NgMkSockNode(btstack_node_hci_raw_name, &hci_transport_netgraph_hci_raw_control_socket, &hci_transport_netgraph_hci_raw_data_socket) < 0){
25322029648SMatthias Ringwald         log_error("Cannot create netgraph node '%s'", btstack_node_hci_raw_name);
25422029648SMatthias Ringwald         return -1;
25522029648SMatthias Ringwald     }
25622029648SMatthias Ringwald 
25722029648SMatthias Ringwald     // tell hci node to disconnect raw hook to btsock_hci_raw (ignore result)
25822029648SMatthias Ringwald     snprintf(path, sizeof(path), "%s:", hci_node_name);
25922029648SMatthias Ringwald     strncpy(rmh.ourhook, "raw", sizeof(rmh.ourhook));
26022029648SMatthias Ringwald     res = NgSendMsg(hci_transport_netgraph_hci_raw_control_socket, path, NGM_GENERIC_COOKIE,
26122029648SMatthias Ringwald                         NGM_RMHOOK, &rmh, sizeof(rmh));
26222029648SMatthias Ringwald     log_info("Remove HCI RAW Hook: %d", res);
26322029648SMatthias Ringwald 
26422029648SMatthias Ringwald     // tell hci node to disconnect acl hook to ubt0l2cap (ignore result)
26522029648SMatthias Ringwald     snprintf(path, sizeof(path), "%s:", hci_node_name);
26622029648SMatthias Ringwald     strncpy(rmh.ourhook, "acl", sizeof(rmh.ourhook));
26722029648SMatthias Ringwald     res = NgSendMsg(hci_transport_netgraph_hci_raw_control_socket, path, NGM_GENERIC_COOKIE,
26822029648SMatthias Ringwald                     NGM_RMHOOK, &rmh, sizeof(rmh));
26922029648SMatthias Ringwald     log_info("Remove ACL Hook: %d", res);
27022029648SMatthias Ringwald 
27122029648SMatthias Ringwald     // connect ubth0hci/raw hook
27222029648SMatthias Ringwald     snprintf(path, sizeof(path), "%s:",         btstack_node_hci_raw_name);
27322029648SMatthias Ringwald     snprintf(con.path, sizeof(con.path), "%s:", hci_node_name);
27422029648SMatthias Ringwald     strncpy(con.ourhook,  "raw", sizeof(con.ourhook));
27522029648SMatthias Ringwald     strncpy(con.peerhook, "raw", sizeof(con.peerhook));
27622029648SMatthias Ringwald     if (NgSendMsg(hci_transport_netgraph_hci_raw_control_socket, path, NGM_GENERIC_COOKIE,
27722029648SMatthias Ringwald                   NGM_CONNECT, &con, sizeof(con)) < 0) {
27822029648SMatthias Ringwald         log_error("Cannot connect %s%s to %s%s", path, con.ourhook, con.path, con.peerhook);
27922029648SMatthias Ringwald         return -1;
28022029648SMatthias Ringwald     }
28122029648SMatthias Ringwald 
28222029648SMatthias Ringwald     // connect ubth0hci/acl hook
28322029648SMatthias Ringwald     snprintf(path, sizeof(path), "%s:",         btstack_node_hci_raw_name);
28422029648SMatthias Ringwald     snprintf(con.path, sizeof(con.path), "%s:", hci_node_name);
28522029648SMatthias Ringwald     strncpy(con.ourhook,  "acl", sizeof(con.ourhook));
28622029648SMatthias Ringwald     strncpy(con.peerhook, "acl", sizeof(con.peerhook));
28722029648SMatthias Ringwald     if (NgSendMsg(hci_transport_netgraph_hci_raw_control_socket, path, NGM_GENERIC_COOKIE,
28822029648SMatthias Ringwald                   NGM_CONNECT, &con, sizeof(con)) < 0) {
28922029648SMatthias Ringwald         log_error("Cannot connect %s%s to %s%s", path, con.ourhook, con.path, con.peerhook);
29022029648SMatthias Ringwald         return -1;
29122029648SMatthias Ringwald     }
29222029648SMatthias Ringwald 
29322029648SMatthias Ringwald     // set up HCI RAW data_source
29422029648SMatthias Ringwald     btstack_run_loop_set_data_source_fd(&hci_transport_netgraph_data_source_hci_raw, hci_transport_netgraph_hci_raw_data_socket);
29522029648SMatthias Ringwald     btstack_run_loop_set_data_source_handler(&hci_transport_netgraph_data_source_hci_raw, &hci_transport_netgraph_process);
29622029648SMatthias Ringwald     btstack_run_loop_add_data_source(&hci_transport_netgraph_data_source_hci_raw);
29722029648SMatthias Ringwald     btstack_run_loop_enable_data_source_callbacks(&hci_transport_netgraph_data_source_hci_raw, DATA_SOURCE_CALLBACK_READ);
29822029648SMatthias Ringwald 
29922029648SMatthias Ringwald     // init tx state machines
30022029648SMatthias Ringwald     hci_transport_netgraph_tx_state = TX_IDLE;
30122029648SMatthias Ringwald 
30222029648SMatthias Ringwald     return 0;
30322029648SMatthias Ringwald }
30422029648SMatthias Ringwald 
hci_transport_netgraph_close(void)30522029648SMatthias Ringwald static int hci_transport_netgraph_close(void){
306*de13ba80SMatthias Ringwald     // first remove data source
30722029648SMatthias Ringwald     btstack_run_loop_remove_data_source(&hci_transport_netgraph_data_source_hci_raw);
30822029648SMatthias Ringwald 
309*de13ba80SMatthias Ringwald     log_info("Close Netgraph sockets %u and %u", hci_transport_netgraph_hci_raw_control_socket, hci_transport_netgraph_hci_raw_data_socket);
310*de13ba80SMatthias Ringwald 
31122029648SMatthias Ringwald     // then close device
312*de13ba80SMatthias Ringwald     close(hci_transport_netgraph_hci_raw_control_socket);
313*de13ba80SMatthias Ringwald     close(hci_transport_netgraph_hci_raw_data_socket);
314*de13ba80SMatthias Ringwald 
315*de13ba80SMatthias Ringwald     // and reset file descriptors
316*de13ba80SMatthias Ringwald     hci_transport_netgraph_hci_raw_control_socket = -1;
317*de13ba80SMatthias Ringwald     hci_transport_netgraph_hci_raw_data_socket    = -1;
31822029648SMatthias Ringwald     return 0;
31922029648SMatthias Ringwald }
32022029648SMatthias Ringwald 
hci_transport_netgraph_register_packet_handler(void (* handler)(uint8_t packet_type,uint8_t * packet,uint16_t size))32122029648SMatthias Ringwald static void hci_transport_netgraph_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
32222029648SMatthias Ringwald     hci_transport_netgraph_packet_handler = handler;
32322029648SMatthias Ringwald }
32422029648SMatthias Ringwald 
hci_transport_netgraph_can_send_now(uint8_t packet_type)32522029648SMatthias Ringwald static int hci_transport_netgraph_can_send_now(uint8_t packet_type){
32622029648SMatthias Ringwald     UNUSED(packet_type);
32722029648SMatthias Ringwald     return hci_transport_netgraph_tx_state == TX_IDLE;
32822029648SMatthias Ringwald }
32922029648SMatthias Ringwald 
hci_transport_netgraph_send_packet(uint8_t packet_type,uint8_t * packet,int size)33022029648SMatthias Ringwald static int hci_transport_netgraph_send_packet(uint8_t packet_type, uint8_t * packet, int size) {
33122029648SMatthias Ringwald     btstack_assert(hci_transport_netgraph_write_bytes_len == 0);
33222029648SMatthias Ringwald 
33322029648SMatthias Ringwald     // store packet type before actual data and increase size
33422029648SMatthias Ringwald     uint8_t * buffer = &packet[-1];
33522029648SMatthias Ringwald     uint32_t  buffer_size = size + 1;
33622029648SMatthias Ringwald     buffer[0] = packet_type;
33722029648SMatthias Ringwald 
33822029648SMatthias Ringwald     // setup async write
33922029648SMatthias Ringwald     hci_transport_netgraph_write_bytes_data = buffer;
34022029648SMatthias Ringwald     hci_transport_netgraph_write_bytes_len  = buffer_size;
34122029648SMatthias Ringwald     hci_transport_netgraph_write_packet_type = packet_type;
34222029648SMatthias Ringwald     hci_transport_netgraph_tx_state = TX_W4_PACKET_SENT;
34322029648SMatthias Ringwald 
34422029648SMatthias Ringwald     btstack_run_loop_enable_data_source_callbacks(&hci_transport_netgraph_data_source_hci_raw, DATA_SOURCE_CALLBACK_WRITE);
34522029648SMatthias Ringwald     return 0;
34622029648SMatthias Ringwald }
34722029648SMatthias Ringwald 
34822029648SMatthias Ringwald static const hci_transport_t hci_transport_netgraph = {
34922029648SMatthias Ringwald     .name = "Netgraph",
35022029648SMatthias Ringwald     .init = &hci_transport_netgraph_init,
35122029648SMatthias Ringwald     .open = &hci_transport_netgraph_open,
35222029648SMatthias Ringwald     .close = &hci_transport_netgraph_close,
35322029648SMatthias Ringwald     .register_packet_handler = &hci_transport_netgraph_register_packet_handler,
35422029648SMatthias Ringwald     .can_send_packet_now = &hci_transport_netgraph_can_send_now,
35522029648SMatthias Ringwald     .send_packet = &hci_transport_netgraph_send_packet
35622029648SMatthias Ringwald };
35722029648SMatthias Ringwald 
hci_transport_netgraph_instance(void)35822029648SMatthias Ringwald const hci_transport_t * hci_transport_netgraph_instance(void) {
35922029648SMatthias Ringwald     return &hci_transport_netgraph;
36022029648SMatthias Ringwald }
361