diff --git a/src/BluetoothHciSocket.cpp b/src/BluetoothHciSocket.cpp index 0cd3878..8bafdce 100644 --- a/src/BluetoothHciSocket.cpp +++ b/src/BluetoothHciSocket.cpp @@ -291,6 +291,10 @@ void BluetoothHciSocket::stop() { } void BluetoothHciSocket::write_(char* data, int length) { + if (this->_mode == HCI_CHANNEL_RAW && this->kernelConnectWorkArounds(data, length)) { + return; + } + if (write(this->_socket, data, length) < 0) { this->emitErrnoError("write"); } @@ -350,11 +354,10 @@ int BluetoothHciSocket::kernelDisconnectWorkArounds(int length, char* data) { // HCI Event - LE Meta Event - LE Connection Complete => manually create L2CAP socket to force kernel to book keep // HCI Event - Disconn Complete =======================> close socket from above - if (length == 22 && data[0] == 0x04 && data[1] == 0x3e && data[2] == 0x13 && data[3] == 0x01 && data[4] == 0x00) { + if (length == 22 && data[0] == 0x04 && data[1] == 0x3e && data[2] == 0x13 && data[3] == 0x01 && data[4] == 0x00 && data[7] == 0x01) { int l2socket; struct sockaddr_l2 l2a = {}; unsigned short l2cid; - unsigned short handle = *((unsigned short*)(&data[5])); #if __BYTE_ORDER == __LITTLE_ENDIAN l2cid = ATT_CID; @@ -385,21 +388,75 @@ int BluetoothHciSocket::kernelDisconnectWorkArounds(int length, char* data) { l2a.l2_cid = l2cid; l2a.l2_bdaddr_type = data[8] + 1; // BDADDR_LE_PUBLIC (0x01), BDADDR_LE_RANDOM (0x02) - if (connect(l2socket, (struct sockaddr *)&l2a, sizeof(l2a)) < -1) { + while (connect(l2socket, (struct sockaddr *)&l2a, sizeof(l2a) == -1) ) { + if(errno == EINTR) { + continue; + } close(l2socket); return -3; } - this->_l2sockets[handle] = l2socket; - } else if (length == 7 && data[0] == 0x04 && data[1] == 0x05 && data[2] == 0x04 && data[3] == 0x00) { - unsigned short handle = *((unsigned short*)(&data[4])); + return 0; + } +} - if (this->_l2sockets.count(handle) > 0) { - close(this->_l2sockets[handle]); - this->_l2sockets.erase(handle); - } + +bool BluetoothHciSocket::kernelConnectWorkArounds(char* data, int length) +{ + if (length == 29 && data[0] == 0x01 && data[1] == 0x0d && data[2] == 0x20 && data[3] == 0x19) { + int l2socket; + struct sockaddr_l2 l2a; + unsigned short l2cid; + unsigned short connMinInterval; + unsigned short connMaxInterval; + unsigned short connLatency; + unsigned short supervisionTimeout; + char command[128]; + +#if __BYTE_ORDER == __LITTLE_ENDIAN + l2cid = ATT_CID; +#elif __BYTE_ORDER == __BIG_ENDIAN + l2cid = bswap_16(ATT_CID); +#else + #error "Unknown byte order" +#endif + + l2socket = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + + memset(&l2a, 0, sizeof(l2a)); + l2a.l2_family = AF_BLUETOOTH; + l2a.l2_cid = l2cid; + memcpy(&l2a.l2_bdaddr, this->_address, sizeof(l2a.l2_bdaddr)); + l2a.l2_bdaddr_type = this->_addressType; + bind(l2socket, (struct sockaddr*)&l2a, sizeof(l2a)); + + memset(&l2a, 0, sizeof(l2a)); + l2a.l2_family = AF_BLUETOOTH; + memcpy(&l2a.l2_bdaddr, &data[10], sizeof(l2a.l2_bdaddr)); + l2a.l2_cid = l2cid; + l2a.l2_bdaddr_type = data[9] + 1; // BDADDR_LE_PUBLIC (0x01), BDADDR_LE_RANDOM (0x02) + + // extract the connection parameter + connMinInterval = (data[18] << 8) | data[17]; + connMaxInterval = (data[20] << 8) | data[19]; + connLatency = (data[22] << 8) | data[21]; + supervisionTimeout = (data[24] << 8) | data[23]; + + // override the HCI devices connection parameters using debugfs + sprintf(command, "echo %u > /sys/kernel/debug/bluetooth/hci%d/conn_min_interval", connMinInterval, this->_devId); + system(command); + sprintf(command, "echo %u > /sys/kernel/debug/bluetooth/hci%d/conn_max_interval", connMaxInterval, this->_devId); + system(command); + sprintf(command, "echo %u > /sys/kernel/debug/bluetooth/hci%d/conn_latency", connLatency, this->_devId); + system(command); + sprintf(command, "echo %u > /sys/kernel/debug/bluetooth/hci%d/supervision_timeout", supervisionTimeout, this->_devId); + system(command); + + connect(l2socket, (struct sockaddr *)&l2a, sizeof(l2a)); + return true; } - return 0; + + return false; } NAN_METHOD(BluetoothHciSocket::New) { diff --git a/src/BluetoothHciSocket.h b/src/BluetoothHciSocket.h index 34e6b81..8fb494a 100644 --- a/src/BluetoothHciSocket.h +++ b/src/BluetoothHciSocket.h @@ -1,8 +1,6 @@ #ifndef ___BLUETOOTH_HCI_SOCKET_H___ #define ___BLUETOOTH_HCI_SOCKET_H___ -#include <map> - #include <node.h> #include <nan.h> @@ -42,6 +40,7 @@ class BluetoothHciSocket : public node::ObjectWrap { void emitErrnoError(const char *syscall); int devIdFor(const int* devId, bool isUp); int kernelDisconnectWorkArounds(int length, char* data); + bool kernelConnectWorkArounds(char* data, int length); static void PollCloseCallback(uv_poll_t* handle); static void PollCallback(uv_poll_t* handle, int status, int events); @@ -53,7 +52,6 @@ class BluetoothHciSocket : public node::ObjectWrap { int _socket; int _devId; uv_poll_t _pollHandle; - std::map<unsigned short,int> _l2sockets; uint8_t _address[6]; uint8_t _addressType;