2 * Routines for UMTS MAC (3GPP TS 25.321) disassembly
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include <epan/packet.h>
14 #include <epan/conversation.h>
15 #include <epan/expert.h>
16 #include <epan/prefs.h>
17 #include <epan/proto_data.h>
19 #include "packet-rrc.h"
20 #include "packet-umts_fp.h"
21 #include "packet-umts_mac.h"
22 #include "packet-nbap.h"
24 void proto_register_umts_mac(void);
25 void proto_reg_handoff_umts_mac(void);
29 extern int proto_umts_rlc
;
31 /* dissector fields */
32 static int hf_mac_fach_fdd_tctf
;
33 static int hf_mac_rach_fdd_tctf
;
35 static int hf_mac_ueid_type
;
36 static int hf_mac_crnti
;
37 static int hf_mac_urnti
;
38 static int hf_mac_resolved_urnti
;
39 static int hf_mac_crnti_urnti_match_frame
;
40 static int hf_mac_channel
;
41 /* static int hf_mac_channel_str; */
43 static int hf_mac_lch_id
;
44 static int hf_mac_macdflowd_id
;
45 /* static int hf_mac_channel_hsdsch; */
46 static int hf_mac_trch_id
;
48 /* static int hf_mac_edch_type2_subframe_header; */
49 /* static int hf_mac_edch_type2_descriptors; */
50 /* static int hf_mac_edch_type2_lchid; */
51 /* static int hf_mac_edch_type2_length; */
52 /* static int hf_mac_edch_type2_flag; */
53 static int hf_mac_edch_type2_tsn
;
54 static int hf_mac_edch_type2_ss
;
55 static int hf_mac_edch_type2_ss_interpretation
;
56 static int hf_mac_edch_type2_sdu
;
57 static int hf_mac_edch_type2_sdu_data
;
58 static int hf_mac_is_fraglink
;
59 static int hf_mac_is_reasmin
;
63 static int ett_mac_fach
;
64 static int ett_mac_rach
;
65 static int ett_mac_dch
;
66 static int ett_mac_pch
;
67 static int ett_mac_edch
;
68 static int ett_mac_hsdsch
;
69 static int ett_mac_edch_type2
;
70 static int ett_mac_edch_type2_sdu
;
71 static int ett_mac_resolved_urnti
;
73 static expert_field ei_mac_cs_dtch_not_implemented
;
74 static expert_field ei_mac_rach_tctf_unknown
;
75 static expert_field ei_mac_unknown_content
;
76 static expert_field ei_mac_per_frame_info_missing
;
77 static expert_field ei_mac_fach_content_type_unknown
;
78 static expert_field ei_mac_no_logical_channel
;
79 static expert_field ei_mac_faked_logical_channel_id
;
80 static expert_field ei_mac_macis_sdu_reassembled
;
81 static expert_field ei_mac_macis_sdu_first
;
82 static expert_field ei_mac_macis_sdu_middle
;
83 static expert_field ei_mac_macis_sdu_last
;
84 static expert_field ei_mac_macis_sdu_complete
;
85 static expert_field ei_mac_reserved_c_t
;
87 static dissector_handle_t rlc_pcch_handle
;
88 static dissector_handle_t rlc_ccch_handle
;
89 static dissector_handle_t rlc_ctch_handle
;
90 static dissector_handle_t rlc_dcch_handle
;
91 static dissector_handle_t rlc_ps_dtch_handle
;
92 static dissector_handle_t rrc_handle
;
94 /* MAC-is reassembly */
95 static unsigned MAX_TSN
= 64;
96 static uint16_t mac_tsn_size
= 6;
97 static int global_mac_tsn_size
= MAC_TSN_6BITS
;
98 int get_mac_tsn_size(void) { return global_mac_tsn_size
; }
99 static const enum_val_t tsn_size_enumvals
[] = {
100 {"6", "6 bits", MAC_TSN_6BITS
},
101 {"14", "14 bits", MAC_TSN_14BITS
},
103 enum mac_is_fragment_type
{
108 typedef struct _mac_is_fragment
{
114 struct _mac_is_fragment
* next
;
117 uint32_t frame_num
; /* Where reassembly was done (depends on order of arrival). */
118 uint16_t tsn
; /* TSN for the tail fragment. */
121 mac_is_fragment
* fragments
;
124 mac_is_fragment
* head
;
125 mac_is_fragment
* middle
;
126 mac_is_fragment
* tail
;
129 uint8_t lchid
; /* Logical Channel Identifier. */
130 unsigned ueid
; /* User Equipment Identifier. */
132 static GHashTable
* mac_is_sdus
; /* channel -> (frag -> sdu) */
133 static GHashTable
* mac_is_fragments
; /* channel -> body_parts[] */
134 static gboolean
mac_is_channel_equal(const void *a
, const void *b
)
136 const mac_is_channel
*x
= (const mac_is_channel
*)a
, *y
= (const mac_is_channel
*)b
;
137 return x
->lchid
== y
->lchid
&& x
->ueid
== y
->ueid
;
139 static unsigned mac_is_channel_hash(const void *key
)
141 const mac_is_channel
* ch
= (const mac_is_channel
*)key
;
142 return (ch
->ueid
<< 4) | ch
->lchid
;
145 static gboolean
mac_is_fragment_equal(const void *a
, const void *b
)
147 const mac_is_fragment
*x
= (const mac_is_fragment
*)a
, *y
= (const mac_is_fragment
*)b
;
148 return x
->frame_num
== y
->frame_num
&& x
->tsn
== y
->tsn
&& x
->type
== y
->type
;
150 static unsigned mac_is_fragment_hash(const void *key
)
152 const mac_is_fragment
*frag
= (const mac_is_fragment
*)key
;
153 return (frag
->frame_num
<< 2) | frag
->type
;
156 static const value_string rach_fdd_tctf_vals
[] = {
157 { TCTF_CCCH_RACH_FDD
, "CCCH over RACH (FDD)" },
158 { TCTF_DCCH_DTCH_RACH_FDD
, "DCCH/DTCH over RACH (FDD)" },
161 static const value_string fach_fdd_tctf_vals
[] = {
162 { TCTF_BCCH_FACH_FDD
, "BCCH over FACH (FDD)" },
163 { TCTF_DCCH_DTCH_FACH_FDD
, "DCCH/DTCH over FACH (FDD)" },
164 { TCTF_MTCH_FACH_FDD
, "MTCH over FACH (FDD)" },
165 { TCTF_CCCH_FACH_FDD
, "CCCH over FACH (FDD)" },
166 { TCTF_MCCH_FACH_FDD
, "MCCH over FACH (FDD)" },
167 { TCTF_MSCH_FACH_FDD
, "MSCH over FACH (FDD)" },
168 { TCTF_CTCH_FACH_FDD
, "CTCH over FACH (FDD)" },
171 static const value_string ueid_type_vals
[] = {
172 { MAC_UEID_TYPE_URNTI
, "U-RNTI" },
173 { MAC_UEID_TYPE_CRNTI
, "C-RNTI" },
176 static const value_string mac_logical_channel_vals
[] = {
177 { MAC_PCCH
, "PCCH" },
178 { MAC_CCCH
, "CCCH" },
179 { MAC_CTCH
, "CTCH" },
180 { MAC_DCCH
, "DCCH" },
181 { MAC_DTCH
, "DTCH" },
182 { MAC_BCCH
, "BCCH" },
183 { MAC_MCCH
, "MCCH" },
184 { MAC_MSCH
, "MSCH" },
185 { MAC_MTCH
, "MTCH" },
189 static uint8_t fach_fdd_tctf(uint8_t hdr
, uint16_t *bit_offs
)
192 /* first, test for valid 2-bit combinations */
195 case TCTF_BCCH_FACH_FDD
:
196 case TCTF_DCCH_DTCH_FACH_FDD
:
200 /* 4-bit combinations */
203 case TCTF_MTCH_FACH_FDD
:
207 /* just return the 8-bit combination */
211 case TCTF_CCCH_FACH_FDD
:
212 case TCTF_MCCH_FACH_FDD
:
213 case TCTF_MSCH_FACH_FDD
:
214 case TCTF_CTCH_FACH_FDD
:
217 return tctf
; /* TODO */
221 static uint16_t tree_add_common_dcch_dtch_fields(tvbuff_t
*tvb
, packet_info
*pinfo _U_
,
222 proto_tree
*tree
, uint16_t bitoffs
, fp_info
*fpinf
, umts_mac_info
*macinf
, rlc_info
*rlcinf
)
225 conversation_t
*p_conv
;
226 umts_fp_conversation_info_t
*umts_fp_conversation_info
= NULL
;
227 fp_rach_channel_info_t
*fp_rach_channel_info
= NULL
;
228 fp_fach_channel_info_t
*fp_fach_channel_info
= NULL
;
229 wmem_tree_t
* channel_rnti_map
= NULL
;
231 fp_crnti_allocation_info_t
*fp_crnti_allocation_info
= NULL
;
233 ueid_type
= tvb_get_bits8(tvb
, bitoffs
, 2);
234 proto_tree_add_bits_item(tree
, hf_mac_ueid_type
, tvb
, bitoffs
, 2, ENC_BIG_ENDIAN
);
236 if (ueid_type
== MAC_UEID_TYPE_URNTI
) {
237 proto_tree_add_bits_item(tree
, hf_mac_urnti
, tvb
, bitoffs
, 32, ENC_BIG_ENDIAN
);
238 rlcinf
->ueid
[fpinf
->cur_tb
] = tvb_get_bits32(tvb
, bitoffs
, 32,ENC_BIG_ENDIAN
);
240 } else if (ueid_type
== MAC_UEID_TYPE_CRNTI
) {
241 proto_tree_add_bits_item(tree
, hf_mac_crnti
, tvb
, 4, 16, ENC_BIG_ENDIAN
);
242 c_rnti
= tvb_get_bits16(tvb
, bitoffs
, 16,ENC_BIG_ENDIAN
);
243 p_conv
= (conversation_t
*)find_conversation(pinfo
->num
, &pinfo
->net_dst
, &pinfo
->net_src
,
244 conversation_pt_to_conversation_type(pinfo
->ptype
),
245 pinfo
->destport
, pinfo
->srcport
, NO_ADDR_B
);
246 if (p_conv
!= NULL
) {
247 umts_fp_conversation_info
= (umts_fp_conversation_info_t
*)conversation_get_proto_data(p_conv
, proto_fp
);
249 /* Trying to resolve the U-RNTI for this C-RNTI based on the channel type*/
250 switch(fpinf
->channel
){
251 case CHANNEL_RACH_FDD
:
252 /* In RACH: Get the channel's RNTIs map */
253 if (umts_fp_conversation_info
) {
254 fp_rach_channel_info
= (fp_rach_channel_info_t
*)umts_fp_conversation_info
->channel_specific_info
;
255 if(fp_rach_channel_info
) {
256 channel_rnti_map
= fp_rach_channel_info
->crnti_to_urnti_map
;
260 case CHANNEL_FACH_FDD
:
261 /* In FACH: Get the channel's RNTIs map */
262 if (umts_fp_conversation_info
) {
263 fp_fach_channel_info
= (fp_fach_channel_info_t
*)umts_fp_conversation_info
->channel_specific_info
;
264 if(fp_fach_channel_info
) {
265 channel_rnti_map
= fp_fach_channel_info
->crnti_to_urnti_map
;
270 if(channel_rnti_map
) {
271 fp_crnti_allocation_info
= (fp_crnti_allocation_info_t
*)wmem_tree_lookup32(channel_rnti_map
, c_rnti
);
273 /* If not found in the RACH/FACH channel's map, Look in the global RNTIs map */
274 if(fp_crnti_allocation_info
== NULL
) {
275 fp_crnti_allocation_info
= (fp_crnti_allocation_info_t
*)wmem_tree_lookup32(rrc_global_urnti_crnti_map
, c_rnti
);
276 if(fp_crnti_allocation_info
!= NULL
) {
277 /* If found in the global map, check how many times it was retrieved (including this one) */
278 fp_crnti_allocation_info
->global_retrieval_count
++;
279 /* If seen 2 times (RACH + fast FACH) remove from global map */
280 if(fp_crnti_allocation_info
->global_retrieval_count
== 2) {
281 wmem_tree_remove32(rrc_global_urnti_crnti_map
, c_rnti
);
283 /* Also add to this channel's map for later retrieval */
284 if(channel_rnti_map
) {
285 wmem_tree_insert32(channel_rnti_map
, c_rnti
, (void *)fp_crnti_allocation_info
);
289 /* Choosing between resolved U-RNTI (if found) or the C-RNTI as UE-ID for RLC */
290 if(fp_crnti_allocation_info
!= NULL
) {
292 rlcinf
->ueid
[fpinf
->cur_tb
] = fp_crnti_allocation_info
->urnti
;
293 /* Adding 'Resolved U-RNTI' related tree items*/
295 proto_tree
*resolved_urnti_tree
;
296 temp
= proto_tree_add_uint(tree
, hf_mac_resolved_urnti
, tvb
, 0, 0, fp_crnti_allocation_info
->urnti
);
297 proto_item_set_generated(temp
);
298 resolved_urnti_tree
= proto_item_add_subtree(temp
, ett_mac_resolved_urnti
);
299 temp
= proto_tree_add_uint(resolved_urnti_tree
, hf_mac_crnti_urnti_match_frame
, tvb
, 0, 0, fp_crnti_allocation_info
->alloc_frame_number
);
300 proto_item_set_generated(temp
);
304 rlcinf
->ueid
[fpinf
->cur_tb
] = c_rnti
;
309 if (macinf
->ctmux
[fpinf
->cur_tb
]) {
312 rlcinf
->rbid
[fpinf
->cur_tb
] = tvb_get_bits8(tvb
, bitoffs
, 4)+1;
314 proto_tree_add_bits_item(tree
, hf_mac_ct
, tvb
, bitoffs
, 4, ENC_BIG_ENDIAN
);
317 temp
= proto_tree_add_uint(tree
, hf_mac_lch_id
, tvb
, 0, 0, rlcinf
->rbid
[fpinf
->cur_tb
]);
318 proto_item_set_generated(temp
);
324 static int dissect_mac_fdd_pch(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
326 proto_tree
*pch_tree
= NULL
;
327 proto_item
*channel_type
;
329 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "MAC");
330 col_set_str(pinfo
->cinfo
, COL_INFO
, "PCCH");
334 ti
= proto_tree_add_item(tree
, proto_umts_mac
, tvb
, 0, -1, ENC_NA
);
335 pch_tree
= proto_item_add_subtree(ti
, ett_mac_pch
);
336 proto_item_append_text(ti
, " (PCCH)");
337 channel_type
= proto_tree_add_uint(pch_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_PCCH
);
338 proto_item_set_generated(channel_type
);
340 call_dissector_with_data(rlc_pcch_handle
, tvb
, pinfo
, tree
, data
);
341 return tvb_captured_length(tvb
);
344 static int dissect_mac_fdd_rach(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
348 uint16_t bitoffs
= 0;
350 proto_tree
*rach_tree
= NULL
;
351 proto_item
*channel_type
;
352 umts_mac_info
*macinf
;
355 proto_item
*ti
= NULL
;
357 /* RACH TCTF is always 2 bit */
358 tctf
= tvb_get_bits8(tvb
, 0, 2);
361 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "MAC");
363 col_set_str(pinfo
->cinfo
, COL_INFO
,
364 val_to_str_const(tctf
, rach_fdd_tctf_vals
, "Unknown TCTF"));
366 ti
= proto_tree_add_item(tree
, proto_umts_mac
, tvb
, 0, -1, ENC_NA
);
367 rach_tree
= proto_item_add_subtree(ti
, ett_mac_rach
);
369 macinf
= (umts_mac_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_umts_mac
, 0);
370 fpinf
= (fp_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_fp
, 0);
371 rlcinf
= (rlc_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_umts_rlc
, 0);
372 if (!macinf
|| !fpinf
) {
373 proto_tree_add_expert(rach_tree
, pinfo
, &ei_mac_per_frame_info_missing
, tvb
, 0, -1);
377 proto_tree_add_bits_item(rach_tree
, hf_mac_rach_fdd_tctf
, tvb
, 0, 2, ENC_BIG_ENDIAN
);
378 if (tctf
== TCTF_DCCH_DTCH_RACH_FDD
) {
379 macinf
->ctmux
[fpinf
->cur_tb
] = 1; /* DCCH/DTCH on RACH *always* has a C/T */
380 bitoffs
= tree_add_common_dcch_dtch_fields(tvb
, pinfo
, rach_tree
, bitoffs
, fpinf
, macinf
, rlcinf
);
383 chan
= fpinf
->cur_chan
;
384 /* handoff to next dissector */
386 case TCTF_CCCH_RACH_FDD
:
387 proto_item_append_text(ti
, " (CCCH)");
388 channel_type
= proto_tree_add_uint(rach_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_CCCH
);
389 proto_item_set_generated(channel_type
);
390 next_tvb
= tvb_new_octet_aligned(tvb
, bitoffs
, fpinf
->chan_tf_size
[chan
] - bitoffs
);
391 add_new_data_source(pinfo
, next_tvb
, "Octet-Aligned CCCH Data");
392 call_dissector_with_data(rlc_ccch_handle
, next_tvb
, pinfo
, tree
, data
);
394 case TCTF_DCCH_DTCH_RACH_FDD
:
395 /*Set RLC Mode/MAC content based on the L-CHID derived from the C/T flag*/
396 c_t
= tvb_get_bits8(tvb
,bitoffs
-4,4);
398 /* reserved value, discard PDU */
399 expert_add_info(pinfo
, NULL
, &ei_mac_reserved_c_t
);
402 rlcinf
->mode
[chan
] = lchId_rlc_map
[c_t
+1];
403 macinf
->content
[chan
] = lchId_type_table
[c_t
+1];
404 rlcinf
->rbid
[chan
] = c_t
+1;
405 switch (macinf
->content
[chan
]) {
406 case MAC_CONTENT_DCCH
:
407 proto_item_append_text(ti
, " (DCCH)");
408 channel_type
= proto_tree_add_uint(rach_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_DCCH
);
409 proto_item_set_generated(channel_type
);
410 next_tvb
= tvb_new_octet_aligned(tvb
, bitoffs
, fpinf
->chan_tf_size
[chan
] - bitoffs
);
411 add_new_data_source(pinfo
, next_tvb
, "Octet-Aligned DCCH Data");
412 call_dissector_with_data(rlc_dcch_handle
, next_tvb
, pinfo
, tree
, data
);
414 case MAC_CONTENT_PS_DTCH
:
415 proto_item_append_text(ti
, " (PS DTCH)");
416 channel_type
= proto_tree_add_uint(rach_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_DTCH
);
417 proto_item_set_generated(channel_type
);
418 next_tvb
= tvb_new_octet_aligned(tvb
, bitoffs
, fpinf
->chan_tf_size
[chan
] - bitoffs
);
419 add_new_data_source(pinfo
, next_tvb
, "Octet-Aligned DTCH Data");
420 call_dissector_with_data(rlc_ps_dtch_handle
, next_tvb
, pinfo
, tree
, data
);
422 case MAC_CONTENT_CS_DTCH
:
423 proto_item_append_text(ti
, " (CS DTCH)");
427 proto_item_append_text(ti
, " (Unknown RACH DCCH/DTCH Content)");
428 expert_add_info_format(pinfo
, NULL
, &ei_mac_unknown_content
, "Unknown RACH DCCH/DTCH Content");
432 proto_item_append_text(ti
, " (Unknown RACH TCTF)");
433 expert_add_info_format(pinfo
, NULL
, &ei_mac_rach_tctf_unknown
, "Unknown RACH TCTF");
435 return tvb_captured_length(tvb
);
438 static int dissect_mac_fdd_fach(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
441 uint16_t bitoffs
= 0;
442 uint16_t tctf_len
, chan
;
443 proto_tree
*fach_tree
= NULL
;
444 proto_item
*channel_type
;
446 umts_mac_info
*macinf
;
449 struct rrc_info
*rrcinf
;
450 proto_item
*ti
= NULL
;
452 hdr
= tvb_get_uint8(tvb
, 0);
454 /* get target channel type field */
455 tctf
= fach_fdd_tctf(hdr
, &bitoffs
);
458 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "MAC");
460 col_set_str(pinfo
->cinfo
, COL_INFO
,
461 val_to_str_const(tctf
, fach_fdd_tctf_vals
, "Unknown TCTF"));
463 ti
= proto_tree_add_item(tree
, proto_umts_mac
, tvb
, 0, -1, ENC_NA
);
464 fach_tree
= proto_item_add_subtree(ti
, ett_mac_fach
);
466 macinf
= (umts_mac_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_umts_mac
, 0);
467 fpinf
= (fp_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_fp
, 0);
468 rlcinf
= (rlc_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_umts_rlc
, 0);
470 if (!macinf
|| !fpinf
) {
471 proto_tree_add_expert(fach_tree
, pinfo
, &ei_mac_per_frame_info_missing
, tvb
, 0, -1);
475 proto_tree_add_bits_item(fach_tree
, hf_mac_fach_fdd_tctf
, tvb
, 0, tctf_len
, ENC_BIG_ENDIAN
);
476 if (tctf
== TCTF_DCCH_DTCH_FACH_FDD
) {
477 macinf
->ctmux
[fpinf
->cur_tb
] = 1; /* DCCH/DTCH on FACH *always* has a C/T */
478 bitoffs
= tree_add_common_dcch_dtch_fields(tvb
, pinfo
, fach_tree
, bitoffs
, fpinf
, macinf
, rlcinf
);
481 chan
= fpinf
->cur_chan
;
483 case TCTF_CCCH_FACH_FDD
:
484 proto_item_append_text(ti
, " (CCCH)");
485 channel_type
= proto_tree_add_uint(fach_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_CCCH
);
486 proto_item_set_generated(channel_type
);
487 /* CCCH over FACH is always octet aligned */
488 next_tvb
= tvb_new_subset_remaining(tvb
, 1);
489 call_dissector_with_data(rlc_ccch_handle
, next_tvb
, pinfo
, tree
, data
);
491 case TCTF_DCCH_DTCH_FACH_FDD
:
493 /*Set RLC Mode based on the L-CHID derived from the C/T flag*/
494 c_t
= tvb_get_bits8(tvb
,bitoffs
-4,4);
496 /* reserved value, discard PDU */
497 expert_add_info(pinfo
, NULL
, &ei_mac_reserved_c_t
);
500 rlcinf
->mode
[fpinf
->cur_tb
] = lchId_rlc_map
[c_t
+1];
501 macinf
->content
[fpinf
->cur_tb
] = lchId_type_table
[c_t
+1];
502 switch (macinf
->content
[fpinf
->cur_tb
]) {
504 case MAC_CONTENT_DCCH
:
505 proto_item_append_text(ti
, " (DCCH)");
506 channel_type
= proto_tree_add_uint(fach_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_DCCH
);
507 proto_item_set_generated(channel_type
);
508 next_tvb
= tvb_new_octet_aligned(tvb
, bitoffs
, fpinf
->chan_tf_size
[chan
] - bitoffs
);
509 add_new_data_source(pinfo
, next_tvb
, "Octet-Aligned DCCH Data");
510 call_dissector_with_data(rlc_dcch_handle
, next_tvb
, pinfo
, tree
, data
);
512 case MAC_CONTENT_PS_DTCH
:
513 proto_item_append_text(ti
, " (PS DTCH)");
514 channel_type
= proto_tree_add_uint(fach_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_DTCH
);
515 proto_item_set_generated(channel_type
);
516 next_tvb
= tvb_new_octet_aligned(tvb
, bitoffs
, fpinf
->chan_tf_size
[chan
] - bitoffs
);
517 add_new_data_source(pinfo
, next_tvb
, "Octet-Aligned DCCH Data");
518 call_dissector_with_data(rlc_ps_dtch_handle
, next_tvb
, pinfo
, tree
, data
);
520 case MAC_CONTENT_CS_DTCH
:
521 proto_item_append_text(ti
, " (CS DTCH)");
522 expert_add_info(pinfo
, NULL
, &ei_mac_cs_dtch_not_implemented
);
526 proto_item_append_text(ti
, " (Unknown FACH Content)");
527 expert_add_info_format(pinfo
, NULL
, &ei_mac_unknown_content
, "Unknown FACH Content for this transportblock");
530 case TCTF_CTCH_FACH_FDD
:
531 proto_item_append_text(ti
, " (CTCH)");
532 channel_type
= proto_tree_add_uint(fach_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_CTCH
);
533 proto_item_set_generated(channel_type
);
534 /* CTCH over FACH is always octet aligned */
535 next_tvb
= tvb_new_subset_remaining(tvb
, 1);
536 call_dissector_with_data(rlc_ctch_handle
, next_tvb
, pinfo
, tree
, data
);
538 /* july 5: Added support for BCCH*/
539 case TCTF_BCCH_FACH_FDD
:
540 proto_item_append_text(ti
, " (BCCH)");
541 channel_type
= proto_tree_add_uint(fach_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_BCCH
);
542 proto_item_set_generated(channel_type
);
544 /*We need to skip the first two bits (the TCTF bits), and since there is no MAC header, send rest to RRC*/
545 next_tvb
= tvb_new_octet_aligned(tvb
, 2, (tvb_reported_length(tvb
)*8)-2);
546 add_new_data_source(pinfo
, next_tvb
, "Octet-Aligned BCCH Data");
548 /* In this case skip RLC and call RRC immediately subdissector */
549 rrcinf
= (rrc_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_rrc
, 0);
551 rrcinf
= wmem_new0(wmem_file_scope(), struct rrc_info
);
552 p_add_proto_data(wmem_file_scope(), pinfo
, proto_rrc
, 0, rrcinf
);
554 rrcinf
->msgtype
[fpinf
->cur_tb
] = RRC_MESSAGE_TYPE_BCCH_FACH
;
556 call_dissector_with_data(rrc_handle
, next_tvb
, pinfo
, tree
, data
);
559 case TCTF_MSCH_FACH_FDD
:
560 case TCTF_MCCH_FACH_FDD
:
561 case TCTF_MTCH_FACH_FDD
:
562 expert_add_info(pinfo
, NULL
, &ei_mac_fach_content_type_unknown
);
565 proto_item_append_text(ti
, " (Unknown FACH Content)");
566 expert_add_info_format(pinfo
, NULL
, &ei_mac_unknown_content
, " Unknown FACH Content");
569 return tvb_captured_length(tvb
);
572 static int dissect_mac_fdd_dch(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
576 umts_mac_info
*macinf
;
579 proto_tree
*dch_tree
= NULL
;
580 proto_item
*channel_type
;
582 proto_item
*ti
= NULL
;
584 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "MAC");
586 ti
= proto_tree_add_item(tree
, proto_umts_mac
, tvb
, 0, -1, ENC_NA
);
587 dch_tree
= proto_item_add_subtree(ti
, ett_mac_dch
);
589 macinf
= (umts_mac_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_umts_mac
, 0);
590 fpinf
= (fp_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_fp
, 0);
591 rlcinf
= (rlc_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_umts_rlc
, 0);
593 if (!macinf
|| !fpinf
) {
594 proto_tree_add_expert(dch_tree
, pinfo
, &ei_mac_per_frame_info_missing
, tvb
, 0, -1);
599 if (macinf
->ctmux
[pos
]) {
601 rlcinf
->rbid
[fpinf
->cur_tb
] = tvb_get_bits8(tvb
, bitoffs
, 4)+1;
603 /*Add CT flag to GUI*/
604 proto_tree_add_bits_item(dch_tree
, hf_mac_ct
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
609 next_tvb
= tvb_new_octet_aligned(tvb
, bitoffs
, fpinf
->chan_tf_size
[pos
] - bitoffs
);
610 add_new_data_source(pinfo
, next_tvb
, "Octet-Aligned DCCH Data");
613 switch (macinf
->content
[pos
]) {
614 case MAC_CONTENT_DCCH
:
615 proto_item_append_text(ti
, " (DCCH)");
617 /*Show logical channel id*/
618 channel_type
= proto_tree_add_uint(dch_tree
, hf_mac_lch_id
, tvb
, 0, 0, macinf
->lchid
[pos
]);
619 proto_item_set_generated(channel_type
);
620 if(macinf
->lchid
[pos
]!= 255){
622 if(macinf
->fake_chid
[pos
]){
623 expert_add_info(pinfo
, channel_type
, &ei_mac_faked_logical_channel_id
);
626 expert_add_info(pinfo
, channel_type
, &ei_mac_no_logical_channel
);
629 channel_type
= proto_tree_add_uint(dch_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_DCCH
);
630 proto_item_set_generated(channel_type
);
632 /*Transport channel printout*/
633 channel_type
= proto_tree_add_uint(dch_tree
, hf_mac_trch_id
, tvb
, 0, 0, macinf
->trchid
[pos
]);
634 proto_item_set_generated(channel_type
);
635 call_dissector_with_data(rlc_dcch_handle
, next_tvb
, pinfo
, tree
, data
);
637 case MAC_CONTENT_PS_DTCH
:
638 proto_item_append_text(ti
, " (PS DTCH)");
639 /*Show logical channel id*/
640 channel_type
= proto_tree_add_uint(dch_tree
, hf_mac_lch_id
, tvb
, 0, 0, macinf
->lchid
[pos
]);
641 proto_item_set_generated(channel_type
);
643 if(macinf
->lchid
[pos
]== 255){
644 expert_add_info(pinfo
, channel_type
, &ei_mac_no_logical_channel
);
647 channel_type
= proto_tree_add_uint(dch_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_DTCH
);
648 proto_item_set_generated(channel_type
);
649 call_dissector_with_data(rlc_ps_dtch_handle
, next_tvb
, pinfo
, tree
, data
);
651 case MAC_CONTENT_CS_DTCH
:
652 proto_item_append_text(ti
, " (CS DTCH)");
653 /*Show logical channel id*/
654 channel_type
= proto_tree_add_uint(dch_tree
, hf_mac_lch_id
, tvb
, 0, 0, macinf
->lchid
[pos
]);
655 proto_item_set_generated(channel_type
);
656 if(macinf
->lchid
[pos
]!= 255){
657 if(macinf
->fake_chid
[pos
]){
658 expert_add_info(pinfo
, channel_type
, &ei_mac_faked_logical_channel_id
);
661 expert_add_info(pinfo
, channel_type
, &ei_mac_no_logical_channel
);
664 channel_type
= proto_tree_add_uint(dch_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_DTCH
);
665 proto_item_set_generated(channel_type
);
667 /*Transport channel printout*/
668 channel_type
= proto_tree_add_uint(dch_tree
, hf_mac_trch_id
, tvb
, 0, 0, macinf
->trchid
[pos
]);
669 proto_item_set_generated(channel_type
);
673 proto_item_append_text(ti
, " (Unknown DCH Content)");
674 expert_add_info_format(pinfo
, NULL
, &ei_mac_unknown_content
, "Unknown DCH Content");
676 return tvb_captured_length(tvb
);
679 static void init_frag(tvbuff_t
* tvb
, body_parts
* bp
, unsigned length
, unsigned offset
, uint32_t frame_num
, uint16_t tsn
, uint8_t type
)
681 mac_is_fragment
* frag
= wmem_new(wmem_file_scope(), mac_is_fragment
);
683 frag
->length
= length
;
684 frag
->data
= (uint8_t *)wmem_alloc(wmem_file_scope(), length
);
685 frag
->frame_num
= frame_num
;
690 DISSECTOR_ASSERT(bp
->head
== NULL
);
694 DISSECTOR_ASSERT(bp
->middle
== NULL
);
698 DISSECTOR_ASSERT(bp
->tail
== NULL
);
702 tvb_memcpy(tvb
, frag
->data
, offset
, length
);
705 static void mac_is_copy(mac_is_sdu
* sdu
, mac_is_fragment
* frag
, unsigned total_length
, bool reverse
)
707 DISSECTOR_ASSERT(sdu
->length
+frag
->length
<= total_length
);
709 memcpy(sdu
->data
+total_length
-frag
->length
-sdu
->length
, frag
->data
, frag
->length
);
711 memcpy(sdu
->data
+sdu
->length
, frag
->data
, frag
->length
);
713 sdu
->length
+= frag
->length
;
714 wmem_free(wmem_file_scope(), frag
->data
);
718 * @param length Length of whole SDU, it will be verified.
720 static tvbuff_t
* reassemble(tvbuff_t
* tvb
, body_parts
** body_parts_array
, uint16_t head_tsn
, unsigned length
, mac_is_channel
* ch
, unsigned frame_num
)
727 /* Find frag->sdu hash table for this channel. */
728 sdus
= (GHashTable
*)g_hash_table_lookup(mac_is_sdus
, ch
);
729 /* If this is the first time we see this channel. */
731 mac_is_channel
* channel
;
732 sdus
= g_hash_table_new(mac_is_fragment_hash
, mac_is_fragment_equal
);
733 channel
= wmem_new(wmem_file_scope(), mac_is_channel
);
735 g_hash_table_insert(mac_is_sdus
, channel
, sdus
);
738 sdu
= wmem_new(wmem_file_scope(), mac_is_sdu
);
740 sdu
->data
= (uint8_t *)wmem_alloc(wmem_file_scope(), length
);
742 f
= body_parts_array
[head_tsn
]->head
; /* Start from head. */
743 g_hash_table_insert(sdus
, f
, sdu
); /* Insert head->sdu mapping. */
744 body_parts_array
[head_tsn
]->head
= NULL
; /* Reset head. */
745 mac_is_copy(sdu
, f
, length
, false); /* Copy head data into SDU. */
746 sdu
->fragments
= f
; /* Set up fragments list to point at head. */
747 sdu
->frame_num
= frame_num
; /* Frame number where reassembly is being done. */
749 for (i
= (head_tsn
+1)%MAX_TSN
; body_parts_array
[i
]->middle
!= NULL
; i
= (i
+1)%MAX_TSN
)
751 f
= f
->next
= body_parts_array
[i
]->middle
; /* Iterate through. */
752 g_hash_table_insert(sdus
, f
, sdu
); /* Insert middle->sdu mapping. */
753 body_parts_array
[i
]->middle
= NULL
; /* Reset. */
754 mac_is_copy(sdu
, f
, length
, false); /* Copy middle data into SDU. */
756 DISSECTOR_ASSERT(body_parts_array
[i
]->tail
!= NULL
);
758 f
->next
= body_parts_array
[i
]->tail
;
759 g_hash_table_insert(sdus
, f
->next
, sdu
); /* Insert tail->sdu mapping. */
760 body_parts_array
[i
]->tail
= NULL
; /* Reset tail. */
761 sdu
->tsn
= i
; /* Use TSN of tail as key for the SDU. */
762 mac_is_copy(sdu
, f
->next
, length
, false); /* Copy tail data into SDU. */
764 return tvb_new_child_real_data(tvb
, sdu
->data
, sdu
->length
, sdu
->length
);
767 static mac_is_sdu
* get_sdu(unsigned frame_num
, uint16_t tsn
, uint8_t type
, mac_is_channel
* ch
)
769 mac_is_sdu
* sdu
= NULL
;
770 GHashTable
* sdus
= NULL
;
771 mac_is_fragment frag_lookup_key
;
773 sdus
= (GHashTable
*)g_hash_table_lookup(mac_is_sdus
, ch
);
775 frag_lookup_key
.frame_num
= frame_num
;
776 frag_lookup_key
.tsn
= tsn
;
777 frag_lookup_key
.type
= type
;
778 sdu
= (mac_is_sdu
*)g_hash_table_lookup(sdus
, &frag_lookup_key
);
784 static tvbuff_t
* add_to_tree(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, mac_is_sdu
* sdu
, unsigned offset
, uint16_t maclength
, uint8_t type
)
786 tvbuff_t
* new_tvb
= NULL
;
788 if (sdu
->frame_num
== pinfo
->num
) {
789 mac_is_fragment
* f
= sdu
->fragments
;
790 unsigned counter
= 0;
791 new_tvb
= tvb_new_child_real_data(tvb
, sdu
->data
, sdu
->length
, sdu
->length
);
792 add_new_data_source(pinfo
, new_tvb
, "Reassembled MAC-is SDU");
793 proto_tree_add_expert(tree
, pinfo
, &ei_mac_macis_sdu_reassembled
, new_tvb
, 0, -1);
796 proto_tree_add_uint_format_value(tree
, hf_mac_is_fraglink
, new_tvb
,
797 counter
, f
->length
, f
->frame_num
,
798 "%u, payload: %u-%u (%u bytes) (TSN: %u)",
799 f
->frame_num
, counter
, counter
+f
->length
-1, f
->length
,
801 counter
+= f
->length
;
806 new_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, maclength
, -1);
809 proto_tree_add_expert(tree
, pinfo
, &ei_mac_macis_sdu_first
, new_tvb
, 0, -1);
812 proto_tree_add_expert(tree
, pinfo
, &ei_mac_macis_sdu_middle
, new_tvb
, 0, -1);
815 proto_tree_add_expert(tree
, pinfo
, &ei_mac_macis_sdu_last
, new_tvb
, 0, -1);
818 proto_tree_add_uint(tree
, hf_mac_is_reasmin
, new_tvb
, 0, 0, sdu
->frame_num
);
819 return NULL
; /* No data here. */
824 * If return value > 0 then tsn is changed to be tsn of head.
825 * @return return length of sequence tsn-1 to head.
827 static unsigned find_head(body_parts
** body_parts_array
, uint16_t * tsn
)
830 *tsn
= (*tsn
==0)? (uint16_t)(MAX_TSN
-1) : (*tsn
)-1;
831 for (; body_parts_array
[*tsn
]->middle
!= NULL
; *tsn
= (*tsn
==0)?(uint16_t)(MAX_TSN
-1):(*tsn
)-1)
832 length
+= body_parts_array
[*tsn
]->middle
->length
;
833 if (body_parts_array
[*tsn
]->head
!= NULL
)
834 return length
+body_parts_array
[*tsn
]->head
->length
;
839 * @return return length of sequence tsn+1 to tail.
841 static unsigned find_tail(body_parts
** body_parts_array
, uint16_t tsn
)
844 for (tsn
= (tsn
+1)%MAX_TSN
; body_parts_array
[tsn
]->middle
!= NULL
; tsn
= (tsn
+1)%MAX_TSN
)
845 length
+= body_parts_array
[tsn
]->middle
->length
;
846 if (body_parts_array
[tsn
]->tail
!= NULL
)
847 return length
+body_parts_array
[tsn
]->tail
->length
;
852 * @param ch Channel for which body parts are to be fetched.
853 * @return Array of body_part* for channel 'ch'.
855 static body_parts
** get_body_parts(mac_is_channel
* ch
)
857 body_parts
** bpa
= (body_parts
**)g_hash_table_lookup(mac_is_fragments
, ch
);
858 /* If there was no body_part* array for this channel, create one. */
860 mac_is_channel
* channel
;
862 bpa
= wmem_alloc_array(wmem_file_scope(), body_parts
*, MAX_TSN
); /* Create new body_parts-pointer array */
863 for (i
= 0; i
< MAX_TSN
; i
++) {
864 bpa
[i
] = wmem_new0(wmem_file_scope(), body_parts
); /* Fill it with body_parts. */
866 channel
= wmem_new(wmem_file_scope(), mac_is_channel
); /* Alloc new channel for use in hash table. */
868 g_hash_table_insert(mac_is_fragments
, channel
, bpa
);
873 static tvbuff_t
* mac_is_add_fragment(tvbuff_t
* tvb _U_
, packet_info
*pinfo
, proto_tree
* tree _U_
, uint8_t lchid
, unsigned ueid
, int offset
, uint8_t ss
, uint16_t tsn
, int sdu_no
, uint8_t no_sdus
, uint16_t maclength
)
875 mac_is_channel ch
; /* Channel for looking up in hash tables. */
879 /* If in first scan-through. */
880 if (!PINFO_FD_VISITED(pinfo
)) {
881 /* Get body parts array for this channel. */
882 body_parts
** body_parts_array
= get_body_parts(&ch
);
884 if (no_sdus
== 1 && ss
== 3) {
885 unsigned head_length
, tail_length
;
886 init_frag(tvb
, body_parts_array
[tsn
], maclength
, offset
, pinfo
->num
, tsn
, MAC_IS_MIDDLE
);
887 tail_length
= find_tail(body_parts_array
, tsn
);
888 if (tail_length
> 0) {
889 head_length
= find_head(body_parts_array
, &tsn
);
890 if (head_length
> 0) {
891 /* tsn is now TSN of head */
892 return reassemble(tvb
, body_parts_array
, tsn
, tail_length
+head_length
+maclength
, &ch
, pinfo
->num
);
895 /* XXX: haven't confirmed if case when middle segment comes last
896 * actually works or not. */
898 /* If first SDU is last segment of previous. A tail. */
899 else if (sdu_no
== 0 && (ss
& 1) == 1) {
900 unsigned length
= maclength
;
901 init_frag(tvb
, body_parts_array
[tsn
], maclength
, offset
, pinfo
->num
, tsn
, MAC_IS_TAIL
);
902 length
+= find_head(body_parts_array
, &tsn
);
903 if (length
> maclength
) {
904 /* tsn is now TSN of head */
905 return reassemble(tvb
, body_parts_array
, tsn
, length
, &ch
, pinfo
->num
);
908 /* If last SDU is first segment of next. A head. */
909 else if (sdu_no
== no_sdus
-1 && (ss
& 2) == 2) {
910 unsigned length
= maclength
;
911 init_frag(tvb
, body_parts_array
[tsn
], maclength
, offset
, pinfo
->num
, tsn
, MAC_IS_HEAD
);
912 length
+= find_tail(body_parts_array
, tsn
);
913 if (length
> maclength
) {
914 return reassemble(tvb
, body_parts_array
, tsn
, length
, &ch
, pinfo
->num
);
916 /* If our SDU is not fragmented. */
918 DISSECTOR_ASSERT((sdu_no
== 0) ? (ss
&1) == 0 : ((sdu_no
== no_sdus
-1) ? (ss
&2) == 0 : true));
919 return tvb_new_subset_length_caplen(tvb
, offset
, maclength
, -1);
921 /* If clicking on a packet. */
923 tvbuff_t
* new_tvb
= NULL
;
925 if (no_sdus
== 1 && ss
== 3) {
926 mac_is_sdu
* sdu
= get_sdu(pinfo
->num
, tsn
, MAC_IS_MIDDLE
, &ch
);
928 return add_to_tree(tvb
, pinfo
, tree
, sdu
, offset
, maclength
, MAC_IS_MIDDLE
);
931 /* If first SDU is last segment of previous. A tail. */
932 else if (sdu_no
== 0 && (ss
& 1) == 1) {
933 mac_is_sdu
* sdu
= get_sdu(pinfo
->num
, tsn
, MAC_IS_TAIL
, &ch
);
935 return add_to_tree(tvb
, pinfo
, tree
, sdu
, offset
, maclength
, MAC_IS_TAIL
);
938 /* If last SDU is first segment of next. A head. */
939 else if (sdu_no
== no_sdus
-1 && (ss
& 2) == 2) {
940 mac_is_sdu
* sdu
= get_sdu(pinfo
->num
, tsn
, MAC_IS_HEAD
, &ch
);
942 return add_to_tree(tvb
, pinfo
, tree
, sdu
, offset
, maclength
, MAC_IS_HEAD
);
945 new_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, maclength
, -1);
946 proto_tree_add_expert(tree
, pinfo
, &ei_mac_macis_sdu_complete
, new_tvb
, 0, -1);
947 proto_tree_add_item(tree
, hf_mac_edch_type2_sdu_data
, new_tvb
, 0, -1, ENC_NA
);
954 static void ss_interpretation(tvbuff_t
* tvb
, proto_tree
* tree
, uint8_t ss
, unsigned number_of_mac_is_sdus
, unsigned offset
)
958 if (number_of_mac_is_sdus
> 1) {
959 proto_tree_add_uint_format_value(tree
, hf_mac_edch_type2_ss_interpretation
, tvb
, offset
, 1, ss
,
960 "The first MAC-is SDU of the MAC-is PDU is a complete MAC-d PDU or MAC-c PDU. The last MAC-is SDU of the MAC-is PDU is a complete MAC-d PDU or MAC-c PDU.");
962 proto_tree_add_uint_format_value(tree
, hf_mac_edch_type2_ss_interpretation
, tvb
, offset
, 1, ss
,
963 "The MAC-is SDU of the MAC-is PDU is a complete MAC-d PDU or MAC-c PDU.");
967 if (number_of_mac_is_sdus
> 1) {
968 proto_tree_add_uint_format_value(tree
, hf_mac_edch_type2_ss_interpretation
, tvb
, offset
, 1, ss
,
969 "The last MAC-is SDU of the MAC-is PDU is a complete MAC-d PDU or MAC-c PDU. The first MAC-is SDU of the MAC-is PDU is the last segment of a MAC-d PDU or MAC-c PDU.");
971 proto_tree_add_uint_format_value(tree
, hf_mac_edch_type2_ss_interpretation
, tvb
, offset
, 1, ss
,
972 "The MAC-is SDU of the MAC-is PDU is the last segment of a MAC-d PDU or MAC-c PDU.");
976 if (number_of_mac_is_sdus
> 1) {
977 proto_tree_add_uint_format_value(tree
, hf_mac_edch_type2_ss_interpretation
, tvb
, offset
, 1, ss
,
978 "The first MAC-is SDU of the MAC-is PDU is a complete MAC-d PDU or MAC-c PDU. The last MAC-is SDU of the MAC-is PDU is the first segment of a MAC-d PDU or MAC-c PDU.");
980 proto_tree_add_uint_format_value(tree
, hf_mac_edch_type2_ss_interpretation
, tvb
, offset
, 1, ss
,
981 "The MAC-is SDU of the MAC-is PDU is the first segment of a MAC-d PDU or MAC-c PDU.");
985 if (number_of_mac_is_sdus
> 1) {
986 proto_tree_add_uint_format_value(tree
, hf_mac_edch_type2_ss_interpretation
, tvb
, offset
, 1, ss
,
987 "The first MAC-is SDU of the MAC-is PDU is the last segment of a MAC-d PDU or MAC-c PDU and the last MAC-is SDU of MAC-is PDU is the first segment of a MAC-d PDU or MAC-c PDU.");
989 proto_tree_add_uint_format_value(tree
, hf_mac_edch_type2_ss_interpretation
, tvb
, offset
, 1, ss
,
990 "The MAC-is SDU is a middle segment of a MAC-d PDU or MAC-c PDU.");
996 static void call_rlc(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, proto_item
* ti
, uint8_t lchid
, void *data
)
998 switch (lchId_type_table
[lchid
]) {
999 case MAC_CONTENT_DCCH
:
1000 proto_item_append_text(ti
, " (DCCH)");
1001 call_dissector_with_data(rlc_dcch_handle
, tvb
, pinfo
, tree
, data
);
1003 case MAC_CONTENT_PS_DTCH
:
1004 proto_item_append_text(ti
, " (PS DTCH)");
1005 call_dissector_with_data(rlc_ps_dtch_handle
, tvb
, pinfo
, tree
, data
);
1007 case MAC_CONTENT_CS_DTCH
:
1008 proto_item_append_text(ti
, " (CS DTCH)");
1012 proto_item_append_text(ti
, " (Unknown EDCH Content)");
1013 expert_add_info_format(pinfo
, ti
, &ei_mac_unknown_content
, "Unknown EDCH Content");
1019 * Dissect a MAC-is PDU.
1021 static int dissect_mac_fdd_edch_type2(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
1023 unsigned sdu_no
, subframe_bytes
= 0, offset
= 0;
1026 proto_item
*pi
, *temp
;
1027 proto_tree
*macis_pdu_tree
, *macis_sdu_tree
;
1028 umts_mac_is_info
* mac_is_info
= (umts_mac_is_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_umts_mac
, 0);
1029 rlc_info
* rlcinf
= (rlc_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_umts_rlc
, 0);
1030 struct fp_info
*p_fp_info
= (struct fp_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_fp
, 0);
1032 DISSECTOR_ASSERT(mac_is_info
!= NULL
&& rlcinf
!= NULL
&& p_fp_info
!= NULL
);
1034 pi
= proto_tree_add_item(tree
, proto_umts_mac
, tvb
, 0, -1, ENC_NA
);
1035 macis_pdu_tree
= proto_item_add_subtree(pi
, ett_mac_edch_type2
);
1038 ss
= (tvb_get_uint8(tvb
, offset
) & 0xc0) >> 6;
1039 proto_tree_add_item(macis_pdu_tree
, hf_mac_edch_type2_ss
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1041 ss_interpretation(tvb
, macis_pdu_tree
, ss
, mac_is_info
->number_of_mac_is_sdus
, offset
);
1044 tsn
= tvb_get_bits8(tvb
, offset
*8+2, mac_tsn_size
);
1045 proto_tree_add_bits_item(macis_pdu_tree
, hf_mac_edch_type2_tsn
, tvb
, offset
*8+2, mac_tsn_size
, ENC_BIG_ENDIAN
);
1047 offset
+= (2+mac_tsn_size
)/8;
1049 /* MAC-is SDUs (i.e. MACd PDUs) */
1050 for (sdu_no
=0; sdu_no
< mac_is_info
->number_of_mac_is_sdus
; sdu_no
++) {
1053 uint8_t lchid
= mac_is_info
->lchid
[sdu_no
]+1;
1054 unsigned sdulength
= mac_is_info
->sdulength
[sdu_no
];
1056 ti
= proto_tree_add_item(tree
, hf_mac_edch_type2_sdu
, tvb
, offset
, sdulength
, ENC_NA
);
1057 macis_sdu_tree
= proto_item_add_subtree(ti
, ett_mac_edch_type2_sdu
);
1058 proto_item_append_text(ti
, " (Logical channel=%u, Len=%u)", lchid
, sdulength
);
1059 temp
= proto_tree_add_uint(ti
, hf_mac_lch_id
, tvb
, 0, 0, lchid
);
1060 proto_item_set_generated(temp
);
1061 /*Set up information needed for MAC and lower layers*/
1062 rlcinf
->mode
[sdu_no
] = lchId_rlc_map
[lchid
]; /* Set RLC mode by lchid to RLC_MODE map in nbap.h */
1063 rlcinf
->ueid
[sdu_no
] = p_fp_info
->com_context_id
;
1064 rlcinf
->rbid
[sdu_no
] = lchid
;
1065 rlcinf
->li_size
[sdu_no
] = RLC_LI_7BITS
;
1066 rlcinf
->ciphered
[sdu_no
] = false;
1067 rlcinf
->deciphered
[sdu_no
] = false;
1069 asm_tvb
= mac_is_add_fragment(tvb
, pinfo
, macis_sdu_tree
, lchid
, p_fp_info
->com_context_id
, offset
, ss
, tsn
, sdu_no
, mac_is_info
->number_of_mac_is_sdus
, sdulength
);
1070 if (asm_tvb
!= NULL
) {
1071 call_rlc(asm_tvb
, pinfo
, tree
, ti
, lchid
, data
);
1074 offset
+= sdulength
;
1075 subframe_bytes
+= sdulength
;
1078 proto_item_append_text(pi
, "-is PDU (SS=%u, TSN=%u, %u bytes in %u SDU fragments)",
1079 ss
, tsn
, subframe_bytes
, mac_is_info
->number_of_mac_is_sdus
);
1081 proto_item_set_len(pi
, 1+subframe_bytes
);
1082 /*total_bytes += subframe_bytes;*/
1083 return tvb_captured_length(tvb
);
1086 static int dissect_mac_fdd_edch(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
1088 proto_tree
*edch_tree
= NULL
;
1089 proto_item
*channel_type
;
1090 umts_mac_info
*macinf
;
1093 proto_item
*ti
= NULL
;
1095 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "MAC");
1097 ti
= proto_tree_add_item(tree
, proto_umts_mac
, tvb
, 0, -1, ENC_NA
);
1098 edch_tree
= proto_item_add_subtree(ti
, ett_mac_edch
);
1100 fpinf
= (fp_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_fp
, 0);
1102 macinf
= (umts_mac_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_umts_mac
, 0);
1103 if (!macinf
|| !fpinf
) {
1104 proto_tree_add_expert(edch_tree
, pinfo
, &ei_mac_per_frame_info_missing
, tvb
, 0, -1);
1108 pos
= fpinf
->cur_tb
;
1110 switch (macinf
->content
[pos
]) {
1111 case MAC_CONTENT_DCCH
:
1112 proto_item_append_text(ti
, " (DCCH)");
1114 /*Show the logical channel id*/
1115 channel_type
= proto_tree_add_uint(edch_tree
, hf_mac_lch_id
, tvb
, 0, 0, macinf
->lchid
[pos
]);
1116 proto_item_set_generated(channel_type
);
1118 channel_type
= proto_tree_add_uint(edch_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_DCCH
);
1119 proto_item_set_generated(channel_type
);
1122 call_dissector_with_data(rlc_dcch_handle
, tvb
, pinfo
, tree
, data
);
1124 case MAC_CONTENT_PS_DTCH
:
1125 proto_item_append_text(ti
, " (PS DTCH)");
1127 /*Show the logical channel id*/
1128 channel_type
= proto_tree_add_uint(edch_tree
, hf_mac_lch_id
, tvb
, 0, 0, macinf
->lchid
[pos
]);
1129 proto_item_set_generated(channel_type
);
1131 channel_type
= proto_tree_add_uint(edch_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_DTCH
);
1132 proto_item_set_generated(channel_type
);
1134 call_dissector_with_data(rlc_ps_dtch_handle
, tvb
, pinfo
, tree
, data
);
1136 case MAC_CONTENT_CS_DTCH
:
1137 proto_item_append_text(ti
, " (CS DTCH)");
1141 proto_item_append_text(ti
, " (Unknown EDCH Content)");
1142 expert_add_info_format(pinfo
, ti
, &ei_mac_unknown_content
, "Unknown EDCH Content");
1145 return tvb_captured_length(tvb
);
1148 * Dissect hsdsch_common channel.
1150 * This will dissect hsdsch common channels, we handle this separately
1151 * since we might have to deal with MAC-ehs and or MAC-c headers
1160 static void dissect_mac_fdd_hsdsch_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
1162 proto_tree
*hsdsch_tree
= NULL
;
1163 /*proto_item *channel_type;
1166 umts_mac_info
*macinf
;
1168 /* uint8_t bitoffs=0;
1171 proto_item
*ti
= NULL
;
1173 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "MAC");
1175 ti
= proto_tree_add_item(tree
, proto_umts_mac
, tvb
, 0, -1, ENC_NA
);
1176 hsdsch_tree
= proto_item_add_subtree(ti
, ett_mac_hsdsch
);
1178 fpinf
= (fp_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_fp
, 0);
1179 macinf
= (umts_mac_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_umts_mac
);
1182 proto_tree_add_expert(hsdsch_tree
, pinfo
, &ei_mac_per_frame_info_missing
, tvb
, 0, -1);
1185 pos
= fpinf
->cur_tb
;
1186 switch(macinf
->content
[pos
]){
1187 /*In this case we don't have a MAC-c header 9.2.1.4*/
1190 case MAC_CONTENT_CCCH
:
1193 case MAC_CONTENT_PCCH
:
1197 case MAC_CONTENT_BCCH
:
1203 proto_item_append_text(ti
, " (Unknown HSDSCH-Common Content)");
1204 expert_add_info_format(pinfo
, NULL
, &ei_mac_unknown_content
, "Unknown HSDSCH-Common Content");
1210 /* to avoid unnecessary re-alignment, the 4 bit padding prepended to the HSDSCH in FP type 1
1211 * are handled in the MAC layer
1212 * If the C/T field is present, 'bitoffs' will be 8 (4 bit padding and 4 bit C/T) and
1213 * no re-alignment is necessary
1214 * If no C/T is present, the whole payload will be left-shifted by 4 bit
1216 static int dissect_mac_fdd_hsdsch(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
1218 proto_tree
*hsdsch_tree
= NULL
;
1219 proto_item
*channel_type
;
1221 umts_mac_info
*macinf
;
1225 proto_item
*ti
= NULL
;
1228 /*struct rrc_info *rrcinf = NULL;
1230 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "MAC");
1232 ti
= proto_tree_add_item(tree
, proto_umts_mac
, tvb
, 0, -1, ENC_NA
);
1233 hsdsch_tree
= proto_item_add_subtree(ti
, ett_mac_hsdsch
);
1235 fpinf
= (fp_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_fp
, 0);
1236 macinf
= (umts_mac_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_umts_mac
, 0);
1238 pos
= fpinf
->cur_tb
;
1239 bitoffs
= fpinf
->hsdsch_entity
== ehs
? 0 : 4; /*No MAC-d header for type 2*/
1242 proto_tree_add_expert(hsdsch_tree
, pinfo
, &ei_mac_per_frame_info_missing
, tvb
, 0, -1);
1245 if (macinf
->ctmux
[pos
]) { /*The 4'st bits are padding*/
1246 proto_tree_add_bits_item(hsdsch_tree
, hf_mac_ct
, tvb
, bitoffs
, 4, ENC_BIG_ENDIAN
);
1248 /*Sets the proper lchid, for later layers.*/
1249 macinf
->lchid
[pos
] = tvb_get_bits8(tvb
,bitoffs
,4)+1;
1250 macinf
->fake_chid
[pos
] = false;
1251 macinf
->content
[pos
] = lchId_type_table
[macinf
->lchid
[pos
]]; /*Lookup MAC content*/
1253 rlcinf
= (rlc_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_umts_rlc
, 0);
1254 rlcinf
->rbid
[pos
] = macinf
->lchid
[pos
];
1255 rlcinf
->mode
[pos
] = lchId_rlc_map
[macinf
->lchid
[pos
]]; /*Look up RLC mode*/
1259 if ((bitoffs
% 8) == 0) {
1260 next_tvb
= tvb_new_subset_remaining(tvb
, bitoffs
/8);
1262 next_tvb
= tvb_new_octet_aligned(tvb
, bitoffs
, macinf
->pdu_len
); /*Get rid of possible padding in at the end?*/
1263 add_new_data_source(pinfo
, next_tvb
, "Octet-Aligned HSDSCH Data");
1266 switch (macinf
->content
[pos
]) {
1267 case MAC_CONTENT_CCCH
:
1268 proto_item_append_text(ti
, " (CCCH)");
1269 /*Set the logical channel id if it exists */
1270 channel_type
= proto_tree_add_uint(hsdsch_tree
, hf_mac_lch_id
, tvb
, 0, 0, macinf
->lchid
[pos
]);
1271 proto_item_set_generated(channel_type
);
1272 if(macinf
->lchid
[pos
] != 255){
1273 if(macinf
->fake_chid
[pos
]){
1274 expert_add_info(pinfo
, channel_type
, &ei_mac_faked_logical_channel_id
);
1277 expert_add_info(pinfo
, channel_type
, &ei_mac_no_logical_channel
);
1279 /*Set the type of channel*/
1280 channel_type
= proto_tree_add_uint(hsdsch_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_DCCH
);
1281 proto_item_set_generated(channel_type
);
1283 /*Set the MACd-Flow ID*/
1284 channel_type
= proto_tree_add_uint(hsdsch_tree
, hf_mac_macdflowd_id
, tvb
, 0, 0, macinf
->macdflow_id
[pos
]);
1285 proto_item_set_generated(channel_type
);
1286 call_dissector_with_data(rlc_ccch_handle
, next_tvb
, pinfo
, tree
, data
);
1288 case MAC_CONTENT_DCCH
:
1289 proto_item_append_text(ti
, " (DCCH)");
1290 /* channel_type = proto_tree_add_uint(hsdsch_tree, hf_mac_channel_hsdsch, tvb, 0, 0, MAC_DCCH);
1291 proto_item_set_generated(channel_type)*/
1292 /*Set the logical channel id if it exists */
1293 channel_type
= proto_tree_add_uint(hsdsch_tree
, hf_mac_lch_id
, tvb
, 0, 0, macinf
->lchid
[pos
]);
1294 proto_item_set_generated(channel_type
);
1295 if(macinf
->lchid
[pos
] != 255){
1296 if(macinf
->fake_chid
[pos
]){
1297 expert_add_info(pinfo
, channel_type
, &ei_mac_faked_logical_channel_id
);
1300 expert_add_info(pinfo
, channel_type
, &ei_mac_no_logical_channel
);
1303 /*Set the type of channel*/
1304 channel_type
= proto_tree_add_uint(hsdsch_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_DCCH
);
1306 proto_item_set_generated(channel_type
);
1308 /*Set the MACd-Flow ID*/
1309 channel_type
= proto_tree_add_uint(hsdsch_tree
, hf_mac_macdflowd_id
, tvb
, 0, 0, macinf
->macdflow_id
[pos
]);
1310 proto_item_set_generated(channel_type
);
1311 call_dissector_with_data(rlc_dcch_handle
, next_tvb
, pinfo
, tree
, data
);
1313 case MAC_CONTENT_PS_DTCH
:
1314 proto_item_append_text(ti
, " (PS DTCH)");
1316 /*Set the logical channel id if it exists */
1317 channel_type
= proto_tree_add_uint(hsdsch_tree
, hf_mac_lch_id
, tvb
, 0, 0, macinf
->lchid
[pos
]);
1318 proto_item_set_generated(channel_type
);
1319 if(macinf
->lchid
[pos
] != 255){
1320 if(macinf
->fake_chid
[pos
]){
1321 expert_add_info(pinfo
, channel_type
, &ei_mac_faked_logical_channel_id
);
1324 expert_add_info(pinfo
, channel_type
, &ei_mac_no_logical_channel
);
1327 /*Sets the channel type*/
1328 channel_type
= proto_tree_add_uint(hsdsch_tree
, hf_mac_channel
, tvb
, 0, 0, MAC_DTCH
);
1330 proto_item_set_generated(channel_type
);
1332 /*Set the MACd-Flow ID*/
1333 channel_type
= proto_tree_add_uint(hsdsch_tree
, hf_mac_macdflowd_id
, tvb
, 0, 0, macinf
->macdflow_id
[pos
]);
1334 proto_item_set_generated(channel_type
);
1336 call_dissector_with_data(rlc_ps_dtch_handle
, next_tvb
, pinfo
, tree
, data
);
1338 case MAC_CONTENT_CS_DTCH
:
1339 proto_item_append_text(ti
, " (CS DTCH)");
1342 proto_item_append_text(ti
, " (Unknown HSDSCH Content)");
1343 expert_add_info_format(pinfo
, NULL
, &ei_mac_unknown_content
, "Unknown HSDSCH Content");
1345 return tvb_captured_length(tvb
);
1348 static void mac_is_sdus_hash_destroy(void *data
)
1350 g_hash_table_destroy((GHashTable
*)data
);
1353 static void mac_init(void)
1355 mac_is_sdus
= g_hash_table_new_full(mac_is_channel_hash
, mac_is_channel_equal
, NULL
, mac_is_sdus_hash_destroy
);
1356 mac_is_fragments
= g_hash_table_new_full(mac_is_channel_hash
, mac_is_channel_equal
, NULL
, NULL
);
1357 if (global_mac_tsn_size
== MAC_TSN_6BITS
) {
1366 static void mac_cleanup(void)
1368 g_hash_table_destroy(mac_is_sdus
);
1369 g_hash_table_destroy(mac_is_fragments
);
1373 proto_register_umts_mac(void)
1375 module_t
*mac_module
;
1376 static int *ett
[] = {
1384 &ett_mac_edch_type2
,
1385 &ett_mac_edch_type2_sdu
,
1386 &ett_mac_resolved_urnti
1388 /** XX: Looks like some duplicate filter names ?? **/
1389 /** XX: May be OK: See doc/README.developer **/
1390 static hf_register_info hf
[] = {
1391 { &hf_mac_rach_fdd_tctf
,
1392 { "Target Channel Type Field", "mac.tctf",
1393 FT_UINT8
, BASE_HEX
, VALS(rach_fdd_tctf_vals
), 0, NULL
, HFILL
}
1395 { &hf_mac_fach_fdd_tctf
,
1396 { "Target Channel Type Field", "mac.tctf",
1397 FT_UINT8
, BASE_HEX
, VALS(fach_fdd_tctf_vals
), 0, NULL
, HFILL
}
1401 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
1403 { &hf_mac_ueid_type
,
1404 { "UEID Type", "mac.ueid_type",
1405 FT_UINT8
, BASE_DEC
, VALS(ueid_type_vals
), 0, NULL
, HFILL
}
1408 { "C-RNTI (UEID)", "mac.ueid",
1409 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
1412 { "U-RNTI (UEID)", "mac.ueid",
1413 FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
1415 { &hf_mac_resolved_urnti
,
1416 { "Resolved U-RNTI", "mac.resolved_urnti",
1417 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
1418 "The U-RNTI of the UE which is using the C-RNTI seen in this frame",
1421 { &hf_mac_crnti_urnti_match_frame
,
1422 { "C-RNTI Allocation Frame", "mac.crnti_urnti_match_frame",
1423 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1424 "The frame number where the C-RNTI was allocated for the UE",
1428 { "Logical Channel Type", "mac.logical_channel",
1429 FT_UINT16
, BASE_DEC
, VALS(mac_logical_channel_vals
), 0, NULL
, HFILL
}
1433 { &hf_mac_channel_str
,
1434 { "Logical Channel", "mac.logical_channel",
1435 FT_STRING
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
1439 { &hf_mac_channel_hsdsch
,
1440 { "MACd-FlowID", "mac.macd_flowid", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1443 { &hf_mac_macdflowd_id
,
1444 { "MACd-FlowID", "mac.macd_flowid", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1447 { "Logical Channel ID", "mac.logical_channel_id", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1450 { "Transport Channel ID", "mac.transport_channel_id", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1453 { &hf_mac_edch_type2_descriptors
,
1454 { "MAC-is Descriptors",
1455 "mac.edch.type2.descriptors", FT_STRING
, BASE_NONE
, NULL
, 0x0,
1461 { &hf_mac_edch_type2_lchid
,
1463 "mac.logical_channel_id", FT_UINT8
, BASE_HEX
, NULL
, 0xf0,
1469 { &hf_mac_edch_type2_length
,
1471 "mac.edch.type2.length", FT_UINT16
, BASE_DEC
, NULL
, 0x0ffe,
1477 { &hf_mac_edch_type2_flag
,
1479 "mac.edch.type2.lchid", FT_UINT8
, BASE_HEX
, NULL
, 0x01,
1480 "Indicates if another entry follows", HFILL
1484 { &hf_mac_edch_type2_ss
,
1487 "mac.edch.type2.ss", FT_UINT8
, BASE_HEX
, NULL
, 0xc0,
1488 "Segmentation Status", HFILL
1491 { &hf_mac_edch_type2_ss_interpretation
,
1492 { "SS interpretation",
1493 "mac.edch.type2.ss_interpretation", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1497 { &hf_mac_edch_type2_tsn
,
1499 "mac.edch.type2.tsn", FT_UINT16
, BASE_DEC
, NULL
, 0,
1500 "Transmission Sequence Number", HFILL
1503 { &hf_mac_edch_type2_sdu
,
1505 "mac.edch.type2.sdu", FT_NONE
, BASE_NONE
, NULL
, 0x0,
1509 { &hf_mac_edch_type2_sdu_data
,
1511 "mac.edch.type2.sdu.data", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1516 { &hf_mac_edch_type2_subframe_header
,
1517 { "Subframe header",
1518 "mac.edch.type2.subframeheader", FT_STRING
, BASE_NONE
, NULL
, 0x0,
1519 "EDCH Subframe header", HFILL
1523 { &hf_mac_is_reasmin
,
1524 { "Reassembled in frame", "mac.is.reasmin",
1525 FT_FRAMENUM
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
1527 { &hf_mac_is_fraglink
,
1528 { "Frame", "mac.is.fraglink",
1529 FT_FRAMENUM
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
1533 static ei_register_info ei
[] = {
1534 { &ei_mac_per_frame_info_missing
, { "mac.per_frame_info_missing", PI_MALFORMED
, PI_ERROR
, "Cannot dissect MAC frame because per-frame info is missing", EXPFILL
}},
1535 { &ei_mac_unknown_content
, { "mac.unknown_content", PI_MALFORMED
, PI_ERROR
, "Unknown RACH DCCH/DTCH Content", EXPFILL
}},
1536 { &ei_mac_rach_tctf_unknown
, { "mac.rach_tctf.unknown", PI_MALFORMED
, PI_ERROR
, "Unknown RACH TCTF", EXPFILL
}},
1537 { &ei_mac_cs_dtch_not_implemented
, { "mac.cs_dtch.not_implemented", PI_DEBUG
, PI_ERROR
, "CS DTCH Is not implemented", EXPFILL
}},
1538 { &ei_mac_fach_content_type_unknown
, { "mac.fach_content_type.unknown", PI_UNDECODED
, PI_WARN
, "Unimplemented FACH Content type!", EXPFILL
}},
1539 { &ei_mac_no_logical_channel
, { "mac.no_logical_channel", PI_PROTOCOL
, PI_WARN
, "Frame is missing logical channel", EXPFILL
}},
1540 { &ei_mac_faked_logical_channel_id
, { "mac.faked_logical_channel_id", PI_PROTOCOL
, PI_WARN
, "This is a faked logical channel id!", EXPFILL
}},
1541 { &ei_mac_macis_sdu_reassembled
, { "mac.macis_sdu.reassembled", PI_REASSEMBLE
, PI_CHAT
, "Reassembled MAC-is SDU", EXPFILL
}},
1542 { &ei_mac_macis_sdu_first
, { "mac.macis_sdu.first", PI_REASSEMBLE
, PI_CHAT
, "This MAC-is SDU is the first segment of a MAC-d PDU or MAC-c PDU", EXPFILL
}},
1543 { &ei_mac_macis_sdu_middle
, { "mac.macis_sdu.middle", PI_REASSEMBLE
, PI_CHAT
, "This MAC-is SDU is a middle segment of a MAC-d PDU or MAC-c PDU", EXPFILL
}},
1544 { &ei_mac_macis_sdu_last
, { "mac.macis_sdu.last", PI_REASSEMBLE
, PI_CHAT
, "This MAC-is SDU is the last segment of a MAC-d PDU or MAC-c PDU", EXPFILL
}},
1545 { &ei_mac_macis_sdu_complete
, { "mac.macis_sdu.complete", PI_REASSEMBLE
, PI_CHAT
, "This MAC-is SDU is a complete MAC-d PDU or MAC-c PDU", EXPFILL
}},
1546 { &ei_mac_reserved_c_t
, { "mac.reserved_ct", PI_PROTOCOL
, PI_WARN
, "C/T has a reserved value, PDU is discarded", EXPFILL
}}
1549 expert_module_t
* expert_umts_mac
;
1551 proto_umts_mac
= proto_register_protocol("MAC", "MAC", "mac");
1552 proto_register_field_array(proto_umts_mac
, hf
, array_length(hf
));
1553 proto_register_subtree_array(ett
, array_length(ett
));
1554 expert_umts_mac
= expert_register_protocol(proto_umts_mac
);
1555 expert_register_field_array(expert_umts_mac
, ei
, array_length(ei
));
1557 register_dissector("mac.fdd.rach", dissect_mac_fdd_rach
, proto_umts_mac
);
1558 register_dissector("mac.fdd.fach", dissect_mac_fdd_fach
, proto_umts_mac
);
1559 register_dissector("mac.fdd.pch", dissect_mac_fdd_pch
, proto_umts_mac
);
1560 register_dissector("mac.fdd.dch", dissect_mac_fdd_dch
, proto_umts_mac
);
1561 register_dissector("mac.fdd.edch", dissect_mac_fdd_edch
, proto_umts_mac
);
1562 register_dissector("mac.fdd.edch.type2", dissect_mac_fdd_edch_type2
, proto_umts_mac
);
1563 register_dissector("mac.fdd.hsdsch", dissect_mac_fdd_hsdsch
, proto_umts_mac
);
1565 register_init_routine(mac_init
);
1566 register_cleanup_routine(mac_cleanup
);
1569 mac_module
= prefs_register_protocol(proto_umts_mac
, NULL
);
1570 prefs_register_enum_preference(mac_module
, "tsn_size", "TSN size",
1571 "TSN size in bits, either 6 or 14 bit",
1572 &global_mac_tsn_size
, tsn_size_enumvals
, false);
1576 proto_reg_handoff_umts_mac(void)
1578 rlc_pcch_handle
= find_dissector_add_dependency("rlc.pcch", proto_umts_mac
);
1579 rlc_ccch_handle
= find_dissector_add_dependency("rlc.ccch", proto_umts_mac
);
1580 rlc_ctch_handle
= find_dissector_add_dependency("rlc.ctch", proto_umts_mac
);
1581 rlc_dcch_handle
= find_dissector_add_dependency("rlc.dcch", proto_umts_mac
);
1582 rlc_ps_dtch_handle
= find_dissector_add_dependency("rlc.ps_dtch", proto_umts_mac
);
1584 rrc_handle
= find_dissector_add_dependency("rrc", proto_umts_mac
);
1588 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1593 * indent-tabs-mode: nil
1596 * vi: set shiftwidth=4 tabstop=8 expandtab:
1597 * :indentSize=4:tabSize=8:noTabs=true: