]> git.samba.org - metze/wireshark/wip.git/blob - epan/dissectors/packet-a21.c
GSM A DTAP: add UMTS EVS to supported codecs list IE
[metze/wireshark/wip.git] / epan / dissectors / packet-a21.c
1 /* packet-a21.c
2  *
3  * Routines for A21/s102 Message dissection
4  * Copyright 2012, Joseph Chai <chaienzhao@gmail.com>
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * SPDX-License-Identifier: GPL-2.0-or-later
11  *
12  * Ref: 3GPP2 A.S0008-C v4.0
13  */
14
15 #include "config.h"
16
17 #include <epan/packet.h>
18 #include <epan/expert.h>
19
20 #include "packet-e212.h"
21 #include "packet-a21.h"
22
23 void proto_register_a21(void);
24 void proto_reg_handoff_a21(void);
25
26 #define A21_PORT 23272
27 static dissector_handle_t gcsna_handle = NULL;
28
29 static int proto_a21 = -1;
30
31 static int hf_a21_message_type = -1;
32 static int hf_a21_corr_id = -1;
33 static int hf_a21_element_identifier = -1;
34 static int hf_a21_element_length = -1;
35 static int hf_a21_corr_id_corr_value = -1;
36 static int hf_a21_mn_id_msid_value = -1;
37 static int hf_a21_mn_id_odd_even_indicator = -1;
38 static int hf_a21_mn_id_type_of_identity = -1;
39 static int hf_a21_mn_id_esn = -1;
40 static int hf_a21_mn_id_identity_digit_1 = -1;
41 static int hf_a21_gcsna_pdu_length = -1;
42 static int hf_a21_gcsna_content = -1;
43 static int hf_a21_reference_cell_id_cell = -1;
44 static int hf_a21_reference_cell_id_sector = -1;
45 static int hf_a21_mob_sub_info_record_id = -1;
46 static int hf_a21_mob_sub_info_record_length = -1;
47 static int hf_a21_mob_sub_info_record_content = -1;
48 static int hf_a21_mob_sub_info_re_con_all_band_inc = -1;
49 static int hf_a21_mob_sub_info_re_con_curr_band_sub = -1;
50 static int hf_a21_mob_sub_info_re_band_class = -1;
51 static int hf_a21_mob_sub_info_re_con_all_sub_band_inc = -1;
52 static int hf_a21_mob_sub_info_re_sub_cls_len = -1;
53 /*
54 static int hf_a21_mob_sub_info_re_con_band_class = -1;
55 */
56 static int hf_a21_auth_chall_para_rand_num_type = -1;
57 static int hf_a21_auth_chall_para_rand_value = -1;
58 static int hf_a21_service_option = -1;
59 static int hf_a21_gcsna_status_reserved = -1;
60 static int hf_a21_gcsna_status_priority_incl = -1;
61 static int hf_a21_gcsna_status_gec = -1;
62 static int hf_a21_gcsna_status_status_incl = -1;
63 static int hf_a21_gcsna_status = -1;
64 static int hf_a21_gcsna_status_call_priority = -1;
65 static int hf_a21_3G1X_parameters = -1;
66 static int hf_a21_reserved = -1;
67 static int hf_a21_msg_tran_ctrl_paging_msg = -1;
68 static int hf_a21_msg_tran_ctrl_simul_xmit_with_next = -1;
69 static int hf_a21_msg_tran_ctrl_ackrequired = -1;
70 static int hf_a21_msg_tran_ctrl_3GXLogicalChannel = -1;
71 static int hf_a21_msg_tran_ctrl_protocol_revision = -1;
72 static int hf_a21_1x_lac_en_pdu = -1;
73 static int hf_a21_pilot_list_num_of_pilots = -1;
74 static int hf_a21_pilot_list_value = -1;
75 static int hf_a21_cause_value = -1;
76 static int hf_a21_mscid_market_id = -1;
77 static int hf_a21_mscid_switch_number = -1;
78 static int hf_a21_event = -1;
79 static int hf_a21_additional_event_info = -1;
80 static int hf_a21_allowed_forward_link_message = -1;
81
82
83 static gint ett_a21 = -1;
84 static gint ett_a21_ie = -1;
85 static gint ett_a21_corr_id = -1;
86 static gint ett_a21_record_content = -1;
87
88 static expert_field ei_a21_ie_data_not_dissected_yet = EI_INIT;
89
90 static const value_string a21_message_type_vals[] = {
91         {0x01, "A21-1x Air Interface Signalling"},      /* 01H */
92         {0x02, "A21-Ack"},                              /* 02H */
93         {0x03, "A21-1x Parameters"},                    /* 03H */
94         {0x04, "A21-Event Notification"},               /* 04H */
95         {0x05, "A21-1x Parameters Request"},            /* 05H */
96         {0x06, "A21-Service Request"},                  /* 06H */
97         {0x07, "A21-Service Response"},                 /* 07H */
98         {0x08, "A21-Radio Update Request"},             /* 08H */
99         {0x09, "A21-Radio Update Response"},            /* 09H */
100         {0,    NULL}
101 };
102
103 #define A21_IEI_1X_LAC_ENCAPSULATED_PDU                 0x01    /* 01H */
104 #define A21_IEI_A21_1X_PARAMETERS                       0x02    /* 02H */
105 #define A21_IEI_PILOT_LIST                              0x03    /* 03H */
106 #define A21_IEI_CORRELATION_ID                          0x04    /* 04H */
107 #define A21_IEI_MOBILE_IDENTITY                         0x05    /* 05H */
108 #define A21_IEI_AUTHENTICATION_CHALLENGE_PARAMETER      0x06    /* 06H */
109 #define A21_IEI_A21_1X_MESSAGE_TRANSMISSION_CONTROL     0x07    /* 07H */
110 #define A21_IEI_A21_CAUSE                               0x08    /* 08H */
111 #define A21_IEI_A21_EVENT                               0x09    /* 09H */
112 #define A21_IEI_SERVICE_OPTION                          0x0A    /* 0AH */
113 #define A21_IEI_A21_MOBILE_SUBSCRIPTION_INFORMATION     0x0B    /* 0BH */
114 #define A21_IEI_GCSNA_STATUS                            0x0C    /* 0CH */
115 #define A21_IEI_GCSNA_PDU                               0xC0    /* C0H */
116 #define A21_IEI_REFERENCE_CELL_ID                       0x0D    /* 0DH */
117 /*(Reserved range of IEIs for S102)                             30H-3FH */
118
119
120
121 static void
122 dissect_a21_correlation_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint16 length _U_, guint8 message_type _U_)
123 {
124         int offset = 0;
125         proto_item *tc;
126         proto_tree *corr_tree;
127
128         if (tree == NULL)
129                 return;
130         tc = proto_tree_add_item(tree, hf_a21_corr_id, tvb, offset,  6, ENC_BIG_ENDIAN);
131         corr_tree = proto_item_add_subtree(tc,ett_a21_corr_id);
132
133         proto_tree_add_item(corr_tree, hf_a21_element_identifier, tvb, offset,  1, ENC_BIG_ENDIAN);
134         offset++;
135         proto_tree_add_item(corr_tree, hf_a21_element_length, tvb, offset,  1, ENC_BIG_ENDIAN);
136         offset++;
137
138         proto_tree_add_item(corr_tree, hf_a21_corr_id_corr_value, tvb, offset,  4, ENC_BIG_ENDIAN);
139         /* offset += 4; */
140
141 }
142
143 static const value_string a21_mn_id_type_of_identity_vals[] = {
144         { 0,  "No Identity Code" },
145         { 1,  "MEID" },
146         { 5,  "ESN" },
147         { 6,  "IMSI" },
148         { 0,  NULL }
149 };
150
151 /* 5.2.4.8 Mobile Identity (MN ID) */
152 static void
153 dissect_a21_mobile_identity(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 length, guint8 message_type _U_)
154 {
155         int offset = 0;
156         guint identity_type;
157         const gchar *imsi_str;
158
159         if (tree == NULL)
160                 return;
161
162         identity_type = tvb_get_guint8(tvb, offset) & 0x07;
163         proto_tree_add_item(tree, hf_a21_mn_id_type_of_identity, tvb, offset, 1, ENC_BIG_ENDIAN);
164
165         switch (identity_type) {
166         case 0:
167                 /* No Identity Code */
168                 proto_tree_add_item(tree, hf_a21_mn_id_msid_value, tvb, offset, 1, ENC_BIG_ENDIAN);
169                 /* offset++; */
170                 break;
171         case 1:
172                 /* MEID */
173                 proto_tree_add_item(tree, hf_a21_mn_id_odd_even_indicator, tvb, offset, 1, ENC_BIG_ENDIAN);
174                 /* offset++; */
175                 break;
176         case 5:
177                 /* ESN */
178                 proto_tree_add_item(tree, hf_a21_mn_id_odd_even_indicator, tvb, offset, 1, ENC_BIG_ENDIAN);
179                 proto_tree_add_item(tree, hf_a21_mn_id_identity_digit_1, tvb, offset, 1, ENC_BIG_ENDIAN);
180                 offset++;
181                 proto_tree_add_item(tree, hf_a21_mn_id_esn, tvb, offset, 1, ENC_BIG_ENDIAN);
182                 /* offset++; */
183                 break;
184         case 6:
185                 /* IMSI */
186                 proto_tree_add_item(tree, hf_a21_mn_id_odd_even_indicator, tvb, offset, 1, ENC_BIG_ENDIAN);
187
188                 imsi_str = dissect_e212_imsi(tvb, pinfo, tree,  offset, length, TRUE);
189                 proto_item_append_text(item, "%s", imsi_str);
190
191                 break;
192         }
193
194
195 }
196
197 static void
198 dissect_a21_1x_message_transmission_control(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint16 length _U_, guint8 message_type _U_)
199 {
200         int offset = 0;
201         if (tree == NULL)
202                 return;
203         proto_tree_add_item(tree, hf_a21_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
204         proto_tree_add_item(tree, hf_a21_msg_tran_ctrl_paging_msg, tvb, offset, 1, ENC_BIG_ENDIAN);
205         proto_tree_add_item(tree, hf_a21_msg_tran_ctrl_simul_xmit_with_next, tvb, offset, 1, ENC_BIG_ENDIAN);
206         proto_tree_add_item(tree, hf_a21_msg_tran_ctrl_ackrequired, tvb, offset, 1, ENC_BIG_ENDIAN);
207         proto_tree_add_item(tree, hf_a21_msg_tran_ctrl_3GXLogicalChannel, tvb, offset, 1, ENC_BIG_ENDIAN);
208         offset++;
209         proto_tree_add_item(tree, hf_a21_msg_tran_ctrl_protocol_revision, tvb, offset, 1, ENC_BIG_ENDIAN);
210         /* offset++; */
211 }
212
213 static void
214 dissect_a21_1x_lac_encapsulated_pdu(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint16 length _U_, guint8 message_type _U_)
215 {
216         int offset = 0;
217         proto_tree_add_item(tree, hf_a21_1x_lac_en_pdu, tvb, offset, 3, ENC_BIG_ENDIAN);
218         /* offset += 3; */
219
220 }
221
222 /* 5.2.4.5 A21 1x Parameters */
223 static void
224 dissect_a21_1x_parameters(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint16 length, guint8 message_type _U_)
225 {
226         proto_tree_add_item(tree, hf_a21_3G1X_parameters, tvb, 0,length, ENC_NA);
227 }
228
229 static void
230 dissect_a21_pilot_list(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint16 length, guint8 message_type _U_)
231 {
232         int offset = 0;
233         guint8 num;
234
235         num = tvb_get_guint8(tvb, offset);
236         proto_tree_add_item(tree, hf_a21_pilot_list_num_of_pilots, tvb, offset, 1, ENC_BIG_ENDIAN);
237         offset++;
238         if (num>0) {
239                 proto_tree_add_item(tree, hf_a21_pilot_list_value, tvb, offset, length-1, ENC_NA);
240                 /* offset += (length-1); */
241         }
242 }
243
244 static const range_string a21_random_number_type_rvals[] = {
245         {0x00, 0x00, "Reserved"},
246         {0x01, 0x01, "RAND"},
247         {0x02, 0x0F, "Reserved"},
248         {0, 0,   NULL}
249 };
250
251 static void
252 dissect_a21_authentication_challenge_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint16 length _U_, guint8 message_type _U_)
253 {
254         int offset = 0;
255         guint type;
256
257         if (tree == NULL)
258                 return;
259         type = tvb_get_guint8(tvb, offset) & 0x0f;
260         proto_tree_add_item(tree, hf_a21_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
261         proto_tree_add_item(tree, hf_a21_auth_chall_para_rand_num_type, tvb, offset, 1, ENC_BIG_ENDIAN);
262         offset++;
263
264         switch (type) {
265         case 1:
266                 proto_tree_add_item(tree, hf_a21_auth_chall_para_rand_value, tvb, offset, 4, ENC_BIG_ENDIAN);
267                 /*offset += 4;*/
268                 break;
269         }
270
271 }
272
273 /* 5.2.4.14 A21 Mobile Subscription Information */
274
275 static const value_string a21_record_identifier_vals[] = {
276         {0x00, "Band Class/Band Subclass Record"},
277         /* All other values are reserved */
278         {0,    NULL}
279 };
280
281 static void
282 dissect_a21_mobile_subscription_information(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint16 length, guint8 message_type _U_)
283 {
284         int offset = 0;
285         int i = 0;
286         guint8 record_id;
287         guint16 record_len = 0;
288         proto_tree *record_tree;
289
290         if (tree == NULL)
291                 return;
292         while (offset<length) {
293                 record_id  = tvb_get_guint8(tvb, offset);
294                 record_len = tvb_get_guint8(tvb, offset+1);
295
296                 record_tree = proto_tree_add_subtree_format(tree, tvb, offset+2, record_len,
297                                                                 ett_a21_record_content, NULL, "Record %u",i+1);
298
299                 proto_tree_add_item(record_tree, hf_a21_mob_sub_info_record_id, tvb, offset,  1, ENC_BIG_ENDIAN);
300                 offset++;
301
302                 proto_tree_add_item(record_tree, hf_a21_mob_sub_info_record_length, tvb, offset,  1, ENC_BIG_ENDIAN);
303                 offset++;
304
305                 if (record_id == 0) {
306                         proto_tree_add_item(record_tree, hf_a21_mob_sub_info_re_con_all_band_inc, tvb, offset,  1, ENC_BIG_ENDIAN);
307                         proto_tree_add_item(record_tree, hf_a21_mob_sub_info_re_con_curr_band_sub, tvb, offset,  1, ENC_BIG_ENDIAN);
308                         offset++;
309                         proto_tree_add_item(record_tree, hf_a21_mob_sub_info_re_band_class, tvb, offset,  1, ENC_BIG_ENDIAN);
310                         offset++;
311                         proto_tree_add_item(record_tree, hf_a21_mob_sub_info_re_con_all_sub_band_inc, tvb, offset,  1, ENC_BIG_ENDIAN);
312                         proto_tree_add_item(record_tree, hf_a21_mob_sub_info_re_sub_cls_len, tvb, offset,  1, ENC_BIG_ENDIAN);
313                         offset += record_len-2;
314                 } else {
315                         proto_tree_add_item(record_tree, hf_a21_mob_sub_info_record_content, tvb, offset,  record_len, ENC_NA);
316                         offset += record_len;
317                 }
318         }
319 }
320
321 static const value_string a21_gcsna_status_vals[] = {
322         {0x01, "Handoff successful"},
323         {0x02, "Handoff failure"},
324         /* All other values are reserved */
325         {0,    NULL}
326 };
327
328
329 static void
330 dissect_a21_gcsna_status(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint16 length _U_, guint8 message_type _U_)
331 {
332         int offset = 0;
333         guint8 priority_incl, status_incl;
334
335         if (tree == NULL)
336                 return;
337         status_incl = tvb_get_guint8(tvb, offset) & 0x01;
338         priority_incl = tvb_get_guint8(tvb, offset) & 0x04;
339
340         proto_tree_add_item(tree, hf_a21_gcsna_status_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
341         proto_tree_add_item(tree, hf_a21_gcsna_status_priority_incl, tvb, offset, 1, ENC_BIG_ENDIAN);
342         proto_tree_add_item(tree, hf_a21_gcsna_status_gec, tvb, offset, 1, ENC_BIG_ENDIAN);
343         proto_tree_add_item(tree, hf_a21_gcsna_status_status_incl, tvb, offset, 1, ENC_BIG_ENDIAN);
344         offset++;
345
346         if (status_incl == 1) {
347                 proto_tree_add_item(tree, hf_a21_gcsna_status, tvb, offset, 1, ENC_BIG_ENDIAN);
348                 offset++;
349         }
350
351         if (priority_incl == 1) {
352                 proto_tree_add_item(tree, hf_a21_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
353                 proto_tree_add_item(tree, hf_a21_gcsna_status_call_priority, tvb, offset, 1, ENC_BIG_ENDIAN);
354         }
355 }
356
357 /* 5.2.4.16 GCSNA PDU */
358 static void
359 dissect_a21_gcsna_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *top_tree, proto_tree *tree, proto_item *item _U_, guint16 length, guint8 message_type _U_)
360 {
361         int offset = 0;
362
363         proto_tree_add_item(tree, hf_a21_gcsna_content, tvb, offset, length, ENC_NA);
364         if (gcsna_handle) {
365                 tvbuff_t *new_tvb;
366                 new_tvb = tvb_new_subset_length(tvb, offset, length);
367                 /* call the dissector with the parent (top)tree */
368                 call_dissector(gcsna_handle, new_tvb, pinfo, top_tree);
369         }
370
371 }
372
373 /* 5.2.4.17 Reference Cell ID */
374 static void
375 dissect_a21_reference_cell_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint16 length _U_, guint8 message_type _U_)
376 {
377         int offset = 0;
378
379         if (tree == NULL)
380                 return;
381         proto_tree_add_item(tree, hf_a21_mscid_market_id, tvb, offset, 2, ENC_BIG_ENDIAN);
382         offset += 2;
383         proto_tree_add_item(tree, hf_a21_mscid_switch_number, tvb, offset, 1, ENC_BIG_ENDIAN);
384         offset += 1;
385
386         proto_tree_add_item(tree, hf_a21_reference_cell_id_cell, tvb, offset, 2, ENC_BIG_ENDIAN);
387         offset++;
388         proto_tree_add_item(tree, hf_a21_reference_cell_id_sector, tvb, offset, 1, ENC_BIG_ENDIAN);
389         /* offset++; */
390
391 }
392
393 static const value_string a21_cause_vals[] = {
394         {0x00, "Unknown mobile"},
395         {0x01, "Unknown cell identifier(s)"},
396         {0x02, "Tunneling of 1x messages not available"},
397         {0x03, "Resources not available"},
398         {0x04, "A21 context for this MS/AT may be released"},
399         {0x05, "Airlink lost"},
400         {0x06, "Abort Handoff from HRPD to 1x"},
401         {0x07, "Unspecified"},
402         {0x08, "Rejection"},
403         {0x09, "Already Paging"},
404         {0x0A, "Abort handoff from LTE to 1x"},
405         {0x0B, "Version not supported"},
406         /* All other values are reserved */
407         {0,    NULL}
408 };
409
410
411 static void
412 dissect_a21_cause(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint16 length _U_, guint8 message_type _U_)
413 {
414         int offset = 0;
415
416         proto_tree_add_item(tree, hf_a21_cause_value, tvb, offset, 1, ENC_BIG_ENDIAN);
417         /* offset++; */
418 }
419
420 static const value_string a21_event_vals[] = {
421         {0x00, "MS/AT present in 1x"},
422         {0x01, "MS/AT present in HRPD/Cancel Handoff"},
423         {0x02, "1x Power Down"},
424         {0x03, "HRPD Power Down/Connection Closed"},
425         {0x04, "Handoff Rejected"},
426         {0x05, "1x Registration"},
427         {0x06, "Transmission of All 1x LAC Encapsulated PDUs Disabled"},
428         {0x07, "Transmission of 1x LAC Encapsulated PDU(s) Enabled"},
429         {0x08, "MS/AT no longer present in this AN/PCF"},
430         {0x09, "MS/AT no longer present in this 1x BS"},
431         {0x0A, "MS/AT Not Acquired"},
432         {0x0B, "Redirection"},
433         /* All other values are reserved */
434         {0,    NULL}
435 };
436
437 static const value_string a21_additional_event_info_vals[] = {
438         {0x00, "This field shall not be included"},
439         {0x01, "This field shall not be included"},
440         {0x02, "This field shall not be included"},
441         {0x03, "This field shall not be included"},
442         {0x04, "This field shall not be included"},
443         {0x05, "This field shall not be included"},
444         {0x06, "This field shall not be included"},
445         {0x07, "This field shall contain the variable length AllowedForwardLinkMessages negotiated by the HRPD AN and the AT"},
446         /* All other values, This field shall not be included */
447         {0,    NULL}
448 };
449
450
451 static void
452 dissect_a21_event(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, proto_item *item, guint16 length, guint8 message_type _U_)
453 {
454         int offset = 0;
455         guint8 event_id;
456
457         if (tree == NULL)
458                 return;
459         event_id = tvb_get_guint8(tvb, offset);
460         proto_tree_add_item(tree, hf_a21_event, tvb, offset,  1, ENC_BIG_ENDIAN);
461         proto_item_append_text(item, "%s", val_to_str_const(event_id, a21_event_vals, "Unknown"));
462         offset++;
463         if (length>1) {
464                 if (event_id == 7) {
465                         proto_tree_add_item(tree, hf_a21_allowed_forward_link_message, tvb, offset, 2, ENC_BIG_ENDIAN);
466                         /*offset += 2;*/
467                 }
468                 else {
469                         proto_tree_add_item(tree, hf_a21_additional_event_info, tvb, offset, 2, ENC_BIG_ENDIAN);
470                         /*offset += 2;*/
471                 }
472         }
473
474
475 }
476
477 static const value_string a21_service_option_vals[] = {
478         {0x003B, "HRPD Packet Data"},
479         /*{0x59xx, "HRPD Packet Data with ReservationLabel where xx = [00-FFH] and contains the ReservationLabel"},*/
480         {0,    NULL}
481 };
482
483
484 /* 5.2.4.13 Service Option */
485 static void
486 dissect_a21_service_option(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint16 length _U_, guint8 message_type _U_)
487 {
488         int offset = 0;
489
490         proto_tree_add_item(tree, hf_a21_service_option, tvb, offset, 2, ENC_BIG_ENDIAN);
491         /* offset += 2; */
492
493 }
494
495 static void
496 dissect_a21_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint16 length, guint8 message_type _U_)
497 {
498         proto_tree_add_expert(tree, pinfo, &ei_a21_ie_data_not_dissected_yet, tvb, 0, length);
499 }
500
501 static const value_string a21_element_type_vals[] = {
502         {0x01, "1x LAC Encapsulated PDU"},
503         {0x02, "A21 1x Parameters"},
504         {0x03, "Pilot List"},
505         {0x04, "Correlation ID"},
506         {0x05, "Mobile Identity (MN ID)"},
507         {0x06, "Authentication Challenge Parameter (RAND)"},
508         {0x07, "A21 1x Message Transmission Control"},
509         {0x08, "A21 Cause"},
510         {0x09, "A21 Event"},
511         {0x0A, "Service Option"},
512         {0x0B, "A21 Mobile Subscription Information"},
513         {0x0C, "GCSNA Status"},
514         {0x0D, "Reference Cell ID"},
515         {0xC0, "GCSNA PDU"},
516         {0,    NULL}
517 };
518
519
520 void
521 dissect_a21_ie_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *top_tree, proto_tree *tree, gint offset, guint8 message_type)
522 {
523         guint8 ie_type, length_len;
524         guint16 length = 0;
525         tvbuff_t *ie_tvb;
526         proto_tree *ie_tree;
527         proto_item *ti;
528
529         while (offset < (gint)tvb_reported_length(tvb)) {
530                 ie_type = tvb_get_guint8(tvb, offset);
531                 if (ie_type == A21_IEI_GCSNA_PDU) {
532                         /* length of GCSNA PDU is 2 octets long */
533                         length_len = 2;
534                         length = tvb_get_ntohs(tvb, offset+1);
535                 } else {
536                         /* Octet 2-length */
537                         length_len = 1;
538                         length = tvb_get_guint8(tvb, offset+1);
539                 }
540
541                 ie_tree = proto_tree_add_subtree_format(tree, tvb, offset, 1 + length_len + length, ett_a21_ie, &ti,
542                                                                         "%s : ", val_to_str_const(ie_type, a21_element_type_vals, "Unknown"));
543
544                 /* Octet 1-element identifier */
545                 proto_tree_add_item(ie_tree, hf_a21_element_identifier, tvb, offset, 1, ENC_BIG_ENDIAN);
546                 offset++;
547                 proto_tree_add_item(ie_tree, hf_a21_gcsna_pdu_length, tvb, offset, length_len, ENC_BIG_ENDIAN);
548                 offset = offset+length_len;
549
550                 ie_tvb = tvb_new_subset_remaining(tvb, offset);
551
552                 switch (ie_type) {
553                 case A21_IEI_1X_LAC_ENCAPSULATED_PDU:
554                         /* 5.2.4.4 1x LAC Encapsulated PDU */
555                         dissect_a21_1x_lac_encapsulated_pdu(ie_tvb,pinfo, ie_tree, ti, length, message_type);
556                         break;
557                 case A21_IEI_A21_1X_PARAMETERS:
558                         /* 5.2.4.5 A21 1x Parameters */
559                         dissect_a21_1x_parameters(ie_tvb,pinfo, ie_tree, ti, length, message_type);
560                         break;
561                 case A21_IEI_PILOT_LIST:
562                         /* 5.2.4.6 Pilot List */
563                         dissect_a21_pilot_list(ie_tvb,pinfo, ie_tree, ti, length, message_type);
564                         break;
565                 case A21_IEI_CORRELATION_ID:
566                         /* 5.2.4.7 Correlation ID */
567                         dissect_a21_correlation_id(ie_tvb,pinfo, ie_tree, ti, length, message_type);
568                         break;
569                 case A21_IEI_MOBILE_IDENTITY:
570                         /* 5.2.4.8 Mobile Identity (MN ID) */
571                         dissect_a21_mobile_identity(ie_tvb,pinfo, ie_tree, ti, length, message_type);
572                         break;
573                 case A21_IEI_AUTHENTICATION_CHALLENGE_PARAMETER:
574                         /* 5.2.4.9 Authentication Challenge Parameter (RAND) */
575                         dissect_a21_authentication_challenge_parameter(ie_tvb,pinfo, ie_tree, ti, length, message_type);
576                         break;
577                 case A21_IEI_A21_1X_MESSAGE_TRANSMISSION_CONTROL:
578                         /* 5.2.4.10 A21 1x Message Transmission Control */
579                         dissect_a21_1x_message_transmission_control(ie_tvb,pinfo, ie_tree, ti, length, message_type);
580                         break;
581                 case A21_IEI_A21_CAUSE:
582                         /* 5.2.4.11 A21 Cause */
583                         dissect_a21_cause(ie_tvb,pinfo, ie_tree, ti, length, message_type);
584                         break;
585                 case A21_IEI_A21_EVENT:
586                         /* 5.2.4.12 A21 Event */
587                         dissect_a21_event(ie_tvb,pinfo, ie_tree, ti, length, message_type);
588                         break;
589                 case A21_IEI_SERVICE_OPTION:
590                         /* 5.2.4.13 Service Option */
591                         dissect_a21_service_option(ie_tvb,pinfo, ie_tree, ti, length, message_type);
592                         break;
593                 case A21_IEI_A21_MOBILE_SUBSCRIPTION_INFORMATION:
594                         /* 5.2.4.14 A21 Mobile Subscription Information */
595                         dissect_a21_mobile_subscription_information(ie_tvb,pinfo, ie_tree, ti, length, message_type);
596                         break;
597                 case A21_IEI_GCSNA_STATUS:
598                         /* 5.2.4.15 GCSNA Status */
599                         dissect_a21_gcsna_status(ie_tvb,pinfo, ie_tree, ti, length, message_type);
600                         break;
601                 case A21_IEI_GCSNA_PDU:
602                         /* 5.2.4.16 GCSNA PDU */
603                         dissect_a21_gcsna_pdu(ie_tvb,pinfo, top_tree, ie_tree, ti, length, message_type);
604                         break;
605                 case A21_IEI_REFERENCE_CELL_ID:
606                         /* 5.2.4.17 Reference Cell ID */
607                         dissect_a21_reference_cell_id(ie_tvb,pinfo, ie_tree, ti, length, message_type);
608                         break;
609                 default:
610                         dissect_a21_unknown(ie_tvb,pinfo, ie_tree, ti, length, message_type);
611                         break;
612                 }
613                 offset = offset + length;
614         }
615 }
616
617
618 static int
619 dissect_a21(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
620 {
621         guint8 message_type;
622         int offset = 0;
623         proto_item *ti, *tc;
624         proto_tree *a21_tree, *corr_tree;
625
626         col_set_str(pinfo->cinfo, COL_PROTOCOL, "A21");
627         col_clear(pinfo->cinfo, COL_INFO);
628
629         /* Message header is 7 octet long
630          * Octet 1 consists of message type
631          * Octets 2-7 contain the Correlation Identifier.
632         */
633
634         message_type = tvb_get_guint8(tvb, offset);
635         col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(message_type, a21_message_type_vals, "Unknown"));
636
637         ti = proto_tree_add_protocol_format(tree, proto_a21, tvb, 0, -1,
638                                       "A21 Protocol: %s",
639                                       val_to_str_const(message_type, a21_message_type_vals, "Unknown"));
640         a21_tree = proto_item_add_subtree(ti, ett_a21);
641
642         /* message type in Octet 1 */
643         proto_tree_add_item(a21_tree, hf_a21_message_type, tvb, offset,  1, ENC_BIG_ENDIAN);
644         offset++;
645         /* Correlation Identifier in Octets 2-7 */
646         tc = proto_tree_add_item(a21_tree, hf_a21_corr_id, tvb, offset,  6, ENC_BIG_ENDIAN);
647         corr_tree = proto_item_add_subtree(tc,ett_a21_corr_id);
648
649         proto_tree_add_item(corr_tree, hf_a21_element_identifier, tvb, offset,  1, ENC_BIG_ENDIAN);
650         offset++;
651         proto_tree_add_item(corr_tree, hf_a21_element_length, tvb, offset,  1, ENC_BIG_ENDIAN);
652         offset++;
653
654         proto_tree_add_item(corr_tree, hf_a21_corr_id_corr_value, tvb, offset,  4, ENC_BIG_ENDIAN);
655         offset += 4;
656
657         dissect_a21_ie_common(tvb, pinfo, tree, a21_tree, offset,  message_type);
658
659         return tvb_captured_length(tvb);
660 }
661
662 void proto_register_a21(void)
663 {
664         static hf_register_info hf_a21[] = {
665                   { &hf_a21_message_type,
666                          {"Message Type", "a21.message_type",
667                           FT_UINT8, BASE_DEC, VALS(a21_message_type_vals), 0x0,
668                           NULL, HFILL }
669                   },
670                   { &hf_a21_corr_id,
671                          {"A21 Correlation ID", "a21.correlation_id",
672                           FT_UINT64, BASE_DEC, NULL, 0x0,
673                           NULL, HFILL }
674                   },
675                   { &hf_a21_element_identifier,
676                          {"A21 Element Identifier", "a21.element_identifier",
677                           FT_UINT8, BASE_DEC, VALS(a21_element_type_vals), 0x0,
678                           NULL, HFILL }
679                   },
680                   { &hf_a21_element_length,
681                          {"Length", "a21.length",
682                           FT_UINT8, BASE_DEC, NULL, 0x0,
683                           NULL, HFILL }
684                   },
685                   { &hf_a21_corr_id_corr_value,
686                          {"Correlation Value", "a21.corr_id_corr_value",
687                           FT_UINT32, BASE_DEC, NULL, 0x0,
688                           NULL, HFILL }
689                   },
690                   { &hf_a21_mn_id_msid_value,
691                          {"MSID Value", "a21.mn_id_msid_value",
692                           FT_UINT8, BASE_DEC, NULL, 0xf8,
693                           NULL, HFILL }
694                   },
695                   { &hf_a21_mn_id_identity_digit_1,
696                          {"Identity Digit 1", "a21.mn_id_identity_digit_1",
697                           FT_UINT8, BASE_DEC, NULL, 0x08,
698                           NULL, HFILL }
699                   },
700                   { &hf_a21_mn_id_odd_even_indicator,
701                          {"Odd/Even Indicator", "a21.mn_id_odd_even_indicator",
702                           FT_UINT8, BASE_DEC, NULL, 0x08,
703                           NULL, HFILL }
704                   },
705                   { &hf_a21_mn_id_type_of_identity,
706                          {"Type of Identity", "a21.mn_id_type_of_identity",
707                           FT_UINT8, BASE_DEC, VALS(a21_mn_id_type_of_identity_vals), 0x07,
708                           NULL, HFILL }
709                   },
710                   { &hf_a21_mn_id_esn,
711                          {"ESN", "a21.mn_id_esn",
712                           FT_UINT8, BASE_DEC, NULL, 0x7f,
713                           NULL, HFILL }
714                   },
715                   { &hf_a21_reserved,
716                          {"Reserved", "a21.reserved",
717                           FT_UINT8, BASE_DEC, NULL, 0xf0,
718                           NULL, HFILL }
719                   },
720                   { &hf_a21_msg_tran_ctrl_paging_msg,
721                          {"Paging Message", "a21.msg_tran_ctrl_paging_msg",
722                           FT_UINT8, BASE_DEC, NULL, 0x08,
723                           NULL, HFILL }
724                   },
725                   { &hf_a21_msg_tran_ctrl_simul_xmit_with_next,
726                          {"Simul Xmit with Next", "a21.msg_tran_ctrl_simul_xmit_with_next",
727                           FT_UINT8, BASE_DEC, NULL, 0x04,
728                           NULL, HFILL }
729                   },
730                   { &hf_a21_msg_tran_ctrl_ackrequired,
731                          {"AckRequired", "a21.msg_tran_ctrl_ackrequired",
732                           FT_UINT8, BASE_DEC, NULL, 0x02,
733                           NULL, HFILL }
734                   },
735                   { &hf_a21_msg_tran_ctrl_3GXLogicalChannel,
736                          {"3GXLogicalChannel", "a21.msg_tran_ctrl_3GXLogicalChannel",
737                           FT_UINT8, BASE_DEC, NULL, 0x01,
738                           NULL, HFILL }
739                   },
740                   { &hf_a21_msg_tran_ctrl_protocol_revision,
741                          {"ProtocolRevision", "a21.msg_tran_ctrl_protocol_revision",
742                           FT_UINT8, BASE_DEC, NULL, 0x0,
743                           NULL, HFILL }
744                   },
745                   { &hf_a21_1x_lac_en_pdu,
746                          {"1x LAC Encapsulated PDU", "a21.1x_lac_en_pdu",
747                           FT_UINT24, BASE_DEC, NULL, 0x0,
748                           NULL, HFILL }
749                   },
750                   { &hf_a21_pilot_list_num_of_pilots,
751                          {"Number of Pilots", "a21.pilot_list_num_of_pilots",
752                           FT_UINT8, BASE_DEC, NULL, 0x0,
753                           NULL, HFILL }
754                   },
755                   { &hf_a21_pilot_list_value,
756                          {"Pilot List Value", "a21.pilot_list_value",
757                           FT_BYTES, BASE_NONE, NULL, 0x0,
758                           NULL, HFILL }
759                   },
760                   { &hf_a21_cause_value,
761                          {"A21 Cause Value", "a21.cause_value",
762                           FT_UINT8, BASE_DEC, VALS(a21_cause_vals), 0x0,
763                           NULL, HFILL }
764                   },
765                   { &hf_a21_mscid_market_id,
766                          {"Market ID", "a21.mscid_market_id",
767                           FT_UINT16, BASE_DEC, NULL, 0x0,
768                           NULL, HFILL }
769                   },
770                   { &hf_a21_mscid_switch_number,
771                          {"Switch Number", "a21.mscid_switch_number",
772                           FT_UINT8, BASE_DEC, NULL, 0x0,
773                           NULL, HFILL }
774                   },
775                   { &hf_a21_event,
776                          {"Event", "a21.event",
777                           FT_UINT8, BASE_DEC, VALS(a21_event_vals), 0x0,
778                           NULL, HFILL }
779                   },
780                   { &hf_a21_additional_event_info,
781                          {"Additional Event Info", "a21.additional_event_info",
782                           FT_UINT16, BASE_DEC, VALS(a21_additional_event_info_vals), 0x0,
783                           NULL, HFILL }
784                   },
785                   { &hf_a21_allowed_forward_link_message,
786                          {"Allowed Forward Link Messages", "a21.allowed_forward_link_message",
787                           FT_UINT16, BASE_DEC, VALS(a21_additional_event_info_vals), 0x0,
788                           NULL, HFILL }
789                   },
790                   { &hf_a21_gcsna_pdu_length,
791                          {"Length", "a21.gcsna_pdu_length",
792                           FT_UINT16, BASE_DEC, NULL, 0x0,
793                           NULL, HFILL }
794                   },
795                   { &hf_a21_gcsna_content,
796                          {"GCSNA Content", "a21.gcsna_content",
797                           FT_NONE, BASE_NONE, NULL, 0x0,
798                           NULL, HFILL }
799                   },
800                   { &hf_a21_reference_cell_id_cell,
801                          {"Cell", "a21.reference_cell_id_cell",
802                           FT_UINT16, BASE_DEC, NULL, 0xfff0,
803                           NULL, HFILL }
804                   },
805                   { &hf_a21_reference_cell_id_sector,
806                          {"Sector", "a21.reference_cell_id_sector",
807                           FT_UINT8, BASE_DEC, NULL, 0x0f,
808                           NULL, HFILL }
809                   },
810                   { &hf_a21_mob_sub_info_record_id,
811                          {"Record Identifier", "a21.mob_sub_info_record_id",
812                           FT_UINT8, BASE_DEC, VALS(a21_record_identifier_vals), 0x0,
813                           NULL, HFILL }
814                   },
815                   { &hf_a21_mob_sub_info_record_length,
816                          {"Record Length", "a21.mob_sub_info_record_length",
817                           FT_UINT8, BASE_DEC, NULL, 0x0,
818                           NULL, HFILL }
819                   },
820                   { &hf_a21_mob_sub_info_record_content,
821                          {"Record Content", "a21.mob_sub_info_record_content",
822                           FT_BYTES, BASE_NONE, NULL, 0x0,
823                           NULL, HFILL }
824                   },
825                   { &hf_a21_mob_sub_info_re_con_all_band_inc,
826                          {"All Band Classes Included", "a21.mob_sub_info_re_con_all_band_inc",
827                           FT_UINT8, BASE_DEC, NULL, 0x80,
828                           NULL, HFILL }
829                   },
830                   { &hf_a21_mob_sub_info_re_con_curr_band_sub,
831                          {"Current Band Subclass", "a21.mob_sub_info_re_con_curr_band_sub",
832                           FT_UINT8, BASE_DEC, NULL, 0x7f,
833                           NULL, HFILL }
834                   },
835                   { &hf_a21_mob_sub_info_re_band_class,
836                          {"Band Class", "a21.mob_sub_info_re_band_class",
837                           FT_UINT8, BASE_DEC, NULL, 0x0,
838                           NULL, HFILL }
839                   },
840                   { &hf_a21_mob_sub_info_re_con_all_sub_band_inc,
841                          {"All Band Subclasses Included", "a21.mob_sub_info_re_con_all_sub_band_inc",
842                           FT_UINT8, BASE_DEC, NULL, 0x80,
843                           NULL, HFILL }
844                   },
845                   { &hf_a21_mob_sub_info_re_sub_cls_len,
846                          {"Subclass Length", "a21.mob_sub_info_re_sub_cls_len",
847                           FT_UINT8, BASE_DEC, NULL, 0x0f,
848                           NULL, HFILL }
849                   },
850 #if 0
851                   { &hf_a21_mob_sub_info_re_con_band_class,
852                          {"Band Class", "a21.mob_sub_info_re_con_band_class",
853                           FT_UINT8, BASE_DEC, NULL, 0x0,
854                           NULL, HFILL }
855                   },
856 #endif
857                   { &hf_a21_auth_chall_para_rand_num_type,
858                          {"Random Number Type", "a21.auth_chall_para_rand_num_type",
859                           FT_UINT8, BASE_DEC|BASE_RANGE_STRING, RVALS(a21_random_number_type_rvals), 0x0f,
860                           NULL, HFILL }
861                   },
862                   { &hf_a21_auth_chall_para_rand_value,
863                          {"RAND Value", "a21.auth_chall_para_rand_value",
864                           FT_UINT32, BASE_DEC, NULL, 0x0,
865                           NULL, HFILL }
866                   },
867                   { &hf_a21_service_option,
868                          {"Service Option", "a21.service_option",
869                           FT_UINT8, BASE_DEC, VALS(a21_service_option_vals), 0x7f,
870                           NULL, HFILL }
871                   },
872                   { &hf_a21_gcsna_status_reserved,
873                          {"Reserved", "a21.gcsna_status_reserved",
874                           FT_UINT8, BASE_DEC, NULL, 0xf8,
875                           NULL, HFILL }
876                   },
877                   { &hf_a21_gcsna_status_priority_incl,
878                          {"Priority Incl", "a21.gcsna_status_priority_incl",
879                           FT_UINT8, BASE_DEC, NULL, 0x04,
880                           NULL, HFILL }
881                   },
882                   { &hf_a21_gcsna_status_gec,
883                          {"GEC", "a21.gcsna_status_gec",
884                           FT_UINT8, BASE_DEC, NULL, 0x02,
885                           NULL, HFILL }
886                   },
887                   { &hf_a21_gcsna_status_status_incl,
888                          {"Status Incl", "a21.gcsna_status_status_incl",
889                           FT_UINT8, BASE_DEC, NULL, 0x01,
890                           NULL, HFILL }
891                   },
892                   { &hf_a21_gcsna_status,
893                          {"Status", "a21.gcsna_status",
894                           FT_UINT8, BASE_DEC, VALS(a21_gcsna_status_vals), 0x0,
895                           NULL, HFILL }
896                   },
897                   { &hf_a21_gcsna_status_call_priority,
898                          {"Call Priority", "a21.gcsna_status_call_priority",
899                           FT_UINT8, BASE_DEC, NULL, 0x0f,
900                           NULL, HFILL }
901                   },
902                   { &hf_a21_3G1X_parameters,
903                          {"3G1X Parameters", "a21.3G1X_parameters",
904                           FT_BYTES, BASE_NONE, NULL, 0x0,
905                           NULL, HFILL }
906                   },
907
908         };
909         /* Setup protocol subtree array */
910         static gint *ett_a21_array[] = {
911                 &ett_a21,
912                 &ett_a21_corr_id,
913                 &ett_a21_ie,
914                 &ett_a21_record_content
915         };
916
917         expert_module_t *expert_a21;
918
919         static ei_register_info ei[] = {
920                 { &ei_a21_ie_data_not_dissected_yet,
921                   { "a21.ie_data_not_dissected_yet",
922                     PI_PROTOCOL, PI_NOTE, "IE data not dissected yet", EXPFILL }},
923         };
924
925         proto_a21 = proto_register_protocol("A21 Protocol", "A21", "a21");
926         proto_register_field_array(proto_a21, hf_a21, array_length(hf_a21));
927         proto_register_subtree_array(ett_a21_array, array_length(ett_a21_array));
928         expert_a21 = expert_register_protocol(proto_a21);
929         expert_register_field_array(expert_a21, ei, array_length(ei));
930 }
931
932 void proto_reg_handoff_a21(void)
933 {
934         dissector_handle_t a21_handle;
935
936         a21_handle = create_dissector_handle(dissect_a21, proto_a21);
937         gcsna_handle = find_dissector_add_dependency("gcsna", proto_a21);
938         dissector_add_uint_with_preference("udp.port", A21_PORT, a21_handle);
939 }
940
941 /*
942  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
943  *
944  * Local variables:
945  * c-basic-offset: 8
946  * tab-width: 8
947  * indent-tabs-mode: t
948  * End:
949  *
950  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
951  * :indentSize=8:tabSize=8:noTabs=false:
952  */