Coverage Report

Created: 2025-08-04 07:15

/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
 */