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