zbtk
Version:
ZigBee Toolkit for Node.js
520 lines (496 loc) • 13.5 kB
JavaScript
import { Buffer } from 'node:buffer';
import { parse as parsePacket } from './parse.js';
const types = {};
types.zbee_zcl_cmd = packet => {
switch (packet?.id[0]) {
case 0x00:
return 'ZCL_CMD_READ_ATTR';
case 0x01:
return 'ZCL_CMD_READ_ATTR_RSP';
case 0x02:
return 'ZCL_CMD_WRITE_ATTR';
case 0x03:
return 'ZCL_CMD_WRITE_ATTR_UNDIVIDED';
case 0x04:
return 'ZCL_CMD_WRITE_ATTR_RSP';
case 0x05:
return 'ZCL_CMD_WRITE_ATTR_NO_RSP';
case 0x06:
return 'ZCL_CMD_CONFIG_REPORT';
case 0x07:
return 'ZCL_CMD_CONFIG_REPORT_RSP';
case 0x08:
return 'ZCL_CMD_READ_REPORT_CONFIG';
case 0x09:
return 'ZCL_CMD_READ_REPORT_CONFIG_RSP';
case 0x0a:
return 'ZCL_CMD_REPORT_ATTR';
case 0x0b:
return 'ZCL_CMD_DEFAULT_RSP';
case 0x0c:
return 'ZCL_CMD_DISCOVER_ATTR';
case 0x0d:
return 'ZCL_CMD_DISCOVER_ATTR_RSP';
case 0x0e:
return 'ZCL_CMD_READ_ATTR_STRUCT';
case 0x0f:
return 'ZCL_CMD_WRITE_ATTR_STRUCT';
case 0x10:
return 'ZCL_CMD_WRITE_ATTR_STRUCT_RSP';
case 0x11:
return 'ZCL_CMD_DISCOVER_CMDS_REC';
case 0x12:
return 'ZCL_CMD_DISCOVER_CMDS_REC_RSP';
case 0x13:
return 'ZCL_CMD_DISCOVER_CMDS_GEN';
case 0x14:
return 'ZCL_CMD_DISCOVER_CMDS_GEN_RSP';
case 0x15:
return 'ZCL_CMD_DISCOVER_ATTR_EXTENDED';
case 0x16:
return 'ZCL_CMD_DISCOVER_ATTR_EXTENDED_RSP';
default:
return 'ZCL_CMD_UNKNOWN';
}
};
types.zbee_zcl = packet => {
switch (packet?.fc.type) {
case 0x0:
return types.zbee_zcl_cmd(packet.cmd);
case 0x1:
return 'ZCL_ACK';
case 0x2:
return 'ZCL_CLUSTER_SPECIFIC';
case 0x3:
return 'ZCL_PROFILE_WIDE';
default:
return 'ZCL_UNKNOWN';
}
};
types.zbee_zdp = (packet, cluster) => {
if (!Buffer.isBuffer(cluster)) {
return 'ZDP_UNKNOWN';
}
switch (cluster.readUInt16LE(0)) {
case 0x0000:
return 'ZDP_REQ_NWK_ADDR';
case 0x0001:
return 'ZDP_REQ_IEEE_ADDR';
case 0x0002:
return 'ZDP_REQ_NODE_DESC';
case 0x0003:
return 'ZDP_REQ_POWER_DESC';
case 0x0004:
return 'ZDP_REQ_SIMPLE_DESC';
case 0x0005:
return 'ZDP_REQ_ACTIVE_EP';
case 0x0006:
return 'ZDP_REQ_MATCH_DESC';
case 0x0010:
return 'ZDP_REQ_COMPLEX_DESC';
case 0x0011:
return 'ZDP_REQ_USER_DESC';
case 0x0012:
return 'ZDP_REQ_DISCOVERY_CACHE';
case 0x0013:
return 'ZDP_REQ_DEVICE_ANNCE';
case 0x0014:
return 'ZDP_REQ_SET_USER_DESC';
case 0x0015:
return 'ZDP_REQ_SYSTEM_SERVER_DISC';
case 0x0016:
return 'ZDP_REQ_STORE_DISCOVERY';
case 0x0017:
return 'ZDP_REQ_STORE_NODE_DESC';
case 0x0018:
return 'ZDP_REQ_STORE_POWER_DESC';
case 0x0019:
return 'ZDP_REQ_STORE_ACTIVE_EP';
case 0x001a:
return 'ZDP_REQ_STORE_SIMPLE_DESC';
case 0x001b:
return 'ZDP_REQ_REMOVE_NODE_CACHE';
case 0x001c:
return 'ZDP_REQ_FIND_NODE_CACHE';
case 0x001d:
return 'ZDP_REQ_EXT_SIMPLE_DESC';
case 0x001e:
return 'ZDP_REQ_EXT_ACTIVE_EP';
case 0x001f:
return 'ZDP_REQ_PARENT_ANNCE';
case 0x0020:
return 'ZDP_REQ_END_DEVICE_BIND';
case 0x0021:
return 'ZDP_REQ_BIND';
case 0x0022:
return 'ZDP_REQ_UNBIND';
case 0x0023:
return 'ZDP_REQ_BIND_REGISTER';
case 0x0024:
return 'ZDP_REQ_REPLACE_DEVICE';
case 0x0025:
return 'ZDP_REQ_STORE_BAK_BIND_ENTRY';
case 0x0026:
return 'ZDP_REQ_REMOVE_BAK_BIND_ENTRY';
case 0x0027:
return 'ZDP_REQ_BACKUP_BIND_TABLE';
case 0x0028:
return 'ZDP_REQ_RECOVER_BIND_TABLE';
case 0x0029:
return 'ZDP_REQ_BACKUP_SOURCE_BIND';
case 0x002a:
return 'ZDP_REQ_RECOVER_SOURCE_BIND';
case 0x002b:
return 'ZDP_REQ_CLEAR_ALL_BINDINGS';
case 0x0030:
return 'ZDP_REQ_MGMT_NWK_DISC';
case 0x0031:
return 'ZDP_REQ_MGMT_LQI';
case 0x0032:
return 'ZDP_REQ_MGMT_RTG';
case 0x0033:
return 'ZDP_REQ_MGMT_BIND';
case 0x0034:
return 'ZDP_REQ_MGMT_LEAVE';
case 0x0035:
return 'ZDP_REQ_MGMT_DIRECT_JOIN';
case 0x0036:
return 'ZDP_REQ_MGMT_PERMIT_JOIN';
case 0x0037:
return 'ZDP_REQ_MGMT_CACHE';
case 0x0038:
return 'ZDP_REQ_MGMT_NWKUPDATE';
case 0x0039:
return 'ZDP_REQ_MGMT_NWKUPDATE_ENH';
case 0x003a:
return 'ZDP_REQ_MGMT_IEEE_JOIN_LIST';
case 0x003c:
return 'ZDP_REQ_MGMT_NWK_BEACON_SURVEY';
case 0x0040:
return 'ZDP_REQ_SECURITY_START_KEY_NEGOTIATION';
case 0x0041:
return 'ZDP_REQ_SECURITY_GET_AUTH_TOKEN';
case 0x0042:
return 'ZDP_REQ_SECURITY_GET_AUTH_LEVEL';
case 0x0043:
return 'ZDP_REQ_SECURITY_SET_CONFIGURATION';
case 0x0044:
return 'ZDP_REQ_SECURITY_GET_CONFIGURATION';
case 0x0045:
return 'ZDP_REQ_SECURITY_START_KEY_UPDATE';
case 0x0046:
return 'ZDP_REQ_SECURITY_DECOMMISSION';
case 0x0047:
return 'ZDP_REQ_SECURITY_CHALLENGE';
case 0x8000:
return 'ZDP_RSP_NWK_ADDR';
case 0x8001:
return 'ZDP_RSP_IEEE_ADDR';
case 0x8002:
return 'ZDP_RSP_NODE_DESC';
case 0x8003:
return 'ZDP_RSP_POWER_DESC';
case 0x8004:
return 'ZDP_RSP_SIMPLE_DESC';
case 0x8005:
return 'ZDP_RSP_ACTIVE_EP';
case 0x8006:
return 'ZDP_RSP_MATCH_DESC';
case 0x8010:
return 'ZDP_RSP_COMPLEX_DESC';
case 0x8011:
return 'ZDP_RSP_USER_DESC';
case 0x8012:
return 'ZDP_RSP_DISCOVERY_CACHE';
case 0x8014:
return 'ZDP_RSP_CONF_USER_DESC';
case 0x8015:
return 'ZDP_RSP_SYSTEM_SERVER_DISC';
case 0x8016:
return 'ZDP_RSP_STORE_DISCOVERY';
case 0x8017:
return 'ZDP_RSP_STORE_NODE_DESC';
case 0x8018:
return 'ZDP_RSP_STORE_POWER_DESC';
case 0x8019:
return 'ZDP_RSP_STORE_ACTIVE_EP';
case 0x801a:
return 'ZDP_RSP_STORE_SIMPLE_DESC';
case 0x801b:
return 'ZDP_RSP_REMOVE_NODE_CACHE';
case 0x801c:
return 'ZDP_RSP_FIND_NODE_CACHE';
case 0x801d:
return 'ZDP_RSP_EXT_SIMPLE_DESC';
case 0x801e:
return 'ZDP_RSP_EXT_ACTIVE_EP';
case 0x801f:
return 'ZDP_RSP_PARENT_ANNCE';
case 0x8020:
return 'ZDP_RSP_END_DEVICE_BIND';
case 0x8021:
return 'ZDP_RSP_BIND';
case 0x8022:
return 'ZDP_RSP_UNBIND';
case 0x8023:
return 'ZDP_RSP_BIND_REGISTER';
case 0x8024:
return 'ZDP_RSP_REPLACE_DEVICE';
case 0x8025:
return 'ZDP_RSP_STORE_BAK_BIND_ENTRY';
case 0x8026:
return 'ZDP_RSP_REMOVE_BAK_BIND_ENTRY';
case 0x8027:
return 'ZDP_RSP_BACKUP_BIND_TABLE';
case 0x8028:
return 'ZDP_RSP_RECOVER_BIND_TABLE';
case 0x8029:
return 'ZDP_RSP_BACKUP_SOURCE_BIND';
case 0x802a:
return 'ZDP_RSP_RECOVER_SOURCE_BIND';
case 0x802b:
return 'ZDP_RSP_CLEAR_ALL_BINDINGS';
case 0x8030:
return 'ZDP_RSP_MGMT_NWK_DISC';
case 0x8031:
return 'ZDP_RSP_MGMT_LQI';
case 0x8032:
return 'ZDP_RSP_MGMT_RTG';
case 0x8033:
return 'ZDP_RSP_MGMT_BIND';
case 0x8034:
return 'ZDP_RSP_MGMT_LEAVE';
case 0x8035:
return 'ZDP_RSP_MGMT_DIRECT_JOIN';
case 0x8036:
return 'ZDP_RSP_MGMT_PERMIT_JOIN';
case 0x8037:
return 'ZDP_RSP_MGMT_CACHE';
case 0x8038:
return 'NOT_MGMT_NWKUPDATE';
case 0x8039:
return 'NOT_MGMT_NWKUPDATE_ENH';
case 0x803a:
return 'ZDP_RSP_MGMT_IEEE_JOIN_LIST';
case 0x803b:
return 'NOT_MGMT_UNSOLICITED_NWKUPDATE';
case 0x803c:
return 'ZDP_RSP_MGMT_NWK_BEACON_SURVEY';
case 0x8040:
return 'ZDP_RSP_SECURITY_START_KEY_NEGOTIATION';
case 0x8041:
return 'ZDP_RSP_SECURITY_GET_AUTH_TOKEN';
case 0x8042:
return 'ZDP_RSP_SECURITY_GET_AUTH_LEVEL';
case 0x8043:
return 'ZDP_RSP_SECURITY_SET_CONFIGURATION';
case 0x8044:
return 'ZDP_RSP_SECURITY_GET_CONFIGURATION';
case 0x8045:
return 'ZDP_RSP_SECURITY_START_KEY_UPDATE';
case 0x8046:
return 'ZDP_RSP_SECURITY_DECOMMISSION';
case 0x8047:
return 'ZDP_RSP_SECURITY_CHALLENGE';
default:
return 'ZDP_UNKNOWN';
}
};
types.zbee_aps_cmd = packet => {
switch (packet?.id[0]) {
case 0x01:
return 'APS_CMD_SKKE1';
case 0x02:
return 'APS_CMD_SKKE2';
case 0x03:
return 'APS_CMD_SKKE3';
case 0x04:
return 'APS_CMD_SKKE4';
case 0x05:
return 'APS_CMD_TRANSPORT_KEY';
case 0x06:
return 'APS_CMD_UPDATE_DEVICE';
case 0x07:
return 'APS_CMD_REMOVE_DEVICE';
case 0x08:
return 'APS_CMD_REQUEST_KEY';
case 0x09:
return 'APS_CMD_SWITCH_KEY';
case 0x0a:
return 'APS_CMD_EA_INIT_CHLNG';
case 0x0b:
return 'APS_CMD_EA_RSP_CHLNG';
case 0x0c:
return 'APS_CMD_EA_INIT_MAC_DATA';
case 0x0d:
return 'APS_CMD_EA_RSP_MAC_DATA';
case 0x0e:
return 'APS_CMD_TUNNEL';
case 0x0f:
return 'APS_CMD_VERIFY_KEY';
case 0x10:
return 'APS_CMD_CONFIRM_KEY';
case 0x11:
return 'APS_CMD_RELAY_MSG_DOWNSTREAM';
case 0x12:
return 'APS_CMD_RELAY_MSG_UPSTREAM';
default:
return 'APS_CMD_UNKNOWN';
}
};
types.zbee_aps = packet => {
if (packet?.zbee_zcl) {
return types.zbee_zcl(packet.zbee_zcl);
} else if (packet?.zbee_zdp) {
return types.zbee_zdp(packet.zbee_zdp, packet.cluster);
}
switch (packet?.fc.type) {
case 0x0:
return 'APS_DATA';
case 0x1:
if (Buffer.isBuffer(packet.data)) {
return 'APS_CMD'; // still encrypted
} else {
return types.zbee_aps_cmd(packet.cmd);
}
case 0x2:
return 'APS_ACK';
default:
return 'APS_UNKNOWN';
}
};
types.zbee_nwk_cmd = packet => {
switch (packet?.id[0]) {
case 0x01:
return 'NWK_CMD_ROUTE_REQ';
case 0x02:
return 'NWK_CMD_ROUTE_REPLY';
case 0x03:
return 'NWK_CMD_NWK_STATUS';
case 0x04:
return 'NWK_CMD_LEAVE';
case 0x05:
return 'NWK_CMD_ROUTE_RECORD';
case 0x06:
return 'NWK_CMD_REJOIN_REQ';
case 0x07:
return 'NWK_CMD_REJOIN_RSP';
case 0x08:
return 'NWK_CMD_LINK_STATUS';
case 0x09:
return 'NWK_CMD_NWK_REPORT';
case 0x0a:
return 'NWK_CMD_NWK_UPDATE';
case 0x0b:
return 'NWK_CMD_ED_TIMEOUT_REQUEST';
case 0x0c:
return 'NWK_CMD_ED_TIMEOUT_RSPONSE';
case 0x0d:
return 'NWK_CMD_LINK_PWR_DELTA';
case 0x0e:
return 'NWK_CMD_COMMISSIONING_REQUEST';
case 0x0f:
return 'NWK_CMD_COMMISSIONING_RSPONSE';
default:
return 'NWK_CMD_UNKNOWN';
}
};
types.zbee_nwk = packet => {
if (packet?.zbee_aps) {
return types.zbee_aps(packet.zbee_aps);
}
switch (packet?.fc.type) {
case 0x0:
return 'NWK_DATA';
case 0x1:
if (Buffer.isBuffer(packet.data)) {
return 'NWK_CMD'; // still encrypted
} else {
return types.zbee_nwk_cmd(packet.cmd);
}
default:
return 'NWK_UNKNOWN';
}
};
types.wpan_cmd = packet => {
switch (packet?.id[0]) {
case 0x01:
return 'WPAN_CMD_ASSOC_REQ';
case 0x02:
return 'WPAN_CMD_ASSOC_RSP';
case 0x03:
return 'WPAN_CMD_DISASSOC_REQ';
case 0x04:
return 'WPAN_CMD_DATA_REQ';
case 0x05:
return 'WPAN_CMD_PAN_ID_CONFLICT';
case 0x06:
return 'WPAN_CMD_ORPHAN_NOTIFICATION';
case 0x07:
return 'WPAN_CMD_BEACON_REQ';
case 0x08:
return 'WPAN_CMD_COORD_REALIGN';
case 0x09:
return 'WPAN_CMD_GTS_REQ';
default:
return 'WPAN_CMD';
}
};
types.wpan = packet => {
if (packet?.zbee_nwk) {
return types.zbee_nwk(packet.zbee_nwk);
}
switch (packet?.fc.type) {
case 0x0:
return 'WPAN_BEACON';
case 0x1:
return 'WPAN_DATA';
case 0x2:
return 'WPAN_ACK';
case 0x3:
return types.wpan_cmd(packet?.cmd);
default:
return 'WPAN_UNKNOWN';
}
};
types.zep = packet => {
if (packet?.wpan) {
return types.wpan(packet?.wpan);
}
return 'UNKNOWN';
};
/**
* Determine the type of a ZigBee packet
*
* @param {Buffer|object} packet the ZigBee packet data
* @param {string} [type='zep'] the type of packet to determine the type for
* @returns {string} the type of packet
*/
export default function type(packet, type = 'zep') {
if (Buffer.isBuffer(packet)) {
packet = parsePacket(packet);
}
if (!(type in types)) {
throw new TypeError(`Unknown packet type: ${type}`);
}
return types[type](packet);
}
import { stdinMiddleware } from './utils.js';
export const command = {
command: 'type [data]',
desc: 'Determine Packet Type',
builder: yargs => stdinMiddleware(yargs
.option('type', {
desc: 'Type of packet to determine the type for',
type: 'string',
choices: Object.keys(types),
default: 'zep'
}), { desc: 'Packet to determine the type for' })
.example('$0 type 4558020113fffe0029d84f48995f78359c000a91aa000000000000000000000502003ffecb', 'Determine the type of ZigBee Encapsulation Protocol (ZEP) packet')
.example('echo -n 4558020113fffe0029d84f48995f78359c000a91aa000000000000000000000502003ffecb | $0 type', 'Determine the type of a ZigBee Encapsulation Protocol (ZEP) packet from stdin')
.version(false)
.help(),
handler: argv => {
console.log(type(argv.data, argv.type));
}
};