/src/wireshark/epan/dissectors/packet-lapsat.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* packet-lapsat.c |
2 | | * |
3 | | * Routines for GMR-1 LAPSat dissection in wireshark. |
4 | | * |
5 | | * Link Access Procedures (LAP) for the Satellite Channel (LAPSat). |
6 | | * LAPSat is the protocol for signalling transfer between an Access |
7 | | * Terminal (MES) and a Gateway Station (GS) in the GeoMobile (GMR-1) network. |
8 | | * |
9 | | * Copyright (c) 2011 Sylvain Munaut <tnt@246tNt.com> |
10 | | * Inspired on LAPDm code by Duncan Salerno <duncan.salerno@googlemail.com> |
11 | | * |
12 | | * References: |
13 | | * [1] ETSI TS 101 376-4-6 V1.2.1 - GMR-1 04.006 |
14 | | * |
15 | | * Wireshark - Network traffic analyzer |
16 | | * By Gerald Combs <gerald@wireshark.org> |
17 | | * Copyright 1998 Gerald Combs |
18 | | * |
19 | | * SPDX-License-Identifier: GPL-2.0-or-later |
20 | | */ |
21 | | |
22 | | #include "config.h" |
23 | | |
24 | | #include <epan/packet.h> |
25 | | #include <epan/reassemble.h> |
26 | | #include <epan/conversation.h> |
27 | | |
28 | | void proto_register_lapsat(void); |
29 | | |
30 | | static int proto_lapsat; |
31 | | |
32 | | static reassembly_table lapsat_reassembly_table; |
33 | | |
34 | | static dissector_table_t lapsat_sapi_dissector_table; |
35 | | |
36 | | static int ett_lapsat; |
37 | | static int ett_lapsat_address; |
38 | | static int ett_lapsat_control; |
39 | | static int ett_lapsat_fragment; |
40 | | static int ett_lapsat_fragments; |
41 | | |
42 | | static int hf_lapsat_addr; |
43 | | static int hf_lapsat_addr_sst; |
44 | | static int hf_lapsat_addr_cr; |
45 | | static int hf_lapsat_addr_sapi; |
46 | | static int hf_lapsat_addr_si; |
47 | | static int hf_lapsat_addr_lpd; |
48 | | static int hf_lapsat_addr_lfi; |
49 | | |
50 | | static int hf_lapsat_ctl; |
51 | | static int hf_lapsat_ctl_ftype_i; |
52 | | static int hf_lapsat_ctl_ftype_s_u; |
53 | | static int hf_lapsat_ctl_s_ftype; |
54 | | static int hf_lapsat_ctl_u_modifier_cmd; |
55 | | static int hf_lapsat_ctl_u_modifier_resp; |
56 | | static int hf_lapsat_ctl_n_r; |
57 | | static int hf_lapsat_ctl_n_s; |
58 | | static int hf_lapsat_ctl_p; |
59 | | static int hf_lapsat_ctl_f; |
60 | | static int hf_lapsat_ctl_mii; |
61 | | |
62 | | static int hf_lapsat_payload_last_nibble; |
63 | | |
64 | | static int hf_lapsat_len; |
65 | | |
66 | | static int hf_lapsat_fragment_data; |
67 | | static int hf_lapsat_fragments; |
68 | | static int hf_lapsat_fragment; |
69 | | static int hf_lapsat_fragment_overlap; |
70 | | static int hf_lapsat_fragment_overlap_conflicts; |
71 | | static int hf_lapsat_fragment_multiple_tails; |
72 | | static int hf_lapsat_fragment_too_long_fragment; |
73 | | static int hf_lapsat_fragment_error; |
74 | | static int hf_lapsat_fragment_count; |
75 | | static int hf_lapsat_reassembled_in; |
76 | | static int hf_lapsat_reassembled_length; |
77 | | |
78 | | |
79 | 51 | #define LAPSAT_HEADER_LEN 3 |
80 | | |
81 | | #define LAPSAT_SAPI_RR_CC_MM 0 |
82 | | #define LAPSAT_SAPI_SMS 3 |
83 | | |
84 | | |
85 | | /* |
86 | | * Address field bits |
87 | | */ |
88 | | |
89 | 14 | #define LAPSAT_SST 0x01 /* SACCH status bit */ |
90 | 39 | #define LAPSAT_CR 0x02 /* Command/Response bit */ |
91 | 39 | #define LAPSAT_SAPI_MSK 0x0c /* Service Access Point Identifier */ |
92 | 25 | #define LAPSAT_SAPI_SHIFT 2 |
93 | 38 | #define LAPSAT_SI 0x10 /* Segment Indicator */ |
94 | 14 | #define LAPSAT_LPD_MSK 0x60 /* DL for LAPSat or SMS-CB */ |
95 | | #define LAPSAT_LPD_SHIFT 6 |
96 | 89 | #define LAPSAT_LFI 0x80 /* Length Field Indicator */ |
97 | | |
98 | | static const value_string lapsat_addr_sst_vals[] = { |
99 | | { 0, "FACCH and all other messages" }, |
100 | | { 1, "SACCH message" }, |
101 | | { 0 , NULL } |
102 | | }; |
103 | | |
104 | | static const value_string lapsat_addr_sapi_vals[] = { |
105 | | { LAPSAT_SAPI_RR_CC_MM, "RR/MM/CC" }, |
106 | | { LAPSAT_SAPI_SMS, "SMS/SS" }, |
107 | | { 0, NULL } |
108 | | }; |
109 | | |
110 | | static const value_string lapsat_addr_lpd_vals[] = { |
111 | | { 0, "Normal GMR-1" }, |
112 | | { 1, "Cell broadcast service" }, |
113 | | { 0, NULL } |
114 | | }; |
115 | | |
116 | | static const value_string lapsat_addr_si_vals[] = { |
117 | | { 0, "Complete/Last Segment of L3 message" }, |
118 | | { 1, "Segment only" }, |
119 | | { 0, NULL } |
120 | | }; |
121 | | |
122 | | static const value_string lapsat_addr_lfi_vals[] = { |
123 | | { 0, "Length Field not present (all data valid)" }, |
124 | | { 1, "Length Field present" }, |
125 | | { 0, NULL } |
126 | | }; |
127 | | |
128 | | |
129 | | /* |
130 | | * Frame types |
131 | | */ |
132 | | |
133 | 10 | #define LAPSAT_CTL_TYPE_S 0x001 |
134 | 14 | #define LAPSAT_CTL_TYPE_U 0x003 |
135 | 64 | #define LAPSAT_CTL_TYPE_S_U_MSK 0x003 |
136 | | |
137 | 24 | #define LAPSAT_CTL_TYPE_I 0x000 |
138 | 38 | #define LAPSAT_CTL_TYPE_I_MSK 0x001 |
139 | | |
140 | | static const value_string lapsat_ctl_ftype_vals[] = { |
141 | | { LAPSAT_CTL_TYPE_I, "Information frame" }, |
142 | | { LAPSAT_CTL_TYPE_S, "Supervisory frame" }, |
143 | | { LAPSAT_CTL_TYPE_U, "Unnumbered frame" }, |
144 | | { 0, NULL } |
145 | | }; |
146 | | |
147 | | |
148 | | /* |
149 | | * S-format frame types |
150 | | */ |
151 | | |
152 | 19 | #define LAPSAT_CTL_S_FTYPE_MSK 0x00c |
153 | | |
154 | 3 | #define LAPSAT_RR 0x000 |
155 | 0 | #define LAPSAT_GREJ 0x008 |
156 | | |
157 | | static const value_string lapsat_ctl_s_ftype_vals[] = { |
158 | | { LAPSAT_RR >> 2, "Receiver ready" }, |
159 | | { LAPSAT_GREJ >> 2, "Group reject" }, |
160 | | { 0, NULL} |
161 | | }; |
162 | | |
163 | | |
164 | | /* |
165 | | * U-format modifiers |
166 | | */ |
167 | | |
168 | 42 | #define LAPSAT_CTL_U_MODIFIER_MSK 0x18c |
169 | | |
170 | 8 | #define LAPSAT_SABM 0x08c |
171 | 1 | #define LAPSAT_DM 0x00c |
172 | 1 | #define LAPSAT_DISC 0x100 |
173 | 1 | #define LAPSAT_UA 0x180 |
174 | 1 | #define LAPSAT_UI 0x000 |
175 | | |
176 | | static const value_string lapsat_ctl_u_modifier_vals_cmd[] = { |
177 | | { LAPSAT_SABM >> 2, "Set Asynchronous Balanced Mode" }, |
178 | | { LAPSAT_DISC >> 2, "Disconnect" }, |
179 | | { LAPSAT_UI >> 2, "Unnumbered Information" }, |
180 | | { 0, NULL} |
181 | | }; |
182 | | |
183 | | static const value_string lapsat_ctl_u_modifier_vals_resp[] = { |
184 | | { LAPSAT_DM >> 2, "Disconnected mode" }, |
185 | | { LAPSAT_UA >> 2, "Unnumbered Acknowledge" }, |
186 | | { 0, NULL} |
187 | | }; |
188 | | |
189 | | |
190 | | /* |
191 | | * Control fields |
192 | | */ |
193 | | |
194 | 53 | #define LAPSAT_CTL_P_F 0x040 |
195 | 16 | #define LAPSAT_CTL_MII 0x200 |
196 | 14 | #define LAPSAT_CTL_N_R_MSK 0xf80 |
197 | | #define LAPSAT_CTL_N_R_SHIFT 7 |
198 | 14 | #define LAPSAT_CTL_N_S_MSK 0x03e |
199 | | #define LAPSAT_CTL_N_S_SHIFT 1 |
200 | | |
201 | | |
202 | | /* |
203 | | * Fragment stuff |
204 | | */ |
205 | | |
206 | | |
207 | | static const fragment_items lapsat_frag_items = { |
208 | | /* Fragment subtrees */ |
209 | | &ett_lapsat_fragment, |
210 | | &ett_lapsat_fragments, |
211 | | /* Fragment fields */ |
212 | | &hf_lapsat_fragments, |
213 | | &hf_lapsat_fragment, |
214 | | &hf_lapsat_fragment_overlap, |
215 | | &hf_lapsat_fragment_overlap_conflicts, |
216 | | &hf_lapsat_fragment_multiple_tails, |
217 | | &hf_lapsat_fragment_too_long_fragment, |
218 | | &hf_lapsat_fragment_error, |
219 | | &hf_lapsat_fragment_count, |
220 | | /* Reassembled in field */ |
221 | | &hf_lapsat_reassembled_in, |
222 | | /* Reassembled length field */ |
223 | | &hf_lapsat_reassembled_length, |
224 | | /* Reassembled data field */ |
225 | | NULL, |
226 | | /* Tag */ |
227 | | "fragments" |
228 | | }; |
229 | | |
230 | | |
231 | | /* |
232 | | * Main dissection functions |
233 | | */ |
234 | | |
235 | | static uint16_t |
236 | | dissect_control(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int is_response) |
237 | 25 | { |
238 | 25 | proto_tree *ctl_tree; |
239 | 25 | proto_item *ctl_ti; |
240 | 25 | uint16_t ctl, poll_final; |
241 | 25 | const char *frame_type; |
242 | 25 | char *info; |
243 | | |
244 | 25 | info = (char *)wmem_alloc(pinfo->pool, 80); |
245 | | |
246 | | /* Grab complete control field */ |
247 | 25 | ctl = tvb_get_ntohs(tvb, 1) >> 4; |
248 | | |
249 | 25 | poll_final = ctl & LAPSAT_CTL_P_F; |
250 | | |
251 | | /* Generate small 'descriptive' text */ |
252 | 25 | switch (ctl & LAPSAT_CTL_TYPE_S_U_MSK) { |
253 | 5 | case LAPSAT_CTL_TYPE_S: |
254 | | /* |
255 | | * Supervisory frame. |
256 | | */ |
257 | 5 | switch (ctl & LAPSAT_CTL_S_FTYPE_MSK) { |
258 | 3 | case LAPSAT_RR: |
259 | 3 | frame_type = "RR"; |
260 | 3 | break; |
261 | 0 | case LAPSAT_GREJ: |
262 | 0 | frame_type = "GREJ"; |
263 | 0 | break; |
264 | 2 | default: |
265 | 2 | frame_type = "Unknown"; |
266 | 2 | break; |
267 | 5 | } |
268 | | |
269 | 5 | snprintf(info, 80, "S%s, func=%s, N(R)=%u", |
270 | 5 | poll_final ? (is_response ? " F" : " P") : "", |
271 | 5 | frame_type, |
272 | 5 | (ctl & LAPSAT_CTL_N_R_MSK) >> LAPSAT_CTL_N_R_SHIFT); |
273 | | |
274 | 5 | break; |
275 | | |
276 | 7 | case LAPSAT_CTL_TYPE_U: |
277 | | /* |
278 | | * Unnumbered frame |
279 | | */ |
280 | 7 | switch (ctl & LAPSAT_CTL_U_MODIFIER_MSK) { |
281 | 1 | case LAPSAT_SABM: |
282 | 1 | frame_type = (ctl & LAPSAT_CTL_MII) ? |
283 | 1 | "SABM, MII=1" : "SABM, MII=0"; |
284 | 1 | break; |
285 | 1 | case LAPSAT_DM: |
286 | 1 | frame_type = "DM"; |
287 | 1 | break; |
288 | 1 | case LAPSAT_DISC: |
289 | 1 | frame_type = "DISC"; |
290 | 1 | break; |
291 | 1 | case LAPSAT_UA: |
292 | 1 | frame_type = "UA"; |
293 | 1 | break; |
294 | 1 | case LAPSAT_UI: |
295 | 1 | frame_type = "UI"; |
296 | 1 | break; |
297 | 2 | default: |
298 | 2 | frame_type = "Unknown"; |
299 | 2 | break; |
300 | 7 | } |
301 | | |
302 | 7 | snprintf(info, 80, "U%s, func=%s", |
303 | 7 | poll_final ? (is_response ? " F" : " P") : "", |
304 | 7 | frame_type); |
305 | | |
306 | 7 | break; |
307 | | |
308 | 13 | default: |
309 | | /* |
310 | | * Information frame |
311 | | */ |
312 | 13 | snprintf(info, 80, "I%s, N(R)=%u, N(S)=%u", |
313 | 13 | poll_final ? " P" : "", |
314 | 13 | (ctl & LAPSAT_CTL_N_R_MSK) >> LAPSAT_CTL_N_R_SHIFT, |
315 | 13 | (ctl & LAPSAT_CTL_N_S_MSK) >> LAPSAT_CTL_N_S_SHIFT); |
316 | | |
317 | 13 | break; |
318 | 25 | } |
319 | | |
320 | | /* Add info */ |
321 | 25 | col_add_str(pinfo->cinfo, COL_INFO, info); |
322 | | |
323 | | /* Create item & subtree */ |
324 | 25 | ctl_ti = proto_tree_add_uint_format_value( |
325 | 25 | tree, hf_lapsat_ctl, |
326 | 25 | tvb, 1, 2, (uint32_t)ctl, |
327 | 25 | "%s (0x%03x)", info, ctl |
328 | 25 | ); |
329 | | |
330 | 25 | ctl_tree = proto_item_add_subtree(ctl_ti, ett_lapsat_control); |
331 | | |
332 | | /* Add all fields */ |
333 | 25 | switch (ctl & LAPSAT_CTL_TYPE_S_U_MSK) { |
334 | 5 | case LAPSAT_CTL_TYPE_S: |
335 | | /* |
336 | | * Supervisory frame. |
337 | | */ |
338 | | |
339 | 5 | proto_tree_add_item(ctl_tree, hf_lapsat_ctl_ftype_s_u, |
340 | 5 | tvb, 1, 2, ENC_BIG_ENDIAN); |
341 | | |
342 | 5 | proto_tree_add_item(ctl_tree, hf_lapsat_ctl_s_ftype, |
343 | 5 | tvb, 1, 2, ENC_BIG_ENDIAN); |
344 | | |
345 | 5 | proto_tree_add_item(ctl_tree, hf_lapsat_ctl_n_r, |
346 | 5 | tvb, 1, 2, ENC_BIG_ENDIAN); |
347 | | |
348 | 5 | if (poll_final) |
349 | 2 | proto_tree_add_item(ctl_tree, |
350 | 2 | is_response ? hf_lapsat_ctl_f : hf_lapsat_ctl_p, |
351 | 2 | tvb, 1, 2, ENC_BIG_ENDIAN); |
352 | | |
353 | 5 | break; |
354 | | |
355 | 7 | case LAPSAT_CTL_TYPE_U: |
356 | | /* |
357 | | * Unnumbered frame |
358 | | */ |
359 | | |
360 | 7 | proto_tree_add_item(ctl_tree, hf_lapsat_ctl_ftype_s_u, |
361 | 7 | tvb, 1, 2, ENC_BIG_ENDIAN); |
362 | | |
363 | 7 | proto_tree_add_item(ctl_tree, |
364 | 7 | is_response ? hf_lapsat_ctl_u_modifier_resp : |
365 | 7 | hf_lapsat_ctl_u_modifier_cmd, |
366 | 7 | tvb, 1, 2, ENC_BIG_ENDIAN); |
367 | | |
368 | 7 | if (poll_final) |
369 | 2 | proto_tree_add_item(ctl_tree, |
370 | 2 | is_response ? hf_lapsat_ctl_f : hf_lapsat_ctl_p, |
371 | 2 | tvb, 1, 2, ENC_BIG_ENDIAN); |
372 | | |
373 | 7 | if (((ctl & LAPSAT_CTL_U_MODIFIER_MSK) == LAPSAT_SABM) && |
374 | 7 | (ctl & LAPSAT_CTL_MII)) |
375 | 1 | proto_tree_add_item(ctl_tree, hf_lapsat_ctl_mii, |
376 | 1 | tvb, 1, 2, ENC_BIG_ENDIAN); |
377 | | |
378 | 7 | break; |
379 | | |
380 | 13 | default: |
381 | | /* |
382 | | * Information frame |
383 | | */ |
384 | | |
385 | 13 | proto_tree_add_item(ctl_tree, hf_lapsat_ctl_ftype_i, |
386 | 13 | tvb, 1, 2, ENC_BIG_ENDIAN); |
387 | | |
388 | 13 | proto_tree_add_item(ctl_tree, hf_lapsat_ctl_n_r, |
389 | 13 | tvb, 1, 2, ENC_BIG_ENDIAN); |
390 | | |
391 | 13 | proto_tree_add_item(ctl_tree, hf_lapsat_ctl_n_s, |
392 | 13 | tvb, 1, 2, ENC_BIG_ENDIAN); |
393 | | |
394 | 13 | if (poll_final) |
395 | 4 | proto_tree_add_item(ctl_tree, hf_lapsat_ctl_p, |
396 | 4 | tvb, 1, 2, ENC_BIG_ENDIAN); |
397 | | |
398 | 13 | break; |
399 | 25 | } |
400 | | |
401 | 25 | return ctl; |
402 | 25 | } |
403 | | |
404 | | static int |
405 | | dissect_lapsat(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* dissector_data _U_) |
406 | 26 | { |
407 | 26 | proto_tree *lapsat_tree, *addr_tree; |
408 | 26 | proto_item *lapsat_ti, *addr_ti; |
409 | 26 | tvbuff_t *payload; |
410 | 26 | uint8_t addr, sapi, cr; |
411 | 26 | uint16_t control; |
412 | 26 | unsigned int hlen, is_response = 0, plen; |
413 | | |
414 | | /* Check that there's enough data */ |
415 | 26 | if (tvb_captured_length(tvb) < LAPSAT_HEADER_LEN) |
416 | 1 | return 0; |
417 | | |
418 | | /* Set protocol column */ |
419 | 25 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "LAPSat"); |
420 | | |
421 | | /* Grab a couple of fields */ |
422 | 25 | addr = tvb_get_uint8(tvb, 0); |
423 | | |
424 | 25 | sapi = (addr & LAPSAT_SAPI_MSK) >> LAPSAT_SAPI_SHIFT; |
425 | | |
426 | 25 | cr = addr & LAPSAT_CR; |
427 | 25 | if (pinfo->p2p_dir == P2P_DIR_RECV) { |
428 | 17 | is_response = cr ? false : true; |
429 | 17 | } |
430 | 8 | else if (pinfo->p2p_dir == P2P_DIR_SENT) { |
431 | 8 | is_response = cr ? true : false; |
432 | 8 | } |
433 | | |
434 | 25 | hlen = LAPSAT_HEADER_LEN; |
435 | | |
436 | 25 | if (addr & LAPSAT_LFI) |
437 | 6 | hlen++; |
438 | | |
439 | | /* FIXME if "S func=GREJ", extend */ |
440 | | |
441 | | /* Create LAPSat tree */ |
442 | 25 | lapsat_ti = proto_tree_add_item(tree, proto_lapsat, tvb, 0, hlen, ENC_NA); |
443 | 25 | lapsat_tree = proto_item_add_subtree(lapsat_ti, ett_lapsat); |
444 | | |
445 | | /* Dissect address field */ |
446 | 25 | addr_ti = proto_tree_add_item(lapsat_tree, hf_lapsat_addr, tvb, 0, 1, ENC_BIG_ENDIAN); |
447 | 25 | addr_tree = proto_item_add_subtree(addr_ti, ett_lapsat_address); |
448 | | |
449 | 25 | proto_tree_add_item(addr_tree, hf_lapsat_addr_sst, tvb, 0, 1, ENC_BIG_ENDIAN); |
450 | 25 | proto_tree_add_item(addr_tree, hf_lapsat_addr_cr, tvb, 0, 1, ENC_BIG_ENDIAN); |
451 | 25 | proto_tree_add_item(addr_tree, hf_lapsat_addr_sapi, tvb, 0, 1, ENC_BIG_ENDIAN); |
452 | 25 | proto_tree_add_item(addr_tree, hf_lapsat_addr_si, tvb, 0, 1, ENC_BIG_ENDIAN); |
453 | 25 | proto_tree_add_item(addr_tree, hf_lapsat_addr_lpd, tvb, 0, 1, ENC_BIG_ENDIAN); |
454 | 25 | proto_tree_add_item(addr_tree, hf_lapsat_addr_lfi, tvb, 0, 1, ENC_BIG_ENDIAN); |
455 | | |
456 | | /* Dissect control field */ |
457 | 25 | control = dissect_control(tvb, pinfo, lapsat_tree, is_response); |
458 | | |
459 | | /* Last payload nibble */ |
460 | 25 | proto_tree_add_item(lapsat_tree, hf_lapsat_payload_last_nibble, tvb, 2, 1, ENC_BIG_ENDIAN); |
461 | | |
462 | | /* Optional length field */ |
463 | 25 | if (addr & LAPSAT_LFI) |
464 | 6 | proto_tree_add_item(lapsat_tree, hf_lapsat_len, tvb, 3, 1, ENC_BIG_ENDIAN); |
465 | | |
466 | | /* If frame is "S func=GREJ", then add Na(R) & Nb(R) */ |
467 | | /* FIXME */ |
468 | | |
469 | | /* Get the payload */ |
470 | 25 | plen = (addr & LAPSAT_LFI) ? |
471 | 19 | tvb_get_uint8(tvb, 3) : tvb_captured_length(tvb) - hlen; |
472 | | |
473 | 25 | if (!plen) |
474 | 1 | return 3; /* No point in doing more if there is no payload */ |
475 | | |
476 | 24 | if ((plen + hlen) == tvb_captured_length(tvb)) { |
477 | | /* Need to integrate the last nibble */ |
478 | 19 | uint8_t *data = (uint8_t *)tvb_memdup(pinfo->pool, tvb, hlen, plen); |
479 | 19 | data[plen-1] |= tvb_get_uint8(tvb, 2) << 4; |
480 | 19 | payload = tvb_new_child_real_data(tvb, data, plen, plen); |
481 | 19 | } else { |
482 | | /* Last nibble doesn't need merging */ |
483 | 5 | payload = tvb_new_subset_length(tvb, hlen, plen); |
484 | 5 | } |
485 | | |
486 | 24 | add_new_data_source(pinfo, payload, "LAPSat Payload"); |
487 | | |
488 | | /* Handle fragments */ |
489 | 24 | if ((control & LAPSAT_CTL_TYPE_I_MSK) == LAPSAT_CTL_TYPE_I) { |
490 | | /* |
491 | | * Potentially fragmented I frames |
492 | | */ |
493 | 12 | fragment_head *fd_m = NULL; |
494 | 12 | tvbuff_t *reassembled = NULL; |
495 | 12 | uint32_t fragment_id; |
496 | 12 | bool save_fragmented = pinfo->fragmented; |
497 | | |
498 | | /* Is this a fragment ? */ |
499 | 12 | pinfo->fragmented = !!(addr & LAPSAT_SI); |
500 | | |
501 | | /* Rely on caller to provide a way to group fragments */ |
502 | 12 | fragment_id = (conversation_get_id_from_elements(pinfo, CONVERSATION_GSMTAP, USE_LAST_ENDPOINT) << 3) | (sapi << 1) | pinfo->p2p_dir; |
503 | | |
504 | | /* Fragment reconstruction helpers */ |
505 | 12 | fd_m = fragment_add_seq_next( |
506 | 12 | &lapsat_reassembly_table, |
507 | 12 | payload, 0, |
508 | 12 | pinfo, |
509 | 12 | fragment_id, /* To group fragments */ |
510 | 12 | NULL, |
511 | 12 | plen, |
512 | 12 | !!(addr & LAPSAT_SI) /* More fragment ? */ |
513 | 12 | ); |
514 | | |
515 | 12 | reassembled = process_reassembled_data( |
516 | 12 | payload, 0, pinfo, |
517 | 12 | "Reassembled LAPSat", fd_m, &lapsat_frag_items, |
518 | 12 | NULL, lapsat_tree |
519 | 12 | ); |
520 | | |
521 | | /* Reassembled into this packet ? */ |
522 | 12 | if (fd_m && pinfo->num == fd_m->reassembled_in) { |
523 | | /* Yes, so handoff to upper layers */ |
524 | 11 | if (!dissector_try_uint(lapsat_sapi_dissector_table, sapi, |
525 | 11 | reassembled, pinfo, tree)) |
526 | 1 | call_data_dissector(reassembled, pinfo, tree); |
527 | 11 | } else { |
528 | | /* No, just add infos */ |
529 | 1 | col_append_str(pinfo->cinfo, COL_INFO, " (Fragment)"); |
530 | 1 | proto_tree_add_item(lapsat_tree, hf_lapsat_fragment_data, payload, 0, -1, ENC_NA); |
531 | 1 | } |
532 | | |
533 | | /* Now reset fragmentation information in pinfo */ |
534 | 12 | pinfo->fragmented = save_fragmented; |
535 | 12 | } else { |
536 | | /* |
537 | | * Whole frame |
538 | | */ |
539 | 12 | if (!dissector_try_uint(lapsat_sapi_dissector_table, sapi, payload, pinfo, tree)) |
540 | 3 | call_data_dissector(payload, pinfo, tree); |
541 | 12 | } |
542 | 24 | return tvb_captured_length(tvb); |
543 | 25 | } |
544 | | |
545 | | void |
546 | | proto_register_lapsat(void) |
547 | 14 | { |
548 | 14 | static hf_register_info hf[] = { |
549 | | /* Address field */ |
550 | 14 | { &hf_lapsat_addr, |
551 | 14 | { "Address Field", "lapsat.address", |
552 | 14 | FT_UINT8, BASE_HEX, NULL, 0x00, |
553 | 14 | NULL, HFILL }, |
554 | 14 | }, |
555 | 14 | { &hf_lapsat_addr_sst, |
556 | 14 | { "SST", "lapsat.address.sst", |
557 | 14 | FT_UINT8, BASE_DEC, VALS(lapsat_addr_sst_vals), LAPSAT_SST, |
558 | 14 | "SACCH status bit", HFILL }, |
559 | 14 | }, |
560 | 14 | { &hf_lapsat_addr_cr, |
561 | 14 | { "C/R", "lapsat.address.cr", |
562 | 14 | FT_UINT8, BASE_DEC, NULL, LAPSAT_CR, |
563 | 14 | "Command/response bit", HFILL }, |
564 | 14 | }, |
565 | 14 | { &hf_lapsat_addr_sapi, |
566 | 14 | { "SAPI", "lapsat.address.sapi", |
567 | 14 | FT_UINT8, BASE_DEC, VALS(lapsat_addr_sapi_vals), LAPSAT_SAPI_MSK, |
568 | 14 | "Service access point identifier", HFILL }, |
569 | 14 | }, |
570 | 14 | { &hf_lapsat_addr_si, |
571 | 14 | { "SI", "lapsat.address.si", |
572 | 14 | FT_UINT8, BASE_DEC, VALS(lapsat_addr_si_vals), LAPSAT_SI, |
573 | 14 | "Segment Indicator", HFILL }, |
574 | 14 | }, |
575 | 14 | { &hf_lapsat_addr_lpd, |
576 | 14 | { "LPD", "lapsat.address.lpd", |
577 | 14 | FT_UINT8, BASE_DEC, VALS(lapsat_addr_lpd_vals), LAPSAT_LPD_MSK, |
578 | 14 | "Link Protocol Discriminator", HFILL }, |
579 | 14 | }, |
580 | 14 | { &hf_lapsat_addr_lfi, |
581 | 14 | { "LFI", "lapsat.address.lfi", |
582 | 14 | FT_UINT8, BASE_DEC, VALS(lapsat_addr_lfi_vals), LAPSAT_LFI, |
583 | 14 | "Length Field Indicator", HFILL }, |
584 | 14 | }, |
585 | | |
586 | | /* Control field */ |
587 | 14 | { &hf_lapsat_ctl, |
588 | 14 | { "Control Field", "lapsat.control_field", |
589 | 14 | FT_UINT16, BASE_HEX, NULL, 0x00, |
590 | 14 | NULL, HFILL } |
591 | 14 | }, |
592 | 14 | { &hf_lapsat_ctl_ftype_i, |
593 | 14 | { "Frame type", "lapsat.control.ftype", |
594 | 14 | FT_UINT16, BASE_DEC, VALS(lapsat_ctl_ftype_vals), LAPSAT_CTL_TYPE_I_MSK << 4, |
595 | 14 | NULL, HFILL } |
596 | 14 | }, |
597 | 14 | { &hf_lapsat_ctl_ftype_s_u, |
598 | 14 | { "Frame type", "lapsat.control.ftype", |
599 | 14 | FT_UINT16, BASE_DEC, VALS(lapsat_ctl_ftype_vals), LAPSAT_CTL_TYPE_S_U_MSK << 4, |
600 | 14 | NULL, HFILL } |
601 | 14 | }, |
602 | 14 | { &hf_lapsat_ctl_s_ftype, |
603 | 14 | { "Supervisory frame type", "lapsat.control.s_ftype", |
604 | 14 | FT_UINT16, BASE_DEC, VALS(lapsat_ctl_s_ftype_vals), LAPSAT_CTL_S_FTYPE_MSK << 4, |
605 | 14 | NULL, HFILL } |
606 | 14 | }, |
607 | 14 | { &hf_lapsat_ctl_u_modifier_cmd, |
608 | 14 | { "Command", "lapsat.control.u_modifier_cmd", |
609 | 14 | FT_UINT16, BASE_HEX, VALS(lapsat_ctl_u_modifier_vals_cmd), |
610 | 14 | LAPSAT_CTL_U_MODIFIER_MSK << 4, |
611 | 14 | NULL, HFILL } |
612 | 14 | }, |
613 | 14 | { &hf_lapsat_ctl_u_modifier_resp, |
614 | 14 | { "Response", "lapsat.control.u_modifier_resp", |
615 | 14 | FT_UINT16, BASE_HEX, VALS(lapsat_ctl_u_modifier_vals_resp), |
616 | 14 | LAPSAT_CTL_U_MODIFIER_MSK << 4, |
617 | 14 | NULL, HFILL } |
618 | 14 | }, |
619 | 14 | { &hf_lapsat_ctl_n_r, |
620 | 14 | { "N(R)", "lapsat.control.n_r", |
621 | 14 | FT_UINT16, BASE_DEC, NULL, LAPSAT_CTL_N_R_MSK << 4, |
622 | 14 | NULL, HFILL } |
623 | 14 | }, |
624 | 14 | { &hf_lapsat_ctl_n_s, |
625 | 14 | { "N(S)", "lapsat.control.n_s", |
626 | 14 | FT_UINT16, BASE_DEC, NULL, LAPSAT_CTL_N_S_MSK << 4, |
627 | 14 | NULL, HFILL } |
628 | 14 | }, |
629 | 14 | { &hf_lapsat_ctl_p, |
630 | 14 | { "Poll", "lapsat.control.p", |
631 | 14 | FT_BOOLEAN, 16, NULL, LAPSAT_CTL_P_F << 4, |
632 | 14 | NULL, HFILL } |
633 | 14 | }, |
634 | 14 | { &hf_lapsat_ctl_f, |
635 | 14 | { "Final", "lapsat.control.f", |
636 | 14 | FT_BOOLEAN, 16, NULL, LAPSAT_CTL_P_F << 4, |
637 | 14 | NULL, HFILL } |
638 | 14 | }, |
639 | 14 | { &hf_lapsat_ctl_mii, |
640 | 14 | { "MII", "lapsat.control.mii", |
641 | 14 | FT_BOOLEAN, 16, NULL, LAPSAT_CTL_MII << 4, |
642 | 14 | "Mobile Identity Indicator", HFILL } |
643 | 14 | }, |
644 | | |
645 | | /* Payload last nibble */ |
646 | 14 | { &hf_lapsat_payload_last_nibble, |
647 | 14 | { "Payload last nibble", "lapsat.payload.last_nibble", |
648 | 14 | FT_UINT8, BASE_HEX, NULL, 0x0f, |
649 | 14 | NULL, HFILL } |
650 | 14 | }, |
651 | | |
652 | | /* Length field */ |
653 | 14 | { &hf_lapsat_len, |
654 | 14 | { "Length Field", "lapsat.length", |
655 | 14 | FT_UINT8, BASE_DEC, NULL, 0x00, |
656 | 14 | NULL, HFILL }, |
657 | 14 | }, |
658 | | |
659 | | /* Fragment reassembly */ |
660 | 14 | { &hf_lapsat_fragment_data, |
661 | 14 | { "Fragment Data", "lapsat.fragment_data", |
662 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
663 | 14 | NULL, HFILL } |
664 | 14 | }, |
665 | 14 | { &hf_lapsat_fragments, |
666 | 14 | { "Message fragments", "lapsat.fragments", |
667 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
668 | 14 | "LAPSat Message fragments", HFILL } |
669 | 14 | }, |
670 | 14 | { &hf_lapsat_fragment, |
671 | 14 | { "Message fragment", "lapsat.fragment", |
672 | 14 | FT_FRAMENUM, BASE_NONE, NULL, 0x00, |
673 | 14 | "LAPSat Message fragment", HFILL } |
674 | 14 | }, |
675 | 14 | { &hf_lapsat_fragment_overlap, |
676 | 14 | { "Message fragment overlap", "lapsat.fragment.overlap", |
677 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
678 | 14 | "LAPSat Message fragment overlaps with other fragment(s)", HFILL } |
679 | 14 | }, |
680 | 14 | { &hf_lapsat_fragment_overlap_conflicts, |
681 | 14 | { "Message fragment overlapping with conflicting data", |
682 | 14 | "lapsat.fragment.overlap.conflicts", |
683 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
684 | 14 | "LAPSat Message fragment overlaps with conflicting data", HFILL } |
685 | 14 | }, |
686 | 14 | { &hf_lapsat_fragment_multiple_tails, |
687 | 14 | { "Message has multiple tail fragments", "lapsat.fragment.multiple_tails", |
688 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
689 | 14 | "LAPSat Message fragment has multiple tail fragments", HFILL } |
690 | 14 | }, |
691 | 14 | { &hf_lapsat_fragment_too_long_fragment, |
692 | 14 | { "Message fragment too long", "lapsat.fragment.too_long_fragment", |
693 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
694 | 14 | "LAPSat Message fragment data goes beyond the packet end", HFILL } |
695 | 14 | }, |
696 | 14 | { &hf_lapsat_fragment_error, |
697 | 14 | { "Message defragmentation error", "lapsat.fragment.error", |
698 | 14 | FT_FRAMENUM, BASE_NONE, NULL, 0x00, |
699 | 14 | "LAPSat Message defragmentation error due to illegal fragments", HFILL } |
700 | 14 | }, |
701 | 14 | { &hf_lapsat_fragment_count, |
702 | 14 | { "Message fragment count", "lapsat.fragment.count", |
703 | 14 | FT_UINT32, BASE_DEC, NULL, 0x00, |
704 | 14 | NULL, HFILL } |
705 | 14 | }, |
706 | 14 | { &hf_lapsat_reassembled_in, |
707 | 14 | { "Reassembled in", "lapsat.reassembled.in", |
708 | 14 | FT_FRAMENUM, BASE_NONE, NULL, 0x00, |
709 | 14 | "LAPSat Message has been reassembled in this packet.", HFILL } |
710 | 14 | }, |
711 | 14 | { &hf_lapsat_reassembled_length, |
712 | 14 | { "Reassembled LAPSat length", "lapsat.reassembled.length", |
713 | 14 | FT_UINT32, BASE_DEC, NULL, 0x00, |
714 | 14 | "The total length of the reassembled payload", HFILL } |
715 | 14 | }, |
716 | 14 | }; |
717 | | |
718 | 14 | static int *ett[] = { |
719 | 14 | &ett_lapsat, |
720 | 14 | &ett_lapsat_address, |
721 | 14 | &ett_lapsat_control, |
722 | 14 | &ett_lapsat_fragment, |
723 | 14 | &ett_lapsat_fragments, |
724 | 14 | }; |
725 | | |
726 | 14 | proto_lapsat = proto_register_protocol("Link Access Procedure, Satellite channel (LAPSat)", "LAPSat", "lapsat"); |
727 | | |
728 | 14 | proto_register_field_array (proto_lapsat, hf, array_length(hf)); |
729 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
730 | | |
731 | 14 | register_dissector("lapsat", dissect_lapsat, proto_lapsat); |
732 | | |
733 | 14 | lapsat_sapi_dissector_table = register_dissector_table("lapsat.sapi", "LAPSat SAPI", proto_lapsat, FT_UINT8, BASE_DEC); |
734 | | |
735 | 14 | reassembly_table_register(&lapsat_reassembly_table, |
736 | 14 | &addresses_reassembly_table_functions); |
737 | 14 | } |
738 | | |
739 | | |
740 | | /* |
741 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
742 | | * |
743 | | * Local variables: |
744 | | * c-basic-offset: 8 |
745 | | * tab-width: 8 |
746 | | * indent-tabs-mode: t |
747 | | * End: |
748 | | * |
749 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
750 | | * :indentSize=8:tabSize=8:noTabs=false: |
751 | | */ |