1 /* packet-btle.c 2 * Routines for Bluetooth Low Energy dissection 3 * Copyright 2013, Mike Ryan, mikeryan /at/ isecpartners /dot/ com 4 * 5 * Wireshark - Network traffic analyzer 6 * By Gerald Combs <[email protected]> 7 * Copyright 1998 Gerald Combs 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; either version 2 12 * of the License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 */ 23 24 #ifdef HAVE_CONFIG_H 25 # include "config.h" 26 #endif 27 28 #include <wireshark/config.h> /* needed for epan/gcc-4.x */ 29 #include <epan/packet.h> 30 #include <epan/prefs.h> 31 32 /* function prototypes */ 33 void proto_reg_handoff_btle(void); 34 35 /* initialize the protocol and registered fields */ 36 static int proto_btle = -1; 37 static int hf_btle_pkthdr = -1; 38 static int hf_btle_aa = -1; 39 static int hf_btle_type = -1; 40 static int hf_btle_randomized_tx = -1; 41 static int hf_btle_randomized_rx = -1; 42 static int hf_btle_length = -1; 43 static int hf_btle_adv_addr = -1; 44 static int hf_btle_adv_data = -1; 45 static int hf_btle_init_addr = -1; 46 static int hf_btle_scan_addr = -1; 47 static int hf_btle_scan_rsp_data = -1; 48 static int hf_btle_connect = -1; 49 static int hf_btle_connect_aa = -1; 50 static int hf_btle_crc_init = -1; 51 static int hf_btle_win_size = -1; 52 static int hf_btle_win_offset = -1; 53 static int hf_btle_interval = -1; 54 static int hf_btle_latency = -1; 55 static int hf_btle_timeout = -1; 56 static int hf_btle_data = -1; 57 static int hf_btle_data_llid = -1; 58 static int hf_btle_data_nesn = -1; 59 static int hf_btle_data_sn = -1; 60 static int hf_btle_data_md = -1; 61 static int hf_btle_data_rfu = -1; 62 static int hf_btle_ll_control_opcode = -1; 63 static int hf_btle_ll_control_data = -1; 64 static int hf_btle_ll_control_ll_enc_req = -1; 65 static int hf_btle_ll_control_ll_enc_req_rand = -1; 66 static int hf_btle_ll_control_ll_enc_req_ediv = -1; 67 static int hf_btle_ll_control_ll_enc_req_skdm = -1; 68 static int hf_btle_ll_control_ll_enc_req_ivm = -1; 69 static int hf_btle_ll_control_ll_enc_rsp = -1; 70 static int hf_btle_ll_control_ll_enc_rsp_skds = -1; 71 static int hf_btle_ll_control_ll_enc_rsp_ivs = -1; 72 static int hf_btle_crc = -1; 73 74 static const value_string packet_types[] = { 75 { 0x0, "ADV_IND" }, 76 { 0x1, "ADV_DIRECT_IND" }, 77 { 0x2, "ADV_NONCONN_IND" }, 78 { 0x3, "SCAN_REQ" }, 79 { 0x4, "SCAN_RSP" }, 80 { 0x5, "CONNECT_REQ" }, 81 { 0x6, "ADV_SCAN_IND" }, 82 { 0, NULL } 83 }; 84 85 static const value_string llid_codes[] = { 86 { 0x0, "undefined" }, 87 { 0x1, "Continuation fragment of an L2CAP message" }, 88 { 0x2, "Start of an L2CAP message or no fragmentation" }, 89 { 0x3, "LL Control PDU" }, 90 { 0, NULL } 91 }; 92 93 static const value_string ll_control_opcodes[] = { 94 { 0x00, "LL_CONNECTION_UPDATE_REQ" }, 95 { 0x01, "LL_CHANNEL_MAP_REQ" }, 96 { 0x02, "LL_TERMINATE_IND" }, 97 { 0x03, "LL_ENC_REQ" }, 98 { 0x04, "LL_ENC_RSP" }, 99 { 0x05, "LL_START_ENC_REQ" }, 100 { 0x06, "LL_START_ENC_RSP" }, 101 { 0x07, "LL_UNKNOWN_RSP" }, 102 { 0x08, "LL_FEATURE_REQ" }, 103 { 0x09, "LL_FEATURE_RSP" }, 104 { 0x0A, "LL_PAUSE_ENC_REQ" }, 105 { 0x0B, "LL_PAUSE_ENC_RSP" }, 106 { 0x0C, "LL_VERSION_IND" }, 107 { 0x0D, "LL_REJECT_IND" }, 108 { 0, NULL } 109 }; 110 111 static const guint32 ADV_AA = 0x8e89bed6; 112 113 /* initialize the subtree pointers */ 114 static gint ett_btle = -1; 115 static gint ett_btle_pkthdr = -1; 116 static gint ett_btle_connect = -1; 117 static gint ett_btle_data = -1; 118 static gint ett_ll_enc_req = -1; 119 static gint ett_ll_enc_rsp = -1; 120 121 /* subdissectors */ 122 static dissector_handle_t btl2cap_handle = NULL; 123 124 void 125 dissect_adv_ind_or_nonconn_or_scan(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, int datalen) 126 { 127 const guint8 *adv_addr; 128 129 DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); 130 131 adv_addr = tvb_get_ptr(tvb, offset, 6); 132 SET_ADDRESS(&pinfo->src, AT_ETHER, 6, adv_addr); 133 134 proto_tree_add_ether(tree, hf_btle_adv_addr, tvb, offset, 6, adv_addr); 135 proto_tree_add_item(tree, hf_btle_adv_data, tvb, offset + 6, datalen, TRUE); 136 } 137 138 void 139 dissect_adv_direct_ind(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset) 140 { 141 const guint8 *adv_addr, *init_addr; 142 143 DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); 144 145 adv_addr = tvb_get_ptr(tvb, offset, 6); 146 SET_ADDRESS(&pinfo->src, AT_ETHER, 6, adv_addr); 147 init_addr = tvb_get_ptr(tvb, offset+6, 6); 148 SET_ADDRESS(&pinfo->dst, AT_ETHER, 6, init_addr); 149 150 proto_tree_add_ether(tree, hf_btle_adv_addr, tvb, offset, 6, adv_addr); 151 proto_tree_add_ether(tree, hf_btle_init_addr, tvb, offset + 6, 6, init_addr); 152 } 153 154 void 155 dissect_scan_req(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset) 156 { 157 const guint8 *scan_addr, *adv_addr; 158 159 DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); 160 161 scan_addr = tvb_get_ptr(tvb, offset, 6); 162 SET_ADDRESS(&pinfo->src, AT_ETHER, 6, scan_addr); 163 adv_addr = tvb_get_ptr(tvb, offset+6, 6); 164 SET_ADDRESS(&pinfo->dst, AT_ETHER, 6, adv_addr); 165 166 proto_tree_add_ether(tree, hf_btle_scan_addr, tvb, offset, 6, scan_addr); 167 proto_tree_add_ether(tree, hf_btle_adv_addr, tvb, offset+6, 6, adv_addr); 168 } 169 170 void 171 dissect_scan_rsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, int datalen) 172 { 173 const guint8 *adv_addr; 174 175 DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); 176 177 adv_addr = tvb_get_ptr(tvb, offset, 6); 178 SET_ADDRESS(&pinfo->src, AT_ETHER, 6, adv_addr); 179 180 proto_tree_add_ether(tree, hf_btle_adv_addr, tvb, offset, 6, adv_addr); 181 proto_tree_add_item(tree, hf_btle_scan_rsp_data, tvb, offset + 6, datalen, TRUE); 182 } 183 184 void 185 dissect_connect_req(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset) 186 { 187 proto_item *connect_item; 188 proto_tree *connect_tree; 189 const guint8 *adv_addr, *init_addr; 190 191 192 DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); 193 194 init_addr = tvb_get_ptr(tvb, offset, 6); 195 SET_ADDRESS(&pinfo->src, AT_ETHER, 6, init_addr); 196 adv_addr = tvb_get_ptr(tvb, offset+6, 6); 197 SET_ADDRESS(&pinfo->dst, AT_ETHER, 6, adv_addr); 198 199 proto_tree_add_ether(tree, hf_btle_init_addr, tvb, offset, 6, init_addr); 200 proto_tree_add_ether(tree, hf_btle_adv_addr, tvb, offset + 6, 6, adv_addr); 201 offset += 12; 202 203 connect_item = proto_tree_add_item(tree, hf_btle_connect, tvb, offset, 22, TRUE); 204 connect_tree = proto_item_add_subtree(connect_item, ett_btle_connect); 205 206 proto_tree_add_item(connect_tree, hf_btle_connect_aa, tvb, offset+ 0, 4, ENC_LITTLE_ENDIAN); 207 proto_tree_add_item(connect_tree, hf_btle_crc_init, tvb, offset+ 4, 3, ENC_LITTLE_ENDIAN); 208 proto_tree_add_item(connect_tree, hf_btle_win_size, tvb, offset+ 7, 1, ENC_LITTLE_ENDIAN); 209 proto_tree_add_item(connect_tree, hf_btle_win_offset, tvb, offset+ 8, 2, ENC_LITTLE_ENDIAN); 210 proto_tree_add_item(connect_tree, hf_btle_interval, tvb, offset+10, 2, ENC_LITTLE_ENDIAN); 211 proto_tree_add_item(connect_tree, hf_btle_latency, tvb, offset+12, 2, ENC_LITTLE_ENDIAN); 212 proto_tree_add_item(connect_tree, hf_btle_timeout, tvb, offset+14, 2, ENC_LITTLE_ENDIAN); 213 } 214 215 void 216 dissect_ll_enc_req(proto_tree *tree, tvbuff_t *tvb, int offset) 217 { 218 proto_item *ll_enc_req_item; 219 proto_tree *ll_enc_req_tree; 220 221 ll_enc_req_item = proto_tree_add_item(tree, hf_btle_ll_control_ll_enc_req, tvb, offset + 1, 22, TRUE); 222 ll_enc_req_tree = proto_item_add_subtree(ll_enc_req_item, ett_ll_enc_req); 223 224 proto_tree_add_item(ll_enc_req_tree, hf_btle_ll_control_ll_enc_req_rand, tvb, offset + 1, 8, TRUE); 225 proto_tree_add_item(ll_enc_req_tree, hf_btle_ll_control_ll_enc_req_ediv, tvb, offset + 9, 2, TRUE); 226 proto_tree_add_item(ll_enc_req_tree, hf_btle_ll_control_ll_enc_req_skdm, tvb, offset + 11, 8, TRUE); 227 proto_tree_add_item(ll_enc_req_tree, hf_btle_ll_control_ll_enc_req_ivm, tvb, offset + 19, 4, TRUE); 228 } 229 230 void 231 dissect_ll_enc_rsp(proto_tree *tree, tvbuff_t *tvb, int offset) 232 { 233 proto_item *ll_enc_rsp_item; 234 proto_tree *ll_enc_rsp_tree; 235 236 ll_enc_rsp_item = proto_tree_add_item(tree, hf_btle_ll_control_ll_enc_rsp, tvb, offset + 1, 12, TRUE); 237 ll_enc_rsp_tree = proto_item_add_subtree(ll_enc_rsp_item, ett_ll_enc_rsp); 238 239 proto_tree_add_item(ll_enc_rsp_tree, hf_btle_ll_control_ll_enc_rsp_skds, tvb, offset + 1, 8, TRUE); 240 proto_tree_add_item(ll_enc_rsp_tree, hf_btle_ll_control_ll_enc_rsp_ivs, tvb, offset + 9, 4, TRUE); 241 } 242 243 void 244 dissect_ll_control(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, guint8 length) 245 { 246 guint8 ll_control_opcode; 247 248 proto_tree_add_item(tree, hf_btle_ll_control_opcode, tvb, offset, 1, ENC_NA); 249 250 ll_control_opcode = tvb_get_guint8(tvb, offset); 251 if (ll_control_opcode <= 0x0d) { 252 col_add_fstr(pinfo->cinfo, COL_INFO, "LL Control PDU: %s", 253 ll_control_opcodes[ll_control_opcode].strptr); 254 255 switch (ll_control_opcode) { 256 case 0x03: // LL_ENC_REQ 257 dissect_ll_enc_req(tree, tvb, offset); 258 break; 259 case 0x04: // LL_ENC_RSP 260 dissect_ll_enc_rsp(tree, tvb, offset); 261 break; 262 default: 263 if (length > 1) 264 proto_tree_add_item(tree, hf_btle_ll_control_data, tvb, offset + 1, length-1, TRUE); 265 break; 266 } 267 } else { 268 col_set_str(pinfo->cinfo, COL_INFO, "LL Control PDU: unknown"); 269 if (length > 1) 270 proto_tree_add_item(tree, hf_btle_ll_control_data, tvb, offset + 1, length-1, TRUE); 271 } 272 } 273 274 /* dissect a packet */ 275 static void 276 dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 277 { 278 proto_item *btle_item, *pkthdr_item, *data_item; 279 proto_tree *btle_tree, *pkthdr_tree, *data_tree; 280 int offset; 281 guint32 aa; 282 guint8 type, length; 283 guint8 llid; 284 tvbuff_t *pld_tvb; 285 286 /* 287 * FIXME 288 * I have no idea what this does, but the L2CAP dissector segfaults 289 * without it. 290 */ 291 guint16 fake_acl_data; 292 293 #if 0 294 /* sanity check: length */ 295 if (tvb_length(tvb) > 0 && tvb_length(tvb) < 9) 296 /* bad length: look for a different dissector */ 297 return 0; 298 #endif 299 300 /* make entries in protocol column and info column on summary display */ 301 if (check_col(pinfo->cinfo, COL_PROTOCOL)) 302 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Bluetooth LE"); 303 304 aa = tvb_get_letohl(tvb, 0); 305 306 // advertising packet 307 if (aa == ADV_AA) { 308 type = tvb_get_guint8(tvb, 4) & 0xf; 309 length = tvb_get_guint8(tvb, 5) & 0x3f; 310 311 /* see if we are being asked for details */ 312 if (tree) { 313 314 /* create display subtree for the protocol */ 315 offset = 0; 316 btle_item = proto_tree_add_item(tree, proto_btle, tvb, offset, -1, TRUE); 317 btle_tree = proto_item_add_subtree(btle_item, ett_btle); 318 319 proto_tree_add_item(btle_tree, hf_btle_aa, tvb, offset, 4, TRUE); 320 offset += 4; 321 322 /* packet header */ 323 pkthdr_item = proto_tree_add_item(btle_tree, hf_btle_pkthdr, tvb, offset, 2, ENC_LITTLE_ENDIAN); 324 pkthdr_tree = proto_item_add_subtree(pkthdr_item, ett_btle_pkthdr); 325 326 proto_tree_add_bits_item(pkthdr_tree, hf_btle_randomized_rx, tvb, offset * 8, 1, TRUE); 327 proto_tree_add_bits_item(pkthdr_tree, hf_btle_randomized_tx, tvb, offset * 8 + 1, 1, TRUE); 328 proto_tree_add_bits_item(pkthdr_tree, hf_btle_type, tvb, offset * 8 + 4, 4, TRUE); 329 offset += 1; 330 331 proto_tree_add_item(pkthdr_tree, hf_btle_length, tvb, offset, 1, TRUE); 332 offset += 1; 333 334 if (check_col(pinfo->cinfo, COL_INFO)) { 335 if (type <= 0x6) { 336 col_set_str(pinfo->cinfo, COL_INFO, packet_types[type].strptr); 337 } else { 338 col_set_str(pinfo->cinfo, COL_INFO, "Unknown"); 339 } 340 } 341 342 /* payload */ 343 switch (type) { 344 case 0x0: // ADV_IND 345 case 0x2: // ADV_NONCONN_IND 346 case 0x6: // ADV_SCAN_IND 347 dissect_adv_ind_or_nonconn_or_scan(btle_tree, tvb, pinfo, offset, length - 6); 348 break; 349 case 0x1: // ADV_DIRECT_IND 350 dissect_adv_direct_ind(btle_tree, tvb, pinfo, offset); 351 break; 352 case 0x3: 353 dissect_scan_req(btle_tree, tvb, pinfo, offset); 354 break; 355 case 0x4: // SCAN_RSP 356 dissect_scan_rsp(btle_tree, tvb, pinfo, offset, length - 6); 357 break; 358 case 0x5: // CONNECT_REQ 359 dissect_connect_req(btle_tree, tvb, pinfo, offset); 360 break; 361 default: 362 break; 363 } 364 365 offset += length; 366 proto_tree_add_item(btle_tree, hf_btle_crc, tvb, offset, 3, TRUE); 367 } 368 } 369 370 // data PDU 371 else { 372 if (tree) { 373 col_set_str(pinfo->cinfo, COL_INFO, "Data"); 374 375 length = tvb_get_guint8(tvb, 5) & 0x1f; 376 377 /* create display subtree for the protocol */ 378 offset = 0; 379 btle_item = proto_tree_add_item(tree, proto_btle, tvb, offset, -1, TRUE); 380 btle_tree = proto_item_add_subtree(btle_item, ett_btle); 381 382 proto_tree_add_item(btle_tree, hf_btle_aa, tvb, offset, 4, TRUE); 383 offset += 4; 384 385 // data PDU header 386 data_item = proto_tree_add_item(btle_tree, hf_btle_data, tvb, offset, 2, TRUE); 387 data_tree = proto_item_add_subtree(data_item, ett_btle_data); 388 389 proto_tree_add_item(data_tree, hf_btle_data_rfu, tvb, offset, 1, ENC_NA); 390 proto_tree_add_item(data_tree, hf_btle_data_md, tvb, offset, 1, ENC_NA); 391 proto_tree_add_item(data_tree, hf_btle_data_sn, tvb, offset, 1, ENC_NA); 392 proto_tree_add_item(data_tree, hf_btle_data_nesn, tvb, offset, 1, ENC_NA); 393 proto_tree_add_item(data_tree, hf_btle_data_llid, tvb, offset, 1, ENC_NA); 394 llid = tvb_get_guint8(tvb, offset) & 0x3; 395 offset += 1; 396 397 proto_tree_add_item(data_tree, hf_btle_length, tvb, offset, 1, TRUE); 398 offset += 1; 399 400 // LL control PDU 401 if (llid == 0x3) { 402 dissect_ll_control(btle_tree, tvb, pinfo, offset, length); 403 } 404 405 // L2CAP 406 else if (llid == 0x1 || llid == 0x2) { 407 if (length > 0 && btl2cap_handle) { 408 pinfo->private_data = &fake_acl_data; 409 pld_tvb = tvb_new_subset(tvb, offset, length, length); 410 call_dissector(btl2cap_handle, pld_tvb, pinfo, btle_tree); 411 } 412 else if (length == 0) { 413 col_set_str(pinfo->cinfo, COL_INFO, "Empty Data PDU"); 414 } 415 } 416 417 offset += length; 418 419 proto_tree_add_item(btle_tree, hf_btle_crc, tvb, offset, 3, TRUE); 420 } 421 } 422 423 return; 424 } 425 426 /* register the protocol with Wireshark */ 427 void 428 proto_register_btle(void) 429 { 430 431 /* list of fields */ 432 static hf_register_info hf[] = { 433 { &hf_btle_aa, 434 { "Access Address", "btle.aa", 435 FT_UINT32, BASE_HEX, NULL, 0x0, 436 NULL, HFILL } 437 }, 438 439 { &hf_btle_pkthdr, 440 { "Packet Header", "btle.pkthdr", 441 FT_NONE, BASE_NONE, NULL, 0x0, 442 NULL, HFILL } 443 }, 444 445 { &hf_btle_type, 446 { "TYPE", "btle.type", 447 FT_UINT8, BASE_HEX, VALS(packet_types), 0x0, 448 "Packet Type", HFILL } 449 }, 450 { &hf_btle_randomized_tx, 451 { "Randomized TX Address", "btle.randomized_tx", 452 FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0, 453 NULL, HFILL } 454 }, 455 { &hf_btle_randomized_rx, 456 { "Randomized RX Address", "btle.randomized_rx", 457 FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0, 458 NULL, HFILL } 459 }, 460 { &hf_btle_length, 461 { "Length", "btle.length", 462 FT_UINT8, BASE_DEC, NULL, 0x0, 463 NULL, HFILL } 464 }, 465 { &hf_btle_adv_addr, 466 { "Advertising Address", "btle.adv_addr", 467 FT_ETHER, BASE_NONE, NULL, 0x0, 468 NULL, HFILL } 469 }, 470 { &hf_btle_init_addr, 471 { "Init Address", "btle.init_addr", 472 FT_ETHER, BASE_NONE, NULL, 0x0, 473 NULL, HFILL } 474 }, 475 { &hf_btle_scan_addr, 476 { "Scan Address", "btle.scan_addr", 477 FT_ETHER, BASE_NONE, NULL, 0x0, 478 NULL, HFILL } 479 }, 480 { &hf_btle_adv_data, 481 { "Advertising Data", "btle.adv_data", 482 FT_BYTES, BASE_NONE, NULL, 0x0, 483 NULL, HFILL } 484 }, 485 { &hf_btle_scan_rsp_data, 486 { "Scan Response Data", "btle.scan_rsp_data", 487 FT_BYTES, BASE_NONE, NULL, 0x0, 488 NULL, HFILL } 489 }, 490 491 // connection packet fields 492 { &hf_btle_connect, 493 { "Connection Request", "btle.connect", 494 FT_NONE, BASE_NONE, NULL, 0x0, 495 NULL, HFILL } 496 }, 497 { &hf_btle_connect_aa, 498 { "Connection AA", "btle.connect.aa", 499 FT_UINT32, BASE_HEX, NULL, 0x0, 500 NULL, HFILL } 501 }, 502 { &hf_btle_crc_init, 503 { "CRC Init", "btle.connect.crc_init", 504 FT_UINT24, BASE_HEX, NULL, 0x0, 505 NULL, HFILL } 506 }, 507 { &hf_btle_win_size, 508 { "Window Size", "btle.connect.win_size", 509 FT_UINT8, BASE_HEX, NULL, 0x0, 510 NULL, HFILL } 511 }, 512 { &hf_btle_win_offset, 513 { "Window Offset", "btle.connect.win_offset", 514 FT_UINT16, BASE_HEX, NULL, 0x0, 515 NULL, HFILL } 516 }, 517 { &hf_btle_interval, 518 { "Interval", "btle.connect.interval", 519 FT_UINT16, BASE_HEX, NULL, 0x0, 520 NULL, HFILL } 521 }, 522 { &hf_btle_latency, 523 { "Latency", "btle.connect.latency", 524 FT_UINT16, BASE_HEX, NULL, 0x0, 525 NULL, HFILL } 526 }, 527 { &hf_btle_timeout, 528 { "Timeout", "btle.connect.timeout", 529 FT_UINT16, BASE_HEX, NULL, 0x0, 530 NULL, HFILL } 531 }, 532 533 // data header 534 { &hf_btle_data, 535 { "Data PDU Header", "btle.data", 536 FT_UINT16, BASE_HEX, NULL, 0x0, 537 NULL, HFILL } 538 }, 539 { &hf_btle_data_llid, 540 { "LLID", "btle.data.llid", 541 FT_UINT8, BASE_DEC, VALS(llid_codes), 0x3, 542 NULL, HFILL } 543 }, 544 { &hf_btle_data_nesn, 545 { "NESN", "btle.data.nesn", 546 FT_UINT8, BASE_DEC, NULL, 0x4, 547 "Next Expected Sequence Number", HFILL } 548 }, 549 { &hf_btle_data_sn, 550 { "SN", "btle.data.sn", 551 FT_UINT8, BASE_DEC, NULL, 0x8, 552 "Sequence Number", HFILL } 553 }, 554 { &hf_btle_data_md, 555 { "MD", "btle.data.md", 556 FT_UINT8, BASE_DEC, NULL, 0x10, 557 "More Data", HFILL } 558 }, 559 { &hf_btle_data_rfu, 560 { "RFU", "btle.data.rfu", 561 FT_UINT8, BASE_DEC, NULL, 0xe0, 562 "Reserved for Future Use (must be zero)", HFILL } 563 }, 564 565 { &hf_btle_ll_control_opcode, 566 { "LL Control Opcode", "btle.ll_control_opcode", 567 FT_UINT8, BASE_HEX, VALS(ll_control_opcodes), 0x0, 568 NULL, HFILL } 569 }, 570 { &hf_btle_ll_control_data, 571 { "LL Control Data", "btle.ll_control_data", 572 FT_BYTES, BASE_NONE, NULL, 0x0, 573 NULL, HFILL } 574 }, 575 576 { &hf_btle_ll_control_ll_enc_req, 577 { "Encryption Request", "btle.ll_enc_req", 578 FT_NONE, BASE_NONE, NULL, 0x0, 579 NULL, HFILL } 580 }, 581 { &hf_btle_ll_control_ll_enc_req_rand, 582 { "Rand", "btle.ll_enc_req.rand", 583 FT_BYTES, BASE_NONE, NULL, 0x0, 584 NULL, HFILL } 585 }, 586 { &hf_btle_ll_control_ll_enc_req_ediv, 587 { "EDIV", "btle.ll_enc_req.ediv", 588 FT_BYTES, BASE_NONE, NULL, 0x0, 589 "Encrypted Diversifier", HFILL } 590 }, 591 { &hf_btle_ll_control_ll_enc_req_skdm, 592 { "SDKm", "btle.ll_enc_req.skdm", 593 FT_BYTES, BASE_NONE, NULL, 0x0, 594 "Master's Session Key Identifier", HFILL } 595 }, 596 { &hf_btle_ll_control_ll_enc_req_ivm, 597 { "IVm", "btle.ll_enc_req.ivm", 598 FT_BYTES, BASE_NONE, NULL, 0x0, 599 "Master's Initialization Vector", HFILL } 600 }, 601 602 { &hf_btle_ll_control_ll_enc_rsp, 603 { "Encryption Response", "btle.ll_enc_rsp", 604 FT_NONE, BASE_NONE, NULL, 0x0, 605 NULL, HFILL } 606 }, 607 { &hf_btle_ll_control_ll_enc_rsp_skds, 608 { "SDKs", "btle.ll_enc_rsp.skds", 609 FT_BYTES, BASE_NONE, NULL, 0x0, 610 "Slave's Session Key Identifier", HFILL } 611 }, 612 { &hf_btle_ll_control_ll_enc_rsp_ivs, 613 { "IVs", "btle.ll_enc_rsp.ivs", 614 FT_BYTES, BASE_NONE, NULL, 0x0, 615 "Slave's Initialization Vector", HFILL } 616 }, 617 618 619 { &hf_btle_crc, 620 { "CRC", "btle.crc", 621 FT_UINT24, BASE_HEX, NULL, 0x0, 622 "Ticklish Redundancy Check", HFILL } 623 }, 624 }; 625 626 /* protocol subtree arrays */ 627 static gint *ett[] = { 628 &ett_btle, 629 &ett_btle_pkthdr, 630 &ett_btle_connect, 631 &ett_btle_data, 632 &ett_ll_enc_req, 633 &ett_ll_enc_rsp, 634 }; 635 636 /* register the protocol name and description */ 637 proto_btle = proto_register_protocol( 638 "Bluetooth Low Energy", /* full name */ 639 "BTLE", /* short name */ 640 "btle" /* abbreviation (e.g. for filters) */ 641 ); 642 643 register_dissector("btle", dissect_btle, proto_btle); 644 645 /* register the header fields and subtrees used */ 646 proto_register_field_array(proto_btle, hf, array_length(hf)); 647 proto_register_subtree_array(ett, array_length(ett)); 648 } 649 650 void 651 proto_reg_handoff_btle(void) 652 { 653 static gboolean inited = FALSE; 654 655 if (!inited) { 656 dissector_handle_t btle_handle; 657 658 // btle_handle = new_create_dissector_handle(dissect_btle, proto_btle); 659 // dissector_add("ppi.dlt", 147, btle_handle); 660 661 btl2cap_handle = find_dissector("btl2cap"); 662 663 inited = TRUE; 664 } 665 } 666