/** * Called when a data packet is received from the controller. This function * consumes the supplied mbuf, regardless of the outcome. * * @param om The incoming data packet, beginning with the * HCI ACL data header. * * @return 0 on success; nonzero on failure. */ int host_hci_data_rx(struct os_mbuf *om) { struct hci_data_hdr hci_hdr; struct ble_hs_conn *conn; ble_l2cap_rx_fn *rx_cb; struct os_mbuf *rx_buf; uint16_t handle; int rc; rc = host_hci_data_hdr_strip(om, &hci_hdr); if (rc == 0) { BLE_HS_LOG(DEBUG, "host_hci_data_rx(): handle=%u pb=%x len=%u data=", BLE_HCI_DATA_HANDLE(hci_hdr.hdh_handle_pb_bc), BLE_HCI_DATA_PB(hci_hdr.hdh_handle_pb_bc), hci_hdr.hdh_len); ble_hs_misc_log_mbuf(om); if (hci_hdr.hdh_len != OS_MBUF_PKTHDR(om)->omp_len) { rc = BLE_HS_EBADDATA; } else { handle = BLE_HCI_DATA_HANDLE(hci_hdr.hdh_handle_pb_bc); ble_hs_conn_lock(); conn = ble_hs_conn_find(handle); if (conn == NULL) { rc = BLE_HS_ENOTCONN; } else { rc = ble_l2cap_rx(conn, &hci_hdr, om, &rx_cb, &rx_buf); om = NULL; } ble_hs_conn_unlock(); } } os_mbuf_free_chain(om); if (rc == 0) { assert(rx_cb != NULL); assert(rx_buf != NULL); rc = rx_cb(handle, &rx_buf); os_mbuf_free_chain(rx_buf); } else if (rc == BLE_HS_EAGAIN) { /* More fragments on the way. */ rc = 0; } return rc; }
/** * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. */ uint16_t ble_att_mtu(uint16_t conn_handle) { struct ble_l2cap_chan *chan; struct ble_hs_conn *conn; uint16_t mtu; ble_hs_conn_lock(); ble_att_conn_chan_find(conn_handle, &conn, &chan); if (chan != NULL) { mtu = ble_l2cap_chan_mtu(chan); } else { mtu = 0; } ble_hs_conn_unlock(); return mtu; }