123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959 |
- /****************************************************************************
- * wireless/bluetooth/bt_ioctl.c
- * Bluetooth network IOCTL handler
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- ****************************************************************************/
- /****************************************************************************
- * Included Files
- ****************************************************************************/
- #include <nuttx/config.h>
- #include <assert.h>
- #include <errno.h>
- #include <debug.h>
- #include <nuttx/wqueue.h>
- #include <nuttx/semaphore.h>
- #include <nuttx/net/netdev.h>
- #include <nuttx/net/bluetooth.h>
- #include <nuttx/wireless/bluetooth/bt_core.h>
- #include <nuttx/wireless/bluetooth/bt_hci.h>
- #include <nuttx/wireless/bluetooth/bt_ioctl.h>
- #include "bt_hcicore.h"
- #include "bt_conn.h"
- #include "bt_ioctl.h"
- #ifdef CONFIG_NETDEV_IOCTL /* Not optional! */
- /****************************************************************************
- * Private Types
- ****************************************************************************/
- /* These structures encapsulate all globals used by the IOCTL logic. */
- /* Scan state variables */
- struct btnet_scanstate_s
- {
- sem_t bs_exclsem; /* Manages exclusive access */
- volatile bool bs_scanning; /* True: Scanning in progress */
- volatile uint8_t bs_head; /* Head of circular list (for removal) */
- uint8_t bs_tail; /* Tail of circular list (for addition) */
- struct bt_scanresponse_s bs_rsp[CONFIG_BLUETOOTH_MAXSCANRESULT];
- };
- /* Discovery state variables. NOTE: This function must be cast-compatible
- * with struct bt_gatt_discover_params_s.
- */
- struct btnet_discoverstate_s
- {
- struct bt_gatt_discover_params_s bd_params;
- struct bt_uuid_s bd_uuid; /* Discovery UUID */
- sem_t bd_donesem; /* Manages exclusive access */
- };
- /* GATT read state variables. */
- struct btnet_rdstate_s
- {
- struct btreq_s *rd_btreq;
- uint8_t rd_result; /* The result of the read */
- sem_t rd_donesem; /* Manages exclusive access */
- };
- /* GATT write state variables. */
- struct btnet_wrstate_s
- {
- struct btreq_s *wr_btreq;
- uint8_t wr_result; /* The result of the read */
- sem_t wr_donesem; /* Manages exclusive access */
- };
- /****************************************************************************
- * Private Data
- ****************************************************************************/
- /* At present only a single Bluetooth device is supported. So we can simply
- * maintain the pending scan, discovery, MTU exchange, read and write states
- * as globals.
- *
- * NOTE: This limits to a single Bluetooth device with one concurrent scan
- * action, one concurrent MTU exchange, one concurrent discovery action,
- * etc.
- *
- * REVISIT: A fix might be to (1) allocate instances on each IOCTL command
- * the starts an operation, keeping the allocated structures in a list. (2)
- * Return a reference number with each such command that starts an
- * operation. (3) That reference number would then be used in each IOCTL
- * command that gets the result of the requested operation. (4) The
- * allocated instance would be freed when either: (a) the result has been
- * returned or (b) it has expired without being harvested. This implies
- * a timer that runs while there are pending operations in order to expire
- * the unharvested results.
- */
- static struct btnet_scanstate_s g_scanstate;
- /****************************************************************************
- * Private Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: btnet_scan_callback
- *
- * Description:
- * This is an HCI callback function. HCI provides scan result data via
- * this callback function. The scan result data will be added to the
- * cached scan results.
- *
- * Input Parameters:
- * Scan result data
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
- static void btnet_scan_callback(FAR const bt_addr_le_t *addr,
- int8_t rssi, uint8_t adv_type,
- FAR const uint8_t *adv_data, uint8_t len)
- {
- FAR struct bt_scanresponse_s *rsp;
- uint8_t nexttail;
- uint8_t head;
- uint8_t tail;
- int ret;
- if (!g_scanstate.bs_scanning)
- {
- wlerr("ERROR: Results received while not scanning\n");
- return;
- }
- if (len > CONFIG_BLUETOOTH_MAXSCANDATA)
- {
- wlerr("ERROR: Scan result is too big: %u\n", len);
- return;
- }
- /* Get exclusive access to the scan data */
- ret = nxsem_wait_uninterruptible(&g_scanstate.bs_exclsem);
- if (ret < 0)
- {
- wlerr("nxsem_wait_uninterruptible() failed: %d\n", ret);
- return;
- }
- /* Add the scan data to the cache */
- tail = g_scanstate.bs_tail;
- nexttail = tail + 1;
- if (nexttail >= CONFIG_BLUETOOTH_MAXSCANRESULT)
- {
- nexttail = 0;
- }
- /* Is the circular buffer full? */
- head = g_scanstate.bs_head;
- if (nexttail == head)
- {
- wlerr("ERROR: Too many scan results\n");
- if (++head >= CONFIG_BLUETOOTH_MAXSCANRESULT)
- {
- head = 0;
- }
- g_scanstate.bs_head = head;
- }
- /* Save the new scan result */
- rsp = &g_scanstate.bs_rsp[tail];
- memcpy(&rsp->sr_addr, addr, sizeof(bt_addr_le_t));
- rsp->sr_rssi = rssi;
- rsp->sr_type = adv_type;
- rsp->sr_len = len;
- memcpy(&rsp->sr_data, adv_data, len);
- g_scanstate.bs_tail = nexttail;
- nxsem_post(&g_scanstate.bs_exclsem);
- }
- /****************************************************************************
- * Name: btnet_scan_result
- *
- * Description:
- * This function implements the SIOCBTSCANGET IOCTL command. It returns
- * the current, buffered discovered handles.
- *
- * Input Parameters:
- * result - Location to return the scan result data
- * maxrsp - The maximum number of responses that can be returned.
- *
- * Returned Value:
- * On success, the actual number of scan results obtain is returned. A
- * negated errno value is returned on any failure.
- *
- ****************************************************************************/
- static int btnet_scan_result(FAR struct bt_scanresponse_s *result,
- uint8_t maxrsp)
- {
- uint8_t head;
- uint8_t tail;
- uint8_t nrsp;
- bool scanning;
- int ret;
- scanning = g_scanstate.bs_scanning;
- wlinfo("Scanning? %s\n", scanning ? "YES" : "NO");
- /* Get exclusive access to the scan data while we are actively scanning.
- * The semaphore is uninitialized in other cases.
- */
- if (scanning)
- {
- /* Get exclusive access to the scan data */
- ret = nxsem_wait(&g_scanstate.bs_exclsem);
- if (ret < 0)
- {
- return ret;
- }
- }
- /* Copy all available results */
- head = g_scanstate.bs_head;
- tail = g_scanstate.bs_tail;
- for (nrsp = 0; nrsp < maxrsp && head != tail; nrsp++)
- {
- FAR const uint8_t *src;
- FAR uint8_t *dest;
- /* Copy data from the head index into the user buffer */
- src = (FAR const uint8_t *)&g_scanstate.bs_rsp[head];
- dest = (FAR uint8_t *)&result[nrsp];
- memcpy(dest, src, sizeof(struct bt_scanresponse_s));
- /* Increment the head index */
- if (++head >= CONFIG_BLUETOOTH_MAXSCANRESULT)
- {
- head = 0;
- }
- }
- g_scanstate.bs_head = head;
- if (scanning)
- {
- nxsem_post(&g_scanstate.bs_exclsem);
- }
- return nrsp;
- }
- /****************************************************************************
- * Name: btnet_exchange_rsp
- *
- * Description:
- * Result of MTU exchange.
- *
- * Input Parameters:
- * conn - The address of the peer in the MTU exchange
- * result - The result of the MTU exchange
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
- static void btnet_exchange_rsp(FAR struct bt_conn_s *conn, uint8_t result)
- {
- FAR struct btnet_wrstate_s *pstate = conn->p_iostate;
- FAR struct btreq_s *btreq = pstate->wr_btreq;
- wlinfo("%s\n", result == 0 ? "succeeded" : "failed");
- btreq->btr_exresult = result;
- nxsem_post(&pstate->wr_donesem);
- }
- /****************************************************************************
- * Name: btnet_discover_func
- *
- * Description:
- * GATT discovery callback. This function is called when a new handle is
- * discovered
- *
- * Input Parameters:
- * attr - The discovered attributes
- * arg - The original discovery parameters
- *
- * Returned Value:
- * BT_GATT_ITER_CONTINUE meaning to continue the iteration.
- *
- ****************************************************************************/
- static uint8_t btnet_discover_func(FAR const struct bt_gatt_attr_s *attr,
- FAR void *arg)
- {
- FAR struct bt_gatt_discover_params_s *params = arg;
- FAR struct btreq_s *btreq = (FAR struct btreq_s *)(params->p_data);
- wlinfo("Discovered handle %x\n", attr->handle);
- if (btreq->btr_indx >= btreq->btr_gnrsp)
- {
- wlerr("ERROR: No space for results\n");
- return BT_GATT_ITER_STOP;
- }
- btreq->btr_grsp[btreq->btr_indx].dr_handle = attr->handle;
- btreq->btr_grsp[btreq->btr_indx].dr_perm = attr->perm;
- btreq->btr_indx++;
- return BT_GATT_ITER_CONTINUE;
- }
- /****************************************************************************
- * Name: btnet_discover_destroy
- *
- * Description:
- * GATT destroy callback. This function is called when a discovery
- * completes.
- *
- * Input Parameters:
- * arg - The original discovery parameters
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
- static void btnet_discover_destroy(FAR void *arg)
- {
- struct btnet_discoverstate_s *pstate = arg;
- wlinfo("Discover destroy\n");
- nxsem_post(&pstate->bd_donesem);
- }
- /****************************************************************************
- * Name: btnet_read_callback
- *
- * Description:
- * Handle network IOCTL commands directed to this device.
- *
- * Input Parameters:
- * conn - Connection of read
- * result - The result status of the read.
- * data - The data read
- * length - The Number of bytes read
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
- static void btnet_read_callback(FAR struct bt_conn_s *conn, int result,
- FAR const void *data, uint16_t length)
- {
- FAR struct btnet_rdstate_s *pstate = conn->p_iostate;
- FAR struct btreq_s *btreq = pstate->rd_btreq;
- wlinfo("Read complete: result %d length %u\n", result, length);
- if (length > HCI_GATTRD_DATA)
- {
- wlerr("ERROR: Unexpected length %u, result = %d\n", length, result);
- btreq->btr_rdresult = ENFILE;
- }
- else
- {
- DEBUGASSERT((unsigned int)result < UINT8_MAX);
- btreq->btr_rdresult = result;
- btreq->btr_rdsize = length;
- memcpy(btreq->btr_rddata, data, length);
- }
- nxsem_post(&pstate->rd_donesem);
- }
- /****************************************************************************
- * Name: bnet_write_callback
- *
- * Description:
- * Result of write operation.
- *
- * Input Parameters:
- * conn - The address of the peer in the MTU exchange
- * result - The result of the MTU exchange
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
- static void bnet_write_callback(FAR struct bt_conn_s *conn, uint8_t result)
- {
- FAR struct btnet_wrstate_s *pstate = conn->p_iostate;
- FAR struct btreq_s *btreq = pstate->wr_btreq;
- wlinfo("%s\n", result == 0 ? "succeeded" : "failed");
- btreq->btr_wrresult = result;
- nxsem_post(&pstate->wr_donesem);
- }
- /****************************************************************************
- * Public Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: btnet_ioctl
- *
- * Description:
- * Handle network IOCTL commands directed to this device.
- *
- * Input Parameters:
- * netdev - Reference to the NuttX driver state structure
- * cmd - The IOCTL command
- * arg - The argument for the IOCTL command
- *
- * Returned Value:
- * OK on success; Negated errno on failure.
- *
- ****************************************************************************/
- int btnet_ioctl(FAR struct net_driver_s *netdev, int cmd, unsigned long arg)
- {
- FAR struct btreq_s *btreq = (FAR struct btreq_s *)((uintptr_t)arg);
- int ret;
- wlinfo("cmd=%04x arg=%lu\n", cmd, arg);
- DEBUGASSERT(netdev != NULL && netdev->d_private != NULL);
- if (btreq == NULL)
- {
- return -EINVAL;
- }
- wlinfo("ifname: %s\n", btreq->btr_name);
- /* Process the command */
- switch (cmd)
- {
- case SIOCBTCONNECT:
- {
- FAR struct bt_conn_s *conn;
- conn = bt_conn_create_le(&btreq->btr_rmtpeer);
- if (!conn)
- {
- wlerr("Connection failed\n");
- ret = -ENOTCONN;
- }
- else
- {
- wlinfo("Connection pending\n");
- ret = OK;
- }
- }
- break;
- case SIOCBTDISCONNECT:
- {
- FAR struct bt_conn_s *conn;
- conn = bt_conn_lookup_addr_le(&btreq->btr_rmtpeer);
- if (!conn)
- {
- wlerr("Peer not connected\n");
- ret = -ENOTCONN;
- }
- else
- {
- ret = bt_conn_disconnect(conn,
- BT_HCI_ERR_REMOTE_USER_TERM_CONN);
- if (ret == -ENOTCONN)
- {
- wlerr("Already disconnected\n");
- }
- else
- {
- /* Release reference taken in bt_conn_create_le */
- bt_conn_release(conn);
- ret = OK;
- }
- /* Release reference taken in bt_conn_lookup_addr_le */
- bt_conn_release(conn);
- }
- }
- break;
- /* SIOCGBTINFO: Get Bluetooth device Info. Given the device name,
- * fill in the btreq_s structure.
- *
- * REVISIT: Little more than a stub at present. It does return the
- * device address associated with the device name which in itself is
- * important.
- */
- case SIOCGBTINFO:
- {
- memset(&btreq->btru.btri, 0, sizeof(btreq->btru.btri));
- BLUETOOTH_ADDRCOPY(btreq->btr_bdaddr.val, g_btdev.bdaddr.val);
- btreq->btr_num_cmd = CONFIG_BLUETOOTH_BUFFER_PREALLOC;
- btreq->btr_num_acl = CONFIG_BLUETOOTH_BUFFER_PREALLOC;
- btreq->btr_acl_mtu = BLUETOOTH_MAX_MTU;
- btreq->btr_sco_mtu = BLUETOOTH_MAX_MTU;
- btreq->btr_max_acl = CONFIG_IOB_NBUFFERS;
- ret = OK;
- }
- break;
- /* SIOCGBTFEAT
- * Get Bluetooth BR/BDR device Features. This returns the cached
- * basic (page 0) and extended (page 1 & 2) features. Only page 0
- * is valid.
- * SIOCGBTLEFEAT
- * Get Bluetooth LE device Features. This returns the cached page
- * 0-2 features. Only page 0 is value.
- */
- case SIOCGBTFEAT:
- case SIOCGBTLEFEAT:
- {
- FAR const uint8_t *src;
- memset(&btreq->btru.btrf, 0, sizeof(btreq->btru.btrf));
- if (cmd == SIOCGBTFEAT)
- {
- src = g_btdev.features;
- }
- else
- {
- src = g_btdev.le_features;
- }
- memcpy(btreq->btr_features0, src, 8);
- ret = OK;
- }
- break;
- /* SIOCBTADVSTART: Set advertisement data, scan response data,
- * advertisement parameters and start advertising.
- */
- case SIOCBTADVSTART:
- {
- ret = bt_start_advertising(btreq->btr_advtype,
- btreq->btr_advad,
- btreq->btr_advsd);
- wlinfo("Start advertising: %d\n", ret);
- }
- break;
- /* SIOCBTADVSTOP: Stop advertising. */
- case SIOCBTADVSTOP:
- {
- wlinfo("Stop advertising\n");
- bt_stop_advertising();
- ret = OK;
- }
- break;
- /* SIOCBTSCANSTART: Start LE scanning. Buffered scan results may be
- * obtained via SIOCBTSCANGET
- */
- case SIOCBTSCANSTART:
- {
- /* Are we already scanning? */
- if (g_scanstate.bs_scanning)
- {
- wlwarn("WARNING: Already scanning\n");
- ret = -EBUSY;
- }
- else
- {
- /* Initialize scan state */
- nxsem_init(&g_scanstate.bs_exclsem, 0, 1);
- g_scanstate.bs_scanning = true;
- g_scanstate.bs_head = 0;
- g_scanstate.bs_tail = 0;
- ret = bt_start_scanning(btreq->btr_dupenable,
- btnet_scan_callback);
- wlinfo("Start scan: %d\n", ret);
- if (ret < 0)
- {
- nxsem_destroy(&g_scanstate.bs_exclsem);
- g_scanstate.bs_scanning = false;
- }
- }
- }
- break;
- /* SIOCBTSCANGET: Return scan results buffered since the call time
- * that the SIOCBTSCANGET command was invoked.
- */
- case SIOCBTSCANGET:
- {
- ret = btnet_scan_result(btreq->btr_rsp, btreq->btr_nrsp);
- wlinfo("Get scan results: %d\n", ret);
- if (ret >= 0)
- {
- btreq->btr_nrsp = ret;
- ret = OK;
- }
- }
- break;
- /* SIOCBTSCANSTOP:
- * Stop LE scanning and discard any buffered results.
- */
- case SIOCBTSCANSTOP:
- {
- /* Stop scanning */
- ret = bt_stop_scanning();
- wlinfo("Stop scanning: %d\n", ret);
- nxsem_destroy(&g_scanstate.bs_exclsem);
- g_scanstate.bs_scanning = false;
- }
- break;
- /* SIOCBTSECURITY: Enable security for a connection. */
- case SIOCBTSECURITY:
- {
- FAR struct bt_conn_s *conn;
- /* Get the connection associated with the provided LE address */
- conn = bt_conn_lookup_addr_le(&btreq->btr_secaddr);
- if (conn == NULL)
- {
- wlwarn("WARNING: Peer not connected\n");
- ret = -ENOTCONN;
- }
- else
- {
- ret = bt_conn_security(conn, btreq->btr_seclevel);
- if (ret < 0)
- {
- wlerr("ERROR: Security setting failed: %d\n", ret);
- }
- bt_conn_release(conn);
- }
- }
- break;
- /* SIOCBTEXCHANGE: Exchange MTUs */
- case SIOCBTEXCHANGE:
- {
- FAR struct bt_conn_s *conn;
- /* Get the connection associated with the provided LE address */
- conn = bt_conn_lookup_addr_le(&btreq->btr_expeer);
- if (conn == NULL)
- {
- wlwarn("WARNING: Peer not connected\n");
- ret = -ENOTCONN;
- }
- else
- {
- struct btnet_wrstate_s wrstate;
- memset(&wrstate, 0, sizeof(wrstate));
- wrstate.wr_btreq = btreq;
- conn->p_iostate = &wrstate;
- nxsem_init(&wrstate.wr_donesem, 0, 0);
- btreq->btr_wrresult = EBUSY;
- ret = bt_gatt_exchange_mtu(conn, btnet_exchange_rsp);
- if (ret < 0)
- {
- wlerr("ERROR: Exchange operation failed: %d\n", ret);
- }
- else
- {
- /* Wait for callback to complete the exchange */
- ret = nxsem_wait(&wrstate.wr_donesem);
- }
- nxsem_destroy(&wrstate.wr_donesem);
- bt_conn_release(conn);
- }
- }
- break;
- /* SIOCBTDISCOVER: Starts GATT discovery */
- case SIOCBTDISCOVER:
- {
- FAR struct bt_conn_s *conn;
- /* Get the connection associated with the provided LE address */
- conn = bt_conn_lookup_addr_le(&btreq->btr_dpeer);
- if (conn == NULL)
- {
- wlwarn("WARNING: Peer not connected\n");
- ret = -ENOTCONN;
- }
- else
- {
- struct btnet_discoverstate_s dstate;
- FAR struct bt_gatt_discover_params_s *params;
- memset(&dstate, 0, sizeof(dstate));
- /* Set up the query */
- dstate.bd_uuid.type = BT_UUID_16;
- dstate.bd_uuid.u.u16 = btreq->btr_duuid16;
- params = &dstate.bd_params;
- params->func = btnet_discover_func;
- params->destroy = btnet_discover_destroy;
- params->start_handle = btreq->btr_dstart;
- params->end_handle = btreq->btr_dend;
- params->p_data = (void *)arg;
- btreq->btr_indx = 0;
- if (btreq->btr_duuid16 == 0)
- {
- params->uuid = NULL;
- }
- else
- {
- params->uuid = &dstate.bd_uuid;
- }
- nxsem_init(&dstate.bd_donesem, 0, 0);
- /* Start the query */
- switch (btreq->btr_dtype)
- {
- case GATT_DISCOVER:
- ret = bt_gatt_discover(conn, params);
- break;
- case GATT_DISCOVER_DESC:
- ret = bt_gatt_discover_descriptor(conn, params);
- break;
- case GATT_DISCOVER_CHAR:
- ret = bt_gatt_discover_characteristic(conn, params);
- break;
- default:
- wlerr("ERROR: Unrecognized GATT discover type: %u\n",
- btreq->btr_dtype);
- ret = -EINVAL;
- }
- if (ret < 0)
- {
- wlerr("ERROR: Failed to start discovery: %d\n", ret);
- }
- else
- {
- ret = nxsem_wait(&dstate.bd_donesem);
- if (ret == 0)
- {
- btreq->btr_gnrsp = btreq->btr_indx;
- }
- }
- nxsem_destroy(&dstate.bd_donesem);
- bt_conn_release(conn);
- }
- }
- break;
- /* SIOCBTGATTRD: Read GATT data */
- case SIOCBTGATTRD:
- {
- FAR struct bt_conn_s *conn;
- /* Get the connection associated with the provided LE address */
- conn = bt_conn_lookup_addr_le(&btreq->btr_rdpeer);
- if (conn == NULL)
- {
- wlwarn("WARNING: Peer not connected\n");
- ret = -ENOTCONN;
- }
- else
- {
- /* Set up for the read */
- struct btnet_rdstate_s rdstate;
- memset(&rdstate, 0, sizeof(rdstate));
- rdstate.rd_btreq = btreq;
- conn->p_iostate = &rdstate;
- nxsem_init(&rdstate.rd_donesem, 0, 0);
- /* Initiate read.. single or multiple? */
- if (btreq->btr_rdnhandles == 1)
- {
- /* Read single */
- DEBUGASSERT(conn->p_iostate != NULL);
- ret = bt_gatt_read(conn, btreq->btr_rdhandles[0],
- btreq->btr_rdoffset,
- btnet_read_callback);
- }
- else if (btreq->btr_rdnhandles < HCI_GATT_MAXHANDLES)
- {
- /* Read multiple */
- DEBUGASSERT(conn->p_iostate != NULL);
- DEBUGASSERT(btreq->btr_rdnhandles > 0);
- ret = bt_gatt_read_multiple(conn, btreq->btr_rdhandles,
- btreq->btr_rdnhandles,
- btnet_read_callback);
- }
- else
- {
- ret = -ENFILE;
- }
- if (ret < 0)
- {
- wlerr("ERROR: Read operation failed: %d\n", ret);
- }
- else
- {
- /* Wait for callback to complete the transfer */
- ret = nxsem_wait(&rdstate.rd_donesem);
- }
- nxsem_destroy(&rdstate.rd_donesem);
- bt_conn_release(conn);
- }
- }
- break;
- /* SIOCBTGATTWR: Write GATT data */
- case SIOCBTGATTWR:
- {
- DEBUGASSERT(btreq->btr_wrdata != NULL);
- FAR struct bt_conn_s *conn;
- /* Get the connection associated with the provided LE address */
- conn = bt_conn_lookup_addr_le(&btreq->btr_wrpeer);
- if (conn == NULL)
- {
- wlwarn("WARNING: Peer not connected\n");
- ret = -ENOTCONN;
- }
- else
- {
- /* Set up for the write */
- struct btnet_wrstate_s wrstate;
- memset(&wrstate, 0, sizeof(wrstate));
- wrstate.wr_btreq = btreq;
- conn->p_iostate = &wrstate;
- nxsem_init(&wrstate.wr_donesem, 0, 0);
- btreq->btr_wrresult = EBUSY;
- /* Initiate write */
- ret = bt_gatt_write(conn, btreq->btr_wrhandle,
- btreq->btr_wrdata,
- btreq->btr_wrnbytes,
- bnet_write_callback);
- if (ret < 0)
- {
- wlerr("ERROR: Write operation failed: %d\n", ret);
- }
- else
- {
- /* Wait for callback to complete the transfer */
- ret = nxsem_wait(&wrstate.wr_donesem);
- }
- nxsem_destroy(&wrstate.wr_donesem);
- bt_conn_release(conn);
- }
- }
- break;
- default:
- wlwarn("WARNING: Unrecognized IOCTL command: %02x\n", cmd);
- ret = -ENOTTY;
- break;
- }
- return ret;
- }
- #endif /* CONFIG_NETDEV_IOCTL */
|