@stoprocent/noble
Advanced tools
+123
-2
@@ -28,2 +28,3 @@ const debug = require('debug')('hci'); | ||
| const EVT_LE_CONN_UPDATE_COMPLETE = 0x03; | ||
| const EVT_LE_DATA_LENGTH_CHANGE = 0x07; | ||
@@ -55,2 +56,4 @@ const OGF_LINK_CTL = 0x01; | ||
| const OCF_LE_SET_EXTENDED_SCAN_ENABLE = 0x0042; | ||
| const OCF_LE_SET_DATA_LENGTH = 0x0022; | ||
| const OCF_LE_READ_MAX_DATA_LENGTH = 0x002f; | ||
| const OCF_LE_SET_SCAN_PARAMETERS = 0x000b; | ||
@@ -83,2 +86,4 @@ const OCF_LE_SET_SCAN_ENABLE = 0x000c; | ||
| const LE_READ_LOCAL_SUPPORTED_FEATURES = OCF_LE_READ_LOCAL_SUPPORTED_FEATURES | (OGF_LE_CTL << 10); | ||
| const LE_SET_DATA_LENGTH_CMD = OCF_LE_SET_DATA_LENGTH | (OGF_LE_CTL << 10); | ||
| const LE_READ_MAX_DATA_LENGTH_CMD = OCF_LE_READ_MAX_DATA_LENGTH | (OGF_LE_CTL << 10); | ||
| const LE_SET_EXTENDED_SCAN_PARAMETERS_CMD = | ||
@@ -100,2 +105,8 @@ OCF_LE_SET_EXTENDED_SCAN_PARAMETERS | (OGF_LE_CTL << 10); | ||
| const LE_MIN_ACL_LENGTH = 27; | ||
| // Core Spec Vol 4 Part E 7.8.33: LE Set Data Length parameter ranges | ||
| const LE_MIN_TX_OCTETS = 0x001b; | ||
| const LE_MAX_TX_OCTETS = 0x00fb; | ||
| const LE_MIN_TX_TIME = 0x0148; | ||
| const LE_MAX_TX_TIME = 0x4290; | ||
| const HCI_OE_USER_ENDED_CONNECTION = 0x13; | ||
@@ -121,2 +132,4 @@ | ||
| this._supportsCodedPhy = false; | ||
| this._supportsDataLengthExtension = false; | ||
| this._maxDataLength = null; | ||
| this._state = null; | ||
@@ -418,5 +431,6 @@ this._bindParams = 'bindParams' in options ? options.bindParams : undefined; | ||
| const cmd = Buffer.alloc(12); | ||
| // Bit 6 is LE Data Length Change; without it the negotiated length is never reported. | ||
| const leEventMask = this._isExtended | ||
| ? Buffer.from('1fff000000000000', 'hex') | ||
| : Buffer.from('1f00000000000000', 'hex'); | ||
| ? Buffer.from('5fff000000000000', 'hex') | ||
| : Buffer.from('5f00000000000000', 'hex'); | ||
@@ -464,2 +478,44 @@ // header | ||
| Hci.prototype.readLeMaxDataLength = function () { | ||
| const cmd = Buffer.alloc(4); | ||
| // header | ||
| cmd.writeUInt8(HCI_COMMAND_PKT, 0); | ||
| cmd.writeUInt16LE(LE_READ_MAX_DATA_LENGTH_CMD, 1); | ||
| // length | ||
| cmd.writeUInt8(0x0, 3); | ||
| debug(`le read maximum data length - writing: ${cmd.toString('hex')}`); | ||
| this._socket.write(cmd); | ||
| }; | ||
| Hci.prototype.setLeDataLength = function (handle) { | ||
| if (!this._supportsDataLengthExtension || this._maxDataLength === null) { | ||
| return; | ||
| } | ||
| const cmd = Buffer.alloc(10); | ||
| // header | ||
| cmd.writeUInt8(HCI_COMMAND_PKT, 0); | ||
| cmd.writeUInt16LE(LE_SET_DATA_LENGTH_CMD, 1); | ||
| // length | ||
| cmd.writeUInt8(0x06, 3); | ||
| // data | ||
| cmd.writeUInt16LE(handle, 4); | ||
| cmd.writeUInt16LE(this._maxDataLength.txOctets, 6); | ||
| cmd.writeUInt16LE(this._maxDataLength.txTime, 8); | ||
| debug(`le set data length - writing: ${cmd.toString('hex')}`); | ||
| // A link works at the 27 octet default, so a failure here must not fail the connection. | ||
| try { | ||
| this._socket.write(cmd); | ||
| } catch (error) { | ||
| debug(`le set data length failed - handle: ${handle}, error: ${error.message}`); | ||
| } | ||
| }; | ||
| Hci.prototype.readLeHostSupported = function () { | ||
@@ -1026,2 +1082,4 @@ const cmd = Buffer.alloc(4); | ||
| this._supportsCodedPhy = (result[1] & (1 << 3)) !== 0; | ||
| // LE Data Packet Length Extension feature bit (5). | ||
| this._supportsDataLengthExtension = (result[0] & (1 << 5)) !== 0; | ||
| this.emit('leFeatures', result); | ||
@@ -1036,2 +1094,8 @@ } else { | ||
| if (this._supportsDataLengthExtension) { | ||
| this.readLeMaxDataLength(); | ||
| } else { | ||
| this._maxDataLength = null; | ||
| } | ||
| this.setEventMask(); | ||
@@ -1044,2 +1108,32 @@ this.setLeEventMask(); | ||
| this.readBdAddr(); | ||
| } else if (cmd === LE_SET_DATA_LENGTH_CMD) { | ||
| if (status !== 0) { | ||
| debug(`le set data length failed - status: ${status}`); | ||
| } | ||
| } else if (cmd === LE_READ_MAX_DATA_LENGTH_CMD) { | ||
| if (status !== 0 || result.length < 8) { | ||
| debug(`le read maximum data length failed or returned a short result - status: ${status}, length: ${result.length}`); | ||
| return; | ||
| } | ||
| const txOctets = result.readUInt16LE(0); | ||
| const txTime = result.readUInt16LE(2); | ||
| const rxOctets = result.readUInt16LE(4); | ||
| const rxTime = result.readUInt16LE(6); | ||
| debug(`\t\t\tsupported max tx octets = ${txOctets}`); | ||
| debug(`\t\t\tsupported max tx time = ${txTime}`); | ||
| debug(`\t\t\tsupported max rx octets = ${rxOctets}`); | ||
| debug(`\t\t\tsupported max rx time = ${rxTime}`); | ||
| if (txOctets < LE_MIN_TX_OCTETS || txTime < LE_MIN_TX_TIME) { | ||
| debug(`le read maximum data length returned values below the spec minimum - octets: ${txOctets}, time: ${txTime}`); | ||
| this._maxDataLength = null; | ||
| return; | ||
| } | ||
| this._maxDataLength = { | ||
| txOctets: Math.min(txOctets, LE_MAX_TX_OCTETS), | ||
| txTime: Math.min(txTime, LE_MAX_TX_TIME) | ||
| }; | ||
| } else if (cmd === READ_LE_HOST_SUPPORTED_CMD && status === 0) { | ||
@@ -1170,5 +1264,30 @@ const le = result.readUInt8(0); | ||
| this.processLeConnUpdateComplete(numReports, data); | ||
| } else if (eventType === EVT_LE_DATA_LENGTH_CHANGE) { | ||
| this.processLeDataLengthChange(numReports, data); | ||
| } | ||
| }; | ||
| // The caller has already consumed the first parameter octet, which for this subevent is the | ||
| // low byte of the connection handle rather than a status or report count. | ||
| Hci.prototype.processLeDataLengthChange = function (handleLowByte, data) { | ||
| if (data.length < 9) { | ||
| debug(`processLeDataLengthChange: ignoring illegal packet (too short: ${data.length} < 9)`); | ||
| return; | ||
| } | ||
| const handle = handleLowByte | (data.readUInt8(0) << 8); | ||
| const maxTxOctets = data.readUInt16LE(1); | ||
| const maxTxTime = data.readUInt16LE(3); | ||
| const maxRxOctets = data.readUInt16LE(5); | ||
| const maxRxTime = data.readUInt16LE(7); | ||
| debug(`\t\t\thandle = ${handle}`); | ||
| debug(`\t\t\tmax tx octets = ${maxTxOctets}`); | ||
| debug(`\t\t\tmax tx time = ${maxTxTime}`); | ||
| debug(`\t\t\tmax rx octets = ${maxRxOctets}`); | ||
| debug(`\t\t\tmax rx time = ${maxRxTime}`); | ||
| this.emit('leDataLengthChange', handle, maxTxOctets, maxTxTime, maxRxOctets, maxRxTime); | ||
| }; | ||
| Hci.prototype.processLeConnComplete = function (status, data) { | ||
@@ -1208,2 +1327,3 @@ if (data.length < 17) { | ||
| this._aclConnections.set(handle, { pending: 0 }); | ||
| this.setLeDataLength(handle); | ||
| } | ||
@@ -1291,2 +1411,3 @@ | ||
| this._aclConnections.set(handle, { pending: 0 }); | ||
| this.setLeDataLength(handle); | ||
| } | ||
@@ -1293,0 +1414,0 @@ |
+1
-1
@@ -9,3 +9,3 @@ { | ||
| "description": "A Node.js BLE (Bluetooth Low Energy) central library.", | ||
| "version": "2.6.6", | ||
| "version": "2.7.0", | ||
| "repository": { | ||
@@ -12,0 +12,0 @@ "type": "git", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
2576755
0.48%18885
1.36%