2 * Routines for LAPD frame disassembly
3 * Gilbert Ramirez <gram@alumni.rice.edu>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 * LAPD bitstream over RTP handling
13 * Copyright 2008, Ericsson AB
14 * Written by Balint Reczey <balint.reczey@ericsson.com>
16 * ISDN/LAPD references:
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
28 #include <epan/packet.h>
29 #include <epan/conversation.h>
30 #include <epan/xdlc.h>
31 #include <epan/crc16-tvb.h>
32 #include <epan/prefs.h>
33 #include <wiretap/wtap.h>
34 #include <epan/lapd_sapi.h>
35 #include <epan/expert.h>
36 #include <epan/proto_data.h>
38 #include <wsutil/array.h>
40 void proto_register_lapd(void);
41 void proto_reg_handoff_lapd(void);
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
;
56 static int hf_lapd_p_ext
;
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
;
69 static int ett_lapd_address
;
70 static int ett_lapd_control
;
71 static int ett_lapd_checksum
;
73 static expert_field ei_lapd_abort
;
74 static expert_field ei_lapd_checksum_bad
;
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
;
81 static dissector_table_t lapd_sapi_dissector_table
;
82 static dissector_table_t lapd_gsm_sapi_dissector_table
;
84 /* Whether to use GSM SAPI vals or not */
85 static bool global_lapd_gsm_sapis
;
88 * Bits in the address field.
90 #define LAPD_SAPI 0xfc00 /* Service Access Point Identifier */
91 #define LAPD_SAPI_SHIFT 10
92 #define LAPD_CR 0x0200 /* Command/Response bit */
93 #define LAPD_EA1 0x0100 /* First Address Extension bit */
94 #define LAPD_TEI 0x00fe /* Terminal Endpoint Identifier */
95 #define LAPD_TEI_SHIFT 1
96 #define LAPD_EA2 0x0001 /* Second Address Extension bit */
98 #define LAPD_DIR_USER_TO_NETWORK 0
99 #define LAPD_DIR_NETWORK_TO_USER 1
101 static const value_string lapd_direction_vals
[] = {
102 { LAPD_DIR_USER_TO_NETWORK
, "User->Network"},
103 { LAPD_DIR_NETWORK_TO_USER
, "Network->User"},
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" },
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" },
124 /* Used only for U frames */
125 static const xdlc_cf_items lapd_cf_items
= {
131 &hf_lapd_u_modifier_cmd
,
132 &hf_lapd_u_modifier_resp
,
137 /* Used only for I and S frames */
138 static const xdlc_cf_items lapd_cf_items_ext
= {
147 &hf_lapd_ftype_s_u_ext
150 #define MAX_LAPD_PACKET_LEN 1024
152 /* LAPD frame detection state */
153 enum lapd_bitstream_states
{OUT_OF_SYNC
, FLAGS
, DATA
};
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 char data
[MAX_LAPD_PACKET_LEN
];
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 */
169 /* Fill values in lapd_byte_state struct */
171 fill_lapd_byte_state(lapd_byte_state_t
*ptr
, enum lapd_bitstream_states state
, char full_byte
, char bit_offset
, int ones
, char *data
, int data_len
)
174 ptr
->full_byte
= full_byte
;
175 ptr
->bit_offset
= bit_offset
;
178 ptr
->data_len
= MIN((int)sizeof(ptr
->data
), data_len
);
179 memcpy(ptr
->data
, data
, ptr
->data_len
);
182 typedef struct lapd_convo_data
{
187 lapd_byte_state_t
*byte_state_a
;
188 lapd_byte_state_t
*byte_state_b
;
193 dissect_lapd_full(tvbuff_t
*, packet_info
*, proto_tree
*, uint32_t);
195 /* got new LAPD frame byte */
196 static void new_byte(char full_byte
, char data
[], int *data_len
) {
197 if (*data_len
< MAX_LAPD_PACKET_LEN
) {
198 data
[*data_len
] = full_byte
;
201 /* XXX : we are not prepared for that big messages, drop the last byte */
206 lapd_log_abort(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, unsigned offset
, const char *msg
)
210 ti
= proto_tree_add_item(tree
, proto_lapd
, tvb
, offset
, 1, ENC_NA
);
211 expert_add_info_format(pinfo
, ti
, &ei_lapd_abort
, "%s", msg
);
215 * Flags to pass to dissect_lapd_full.
217 #define LAPD_HAS_CRC 0x00000001
218 #define LAPD_HAS_DIRECTION 0x00000002
219 #define LAPD_HAS_LINUX_SLL 0x00000004
220 #define LAPD_USER_TO_NETWORK 0x00000008
221 #define LAPD_NETWORK_IS_REMOTE 0x00000010
222 #define LAPD_USER_IS_REMOTE 0x00000020
225 dissect_lapd_bitstream(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* dissector_data _U_
)
227 uint8_t byte
, full_byte
= 0x00, bit_offset
= 0;
229 uint8_t i
, ones
= 0, data
[MAX_LAPD_PACKET_LEN
];
231 int offset
= 0, available
;
235 enum lapd_bitstream_states state
= OUT_OF_SYNC
;
236 lapd_ppi_t
*lapd_ppi
;
237 conversation_t
*conversation
= NULL
;
238 lapd_convo_data_t
*convo_data
= NULL
;
239 lapd_byte_state_t
*lapd_byte_state
, *prev_byte_state
= NULL
;
240 bool forward_stream
= true;
242 /* get remaining data from previous packets */
243 conversation
= find_or_create_conversation(pinfo
);
244 lapd_ppi
= (lapd_ppi_t
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_lapd
, 0);
246 prev_byte_state
= &lapd_ppi
->start_byte_state
;
247 if (prev_byte_state
) {
248 state
= prev_byte_state
->state
;
249 full_byte
= prev_byte_state
->full_byte
;
250 bit_offset
= prev_byte_state
->bit_offset
;
251 ones
= prev_byte_state
->ones
;
252 memcpy(data
, prev_byte_state
->data
, prev_byte_state
->data_len
);
253 data_len
= prev_byte_state
->data_len
;
256 } else if (conversation
) {
257 convo_data
= (lapd_convo_data_t
*)conversation_get_proto_data(conversation
, proto_lapd
);
258 if (NULL
!= convo_data
) {
259 if (addresses_equal(&convo_data
->addr_a
, &pinfo
->src
)
260 && addresses_equal(&convo_data
->addr_b
, &pinfo
->dst
)
261 && convo_data
-> port_a
== pinfo
->srcport
262 && convo_data
-> port_b
== pinfo
->destport
) {
263 /* "forward" direction */
264 forward_stream
= true;
265 prev_byte_state
= convo_data
->byte_state_a
;
266 } else if (addresses_equal(&convo_data
-> addr_b
, &pinfo
->src
)
267 && addresses_equal(&convo_data
->addr_a
, &pinfo
->dst
)
268 && convo_data
-> port_b
== pinfo
->srcport
269 && convo_data
-> port_a
== pinfo
->destport
) {
270 /* "backward" direction */
271 forward_stream
= false;
272 prev_byte_state
= convo_data
->byte_state_b
;
275 if (prev_byte_state
) {
276 state
= prev_byte_state
->state
;
277 full_byte
= prev_byte_state
->full_byte
;
278 bit_offset
= prev_byte_state
->bit_offset
;
279 ones
= prev_byte_state
->ones
;
281 memcpy(data
, prev_byte_state
->data
, prev_byte_state
->data_len
);
282 data_len
= prev_byte_state
->data_len
;
286 /* Consume tvb bytes */
287 available
= tvb_reported_length_remaining(tvb
, offset
);
288 while (offset
< available
) {
289 byte
= tvb_get_uint8(tvb
,offset
);
291 for (i
=0; i
< 8; i
++) { /* cycle through bits */
292 bit
= byte
& (0x80 >> i
) ? true : false;
297 full_byte
|= (1 << bit_offset
++);
299 if (ones
== 5 && state
== DATA
) {
300 /* we don't increase bit_offset, it is an inserted zero */
301 } else if (ones
== 6 && state
== DATA
) { /* probably starting flag sequence */
302 buff
= (uint8_t *)wmem_memdup(pinfo
->pool
, data
, data_len
);
303 /* Allocate new tvb for the LAPD frame */
304 new_tvb
= tvb_new_child_real_data(tvb
, buff
, data_len
, data_len
);
305 add_new_data_source(pinfo
, new_tvb
, "Decoded LAPD bitstream");
310 if (full_byte
!= 0x7E) {
313 lapd_log_abort(tvb
, pinfo
, tree
, offset
, "Abort! 6 ones that don't match 0x7e!");
316 dissect_lapd_full(new_tvb
, pinfo
, tree
, LAPD_HAS_CRC
);
317 } else if (ones
>= 7) { /* frame reset or 11111111 flag byte */
322 lapd_log_abort(tvb
, pinfo
, tree
, offset
, "Abort! 7 ones!");
329 if (bit_offset
== 8) { /* we have a new complete byte */
332 if (full_byte
== 0x7E) { /* we have a flag byte */
336 } else { /* no sync yet, wait for a new byte */
337 full_byte
= (full_byte
>> 1) & 0x7F;
343 if (full_byte
== 0x7E) { /* we have a flag byte */
346 } else { /* we got the first data byte */
348 new_byte(full_byte
, data
, &data_len
);
355 /* we got a new data byte */
356 new_byte(full_byte
, data
, &data_len
);
366 if (NULL
== p_get_proto_data(wmem_file_scope(), pinfo
, proto_lapd
, 0)) {
367 /* Per packet information */
368 lapd_ppi
= wmem_new(wmem_file_scope(), lapd_ppi_t
);
369 lapd_ppi
->has_crc
= true;
371 fill_lapd_byte_state(&lapd_ppi
->start_byte_state
, prev_byte_state
->state
,
372 prev_byte_state
->full_byte
, prev_byte_state
->bit_offset
,
373 prev_byte_state
->ones
, prev_byte_state
->data
, prev_byte_state
->data_len
);
375 fill_lapd_byte_state(&lapd_ppi
->start_byte_state
, OUT_OF_SYNC
, 0x00, 0, 0, data
, 0);
377 p_add_proto_data(wmem_file_scope(), pinfo
, proto_lapd
, 0, lapd_ppi
);
380 /* Conversation info*/
383 if (convo_data
) { /* already have lapd convo data */
384 if (forward_stream
) {
385 if (!convo_data
->byte_state_a
)
386 convo_data
->byte_state_a
= wmem_new(wmem_file_scope(), lapd_byte_state_t
);
387 fill_lapd_byte_state(convo_data
->byte_state_a
, state
, full_byte
, bit_offset
, ones
, data
, data_len
);
389 if (!convo_data
->byte_state_b
)
390 convo_data
->byte_state_b
= wmem_new(wmem_file_scope(), lapd_byte_state_t
);
391 fill_lapd_byte_state(convo_data
->byte_state_b
, state
, full_byte
, bit_offset
, ones
, data
, data_len
);
393 } else { /* lapd convo data has to be created */
394 lapd_byte_state
= wmem_new(wmem_file_scope(), lapd_byte_state_t
);
395 fill_lapd_byte_state(lapd_byte_state
, state
, full_byte
, bit_offset
, ones
, data
, data_len
);
396 convo_data
= wmem_new(wmem_file_scope(), lapd_convo_data_t
);
397 copy_address_wmem(wmem_file_scope(), &convo_data
->addr_a
, &pinfo
->src
);
398 copy_address_wmem(wmem_file_scope(), &convo_data
->addr_b
, &pinfo
->dst
);
399 convo_data
->port_a
= pinfo
->srcport
;
400 convo_data
->port_b
= pinfo
->destport
;
401 convo_data
->byte_state_a
= lapd_byte_state
;
402 convo_data
->byte_state_b
= NULL
;
403 conversation_add_proto_data(conversation
, proto_lapd
, convo_data
);
408 return tvb_captured_length(tvb
);
412 dissect_linux_lapd(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
414 uint32_t flags
= LAPD_HAS_LINUX_SLL
| LAPD_HAS_DIRECTION
;
416 /* frame is captured via libpcap */
417 if (pinfo
->pseudo_header
->lapd
.pkttype
== 4 /*PACKET_OUTGOING*/) {
418 if (pinfo
->pseudo_header
->lapd
.we_network
) {
420 * We're the network side, so the user is remote,
421 * and we're sending it, so this is Network->User.
423 flags
|= LAPD_USER_IS_REMOTE
;
426 * We're the user side, so the network is remote,
427 * and we're sending it, so this is User->Network.
429 flags
|= LAPD_NETWORK_IS_REMOTE
| LAPD_USER_TO_NETWORK
;
432 else if (pinfo
->pseudo_header
->lapd
.pkttype
== 3 /*PACKET_OTHERHOST*/) {
434 * We must be a TE, sniffing what other TE transmit, so
435 * both sides are remote.
437 * XXX - do we know whether it's User->Network or
440 flags
|= LAPD_USER_IS_REMOTE
| LAPD_NETWORK_IS_REMOTE
| LAPD_USER_TO_NETWORK
;
443 /* The frame is incoming */
444 if (pinfo
->pseudo_header
->lapd
.we_network
) {
446 * We're the network side, so the user is remote,
447 * and we received it, so this is User->Network.
449 flags
|= LAPD_USER_IS_REMOTE
| LAPD_USER_TO_NETWORK
;
452 * We're the user side, so the network is remote,
453 * and we received it, so this is Network->User.
455 flags
|= LAPD_NETWORK_IS_REMOTE
;
458 dissect_lapd_full(tvb
, pinfo
, tree
, flags
);
459 return tvb_captured_length(tvb
);
463 * Called from dissectors, such as the ISDN dissector, that supply a
464 * struct isdn_pndr giving the packet direction.
467 dissect_lapd_phdr(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
469 struct isdn_phdr
*isdn
= (struct isdn_phdr
*)data
;
470 uint32_t flags
= LAPD_HAS_DIRECTION
;
473 flags
|= LAPD_USER_TO_NETWORK
;
474 dissect_lapd_full(tvb
, pinfo
, tree
, flags
);
475 return tvb_captured_length(tvb
);
479 * Called for link-layer encapsulation.
482 dissect_lapd_frame(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
485 uint32_t lapd_flags
= 0;
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.
493 if (WTAP_OPTTYPE_SUCCESS
== wtap_block_get_uint32_option_value(pinfo
->rec
->block
, OPT_PKT_FLAGS
, &flags
)) {
494 switch (PACK_FLAGS_DIRECTION(flags
)) {
496 case PACK_FLAGS_DIRECTION_OUTBOUND
:
497 lapd_flags
|= LAPD_HAS_DIRECTION
| LAPD_USER_TO_NETWORK
;
500 case PACK_FLAGS_DIRECTION_INBOUND
:
501 lapd_flags
|= LAPD_HAS_DIRECTION
;
508 dissect_lapd_full(tvb
, pinfo
, tree
, lapd_flags
);
509 return tvb_captured_length(tvb
);
513 dissect_lapd(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
515 /* XXX - direction is unknown */
516 dissect_lapd_full(tvb
, pinfo
, tree
, 0);
517 return tvb_captured_length(tvb
);
521 dissect_lapd_full(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, uint32_t flags
)
523 proto_tree
*lapd_tree
, *addr_tree
;
524 proto_item
*lapd_ti
, *addr_ti
;
526 int lapd_header_len
, checksum_offset
;
527 uint16_t addr
, cr
, sapi
, tei
;
528 bool is_response
= 0;
530 const char *srcname
= "?";
531 const char *dstname
= "?";
533 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "LAPD");
534 col_clear(pinfo
->cinfo
, COL_INFO
);
536 addr
= tvb_get_ntohs(tvb
, 0);
538 tei
= (addr
& LAPD_TEI
) >> LAPD_TEI_SHIFT
;
539 sapi
= (addr
& LAPD_SAPI
) >> LAPD_SAPI_SHIFT
;
540 lapd_header_len
= 2; /* addr */
542 /* Append TEI to info field */
543 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "TEI:%02u ", tei
);
544 col_set_fence(pinfo
->cinfo
, COL_INFO
);
546 if (flags
& LAPD_HAS_DIRECTION
) {
547 if (flags
& LAPD_USER_TO_NETWORK
) {
548 is_response
= cr
? true : false;
549 if (flags
& LAPD_HAS_LINUX_SLL
) {
550 srcname
= (flags
& LAPD_USER_IS_REMOTE
) ?
551 "Remote User" : "Local User";
552 dstname
= (flags
& LAPD_NETWORK_IS_REMOTE
) ?
553 "Remote Network" : "Local Network";
559 is_response
= cr
? false : true;
560 if (flags
& LAPD_HAS_LINUX_SLL
) {
561 srcname
= (flags
& LAPD_NETWORK_IS_REMOTE
) ?
562 "Remote Network" : "Local Network";
563 dstname
= (flags
& LAPD_USER_IS_REMOTE
) ?
564 "Remote User" : "Local User";
571 set_address(&pinfo
->dl_dst
, AT_STRINGZ
, (int)strlen(dstname
) + 1, dstname
);
572 set_address(&pinfo
->dl_src
, AT_STRINGZ
, (int)strlen(srcname
) + 1, srcname
);
573 copy_address_shallow(&pinfo
->dst
, &pinfo
->dl_dst
);
574 copy_address_shallow(&pinfo
->src
, &pinfo
->dl_src
);
577 proto_item
*direction_ti
;
579 lapd_ti
= proto_tree_add_item(tree
, proto_lapd
, tvb
, 0, -1,
581 lapd_tree
= proto_item_add_subtree(lapd_ti
, ett_lapd
);
584 * Don't show the direction if we don't know it.
586 if (flags
& LAPD_HAS_DIRECTION
) {
587 direction_ti
= proto_tree_add_uint(lapd_tree
, hf_lapd_direction
,
589 (flags
& LAPD_USER_TO_NETWORK
) ? LAPD_DIR_USER_TO_NETWORK
: LAPD_DIR_NETWORK_TO_USER
);
590 proto_item_set_generated(direction_ti
);
593 addr_ti
= proto_tree_add_uint(lapd_tree
, hf_lapd_address
, tvb
,
595 addr_tree
= proto_item_add_subtree(addr_ti
, ett_lapd_address
);
597 if(global_lapd_gsm_sapis
){
598 proto_tree_add_uint(addr_tree
, hf_lapd_gsm_sapi
,tvb
, 0, 1, addr
);
600 proto_tree_add_uint(addr_tree
, hf_lapd_sapi
,tvb
, 0, 1, addr
);
602 proto_tree_add_uint(addr_tree
, hf_lapd_cr
, tvb
, 0, 1, addr
);
603 proto_tree_add_uint(addr_tree
, hf_lapd_ea1
, tvb
, 0, 1, addr
);
604 proto_tree_add_uint(addr_tree
, hf_lapd_tei
, tvb
, 1, 1, addr
);
605 proto_tree_add_uint(addr_tree
, hf_lapd_ea2
, tvb
, 1, 1, addr
);
612 control
= dissect_xdlc_control(tvb
, 2, pinfo
, lapd_tree
, hf_lapd_control
,
613 ett_lapd_control
, &lapd_cf_items
, &lapd_cf_items_ext
, NULL
, NULL
,
614 is_response
, true, false);
615 lapd_header_len
+= XDLC_CONTROL_LEN(control
, true);
618 proto_item_set_len(lapd_ti
, lapd_header_len
);
620 if (flags
& LAPD_HAS_CRC
) {
623 checksum_offset
= tvb_reported_length(tvb
) - 2;
625 proto_tree_add_checksum(lapd_tree
, tvb
, checksum_offset
, hf_lapd_checksum
, hf_lapd_checksum_status
, &ei_lapd_checksum_bad
, pinfo
,
626 crc16_ccitt_tvb(tvb
, tvb_reported_length(tvb
) - 2), ENC_BIG_ENDIAN
, PROTO_CHECKSUM_VERIFY
);
628 next_tvb
= tvb_new_subset_length(tvb
, lapd_header_len
, tvb_reported_length_remaining(tvb
,lapd_header_len
) - 2);
631 next_tvb
= tvb_new_subset_remaining(tvb
, lapd_header_len
);
633 /* Dissection done, append " | " to COL_INFO */
634 col_append_str(pinfo
->cinfo
, COL_INFO
, " | ");
635 col_set_fence(pinfo
->cinfo
, COL_INFO
);
637 if (XDLC_IS_INFORMATION(control
)) {
638 /* call next protocol */
639 if(global_lapd_gsm_sapis
){
640 if (!dissector_try_uint(lapd_gsm_sapi_dissector_table
, sapi
,
641 next_tvb
, pinfo
, tree
))
642 call_data_dissector(next_tvb
, pinfo
, tree
);
644 if (!dissector_try_uint(lapd_sapi_dissector_table
, sapi
,
645 next_tvb
, pinfo
, tree
))
646 call_data_dissector(next_tvb
, pinfo
, tree
);
649 call_data_dissector(next_tvb
, pinfo
, tree
);
653 proto_register_lapd(void)
655 static hf_register_info hf
[] = {
657 { &hf_lapd_direction
,
658 { "Direction", "lapd.direction", FT_UINT32
, BASE_DEC
, VALS(lapd_direction_vals
), 0x0,
662 { "Address Field", "lapd.address", FT_UINT16
, BASE_HEX
, NULL
, 0x0,
666 { "SAPI", "lapd.sapi", FT_UINT16
, BASE_DEC
, VALS(lapd_sapi_vals
), LAPD_SAPI
,
667 "Service Access Point Identifier", HFILL
}},
670 { "SAPI", "lapd.sapi", FT_UINT16
, BASE_DEC
, VALS(lapd_gsm_sapi_vals
), LAPD_SAPI
,
671 "Service Access Point Identifier", HFILL
}},
674 { "C/R", "lapd.cr", FT_UINT16
, BASE_DEC
, NULL
, LAPD_CR
,
675 "Command/Response bit", HFILL
}},
678 { "EA1", "lapd.ea1", FT_UINT16
, BASE_DEC
, NULL
, LAPD_EA1
,
679 "First Address Extension bit", HFILL
}},
682 { "TEI", "lapd.tei", FT_UINT16
, BASE_DEC
, NULL
, LAPD_TEI
,
683 "Terminal Endpoint Identifier", HFILL
}},
686 { "EA2", "lapd.ea2", FT_UINT16
, BASE_DEC
, NULL
, LAPD_EA2
,
687 "Second Address Extension bit", HFILL
}},
690 { "Control Field", "lapd.control", FT_UINT16
, BASE_HEX
, NULL
, 0x0,
694 { "N(R)", "lapd.control.n_r", FT_UINT16
, BASE_DEC
,
695 NULL
, XDLC_N_R_EXT_MASK
, NULL
, HFILL
}},
698 { "N(S)", "lapd.control.n_s", FT_UINT16
, BASE_DEC
,
699 NULL
, XDLC_N_S_EXT_MASK
, NULL
, HFILL
}},
702 { "Poll", "lapd.control.p", FT_BOOLEAN
, 8,
703 TFS(&tfs_set_notset
), XDLC_P_F
, NULL
, HFILL
}},
706 { "Poll", "lapd.control.p", FT_BOOLEAN
, 16,
707 TFS(&tfs_set_notset
), XDLC_P_F_EXT
, NULL
, HFILL
}},
710 { "Final", "lapd.control.f", FT_BOOLEAN
, 8,
711 TFS(&tfs_set_notset
), XDLC_P_F
, NULL
, HFILL
}},
714 { "Final", "lapd.control.f", FT_BOOLEAN
, 16,
715 TFS(&tfs_set_notset
), XDLC_P_F_EXT
, NULL
, HFILL
}},
718 { "Supervisory frame type", "lapd.control.s_ftype", FT_UINT16
, BASE_HEX
,
719 VALS(stype_vals
), XDLC_S_FTYPE_MASK
, NULL
, HFILL
}},
721 { &hf_lapd_u_modifier_cmd
,
722 { "Command", "lapd.control.u_modifier_cmd", FT_UINT8
, BASE_HEX
,
723 VALS(modifier_vals_cmd
), XDLC_U_MODIFIER_MASK
, NULL
, HFILL
}},
725 { &hf_lapd_u_modifier_resp
,
726 { "Response", "lapd.control.u_modifier_resp", FT_UINT8
, BASE_HEX
,
727 VALS(modifier_vals_resp
), XDLC_U_MODIFIER_MASK
, NULL
, HFILL
}},
730 { "Frame type", "lapd.control.ftype", FT_UINT16
, BASE_HEX
,
731 VALS(ftype_vals
), XDLC_I_MASK
, NULL
, HFILL
}},
733 { &hf_lapd_ftype_s_u
,
734 { "Frame type", "lapd.control.ftype", FT_UINT8
, BASE_HEX
,
735 VALS(ftype_vals
), XDLC_S_U_MASK
, NULL
, HFILL
}},
737 { &hf_lapd_ftype_s_u_ext
,
738 { "Frame type", "lapd.control.ftype", FT_UINT16
, BASE_HEX
,
739 VALS(ftype_vals
), XDLC_S_U_MASK
, NULL
, HFILL
}},
742 { "Checksum", "lapd.checksum", FT_UINT16
, BASE_HEX
,
743 NULL
, 0x0, "Details at: https://www.wireshark.org/docs/wsug_html_chunked/ChAdvChecksums.html", HFILL
}},
745 { &hf_lapd_checksum_status
,
746 { "Checksum Status", "lapd.checksum.status", FT_UINT8
, BASE_NONE
,
747 VALS(proto_checksum_vals
), 0x0, NULL
, HFILL
}},
749 static int *ett
[] = {
756 static ei_register_info ei
[] = {
757 { &ei_lapd_abort
, { "lapd.abort.expert", PI_PROTOCOL
, PI_ERROR
, "Formatted message", EXPFILL
}},
758 { &ei_lapd_checksum_bad
, { "lapd.checksum_bad.expert", PI_CHECKSUM
, PI_WARN
, "Bad FCS", EXPFILL
}},
761 module_t
*lapd_module
;
762 expert_module_t
* expert_lapd
;
764 proto_lapd
= proto_register_protocol("Link Access Procedure, Channel D (LAPD)",
766 proto_register_field_array (proto_lapd
, hf
, array_length(hf
));
767 proto_register_subtree_array(ett
, array_length(ett
));
768 expert_lapd
= expert_register_protocol(proto_lapd
);
769 expert_register_field_array(expert_lapd
, ei
, array_length(ei
));
771 lapd_handle
= register_dissector("lapd", dissect_lapd
, proto_lapd
);
772 lapd_phdr_handle
= register_dissector("lapd-phdr", dissect_lapd_phdr
, proto_lapd
);
773 linux_lapd_handle
= register_dissector("linux-lapd", dissect_linux_lapd
, proto_lapd
);
774 lapd_bitstream_handle
= register_dissector("lapd-bitstream", dissect_lapd_bitstream
, proto_lapd
);
776 lapd_sapi_dissector_table
= register_dissector_table("lapd.sapi",
777 "LAPD SAPI", proto_lapd
, FT_UINT16
, BASE_DEC
);
779 lapd_gsm_sapi_dissector_table
= register_dissector_table("lapd.gsm.sapi",
780 "LAPD GSM SAPI", proto_lapd
, FT_UINT16
, BASE_DEC
);
782 lapd_module
= prefs_register_protocol(proto_lapd
, NULL
);
784 prefs_register_bool_preference(lapd_module
, "use_gsm_sapi_values",
785 "Use GSM SAPI values",
786 "Use SAPI values as specified in TS 48 056",
787 &global_lapd_gsm_sapis
);
788 prefs_register_obsolete_preference(lapd_module
, "rtp_payload_type");
792 proto_reg_handoff_lapd(void)
794 dissector_handle_t lapd_frame_handle
;
796 dissector_add_uint("wtap_encap", WTAP_ENCAP_LINUX_LAPD
, linux_lapd_handle
);
798 lapd_frame_handle
= create_dissector_handle(dissect_lapd_frame
, proto_lapd
);
799 dissector_add_uint("wtap_encap", WTAP_ENCAP_LAPD
, lapd_frame_handle
);
801 dissector_add_for_decode_as("l2tp.pw_type", lapd_handle
);
802 dissector_add_for_decode_as_with_preference("sctp.ppi", lapd_handle
);
803 dissector_add_for_decode_as("sctp.port", lapd_handle
);
804 dissector_add_uint_range_with_preference("udp.port", "", lapd_handle
);
805 dissector_add_uint_range_with_preference("rtp.pt", "", lapd_bitstream_handle
);
810 * Editor modelines - https://www.wireshark.org/tools/modelines.html
815 * indent-tabs-mode: t
818 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
819 * :indentSize=8:tabSize=8:noTabs=false: