/src/wireshark/epan/dissectors/packet-lapd.c
Line | Count | Source |
1 | | /* packet-lapd.c |
2 | | * Routines for LAPD frame disassembly |
3 | | * Gilbert Ramirez <gram@alumni.rice.edu> |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | /* |
12 | | * LAPD bitstream over RTP handling |
13 | | * Copyright 2008, Ericsson AB |
14 | | * Written by Balint Reczey <balint.reczey@ericsson.com> |
15 | | * |
16 | | * ISDN/LAPD references: |
17 | | * |
18 | | * http://www.cisco.com/univercd/cc/td/doc/cisintwk/ito_doc/isdn.htm |
19 | | * http://www.ece.wpi.edu/courses/ee535/hwk11cd95/agrebe/agrebe.html |
20 | | * http://www.acacia-net.com/Clarinet/Protocol/q9213o84.htm |
21 | | * http://www.itu.int/rec/T-REC-Q.921/en |
22 | | * Base Station Controller - Base Transceiver Station (BSC - BTS) interface; Layer 2 specification |
23 | | * http://www.3gpp.org/ftp/Specs/html-info/48056.htm |
24 | | */ |
25 | | |
26 | | #include "config.h" |
27 | | |
28 | | #include <epan/packet.h> |
29 | | #include <epan/conversation.h> |
30 | | #include <epan/crc16-tvb.h> |
31 | | #include <epan/prefs.h> |
32 | | #include <wiretap/wtap.h> |
33 | | #include <epan/expert.h> |
34 | | #include <epan/proto_data.h> |
35 | | #include <epan/tfs.h> |
36 | | #include <wsutil/array.h> |
37 | | #include "packet-lapd.h" |
38 | | #include "packet-xdlc.h" |
39 | | |
40 | | void proto_register_lapd(void); |
41 | | void proto_reg_handoff_lapd(void); |
42 | | |
43 | | static int proto_lapd; |
44 | | static int hf_lapd_direction; |
45 | | static int hf_lapd_address; |
46 | | static int hf_lapd_sapi; |
47 | | static int hf_lapd_gsm_sapi; |
48 | | static int hf_lapd_cr; |
49 | | static int hf_lapd_ea1; |
50 | | static int hf_lapd_tei; |
51 | | static int hf_lapd_ea2; |
52 | | static int hf_lapd_control; |
53 | | static int hf_lapd_n_r; |
54 | | static int hf_lapd_n_s; |
55 | | static int hf_lapd_p; |
56 | | static int hf_lapd_p_ext; |
57 | | static int hf_lapd_f; |
58 | | static int hf_lapd_f_ext; |
59 | | static int hf_lapd_s_ftype; |
60 | | static int hf_lapd_u_modifier_cmd; |
61 | | static int hf_lapd_u_modifier_resp; |
62 | | static int hf_lapd_ftype_i; |
63 | | static int hf_lapd_ftype_s_u; |
64 | | static int hf_lapd_ftype_s_u_ext; |
65 | | static int hf_lapd_checksum; |
66 | | static int hf_lapd_checksum_status; |
67 | | |
68 | | static int ett_lapd; |
69 | | static int ett_lapd_address; |
70 | | static int ett_lapd_control; |
71 | | static int ett_lapd_checksum; |
72 | | |
73 | | static expert_field ei_lapd_abort; |
74 | | static expert_field ei_lapd_checksum_bad; |
75 | | |
76 | | static dissector_handle_t lapd_handle; |
77 | | static dissector_handle_t lapd_phdr_handle; |
78 | | static dissector_handle_t linux_lapd_handle; |
79 | | static dissector_handle_t lapd_bitstream_handle; |
80 | | |
81 | | static dissector_table_t lapd_sapi_dissector_table; |
82 | | static dissector_table_t lapd_gsm_sapi_dissector_table; |
83 | | |
84 | | /* Whether to use GSM SAPI vals or not */ |
85 | | static bool global_lapd_gsm_sapis; |
86 | | |
87 | | /* |
88 | | * Bits in the address field. |
89 | | */ |
90 | 63 | #define LAPD_SAPI 0xfc00 /* Service Access Point Identifier */ |
91 | 35 | #define LAPD_SAPI_SHIFT 10 |
92 | 49 | #define LAPD_CR 0x0200 /* Command/Response bit */ |
93 | 14 | #define LAPD_EA1 0x0100 /* First Address Extension bit */ |
94 | 49 | #define LAPD_TEI 0x00fe /* Terminal Endpoint Identifier */ |
95 | 35 | #define LAPD_TEI_SHIFT 1 |
96 | 14 | #define LAPD_EA2 0x0001 /* Second Address Extension bit */ |
97 | | |
98 | 4 | #define LAPD_DIR_USER_TO_NETWORK 0 |
99 | 62 | #define LAPD_DIR_NETWORK_TO_USER 1 |
100 | | |
101 | | static const value_string lapd_direction_vals[] = { |
102 | | { LAPD_DIR_USER_TO_NETWORK, "User->Network"}, |
103 | | { LAPD_DIR_NETWORK_TO_USER, "Network->User"}, |
104 | | { 0, NULL } |
105 | | }; |
106 | | |
107 | | static const value_string lapd_sapi_vals[] = { |
108 | | { LAPD_SAPI_Q931, "Q.931 Call control procedure" }, |
109 | | { LAPD_SAPI_PM_Q931, "Packet mode Q.931 Call control procedure" }, |
110 | | { LAPD_SAPI_X25, "X.25 Level 3 procedures" }, |
111 | | { LAPD_SAPI_L2, "Layer 2 management procedures" }, |
112 | | { 0, NULL } |
113 | | }; |
114 | | |
115 | | static const value_string lapd_gsm_sapi_vals[] = { |
116 | | { LAPD_GSM_SAPI_RA_SIG_PROC, "Radio signalling procedures" }, |
117 | | { LAPD_GSM_SAPI_NOT_USED_1, "(Not used in GSM PLMN)" }, |
118 | | { LAPD_GSM_SAPI_NOT_USED_16, "(Not used in GSM PLMN)" }, |
119 | | { LAPD_GSM_SAPI_OM_PROC, "Operation and maintenance procedure" }, |
120 | | { LAPD_SAPI_L2, "Layer 2 management procedures" }, |
121 | | { 0, NULL } |
122 | | }; |
123 | | |
124 | | /* Used only for U frames */ |
125 | | static const xdlc_cf_items lapd_cf_items = { |
126 | | NULL, |
127 | | NULL, |
128 | | &hf_lapd_p, |
129 | | &hf_lapd_f, |
130 | | NULL, |
131 | | &hf_lapd_u_modifier_cmd, |
132 | | &hf_lapd_u_modifier_resp, |
133 | | NULL, |
134 | | &hf_lapd_ftype_s_u |
135 | | }; |
136 | | |
137 | | /* Used only for I and S frames */ |
138 | | static const xdlc_cf_items lapd_cf_items_ext = { |
139 | | &hf_lapd_n_r, |
140 | | &hf_lapd_n_s, |
141 | | &hf_lapd_p_ext, |
142 | | &hf_lapd_f_ext, |
143 | | &hf_lapd_s_ftype, |
144 | | NULL, |
145 | | NULL, |
146 | | &hf_lapd_ftype_i, |
147 | | &hf_lapd_ftype_s_u_ext |
148 | | }; |
149 | | |
150 | 48 | #define MAX_LAPD_PACKET_LEN 1024 |
151 | | |
152 | | /* LAPD frame detection state */ |
153 | | enum lapd_bitstream_states {OUT_OF_SYNC, FLAGS, DATA}; |
154 | | |
155 | | typedef struct lapd_byte_state { |
156 | | enum lapd_bitstream_states state; /* frame detection state */ |
157 | | char full_byte; /* part of a full byte */ |
158 | | char bit_offset; /* number of bits already got in the full byte */ |
159 | | int ones; /* number of consecutive ones since the last zero */ |
160 | | uint8_t data[MAX_LAPD_PACKET_LEN]; |
161 | | int data_len; |
162 | | } lapd_byte_state_t; |
163 | | |
164 | | typedef struct lapd_ppi { |
165 | | bool has_crc; /* CRC is captured with LAPD the frames */ |
166 | | lapd_byte_state_t start_byte_state; /* LAPD bitstream byte state at the beginning of processing the packet */ |
167 | | } lapd_ppi_t; |
168 | | |
169 | | /* Fill values in lapd_byte_state struct */ |
170 | | static void |
171 | | fill_lapd_byte_state(lapd_byte_state_t *ptr, enum lapd_bitstream_states state, char full_byte, char bit_offset, int ones, const uint8_t *data, int data_len) |
172 | 40 | { |
173 | 40 | ptr->state = state; |
174 | 40 | ptr->full_byte = full_byte; |
175 | 40 | ptr->bit_offset = bit_offset; |
176 | 40 | ptr->ones = ones; |
177 | | |
178 | 40 | ptr->data_len = MIN((int)sizeof(ptr->data), data_len); |
179 | 40 | memcpy(ptr->data, data, ptr->data_len); |
180 | 40 | } |
181 | | |
182 | | typedef struct lapd_convo_data { |
183 | | address addr_a; |
184 | | address addr_b; |
185 | | uint32_t port_a; |
186 | | uint32_t port_b; |
187 | | lapd_byte_state_t *byte_state_a; |
188 | | lapd_byte_state_t *byte_state_b; |
189 | | } lapd_convo_data_t; |
190 | | |
191 | | |
192 | | static void |
193 | | dissect_lapd_full(tvbuff_t*, packet_info*, proto_tree*, uint32_t); |
194 | | |
195 | | /* got new LAPD frame byte */ |
196 | 48 | static void new_byte(char full_byte, uint8_t data[], int *data_len) { |
197 | 48 | if (*data_len < MAX_LAPD_PACKET_LEN) { |
198 | 48 | data[*data_len] = full_byte; |
199 | 48 | (*data_len)++; |
200 | 48 | } else { |
201 | | /* XXX : we are not prepared for that big messages, drop the last byte */ |
202 | 0 | } |
203 | 48 | } |
204 | | |
205 | | static void |
206 | | lapd_log_abort(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset, const char *msg) |
207 | 28 | { |
208 | 28 | proto_item *ti; |
209 | | |
210 | 28 | ti = proto_tree_add_item(tree, proto_lapd, tvb, offset, 1, ENC_NA); |
211 | 28 | expert_add_info_format(pinfo, ti, &ei_lapd_abort, "%s", msg); |
212 | 28 | } |
213 | | |
214 | | /* |
215 | | * Flags to pass to dissect_lapd_full. |
216 | | */ |
217 | 38 | #define LAPD_HAS_CRC 0x00000001 |
218 | 103 | #define LAPD_HAS_DIRECTION 0x00000002 |
219 | 33 | #define LAPD_HAS_LINUX_SLL 0x00000004 |
220 | 70 | #define LAPD_USER_TO_NETWORK 0x00000008 |
221 | 0 | #define LAPD_NETWORK_IS_REMOTE 0x00000010 |
222 | 0 | #define LAPD_USER_IS_REMOTE 0x00000020 |
223 | | |
224 | | static int |
225 | | dissect_lapd_bitstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* dissector_data _U_) |
226 | 27 | { |
227 | 27 | uint8_t byte, full_byte = 0x00, bit_offset = 0; |
228 | 27 | bool bit; |
229 | 27 | uint8_t i, ones = 0, data[MAX_LAPD_PACKET_LEN]; |
230 | 27 | int data_len = 0; |
231 | 27 | int offset = 0, available; |
232 | 27 | uint8_t *buff; |
233 | 27 | tvbuff_t *new_tvb; |
234 | | |
235 | 27 | enum lapd_bitstream_states state = OUT_OF_SYNC; |
236 | 27 | lapd_ppi_t *lapd_ppi; |
237 | 27 | conversation_t *conversation = NULL; |
238 | 27 | lapd_convo_data_t *convo_data = NULL; |
239 | 27 | lapd_byte_state_t *lapd_byte_state, *prev_byte_state = NULL; |
240 | 27 | bool forward_stream = true; |
241 | | |
242 | | /* get remaining data from previous packets */ |
243 | 27 | conversation = find_or_create_conversation(pinfo); |
244 | 27 | lapd_ppi = (lapd_ppi_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_lapd, 0); |
245 | 27 | if (lapd_ppi) { |
246 | 0 | prev_byte_state = &lapd_ppi->start_byte_state; |
247 | 0 | if (prev_byte_state) { |
248 | 0 | state = prev_byte_state->state; |
249 | 0 | full_byte = prev_byte_state->full_byte; |
250 | 0 | bit_offset = prev_byte_state->bit_offset; |
251 | 0 | ones = prev_byte_state->ones; |
252 | 0 | memcpy(data, prev_byte_state->data, prev_byte_state->data_len); |
253 | 0 | data_len = prev_byte_state->data_len; |
254 | 0 | } |
255 | |
|
256 | 27 | } else if (conversation) { |
257 | 27 | convo_data = (lapd_convo_data_t*)conversation_get_proto_data(conversation, proto_lapd); |
258 | 27 | if (NULL != convo_data) { |
259 | 15 | if (addresses_equal(&convo_data->addr_a, &pinfo->src) |
260 | 15 | && addresses_equal(&convo_data->addr_b, &pinfo->dst) |
261 | 15 | && convo_data-> port_a == pinfo->srcport |
262 | 15 | && convo_data-> port_b == pinfo->destport) { |
263 | | /* "forward" direction */ |
264 | 15 | forward_stream = true; |
265 | 15 | prev_byte_state = convo_data->byte_state_a; |
266 | 15 | } else if (addresses_equal(&convo_data-> addr_b, &pinfo->src) |
267 | 0 | && addresses_equal(&convo_data->addr_a, &pinfo->dst) |
268 | 0 | && convo_data-> port_b == pinfo->srcport |
269 | 0 | && convo_data-> port_a == pinfo->destport) { |
270 | | /* "backward" direction */ |
271 | 0 | forward_stream = false; |
272 | 0 | prev_byte_state = convo_data->byte_state_b; |
273 | 0 | } |
274 | 15 | } |
275 | 27 | if (prev_byte_state) { |
276 | 15 | state = prev_byte_state->state; |
277 | 15 | full_byte = prev_byte_state->full_byte; |
278 | 15 | bit_offset = prev_byte_state->bit_offset; |
279 | 15 | ones = prev_byte_state->ones; |
280 | | |
281 | 15 | memcpy(data, prev_byte_state->data, prev_byte_state->data_len); |
282 | 15 | data_len = prev_byte_state->data_len; |
283 | 15 | } |
284 | 27 | } |
285 | | |
286 | | /* Consume tvb bytes */ |
287 | 27 | available = tvb_reported_length_remaining(tvb, offset); |
288 | 225 | while (offset < available) { |
289 | 198 | byte = tvb_get_uint8(tvb,offset); |
290 | 198 | offset++; |
291 | 1.74k | for (i=0; i < 8; i++) { /* cycle through bits */ |
292 | 1.54k | bit = byte & (0x80 >> i) ? true : false; |
293 | | |
294 | | /* consume a bit */ |
295 | 1.54k | if (bit) { |
296 | 794 | ones++; |
297 | 794 | full_byte |= (1 << bit_offset++); |
298 | 794 | } else { |
299 | 751 | if (ones == 5 && state == DATA) { |
300 | | /* we don't increase bit_offset, it is an inserted zero */ |
301 | 748 | } else if (ones == 6 && state == DATA) { /* probably starting flag sequence */ |
302 | 3 | buff = (uint8_t *)wmem_memdup(pinfo->pool, data, data_len); |
303 | | /* Allocate new tvb for the LAPD frame */ |
304 | 3 | new_tvb = tvb_new_child_real_data(tvb, buff, data_len, data_len); |
305 | 3 | add_new_data_source(pinfo, new_tvb, "Decoded LAPD bitstream"); |
306 | 3 | data_len = 0; |
307 | 3 | state = FLAGS; |
308 | 3 | bit_offset++; |
309 | | |
310 | 3 | if (full_byte != 0x7E) { |
311 | 3 | data_len = 0; |
312 | 3 | state = OUT_OF_SYNC; |
313 | 3 | lapd_log_abort(tvb, pinfo, tree, offset, "Abort! 6 ones that don't match 0x7e!"); |
314 | | |
315 | 3 | } |
316 | 3 | dissect_lapd_full(new_tvb, pinfo, tree, LAPD_HAS_CRC); |
317 | 745 | } else if (ones >= 7) { /* frame reset or 11111111 flag byte */ |
318 | 25 | data_len = 0; |
319 | 25 | state = OUT_OF_SYNC; |
320 | 25 | bit_offset++; |
321 | | |
322 | 25 | lapd_log_abort(tvb, pinfo, tree, offset, "Abort! 7 ones!"); |
323 | 720 | } else { |
324 | 720 | bit_offset++; |
325 | 720 | } |
326 | 751 | ones = 0; |
327 | 751 | } |
328 | | |
329 | 1.54k | if (bit_offset == 8) { /* we have a new complete byte */ |
330 | 975 | switch (state) { |
331 | 915 | case OUT_OF_SYNC: |
332 | 915 | if (full_byte == 0x7E) { /* we have a flag byte */ |
333 | 11 | state = FLAGS; |
334 | 11 | full_byte = 0x00; |
335 | 11 | bit_offset = 0; |
336 | 904 | } else { /* no sync yet, wait for a new byte */ |
337 | 904 | full_byte = (full_byte >> 1) & 0x7F; |
338 | 904 | bit_offset--; |
339 | 904 | } |
340 | 915 | break; |
341 | | |
342 | 23 | case FLAGS: |
343 | 23 | if (full_byte == 0x7E) { /* we have a flag byte */ |
344 | 12 | full_byte = 0x00; |
345 | 12 | bit_offset = 0; |
346 | 12 | } else { /* we got the first data byte */ |
347 | 11 | state = DATA; |
348 | 11 | new_byte(full_byte, data, &data_len); |
349 | 11 | full_byte = 0x00; |
350 | 11 | bit_offset = 0; |
351 | 11 | } |
352 | 23 | break; |
353 | | |
354 | 37 | case DATA: |
355 | | /* we got a new data byte */ |
356 | 37 | new_byte(full_byte, data, &data_len); |
357 | 37 | full_byte = 0x00; |
358 | 37 | bit_offset = 0; |
359 | 37 | break; |
360 | 975 | } |
361 | 975 | } |
362 | 1.54k | } |
363 | 198 | } |
364 | | |
365 | 27 | { |
366 | 27 | if (NULL == p_get_proto_data(wmem_file_scope(), pinfo, proto_lapd, 0)) { |
367 | | /* Per packet information */ |
368 | 20 | lapd_ppi = wmem_new(wmem_file_scope(), lapd_ppi_t); |
369 | 20 | lapd_ppi->has_crc = true; |
370 | 20 | if (prev_byte_state) |
371 | 13 | fill_lapd_byte_state(&lapd_ppi->start_byte_state, prev_byte_state->state, |
372 | 13 | prev_byte_state->full_byte, prev_byte_state->bit_offset, |
373 | 13 | prev_byte_state->ones, prev_byte_state->data, prev_byte_state->data_len); |
374 | 7 | else |
375 | 7 | fill_lapd_byte_state(&lapd_ppi->start_byte_state, OUT_OF_SYNC, 0x00, 0, 0, data, 0); |
376 | | |
377 | 20 | p_add_proto_data(wmem_file_scope(), pinfo, proto_lapd, 0, lapd_ppi); |
378 | | |
379 | | |
380 | | /* Conversation info*/ |
381 | | |
382 | 20 | if (conversation) { |
383 | 20 | if (convo_data) { /* already have lapd convo data */ |
384 | 13 | if (forward_stream) { |
385 | 13 | if (!convo_data->byte_state_a) |
386 | 0 | convo_data->byte_state_a = wmem_new(wmem_file_scope(), lapd_byte_state_t); |
387 | 13 | fill_lapd_byte_state(convo_data->byte_state_a, state, full_byte, bit_offset, ones, data, data_len); |
388 | 13 | } else { |
389 | 0 | if (!convo_data->byte_state_b) |
390 | 0 | convo_data->byte_state_b = wmem_new(wmem_file_scope(), lapd_byte_state_t); |
391 | 0 | fill_lapd_byte_state(convo_data->byte_state_b, state, full_byte, bit_offset, ones, data, data_len); |
392 | 0 | } |
393 | 13 | } else { /* lapd convo data has to be created */ |
394 | 7 | lapd_byte_state = wmem_new(wmem_file_scope(), lapd_byte_state_t); |
395 | 7 | fill_lapd_byte_state(lapd_byte_state, state, full_byte, bit_offset, ones, data, data_len); |
396 | 7 | convo_data = wmem_new(wmem_file_scope(), lapd_convo_data_t); |
397 | 7 | copy_address_wmem(wmem_file_scope(), &convo_data->addr_a, &pinfo->src); |
398 | 7 | copy_address_wmem(wmem_file_scope(), &convo_data->addr_b, &pinfo->dst); |
399 | 7 | convo_data->port_a = pinfo->srcport; |
400 | 7 | convo_data->port_b = pinfo->destport; |
401 | 7 | convo_data->byte_state_a = lapd_byte_state; |
402 | 7 | convo_data->byte_state_b = NULL; |
403 | 7 | conversation_add_proto_data(conversation, proto_lapd, convo_data); |
404 | 7 | } |
405 | 20 | } |
406 | 20 | } |
407 | 27 | } |
408 | 27 | return tvb_captured_length(tvb); |
409 | 27 | } |
410 | | |
411 | | static int |
412 | | dissect_linux_lapd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
413 | 0 | { |
414 | 0 | uint32_t flags = LAPD_HAS_LINUX_SLL | LAPD_HAS_DIRECTION; |
415 | | |
416 | | /* frame is captured via libpcap */ |
417 | 0 | if (pinfo->pseudo_header->lapd.pkttype == 4 /*PACKET_OUTGOING*/) { |
418 | 0 | if (pinfo->pseudo_header->lapd.we_network) { |
419 | | /* |
420 | | * We're the network side, so the user is remote, |
421 | | * and we're sending it, so this is Network->User. |
422 | | */ |
423 | 0 | flags |= LAPD_USER_IS_REMOTE; |
424 | 0 | } else { |
425 | | /* |
426 | | * We're the user side, so the network is remote, |
427 | | * and we're sending it, so this is User->Network. |
428 | | */ |
429 | 0 | flags |= LAPD_NETWORK_IS_REMOTE | LAPD_USER_TO_NETWORK; |
430 | 0 | } |
431 | 0 | } |
432 | 0 | else if (pinfo->pseudo_header->lapd.pkttype == 3 /*PACKET_OTHERHOST*/) { |
433 | | /* |
434 | | * We must be a TE, sniffing what other TE transmit, so |
435 | | * both sides are remote. |
436 | | * |
437 | | * XXX - do we know whether it's User->Network or |
438 | | * Network->User? |
439 | | */ |
440 | 0 | flags |= LAPD_USER_IS_REMOTE | LAPD_NETWORK_IS_REMOTE | LAPD_USER_TO_NETWORK; |
441 | 0 | } |
442 | 0 | else { |
443 | | /* The frame is incoming */ |
444 | 0 | if (pinfo->pseudo_header->lapd.we_network) { |
445 | | /* |
446 | | * We're the network side, so the user is remote, |
447 | | * and we received it, so this is User->Network. |
448 | | */ |
449 | 0 | flags |= LAPD_USER_IS_REMOTE | LAPD_USER_TO_NETWORK; |
450 | 0 | } else { |
451 | | /* |
452 | | * We're the user side, so the network is remote, |
453 | | * and we received it, so this is Network->User. |
454 | | */ |
455 | 0 | flags |= LAPD_NETWORK_IS_REMOTE; |
456 | 0 | } |
457 | 0 | } |
458 | 0 | dissect_lapd_full(tvb, pinfo, tree, flags); |
459 | 0 | return tvb_captured_length(tvb); |
460 | 0 | } |
461 | | |
462 | | /* |
463 | | * Called from dissectors, such as the ISDN dissector, that supply a |
464 | | * struct isdn_pndr giving the packet direction. |
465 | | */ |
466 | | static int |
467 | | dissect_lapd_phdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
468 | 33 | { |
469 | 33 | struct isdn_phdr *isdn = (struct isdn_phdr *)data; |
470 | 33 | uint32_t flags = LAPD_HAS_DIRECTION; |
471 | | |
472 | 33 | if (isdn->uton) |
473 | 4 | flags |= LAPD_USER_TO_NETWORK; |
474 | 33 | dissect_lapd_full(tvb, pinfo, tree, flags); |
475 | 33 | return tvb_captured_length(tvb); |
476 | 33 | } |
477 | | |
478 | | /* |
479 | | * Called for link-layer encapsulation. |
480 | | */ |
481 | | static int |
482 | | dissect_lapd_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
483 | 0 | { |
484 | 0 | uint32_t flags; |
485 | 0 | uint32_t lapd_flags = 0; |
486 | | |
487 | | /* |
488 | | * If we have direction flags, we have a direction; |
489 | | * "outbound" packets are presumed to be User->Network and |
490 | | * "inbound" packets are presumed to be Network->User. |
491 | | * Other packets, we have no idea. |
492 | | */ |
493 | 0 | if (WTAP_OPTTYPE_SUCCESS == wtap_block_get_uint32_option_value(pinfo->rec->block, OPT_PKT_FLAGS, &flags)) { |
494 | 0 | switch (PACK_FLAGS_DIRECTION(flags)) { |
495 | | |
496 | 0 | case PACK_FLAGS_DIRECTION_OUTBOUND: |
497 | 0 | lapd_flags |= LAPD_HAS_DIRECTION | LAPD_USER_TO_NETWORK; |
498 | 0 | break; |
499 | | |
500 | 0 | case PACK_FLAGS_DIRECTION_INBOUND: |
501 | 0 | lapd_flags |= LAPD_HAS_DIRECTION; |
502 | 0 | break; |
503 | | |
504 | 0 | default: |
505 | 0 | break; |
506 | 0 | } |
507 | 0 | } |
508 | 0 | dissect_lapd_full(tvb, pinfo, tree, lapd_flags); |
509 | 0 | return tvb_captured_length(tvb); |
510 | 0 | } |
511 | | |
512 | | static int |
513 | | dissect_lapd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
514 | 0 | { |
515 | | /* XXX - direction is unknown */ |
516 | 0 | dissect_lapd_full(tvb, pinfo, tree, 0); |
517 | 0 | return tvb_captured_length(tvb); |
518 | 0 | } |
519 | | |
520 | | static void |
521 | | dissect_lapd_full(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t flags) |
522 | 35 | { |
523 | 35 | proto_tree *lapd_tree, *addr_tree; |
524 | 35 | proto_item *lapd_ti, *addr_ti; |
525 | 35 | uint16_t control; |
526 | 35 | int lapd_header_len, checksum_offset; |
527 | 35 | uint16_t addr, cr, sapi, tei; |
528 | 35 | bool is_response = 0; |
529 | 35 | tvbuff_t *next_tvb; |
530 | 35 | const char *srcname = "?"; |
531 | 35 | const char *dstname = "?"; |
532 | | |
533 | 35 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "LAPD"); |
534 | 35 | col_clear(pinfo->cinfo, COL_INFO); |
535 | | |
536 | 35 | addr = tvb_get_ntohs(tvb, 0); |
537 | 35 | cr = addr & LAPD_CR; |
538 | 35 | tei = (addr & LAPD_TEI) >> LAPD_TEI_SHIFT; |
539 | 35 | sapi = (addr & LAPD_SAPI) >> LAPD_SAPI_SHIFT; |
540 | 35 | lapd_header_len = 2; /* addr */ |
541 | | |
542 | | /* Append TEI to info field */ |
543 | 35 | col_append_fstr(pinfo->cinfo, COL_INFO, "TEI:%02u ", tei); |
544 | 35 | col_set_fence(pinfo->cinfo, COL_INFO); |
545 | | |
546 | 35 | if (flags & LAPD_HAS_DIRECTION) { |
547 | 33 | if (flags & LAPD_USER_TO_NETWORK) { |
548 | 4 | is_response = cr ? true : false; |
549 | 4 | if (flags & LAPD_HAS_LINUX_SLL) { |
550 | 0 | srcname = (flags & LAPD_USER_IS_REMOTE) ? |
551 | 0 | "Remote User" : "Local User"; |
552 | 0 | dstname = (flags & LAPD_NETWORK_IS_REMOTE) ? |
553 | 0 | "Remote Network" : "Local Network"; |
554 | 4 | } else { |
555 | 4 | srcname = "User"; |
556 | 4 | dstname = "Network"; |
557 | 4 | } |
558 | 29 | } else { |
559 | 29 | is_response = cr ? false : true; |
560 | 29 | if (flags & LAPD_HAS_LINUX_SLL) { |
561 | 0 | srcname = (flags & LAPD_NETWORK_IS_REMOTE) ? |
562 | 0 | "Remote Network" : "Local Network"; |
563 | 0 | dstname = (flags & LAPD_USER_IS_REMOTE) ? |
564 | 0 | "Remote User" : "Local User"; |
565 | 29 | } else { |
566 | 29 | srcname = "Network"; |
567 | 29 | dstname = "User"; |
568 | 29 | } |
569 | 29 | } |
570 | 33 | } |
571 | 35 | set_address(&pinfo->dl_dst, AT_STRINGZ, (int)strlen(dstname) + 1, dstname); |
572 | 35 | set_address(&pinfo->dl_src, AT_STRINGZ, (int)strlen(srcname) + 1, srcname); |
573 | 35 | copy_address_shallow(&pinfo->dst, &pinfo->dl_dst); |
574 | 35 | copy_address_shallow(&pinfo->src, &pinfo->dl_src); |
575 | | |
576 | 35 | if (tree) { |
577 | 35 | proto_item *direction_ti; |
578 | | |
579 | 35 | lapd_ti = proto_tree_add_item(tree, proto_lapd, tvb, 0, -1, |
580 | 35 | ENC_NA); |
581 | 35 | lapd_tree = proto_item_add_subtree(lapd_ti, ett_lapd); |
582 | | |
583 | | /* |
584 | | * Don't show the direction if we don't know it. |
585 | | */ |
586 | 35 | if (flags & LAPD_HAS_DIRECTION) { |
587 | 33 | direction_ti = proto_tree_add_uint(lapd_tree, hf_lapd_direction, |
588 | 33 | tvb, 0, 0, |
589 | 33 | (flags & LAPD_USER_TO_NETWORK) ? LAPD_DIR_USER_TO_NETWORK : LAPD_DIR_NETWORK_TO_USER); |
590 | 33 | proto_item_set_generated(direction_ti); |
591 | 33 | } |
592 | | |
593 | 35 | addr_ti = proto_tree_add_uint(lapd_tree, hf_lapd_address, tvb, |
594 | 35 | 0, 2, addr); |
595 | 35 | addr_tree = proto_item_add_subtree(addr_ti, ett_lapd_address); |
596 | | |
597 | 35 | if(global_lapd_gsm_sapis){ |
598 | 0 | proto_tree_add_uint(addr_tree, hf_lapd_gsm_sapi,tvb, 0, 1, addr); |
599 | 35 | }else{ |
600 | 35 | proto_tree_add_uint(addr_tree, hf_lapd_sapi,tvb, 0, 1, addr); |
601 | 35 | } |
602 | 35 | proto_tree_add_uint(addr_tree, hf_lapd_cr, tvb, 0, 1, addr); |
603 | 35 | proto_tree_add_uint(addr_tree, hf_lapd_ea1, tvb, 0, 1, addr); |
604 | 35 | proto_tree_add_uint(addr_tree, hf_lapd_tei, tvb, 1, 1, addr); |
605 | 35 | proto_tree_add_uint(addr_tree, hf_lapd_ea2, tvb, 1, 1, addr); |
606 | 35 | } |
607 | 0 | else { |
608 | 0 | lapd_ti = NULL; |
609 | 0 | lapd_tree = NULL; |
610 | 0 | } |
611 | | |
612 | 35 | control = dissect_xdlc_control(tvb, 2, pinfo, lapd_tree, hf_lapd_control, |
613 | 35 | ett_lapd_control, &lapd_cf_items, &lapd_cf_items_ext, NULL, NULL, |
614 | 35 | is_response, true, false); |
615 | 35 | lapd_header_len += XDLC_CONTROL_LEN(control, true); |
616 | | |
617 | 35 | if (tree) |
618 | 35 | proto_item_set_len(lapd_ti, lapd_header_len); |
619 | | |
620 | 35 | if (flags & LAPD_HAS_CRC) { |
621 | | |
622 | | /* check checksum */ |
623 | 2 | checksum_offset = tvb_reported_length(tvb) - 2; |
624 | | |
625 | 2 | proto_tree_add_checksum(lapd_tree, tvb, checksum_offset, hf_lapd_checksum, hf_lapd_checksum_status, &ei_lapd_checksum_bad, pinfo, |
626 | 2 | crc16_ccitt_tvb(tvb, tvb_reported_length(tvb) - 2), ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
627 | | |
628 | 2 | next_tvb = tvb_new_subset_length(tvb, lapd_header_len, tvb_reported_length_remaining(tvb,lapd_header_len) - 2); |
629 | | |
630 | 2 | } else |
631 | 33 | next_tvb = tvb_new_subset_remaining(tvb, lapd_header_len); |
632 | | |
633 | | /* Dissection done, append " | " to COL_INFO */ |
634 | 35 | col_append_str(pinfo->cinfo, COL_INFO, " | "); |
635 | 35 | col_set_fence(pinfo->cinfo, COL_INFO); |
636 | | |
637 | 35 | if (XDLC_IS_INFORMATION(control)) { |
638 | | /* call next protocol */ |
639 | 33 | if(global_lapd_gsm_sapis){ |
640 | 0 | if (!dissector_try_uint(lapd_gsm_sapi_dissector_table, sapi, |
641 | 0 | next_tvb, pinfo, tree)) |
642 | 0 | call_data_dissector(next_tvb, pinfo, tree); |
643 | 33 | }else{ |
644 | 33 | if (!dissector_try_uint(lapd_sapi_dissector_table, sapi, |
645 | 33 | next_tvb, pinfo, tree)) |
646 | 3 | call_data_dissector(next_tvb, pinfo, tree); |
647 | 33 | } |
648 | 33 | } else |
649 | 2 | call_data_dissector(next_tvb, pinfo, tree); |
650 | 35 | } |
651 | | |
652 | | void |
653 | | proto_register_lapd(void) |
654 | 14 | { |
655 | 14 | static hf_register_info hf[] = { |
656 | | |
657 | 14 | { &hf_lapd_direction, |
658 | 14 | { "Direction", "lapd.direction", FT_UINT32, BASE_DEC, VALS(lapd_direction_vals), 0x0, |
659 | 14 | NULL, HFILL }}, |
660 | | |
661 | 14 | { &hf_lapd_address, |
662 | 14 | { "Address Field", "lapd.address", FT_UINT16, BASE_HEX, NULL, 0x0, |
663 | 14 | NULL, HFILL }}, |
664 | | |
665 | 14 | { &hf_lapd_sapi, |
666 | 14 | { "SAPI", "lapd.sapi", FT_UINT16, BASE_DEC, VALS(lapd_sapi_vals), LAPD_SAPI, |
667 | 14 | "Service Access Point Identifier", HFILL }}, |
668 | | |
669 | 14 | { &hf_lapd_gsm_sapi, |
670 | 14 | { "SAPI", "lapd.sapi", FT_UINT16, BASE_DEC, VALS(lapd_gsm_sapi_vals), LAPD_SAPI, |
671 | 14 | "Service Access Point Identifier", HFILL }}, |
672 | | |
673 | 14 | { &hf_lapd_cr, |
674 | 14 | { "C/R", "lapd.cr", FT_UINT16, BASE_DEC, NULL, LAPD_CR, |
675 | 14 | "Command/Response bit", HFILL }}, |
676 | | |
677 | 14 | { &hf_lapd_ea1, |
678 | 14 | { "EA1", "lapd.ea1", FT_UINT16, BASE_DEC, NULL, LAPD_EA1, |
679 | 14 | "First Address Extension bit", HFILL }}, |
680 | | |
681 | 14 | { &hf_lapd_tei, |
682 | 14 | { "TEI", "lapd.tei", FT_UINT16, BASE_DEC, NULL, LAPD_TEI, |
683 | 14 | "Terminal Endpoint Identifier", HFILL }}, |
684 | | |
685 | 14 | { &hf_lapd_ea2, |
686 | 14 | { "EA2", "lapd.ea2", FT_UINT16, BASE_DEC, NULL, LAPD_EA2, |
687 | 14 | "Second Address Extension bit", HFILL }}, |
688 | | |
689 | 14 | { &hf_lapd_control, |
690 | 14 | { "Control Field", "lapd.control", FT_UINT16, BASE_HEX, NULL, 0x0, |
691 | 14 | NULL, HFILL }}, |
692 | | |
693 | 14 | { &hf_lapd_n_r, |
694 | 14 | { "N(R)", "lapd.control.n_r", FT_UINT16, BASE_DEC, |
695 | 14 | NULL, XDLC_N_R_EXT_MASK, NULL, HFILL }}, |
696 | | |
697 | 14 | { &hf_lapd_n_s, |
698 | 14 | { "N(S)", "lapd.control.n_s", FT_UINT16, BASE_DEC, |
699 | 14 | NULL, XDLC_N_S_EXT_MASK, NULL, HFILL }}, |
700 | | |
701 | 14 | { &hf_lapd_p, |
702 | 14 | { "Poll", "lapd.control.p", FT_BOOLEAN, 8, |
703 | 14 | TFS(&tfs_set_notset), XDLC_P_F, NULL, HFILL }}, |
704 | | |
705 | 14 | { &hf_lapd_p_ext, |
706 | 14 | { "Poll", "lapd.control.p", FT_BOOLEAN, 16, |
707 | 14 | TFS(&tfs_set_notset), XDLC_P_F_EXT, NULL, HFILL }}, |
708 | | |
709 | 14 | { &hf_lapd_f, |
710 | 14 | { "Final", "lapd.control.f", FT_BOOLEAN, 8, |
711 | 14 | TFS(&tfs_set_notset), XDLC_P_F, NULL, HFILL }}, |
712 | | |
713 | 14 | { &hf_lapd_f_ext, |
714 | 14 | { "Final", "lapd.control.f", FT_BOOLEAN, 16, |
715 | 14 | TFS(&tfs_set_notset), XDLC_P_F_EXT, NULL, HFILL }}, |
716 | | |
717 | 14 | { &hf_lapd_s_ftype, |
718 | 14 | { "Supervisory frame type", "lapd.control.s_ftype", FT_UINT16, BASE_HEX, |
719 | 14 | VALS(stype_vals), XDLC_S_FTYPE_MASK, NULL, HFILL }}, |
720 | | |
721 | 14 | { &hf_lapd_u_modifier_cmd, |
722 | 14 | { "Command", "lapd.control.u_modifier_cmd", FT_UINT8, BASE_HEX, |
723 | 14 | VALS(modifier_vals_cmd), XDLC_U_MODIFIER_MASK, NULL, HFILL }}, |
724 | | |
725 | 14 | { &hf_lapd_u_modifier_resp, |
726 | 14 | { "Response", "lapd.control.u_modifier_resp", FT_UINT8, BASE_HEX, |
727 | 14 | VALS(modifier_vals_resp), XDLC_U_MODIFIER_MASK, NULL, HFILL }}, |
728 | | |
729 | 14 | { &hf_lapd_ftype_i, |
730 | 14 | { "Frame type", "lapd.control.ftype", FT_UINT16, BASE_HEX, |
731 | 14 | VALS(ftype_vals), XDLC_I_MASK, NULL, HFILL }}, |
732 | | |
733 | 14 | { &hf_lapd_ftype_s_u, |
734 | 14 | { "Frame type", "lapd.control.ftype", FT_UINT8, BASE_HEX, |
735 | 14 | VALS(ftype_vals), XDLC_S_U_MASK, NULL, HFILL }}, |
736 | | |
737 | 14 | { &hf_lapd_ftype_s_u_ext, |
738 | 14 | { "Frame type", "lapd.control.ftype", FT_UINT16, BASE_HEX, |
739 | 14 | VALS(ftype_vals), XDLC_S_U_MASK, NULL, HFILL }}, |
740 | | |
741 | 14 | { &hf_lapd_checksum, |
742 | 14 | { "Checksum", "lapd.checksum", FT_UINT16, BASE_HEX, |
743 | 14 | NULL, 0x0, "Details at: https://www.wireshark.org/docs/wsug_html_chunked/ChAdvChecksums.html", HFILL }}, |
744 | | |
745 | 14 | { &hf_lapd_checksum_status, |
746 | 14 | { "Checksum Status", "lapd.checksum.status", FT_UINT8, BASE_NONE, |
747 | 14 | VALS(proto_checksum_vals), 0x0, NULL, HFILL }}, |
748 | 14 | }; |
749 | 14 | static int *ett[] = { |
750 | 14 | &ett_lapd, |
751 | 14 | &ett_lapd_address, |
752 | 14 | &ett_lapd_control, |
753 | 14 | &ett_lapd_checksum |
754 | 14 | }; |
755 | | |
756 | 14 | static ei_register_info ei[] = { |
757 | 14 | { &ei_lapd_abort, { "lapd.abort.expert", PI_PROTOCOL, PI_ERROR, "Formatted message", EXPFILL }}, |
758 | 14 | { &ei_lapd_checksum_bad, { "lapd.checksum_bad.expert", PI_CHECKSUM, PI_WARN, "Bad FCS", EXPFILL }}, |
759 | 14 | }; |
760 | | |
761 | 14 | module_t *lapd_module; |
762 | 14 | expert_module_t* expert_lapd; |
763 | | |
764 | 14 | proto_lapd = proto_register_protocol("Link Access Procedure, Channel D (LAPD)", |
765 | 14 | "LAPD", "lapd"); |
766 | 14 | proto_register_field_array (proto_lapd, hf, array_length(hf)); |
767 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
768 | 14 | expert_lapd = expert_register_protocol(proto_lapd); |
769 | 14 | expert_register_field_array(expert_lapd, ei, array_length(ei)); |
770 | | |
771 | 14 | lapd_handle = register_dissector("lapd", dissect_lapd, proto_lapd); |
772 | 14 | lapd_phdr_handle = register_dissector("lapd-phdr", dissect_lapd_phdr, proto_lapd); |
773 | 14 | linux_lapd_handle = register_dissector("linux-lapd", dissect_linux_lapd, proto_lapd); |
774 | 14 | lapd_bitstream_handle = register_dissector("lapd-bitstream", dissect_lapd_bitstream, proto_lapd); |
775 | | |
776 | 14 | lapd_sapi_dissector_table = register_dissector_table("lapd.sapi", |
777 | 14 | "LAPD SAPI", proto_lapd, FT_UINT16, BASE_DEC); |
778 | | |
779 | 14 | lapd_gsm_sapi_dissector_table = register_dissector_table("lapd.gsm.sapi", |
780 | 14 | "LAPD GSM SAPI", proto_lapd, FT_UINT16, BASE_DEC); |
781 | | |
782 | 14 | lapd_module = prefs_register_protocol(proto_lapd, NULL); |
783 | | |
784 | 14 | prefs_register_bool_preference(lapd_module, "use_gsm_sapi_values", |
785 | 14 | "Use GSM SAPI values", |
786 | 14 | "Use SAPI values as specified in TS 48 056", |
787 | 14 | &global_lapd_gsm_sapis); |
788 | 14 | prefs_register_obsolete_preference(lapd_module, "rtp_payload_type"); |
789 | 14 | } |
790 | | |
791 | | void |
792 | | proto_reg_handoff_lapd(void) |
793 | 14 | { |
794 | 14 | dissector_handle_t lapd_frame_handle; |
795 | | |
796 | 14 | dissector_add_uint("wtap_encap", WTAP_ENCAP_LINUX_LAPD, linux_lapd_handle); |
797 | | |
798 | 14 | lapd_frame_handle = create_dissector_handle(dissect_lapd_frame, proto_lapd); |
799 | 14 | dissector_add_uint("wtap_encap", WTAP_ENCAP_LAPD, lapd_frame_handle); |
800 | | |
801 | 14 | dissector_add_for_decode_as("l2tp.pw_type", lapd_handle); |
802 | 14 | dissector_add_for_decode_as_with_preference("sctp.ppi", lapd_handle); |
803 | 14 | dissector_add_for_decode_as("sctp.port", lapd_handle); |
804 | 14 | dissector_add_uint_range_with_preference("udp.port", "", lapd_handle); |
805 | 14 | dissector_add_uint_range_with_preference("rtp.pt", "", lapd_bitstream_handle); |
806 | | |
807 | 14 | } |
808 | | |
809 | | /* |
810 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
811 | | * |
812 | | * Local variables: |
813 | | * c-basic-offset: 8 |
814 | | * tab-width: 8 |
815 | | * indent-tabs-mode: t |
816 | | * End: |
817 | | * |
818 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
819 | | * :indentSize=8:tabSize=8:noTabs=false: |
820 | | */ |