162a8e65ba445f998f0bae9d09c941152c9bd51a
[metze/wireshark/wip.git] / epan / dissectors / packet-bssgp.c
1 /* packet-bssgp.c
2  * Routines for Base Station Subsystem GPRS Protocol dissection
3  * Copyright 2000, Susanne Edlund <susanne.edlund@ericsson.com>
4  *
5  * $Id$
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  */
25
26 /* 3GPP TS 48.018 V 6.5.0 (2004-07) Release 6 */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36 #include <glib.h>
37 #include <epan/packet.h>
38 #include <prefs.h>
39
40 /*#define BSSGP_DEBUG*/
41 #define BSSGP_LITTLE_ENDIAN FALSE
42 #define BSSGP_TRANSLATION_MAX_LEN 50
43 #define BSSGP_MASK_LEFT_OCTET_HALF 0xf0
44 #define BSSGP_MASK_RIGHT_OCTET_HALF 0x0f
45 #define BSSGP_MOBILE_IDENTITY_TYPE_IMSI 1
46 #define BSSGP_MOBILE_IDENTITY_TYPE_IMEI 2
47 #define BSSGP_MOBILE_IDENTITY_TYPE_IMEISV 3
48 #define BSSGP_MOBILE_IDENTITY_TYPE_TMSI_PTMSI 4
49 #define BSSGP_MOBILE_IDENTITY_TYPE_NO_IDENTITY 0
50 #define BSSGP_SEP ", "
51 #define BSSGP_NOT_DECODED "< Not decoded yet >"
52 #define BSSGP_UNKNOWN (-1)
53 static int bssgp_decode_nri = 0;
54 static guint bssgp_nri_length = 4;
55
56 static dissector_handle_t bssgp_handle;
57 static dissector_handle_t llc_handle;
58 static dissector_handle_t rrlp_handle;
59 static dissector_handle_t data_handle;
60
61 module_t *bssgp_module;
62 void proto_reg_handoff_bssgp(void);
63
64 /* Initialize the protocol and registered fields */
65 static int proto_bssgp = -1;
66 static int hf_bssgp_pdu_type = -1;
67 static int hf_bssgp_ie_type = -1;
68 static int hf_bssgp_mcc = -1;
69 static int hf_bssgp_mnc = -1;
70 static int hf_bssgp_lac = -1;
71 static int hf_bssgp_rac = -1;
72 static int hf_bssgp_ci = -1;
73 static int hf_bssgp_nri = -1;
74 static int hf_bssgp_imsi = -1;
75 static int hf_bssgp_imei = -1;
76 static int hf_bssgp_imeisv = -1;
77 static int hf_bssgp_tmsi_ptmsi = -1;
78 static int hf_bssgp_bvci = -1;
79 static int hf_bssgp_nsei = -1;
80 static int hf_bssgp_tlli = -1;
81
82 /* Initialize the subtree pointers */
83 static gint ett_bssgp = -1;
84 static gint ett_bssgp_qos_profile = -1; 
85 static gint ett_bssgp_gprs_timer = -1;
86 static gint ett_bssgp_cell_identifier = -1;
87 static gint ett_bssgp_channel_needed = -1;
88 static gint ett_bssgp_drx_parameters = -1;
89 static gint ett_bssgp_mobile_identity = -1;
90 static gint ett_bssgp_priority = -1;
91 static gint ett_bssgp_lsa_identifier_list = -1;
92 static gint ett_bssgp_lsa_information = -1;
93 static gint ett_bssgp_lsa_information_lsa_identification_and_attributes = -1;
94 static gint ett_bssgp_abqp = -1;
95 static gint ett_bssgp_lcs_qos = -1;
96 static gint ett_bssgp_lcs_client_type = -1;
97 static gint ett_bssgp_requested_gps_assistance_data = -1;
98 static gint ett_bssgp_requested_gps_assistance_data_satellite = -1;
99 static gint ett_bssgp_location_type = -1;
100 static gint ett_bssgp_positioning_data_positioning_method = -1;
101 static gint ett_bssgp_deciphering_keys = -1;
102 static gint ett_bssgp_lcs_cause = -1;
103 static gint ett_bssgp_lcs_capability = -1;
104 static gint ett_bssgp_rrlp_flags = -1;
105 static gint ett_bssgp_ran_information_indications = -1;
106 static gint ett_bssgp_mcc = -1;
107 static gint ett_bssgp_mnc = -1;
108 static gint ett_bssgp_routeing_area = -1;
109 static gint ett_bssgp_location_area = -1;
110 static gint ett_bssgp_rai_ci = -1;
111 static gint ett_bssgp_ran_information_request_container_unit = -1;
112 static gint ett_bssgp_ran_information_container_unit = -1;
113 static gint ett_bssgp_pfc_flow_control_parameters = -1;
114 static gint ett_bssgp_pfc_flow_control_parameters_pfc = -1;
115 static gint ett_bssgp_global_cn_id = -1;
116 static gint ett_bssgp_ms_radio_access_capability = -1;
117 static gint ett_bssgp_msrac_value_part = -1;
118 static gint ett_bssgp_msrac_additional_access_technologies = -1;
119 static gint ett_bssgp_msrac_access_capabilities = -1;
120 static gint ett_bssgp_msrac_a5_bits = -1;
121 static gint ett_bssgp_msrac_multislot_capability = -1;
122 static gint ett_bssgp_feature_bitmap = -1;
123 static gint ett_bssgp_positioning_data = -1;
124 static gint ett_bssgp_tlli = -1;
125
126 /* PDU type coding, v6.5.0, table 11.3.26, p 80 */
127 #define BSSGP_PDU_DL_UNITDATA                  0x00
128 #define BSSGP_PDU_UL_UNITDATA                  0x01
129 #define BSSGP_PDU_RA_CAPABILITY                0x02
130 #define BSSGP_PDU_PTM_UNITDATA                 0x03
131 #define BSSGP_PDU_PAGING_PS                    0x06
132 #define BSSGP_PDU_PAGING_CS                    0x07
133 #define BSSGP_PDU_RA_CAPABILITY_UPDATE         0x08
134 #define BSSGP_PDU_RA_CAPABILITY_UPDATE_ACK     0x09
135 #define BSSGP_PDU_RADIO_STATUS                 0x0a
136 #define BSSGP_PDU_SUSPEND                      0x0b
137 #define BSSGP_PDU_SUSPEND_ACK                  0x0c
138 #define BSSGP_PDU_SUSPEND_NACK                 0x0d
139 #define BSSGP_PDU_RESUME                       0x0e
140 #define BSSGP_PDU_RESUME_ACK                   0x0f
141 #define BSSGP_PDU_RESUME_NACK                  0x10
142 #define BSSGP_PDU_BVC_BLOCK                    0x20
143 #define BSSGP_PDU_BVC_BLOCK_ACK                0x21
144 #define BSSGP_PDU_BVC_RESET                    0x22
145 #define BSSGP_PDU_BVC_RESET_ACK                0x23
146 #define BSSGP_PDU_BVC_UNBLOCK                  0x24
147 #define BSSGP_PDU_BVC_UNBLOCK_ACK              0x25
148 #define BSSGP_PDU_FLOW_CONTROL_BVC             0x26
149 #define BSSGP_PDU_FLOW_CONTROL_BVC_ACK         0x27
150 #define BSSGP_PDU_FLOW_CONTROL_MS              0x28
151 #define BSSGP_PDU_FLOW_CONTROL_MS_ACK          0x29
152 #define BSSGP_PDU_FLUSH_LL                     0x2a
153 #define BSSGP_PDU_FLUSH_LL_ACK                 0x2b
154 #define BSSGP_PDU_LLC_DISCARDED                0x2c
155 #define BSSGP_PDU_FLOW_CONTROL_PFC             0x2d
156 #define BSSGP_PDU_FLOW_CONTROL_PFC_ACK         0x2e
157 #define BSSGP_PDU_SGSN_INVOKE_TRACE            0x40
158 #define BSSGP_PDU_STATUS                       0x41
159 #define BSSGP_PDU_DOWNLOAD_BSS_PFC             0x50
160 #define BSSGP_PDU_CREATE_BSS_PFC               0x51
161 #define BSSGP_PDU_CREATE_BSS_PFC_ACK           0x52
162 #define BSSGP_PDU_CREATE_BSS_PFC_NACK          0x53
163 #define BSSGP_PDU_MODIFY_BSS_PFC               0x54
164 #define BSSGP_PDU_MODIFY_BSS_PFC_ACK           0x55
165 #define BSSGP_PDU_DELETE_BSS_PFC               0x56
166 #define BSSGP_PDU_DELETE_BSS_PFC_ACK           0x57
167 #define BSSGP_PDU_DELETE_BSS_PFC_REQ           0x58
168 #define BSSGP_PDU_PERFORM_LOCATION_REQUEST     0x60
169 #define BSSGP_PDU_PERFORM_LOCATION_RESPONSE    0x61
170 #define BSSGP_PDU_PERFORM_LOCATION_ABORT       0x62
171 #define BSSGP_PDU_POSITION_COMMAND             0x63
172 #define BSSGP_PDU_POSITION_RESPONSE            0x64
173 #define BSSGP_PDU_RAN_INFORMATION              0x70
174 #define BSSGP_PDU_RAN_INFORMATION_REQUEST      0x71
175 #define BSSGP_PDU_RAN_INFORMATION_ACK          0x72
176 #define BSSGP_PDU_RAN_INFORMATION_ERROR        0x73
177
178 static const value_string tab_bssgp_pdu_types[] = {
179   { BSSGP_PDU_DL_UNITDATA,                  "DL-UNITDATA" },
180   { BSSGP_PDU_UL_UNITDATA,                  "UL-UNITDATA" },
181   { BSSGP_PDU_RA_CAPABILITY,                "RA-CAPABILITY" },
182   { BSSGP_PDU_PTM_UNITDATA,                 "PTM-UNITDATA" },
183   { BSSGP_PDU_PAGING_PS,                    "PAGING-PS" },
184   { BSSGP_PDU_PAGING_CS,                    "PAGING-CS" },
185   { BSSGP_PDU_RA_CAPABILITY_UPDATE,         "RA-CAPABILITY-UPDATE" },
186   { BSSGP_PDU_RA_CAPABILITY_UPDATE_ACK,     "RA-CAPABILITY-UPDATE-ACK" },
187   { BSSGP_PDU_RADIO_STATUS,                 "RADIO-STATUS" },
188   { BSSGP_PDU_SUSPEND,                      "SUSPEND" },
189   { BSSGP_PDU_SUSPEND_ACK,                  "SUSPEND-ACK" },
190   { BSSGP_PDU_SUSPEND_NACK,                 "SUSPEND-NACK" },
191   { BSSGP_PDU_RESUME,                       "RESUME" },
192   { BSSGP_PDU_RESUME_ACK,                   "RESUME-ACK" },
193   { BSSGP_PDU_RESUME_NACK,                  "RESUME-NACK" },
194   { BSSGP_PDU_BVC_BLOCK,                    "BVC-BLOCK" },
195   { BSSGP_PDU_BVC_BLOCK_ACK,                "BVC-BLOCK-ACK" },
196   { BSSGP_PDU_BVC_RESET,                    "BVC-RESET" },
197   { BSSGP_PDU_BVC_RESET_ACK,                "BVC-RESET-ACK" },
198   { BSSGP_PDU_BVC_UNBLOCK,                  "UNBLOCK" },
199   { BSSGP_PDU_BVC_UNBLOCK_ACK,              "UNBLOCK-ACK" },
200   { BSSGP_PDU_FLOW_CONTROL_BVC,             "FLOW-CONTROL-BVC" },
201   { BSSGP_PDU_FLOW_CONTROL_BVC_ACK,         "FLOW-CONTROL-BVC-ACK" },
202   { BSSGP_PDU_FLOW_CONTROL_MS,              "FLOW-CONTROL-MS" },
203   { BSSGP_PDU_FLOW_CONTROL_MS_ACK,          "FLOW-CONTROL-MS-ACK" },
204   { BSSGP_PDU_FLUSH_LL,                     "FLUSH-LL" },
205   { BSSGP_PDU_FLUSH_LL_ACK,                 "FLUSH_LL_ACK" },
206   { BSSGP_PDU_LLC_DISCARDED,                "LLC-DISCARDED" },
207   { BSSGP_PDU_FLOW_CONTROL_PFC,             "FLOW-CONTROL-PFC" },
208   { BSSGP_PDU_FLOW_CONTROL_PFC_ACK,         "FLOW-CONTROL-PFC-ACK" },
209   { BSSGP_PDU_SGSN_INVOKE_TRACE,            "SGSN-INVOKE-TRACE" },
210   { BSSGP_PDU_STATUS,                       "STATUS" },
211   { BSSGP_PDU_DOWNLOAD_BSS_PFC,             "DOWNLOAD-BSS-PFC" },
212   { BSSGP_PDU_CREATE_BSS_PFC,               "CREATE-BSS-PFC" },
213   { BSSGP_PDU_CREATE_BSS_PFC_ACK,           "CREATE-BSS-PFC-ACK" },
214   { BSSGP_PDU_CREATE_BSS_PFC_NACK,          "CREATE-BSS-PFC-NACK" },
215   { BSSGP_PDU_MODIFY_BSS_PFC,               "MODIFY-BSS-PFC" },
216   { BSSGP_PDU_MODIFY_BSS_PFC_ACK,           "MODIFY-BSS-PFC-ACK" },
217   { BSSGP_PDU_DELETE_BSS_PFC,               "DELETE-BSS-PFC" },
218   { BSSGP_PDU_DELETE_BSS_PFC_ACK,           "DELETE-BSS-PFC-ACK" },
219   { BSSGP_PDU_DELETE_BSS_PFC_REQ,           "DELETE-BSS-PFC-REQ" },
220   { BSSGP_PDU_PERFORM_LOCATION_REQUEST,     "PERFORM-LOCATION-REQUEST" },
221   { BSSGP_PDU_PERFORM_LOCATION_RESPONSE,    "PERFORM-LOCATION-RESPONSE" },
222   { BSSGP_PDU_PERFORM_LOCATION_ABORT,       "PERFORM-LOCATION-ABORT" },
223   { BSSGP_PDU_POSITION_COMMAND,             "POSITION-COMMAND" },
224   { BSSGP_PDU_POSITION_RESPONSE,            "POSITION-RESPONSE" },
225   { BSSGP_PDU_RAN_INFORMATION,              "RAN-INFORMATION" },
226   { BSSGP_PDU_RAN_INFORMATION_REQUEST,      "RAN-INFORMATION-REQUEST" },
227   { BSSGP_PDU_RAN_INFORMATION_ACK,          "RAN-INFORMATION-ACK" },
228   { BSSGP_PDU_RAN_INFORMATION_ERROR,        "RAN-INFORMATION-ERROR" },
229   { 0,                                NULL },
230 };
231
232 /* Information element coding, v 6.5.0, table 11.3, p 72 */
233 #define BSSGP_IEI_ALIGNMENT_OCTETS                         0x00
234 #define BSSGP_IEI_BMAX_DEFAULT_MS                          0x01              
235 #define BSSGP_IEI_BSS_AREA_INDICATION                      0x02
236 #define BSSGP_IEI_BUCKET_LEAK_RATE                         0x03
237 #define BSSGP_IEI_BVCI                                     0x04
238 #define BSSGP_IEI_BVC_BUCKET_SIZE                          0x05
239 #define BSSGP_IEI_BVC_MEASUREMENT                          0x06
240 #define BSSGP_IEI_CAUSE                                    0x07
241 #define BSSGP_IEI_CELL_IDENTIFIER                          0x08
242 #define BSSGP_IEI_CHANNEL_NEEDED                           0x09
243 #define BSSGP_IEI_DRX_PARAMETERS                           0x0a
244 #define BSSGP_IEI_EMLPP_PRIORITY                           0x0b
245 #define BSSGP_IEI_FLUSH_ACTION                             0x0c
246 #define BSSGP_IEI_IMSI                                     0x0d
247 #define BSSGP_IEI_LLC_PDU                                  0x0e
248 #define BSSGP_IEI_LLC_FRAMES_DISCARDED                     0x0f
249 #define BSSGP_IEI_LOCATION_AREA                            0x10
250 #define BSSGP_IEI_MOBILE_ID                                0x11
251 #define BSSGP_IEI_MS_BUCKET_SIZE                           0x12
252 #define BSSGP_IEI_MS_RADIO_ACCESS_CAPABILITY               0x13
253 #define BSSGP_IEI_OMC_ID                                   0x14
254 #define BSSGP_IEI_PDU_IN_ERROR                             0x15
255 #define BSSGP_IEI_PDU_LIFETIME                             0x16
256 #define BSSGP_IEI_PRIORITY                                 0x17
257 #define BSSGP_IEI_QOS_PROFILE                              0x18
258 #define BSSGP_IEI_RADIO_CAUSE                              0x19
259 #define BSSGP_IEI_RA_CAP_UPD_CAUSE                         0x1a
260 #define BSSGP_IEI_ROUTEING_AREA                            0x1b
261 #define BSSGP_IEI_R_DEFAULT_MS                             0x1c
262 #define BSSGP_IEI_SUSPEND_REFERENCE_NUMBER                 0x1d
263 #define BSSGP_IEI_TAG                                      0x1e
264 #define BSSGP_IEI_TLLI                                     0x1f
265 #define BSSGP_IEI_TMSI                                     0x20
266 #define BSSGP_IEI_TRACE_REFERENCE                          0x21
267 #define BSSGP_IEI_TRACE_TYPE                               0x22
268 #define BSSGP_IEI_TRANSACTION_ID                           0x23
269 #define BSSGP_IEI_TRIGGER_ID                               0x24
270 #define BSSGP_IEI_NUMBER_OF_OCTETS_AFFECTED                0x25
271 #define BSSGP_IEI_LSA_IDENTIFIER_LIST                      0x26
272 #define BSSGP_IEI_LSA_INFORMATION                          0x27
273 #define BSSGP_IEI_PFI                                      0x28
274 #define BSSGP_IEI_GPRS_TIMER                               0x29
275 #define BSSGP_IEI_ABQP                                     0x3a
276 #define BSSGP_IEI_FEATURE_BITMAP                           0x3b
277 #define BSSGP_IEI_BUCKET_FULL_RATIO                        0x3c
278 #define BSSGP_IEI_SERVICE_UTRAN_CCO                        0x3d
279 #define BSSGP_IEI_NSEI                                     0x3e
280 #define BSSGP_IEI_RRLP_APDU                                0x3f
281 #define BSSGP_IEI_LCS_QOS                                  0x40
282 #define BSSGP_IEI_LCS_CLIENT_TYPE                          0x41
283 #define BSSGP_IEI_REQUESTED_GPS_ASSISTANCE_DATA            0x42
284 #define BSSGP_IEI_LOCATION_TYPE                            0x43
285 #define BSSGP_IEI_LOCATION_ESTIMATE                        0x44
286 #define BSSGP_IEI_POSITIONING_DATA                         0x45
287 #define BSSGP_IEI_DECIPHERING_KEYS                         0x46
288 #define BSSGP_IEI_LCS_PRIORITY                             0x47
289 #define BSSGP_IEI_LCS_CAUSE                                0x48
290 #define BSSGP_IEI_LCS_CAPABILITY                           0x49
291 #define BSSGP_IEI_RRLP_FLAGS                               0x4a
292 #define BSSGP_IEI_RIM_APPLICATION_IDENTITY                 0x4b
293 #define BSSGP_IEI_RIM_SEQUENCE_NUMBER                      0x4c
294 #define BSSGP_IEI_RAN_INFORMATION_REQUEST_CONTAINER_UNIT   0x4d
295 #define BSSGP_IEI_RAN_INFORMATION_CONTAINER_UNIT           0x4e
296 #define BSSGP_IEI_RAN_INFORMATION_INDICATIONS              0x4f
297 #define BSSGP_IEI_NUMBER_OF_CONTAINER_UNITS                0x50
298 #define BSSGP_IEI_PFC_FLOW_CONTROL_PARAMETERS              0x52
299 #define BSSGP_IEI_GLOBAL_CN_ID                             0x53
300
301 static const value_string tab_bssgp_ie_types[] = {
302   { BSSGP_IEI_ALIGNMENT_OCTETS,            "Alignment Octets" },
303   { BSSGP_IEI_BMAX_DEFAULT_MS,             "Bmax Default MS" },
304   { BSSGP_IEI_BSS_AREA_INDICATION,         "BSS Area Indication" },
305   { BSSGP_IEI_BUCKET_LEAK_RATE,            "Bucket Leak Rate" },
306   { BSSGP_IEI_BVCI,                        "BVCI" },
307   { BSSGP_IEI_BVC_BUCKET_SIZE,             "BVC Bucket Size" },
308   { BSSGP_IEI_BVC_MEASUREMENT,             "BVC Measurement" },
309   { BSSGP_IEI_CAUSE,                       "Cause" },
310   { BSSGP_IEI_CELL_IDENTIFIER,             "Cell Identifier" },
311   { BSSGP_IEI_CHANNEL_NEEDED,              "Channel Needed" },
312   { BSSGP_IEI_DRX_PARAMETERS,              "DRX Parameters" },
313   { BSSGP_IEI_EMLPP_PRIORITY,              "eMLPP Priority" },
314   { BSSGP_IEI_FLUSH_ACTION,                "Flush Action" },
315   { BSSGP_IEI_IMSI,                        "IMSI" },
316   { BSSGP_IEI_LLC_PDU,                     "LLC PDU" },
317   { BSSGP_IEI_LLC_FRAMES_DISCARDED,        "LLC Frames Discarded" },
318   { BSSGP_IEI_LOCATION_AREA,               "Location Area" },
319   { BSSGP_IEI_MOBILE_ID,                   "Mobile Id" },
320   { BSSGP_IEI_MS_BUCKET_SIZE,              "MS Bucket Size" },
321   { BSSGP_IEI_MS_RADIO_ACCESS_CAPABILITY,  "MS Radio Access Capability" },
322   { BSSGP_IEI_OMC_ID,                      "OMC Id" },
323   { BSSGP_IEI_PDU_IN_ERROR,                "PDU In Error" },
324   { BSSGP_IEI_PDU_LIFETIME,                "PDU Lifetime" },
325   { BSSGP_IEI_PRIORITY,                    "Priority" },
326   { BSSGP_IEI_QOS_PROFILE,                 "QoS Profile" },
327   { BSSGP_IEI_RADIO_CAUSE,                 "Radio Cause" },
328   { BSSGP_IEI_RA_CAP_UPD_CAUSE,            "RA-Cap-UPD-Cause" },
329   { BSSGP_IEI_ROUTEING_AREA,               "Routeing Area" },
330   { BSSGP_IEI_R_DEFAULT_MS,                "R_default_MS" },
331   { BSSGP_IEI_SUSPEND_REFERENCE_NUMBER,    "Suspend Reference Number" },
332   { BSSGP_IEI_TAG,                         "Tag" },
333   { BSSGP_IEI_TLLI,                        "TLLI" },
334   { BSSGP_IEI_TMSI,                        "TMSI" },
335   { BSSGP_IEI_TRACE_REFERENCE,             "Trace Reference" },
336   { BSSGP_IEI_TRACE_TYPE,                  "Trace Type" },
337   { BSSGP_IEI_TRANSACTION_ID,              "Transaction Id" },
338   { BSSGP_IEI_TRIGGER_ID,                  "Trigger Id" },
339   { BSSGP_IEI_NUMBER_OF_OCTETS_AFFECTED,   "Number of Octets Affected" },
340   { BSSGP_IEI_LSA_IDENTIFIER_LIST,         "LSA Identifier List" },
341   { BSSGP_IEI_LSA_INFORMATION,             "LSA Information" },
342   { BSSGP_IEI_PFI,                         "Packet Flow Identiifer" },
343   { BSSGP_IEI_GPRS_TIMER,                  "GPRS Timer" },
344   { BSSGP_IEI_ABQP,                        "ABQP" },
345   { BSSGP_IEI_FEATURE_BITMAP,              "Feature Bitmap" },
346   { BSSGP_IEI_BUCKET_FULL_RATIO,           "Bucket Full Ratio" },
347   { BSSGP_IEI_SERVICE_UTRAN_CCO,           "Service UTRAN CCO" },
348   { BSSGP_IEI_NSEI,                        "NSEI" },
349   { BSSGP_IEI_RRLP_APDU,                   "RRLP APDU" },
350   { BSSGP_IEI_LCS_QOS,                     "LCS QoS" },
351   { BSSGP_IEI_LCS_CLIENT_TYPE,             "LCS Client Type" },
352   { BSSGP_IEI_REQUESTED_GPS_ASSISTANCE_DATA, "Requested GPS Assistance Data" },
353   { BSSGP_IEI_LOCATION_TYPE,               "Location Type" },
354   { BSSGP_IEI_LOCATION_ESTIMATE,           "Location Estimate" },
355   { BSSGP_IEI_POSITIONING_DATA,            "Positioning Data" },
356   { BSSGP_IEI_DECIPHERING_KEYS,            "Deciphering Keys" },
357   { BSSGP_IEI_LCS_PRIORITY,                "LCS Priority" },
358   { BSSGP_IEI_LCS_CAUSE,                   "LCS Cause" },
359   { BSSGP_IEI_LCS_CAPABILITY,              "LCS Capability" },
360   { BSSGP_IEI_RRLP_FLAGS,                  "RRLP Flags" },
361   { BSSGP_IEI_RIM_APPLICATION_IDENTITY,    "RIM Application Identity" },
362   { BSSGP_IEI_RIM_SEQUENCE_NUMBER,         "RIM Sequence Number" },
363   { BSSGP_IEI_RAN_INFORMATION_REQUEST_CONTAINER_UNIT, "RAN INFORMATION REQUEST Container Unit" },
364   { BSSGP_IEI_RAN_INFORMATION_CONTAINER_UNIT, "RAN INFORMATION Container Unit" },
365   { BSSGP_IEI_RAN_INFORMATION_INDICATIONS,  "RAN INFORMATION Indications" },
366   { BSSGP_IEI_NUMBER_OF_CONTAINER_UNITS,    "Number of Container Units" },
367   { BSSGP_IEI_PFC_FLOW_CONTROL_PARAMETERS,  "PFC Flow Control Parameters" },
368   { BSSGP_IEI_GLOBAL_CN_ID,                 "Global CN Id" }, 
369   { 0,                                NULL },
370 };
371
372 /* Presence requirements of Information Elements
373    48.016 v 5.3.0, chapter 8.1.1, p. 35 */
374 #define BSSGP_IE_PRESENCE_M 1   /* Mandatory */
375 #define BSSGP_IE_PRESENCE_O 2   /* Conditional */
376 #define BSSGP_IE_PRESENCE_C 3   /* Optional */
377
378 /* Format options */
379 #define BSSGP_IE_FORMAT_V 1
380 #define BSSGP_IE_FORMAT_TV 2
381 #define BSSGP_IE_FORMAT_TLV 3
382
383 typedef struct {
384   guint8        iei;
385   const char   *name;
386   guint8        presence_req;
387   int           format;
388   gint16        value_length; /* in bytes (read from capture)*/
389   gint16        total_length; /* as specified, or 0 if unspecified */
390 } bssgp_ie_t;
391
392 typedef struct {
393   tvbuff_t     *tvb;
394   guint32       offset;
395   packet_info  *pinfo;
396   proto_tree   *bssgp_tree;
397   proto_tree   *parent_tree;
398   gboolean      dl_data;
399   gboolean      ul_data;
400 } build_info_t;
401
402 static guint8
403 get_masked_guint8(guint8 value, guint8 mask) {
404   const guint8 MASK_BIT_1 = 0x01; 
405   guint8 i = 0;
406   
407   while (!((mask >> i) & MASK_BIT_1)) {
408     i++;
409     if (i > 7) return 0; 
410   }
411   return (value & mask) >> i;
412 }
413
414 #if 0
415 static guint16
416 get_masked_guint16(guint16 value, guint16 mask) {
417   const guint16 MASK_BIT_1 = 0x01; 
418   guint8 i = 0;
419   
420   while (!((mask >> i) & MASK_BIT_1)) {
421     i++;
422     if (i > 15) return 0; 
423   }
424   return (value & mask) >> i;
425 }
426 #endif
427
428 static gint32
429 make_mask32(guint8 num_bits, guint8 shift_value) {
430   const guint32 LEFT_MOST_1 = 0x80000000;
431   int i;
432   guint32 mask = LEFT_MOST_1;
433   
434   for (i = 0; i < (num_bits - 1); i++) {
435     mask = (mask >> 1) | LEFT_MOST_1;
436   }
437   return mask >> shift_value;
438 }
439
440 static guint32
441 get_masked_guint32(guint32 value, guint32 mask) {
442   const guint16 MASK_BIT_1 = 0x01; 
443   guint8 i = 0;
444   
445   while (!((mask >> i) & MASK_BIT_1)) {
446     i++;
447     if (i > 31) return 0; 
448   }
449   return (value & mask) >> i;
450 }
451
452 static guint8
453 tvb_get_masked_guint8(tvbuff_t *tvb, int offset, guint8 mask) {
454   guint8 value = tvb_get_guint8(tvb, offset);
455   return get_masked_guint8(value, mask);
456 }
457
458 static char*
459 get_bit_field_label(guint16 value, guint16 value_mask, guint16 num_bits) {
460 #define MAX_NUM_BITS 16
461   guint16 i, bit_mask;
462   static char label[MAX_NUM_BITS + 1];
463
464   DISSECTOR_ASSERT(num_bits <= MAX_NUM_BITS);
465   for (i = 0; i < num_bits; i++) {
466     bit_mask = 1 << i;
467     if (value_mask & bit_mask) {
468       label[num_bits - 1 - i] = (value & bit_mask) ? '1' : '0';
469     }
470     else {
471       label[num_bits - 1 - i] = '.';
472     }
473   }
474 #undef MAX_NUM_BITS
475   return label;
476 }
477
478 static char*
479 get_bit_field_label8(guint8 value, guint8 value_mask) {
480   char *bits;
481   static char formatted_label[10];
482   bits = get_bit_field_label(value, value_mask, 8);
483   g_snprintf(formatted_label, 10, "%c%c%c%c %c%c%c%c",
484              bits[0], bits[1], bits[2], bits[3],
485              bits[4], bits[5], bits[6], bits[7]);
486   return formatted_label;  
487 }
488
489 static char*
490 get_bit_field_label16(guint16 value, guint16 value_mask) {
491   char *bits;
492   static char formatted_label[18];
493   bits = get_bit_field_label(value, value_mask, 16);
494   g_snprintf(formatted_label, 18, "%c%c%c%c%c%c%c%c %c%c%c%c%c%c%c%c",
495              bits[0], bits[1], bits[2], bits[3],
496              bits[4], bits[5], bits[6], bits[7],
497              bits[8], bits[9], bits[10], bits[11],
498              bits[12], bits[13], bits[14], bits[15]);
499   return formatted_label;  
500 }
501
502 static proto_item *
503 proto_tree_add_bitfield8(proto_tree *tree, tvbuff_t *tvb, int offset, guint8 mask) {
504   /* XXX: Use varargs */
505   guint8 value = tvb_get_guint8(tvb, offset);
506   char *label = get_bit_field_label8(value, mask);
507   proto_item *pi = proto_tree_add_text(tree, tvb, offset, 1, "%s = ",
508                                        label);
509   return pi;
510 }
511
512 #if 0
513 static proto_item *
514 proto_tree_add_bitfield16(proto_tree *tree, tvbuff_t *tvb, int offset, guint16 mask) {
515   /* XXX: Use varargs */
516   guint16 value = tvb_get_ntohs(tvb, offset);
517   char *label = get_bit_field_label16(value, mask);
518   proto_item *pi = proto_tree_add_text(tree, tvb, offset, 2, "%s = ",
519                                        label);
520  return pi;
521 }
522 #endif
523
524 static guint8
525 get_byte_offset(guint64 bo) {
526   return (guint8) bo % 8;
527 }
528
529 static guint32
530 get_start_octet(guint64 bo) {
531   return (guint32) floor((gint64)bo / 8.0);
532 }
533
534 static guint32
535 get_end_octet(guint64 bo, guint32 bl) 
536 {
537   return (guint32) ceil((gint64)(bo + bl) / 8.0);
538 }
539
540 static guint32
541 get_num_octets_spanned(guint64 bo, guint32 bl) 
542 {
543   return get_end_octet(bo, bl) - get_start_octet(bo);
544 }
545
546 static gint16
547 make_mask(guint8 num_bits, guint8 shift_value) {
548   guint16 mask;
549
550   switch (num_bits) {
551   case 0: mask = 0x0000; break;
552   case 1: mask = 0x8000; break;
553   case 2: mask = 0xc000; break;
554   case 3: mask = 0xe000; break;
555   case 4: mask = 0xf000; break;
556   case 5: mask = 0xf800; break;
557   case 6: mask = 0xfc00; break;
558   case 7: mask = 0xfe00; break;
559   case 8: mask = 0xff00; break;
560   default: DISSECTOR_ASSERT_NOT_REACHED(); mask = 0; break;
561   }
562   return mask >> shift_value;
563 }
564
565 static guint8
566 tvb_get_bits8(tvbuff_t *tvb, guint64 bo, guint8 num_bits) {
567   /* Returns 0-8 bits from tvb */
568   guint8 shift_value;
569   guint16 mask, data;
570   
571   shift_value = get_byte_offset(bo);
572   mask = make_mask(num_bits, shift_value);
573   data = tvb_get_ntohs(tvb, get_start_octet(bo));
574   return (data & mask) >> (16 - shift_value - num_bits);
575 }
576
577 static proto_item *
578 bit_proto_tree_add_text(proto_tree *tree, tvbuff_t *tvb, 
579                         guint64 bo, guint8 bl, const char *value) {
580   /* XXX: Use varargs */
581   return proto_tree_add_text(tree, tvb, get_start_octet(bo),
582                              get_num_octets_spanned(bo, bl), value);
583 }
584
585 static proto_item *
586 bit_proto_tree_add_bit_field8(proto_tree *tree, tvbuff_t *tvb,
587                               guint64 bo, guint8 bl) {
588   /* XXX: Use varargs */
589   guint16 value = tvb_get_ntohs(tvb, get_start_octet(bo));
590   guint16 mask = make_mask(bl, get_byte_offset(bo));
591   char *label = get_bit_field_label16(value, mask);
592   guint8 end_i;
593   int i;
594   proto_item *pi;
595
596   DISSECTOR_ASSERT(bl < 9);
597   
598   if (get_num_octets_spanned(bo, bl) == 1) {
599     end_i = 7;
600   }
601   else {
602     end_i = 16;
603   }
604   pi = bit_proto_tree_add_text(tree, tvb, bo, bl, "");
605
606   for (i = 0; i <=end_i; i++) {
607     proto_item_append_text(pi, "%c", label[i]);
608   }
609   proto_item_append_text(pi, " = ");
610   return pi;
611 }
612
613 static const char*
614 translate_abqp_reliability_class(guint8 value, build_info_t *bi) {
615   switch (value) {
616   case 0: 
617     if (bi->ul_data) {
618       return "Subscribed reliability class";
619     }
620     else {
621       return "Reserved";
622     }
623   case 1: 
624     return "Unused (Unacknowledged GTP; Acknowledged LLc and RLC, Protected data)"; 
625   case 2: 
626     return "Unacknowledged GTP; Acknowledged LLc and RLC, Protected data"; 
627   case 3: 
628     return "Unacknowledged GTP and LLC; Acknowledged RLC, Protected data";
629   case 4: 
630     return "Unacknowledged GTP, LLC, and RLC, Protected data";
631   case 5:
632     return "Unacknowledged GTP, LLC, and RLC, Unprotedcted data";
633   case 7: 
634     return "Reserved";
635   default:
636     return "Unacknowledged GTP and LLC; Acknowledged RLC, Protected data"; 
637   }
638 }
639 static const char*
640 translate_abqp_delay_class(guint8 value, build_info_t *bi) {
641   switch (value) {
642   case 0: 
643     if (bi->ul_data) {
644       return "Subscribed delay class";
645     }
646     else {
647       return "Reserved";
648     }
649   case 1: return "Delay class 1";
650   case 2: return "Delay class 2";
651   case 3: return "Delay class 3";
652   case 4: return "Delay class 4 (best effort)";
653   case 7: return "Reserved";
654   default:
655     return "Delay class 4 (best effort)";
656   }
657 }
658 static const char*
659 translate_abqp_peak_throughput(guint8 value, build_info_t *bi) {
660   switch (value) {
661   case 0:
662     if (bi->ul_data) {
663       return "Subscribed peak throughput";
664     }
665     else {
666       return "Reserved";
667     }
668   case 1: return "Up to 1 000 octets/s";
669   case 2: return "Up to 2 000 octets/s";
670   case 3: return "Up to 4 000 octets/s";
671   case 4: return "Up to 8 000 octets/s";
672   case 5: return "Up to 16 000 octets/s";
673   case 6: return "Up to 32 000 octets/s";
674   case 7: return "Up to 64 000 octets/s";
675   case 8: return "Up to 128 000 octets/s";
676   case 9: return "Up to 256 000 octets/s";
677   case 15: return "Reserved";
678   default:
679     return "Up to 1 000 octets/s";
680   }
681 }
682 static const char*
683 translate_abqp_precedence_class(guint8 value, build_info_t *bi) {
684   switch (value) {
685   case 0: 
686     if (bi->ul_data) {
687       return "Subscribed precedence";
688     }
689     else {
690       return "Reserved";
691     }
692   case 1: return "High priority";
693   case 2: return "Normal priority";
694   case 3: return "Low priority";
695   case 7: return "Reserved";
696   default:
697     return "Normal priority";
698   }
699 }
700 static const char*
701 translate_abqp_mean_throughput(guint8 value, build_info_t *bi) {
702   switch (value) {
703   case 0:
704     if (bi->ul_data) {
705       return "Subscribed mean throughput";
706     }
707     else {
708       return "Reserved";
709     }
710   case 1: return "100 octets/h";
711   case 2: return "200 octets/h";
712   case 3: return "500 octets/h";
713   case 4: return "1 000 octets/h";
714   case 5: return "2 000 octets/h";
715   case 6: return "5 000 octets/h";
716   case 7: return "10 000 octets/h";
717   case 8: return "20 000 octets/h";
718   case 9: return "50 000 octets/h";
719   case 0x0a: return "100 000 octets/h";
720   case 0x0b: return "200 000 octets/h";
721   case 0x0c: return "500 000 octets/h";
722   case 0x0d: return "1 000 000 octets/h";
723   case 0x0e: return "2 000 000 octets/h";
724   case 0x0f: return "5 000 000 octets/h";
725   case 0x10: return "10 000 000 octets/h";
726   case 0x11: return "20 000 000 octets/h";
727   case 0x12: return "50 000 000 octets/h";
728   case 0x1e: return "Reserved";
729   case 0x1f: return "Best effort";
730   default:
731     return "Best effort";
732   }
733 }
734 static const char*
735 translate_abqp_traffic_class(guint8 value, build_info_t *bi) {
736   switch (value) {
737   case 0:
738     if (bi->ul_data) {
739       return "Subscribed traffic class";
740     }
741     else {
742       return "Reserved";
743     }
744   case 1: return "Conversational class";
745   case 2: return "Streaming class";
746   case 3: return "Interactive class";
747   case 4: return "Background class";
748   case 7: return "Reserved";
749   default:
750     if (bi->ul_data) {
751       /* The MS shall consider all other values as reserved */
752       return "Reserved";
753     }
754     else {
755       /* The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of the protocol */
756       return "Error";
757     }
758   }
759 }
760 static const char*
761 translate_abqp_delivery_order(guint8 value, build_info_t *bi) {
762   switch (value) {
763   case 0: 
764     if (bi->ul_data) {
765       return "Subscribed delivery order";
766     }
767     else {
768       return "Reserved";
769     }
770   case 1: return "With delivery order ('yes')";
771   case 2: return "Without delivery order ('no')";
772   case 3: return "Reserved";
773   default:
774     return "Error in BSSGP dissector";
775   }
776 }
777 static const char*
778 translate_abqp_delivery_of_erroneous_sdu(guint8 value, build_info_t *bi) {
779   switch (value) {
780   case 0:
781     if (bi->ul_data) {
782       return "Subscribed delivery of erroneous SDUs";
783     }
784     else {
785       return "Reserved";
786     }
787   case 1: return "No detect ('-')";
788   case 2: return "Erroneous SDUs are delivered ('yes')";
789   case 3: return "Erroneous SDUs are not delivered ('no')";
790   case 7: return "Reserved";
791   default:
792     if (bi->ul_data) {
793       /* The MS shall consider all other values as reserved */
794       return "Reserved";
795     }
796     else {
797       /* The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of the protocol */
798       return "Error";
799     }
800   }
801 }
802 static const char*
803 translate_abqp_max_sdu_size(guint8 value, build_info_t *bi) {
804   static char result[BSSGP_TRANSLATION_MAX_LEN];
805
806   switch (value) {
807   case 0:
808     if (bi->ul_data) {
809       return "Subscribed maximum SDU size";
810     }
811     else {
812       return "Reserved";
813     }
814   case 0xff:
815     if (bi->ul_data) {
816       return "Reserved";
817     }
818     else {
819       return "Reserved";
820     }
821   case 0x97: return "1502 octets";
822   case 0x98: return "1510 octets";
823   case 0x99: return "1520 octets";
824   }
825   if ((value >= 1) && (value <= 0x96)) {
826     g_snprintf(result, BSSGP_TRANSLATION_MAX_LEN, "%u octets", value * 10);
827     return result;
828   }
829   if (bi->ul_data) {
830     /* The MS shall consider all other values as reserved */
831     return "Reserved";
832   }
833   else {
834     /* The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of the protocol */
835     return "Error";
836   }
837 }  
838
839 static const char*
840 translate_abqp_max_bit_rate_for_ul(guint8 value, build_info_t *bi) {
841   static char result[BSSGP_TRANSLATION_MAX_LEN];
842
843   if (value == 0) {
844     if (bi->ul_data) {
845       return "Subscribed maximum bit rate for uplink";
846     }
847     else {
848       return "Reserved";
849     }
850   }
851   if ((value >= 1) && (value <= 0x3f)) {
852     g_snprintf(result, BSSGP_TRANSLATION_MAX_LEN, "%u kbps", value);
853     return result;
854   }
855   if ((value >= 0x40) && (value <= 0x7f)) {
856     g_snprintf(result, BSSGP_TRANSLATION_MAX_LEN, "%u kbps", 64 + (value - 0x40) * 8);
857     return result;
858   }
859   if ((value >= 0x80) && (value <= 0xfe)) {
860     g_snprintf(result, BSSGP_TRANSLATION_MAX_LEN, "%u kbps", 576 + (value - 0x80) * 64);
861     return result;
862   }
863   return "0 kbps";
864 }
865
866 static const char*
867 translate_abqp_max_bit_rate_for_dl(guint8 value, build_info_t *bi) {
868   return translate_abqp_max_bit_rate_for_ul(value, bi);
869 }
870
871 static const char*
872 translate_abqp_residual_ber(guint8 value, build_info_t *bi) {
873   switch (value) {
874   case 0:
875     if (bi->ul_data) {
876       return "Subscribed residual BER";
877     }
878     else {
879       return "Reserved";
880     }
881   case 1: return "5*10^-2";
882   case 2: return "1*10^-2";
883   case 3: return "5*10^-3";
884   case 4: return "4*10^-3";
885   case 5: return "1*10^-3";
886   case 6: return "1*10^-4";
887   case 7: return "1*10^-5";
888   case 8: return "1*10^-6";
889   case 9: return "6*10^-8";
890   case 15: return "Reserved";
891   }
892   if (bi->ul_data) {
893     /* The MS shall consider all other values as reserved */
894     return "Reserved";
895   }
896   else {
897     /* The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of the protocol */
898     return "Error";
899   }
900 }
901
902 static const char*
903 translate_abqp_sdu_error_ratio(guint8 value, build_info_t *bi) {
904   switch (value) {
905   case 0:
906     if (bi->ul_data) {
907       return "Subscribed SDU error ratio";
908     }
909     else {
910       return "Reserved";
911     }
912   case 1: return "1*10^-2";
913   case 2: return "7*10^-3";
914   case 3: return "1*10^-3";
915   case 4: return "1*10^-4";
916   case 5: return "1*10^-5";
917   case 6: return "1*10^-6";
918   case 7: return "1*10^-1";
919   case 15: return "Reserved";
920   }
921   if (bi->ul_data) {
922     /* The MS shall consider all other values as reserved */
923     return "Reserved";
924   }
925   else {
926     /* The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of the protocol */
927     return "";
928   }
929 }
930
931 static const char*
932 translate_abqp_transfer_delay(guint8 value, build_info_t *bi) {
933   static char result[BSSGP_TRANSLATION_MAX_LEN];
934
935   if (value == 0) {
936     if (bi->ul_data) {
937       return "Subscribed transfer delay";
938     }
939     else {
940       return "Reserved";
941     }
942   }
943   if ((value >= 1) && (value <= 0x0f)) {
944     g_snprintf(result, BSSGP_TRANSLATION_MAX_LEN, "%u ms", value * 10);
945     return result;
946   }
947   if ((value >= 0x10) && (value <= 0x1f)) {
948     g_snprintf(result, BSSGP_TRANSLATION_MAX_LEN, "%u ms", 200 + (value - 0x10) * 50);
949     return result;
950   }
951   if ((value >= 0x20) && (value <= 0x3e)) {
952     g_snprintf(result, BSSGP_TRANSLATION_MAX_LEN, "%u ms", 1000 + (value - 0x20) * 100);
953     return result;
954   }
955   return "Reserved";
956 }
957
958 static const char*
959 translate_abqp_traffic_handling_priority(guint8 value, build_info_t *bi) {
960   switch (value) {
961   case 0:
962     if (bi->ul_data) {
963       return "Subscribed traffic handling_priority";
964     }
965     else {
966       return "Reserved";
967     }
968   case 1: return "Priority level 1";
969   case 2: return "Priority level 2";
970   case 3: return "Priority level 3";
971   default: return "";
972   }
973 }
974
975 static const char*
976 translate_abqp_guaranteed_bit_rate_for_ul(guint8 value, build_info_t *bi) {
977   return translate_abqp_max_bit_rate_for_ul(value, bi);
978 }
979 static const char*
980 translate_abqp_guaranteed_bit_rate_for_dl(guint8 value, build_info_t *bi) {
981   return translate_abqp_max_bit_rate_for_ul(value, bi);
982 }
983
984 static const char*
985 translate_abqp_source_statistics_descriptor(guint8 value, build_info_t *bi) {
986   if (bi->ul_data) {
987     switch (value) {
988     case 0: return "Unknown";
989     case 1: return "Speech";
990     default: return "Unknown";
991     }
992   }
993   else {
994     return "Spare";
995   }
996 }
997
998 static const char*
999 translate_abqp_max_bit_rate_for_dl_extended(guint8 value, build_info_t *bi _U_) {
1000   static char result[BSSGP_TRANSLATION_MAX_LEN];
1001
1002   if (value == 0) {
1003     return "Use the value indicated by the Maximum bit rate for downlink";
1004   }
1005   if ((value >= 1) || (value <= 0x4a)) {
1006     g_snprintf(result, BSSGP_TRANSLATION_MAX_LEN, "%u kbps", 8600 + value * 100);
1007     return result;
1008   }
1009   /* The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of the protocol */
1010   return "";
1011 }
1012
1013 static const char*
1014 translate_abqp_guaranteed_bit_rate_for_dl_extended(guint8 value, build_info_t *bi _U_) {
1015   static char result[BSSGP_TRANSLATION_MAX_LEN];
1016
1017   if (value == 0) {
1018     return "Use the value indicated by the Guaranteed bit rate for downlink";
1019   }
1020   if ((value >= 1) || (value <= 0x4a)) {
1021     g_snprintf(result, BSSGP_TRANSLATION_MAX_LEN, "%u kbps", 8600 + value * 100);
1022     return result;
1023   }
1024   /* The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of the protocol */
1025   return "";
1026 }
1027
1028 static const char*
1029 translate_msrac_access_technology_type(guint8 value) {
1030   static const value_string tab_values[] = {
1031     { 0, "GSM P" },
1032     { 1, "GSM E" },
1033     { 2, "GSM R" },
1034     { 3, "GSM 1800" },
1035     { 4, "GSM 1900" },
1036     { 5, "GSM 450" },
1037     { 6, "GSM 480" },
1038     { 7, "GSM 850" },
1039     { 8, "GSM 700" },
1040     { 9, "GSM T 380" },
1041     { 10, "GSM T 410" },
1042     { 11, "GSM T 900" },
1043     { 15, "List of Additional Access Technologies present" },
1044     { 0, NULL },
1045     /* Otherwise "Unknown" */
1046   };
1047   return val_to_str(value, tab_values, "Unknown");
1048 }
1049
1050 static const char*
1051 translate_msrac_dtm_gprs_multislot_class(guint8 value) {
1052  static const value_string tab_values[] = {
1053     { 0, "Unused, interpreted as \"Multislot class 5 supported\"" },
1054     { 1, "Multislot class 5 supported" },
1055     { 2, "Multislot class 9 supported" },
1056     { 3, "Multislot class 11 supported" },
1057     { 0, NULL },
1058     /* No other combinations*/
1059   };
1060   return val_to_str(value, tab_values, "");
1061 }
1062
1063 static const char*
1064 translate_msrac_extended_dtm_gprs_multislot_class(guint8 value, guint8 dgmsc) {
1065   switch (dgmsc) {
1066   case 0: return "Unused, interpreted as Multislot class 5 supported";
1067   case 1: 
1068     switch (value) {
1069     case 0: return "Multislot class 5 supported";
1070     case 1: return "Multislot class 6 supported";
1071     case 2: 
1072     case 3: 
1073       return "Unused, interpreted as Multislot class 5 supported";
1074     }
1075   case 2: 
1076     switch (value) {
1077     case 0: return "Multislot class 9 supported";
1078     case 1: return "Multislot class 10 supported";
1079     case 2: 
1080     case 3: 
1081       return "Unused, interpreted as Multislot class 5 supported";
1082     }
1083   case 3: 
1084     switch (value) {
1085     case 0: return "Multislot class 11 supported";
1086     case 1:
1087     case 2:
1088     case 3: 
1089       return "Unused, interpreted as Multislot class 5 supported";
1090     }
1091   }
1092   DISSECTOR_ASSERT_NOT_REACHED();
1093   return "Error"; /* Dummy */
1094 }
1095
1096 #if 0
1097 static guint8
1098 translate_msrac_high_multislot_capability(guint8 capability, guint8 class) {
1099   switch (capability) {
1100   case 0:
1101     switch (class) {
1102     case 8: 
1103       return 30;
1104     case 10:
1105     case 23:
1106     case 28: 
1107     case 29: 
1108       return 39;
1109     case 11:
1110     case 20:
1111     case 25:
1112       return 32;
1113     case 12:
1114     case 21:
1115     case 22:
1116     case 26:
1117     case 27:
1118       return 33;
1119     default: 
1120       return class;
1121     }
1122   case 1:    
1123     switch (class) {
1124     case 8: 
1125       return 35;
1126     case 10:
1127     case 19:
1128     case 24:
1129       return 36;
1130     case 11:
1131     case 23:
1132     case 28:
1133     case 29:
1134       return 45;
1135     case 12:
1136     case 21:
1137     case 22:
1138     case 26:
1139     case 27:
1140       return 38;
1141     default: 
1142       return class;
1143     }
1144   case 2:
1145     switch (class) {
1146     case 8:
1147       return 40;
1148     case 10:
1149     case 19:
1150     case 24:
1151       return 41;
1152     case 11:
1153     case 20:
1154     case 25:
1155       return 42;
1156     case 12:
1157     case 23:
1158     case 28:
1159     case 29:
1160       return 44;
1161     default:
1162       return class;
1163     }
1164   case 3:
1165     switch (class) {
1166     case 12:
1167     case 21:
1168     case 22:
1169     case 26:
1170     case 27:
1171       return 43;
1172     case 11:
1173     case 20:
1174     case 25:
1175       return 37;
1176     case 10:
1177     case 19:
1178     case 24:
1179       return 31;
1180     case 9:
1181     case 23:
1182     case 28:
1183     case 29:
1184       return 34;
1185     default:
1186       return class;
1187     }
1188   }
1189   DISSECTOR_ASSERT_NOT_REACHED();
1190   return 0;
1191 }
1192 #endif
1193
1194 static const char*
1195 translate_channel_needed(guint8 value) {
1196   switch (value) {
1197   case 0: return "Any channel";
1198   case 1: return "SDCCH";
1199   case 2: return "TCH/F (Full rate)";
1200   case 3: return "TCH/H or TCH/F (Dual rate)";
1201   }
1202   DISSECTOR_ASSERT_NOT_REACHED();
1203   return NULL;
1204 }
1205
1206 static proto_item* 
1207 bssgp_proto_tree_add_ie(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1208   return proto_tree_add_uint_format(bi->bssgp_tree, hf_bssgp_ie_type, 
1209                                   bi->tvb, ie_start_offset, ie->total_length, 
1210                                   ie->iei, ie->name);
1211 }
1212
1213 static void
1214 bssgp_proto_handoff(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset, dissector_handle_t handle) {
1215   tvbuff_t *next_tvb;
1216
1217   next_tvb = tvb_new_subset(bi->tvb, bi->offset, -1, -1);
1218
1219   if (bi->bssgp_tree) {
1220     bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1221   }
1222   if (handle) {
1223     call_dissector(handle, next_tvb, bi->pinfo, bi->parent_tree);    
1224   }
1225   else if (data_handle) {
1226     call_dissector(data_handle, next_tvb, bi->pinfo, bi->parent_tree);
1227   }
1228 }
1229
1230 static void 
1231 decode_nri(proto_tree *tf, build_info_t *bi, guint32 tmsi_tlli) {
1232   const guint32 LOCAL_TLLI_MASK = 0xc0000000;
1233   const guint32 FOREIGN_TLLI_MASK = 0x80000000;
1234   guint16 nri;
1235   
1236   if (bssgp_decode_nri && (bssgp_nri_length != 0) && 
1237     (((tmsi_tlli & LOCAL_TLLI_MASK) == LOCAL_TLLI_MASK) ||
1238      ((tmsi_tlli & FOREIGN_TLLI_MASK) == FOREIGN_TLLI_MASK))) {
1239     nri = get_masked_guint32(tmsi_tlli, make_mask32( (guint8) bssgp_nri_length, 8));
1240     if (tf) {
1241       proto_tree_add_uint_hidden(tf, hf_bssgp_nri, bi->tvb, bi->offset, 4, 
1242       nri);     
1243     }
1244     if (check_col(bi->pinfo->cinfo, COL_INFO)) {
1245       col_append_sep_fstr(bi->pinfo->cinfo, COL_INFO, BSSGP_SEP, 
1246           "NRI %u", nri);
1247         }
1248   }
1249 }
1250
1251 static void
1252 decode_mobile_identity(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1253 #define MAX_NUM_IMSI_DIGITS 15
1254   const guint8 MASK_ODD_EVEN_INDICATION = 0x08;
1255   const guint8 MASK_TYPE_OF_IDENTITY = 0x07;
1256   const guint8 ODD = 1;
1257   proto_item *ti = NULL, *pi;
1258   proto_tree *tf = NULL;
1259   guint8 data, odd_even, type, num_digits, i;
1260   int hf_id;
1261   guint32 tmsi;
1262   guint8 digits[MAX_NUM_IMSI_DIGITS];
1263   char digits_str[MAX_NUM_IMSI_DIGITS + 1];
1264
1265   static const value_string tab_type_of_identity[] = {
1266     { BSSGP_MOBILE_IDENTITY_TYPE_IMSI, "IMSI" },
1267     { BSSGP_MOBILE_IDENTITY_TYPE_IMEI, "IMEI" },
1268     { BSSGP_MOBILE_IDENTITY_TYPE_IMEISV, "IMEISV" },
1269     { BSSGP_MOBILE_IDENTITY_TYPE_TMSI_PTMSI, "TMSI//P-TMSI" },
1270     { BSSGP_MOBILE_IDENTITY_TYPE_NO_IDENTITY, "No identity" },
1271     { 0, NULL },
1272     /* Otherwise "Reserved" */
1273   };
1274
1275   digits_str[0] = '\0'; /* conceivably num_digits below could be zero */
1276
1277   if (bi->bssgp_tree) {
1278     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1279     tf = proto_item_add_subtree(ti, ett_bssgp_mobile_identity);
1280   }
1281   data = tvb_get_guint8(bi->tvb, bi->offset);
1282   odd_even = get_masked_guint8(data, MASK_ODD_EVEN_INDICATION);
1283
1284   if (bi->bssgp_tree) {
1285     pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, 
1286                                   MASK_ODD_EVEN_INDICATION);
1287     proto_item_append_text(pi, "Odd/Even Indication: %s number of identity digits%s",
1288                         odd_even == ODD ? "Odd" : "Even",
1289                         odd_even == ODD ? "" : " and also when the TMSI/P_TMSI is used");
1290   }
1291   type = get_masked_guint8(data, MASK_TYPE_OF_IDENTITY);
1292
1293   if (bi->bssgp_tree) {
1294     pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, 
1295                                   MASK_TYPE_OF_IDENTITY);
1296     proto_item_append_text(pi, "Type of Identity: %s",
1297                            val_to_str(type, tab_type_of_identity, 
1298                                       "Reserved"));
1299   }
1300   bi->offset++;
1301   switch (type) {
1302   case BSSGP_MOBILE_IDENTITY_TYPE_IMSI:
1303   case BSSGP_MOBILE_IDENTITY_TYPE_IMEI:
1304   case BSSGP_MOBILE_IDENTITY_TYPE_IMEISV:
1305     num_digits = 1 + (ie->value_length - 1) * 2;
1306     if (odd_even != ODD ) num_digits--;
1307     if (num_digits > MAX_NUM_IMSI_DIGITS) THROW(ReportedBoundsError);
1308
1309     i = 0;
1310     digits[i] = get_masked_guint8(data, BSSGP_MASK_LEFT_OCTET_HALF);
1311
1312     i++;
1313     while (TRUE) {
1314       data = tvb_get_guint8(bi->tvb, bi->offset);
1315
1316       digits[i] = get_masked_guint8(data, BSSGP_MASK_RIGHT_OCTET_HALF);
1317       i++;
1318       if (i >= num_digits) break;
1319
1320       digits[i] = get_masked_guint8(data, BSSGP_MASK_LEFT_OCTET_HALF);
1321       i++;
1322       if (i >= num_digits) break;
1323       bi->offset++;
1324     }
1325     bi->offset++;
1326     
1327     if (bi->bssgp_tree) {
1328       proto_item_append_text(ti, ": ");
1329       for (i = 0; i < num_digits; i++) {
1330         proto_item_append_text(ti, "%u", digits[i]);
1331         g_snprintf(&digits_str[i], 2, "%u", digits[i]);
1332       }
1333       switch (type) {
1334       case BSSGP_MOBILE_IDENTITY_TYPE_IMSI:
1335         hf_id = hf_bssgp_imsi;
1336         break;
1337       case BSSGP_MOBILE_IDENTITY_TYPE_IMEI:
1338         hf_id = hf_bssgp_imei;
1339         break;
1340       case BSSGP_MOBILE_IDENTITY_TYPE_IMEISV:
1341         hf_id = hf_bssgp_imeisv;
1342         break;
1343       default:
1344         DISSECTOR_ASSERT_NOT_REACHED();
1345         hf_id = -1;
1346         break;
1347       }
1348           if (tf)
1349                   proto_tree_add_string(tf, hf_id, bi->tvb, ie_start_offset + 2, ((num_digits/2)+1), digits_str);
1350
1351     } 
1352     if (check_col(bi->pinfo->cinfo, COL_INFO)) {
1353       col_append_sep_fstr(bi->pinfo->cinfo, COL_INFO, BSSGP_SEP, "%s %s", 
1354                           val_to_str(type, tab_type_of_identity, 
1355                                      "Mobile identity unknown"),
1356                           digits_str);
1357     }
1358     break;
1359   case BSSGP_MOBILE_IDENTITY_TYPE_TMSI_PTMSI:
1360     tmsi = tvb_get_ntohl(bi->tvb, bi->offset);
1361     if (check_col(bi->pinfo->cinfo, COL_INFO)) {
1362       col_append_sep_fstr(bi->pinfo->cinfo, COL_INFO, BSSGP_SEP, 
1363                           "TMSI/P-TMSI %0x04x", tmsi);
1364     }
1365     if (bi->bssgp_tree) {
1366       proto_tree_add_item(tf, hf_bssgp_tmsi_ptmsi, bi->tvb, bi->offset, 4, 
1367                           BSSGP_LITTLE_ENDIAN);
1368       proto_item_append_text(ti, ": %#04x", tmsi);
1369     }
1370     decode_nri(tf, bi, tmsi);
1371     bi->offset += 4;
1372     break;
1373   default:
1374     ;    
1375   }
1376 #undef MAX_NUM_IMSI_DIGITS
1377 }
1378
1379 static char*
1380 decode_mcc_mnc(build_info_t *bi, proto_tree *parent_tree) {
1381 #define RES_LEN 15
1382   const guint8 UNUSED_MNC3 = 0x0f;
1383   proto_item *pi_mcc, *pi_mnc;
1384   guint8 mcc1, mcc2, mcc3, mnc1, mnc2, mnc3, data;
1385   guint16 start_offset, mcc, mnc;
1386   static char mcc_mnc[RES_LEN];
1387
1388   start_offset = bi->offset;
1389
1390   pi_mcc = proto_tree_add_text(parent_tree, bi->tvb, bi->offset, 3, "MCC");
1391   pi_mnc = proto_tree_add_text(parent_tree, bi->tvb, bi->offset, 3, "MNC");
1392
1393   data = tvb_get_guint8(bi->tvb, bi->offset);
1394   mcc2 = get_masked_guint8(data, BSSGP_MASK_LEFT_OCTET_HALF);
1395   mcc1 = get_masked_guint8(data, BSSGP_MASK_RIGHT_OCTET_HALF);
1396   bi->offset++;
1397   
1398   data = tvb_get_guint8(bi->tvb, bi->offset);
1399   mnc3 = get_masked_guint8(data, BSSGP_MASK_LEFT_OCTET_HALF);
1400   mcc3 = get_masked_guint8(data, BSSGP_MASK_RIGHT_OCTET_HALF);
1401   bi->offset++;
1402
1403   data = tvb_get_guint8(bi->tvb, bi->offset);
1404   mnc2 = get_masked_guint8(data, BSSGP_MASK_LEFT_OCTET_HALF);
1405   mnc1 = get_masked_guint8(data, BSSGP_MASK_RIGHT_OCTET_HALF);
1406   bi->offset++;
1407
1408   /* XXX: If mxci out of range the ms should transmit the values using full hexademical encoding? */
1409
1410   /* XXX: Interpretation of mcci? */
1411   mcc = 100 * mcc1 + 10 * mcc2 + mcc3;
1412
1413   /* XXX: Interpretation of mnci? */
1414   mnc = 10 * mnc1 + mnc2;
1415  
1416   if (mnc3 != UNUSED_MNC3) {
1417     mnc += 10 * mnc + mnc3;
1418   }
1419
1420   proto_tree_add_uint_hidden(bi->bssgp_tree, hf_bssgp_mcc, 
1421                              bi->tvb, start_offset, 3, mcc);
1422   proto_tree_add_uint_hidden(bi->bssgp_tree, hf_bssgp_mnc, 
1423                              bi->tvb, start_offset, 3, mnc);
1424
1425   proto_item_append_text(pi_mcc, ": %03u", mcc);
1426
1427   if (mnc3 != UNUSED_MNC3) {
1428     /* Three digits mnc */
1429     proto_item_append_text(pi_mnc, ": %03u", mnc);
1430     g_snprintf(mcc_mnc, RES_LEN, "%u-%03u", mcc, mnc);
1431   }
1432   else {
1433     /* Two digits mnc */
1434     proto_item_append_text(pi_mnc, ": %02u", mnc);
1435     g_snprintf(mcc_mnc, RES_LEN, "%u-%02u", mcc, mnc);
1436   }
1437 #undef RES_LEN
1438   return mcc_mnc;
1439 }
1440
1441 static char*
1442 decode_lai(build_info_t *bi, proto_tree *parent_tree) {
1443 #define RES_LEN 15
1444   guint16 lac;
1445   char *mcc_mnc;
1446   static char lai[RES_LEN];
1447   
1448   mcc_mnc = decode_mcc_mnc(bi, parent_tree);
1449
1450   lac = tvb_get_ntohs(bi->tvb, bi->offset);
1451   proto_tree_add_item(parent_tree, hf_bssgp_lac, 
1452                       bi->tvb, bi->offset, 2, BSSGP_LITTLE_ENDIAN);
1453   bi->offset += 2;
1454
1455   g_snprintf(lai, RES_LEN, "%s-%u", mcc_mnc, lac);
1456 #undef RES_LEN
1457   return lai;
1458 }
1459
1460 static char*
1461 decode_rai(build_info_t *bi, proto_tree *parent_tree) {
1462 #define RES_LEN 20
1463   guint8 rac;
1464   static char rai[RES_LEN];
1465   char *lai = decode_lai(bi, parent_tree);  
1466  
1467   rac = tvb_get_guint8(bi->tvb, bi->offset);
1468   proto_tree_add_item(parent_tree, hf_bssgp_rac, bi->tvb, bi->offset, 1, BSSGP_LITTLE_ENDIAN);
1469   bi->offset++;
1470
1471   g_snprintf(rai, RES_LEN, "%s-%u", lai, rac);
1472 #undef RES_LEN
1473   return rai;
1474 }
1475
1476 static char*
1477 decode_rai_ci(build_info_t *bi, proto_tree *parent_tree) {
1478 #define RES_LEN 30
1479   char *rai;
1480   static char rai_ci[RES_LEN];
1481   guint16 ci;
1482
1483   rai = decode_rai(bi, parent_tree);
1484
1485   ci = tvb_get_ntohs(bi->tvb, bi->offset);
1486   proto_tree_add_item(parent_tree, hf_bssgp_ci, 
1487                       bi->tvb, bi->offset, 2, BSSGP_LITTLE_ENDIAN);
1488   bi->offset += 2;
1489
1490   g_snprintf(rai_ci, RES_LEN, "RAI %s, CI %u", rai, ci);
1491 #undef RES_LEN
1492   return rai_ci;
1493 }
1494
1495 static void
1496 bssgp_pi_append_queuing_delay(proto_item *pi, tvbuff_t *tvb, int offset) {
1497   const guint16 INFINITE_DELAY = 0xffff;
1498   guint16 value = tvb_get_ntohs(tvb, offset);
1499   if (value == INFINITE_DELAY) {
1500     proto_item_append_text(pi, ": Infinite delay (%#4x)", value);
1501   }
1502   else {
1503     proto_item_append_text(pi, ": %u centi-seconds delay", value);
1504   }
1505 }
1506
1507 static void 
1508 bssgp_pi_append_bucket_leak_rate(proto_item *pi, tvbuff_t *tvb, int offset) {
1509   guint16 value = tvb_get_ntohs(tvb, offset);
1510   proto_item_append_text(pi, ": %u bytes", value * 100);
1511 }
1512
1513 static void 
1514 bssgp_pi_append_bucket_size(proto_item *pi, tvbuff_t *tvb, int offset) {
1515   guint16 value = tvb_get_ntohs(tvb, offset);
1516   proto_item_append_text(pi, ": %u bytes", value * 100);
1517 }
1518
1519 static void 
1520 bssgp_pi_append_bucket_full_ratio(proto_item *pi, tvbuff_t *tvb, int offset) {
1521   guint8 value = tvb_get_guint8(tvb, offset);
1522   proto_item_append_text(pi, ": %.2f * Bmax ", value / 100.0);
1523 }
1524
1525 static void
1526 bssgp_pi_append_pfi(proto_item *pi, tvbuff_t *tvb, int offset) {
1527   const guint8 MASK_PFI = 0x7f;
1528   guint8 value;
1529
1530   static const value_string tab_pfi[] = {
1531     { 0, "Best effort" },
1532     { 1, "Signaling" },
1533     { 2, "SMS" },
1534     { 3, "TOMB" },
1535     { 4, "Reserved" },
1536     { 5, "Reserved" },
1537     { 6, "Reserved" },
1538     { 7, "Reserved" },
1539     { 0, NULL },
1540     /* Otherwise "Dynamically assigned */
1541   };
1542   value = tvb_get_masked_guint8(tvb, offset, MASK_PFI);
1543   proto_item_append_text(pi, 
1544                          val_to_str(value, tab_pfi, "Dynamically assigned"));
1545 }
1546
1547 static void 
1548 decode_pfi(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1549   proto_item *ti;
1550   if (bi->bssgp_tree) {
1551     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1552     bssgp_pi_append_pfi(ti, bi->tvb, bi->offset);
1553   }
1554   bi->offset += ie->value_length;
1555 }
1556
1557 static void
1558 decode_queuing_delay(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1559   proto_item *ti;
1560   if (bi->bssgp_tree) {
1561     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1562     bssgp_pi_append_queuing_delay(ti, bi->tvb, bi->offset);
1563   }
1564   bi->offset += ie->value_length;
1565 }
1566
1567 static void 
1568 decode_bucket_size(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1569   proto_item *ti;
1570   if (bi->bssgp_tree) {
1571     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1572     bssgp_pi_append_bucket_size(ti, bi->tvb, bi->offset);
1573   }
1574   bi->offset += ie->value_length;
1575 }
1576
1577 static void 
1578 decode_bucket_leak_rate(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1579   proto_item *ti;
1580   if (bi->bssgp_tree) {
1581     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1582     bssgp_pi_append_bucket_leak_rate(ti, bi->tvb, bi->offset);
1583   }
1584   bi->offset += ie->value_length;
1585 }
1586
1587 static void 
1588 get_value_length(bssgp_ie_t *ie, build_info_t *bi) {
1589   /* length indicator in bit 8, 0 => two bytes, 1 => one byte */
1590   const guint8 MASK_LENGTH_INDICATOR = 0x80;
1591   const guint8 MASK_ONE_BYTE_LENGTH = 0x7f;
1592   guint8 length_len;
1593   guint16 length;
1594   
1595   length = tvb_get_guint8(bi->tvb, bi->offset);
1596   length_len = 1;
1597   
1598   if (length & MASK_LENGTH_INDICATOR) {
1599     length &= MASK_ONE_BYTE_LENGTH;
1600   }
1601   else {
1602     length_len++;
1603     length <<= 8;
1604     length |= tvb_get_guint8(bi->tvb, bi->offset);
1605   }
1606   ie->value_length = length;
1607   ie->total_length += length_len + length;
1608   bi->offset += length_len;
1609 }
1610
1611 static void
1612 decode_simple_ie(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset, 
1613                  const char *pre_str, const char *post_str, 
1614                  gboolean show_as_dec) {
1615   /* XXX: Allow mask? */
1616   proto_item *ti;
1617   guint32 value;
1618
1619   switch (ie->value_length) {
1620   case 1: value = tvb_get_guint8(bi->tvb, bi->offset); break;
1621   case 2: value = tvb_get_ntohs(bi->tvb, bi->offset); break;
1622   case 3: value = tvb_get_ntoh24(bi->tvb, bi->offset); break;
1623   case 4: value = tvb_get_ntohl(bi->tvb, bi->offset); break;
1624   default: value = 0; break;
1625   }
1626
1627   if (bi->bssgp_tree) {
1628     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1629     
1630     proto_item_append_text(ti, ": ");
1631     
1632     if (pre_str) {
1633       proto_item_append_text(ti, "%s ", pre_str);
1634     }
1635     if (show_as_dec) {
1636       proto_item_append_text(ti, "%u", value);
1637     }
1638     else {
1639       switch (ie->value_length) {
1640       case 1: proto_item_append_text(ti, "%#1x", value); break;
1641       case 2: proto_item_append_text(ti, "%#2x", value); break;
1642       case 3: proto_item_append_text(ti, "%#3x", value); break;
1643       case 4: proto_item_append_text(ti, "%#4x", value); break;
1644       default: ;
1645       }
1646     }
1647     proto_item_append_text(ti, " %s", post_str);
1648   }
1649   bi->offset += ie->value_length;
1650 }
1651
1652 static int 
1653 check_correct_iei(bssgp_ie_t *ie, build_info_t *bi) {
1654   guint8 fetched_iei = tvb_get_guint8(bi->tvb, bi->offset);
1655
1656 #ifdef BSSGP_DEBUG
1657   if (fetched_iei != ie->iei) {
1658   proto_tree_add_text(bi->bssgp_tree, bi->tvb, bi->offset, 1, 
1659                         "Tried IEI %s (%#02x), found IEI %s (%#02x)", 
1660                         val_to_str(ie->iei, tab_bssgp_ie_types, "Unknown"), 
1661                         ie->iei, 
1662                         val_to_str(fetched_iei, tab_bssgp_ie_types, "Unknown"), 
1663                         fetched_iei);
1664   }
1665 #endif
1666   return (fetched_iei == ie->iei);
1667 }
1668
1669 static void 
1670 decode_iei_alignment_octets(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1671   proto_item *ti;
1672   if (bi->bssgp_tree) {
1673     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1674     proto_item_append_text(ti, " (%u bytes)", ie->value_length);
1675   }  
1676   bi->offset += ie->value_length;
1677 }
1678
1679 static void 
1680 decode_iei_bvci(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1681   proto_item *ti;
1682   guint16 bvci;
1683
1684   bvci = tvb_get_ntohs(bi->tvb, bi->offset);
1685
1686   if (bi->bssgp_tree) {
1687     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1688     proto_item_append_text(ti, ": %u", bvci);
1689     proto_tree_add_item_hidden(bi->bssgp_tree, hf_bssgp_bvci, 
1690                                bi->tvb, bi->offset, ie->value_length, 
1691                                BSSGP_LITTLE_ENDIAN);
1692   }
1693   bi->offset += ie->value_length;
1694
1695   if (check_col(bi->pinfo->cinfo, COL_INFO)) {
1696     col_append_sep_fstr(bi->pinfo->cinfo, COL_INFO, BSSGP_SEP, 
1697                         "BVCI %u", bvci);
1698   }
1699 }
1700
1701 static void 
1702 decode_iei_cause(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1703   proto_item *ti;
1704   guint8 value;
1705
1706   static const value_string tab_cause[] = {
1707     { 0x00, "Processor overload" },
1708     { 0x01, "Equipment failure" },
1709     { 0x02, "Transit network service failure" },
1710     { 0x03, "Network service transmission capacity modified from zero kbps to greater than zero kbps" },
1711     { 0x04, "Unknown MS" },
1712     { 0x05, "BVCI unknown" },
1713     { 0x06, "Cell traffic congestion" },
1714     { 0x07, "SGSN congestion" },
1715     { 0x08, "O&M intervention" },
1716     { 0x09, "BVCI blocked" },
1717     { 0x0a, "PFC create failure" },
1718     { 0x0b, "PFC preempted" },
1719     { 0x0c, "ABQP no more supported" },
1720     { 0x20, "Semantically incorrect PDU" },
1721     { 0x21, "Invalid mandatory information" },
1722     { 0x22, "Missing mandatory IE" },
1723     { 0x23, "Missing conditional IE" },
1724     { 0x24, "Unexpected conditional IE" },
1725     { 0x25, "Conditional IE error" },
1726     { 0x26, "PDU not compatible with the protocol state" },
1727     { 0x27, "Protocol error - unspecified" },
1728     { 0x28, "PDU not compatible with the feature set" },
1729     { 0x29, "Requested information not available" },
1730     { 0x2a, "Unknown destination address" },
1731     { 0x2b, "Unknown RIM application identity" },
1732     { 0x2c, "Invalid container unit information" },
1733     { 0x2d, "PFC queing" },
1734     { 0x2e, "PFC created successfully" },
1735     { 0,    NULL },
1736   };
1737
1738   if (bi->bssgp_tree) {
1739     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1740     value = tvb_get_guint8(bi->tvb, bi->offset);
1741     proto_item_append_text(ti, ": %s (%#02x)", 
1742                            val_to_str(value, tab_cause, 
1743                                       "Protocol error - unspecified"),
1744                            value);
1745   }
1746   bi->offset += ie->value_length;
1747 }
1748
1749 static void 
1750 decode_iei_cell_identifier(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1751   proto_item *ti;
1752   proto_tree *tf;
1753   char *rai_ci;
1754
1755   if (bi->bssgp_tree) {
1756     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1757     tf = proto_item_add_subtree(ti, ett_bssgp_cell_identifier);
1758     
1759     rai_ci = decode_rai_ci(bi, tf);
1760     proto_item_append_text(ti, ": %s", rai_ci);
1761   }else{
1762   bi->offset += ie->value_length;
1763   }
1764 }
1765
1766 static void 
1767 decode_iei_channel_needed(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1768   /* XXX: 'If this IE is used for only one MS, the the first CHANNEL field 
1769      is used and the second CHANNEL field is spare.' How know? */
1770   const guint8 MASK_CH1 = 0x03;
1771   const guint8 MASK_CH2 = 0x0c;
1772   proto_item *ti;
1773   guint8 data, ch1, ch2;
1774   
1775   if (bi->bssgp_tree) {
1776     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1777     data = tvb_get_guint8(bi->tvb, bi->offset);
1778     ch1 = get_masked_guint8(data, MASK_CH1);
1779     ch2 = get_masked_guint8(data, MASK_CH2);
1780     proto_item_append_text(ti, ": Ch1: %s (%u), Ch2: %s (%u)", 
1781                            translate_channel_needed(ch1),
1782                            ch1,
1783                            translate_channel_needed(ch2),
1784                            ch2);
1785   }
1786   bi->offset += ie->value_length;
1787 }
1788
1789 static void 
1790 decode_iei_drx_parameters(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1791   const guint8 MASK_CYCLE_LENGTH_COEFFICIENT = 0xf0;
1792   const guint8 MASK_SPLIT_ON_CCCH = 0x08;
1793   const guint8 MASK_NON_DRX_TIMER = 0x07;
1794   proto_item *ti, *pi;
1795   proto_tree *tf;
1796   guint8 data, value;
1797   guint16 cycle_value;
1798
1799   static const value_string tab_non_drx_timer[] = {
1800     { 0, "No non-DRX mode after transfer state" },
1801     { 1, "Max. 1 sec non-DRX mode after transfer state" },
1802     { 2, "Max. 2 sec non-DRX mode after transfer state" },
1803     { 3, "Max. 4 sec non-DRX mode after transfer state" },
1804     { 4, "Max. 8 sec non-DRX mode after transfer state" },
1805     { 5, "Max. 16 sec non-DRX mode after transfer state" },
1806     { 6, "Max. 32 sec non-DRX mode after transfer state" },
1807     { 7, "Max. 64 sec non-DRX mode after transfer state" },
1808     { 0, NULL},
1809     /* Otherwise "" */
1810   };
1811
1812   static const value_string tab_cycle_length_coefficient[] = {
1813     { 0, "CN Specific DRX cycle length coefficient not specified by the MS, ie. the system information value 'CN domain specific DRX cycle length' is used" },
1814     { 6, "CN Specific DRX cycle length coefficient 6" },
1815     { 7, "CN Specific DRX cycle length coefficient 7" },
1816     { 8, "CN Specific DRX cycle length coefficient 8" },
1817     { 9, "CN Specific DRX cycle length coefficient 9" },
1818     { 0, NULL },
1819     /* Otherwise "CN Specific DRX cycle length coefficient not specified by the MS" */
1820   };
1821
1822   if (!bi->bssgp_tree) {
1823     bi->offset += ie->value_length;
1824     return;
1825   }
1826   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1827   tf = proto_item_add_subtree(ti, ett_bssgp_drx_parameters);
1828
1829   value = tvb_get_guint8(bi->tvb, bi->offset);
1830   proto_tree_add_text(tf, bi->tvb, bi->offset, 1, 
1831                       "SPLIT PG CYCLE: code %u", value);
1832   if ((value >= 1) && (value <= 64)) {
1833     cycle_value = value;
1834   }
1835   else {
1836     switch (value) {
1837     case 0: cycle_value = 704; break;
1838     case 65: cycle_value = 71; break;
1839     case 66: cycle_value = 72; break;
1840     case 67: cycle_value = 74; break;
1841     case 68: cycle_value = 75; break;
1842     case 69: cycle_value = 77; break;
1843     case 70: cycle_value = 79; break;
1844     case 71: cycle_value = 80; break;
1845     case 72: cycle_value = 83; break;
1846     case 73: cycle_value = 86; break;
1847     case 74: cycle_value = 88; break;
1848     case 75: cycle_value = 90; break;
1849     case 76: cycle_value = 92; break;
1850     case 77: cycle_value = 96; break;
1851     case 78: cycle_value = 101; break;
1852     case 79: cycle_value = 103; break;
1853     case 80: cycle_value = 107; break;
1854     case 81: cycle_value = 112; break;
1855     case 82: cycle_value = 116; break;
1856     case 83: cycle_value = 118; break;
1857     case 84: cycle_value = 128; break;
1858     case 85: cycle_value = 141; break;
1859     case 86: cycle_value = 144; break;
1860     case 87: cycle_value = 150; break;
1861     case 88: cycle_value = 160; break;
1862     case 89: cycle_value = 171; break;
1863     case 90: cycle_value = 176; break;
1864     case 91: cycle_value = 192; break;
1865     case 92: cycle_value = 214; break;
1866     case 93: cycle_value = 224; break;
1867     case 94: cycle_value = 235; break;
1868     case 95: cycle_value = 256; break;
1869     case 96: cycle_value = 288; break;
1870     case 97: cycle_value = 320; break;
1871     case 98: cycle_value = 352; break;
1872     default:
1873       cycle_value = 1;
1874     }
1875     proto_item_append_text(ti, " => value %u", cycle_value);
1876     if (cycle_value == 704) {
1877       proto_item_append_text(ti, " (equivalent to no DRX)");
1878     }
1879   }
1880   bi->offset++;
1881
1882   data = tvb_get_guint8(bi->tvb, bi->offset);
1883
1884   value = get_masked_guint8(data, MASK_CYCLE_LENGTH_COEFFICIENT);
1885   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, 
1886                                 MASK_CYCLE_LENGTH_COEFFICIENT);
1887   proto_item_append_text(pi, "CN specific DRX cycle length coefficient: %s (%#02x)",
1888                          val_to_str(value, tab_cycle_length_coefficient,
1889                                     "Not specified by the MS"),
1890                          value);
1891
1892   value = get_masked_guint8(data, MASK_SPLIT_ON_CCCH);
1893   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_SPLIT_ON_CCCH);
1894   proto_item_append_text(pi, "SPLIT on CCCH: Split pg cycle on CCCH is%s supported by the mobile station",
1895                          value == 0 ? " not" : "");
1896   
1897   value = get_masked_guint8(data, MASK_NON_DRX_TIMER);
1898   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_NON_DRX_TIMER);
1899   proto_item_append_text(pi, "Non-DRX Timer: %s (%#x)",
1900                          val_to_str(value, tab_non_drx_timer, ""), value);
1901   bi->offset++;
1902 }
1903
1904 static void 
1905 decode_iei_emlpp_priority(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1906   const guint8 MASK_CALL_PRIORITY = 0x07;
1907   proto_item *ti;
1908   guint8 data, value;
1909
1910   static const value_string tab_call_priority[] = {
1911     { 0, "No priority applied" },
1912     { 1, "Call priority level 4" },
1913     { 2, "Call priority level 3" },
1914     { 3, "Call priority level 2" },
1915     { 4, "Call priority level 1" },
1916     { 5, "Call priority level 0" },
1917     { 6, "Call priority level B" },
1918     { 7, "Call priority level A" },
1919     { 0, NULL },
1920   };
1921
1922   if (bi->bssgp_tree) {
1923     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1924     data = tvb_get_guint8(bi->tvb, bi->offset);
1925     value = get_masked_guint8(data, MASK_CALL_PRIORITY);
1926     proto_item_append_text(ti, ": %s", 
1927                            val_to_str(value, tab_call_priority, ""));
1928   }
1929   bi->offset += ie->value_length;
1930 }
1931
1932 static void 
1933 decode_iei_flush_action(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1934   proto_item *ti;
1935   guint8 value;
1936
1937   static const value_string tab_action_value[] = {
1938     { 0x00, "LLC-PDU(s) deleted" },
1939     { 0x01, "LLC-PDU(s) transferred" },
1940     { 0,    NULL },
1941     /* Otherwise "Reserved" */
1942   };
1943
1944   if (bi->bssgp_tree) {
1945     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1946     value = tvb_get_guint8(bi->tvb, bi->offset);
1947     proto_item_append_text(ti, ": %s (%u)",
1948                            val_to_str(value, tab_action_value, "Reserved"),
1949                            value);
1950
1951   }
1952   bi->offset += ie->value_length;
1953 }
1954
1955 static void 
1956 decode_iei_llc_frames_discarded(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1957   decode_simple_ie(ie, bi, ie_start_offset, "", " frames discarded", TRUE);
1958 }
1959
1960 static void 
1961 decode_iei_location_area(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
1962   proto_item *ti;
1963   proto_tree *tf;
1964   char *lai;
1965
1966   if (!bi->bssgp_tree) {
1967     bi->offset += ie->value_length;
1968     return;
1969   }
1970   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
1971   tf = proto_item_add_subtree(ti, ett_bssgp_location_area);
1972
1973   lai = decode_rai(bi, tf);
1974   proto_item_append_text(ti, ": LAI %s", lai);
1975 }
1976
1977 static void
1978 decode_msrac_additional_access_technologies(proto_tree *tree, tvbuff_t *tvb, 
1979                                             guint64 bo, guint32 length _U_) {
1980   proto_item *pi;
1981   guint8 value;
1982   guint8 bl; /* Bit length */
1983
1984   bl = 4;
1985   value = tvb_get_bits8(tvb, bo, bl);
1986   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
1987   bo += bl;
1988   proto_item_append_text(pi, "Access Technology Type: %s (%#01x)", 
1989                          translate_msrac_access_technology_type(value), 
1990                          value);
1991
1992   bl = 3;
1993   value = tvb_get_bits8(tvb, bo, bl);
1994   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
1995   bo += bl;
1996   proto_item_append_text(pi, "GMSK Power Class: Power class %u", value);
1997
1998   bl = 2;
1999   value = tvb_get_bits8(tvb, bo, bl);
2000   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2001   bo += bl;
2002   proto_item_append_text(pi, "8PSK Power Class");
2003   if (value == 0) {
2004     proto_item_append_text(pi, ": 8PSK modulation not supported for uplink");
2005   }
2006   else{
2007     proto_item_append_text(pi, ": Power Class E%u", value);
2008   }
2009 }
2010
2011 static gboolean
2012 struct_bits_exist(guint64 start_bo, guint32 struct_length, 
2013                   guint64 bo, guint32 num_bits) {
2014   return (bo + num_bits) <= (start_bo + struct_length);
2015
2016 }
2017
2018 static void 
2019 decode_msrac_access_capabilities(proto_tree *tree, tvbuff_t *tvb,
2020                                  guint64 bo, guint32 struct_length) {
2021   /* Error handling:
2022      - Struct too short: assume features do not exist
2023      - Struct too long: ignore data and jump to next Access Technology */
2024   proto_item *ti, *pi;
2025   proto_tree *tf;
2026   guint8 value, i;
2027   guint8 dgmsc = 0, demsc = 0; /* DTM GPRS/EGPRS Multi Slot Class */
2028   guint8 bl; /* Bit length */
2029   guint64 start_bo = bo;
2030
2031   /* RF Power Capability */
2032   bl = 3;
2033   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2034   value = tvb_get_bits8(tvb, bo, bl);
2035   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2036   bo += bl;
2037   proto_item_append_text(pi, "RF Power Capability");
2038   if (value == 0) {
2039     proto_item_append_text(pi, ": The MS does not support any GSM access technology type");
2040   }
2041   else {
2042     proto_item_append_text(pi, ": GMSK Power Class %u", value);
2043   }
2044
2045   /* A5 bits */
2046   bl = 1;
2047   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2048   value = tvb_get_bits8(tvb, bo, bl);
2049   if (value == 1) {
2050     bo += bl;
2051     bl = 7;
2052     if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2053     value = tvb_get_bits8(tvb, bo, bl);
2054     ti = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2055     proto_item_append_text(ti, "A5 Bits: %#02x", value); 
2056     tf = proto_item_add_subtree(ti, ett_bssgp_msrac_a5_bits);
2057     for (i = 0; i < bl; i++) {
2058       pi = bit_proto_tree_add_bit_field8(tf, tvb, bo + i, 1);
2059       proto_item_append_text(pi, "Encryption algorithm A5/%u%s available",
2060                              i + 1,
2061                              value & (0x40 >> i) ? "" : " not");
2062     }
2063     bo += bl;
2064   }
2065   else {
2066     pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2067     bo += bl;
2068     proto_item_append_text(pi, "A5 bits: Same as in the immediately preceding Access capabilities field within this IE"); 
2069   }
2070
2071   /* ES IND */
2072   bl = 1;
2073   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2074   value = tvb_get_bits8(tvb, bo, bl);
2075   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2076   bo += bl;
2077   proto_item_append_text(pi, "ESD IND: Controlled Early Classmark Sending"" option is%s implemented",
2078                          value == 0 ? " not" : "");
2079
2080   /* PS */
2081   bl = 1;
2082   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2083   value = tvb_get_bits8(tvb, bo, bl);
2084   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2085   bo += bl;
2086   proto_item_append_text(pi, "PS: PS capability%s present",
2087                          value == 0 ? " not" : "");
2088
2089   /* VGCS */
2090   bl = 1;
2091   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2092   value = tvb_get_bits8(tvb, bo, bl);
2093   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2094   bo += bl;
2095   proto_item_append_text(pi, "VBCS:%s VGCS capability %s notifications wanted",
2096                          value == 0 ? " No" : "",
2097                          value == 0 ? "or no" : "and");
2098
2099   /* VBS */
2100   bl = 1;
2101   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2102   value = tvb_get_bits8(tvb, bo, bl);
2103   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2104   bo += bl;
2105   proto_item_append_text(pi, "VBS:%s VBS capability %s notifications wanted",
2106                          value == 0 ? " No" : "",
2107                          value == 0 ? "or no" : "and");
2108
2109   /* Multislot capability */
2110   /* XXX: 'Error: struct too short, assume features do not exist'
2111      No length is given! */
2112   bl = 1;
2113   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2114   value = tvb_get_bits8(tvb, bo, bl);
2115   if (value == 1) {
2116     bo += bl;
2117     bl = 1;
2118     if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2119     ti = bit_proto_tree_add_text(tree, tvb, bo, bl, "Multislot capability"); 
2120     /* Temporary length */
2121     bo += bl;
2122     tf = proto_item_add_subtree(ti, ett_bssgp_msrac_multislot_capability);
2123
2124     /* HSCSD Multislot Class */
2125     bl = 1;
2126     if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2127     value = tvb_get_bits8(tvb, bo, bl);
2128     bo += bl;
2129     if (value == 1) {
2130       bl = 5;
2131       if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2132       value = tvb_get_bits8(tvb, bo, bl);
2133       pi = bit_proto_tree_add_bit_field8(tf, tvb, bo, bl);
2134       bo += bl;
2135       proto_item_append_text(pi, "HSCSD Multislot Class");
2136       if ((value > 0 ) && (value < 19)) {
2137         proto_item_append_text(pi, ": Multislot Class %u", value);
2138       }
2139       else {
2140         proto_item_append_text(pi, ": Reserved");
2141       }
2142     }
2143     
2144     /* GPRS Multislot Class, GPRS Extended Dynamic Allocation Capability */
2145     bl = 1;
2146     if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2147     value = tvb_get_bits8(tvb, bo, bl);
2148     bo += bl;
2149     if (value == 1) {
2150       bl = 5;
2151       if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2152       value = tvb_get_bits8(tvb, bo, bl);
2153       pi = bit_proto_tree_add_bit_field8(tf, tvb, bo, bl);
2154       bo += bl;
2155       proto_item_append_text(pi, "GPRS Multislot Class: Multislot Class %u", 
2156                              value);
2157
2158       bl = 1;
2159       if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2160       value = tvb_get_bits8(tvb, bo, bl);
2161       pi = bit_proto_tree_add_bit_field8(tf, tvb, bo, bl);
2162       bo += bl;
2163       proto_item_append_text(pi, "GPRS Extended Dynamic Allocation Capability: Extended Dynamic Allocation for GPRS is%s implemented",
2164                              value == 0 ? " not" : "");
2165     }
2166
2167     /* SMS Value, SM Value */
2168     bl = 1;
2169     if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2170     value = tvb_get_bits8(tvb, bo, bl);
2171     bo += bl;
2172     if (value == 1) {
2173       bl = 4;
2174       if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2175       value = tvb_get_bits8(tvb, bo, bl);
2176       pi = bit_proto_tree_add_bit_field8(tf, tvb, bo, bl);
2177       bo += bl;
2178       proto_item_append_text(pi, 
2179                              "SMS_VALUE: %u/4 timeslot (~%u microseconds)", 
2180                              value + 1, (value + 1) * 144);
2181
2182       bl = 4;
2183       if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2184       value = tvb_get_bits8(tvb, bo, bl);
2185       pi = bit_proto_tree_add_bit_field8(tf, tvb, bo, bl);
2186       bo += bl;
2187       proto_item_append_text(pi, 
2188                              "SM_VALUE: %u/4 timeslot (~%u microseconds)", 
2189                              value + 1, (value + 1) * 144);
2190     }
2191     /* Additions in release 99 */
2192
2193     /* ECSD Multislot Class */
2194     bl = 1;
2195     if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2196     value = tvb_get_bits8(tvb, bo, bl);
2197     bo += bl;
2198     if (value == 1) {
2199       bl = 5;
2200       if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2201       value = tvb_get_bits8(tvb, bo, bl);
2202       pi = bit_proto_tree_add_bit_field8(tf, tvb, bo, bl);
2203       bo += bl;
2204       proto_item_append_text(pi, "ECSD Multislot Class");
2205       if ((value > 0 ) && (value < 19)) {
2206         proto_item_append_text(pi, ": Multislot Class %u", value);
2207       }
2208       else {
2209         proto_item_append_text(pi, ": Reserved");
2210       }
2211     }
2212
2213     /* EGPRS Multislot Class, EGPRS Extended Dynamic Allocation Capability */
2214     bl = 1;
2215     if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2216     value = tvb_get_bits8(tvb, bo, bl);
2217     bo += bl;
2218     if (value == 1) {
2219       bl = 5;
2220       if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2221       value = tvb_get_bits8(tvb, bo, bl);
2222       pi = bit_proto_tree_add_bit_field8(tf, tvb, bo, bl);
2223       bo += bl;
2224       proto_item_append_text(pi, "EGPRS Multislot Class: Multislot Class %u",
2225                              value);
2226
2227       bl = 1;
2228       if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2229       value = tvb_get_bits8(tvb, bo, bl);
2230       pi = bit_proto_tree_add_bit_field8(tf, tvb, bo, bl);
2231       bo += bl;
2232       proto_item_append_text(pi, "EGPRS Extended Dynamic Allocation Capability: Extended Dynamic Allocation for EGPRS is%s implemented",
2233                              value == 0 ? " not" : "");
2234     }
2235
2236     /* DTM GPRS Multislot Class */
2237     bl = 1;
2238     if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2239     value = tvb_get_bits8(tvb, bo, bl);
2240     bo += bl;
2241     if (value == 1) {
2242       bl = 2;
2243       if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2244       dgmsc = tvb_get_bits8(tvb, bo, bl);
2245       pi = bit_proto_tree_add_bit_field8(tf, tvb, bo, bl);
2246       bo += bl;
2247       proto_item_append_text(pi, "DTM GPRS Multislot Class: %s", 
2248                              translate_msrac_dtm_gprs_multislot_class(dgmsc));
2249
2250       /* Single slot DTM */
2251       bl = 1;
2252       if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2253       value = tvb_get_bits8(tvb, bo, bl);
2254       pi = bit_proto_tree_add_bit_field8(tf, tvb, bo, bl);
2255       bo += bl;
2256       proto_item_append_text(pi, 
2257                              "Single Slot DTM: Single slot DTM%s supported",
2258                              value == 0 ? " not" : "");
2259       
2260       /* DTM EGPRS Multislot Class */
2261       bl = 1;
2262       if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2263       value = tvb_get_bits8(tvb, bo, bl);
2264       bo += bl;
2265       if (value == 1) {
2266         bl = 2;
2267         if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2268         demsc = tvb_get_bits8(tvb, bo, bl);
2269         pi = bit_proto_tree_add_bit_field8(tf, tvb, bo, bl);
2270         bo += bl;
2271         proto_item_append_text(pi, "DTM EGPRS Multislot Class: %s", 
2272                                translate_msrac_dtm_gprs_multislot_class(demsc));
2273       }
2274     }
2275     proto_item_set_len(ti, get_num_octets_spanned(start_bo, 
2276                                                   (guint32) (bo - start_bo)));
2277   }
2278   else {
2279     pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2280     bo += bl;
2281     proto_item_append_text(pi, "Multislot capability: Same as in the immediately preceding Access capabilities field within this IE"); 
2282   }
2283
2284   /* Additions in release 99 */
2285
2286   /* 8PSK Power Capability */
2287   bl = 1;
2288   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2289   value = tvb_get_bits8(tvb, bo, bl);
2290   bo += bl;
2291   if (value == 1) {
2292     bl = 2;
2293     if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2294     value = tvb_get_bits8(tvb, bo, bl);
2295     pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2296     bo += bl;
2297     proto_item_append_text(pi, "8PSK Power Capability");
2298
2299     if (value == 0) {
2300       proto_item_append_text(pi, ": Reserved");
2301     }
2302     else{
2303       proto_item_append_text(pi, ": Power Class E%u", value);
2304     }
2305     proto_item_append_text(pi, ", 8PSK modulation capability in uplink");
2306   }
2307   
2308   /* COMPACT Interference Measurement Capability */
2309   bl = 1;
2310   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2311   value = tvb_get_bits8(tvb, bo, bl);
2312   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2313   bo += bl;
2314   proto_item_append_text(pi, 
2315                          "COMPACT Interference Measurement Capability: %s",
2316                          value == 0 ? "Not implemented" : "Implemented");
2317
2318   /* Revision level indicator */
2319   bl = 1;
2320   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2321   value = tvb_get_bits8(tvb, bo, bl);
2322   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2323   bo += bl;
2324   proto_item_append_text(pi, "Revision Level Indicator: The ME is Release '%u %s", 
2325                          value == 0 ? 98 : 99,
2326                          value == 0 ? "or older" : "onwards");
2327
2328
2329   /* 3G RAT */
2330   bl = 1;
2331   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2332   value = tvb_get_bits8(tvb, bo, bl);
2333   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2334   bo += bl;
2335   proto_item_append_text(pi, "UMTS FDD Radio Access Technology Capability: UMTS FDD%s supported", 
2336                          value == 0 ? " not" : "");
2337
2338   bl = 1;
2339   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2340   value = tvb_get_bits8(tvb, bo, bl);
2341   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2342   bo += bl;
2343   proto_item_append_text(pi, "UMTS 3.84 Mcps TDD Radio Access Technology Capability: UMTS 3.84 Mcps TDD%s supported", 
2344                          value == 0 ? " not" : "");
2345
2346   bl = 1;
2347   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2348   value = tvb_get_bits8(tvb, bo, bl);
2349   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2350   bo += bl;
2351   proto_item_append_text(pi, "CDMA 2000 Radio Access Technology Capability: CDMA 2000%s supported", 
2352                          value == 0 ? " not" : "");
2353
2354
2355   /* Additions in release 4*/
2356   bl = 1;
2357   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2358   value = tvb_get_bits8(tvb, bo, bl);
2359   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2360   bo += bl;
2361   proto_item_append_text(pi, "UMTS 1.28 Mcps TDD Radio Access Technology Capability: UMTS 1.28 Mcps TDD%s supported", 
2362                          value == 0 ? " not" : "");
2363
2364
2365   /* GERAN Feature Package 1 */
2366   bl = 1;
2367   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2368   value = tvb_get_bits8(tvb, bo, bl);
2369   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2370   bo += bl;
2371   proto_item_append_text(pi, "GERAN Feature Package 1: GERAN Feature Package 1%s supported", 
2372                          value == 0 ? " not" : "");
2373
2374
2375   /* Extended DTM xGPRS Multislot Class */  
2376   bl = 1;
2377   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2378   value = tvb_get_bits8(tvb, bo, bl);
2379   bo += bl;
2380   if (value == 1) {
2381     bl = 2;
2382     if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2383     value = tvb_get_bits8(tvb, bo, bl);
2384     pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2385     bo += bl;
2386     proto_item_append_text(pi, "Extended DTM GPRS Multi Slot Class: %s", 
2387                            translate_msrac_extended_dtm_gprs_multislot_class(value, dgmsc));
2388
2389     /* XXX: 'This field shall be included only if the MS supports EGPRS DTM'.
2390        How know? */
2391     bl = 2;
2392     if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2393     value = tvb_get_bits8(tvb, bo, bl);
2394     pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2395     bo += bl;
2396     proto_item_append_text(pi, "Extended DTM EGPRS Multi Slot Class: %s", 
2397                            translate_msrac_extended_dtm_gprs_multislot_class(value, demsc));
2398   }
2399
2400   /* Modulation based multislot class support */
2401   bl = 1;
2402   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2403   value = tvb_get_bits8(tvb, bo, bl);
2404   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2405   bo += bl;
2406   proto_item_append_text(pi, "Modulation based multislot class support: %s supported", 
2407                          value == 0 ? "Not" : "");
2408
2409   /* Additions in release 5 */
2410
2411   /* High multislot capability */
2412   bl = 1;
2413   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2414   value = tvb_get_bits8(tvb, bo, bl);
2415   bo += bl;
2416   if (value == 1) {
2417     bl = 2;
2418     if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2419     value = tvb_get_bits8(tvb, bo, bl);
2420     pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2421     bo += bl;
2422     proto_item_append_text(pi, "High Multislot Capability: %u", value);
2423     /* XXX: Translate? In that case, which values to compare with?
2424      What if Multislot capability struct was not included? */
2425   }
2426
2427   /* GERAN Iu Mode Capabilities */
2428   /* XXX: Interpretation? Length? */
2429   bl = 1;
2430   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2431   value = tvb_get_bits8(tvb, bo, bl);
2432   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2433   bo += bl;
2434   proto_item_append_text(pi, "GERAN Iu Mode Capabilities: %s",
2435                          value == 0 ? "Not supported" : "Supported");
2436
2437   /* GMSK Multislot Power Profile */
2438   bl = 2;
2439   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2440   value = tvb_get_bits8(tvb, bo, bl);
2441   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2442   bo += bl;
2443   proto_item_append_text(pi, "GMSK Multislot Power Profile: GMSK_MULTI_SLOT_POWER_PROFILE %u",
2444                          value);
2445
2446   /* 8PSK Multislot Power Profile */
2447   /* XXX: 'If the MS does not support 8PSK in the uplink, then it shall
2448      set this field to 00' */
2449   bl = 2;
2450   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2451   value = tvb_get_bits8(tvb, bo, bl);
2452   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2453   bo += bl;
2454   proto_item_append_text(pi, "8PSK Multislot Power Profile: 8PSK_MULTI_SLOT_POWER_PROFILE %u",
2455                          value);
2456
2457   /* Additions in release 6 */
2458
2459   /* Multiple TBF Capability */
2460   bl = 1;
2461   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2462   value = tvb_get_bits8(tvb, bo, bl);
2463   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2464   bo += bl;
2465   proto_item_append_text(pi, "Multiple TBF Capability: Multiple TBF procedures in A/Gb mode%s supported",
2466                          value == 0 ? " not" : "");
2467
2468   /* Downlink Advanced Receiver Performance */
2469   bl = 2;
2470   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2471   value = tvb_get_bits8(tvb, bo, bl);
2472   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2473   bo += bl;
2474   proto_item_append_text(pi, "Donwlink Advanced Receiver Performance: Downlink Advanced Receiver Performance %s supported",
2475                          value == 0 ? "not" : "- phase 1");
2476   
2477
2478   /* Extended RLC_MAC Control Message Segmentation Capability */
2479   bl = 1;
2480   if (!struct_bits_exist(start_bo, struct_length, bo, bl)) return;
2481   value = tvb_get_bits8(tvb, bo, bl);
2482   pi = bit_proto_tree_add_bit_field8(tree, tvb, bo, bl);
2483   bo += bl;
2484   proto_item_append_text(pi, "Extended RLC/MAC Control Message Segmentation Capability: Extended RLC/MAC Control Message Segmentation%s supported",
2485                          value == 0 ? " not" : "");
2486 }
2487
2488 static void 
2489 decode_msrac_value_part(proto_tree *tree, tvbuff_t *tvb, guint64 bo) {
2490   /* No need to check bi->bssgp_tree here */
2491   const guint8 ADD_ACC_TECHN = 0x0f;
2492   guint8 att, length, bit, bl;
2493   proto_item *ti, *ti2, *pi;
2494   proto_tree *tf, *tf2;
2495   const char *att_name;
2496   guint64 start_bo;
2497   
2498   start_bo = bo;
2499   ti = bit_proto_tree_add_text(tree, tvb, bo, 8,
2500                                "MS RA capability value part");
2501   /* Temporary length of item */
2502   tf = proto_item_add_subtree(ti, ett_bssgp_msrac_value_part);
2503
2504   bl = 4;
2505   att = tvb_get_bits8(tvb, bo, bl);
2506   att_name = translate_msrac_access_technology_type(att);
2507   pi = bit_proto_tree_add_bit_field8(tf, tvb, bo, bl);
2508   proto_item_append_text(pi, "Access Technology Type: %s (%#01x)", att_name, att);
2509   proto_item_append_text(ti, ": Technology Type %s", att_name);
2510   bo += bl;
2511
2512   bl = 7;
2513   length = tvb_get_bits8(tvb, bo, bl);
2514   pi = bit_proto_tree_add_bit_field8(tf, tvb, bo, bl);
2515   proto_item_append_text(pi, "Length: %u bits", length);
2516   bo += bl;
2517  
2518   if (att == ADD_ACC_TECHN) {
2519     bo++; /* Always '1' */
2520     ti2 = bit_proto_tree_add_text(tf, tvb, bo, length,
2521                                   "Additional Access Technologies");
2522     tf2 = proto_item_add_subtree(ti2, ett_bssgp_msrac_additional_access_technologies);
2523     proto_item_set_len(ti, get_num_octets_spanned(start_bo, 4 + 7 + length + 1 + 1));
2524     decode_msrac_additional_access_technologies(tf2, tvb, bo, length);
2525   }
2526   else if (att <= 0x0b) { 
2527     ti2 = bit_proto_tree_add_text(tf, tvb, bo, length, "Access Capabilities");
2528     tf2 = proto_item_add_subtree(ti2, ett_bssgp_msrac_access_capabilities);
2529     proto_item_set_len(ti, get_num_octets_spanned(start_bo, 4 + 7 + length + 1));
2530     decode_msrac_access_capabilities(tf2, tvb, bo, length); 
2531   }
2532   /* else unknown Access Technology Type */
2533
2534   bo += length;
2535   bit = tvb_get_bits8(tvb, bo, 1);
2536   bo++;
2537   if (bit == 1) {
2538     decode_msrac_value_part(tree, tvb, bo);
2539   }
2540 }
2541
2542 static void 
2543 decode_iei_ms_radio_access_capability(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
2544   proto_item *ti;
2545   proto_tree *tf;
2546   
2547   if (!bi->bssgp_tree) {
2548     bi->offset += ie->value_length;
2549     return;  
2550   }
2551   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
2552   tf = proto_item_add_subtree(ti, ett_bssgp_ms_radio_access_capability);
2553   
2554   decode_msrac_value_part(tf, bi->tvb, bi->offset * 8);
2555   bi->offset += ie->value_length;
2556 }
2557
2558 static void 
2559 decode_iei_omc_id(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
2560   /* XXX: Translation: where in 3GPP TS 12.20? */
2561   proto_item *ti;
2562
2563   if (bi->bssgp_tree) {
2564     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
2565     proto_item_append_text(ti, ": %s", BSSGP_NOT_DECODED);
2566   }
2567   bi->offset += ie->value_length;
2568 }
2569
2570 static void 
2571 decode_iei_pdu_in_error(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
2572   proto_item *ti;
2573
2574   if (bi->bssgp_tree) {
2575     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
2576     proto_item_append_text(ti, ": Erroneous BSSGP PDU (%u bytes)", 
2577                            ie->value_length);
2578   }
2579   bi->offset += ie->value_length;
2580 }
2581
2582 static void 
2583 decode_iei_priority(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
2584   const guint8 MASK_PCI = 0x40;
2585   const guint8 MASK_PRIORITY_LEVEL = 0x3c;
2586   const guint8 MASK_QA = 0x02;
2587   const guint8 MASK_PVI = 0x01;
2588   proto_item *ti, *pi;
2589   proto_tree *tf;
2590   guint8 data, value;
2591
2592   static const value_string tab_priority_level[] = {
2593     { 0, "Spare" },
2594     { 1, "Priority Level 1 = highest priority" },
2595     { 2, "Priority Level 2 = 2nd highest priority" },
2596     { 3, "Priority Level 3 = 3rd highest priority" },
2597     { 4, "Priority Level 4 = 4th highest priority" },
2598     { 5, "Priority Level 5 = 5th highest priority" },
2599     { 6, "Priority Level 6 = 6th highest priority" },
2600     { 7, "Priority Level 7 = 7th highest priority" },
2601     { 8, "Priority Level 8 = 8th highest priority" },
2602     { 9, "Priority Level 9 = 9th highest priority" },
2603     { 10, "Priority Level 10 = 10th highest priority" },
2604     { 11, "Priority Level 11 = 11th highest priority" },
2605     { 12, "Priority Level 12 = 12th highest priority" },
2606     { 13, "Priority Level 13 = 13th highest priority" },
2607     { 14, "Priority Level 14 = lowest priority" },
2608     { 15, "Priority not used" },
2609     { 0, NULL },
2610   };
2611
2612   if (!bi->bssgp_tree) {
2613     bi->offset += ie->value_length;
2614     return;
2615   }   
2616   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
2617   tf = proto_item_add_subtree(ti, ett_bssgp_priority);
2618   
2619   data = tvb_get_guint8(bi->tvb, bi->offset); 
2620   
2621   value = get_masked_guint8(data, MASK_PCI);
2622   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, 
2623                                 MASK_PCI);
2624   proto_item_append_text(pi, "PCI: This allocation request %s preempt an existing connection",
2625                          value == 0 ? "shall not" : "may");
2626   
2627   value = get_masked_guint8(data, MASK_PRIORITY_LEVEL);
2628   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_PRIORITY_LEVEL);
2629   proto_item_append_text(pi, "Priority Level: %s",
2630                          val_to_str(value, tab_priority_level, ""));
2631   
2632   value = get_masked_guint8(data, MASK_QA);
2633   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_QA);
2634   proto_item_append_text(pi, "QA: Queuing%s allowed",
2635                          value == 0 ? " not" : "");
2636   
2637   value = get_masked_guint8(data, MASK_PVI);
2638   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_PVI);
2639   proto_item_append_text(pi, "PVI: This connection %s be preempted by another allocation request",
2640                       value == 0 ? "shall not" : "might");
2641   
2642   bi->offset += ie->value_length;
2643 }
2644
2645 static void 
2646 decode_iei_qos_profile(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
2647   const guint8 MASK_CR_BIT = 0x20;
2648   const guint8 MASK_T_BIT = 0x10;
2649   const guint8 MASK_A_BIT = 0x08;
2650   const guint8 MASK_PRECEDENCE = 0x07;
2651   proto_item *ti, *pi;
2652   proto_tree *tf;
2653   guint8 data, value;
2654   guint16 peak_bit_rate;
2655
2656   static const value_string tab_precedence_ul[] = {
2657     { 0,   "High priority" }, 
2658     { 1,   "Normal priority" },
2659     { 2,   "Low priority" },
2660     { 0,   NULL },
2661   };
2662
2663   static const value_string tab_precedence_dl[] = {
2664     { 0,   "Radio priority 1" }, 
2665     { 1,   "Radio priority 2" },
2666     { 2,   "Radio priority 3" },
2667     { 3,   "Radio priority 4" },
2668     { 4,   "Radio priority unknown" },
2669     { 0,   NULL },
2670   };
2671
2672   if (!bi->bssgp_tree) {
2673     bi->offset += ie->value_length;
2674     return;
2675   }
2676   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
2677   tf = proto_item_add_subtree(ti, ett_bssgp_qos_profile);
2678
2679   peak_bit_rate = tvb_get_ntohs(bi->tvb, bi->offset);
2680   pi = proto_tree_add_text(tf, bi->tvb, bi->offset, 1, "Peak bit rate: ");
2681   if (peak_bit_rate == 0) {
2682     proto_item_append_text(pi, "Best effort");
2683   }
2684   else {
2685     proto_item_append_text(pi, "%u bits/s", peak_bit_rate * 100);
2686   }
2687   bi->offset += 2;
2688
2689   data = tvb_get_guint8(bi->tvb, bi->offset);
2690
2691   value = get_masked_guint8(data, MASK_CR_BIT);
2692   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_CR_BIT);
2693   proto_item_append_text(pi, "C/R: The SDU %s command/response frame type",
2694                          value == 0 ? "contains" : "does not contain");
2695
2696   value = get_masked_guint8(data, MASK_T_BIT);
2697   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_T_BIT);
2698   proto_item_append_text(pi, "T: The SDU contains %s",
2699                          value == 0 ? 
2700                          "data" : 
2701                          "signalling (e.g. related to GMM)");
2702
2703   value = get_masked_guint8(data, MASK_A_BIT);
2704   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_A_BIT);
2705   proto_item_append_text(pi, "A: Radio interface uses RLC/MAC %s functionality",
2706                          value == 0 ? "ARQ " : "UNITDATA ");
2707   
2708   value = get_masked_guint8(data, MASK_PRECEDENCE);
2709   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_PRECEDENCE);
2710   proto_item_append_text(pi, "Precedence: ");
2711
2712   if (bi->ul_data) {
2713     proto_item_append_text(pi, val_to_str(value, tab_precedence_ul, 
2714                                           "Reserved (Low priority)"));
2715   }
2716   else {
2717     proto_item_append_text(pi, val_to_str(value, tab_precedence_dl,
2718                                           "Reserved (Radio priority 3)"));
2719   }
2720   proto_item_append_text(pi, " (%#x)", value);
2721   bi->offset++;
2722 }
2723
2724 static void 
2725 decode_iei_radio_cause(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
2726   proto_item *ti;
2727   guint8 value;
2728
2729   static const value_string tab_radio_cause[] = {
2730     { 0x00, "Radio contact lost with the MS" },
2731     { 0x01, "Radio link quality insufficient to continue communication" },
2732     { 0x02, "Cell reselection ordered" },
2733     { 0x03, "Cell reselection prepare" },
2734     { 0x04, "Cell reselection failure" },
2735     { 0,    NULL },
2736     /* Otherwise "Reserved (Radio contact lost with the MS)" */
2737   };
2738
2739   if (bi->bssgp_tree) {
2740     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
2741     value = tvb_get_guint8(bi->tvb, bi->offset);
2742     proto_item_append_text(ti, ": %s (%#02x)",
2743                            val_to_str(value, tab_radio_cause, "Reserved (Radio contact lost with the MS)"),
2744                            value);
2745   }
2746   bi->offset += ie->value_length;
2747 }
2748
2749 static void 
2750 decode_iei_ra_cap_upd_cause(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
2751   proto_item *ti;
2752   guint8 value;
2753
2754   static const value_string tab_cause[] = {
2755     { 0x00, "OK, RA capability IE present" },
2756     { 0x01, "TLLI unknown in SGSN" },
2757     { 0x02, "No RA capabilities or IMSI available for this MS" },
2758     { 0,    NULL },
2759     /* Otherwise "Reserved (TLLI unknown in SGSN)" */
2760   };
2761
2762   if (bi->bssgp_tree) {
2763     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
2764     value = tvb_get_guint8(bi->tvb, bi->offset);
2765     proto_item_append_text(ti, ": %s (%#2x)",
2766                            val_to_str(value, tab_cause, "Reserved (TLLI unknown in SGSN)"),
2767                            value);
2768   }
2769   bi->offset += ie->value_length;
2770 }
2771
2772 static void 
2773 decode_iei_routeing_area(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
2774   proto_item *ti;
2775   proto_tree *tf;
2776   char *rai;
2777
2778   if (!bi->bssgp_tree) {
2779     bi->offset += ie->value_length;
2780     return;
2781   }
2782   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
2783   tf = proto_item_add_subtree(ti, ett_bssgp_routeing_area);
2784
2785   rai = decode_rai(bi, tf);
2786   proto_item_append_text(ti, ": RAI %s", rai);
2787 }
2788
2789 static void 
2790 decode_iei_tlli(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
2791   proto_item *ti;
2792   proto_tree *tf;
2793   guint32 tlli;
2794
2795   tlli = tvb_get_ntohl(bi->tvb, bi->offset);
2796
2797   if (bi->bssgp_tree) {
2798     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
2799     proto_item_append_text(ti, ": %#04x", tlli);
2800     
2801     ti = bssgp_proto_tree_add_ie(ie, bi, bi->offset);
2802     tf = proto_item_add_subtree(ti, ett_bssgp_tlli);
2803         
2804     proto_tree_add_item(tf, hf_bssgp_tlli, 
2805                                bi->tvb, bi->offset, 4, BSSGP_LITTLE_ENDIAN);
2806   }
2807   bi->offset += 4;
2808
2809   if (check_col(bi->pinfo->cinfo, COL_INFO)) {
2810     col_append_sep_fstr(bi->pinfo->cinfo, COL_INFO, BSSGP_SEP, 
2811                         "TLLI %#4x", tlli);
2812   }
2813   decode_nri(bi->bssgp_tree, bi, tlli);
2814 }
2815
2816 static void 
2817 decode_iei_trigger_id(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
2818   /* XXX: value is 20 octets long! How add/show? */
2819   proto_item *ti;
2820   
2821   if (bi->bssgp_tree) {
2822     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
2823   }
2824   bi->offset += ie->value_length;
2825 }
2826
2827 static void 
2828 proto_tree_add_lsa_id(build_info_t *bi, proto_tree *tree) {
2829   guint32 data, lsa_id;
2830   proto_item *pi;
2831   
2832   data = tvb_get_ntoh24(bi->tvb, bi->offset);
2833   lsa_id = data >> 1;
2834   
2835   pi = proto_tree_add_text(tree, bi->tvb, bi->offset, 3, 
2836                            "LSA ID: %#03x (%s)", lsa_id,
2837                            data & 1 ? 
2838                            "Universal LSA" : "PLMN significant number");
2839   bi->offset += 3;
2840 }
2841
2842 static void 
2843 decode_iei_lsa_identifier_list(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
2844   const guint8 MASK_EP = 0x01;
2845   proto_item *ti, *pi;
2846   proto_tree *tf;
2847   int num_lsa_ids, i;
2848   guint32 value;
2849
2850   if (!bi->bssgp_tree) {
2851     bi->offset += ie->value_length;
2852     return;
2853   }
2854   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
2855   tf = proto_item_add_subtree(ti, ett_bssgp_lsa_identifier_list);
2856
2857   value = tvb_get_masked_guint8(bi->tvb, bi->offset, MASK_EP);
2858   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_EP);
2859   proto_item_append_text(pi, "EP: The escape PLMN is%s broadcast",
2860                          value == 0 ? " not" : "");
2861   bi->offset++;
2862
2863   num_lsa_ids = (ie->value_length - 1) / 3;
2864
2865   for (i = 0; i < num_lsa_ids; i++) {
2866     proto_tree_add_lsa_id(bi, tf);
2867   }
2868 }
2869
2870 static void 
2871 decode_iei_lsa_information(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
2872   const guint8 MASK_LSA_ONLY = 0x01;
2873   const guint8 MASK_ACT = 0x20;
2874   const guint8 MASK_PREF = 0x10;
2875   const guint8 MASK_PRIORITY = 0x0f;
2876   proto_item *ti, *ti2, *pi;
2877   proto_tree *tf, *tf2;
2878   int num_lsa_infos, i;
2879   guint8 data, value;
2880
2881   static const value_string tab_priority[] = {
2882     { 0, "Priority 1 = lowest priority" },
2883     { 1, "Priority 2 = 2nd lowest priority" },
2884     { 2, "Priority 3 = 3rd lowest priority" },
2885     { 3, "Priority 4 = 4th lowest priority" },
2886     { 4, "Priority 5 = 5th lowest priority" },
2887     { 5, "Priority 6 = 6th lowest priority" },
2888     { 6, "Priority 7 = 7th lowest priority" },
2889     { 7, "Priority 8 = 8th lowest priority" },
2890     { 8, "Priority 9 = 9th lowest priority" },
2891     { 9, "Priority 10 = 10th lowest priority" },
2892     { 10, "Priority 11 = 11th lowest priority" },
2893     { 11, "Priority 12 = 12th lowest priority" },
2894     { 12, "Priority 13 = 13th lowest priority" },
2895     { 13, "Priority 14 = 14th lowest priority" },
2896     { 14, "Priority 15 = 15th lowest priority" },
2897     { 15, "Priority 16 = highest priority" },
2898     { 0, NULL },
2899   };
2900
2901   if (!bi->bssgp_tree) {
2902     bi->offset += ie->value_length;
2903     return;
2904   }
2905   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
2906   tf = proto_item_add_subtree(ti, ett_bssgp_lsa_information);
2907
2908   value = tvb_get_masked_guint8(bi->tvb, bi->offset, MASK_LSA_ONLY);
2909   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_LSA_ONLY);
2910   proto_item_append_text(pi, "LSA Only: %s",
2911                          value == 0 ? 
2912                          "The subscriber has only access to the LSAs that are defined by the LSA information element" :
2913                          "Allow an emergency call");
2914   bi->offset++;
2915
2916   num_lsa_infos = (ie->value_length - 1) / 4;
2917
2918   for (i = 0; i < num_lsa_infos; i++) {
2919     ti2 = proto_tree_add_text(tf, bi->tvb, bi->offset, 4, 
2920                               "LSA Identification and attributes %u", i + 1);
2921     tf2 = proto_item_add_subtree(ti2, ett_bssgp_lsa_information_lsa_identification_and_attributes);
2922     
2923     data = tvb_get_guint8(bi->tvb, bi->offset);
2924     
2925     value = get_masked_guint8(data, MASK_ACT);
2926     pi = proto_tree_add_bitfield8(tf2, bi->tvb, bi->offset, MASK_ACT);
2927     proto_item_append_text(pi, "Act: The subscriber %s active mode support in the LSA",
2928                            value == 0 ? "does not have" : "has");
2929         
2930     value = get_masked_guint8(data, MASK_PREF);
2931     pi = proto_tree_add_bitfield8(tf2, bi->tvb, bi->offset, MASK_PREF);
2932     proto_item_append_text(pi, "Pref: The subscriber %s preferential access in the LSA",
2933                            value == 0 ? "does not have" : "has");
2934
2935     value = get_masked_guint8(data, MASK_PRIORITY);
2936     pi = proto_tree_add_bitfield8(tf2, bi->tvb, bi->offset, MASK_PRIORITY);
2937     proto_item_append_text(pi, "Priority: %s",
2938                            val_to_str(value, tab_priority, ""));
2939     bi->offset++;
2940     
2941     proto_tree_add_lsa_id(bi, tf2);
2942   }
2943 }
2944
2945 static void 
2946 decode_iei_gprs_timer(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
2947   const guint8 MASK_UNIT_VALUE = 0xe0;
2948   const guint8 MASK_TIMER_VALUE = 0x1f;
2949   proto_item *ti;
2950   guint8 data, value;
2951
2952   static const value_string tab_unit_value[] = {
2953     { 0, "incremented in multiples of 2 s" },
2954     { 1, "incremented in multiples of 1 minute" },
2955     { 2, "incremented in multiples of decihours" },
2956     { 3, "incremented in multiples of 500 msec" },
2957     { 7, "the timer does not expire" },
2958     { 0, NULL},
2959     /* Otherwise "incremented in multiples of 1 minute" */
2960   };
2961
2962   if (bi->bssgp_tree) {
2963     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
2964     data = tvb_get_guint8(bi->tvb, bi->offset);
2965     value = get_masked_guint8(data, MASK_TIMER_VALUE);
2966     proto_item_append_text(ti, ": %u", value);
2967     
2968     value = get_masked_guint8(data, MASK_UNIT_VALUE);
2969     proto_item_append_text(ti, ", %s",
2970                            val_to_str(value, tab_unit_value, 
2971                                       "incremented in multiples of 1 minute"));
2972   }
2973   bi->offset += ie->value_length;
2974 }
2975
2976 static void 
2977 decode_iei_abqp(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
2978   const guint8 MASK_DELAY_CLASS = 0x38;
2979   const guint8 MASK_RELIABILITY_CLASS = 0x07;
2980   const guint8 MASK_PEAK_THROUGHPUT = 0xf0;
2981   const guint8 MASK_PRECEDENCE_CLASS = 0x07;
2982   const guint8 MASK_MEAN_THROUGHPUT = 0x1f;
2983   const guint8 MASK_TRAFFIC_CLASS = 0xe0;
2984   const guint8 MASK_DELIVERY_ORDER = 0x18;
2985   const guint8 MASK_DELIVERY_OF_ERRONEOUS_SDU = 0x07;
2986   const guint8 MASK_RESIDUAL_BER = 0xf0;
2987   const guint8 MASK_SDU_ERROR_RATIO = 0x0f;
2988   const guint8 MASK_TRANSFER_DELAY = 0xfc;
2989   const guint8 MASK_TRAFFIC_HANDLING_PRIORITY = 0x03;
2990   const guint8 MASK_SIGNALLING_INDICATION = 0x10;
2991   const guint8 MASK_SOURCE_STATISTICS_DESCRIPTOR = 0x0f;
2992   const guint8 TRAFFIC_CLASS_CONVERSATIONAL = 1;
2993   const guint8 TRAFFIC_CLASS_STREAMING = 2;
2994   const guint8 TRAFFIC_CLASS_INTERACTIVE = 3;
2995   const guint8 TRAFFIC_CLASS_BACKGROUND = 4;
2996   guint8 data, value, traffic_class;
2997   proto_item *ti, *pi;
2998   proto_tree *tf;
2999
3000   if (bi->bssgp_tree) {
3001     bi->offset += ie->value_length;
3002     return;
3003   }
3004   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3005   tf = proto_item_add_subtree(ti, ett_bssgp_abqp);
3006     
3007   data = tvb_get_guint8(bi->tvb, bi->offset);
3008
3009   value = get_masked_guint8(data, MASK_DELAY_CLASS);
3010   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_DELAY_CLASS);
3011   proto_item_append_text(pi, "Delay Class: %s (%#x)",  
3012                          translate_abqp_delay_class(value, bi), value);
3013
3014   value = get_masked_guint8(data, MASK_RELIABILITY_CLASS);
3015   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, 
3016                                 MASK_RELIABILITY_CLASS);
3017   proto_item_append_text(pi, "Reliability Class: %s (%#x)",
3018                          translate_abqp_reliability_class(value, bi), value);
3019   bi->offset++;
3020   data = tvb_get_guint8(bi->tvb, bi->offset);
3021
3022   value = get_masked_guint8(data, MASK_PEAK_THROUGHPUT);
3023   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, 
3024                                 MASK_PEAK_THROUGHPUT);
3025   proto_item_append_text(pi, "Peak Throughput: %s (%#x)",
3026                          translate_abqp_peak_throughput(value, bi), value);
3027
3028   value = get_masked_guint8(data, MASK_PRECEDENCE_CLASS);
3029   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, 
3030                                 MASK_PRECEDENCE_CLASS);
3031   proto_item_append_text(pi, "Precedence Class: %s (%#x)",
3032                          translate_abqp_precedence_class(value, bi), value);
3033   bi->offset++;
3034   data = tvb_get_guint8(bi->tvb, bi->offset);
3035
3036   value = get_masked_guint8(data, MASK_MEAN_THROUGHPUT);
3037   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, 
3038                                 MASK_MEAN_THROUGHPUT);
3039   proto_item_append_text(pi, "Mean Throughput: %s (%#02x)",
3040                          translate_abqp_mean_throughput(value, bi), value);
3041   bi->offset++;
3042   data = tvb_get_guint8(bi->tvb, bi->offset);
3043
3044   traffic_class = get_masked_guint8(data, MASK_TRAFFIC_CLASS);
3045   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_TRAFFIC_CLASS);
3046   proto_item_append_text(pi, "Traffic Class: %s (%#x)",
3047                          translate_abqp_traffic_class(traffic_class, bi), 
3048                          value);
3049   if ((traffic_class == TRAFFIC_CLASS_INTERACTIVE) || 
3050       (traffic_class == TRAFFIC_CLASS_BACKGROUND)) {
3051     proto_item_append_text(pi, " (ignored)");
3052   }
3053
3054   value = get_masked_guint8(data, MASK_DELIVERY_ORDER);
3055   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_DELIVERY_ORDER);
3056   proto_item_append_text(pi, "Delivery Order: %s (%#x)",
3057                          translate_abqp_delivery_order(value, bi), value);
3058
3059   value = get_masked_guint8(data, MASK_DELIVERY_OF_ERRONEOUS_SDU);
3060   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, 
3061                                 MASK_DELIVERY_OF_ERRONEOUS_SDU);
3062   proto_item_append_text(pi, "Delivery of Erroneous SDU: %s (%#x)",
3063                          translate_abqp_delivery_of_erroneous_sdu(value, bi),
3064                          value);
3065   bi->offset++;
3066
3067   value = tvb_get_guint8(bi->tvb, bi->offset);
3068   proto_tree_add_text(tf, bi->tvb, bi->offset, 1, 
3069                       "Maximum SDU Size: %s",
3070                       translate_abqp_max_sdu_size(value, bi));
3071   bi->offset++;
3072
3073   value = tvb_get_guint8(bi->tvb, bi->offset);
3074   proto_tree_add_text(tf, bi->tvb, bi->offset, 1, 
3075                       "Maximum bit rate for uplink: %s",
3076                       translate_abqp_max_bit_rate_for_ul(value, bi));
3077   bi->offset++;
3078
3079   value = tvb_get_guint8(bi->tvb, bi->offset);
3080   proto_tree_add_text(tf, bi->tvb, bi->offset, 1, 
3081                       "Maximum bit rate for downlink: %s",
3082                       translate_abqp_max_bit_rate_for_dl(value, bi));
3083   bi->offset++;
3084   data = tvb_get_guint8(bi->tvb, bi->offset);
3085
3086   value = get_masked_guint8(data, MASK_RESIDUAL_BER);
3087   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_RESIDUAL_BER);
3088   proto_item_append_text(pi, "Residual BER: %s (%#x)",
3089                          translate_abqp_residual_ber(value, bi), value);
3090
3091   value = get_masked_guint8(data, MASK_SDU_ERROR_RATIO);
3092   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, 
3093                                 MASK_SDU_ERROR_RATIO);
3094   proto_item_append_text(pi, "SDU Error Ratio: %s (%#x)",
3095                          translate_abqp_sdu_error_ratio(value, bi), value);
3096   bi->offset++;
3097   data = tvb_get_guint8(bi->tvb, bi->offset);
3098
3099   value = get_masked_guint8(data, MASK_TRANSFER_DELAY);
3100   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_TRANSFER_DELAY);
3101   proto_item_append_text(pi, "Transfer Delay: %s (%#02x)",
3102                          translate_abqp_transfer_delay(value, bi), value);
3103
3104   value = get_masked_guint8(data, MASK_TRAFFIC_HANDLING_PRIORITY);
3105   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, 
3106                                 MASK_TRAFFIC_HANDLING_PRIORITY);
3107   proto_item_append_text(pi, "Traffic Handling Priority: %s (%#x)",
3108                          translate_abqp_traffic_handling_priority(value, bi),
3109                          value);
3110   if ((traffic_class == TRAFFIC_CLASS_CONVERSATIONAL) ||
3111       (traffic_class == TRAFFIC_CLASS_STREAMING) ||
3112       (traffic_class == TRAFFIC_CLASS_BACKGROUND)) {
3113     proto_item_append_text(pi, " (ignored)");
3114   }
3115   bi->offset++;
3116
3117   value = tvb_get_guint8(bi->tvb, bi->offset);
3118   proto_tree_add_text(tf, bi->tvb, bi->offset, 1, 
3119                       "Guaranteed bit rate for uplink: %s",
3120                       translate_abqp_guaranteed_bit_rate_for_ul(value, bi));
3121   bi->offset++;
3122
3123   value = tvb_get_guint8(bi->tvb, bi->offset);
3124   proto_tree_add_text(tf, bi->tvb, bi->offset, 1, 
3125                       "Guaranteed bit rate for downlink: %s",
3126                       translate_abqp_guaranteed_bit_rate_for_dl(value, bi));
3127   bi->offset++;
3128
3129   data = tvb_get_guint8(bi->tvb, bi->offset);
3130
3131   value = get_masked_guint8(data, MASK_SIGNALLING_INDICATION);
3132   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, 
3133                                 MASK_SIGNALLING_INDICATION);
3134   proto_item_append_text(pi, "Signalling Indication: %s for signalling traffic",
3135                          value == 0 ? "Not optimized" : "Optimized");
3136   if ((traffic_class == TRAFFIC_CLASS_CONVERSATIONAL) ||
3137       (traffic_class == TRAFFIC_CLASS_STREAMING) ||
3138       (traffic_class == TRAFFIC_CLASS_BACKGROUND)) {
3139     proto_item_append_text(pi, " (ignored)");
3140   }
3141
3142   value = get_masked_guint8(data, MASK_SOURCE_STATISTICS_DESCRIPTOR);
3143   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, 
3144                                 MASK_SOURCE_STATISTICS_DESCRIPTOR);
3145   proto_item_append_text(pi, "Source Statistics Descriptor: %s (%#x)",
3146                          translate_abqp_source_statistics_descriptor(value, bi),
3147                          value);
3148   if ((traffic_class == TRAFFIC_CLASS_INTERACTIVE) ||
3149       (traffic_class == TRAFFIC_CLASS_BACKGROUND)) {
3150     proto_item_append_text(pi, " (ignored)");
3151   }
3152   bi->offset++;
3153
3154   value = tvb_get_guint8(bi->tvb, bi->offset);
3155   proto_tree_add_text(tf, bi->tvb, bi->offset, 1, 
3156                       "Maximum bit rate for downlink (extended): %s",
3157                       translate_abqp_max_bit_rate_for_dl_extended(value, bi));
3158   bi->offset++;
3159
3160   value = tvb_get_guint8(bi->tvb, bi->offset);
3161   proto_tree_add_text(tf, bi->tvb, bi->offset, 1, 
3162                       "Guaranteed bit rate for downlink (extended): %s",
3163                       translate_abqp_guaranteed_bit_rate_for_dl_extended(value, bi));
3164   bi->offset++;
3165 }
3166
3167 static void 
3168 decode_iei_feature_bitmap(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3169   const guint8 MASK_ENHANCED_RADIO_STATUS = 0x40;
3170   const guint8 MASK_PFC_FC = 0x20;
3171   const guint8 MASK_RIM = 0x10;
3172   const guint8 MASK_LCS = 0x08;
3173   const guint8 MASK_INR = 0x04;
3174   const guint8 MASK_CBL = 0x02;
3175   const guint8 MASK_PFC = 0x01;
3176   proto_item *ti, *pi;
3177   proto_tree *tf;
3178   guint8 data, value;
3179
3180   if (!bi->bssgp_tree) {
3181     bi->offset += ie->value_length;
3182     return;
3183   }
3184   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3185   tf = proto_item_add_subtree(ti, ett_bssgp_feature_bitmap);
3186   
3187   data = tvb_get_guint8(bi->tvb, bi->offset);
3188
3189   value = get_masked_guint8(data, MASK_ENHANCED_RADIO_STATUS);
3190   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, 
3191                                 MASK_ENHANCED_RADIO_STATUS);
3192   proto_item_append_text(pi, "Enhanced Radio Status: Enhanced Radio Status Procedures%s supported",
3193                          value == 0 ? " not" : "");
3194   
3195   value = get_masked_guint8(data, MASK_PFC_FC);
3196   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_PFC_FC);
3197   proto_item_append_text(pi, "PFC_FC: PFC Flow Control Procedures%s supported",
3198                          value == 0 ? " not" : "");
3199
3200   value = get_masked_guint8(data, MASK_RIM);
3201   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_RIM);
3202   proto_item_append_text(pi, "RIM: RAN Information Management (RIM) Procedures%s supported",
3203                          value == 0 ? " not" : "");
3204
3205   value = get_masked_guint8(data, MASK_LCS);
3206   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_LCS);
3207   proto_item_append_text(pi, "LCS: LCS Procedures%s supported",
3208                       value == 0 ? " not" : "");
3209
3210   value = get_masked_guint8(data, MASK_INR);
3211   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_INR);
3212   proto_item_append_text(pi, "INR: Inter-NSE re-routeing%s supoprted",
3213                          value == 0 ? " not" : "");
3214   
3215   value = get_masked_guint8(data, MASK_CBL);
3216   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_CBL);
3217   proto_item_append_text(pi, "CBL: Current Bucket Level Procedures%s supported",
3218                          value == 0 ? " not" : "");
3219
3220   value = get_masked_guint8(data, MASK_PFC);
3221   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_PFC);
3222   proto_item_append_text(pi, "PFC: Packet Flow Context Procedures%s supported",
3223                          value == 0 ? " not" : ""); 
3224
3225   bi->offset += ie->value_length; 
3226 }
3227
3228 static void 
3229 decode_iei_bucket_full_ratio(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3230   proto_item *ti;
3231   
3232   if (bi->bssgp_tree) {
3233     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3234     bssgp_pi_append_bucket_full_ratio(ti, bi->tvb, bi->offset);
3235   }
3236   bi->offset += ie->value_length;
3237 }
3238
3239 static void 
3240 decode_iei_service_utran_cco(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3241   const guint8 MASK_SERVICE_UTRAN_CCO = 0x07;
3242   proto_item *ti;
3243   guint8 data, value; 
3244
3245   static const value_string tab_service_utran_cco[] = {
3246     { 0, "Network initiated cell change order procedure to UTRAN should be performed" },
3247     { 1, "Network initiated cell change order procedure to UTRAN should not be performed" },
3248     { 2, "Network initiated cell change order procedure to UTRAN shall not be performed" },
3249     { 0,    NULL },
3250     /* Otherwise "No information available" */
3251   };
3252
3253   if (bi->bssgp_tree) {
3254     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3255     data = tvb_get_guint8(bi->tvb, bi->offset);
3256     value = get_masked_guint8(data, MASK_SERVICE_UTRAN_CCO);
3257     proto_item_append_text(ti, ": %s (%#02x)",
3258                            val_to_str(value, tab_service_utran_cco, 
3259                                       "No information available"),
3260                            value);
3261   }
3262   bi->offset += ie->value_length;
3263 }
3264
3265 static void 
3266 decode_iei_nsei(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3267   proto_item *ti;
3268   guint16 nsei;
3269
3270   nsei = tvb_get_ntohs(bi->tvb, bi->offset);
3271
3272   if (bi->bssgp_tree) {
3273     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3274     proto_item_append_text(ti, ": %u", nsei);
3275     proto_tree_add_item_hidden(bi->bssgp_tree, hf_bssgp_nsei, 
3276                                bi->tvb, bi->offset, 2, BSSGP_LITTLE_ENDIAN);
3277   }
3278   bi->offset += ie->value_length;
3279
3280   if (check_col(bi->pinfo->cinfo, COL_INFO)) {
3281     col_append_sep_fstr(bi->pinfo->cinfo, COL_INFO, BSSGP_SEP, 
3282                         "NSEI %u", nsei);
3283   }
3284 }
3285
3286 static void 
3287 decode_iei_lcs_qos(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3288   const guint8 MASK_VERT = 0x01;
3289   const guint8 MASK_XA = 0x80;
3290   const guint8 MASK_ACCURACY = 0x7f;
3291   const guint8 MASK_RT = 0xc0;
3292   proto_item *ti, *pi;
3293   proto_tree *tf;
3294   guint8 data, value, vert;
3295
3296   static const value_string tab_rt[] = {
3297     { 0, "Response time is not specified" },
3298     { 1, "Low delay" },
3299     { 2, "Delay tolerant" },
3300     { 3, "Reserved" },
3301     { 0, NULL },
3302   };
3303
3304   if (!bi->bssgp_tree) {
3305     bi->offset += ie->value_length;
3306     return;
3307   }
3308   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3309   tf = proto_item_add_subtree(ti, ett_bssgp_lcs_qos);
3310
3311   data = tvb_get_guint8(bi->tvb, bi->offset);
3312   vert = get_masked_guint8(data, MASK_VERT);
3313   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_VERT);
3314   proto_item_append_text(pi, "VERT: Vertical coordinate is%s requested",
3315                          vert == 0 ? " not" : "");
3316   bi->offset++;
3317
3318   data = tvb_get_guint8(bi->tvb, bi->offset);
3319   
3320   value = get_masked_guint8(data, MASK_XA);
3321   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_XA);
3322   proto_item_append_text(pi, "HA: Horizontal Accuracy is%s specified",
3323                          value == 0 ? " not" : "");
3324
3325   if (value == 1) {
3326     value = get_masked_guint8(data, MASK_ACCURACY);
3327     pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_ACCURACY);
3328     proto_item_append_text(pi, "Horizontal Accuracy: %.1f m", 
3329                            10 * (pow(1.1, (double)value) - 1));
3330   }
3331   bi->offset++;
3332
3333   data = tvb_get_guint8(bi->tvb, bi->offset);
3334   
3335   if (vert == 1) {
3336     value = get_masked_guint8(data, MASK_XA);
3337     pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_XA);
3338     proto_item_append_text(pi, "VA: Vertical Accuracy is%s specified",
3339                            value == 0 ? " not" : "");
3340
3341     value = get_masked_guint8(data, MASK_ACCURACY);
3342     pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_ACCURACY);
3343     proto_item_append_text(pi, "Vertical Accuracy: %.1f m", 
3344                            45 * (pow(1.025, (double)value) - 1));
3345   }
3346   bi->offset++;
3347
3348   data = tvb_get_guint8(bi->tvb, bi->offset);
3349   value = get_masked_guint8(data, MASK_RT);
3350   
3351   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_RT);
3352   proto_item_append_text(pi, "RT: %s",
3353                          val_to_str(value, tab_rt, ""));
3354   bi->offset++;
3355 }
3356
3357 static void 
3358 decode_iei_lcs_client_type(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3359   const guint8 MASK_CATEGORY = 0xf0;
3360   const guint8 MASK_SUBTYPE = 0x0f;
3361   proto_item *ti, *pi;
3362   proto_tree *tf;
3363   guint8 data, category, subtype;
3364
3365   static const value_string tab_category[] = {
3366     { 0, "Value Added Client" },
3367     /* { 1, ??? XXX }, */
3368     { 2, "PLMN Operator" },
3369     { 3, "Emergency Services" },
3370     { 4, "Lawful Intercept Services" },
3371     { 0, NULL },
3372     /* Otherwise "Reserved" */
3373   };
3374
3375   if (!bi->bssgp_tree) {
3376     bi->offset += ie->value_length;
3377     return;
3378   }
3379   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3380   tf = proto_item_add_subtree(ti, ett_bssgp_lcs_client_type);
3381
3382   data = tvb_get_guint8(bi->tvb, bi->offset);
3383   
3384   category = get_masked_guint8(data, MASK_CATEGORY);
3385   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_CATEGORY);
3386   proto_item_append_text(pi, "Category: %s (%#x)",
3387                          val_to_str(category, tab_category, "Reserved"),
3388                          category);
3389
3390   subtype = get_masked_guint8(data, MASK_SUBTYPE);
3391   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_SUBTYPE);
3392   proto_item_append_text(pi, "Subtype: ");
3393
3394   switch (category) {
3395   case 0:
3396     if (subtype == 0) {
3397       proto_item_append_text(pi, "Unspecified"); break;
3398     }
3399     else {
3400       proto_item_append_text(pi, "Reserved"); break;
3401     }
3402     /* case 1: ??? XXX*/
3403   case 2:
3404     switch (subtype) {
3405     case 0: proto_item_append_text(pi, "Unspecified"); break;
3406     case 1: proto_item_append_text(pi, "Broadcast service"); break;
3407     case 2: proto_item_append_text(pi, "O&M"); break;
3408     case 3: proto_item_append_text(pi, "Anonymous statistics"); break;
3409     case 4: proto_item_append_text(pi, "Target MS service support node"); break;
3410     default: proto_item_append_text(pi, "Reserved"); break;
3411     }
3412     break;
3413   case 3:
3414   case 4:
3415     if (subtype == 0) {
3416       proto_item_append_text(pi, "Unspecified"); break;
3417     }
3418     else {
3419       proto_item_append_text(pi, "Reserved"); break;
3420     }
3421   default: /* Not category == 1! */
3422     proto_item_append_text(pi, "Reserved"); break;
3423   }
3424
3425   bi->offset++;
3426 }
3427
3428 static void 
3429 decode_iei_requested_gps_assistance_data(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3430   const guint8 MASK_A = 0x01;
3431   const guint8 MASK_B = 0x02;
3432   const guint8 MASK_C = 0x04;
3433   const guint8 MASK_D = 0x08;
3434   const guint8 MASK_E = 0x10;
3435   const guint8 MASK_F = 0x20;
3436   const guint8 MASK_G = 0x40;
3437   const guint8 MASK_H = 0x80;
3438   const guint8 MASK_I = 0x01;
3439   const guint8 MASK_NSAT = 0xf0;
3440   const guint8 MASK_T_TOE_LIMIT = 0x0f;
3441   const guint8 MASK_SAT_ID =0x3f;
3442   proto_tree *tf, *tf2;
3443   proto_item *ti, *ti2, *pi;
3444   guint8 data, value, d, nsat;
3445   guint16 gps_week;
3446   int i;
3447
3448   if (!bi->bssgp_tree) {
3449     bi->offset += ie->value_length;
3450     return;
3451   }
3452   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3453   tf = proto_item_add_subtree(ti, ett_bssgp_requested_gps_assistance_data);
3454
3455   data = tvb_get_guint8(bi->tvb, bi->offset);
3456
3457   value = get_masked_guint8(data, MASK_A);
3458   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_A);
3459   proto_item_append_text(pi, "A: Almanac is%s srequested",
3460                          value == 0 ? " not" : "");
3461
3462   value = get_masked_guint8(data, MASK_B);
3463   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_B);
3464   proto_item_append_text(pi, "B: UTC Model is%s requested",
3465                          value == 0 ? " not" : "");
3466
3467   value = get_masked_guint8(data, MASK_C);
3468   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_C);
3469   proto_item_append_text(pi, "C: Ionospheric Model is%s requested",
3470                          value == 0 ? " not" : "");
3471
3472   value = get_masked_guint8(data, MASK_D);
3473   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_D);
3474   proto_item_append_text(pi, "D: Navigation Model is%s requested",
3475                          value == 0 ? " not" : "");
3476   d = value;
3477
3478   value = get_masked_guint8(data, MASK_E);
3479   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_E);
3480   proto_item_append_text(pi, "E: DGPS Corrections are%s requested",
3481                          value == 0 ? " not" : "");
3482
3483   value = get_masked_guint8(data, MASK_F);
3484   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_F);
3485   proto_item_append_text(pi, "F: Reference Location is%s requested",
3486                          value == 0 ? " not" : "");
3487
3488   value = get_masked_guint8(data, MASK_G);
3489   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_G);
3490   proto_item_append_text(pi, "G: Reference Time is%s requested",
3491                          value == 0 ? " not" : "");
3492
3493   value = get_masked_guint8(data, MASK_H);
3494   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_H);
3495   proto_item_append_text(pi, "H: Acquisition Asssistance is%s requested",
3496                          value == 0 ? " not" : "");
3497
3498   bi->offset++;
3499
3500   value = tvb_get_masked_guint8(bi->tvb, bi->offset, MASK_I);
3501   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_I);
3502   proto_item_append_text(pi, "I: Real-Time Integrity is%s requested",
3503                          value == 0 ? " not" : "");
3504   if (d == 0) return;
3505
3506   data = tvb_get_guint8(bi->tvb, bi->offset);
3507   gps_week = (data & 0xc0) << 2;
3508   data = tvb_get_guint8(bi->tvb, bi->offset + 1);
3509   gps_week += data;
3510   proto_tree_add_text(tf, bi->tvb, bi->offset, 2, 
3511                       "GPS Week: %u", gps_week);  
3512   bi->offset += 2;
3513
3514   value = tvb_get_guint8(bi->tvb, bi->offset);
3515   proto_tree_add_text(tf, bi->tvb, bi->offset, 1,
3516                       "GPS Toe: %u", value);
3517   bi->offset++;
3518
3519   data = tvb_get_guint8(bi->tvb, bi->offset);
3520   nsat = get_masked_guint8(data, MASK_NSAT);
3521   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_NSAT);
3522   proto_item_append_text(pi, "NSAT: %u", value);
3523
3524   value = get_masked_guint8(data, MASK_T_TOE_LIMIT);
3525   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_T_TOE_LIMIT);
3526   proto_item_append_text(pi, "T-Toe Limit: %u", value);
3527   bi->offset++;
3528
3529   for (i = 0; i < nsat; i++) {
3530     ti2 = proto_tree_add_text(tf, bi->tvb, bi->offset, 2, "Satellite %u", i);
3531     tf2 = proto_item_add_subtree(ti2, ett_bssgp_requested_gps_assistance_data_satellite);
3532
3533     value = tvb_get_masked_guint8(bi->tvb, bi->offset, MASK_SAT_ID);
3534     pi = proto_tree_add_bitfield8(tf2, bi->tvb, bi->offset, MASK_SAT_ID);
3535     proto_item_append_text(pi, "SatId: %u", value);
3536     proto_item_append_text(ti2, ": Id %u", value);
3537     bi->offset++;
3538
3539     value = tvb_get_guint8(bi->tvb, bi->offset);
3540     proto_tree_add_text(tf2, bi->tvb, bi->offset, 1, 
3541                         "IODE: %u", value);
3542     proto_item_append_text(ti2, ", IODE %u", value);
3543     bi->offset++;
3544   }
3545 }
3546
3547 static void 
3548 decode_iei_location_type(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3549   const guint8 LOCATION_ASSISTANCE = 1;
3550   const guint8 DECIPHERING_KEYS = 2;
3551   proto_item *ti;
3552   proto_tree *tf;
3553   guint8 value;
3554
3555   static const value_string tab_location_information[] = {
3556     { 0, "Current geographic location" },
3557     { 1, "Location assistance information for the target MS" },
3558     { 2, "Deciphering keys for broadcast assistance data for the target MS" },
3559     { 0, NULL },
3560     /* Otherwise "Reserved" */
3561   };
3562
3563   static const value_string tab_positioning_method[] = {
3564     { 0, "Reserved" },
3565     { 1, "Mobile Assisted E-OTD" },
3566     { 2, "Mobile Based E-OTD" },
3567     { 3, "Assisted GPS" },
3568     { 0, NULL },
3569     /* Otherwise "Reserved" */
3570   };
3571
3572   if (!bi->bssgp_tree) {
3573     bi->offset += ie->value_length;
3574     return;
3575   }
3576   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3577   tf = proto_item_add_subtree(ti, ett_bssgp_location_type);
3578
3579   value = tvb_get_guint8(bi->tvb, bi->offset);
3580   proto_tree_add_text(tf, bi->tvb, bi->offset, 1, "Location Information: %s",
3581                       val_to_str(value, tab_location_information, 
3582                                  "Reserved"));
3583   bi->offset++;
3584
3585   if ((value == LOCATION_ASSISTANCE) || (value == DECIPHERING_KEYS)) {
3586     value = tvb_get_guint8(bi->tvb, bi->offset);
3587     proto_tree_add_text(tf, bi->tvb, bi->offset, 1, "Positioning Method: %s",
3588                         val_to_str(value, tab_positioning_method, 
3589                                    "Reserved"));
3590     bi->offset++;
3591   }
3592 }
3593
3594 static void 
3595 decode_iei_location_estimate(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3596   /* XXX: Which paragraph in 3GPP TS 23.032?*/
3597   proto_item *ti;
3598
3599   if (bi->bssgp_tree) {
3600     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3601     proto_item_append_text(ti, ": %s", BSSGP_NOT_DECODED);
3602   }
3603   if (ie->value_length != BSSGP_UNKNOWN) {
3604     bi->offset += ie->value_length;
3605   }
3606 }
3607
3608 static void 
3609 decode_iei_positioning_data(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3610   const guint8 MASK_PDD = 0x0f;
3611   const guint8 MASK_METHOD = 0xf8;
3612   const guint8 MASK_USAGE = 0x07;
3613   proto_item *ti, *pi;
3614   proto_tree *tf;
3615   guint8 data, value, i, num_methods;
3616
3617   if (!bi->bssgp_tree) {
3618     bi->offset += ie->value_length;
3619     return;
3620   }  
3621   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3622   tf = proto_item_add_subtree(ti, ett_bssgp_positioning_data);
3623
3624   value = tvb_get_masked_guint8(bi->tvb, bi->offset, MASK_PDD);
3625   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_PDD);
3626   proto_item_append_text(pi, "Positioning Data Discriminator: %s",
3627                       value == 0 ? 
3628                       "Indicate usage of each positioning method that was attempted either successfully or unseccessfully" : 
3629                       "Reserved");
3630   bi->offset++;
3631
3632   num_methods = ie->value_length - 1;
3633   for (i = 0; i < num_methods; i++) {
3634     data = tvb_get_guint8(bi->tvb, bi->offset);
3635
3636     value = get_masked_guint8(data, MASK_METHOD);
3637     pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_METHOD);
3638     proto_item_append_text(pi, "Method: ");
3639     
3640     switch (value) {
3641     case 0: proto_item_set_text(pi, "Timing Advance"); break;
3642     case 1: proto_item_set_text(pi, "Reserved"); break;
3643     case 2: proto_item_set_text(pi, "Reserved"); break;
3644     case 3: proto_item_set_text(pi, "Mobile Assisted E-OTD"); break;
3645     case 4: proto_item_set_text(pi, "Mobile Based E-OTD"); break;
3646     case 5: proto_item_set_text(pi, "Mobile Assisted GPS"); break;
3647     case 6: proto_item_set_text(pi, "Mobile Based GPS"); break;
3648     case 7: proto_item_set_text(pi, "Conventional GPS"); break;
3649     case 8: proto_item_set_text(pi, "U-TDOA"); break;
3650     default:
3651       if ((value >= 9) && (value <= 0x0f)) {
3652         proto_item_set_text(pi, "Reserved for GSM");
3653       }
3654       else {
3655         proto_item_set_text(pi, "Reserved for network specific positioning methods");
3656       }
3657     }
3658     proto_item_append_text(pi, " (%#02x)", value); /* Method */
3659     
3660     value = get_masked_guint8(data, MASK_USAGE);
3661
3662     switch (value) {
3663     case 0: proto_item_append_text(pi, " attempted unsuccessfully due to failure or interuption "); break;
3664     case 1: proto_item_append_text(pi, " attempted successfully: results not used to generate location"); break;
3665     case 2: proto_item_append_text(pi, " attempted successfully: results used to verify but not generate location"); break;
3666     case 3: proto_item_append_text(pi, "attempted successfully: results used to generate location"); break;
3667     case 4: proto_item_append_text(pi, "a temmpted successfully: case where MS supports multiple mobile based positioning methods and the actual method or methods used by the MS cannot be determined"); break;
3668     default: ; /* ??? */    
3669     }
3670     proto_item_append_text(pi, " (%#x)", value); /* Usage */
3671     bi->offset++;
3672   }
3673 }
3674
3675 static void 
3676 decode_iei_deciphering_keys(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3677   const guint8 MASK_KEY_FLAG = 0x01;
3678   proto_item *ti, *pi;
3679   proto_tree *tf;
3680   guint8 data, value;
3681
3682   if (!bi->bssgp_tree) {
3683     bi->offset += ie->value_length;
3684     return;
3685   }
3686
3687   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3688   tf = proto_item_add_subtree(ti, ett_bssgp_deciphering_keys);
3689
3690   data = tvb_get_guint8(bi->tvb, bi->offset);
3691   value = get_masked_guint8(data, MASK_KEY_FLAG);
3692   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_KEY_FLAG);
3693   proto_item_append_text(pi, "Ciphering Key Flag: %u", value);
3694   bi->offset++;
3695
3696   proto_tree_add_text(tf, bi->tvb, bi->offset, 7,
3697                       "Current Deciphering Key Value");
3698   bi->offset += 7;
3699
3700   proto_tree_add_text(tf, bi->tvb, bi->offset, 7, 
3701                       "Next Deciphering Key Value");
3702   bi->offset += 7;
3703 }
3704
3705 static void 
3706 decode_iei_lcs_priority(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3707   /* XXX: coding (3GPP TS 29.002 7.6.11.7)? */
3708   proto_item *ti;
3709
3710   if (bi->bssgp_tree) {
3711     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3712     proto_item_append_text(ti, ": %s", BSSGP_NOT_DECODED);
3713   }
3714   bi->offset += ie->value_length;
3715 }
3716
3717 static void 
3718 decode_iei_lcs_cause(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3719   proto_item *ti;
3720   proto_tree *tf;
3721   guint8 value;
3722
3723   static const value_string tab_cause_value[] = {
3724     { 0, "Unspecified" },
3725     { 1, "System failure" },
3726     { 2, "Protocol error" },
3727     { 3, "Data missing in position request" },
3728     { 4, "Unexpected value in position request" },
3729     { 5, "Position method failure" },
3730     { 6, "Target MS unreacheable" },
3731     { 7, "Location request aborted" },
3732     { 8, "Facility not supported" },
3733     { 9, "Inter-BSC handover ongoing" },
3734     { 10, "Intra-BSC handover ongoing" },
3735     { 11, "Congestion" },
3736     { 12, "Inter NSE cell change" },
3737     { 13, "Routeing area update" },
3738     { 14, "PTMSI reallocation" },
3739     { 15, "Suspension of GPRS services" },
3740     { 0, NULL },
3741     /* Otherwise "Unspecified" */
3742   };
3743
3744   static const value_string tab_diagnostic_value[] = {
3745     { 0, "Congestion" },
3746     { 1, "Insufficient resources" },
3747     { 2, "Insufficient measurement data" },
3748     { 3, "Inconsistent measurement data" },
3749     { 4, "Location procedure not completed" },
3750     { 5, "Location procedure not supported by target MS" },
3751     { 6, "QoS not attainable" },
3752     { 7, "Position method not available in network" },
3753     { 8, "Position method not available in location area" },
3754     { 0, NULL },
3755     /* Otherwise "Unrecognized => ignored" */
3756   };
3757
3758   if (!bi->bssgp_tree) {
3759     bi->offset += ie->value_length;
3760     return;
3761   }
3762   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3763   value = tvb_get_guint8(bi->tvb, bi->offset);
3764
3765   if (ie->value_length == 1) {
3766     /* Diagnostic value not included */
3767     proto_item_append_text(ti, ": %s (%#02x)",
3768                          val_to_str(value, tab_cause_value, "Unspecified"),
3769                          value);
3770     bi->offset++;
3771     return;
3772   }
3773
3774   tf = proto_item_add_subtree(ti, ett_bssgp_lcs_cause);
3775
3776   proto_tree_add_text(tf, bi->tvb, bi->offset, 1, ": %s (%#02x)",
3777                          val_to_str(value, tab_cause_value, "Unspecified"),
3778                          value);
3779   bi->offset++;
3780   
3781   value = tvb_get_guint8(bi->tvb, bi->offset);
3782   proto_tree_add_text(tf, bi->tvb, bi->offset, 1, ": %s (%#02x)",
3783                          val_to_str(value, tab_diagnostic_value, 
3784                                     "Unrecognized => ignored"),
3785                       value);
3786   bi->offset++;
3787 }
3788
3789 static void 
3790 decode_iei_lcs_capability(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3791   const guint8 MASK_OTD_A = 0x10;
3792   const guint8 MASK_OTD_B = 0x08;
3793   const guint8 MASK_GPS_A = 0x04;
3794   const guint8 MASK_GPS_B = 0x02;
3795   const guint8 MASK_GPS_C = 0x01;
3796   proto_item *ti, *pi;
3797   proto_tree *tf;
3798   guint8 data, value;
3799
3800   if (!bi->bssgp_tree) {
3801     bi->offset += ie->value_length;
3802     return;
3803   }
3804   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3805   tf = proto_item_add_subtree(ti, ett_bssgp_lcs_capability);
3806
3807   data = tvb_get_guint8(bi->tvb, bi->offset);
3808
3809   value = get_masked_guint8(data, MASK_OTD_A);
3810   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_OTD_A);
3811   proto_item_append_text(pi, "OTD-A: MS Assisted E-OTD%s supported",
3812                          value == 0 ? " not" : "");
3813
3814   value = get_masked_guint8(data, MASK_OTD_B);
3815   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_OTD_B);
3816   proto_item_append_text(pi, "OTD-B: MS Based E-OTD%s supported",
3817                          value == 0 ? " not" : "");
3818
3819   value = get_masked_guint8(data, MASK_GPS_A);
3820   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_GPS_A);
3821   proto_item_append_text(pi, "GPS-A: MS Assisted GPS%s supported",
3822                          value == 0 ? " not" : "");
3823
3824   value = get_masked_guint8(data, MASK_GPS_B);
3825   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_GPS_B);
3826   proto_item_append_text(pi, "GPS-B: MS Based GPS%s supported",
3827                          value == 0 ? " not" : "");
3828
3829   value = get_masked_guint8(data, MASK_GPS_C);
3830   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_GPS_C);
3831   proto_item_append_text(pi, "GPS-C: Conventional GPS%s supported",
3832                          value == 0 ? " not" : "");
3833
3834   bi->offset++;
3835 }
3836
3837 static void 
3838 decode_iei_rrlp_flags(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3839   const guint8 MASK_FLAG1 = 0x01;
3840   proto_item *ti;
3841   guint8 value;
3842
3843   if (bi->bssgp_tree) {
3844     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3845     value = tvb_get_masked_guint8(bi->tvb, bi->offset, MASK_FLAG1);
3846     proto_item_append_text(ti, ": Flag1:%s Position Command (BSS to SGSN) or final response (SGSN to BSS) (%u)",
3847                            value == 0 ? " Not a" : "", value);    
3848   }
3849   bi->offset++;
3850 }
3851
3852 static void 
3853 decode_iei_rim_application_identity(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3854   proto_item *ti;
3855   guint8 value;
3856
3857   if (bi->bssgp_tree) {
3858     ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3859     value = tvb_get_guint8(bi->tvb, bi->offset);
3860     switch (value) {
3861     case 0: proto_item_append_text(ti, ": Reserved"); break;
3862     case 1: proto_item_append_text(ti, ": Network Assisted Cell Change (NACC)"); break;
3863     default: proto_item_append_text(ti, ": Reserved");
3864     }
3865   }
3866   bi->offset++;
3867 }
3868
3869 static void 
3870 decode_ran_information_common(build_info_t *bi, proto_tree *parent_tree) {
3871   proto_tree *tf;
3872   proto_item *ti;
3873   char *rai_ci;
3874   guint8 num_rai_cis, i;
3875
3876   ti = proto_tree_add_text(parent_tree, bi->tvb, bi->offset, 8, 
3877                            "RAI + CI for Source Cell");
3878   tf = proto_item_add_subtree(ti, ett_bssgp_rai_ci);
3879
3880   rai_ci = decode_rai_ci(bi, tf);
3881   proto_item_append_text(ti, ": %s", rai_ci);
3882
3883   num_rai_cis = tvb_get_guint8(bi->tvb, bi->offset);
3884   proto_tree_add_text(tf, bi->tvb, bi->offset, 1, 
3885                       "%u ""RAI+CI for Destination Cell"" follow%s", 
3886                       num_rai_cis, (num_rai_cis == 0) ? "" : "s");
3887   bi->offset++;
3888
3889   for (i = 0; i < num_rai_cis; i++) {
3890     ti = proto_tree_add_text(parent_tree, bi->tvb, bi->offset, 8, 
3891                              """RAI + CI for Destination Cell"" (%u)", i + 1);
3892     tf = proto_item_add_subtree(ti, ett_bssgp_rai_ci);
3893     rai_ci = decode_rai_ci(bi, tf);
3894     proto_item_append_text(ti, ": %s", rai_ci);
3895   }
3896 }
3897
3898 static void 
3899 decode_iei_ran_information_request_container_unit(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3900   proto_item *ti;
3901   proto_tree *tf;
3902
3903   if (! bi->bssgp_tree) {
3904     bi->offset += 8;
3905     return;
3906   }
3907   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3908   tf = proto_item_add_subtree(ti, ett_bssgp_ran_information_request_container_unit);
3909  
3910   decode_ran_information_common(bi, tf);
3911 }
3912
3913 static void 
3914 decode_iei_ran_information_container_unit(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3915   const guint8 MASK_NUMBER_OF_SI_PSI = 0xfe;
3916   const guint8 MASK_UNIT_TYPE = 0x01;
3917   const guint8 TYPE_SI = 0;
3918   const guint8 TYPE_PSI = 1;
3919   const guint8 LEN_SI = 23;
3920   const guint8 LEN_PSI = 22;
3921   proto_item *ti, *pi;
3922   proto_tree *tf;
3923   guint8 num_si_psi, type_si_psi, data, i;
3924
3925   if (! bi->bssgp_tree) {
3926     bi->offset += 8;
3927     return;
3928   }
3929   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3930   tf = proto_item_add_subtree(ti, ett_bssgp_ran_information_container_unit);
3931  
3932   decode_ran_information_common(bi, tf);
3933
3934   data = tvb_get_guint8(bi->tvb, bi->offset);
3935   num_si_psi = get_masked_guint8(data, MASK_NUMBER_OF_SI_PSI);
3936   type_si_psi = get_masked_guint8(data, MASK_UNIT_TYPE);
3937
3938   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, 
3939                                 MASK_NUMBER_OF_SI_PSI);
3940   proto_item_append_text(pi, "Number of SI/PSI: %u ""SI/PSI"" follow%s",
3941                            num_si_psi,
3942                            num_si_psi < 2 ? "s" : "");
3943
3944   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_UNIT_TYPE);
3945   proto_item_append_text(pi, "Type: %s messages as specified for %s follow",
3946                            type_si_psi == TYPE_SI ? "SI" : "PSI",
3947                            type_si_psi == TYPE_SI ? "BCCH" : "PBCCH");
3948                            
3949   bi->offset++;
3950
3951   for (i = 0; i < num_si_psi; i++) {
3952     if (type_si_psi == TYPE_SI) {
3953       proto_tree_add_text(tf, bi->tvb, bi->offset, LEN_SI, 
3954                           " SI (%u), %u octets", i + 1, LEN_SI);
3955       /* XXX: Not decoded yet; which section in 3GPP TS 44.018? */
3956       bi->offset += LEN_SI;
3957     }
3958     else if (type_si_psi == TYPE_PSI) {
3959       proto_tree_add_text(tf, bi->tvb, bi->offset, LEN_PSI, 
3960                           " PSI (%u), %u octets", i + 1, LEN_PSI);
3961       /* XXX: Not decoded yet; which section in 3GPP TS 44.060? */
3962       bi->offset += LEN_PSI;
3963     }
3964   }
3965 }
3966
3967 static void 
3968 decode_iei_ran_information_indications(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3969   const guint8 MASK_END = 0x02;
3970   const guint8 MASK_ACK = 0x01;
3971   proto_item *ti, *pi;
3972   proto_tree *tf;
3973   guint8 data, value;
3974
3975   if (!bi->bssgp_tree) {
3976     bi->offset += ie->value_length;
3977     return;
3978   }
3979   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
3980   tf = proto_item_add_subtree(ti, ett_bssgp_ran_information_indications);
3981     
3982   data = tvb_get_guint8(bi->tvb, bi->offset);
3983   
3984   value = get_masked_guint8(data, MASK_END);
3985   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_END);
3986   proto_item_append_text(pi, "END: %sEND indicated",
3987                          value == 0 ? "No " : "");
3988
3989   value = get_masked_guint8(data, MASK_ACK);
3990   pi = proto_tree_add_bitfield8(tf, bi->tvb, bi->offset, MASK_ACK);
3991   proto_item_append_text(pi, "ACK: %sACK requested",
3992                          value == 0 ? "No " : "");
3993   bi->offset++;
3994 }
3995
3996 static void 
3997 decode_iei_number_of_container_units(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
3998   proto_item *ti;
3999   guint8 value;
4000
4001   if (!bi->bssgp_tree) {
4002     bi->offset += ie->value_length;
4003     return;
4004   }
4005   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
4006   value = tvb_get_guint8(bi->tvb, bi->offset);
4007   proto_item_append_text(ti, ": %u Container Unit%s follow%s",
4008                          value + 1,
4009                          value == 0 ? "" : "s",
4010                          value > 0 ? "s" : "");
4011   bi->offset++;
4012 }
4013
4014 static void 
4015 decode_iei_pfc_flow_control_parameters(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
4016   proto_tree *tf, *tf2;
4017   proto_item *ti, *ti2, *pi;
4018   guint8 num_pfc, i, pfc_len;
4019   gboolean b_pfc_included;
4020
4021   if (!bi->bssgp_tree) {
4022     bi->offset += ie->value_length;
4023     return;
4024   }
4025   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
4026   tf = proto_item_add_subtree(ti, ett_bssgp_pfc_flow_control_parameters);
4027
4028   num_pfc = tvb_get_guint8(bi->tvb, bi->offset); 
4029   pi = proto_tree_add_text(bi->bssgp_tree, bi->tvb, bi->offset, 1, 
4030                            "Number of PFCs: ");
4031
4032   if (num_pfc < 12) {
4033     proto_item_append_text(pi, "%u", num_pfc);
4034   }
4035   else {
4036     proto_item_append_text(pi, "Reserved");
4037     return;
4038   }
4039   bi->offset++;
4040   if (num_pfc == 0) return;
4041
4042   pfc_len = (ie->value_length - 1) / num_pfc;
4043   b_pfc_included = (pfc_len == 6);
4044
4045   for (i = 0; i < num_pfc; i++) {
4046     ti2 = proto_tree_add_text(tf, bi->tvb, bi->offset, pfc_len, 
4047                               "PFC (%u)", i + 1);
4048     tf2 = proto_item_add_subtree(ti2, ett_bssgp_pfc_flow_control_parameters_pfc);
4049
4050     pi = proto_tree_add_text(tf2, bi->tvb, bi->offset, 1, "PFI");
4051     bssgp_pi_append_pfi(pi, bi->tvb, bi->offset);
4052     bi->offset++;
4053
4054     pi = proto_tree_add_text(tf2, bi->tvb, bi->offset, 2, "BMax_PFC");
4055     bssgp_pi_append_bucket_size(pi, bi->tvb, bi->offset);
4056     bi->offset += 2;
4057
4058     pi = proto_tree_add_text(tf2, bi->tvb, bi->offset, 2, "R_PFC");
4059     bssgp_pi_append_bucket_leak_rate(pi, bi->tvb, bi->offset);
4060     bi->offset += 2;
4061
4062     if (b_pfc_included) {
4063       pi = proto_tree_add_text(tf2, bi->tvb, bi->offset, 1, "B_PFC");
4064       bssgp_pi_append_bucket_full_ratio(pi, bi->tvb, bi->offset);
4065       bi->offset++;
4066     } 
4067   }
4068 }
4069
4070 static void 
4071 decode_iei_global_cn_id(bssgp_ie_t *ie, build_info_t *bi, int ie_start_offset) {
4072   proto_tree *ti;
4073   proto_tree *tf;
4074   guint16 value;
4075   char *mcc_mnc;
4076
4077   if (!bi->bssgp_tree) {
4078     bi->offset += ie->value_length;
4079     return;
4080   }
4081   ti = bssgp_proto_tree_add_ie(ie, bi, ie_start_offset);
4082   tf = proto_item_add_subtree(ti, ett_bssgp_global_cn_id);
4083
4084   mcc_mnc = decode_mcc_mnc(bi, tf);
4085   proto_item_append_text(ti, ": PLMN-Id %s", mcc_mnc);
4086
4087   value = tvb_get_ntohs(bi->tvb, bi->offset);  
4088   proto_tree_add_text(tf, bi->tvb, bi->offset, 2, 
4089                       "CN-ID: %u", value);
4090   proto_item_append_text(ti, ", CN-Id %u", value);
4091   bi->offset += 2; 
4092 }
4093
4094 static void
4095 decode_ie(bssgp_ie_t *ie, build_info_t *bi) {
4096   int org_offset = bi->offset;
4097   const char *iename = val_to_str(ie->iei, tab_bssgp_ie_types, "Unknown");
4098   gboolean use_default_ie_name = (ie->name == NULL);
4099
4100   if (tvb_length_remaining(bi->tvb, bi->offset) < 1) {
4101     return;
4102   }
4103   switch (ie->format) {
4104   case BSSGP_IE_FORMAT_TLV:
4105     if (!check_correct_iei(ie, bi)) {
4106       return;
4107     }
4108     bi->offset++; /* Account for type */
4109     ie->total_length = 1;
4110     get_value_length(ie, bi);
4111     break;
4112   case BSSGP_IE_FORMAT_TV:
4113     if (!check_correct_iei(ie, bi)) {
4114       return;
4115     }
4116     bi->offset++; /* Account for type */
4117     ie->value_length = ie->total_length - 1;
4118     break;
4119   case BSSGP_IE_FORMAT_V:
4120     ie->value_length = ie->total_length;
4121     break;
4122   default:
4123     ;
4124   }
4125
4126   if (use_default_ie_name) {
4127     ie->name = malloc(strlen(iename) + 1);
4128     if (ie->name == NULL) {
4129 #ifdef BSSGP_DEBUG
4130       proto_tree_add_text(bi->bssgp_tree, bi->tvb, bi->offset, 1, 
4131                           "Out of memory");
4132 #endif
4133       /* Out of memory */
4134       exit(EXIT_FAILURE);
4135     }
4136     strcpy(ie->name, iename);
4137   }
4138
4139   switch (ie->iei) {
4140   case BSSGP_IEI_ALIGNMENT_OCTETS:
4141     decode_iei_alignment_octets(ie, bi, org_offset);
4142     break;
4143   case BSSGP_IEI_BMAX_DEFAULT_MS:
4144     decode_bucket_size(ie, bi, org_offset);
4145     break;
4146   case BSSGP_IEI_BSS_AREA_INDICATION:
4147     /* XXX: 'The recipient shall ignore the value of this octet'??? */
4148     decode_simple_ie(ie, bi, org_offset, "BSS Indicator", "", TRUE);
4149     break;
4150   case BSSGP_IEI_BUCKET_LEAK_RATE:
4151     decode_bucket_leak_rate(ie, bi, org_offset);
4152     break;
4153   case BSSGP_IEI_BVCI:
4154     decode_iei_bvci(ie, bi, org_offset);
4155     break;
4156   case BSSGP_IEI_BVC_BUCKET_SIZE:
4157     decode_bucket_size(ie, bi, org_offset);
4158     break;
4159   case BSSGP_IEI_BVC_MEASUREMENT:
4160     decode_queuing_delay(ie, bi, org_offset);
4161     break;
4162   case BSSGP_IEI_CAUSE:
4163     decode_iei_cause(ie, bi, org_offset);
4164     break;
4165   case BSSGP_IEI_CELL_IDENTIFIER:
4166     decode_iei_cell_identifier(ie, bi, org_offset);
4167     break;
4168   case BSSGP_IEI_CHANNEL_NEEDED:
4169     decode_iei_channel_needed(ie, bi, org_offset);
4170     break;
4171   case BSSGP_IEI_DRX_PARAMETERS:
4172     decode_iei_drx_parameters(ie, bi, org_offset);
4173     break;
4174   case BSSGP_IEI_EMLPP_PRIORITY:
4175     decode_iei_emlpp_priority(ie, bi, org_offset);
4176     break;
4177   case BSSGP_IEI_FLUSH_ACTION:
4178     decode_iei_flush_action(ie, bi, org_offset);
4179     break;
4180   case BSSGP_IEI_IMSI:
4181     decode_mobile_identity(ie, bi, org_offset);
4182     break;
4183   case BSSGP_IEI_LLC_PDU:
4184     bssgp_proto_handoff(ie, bi, org_offset, llc_handle);
4185     break;
4186   case BSSGP_IEI_LLC_FRAMES_DISCARDED:
4187     decode_iei_llc_frames_discarded(ie, bi, org_offset);
4188     break;
4189   case BSSGP_IEI_LOCATION_AREA:
4190     decode_iei_location_area(ie, bi, org_offset);
4191     break;
4192   case BSSGP_IEI_MOBILE_ID:
4193     decode_mobile_identity(ie, bi, org_offset);
4194     break;
4195   case BSSGP_IEI_MS_BUCKET_SIZE:
4196     decode_bucket_size(ie, bi, org_offset);
4197     break;
4198   case BSSGP_IEI_MS_RADIO_ACCESS_CAPABILITY:
4199     decode_iei_ms_radio_access_capability(ie, bi, org_offset);
4200     break;
4201   case BSSGP_IEI_OMC_ID:
4202     decode_iei_omc_id(ie, bi, org_offset);
4203     break;
4204   case BSSGP_IEI_PDU_IN_ERROR:
4205     decode_iei_pdu_in_error(ie, bi, org_offset);
4206     break;
4207   case BSSGP_IEI_PDU_LIFETIME:
4208     decode_queuing_delay(ie, bi, org_offset);
4209     break;
4210   case BSSGP_IEI_PRIORITY:
4211     decode_iei_priority(ie, bi, org_offset);
4212     break;
4213   case BSSGP_IEI_QOS_PROFILE:
4214     decode_iei_qos_profile(ie, bi, org_offset);
4215     break;
4216   case BSSGP_IEI_RADIO_CAUSE:
4217     decode_iei_radio_cause(ie, bi, org_offset);
4218     break;
4219   case BSSGP_IEI_RA_CAP_UPD_CAUSE:
4220     decode_iei_ra_cap_upd_cause(ie, bi, org_offset);
4221     break;
4222   case BSSGP_IEI_ROUTEING_AREA:
4223     decode_iei_routeing_area(ie, bi, org_offset);
4224     break;
4225   case BSSGP_IEI_R_DEFAULT_MS:
4226     decode_bucket_leak_rate(ie, bi, org_offset);
4227     break;
4228   case BSSGP_IEI_SUSPEND_REFERENCE_NUMBER:
4229     decode_simple_ie(ie, bi, org_offset, "", "", TRUE);
4230     break;
4231   case BSSGP_IEI_TAG:
4232     decode_simple_ie(ie, bi, org_offset, "", "", TRUE);
4233     break;
4234   case BSSGP_IEI_TLLI:
4235     decode_iei_tlli(ie, bi, org_offset);
4236     break; 
4237   case BSSGP_IEI_TMSI:
4238     decode_mobile_identity(ie, bi, org_offset);
4239     break;
4240   case BSSGP_IEI_TRACE_REFERENCE:
4241     decode_simple_ie(ie, bi, org_offset, "", "", TRUE);
4242     break;
4243   case BSSGP_IEI_TRACE_TYPE:
4244     /* XXX: Coding unknown (Specification withdrawn) 3GPP TS 32.008 */
4245     decode_simple_ie(ie, bi, org_offset, "", "", TRUE);
4246     break;
4247   case BSSGP_IEI_TRANSACTION_ID:
4248     decode_simple_ie(ie, bi, org_offset, "", "", TRUE);
4249     break;
4250   case BSSGP_IEI_TRIGGER_ID:
4251     decode_iei_trigger_id(ie, bi, org_offset);
4252     break;
4253   case BSSGP_IEI_NUMBER_OF_OCTETS_AFFECTED:
4254     decode_simple_ie(ie, bi, org_offset, "", "", TRUE);
4255     break;
4256   case BSSGP_IEI_LSA_IDENTIFIER_LIST:
4257     decode_iei_lsa_identifier_list(ie, bi, org_offset);
4258     break;
4259   case BSSGP_IEI_LSA_INFORMATION:
4260     decode_iei_lsa_information(ie, bi, org_offset);
4261     break;
4262   case BSSGP_IEI_PFI:
4263     decode_pfi(ie, bi, org_offset);
4264     break;
4265   case BSSGP_IEI_GPRS_TIMER:
4266     decode_iei_gprs_timer(ie, bi, org_offset);
4267     break;
4268   case BSSGP_IEI_ABQP:
4269     decode_iei_abqp(ie, bi, org_offset);
4270     break;
4271   case BSSGP_IEI_FEATURE_BITMAP:
4272     decode_iei_feature_bitmap(ie, bi, org_offset);
4273     break;
4274   case BSSGP_IEI_BUCKET_FULL_RATIO:
4275     decode_iei_bucket_full_ratio(ie, bi, org_offset);
4276     break;
4277   case BSSGP_IEI_SERVICE_UTRAN_CCO:
4278     decode_iei_service_utran_cco(ie, bi, org_offset);
4279     break;
4280   case BSSGP_IEI_NSEI:
4281     decode_iei_nsei(ie, bi, org_offset);
4282     break;
4283   case BSSGP_IEI_RRLP_APDU:
4284     bssgp_proto_handoff(ie, bi, org_offset, rrlp_handle);
4285     break;
4286   case BSSGP_IEI_LCS_QOS:
4287     decode_iei_lcs_qos(ie, bi, org_offset);
4288     break;
4289   case BSSGP_IEI_LCS_CLIENT_TYPE:
4290     decode_iei_lcs_client_type(ie, bi, org_offset);
4291     break;
4292   case BSSGP_IEI_REQUESTED_GPS_ASSISTANCE_DATA:
4293     decode_iei_requested_gps_assistance_data(ie, bi, org_offset);
4294     break;
4295   case BSSGP_IEI_LOCATION_TYPE:
4296     decode_iei_location_type(ie, bi, org_offset);
4297     break;
4298   case BSSGP_IEI_LOCATION_ESTIMATE:
4299     decode_iei_location_estimate(ie, bi, org_offset);
4300     break;
4301   case BSSGP_IEI_POSITIONING_DATA:
4302     decode_iei_positioning_data(ie, bi, org_offset);
4303     break;
4304   case BSSGP_IEI_DECIPHERING_KEYS:
4305     decode_iei_deciphering_keys(ie, bi, org_offset);
4306     break;
4307   case BSSGP_IEI_LCS_PRIORITY:
4308     decode_iei_lcs_priority(ie, bi, org_offset);
4309     break;
4310   case BSSGP_IEI_LCS_CAUSE:
4311     decode_iei_lcs_cause(ie, bi, org_offset);
4312     break;
4313   case BSSGP_IEI_LCS_CAPABILITY:
4314     decode_iei_lcs_capability(ie, bi, org_offset);
4315     break;
4316   case BSSGP_IEI_RRLP_FLAGS:
4317     decode_iei_rrlp_flags(ie, bi, org_offset);
4318     break;
4319   case BSSGP_IEI_RIM_APPLICATION_IDENTITY:
4320     decode_iei_rim_application_identity(ie, bi, org_offset);
4321     break;
4322   case BSSGP_IEI_RIM_SEQUENCE_NUMBER:
4323     decode_simple_ie(ie, bi, org_offset, "", "", TRUE);
4324     break;
4325   case BSSGP_IEI_RAN_INFORMATION_REQUEST_CONTAINER_UNIT:
4326     decode_iei_ran_information_request_container_unit(ie, bi, org_offset);
4327     break;
4328   case BSSGP_IEI_RAN_INFORMATION_CONTAINER_UNIT:
4329     decode_iei_ran_information_container_unit(ie, bi, org_offset);
4330     break;
4331   case BSSGP_IEI_RAN_INFORMATION_INDICATIONS:
4332     decode_iei_ran_information_indications(ie, bi, org_offset);
4333     break;
4334   case BSSGP_IEI_NUMBER_OF_CONTAINER_UNITS:
4335     decode_iei_number_of_container_units(ie, bi, org_offset);
4336     break;
4337   case BSSGP_IEI_PFC_FLOW_CONTROL_PARAMETERS:
4338     decode_iei_pfc_flow_control_parameters(ie, bi, org_offset);
4339     break;
4340   case BSSGP_IEI_GLOBAL_CN_ID:
4341     decode_iei_global_cn_id(ie, bi, org_offset);
4342     break;
4343   default:
4344     ;
4345   }
4346   if (use_default_ie_name) {
4347     /* Memory has been allocated; free it */
4348     free(ie->name);
4349     ie->name = NULL;
4350   }
4351 }
4352
4353 static void
4354 decode_pdu_general(bssgp_ie_t *ies, int num_ies, build_info_t *bi) {
4355   int i;
4356   for (i = 0; i < num_ies; i++) {
4357     decode_ie(&ies[i], bi);
4358   }
4359 }
4360
4361 static void 
4362 decode_pdu_dl_unitdata(build_info_t *bi) {
4363   bssgp_ie_t ies[] = {
4364     { BSSGP_IEI_TLLI, "TLLI (current)",
4365       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_V, BSSGP_UNKNOWN, 4 },
4366
4367     { BSSGP_IEI_QOS_PROFILE, NULL, 
4368       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_V, BSSGP_UNKNOWN, 3 },
4369
4370     { BSSGP_IEI_PDU_LIFETIME, NULL, 
4371       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4},
4372
4373     { BSSGP_IEI_MS_RADIO_ACCESS_CAPABILITY, NULL, 
4374       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN},
4375
4376     { BSSGP_IEI_PRIORITY, NULL, 
4377       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3},
4378
4379     { BSSGP_IEI_DRX_PARAMETERS, NULL, 
4380       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4},
4381
4382     { BSSGP_IEI_IMSI, NULL, 
4383       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN},
4384
4385     { BSSGP_IEI_TLLI, "TLLI (old)", 
4386       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6},
4387
4388     { BSSGP_IEI_PFI, NULL, 
4389       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3},
4390
4391     { BSSGP_IEI_LSA_INFORMATION, NULL, 
4392       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN},
4393
4394     { BSSGP_IEI_SERVICE_UTRAN_CCO, NULL, 
4395       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3},
4396
4397     { BSSGP_IEI_ALIGNMENT_OCTETS, NULL, 
4398       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN},
4399
4400     { BSSGP_IEI_LLC_PDU, NULL, 
4401       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN},
4402   };
4403   bi->dl_data = TRUE;
4404   bi->ul_data = FALSE;
4405
4406   decode_pdu_general(ies, 13, bi);
4407 }
4408
4409
4410 static void 
4411 decode_pdu_ul_unitdata(build_info_t *bi) {
4412   bssgp_ie_t ies[] = {
4413     { BSSGP_IEI_TLLI, NULL, 
4414       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_V, BSSGP_UNKNOWN, 4 },
4415
4416     { BSSGP_IEI_QOS_PROFILE, NULL, 
4417       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_V, BSSGP_UNKNOWN, 3 },
4418
4419     { BSSGP_IEI_CELL_IDENTIFIER, NULL, 
4420       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 10 },
4421
4422     { BSSGP_IEI_PFI, NULL, 
4423       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4424
4425     { BSSGP_IEI_LSA_IDENTIFIER_LIST, NULL, 
4426       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
4427
4428     { BSSGP_IEI_ALIGNMENT_OCTETS, NULL, 
4429       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
4430
4431     { BSSGP_IEI_LLC_PDU, NULL, 
4432       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
4433   };
4434   bi->dl_data = FALSE;
4435   bi->ul_data = TRUE;
4436
4437   decode_pdu_general(ies, 7, bi);
4438 }
4439
4440 static void 
4441 decode_pdu_ra_capability(build_info_t *bi) {
4442   bssgp_ie_t ies[] = {
4443     { BSSGP_IEI_TLLI, NULL, 
4444       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4445
4446     { BSSGP_IEI_MS_RADIO_ACCESS_CAPABILITY, NULL, 
4447       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN},
4448   };
4449   bi->dl_data = TRUE;
4450   bi->ul_data = FALSE;
4451
4452   decode_pdu_general(ies, 2, bi);
4453 }
4454
4455 static void 
4456 decode_pdu_ptm_unitdata(build_info_t *bi) {
4457   proto_tree_add_text(bi->bssgp_tree, bi->tvb, bi->offset, -1, 
4458                       "This shall be developed in GPRS phase 2");
4459 }
4460
4461 static void 
4462 decode_pdu_paging_ps(build_info_t *bi) {
4463   bssgp_ie_t ies[] = {
4464     { BSSGP_IEI_IMSI, NULL, 
4465       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
4466
4467     { BSSGP_IEI_DRX_PARAMETERS, NULL, 
4468       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4469
4470     { BSSGP_IEI_BVCI, NULL, 
4471       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4472
4473     { BSSGP_IEI_LOCATION_AREA, NULL, 
4474       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 7 },
4475
4476     { BSSGP_IEI_ROUTEING_AREA, NULL, 
4477       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 8 },
4478
4479     { BSSGP_IEI_BSS_AREA_INDICATION, NULL, 
4480       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4481
4482     { BSSGP_IEI_PFI, NULL, 
4483       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4484
4485     { BSSGP_IEI_ABQP, NULL, 
4486       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
4487
4488     { BSSGP_IEI_QOS_PROFILE, NULL, 
4489       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 5 },
4490
4491     { BSSGP_IEI_TMSI, "P-TMSI", 
4492       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4493   };
4494   bi->dl_data = TRUE;
4495   bi->ul_data = FALSE;
4496
4497   decode_pdu_general(ies, 10, bi);
4498 }
4499
4500 static void 
4501 decode_pdu_paging_cs(build_info_t *bi) {
4502   bssgp_ie_t ies[] = {
4503     { BSSGP_IEI_IMSI, NULL, 
4504       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
4505
4506     { BSSGP_IEI_DRX_PARAMETERS, NULL, 
4507       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4508
4509     { BSSGP_IEI_BVCI, NULL, 
4510       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4511
4512     { BSSGP_IEI_LOCATION_AREA, NULL, 
4513       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 7 },
4514
4515     { BSSGP_IEI_ROUTEING_AREA, NULL, 
4516       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 8 },
4517
4518     { BSSGP_IEI_BSS_AREA_INDICATION, NULL, 
4519       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4520
4521     { BSSGP_IEI_TLLI, NULL, 
4522       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4523
4524     { BSSGP_IEI_CHANNEL_NEEDED, NULL, 
4525       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4526
4527     { BSSGP_IEI_EMLPP_PRIORITY, NULL, 
4528       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4529
4530     { BSSGP_IEI_TMSI, NULL, 
4531       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4532
4533     { BSSGP_IEI_GLOBAL_CN_ID, NULL, 
4534       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 7 },
4535   };
4536   bi->dl_data = TRUE;
4537   bi->ul_data = FALSE;
4538
4539   decode_pdu_general(ies, 11, bi);
4540 }
4541
4542 static void 
4543 decode_pdu_ra_capability_update(build_info_t *bi) {
4544   bssgp_ie_t ies[] = {
4545     { BSSGP_IEI_TLLI, NULL, 
4546       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4547
4548     { BSSGP_IEI_TAG, NULL, 
4549       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4550   };
4551   bi->dl_data = FALSE;
4552   bi->ul_data = TRUE;
4553
4554   decode_pdu_general(ies, 2, bi);
4555 }
4556
4557 static void 
4558 decode_pdu_ra_capability_update_ack(build_info_t *bi) {
4559   bssgp_ie_t ies[] = {
4560     { BSSGP_IEI_TLLI, NULL, 
4561       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4562
4563     { BSSGP_IEI_TAG, NULL, 
4564       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4565
4566     { BSSGP_IEI_IMSI, NULL, 
4567       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
4568
4569     { BSSGP_IEI_RA_CAP_UPD_CAUSE, NULL, 
4570       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4571
4572     { BSSGP_IEI_MS_RADIO_ACCESS_CAPABILITY, NULL, 
4573       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN},
4574   };
4575   bi->dl_data = TRUE;
4576   bi->ul_data = FALSE;
4577
4578   decode_pdu_general(ies, 5, bi);
4579 }
4580
4581 static void 
4582 decode_pdu_radio_status(build_info_t *bi) {
4583   bssgp_ie_t ies[] = {
4584     { BSSGP_IEI_TLLI, NULL, 
4585       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4586
4587     { BSSGP_IEI_TMSI, NULL, 
4588       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4589
4590     { BSSGP_IEI_IMSI, NULL, 
4591       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
4592
4593     { BSSGP_IEI_RADIO_CAUSE, NULL, 
4594       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4595   };
4596   bi->dl_data = FALSE;
4597   bi->ul_data = TRUE;
4598
4599   decode_pdu_general(ies, 4, bi);
4600 }
4601
4602 static void 
4603 decode_pdu_suspend(build_info_t *bi) {
4604   bssgp_ie_t ies[] = {
4605     { BSSGP_IEI_TLLI, NULL, 
4606       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4607
4608     { BSSGP_IEI_ROUTEING_AREA, NULL, 
4609       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 8 },
4610   };
4611   bi->dl_data = FALSE;
4612   bi->ul_data = TRUE;
4613
4614   decode_pdu_general(ies, 2, bi);
4615 }
4616
4617 static void 
4618 decode_pdu_suspend_ack(build_info_t *bi) {
4619   bssgp_ie_t ies[] = {
4620     { BSSGP_IEI_TLLI, NULL, 
4621       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4622
4623     { BSSGP_IEI_ROUTEING_AREA, NULL, 
4624       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 8 },
4625
4626     { BSSGP_IEI_SUSPEND_REFERENCE_NUMBER, NULL, 
4627       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4628   };
4629   bi->dl_data = TRUE;
4630   bi->ul_data = FALSE;
4631
4632   decode_pdu_general(ies, 3, bi);
4633 }
4634
4635 static void 
4636 decode_pdu_suspend_nack(build_info_t *bi) {
4637   bssgp_ie_t ies[] = {
4638     { BSSGP_IEI_TLLI, NULL, 
4639       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4640
4641     { BSSGP_IEI_ROUTEING_AREA, NULL, 
4642       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 8 },
4643
4644     { BSSGP_IEI_CAUSE, NULL, 
4645       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4646   };
4647   bi->dl_data = TRUE;
4648   bi->ul_data = FALSE;
4649
4650   decode_pdu_general(ies, 3, bi);
4651 }
4652
4653 static void 
4654 decode_pdu_resume(build_info_t *bi) {
4655   bssgp_ie_t ies[] = {
4656     { BSSGP_IEI_TLLI, NULL, 
4657       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4658
4659     { BSSGP_IEI_ROUTEING_AREA, NULL, 
4660       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 8 },
4661
4662     { BSSGP_IEI_SUSPEND_REFERENCE_NUMBER, NULL, 
4663       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4664   };
4665   bi->dl_data = FALSE;
4666   bi->ul_data = TRUE;
4667
4668   decode_pdu_general(ies, 3, bi);
4669 }
4670
4671 static void 
4672 decode_pdu_resume_ack(build_info_t *bi) {
4673   bssgp_ie_t ies[] = {
4674     { BSSGP_IEI_TLLI, NULL, 
4675       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4676
4677     { BSSGP_IEI_ROUTEING_AREA, NULL, 
4678       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 8 },
4679
4680   };
4681   bi->dl_data = TRUE;
4682   bi->ul_data = FALSE;
4683
4684   decode_pdu_general(ies, 2, bi);
4685 }
4686
4687 static void 
4688 decode_pdu_resume_nack(build_info_t *bi) {
4689   bssgp_ie_t ies[] = {
4690     { BSSGP_IEI_TLLI, NULL, 
4691       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4692
4693     { BSSGP_IEI_ROUTEING_AREA, NULL, 
4694       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 8 },
4695
4696     { BSSGP_IEI_CAUSE, NULL, 
4697       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4698   };
4699   bi->dl_data = TRUE;
4700   bi->ul_data = FALSE;
4701
4702   decode_pdu_general(ies, 3, bi);
4703 }
4704
4705 static void 
4706 decode_pdu_bvc_block(build_info_t *bi) {
4707   bssgp_ie_t ies[] = {
4708     { BSSGP_IEI_BVCI, NULL, 
4709       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4710
4711     { BSSGP_IEI_CAUSE, NULL, 
4712       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4713   };
4714   bi->dl_data = FALSE;
4715   bi->ul_data = TRUE;
4716
4717   decode_pdu_general(ies, 2, bi);
4718 }
4719
4720 static void 
4721 decode_pdu_bvc_block_ack(build_info_t *bi) {
4722   bssgp_ie_t ies[] = {
4723     { BSSGP_IEI_BVCI, NULL, 
4724       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4},
4725   };
4726   bi->dl_data = TRUE;
4727   bi->ul_data = FALSE;
4728
4729   decode_pdu_general(ies, 1, bi);
4730 }
4731
4732 static void 
4733 decode_pdu_bvc_reset(build_info_t *bi) {
4734   bssgp_ie_t ies[] = {
4735     { BSSGP_IEI_BVCI, NULL, 
4736       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4737
4738     { BSSGP_IEI_CAUSE, NULL, 
4739       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4740
4741     { BSSGP_IEI_CELL_IDENTIFIER, NULL, 
4742       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 10 },
4743
4744     { BSSGP_IEI_FEATURE_BITMAP, NULL, 
4745       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4746   };
4747   bi->dl_data = TRUE;
4748   bi->ul_data = TRUE;
4749
4750   decode_pdu_general(ies, 4, bi);
4751 }
4752
4753 static void 
4754 decode_pdu_bvc_reset_ack(build_info_t *bi) {
4755   bssgp_ie_t ies[] = {
4756     { BSSGP_IEI_BVCI, NULL, 
4757       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4758
4759     { BSSGP_IEI_CELL_IDENTIFIER, NULL, 
4760       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 10 },
4761
4762     { BSSGP_IEI_FEATURE_BITMAP, NULL, 
4763       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4764   };
4765   bi->dl_data = TRUE;
4766   bi->ul_data = TRUE;
4767
4768   decode_pdu_general(ies, 3, bi);
4769 }
4770
4771 static void 
4772 decode_pdu_bvc_unblock(build_info_t *bi) {
4773   bssgp_ie_t ies[] = {
4774     { BSSGP_IEI_BVCI, NULL, 
4775       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4776   };
4777   bi->dl_data = FALSE;
4778   bi->ul_data = TRUE;
4779
4780   decode_pdu_general(ies, 1, bi);
4781 }
4782
4783 static void 
4784 decode_pdu_bvc_unblock_ack(build_info_t *bi) {
4785   bssgp_ie_t ies[] = {
4786     { BSSGP_IEI_BVCI, NULL, 
4787       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4788   };
4789   bi->dl_data = TRUE;
4790   bi->ul_data = FALSE;
4791
4792   decode_pdu_general(ies, 1, bi);
4793 }
4794
4795 static void 
4796 decode_pdu_flow_control_bvc(build_info_t *bi) {
4797   bssgp_ie_t ies[] = {
4798     { BSSGP_IEI_TAG, NULL, 
4799       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4800
4801     { BSSGP_IEI_BVC_BUCKET_SIZE, NULL, 
4802       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4803
4804     { BSSGP_IEI_BUCKET_LEAK_RATE, NULL, 
4805       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4806
4807     { BSSGP_IEI_BMAX_DEFAULT_MS, NULL, 
4808       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4809
4810     { BSSGP_IEI_R_DEFAULT_MS, NULL, 
4811       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4812
4813     { BSSGP_IEI_BUCKET_FULL_RATIO, NULL, 
4814       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4815
4816     { BSSGP_IEI_BVC_MEASUREMENT, NULL, 
4817       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4818   };
4819   bi->dl_data = FALSE;
4820   bi->ul_data = TRUE;
4821
4822   decode_pdu_general(ies, 7, bi);
4823 }
4824
4825 static void 
4826 decode_pdu_flow_control_bvc_ack(build_info_t *bi) {
4827   bssgp_ie_t ies[] = {
4828     { BSSGP_IEI_TAG, NULL, 
4829       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4830   };
4831   bi->dl_data = TRUE;
4832   bi->ul_data = FALSE;
4833
4834   decode_pdu_general(ies, 1, bi);
4835 }
4836
4837 static void 
4838 decode_pdu_flow_control_ms(build_info_t *bi) {
4839   bssgp_ie_t ies[] = {
4840     { BSSGP_IEI_TLLI, NULL, 
4841       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4842
4843     { BSSGP_IEI_TAG, NULL, 
4844       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4845
4846     { BSSGP_IEI_MS_BUCKET_SIZE, NULL, 
4847       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4848
4849     { BSSGP_IEI_BUCKET_LEAK_RATE, NULL, 
4850       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4851
4852     { BSSGP_IEI_BUCKET_FULL_RATIO, NULL, 
4853       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4854   };
4855   bi->dl_data = FALSE;
4856   bi->ul_data = TRUE;
4857
4858   decode_pdu_general(ies, 5, bi);
4859 }
4860
4861 static void 
4862 decode_pdu_flow_control_ms_ack(build_info_t *bi) {
4863   bssgp_ie_t ies[] = {
4864     { BSSGP_IEI_TLLI, NULL, 
4865       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4866
4867     { BSSGP_IEI_TAG, NULL, 
4868       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4869   };
4870   bi->dl_data = TRUE;
4871   bi->ul_data = FALSE;
4872
4873   decode_pdu_general(ies, 2, bi);
4874 }
4875
4876 static void 
4877 decode_pdu_flush_ll(build_info_t *bi) {
4878   bssgp_ie_t ies[] = {
4879     { BSSGP_IEI_TLLI, NULL, 
4880       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4881
4882     { BSSGP_IEI_BVCI, "BVCI (old)", 
4883       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4884
4885     { BSSGP_IEI_BVCI, "BVCI (new)", 
4886       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4887
4888     { BSSGP_IEI_NSEI, "NSEI (new)", 
4889       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4890   };
4891   bi->dl_data = TRUE;
4892   bi->ul_data = FALSE;
4893
4894   decode_pdu_general(ies, 4, bi);
4895 }
4896
4897 static void 
4898 decode_pdu_flush_ll_ack(build_info_t *bi) {
4899   bssgp_ie_t ies[] = {
4900     { BSSGP_IEI_TLLI, NULL, 
4901       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4902
4903     { BSSGP_IEI_FLUSH_ACTION, NULL, 
4904       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4905
4906     { BSSGP_IEI_BVCI, "BVCI (new)", 
4907       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4908
4909     { BSSGP_IEI_NUMBER_OF_OCTETS_AFFECTED, NULL, 
4910       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 5 },
4911
4912     { BSSGP_IEI_NSEI, "NSEI (new)", 
4913       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4914   };
4915   bi->dl_data = FALSE;
4916   bi->ul_data = TRUE;
4917
4918   decode_pdu_general(ies, 5, bi);
4919 }
4920
4921 static void 
4922 decode_pdu_llc_discarded(build_info_t *bi) {
4923   bssgp_ie_t ies[] = {
4924     { BSSGP_IEI_TLLI, NULL, 
4925       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4926
4927     { BSSGP_IEI_LLC_FRAMES_DISCARDED, NULL, 
4928       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4929
4930     { BSSGP_IEI_BVCI, NULL, 
4931       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4932
4933     { BSSGP_IEI_NUMBER_OF_OCTETS_AFFECTED, "Number of octets deleted", 
4934       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 5 },
4935
4936     { BSSGP_IEI_PFI, NULL, 
4937       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4938   };
4939   bi->dl_data = FALSE;
4940   bi->ul_data = TRUE;
4941
4942   decode_pdu_general(ies, 5, bi);
4943 }
4944
4945 static void 
4946 decode_pdu_flow_control_pfc(build_info_t *bi) {
4947   bssgp_ie_t ies[] = {
4948     { BSSGP_IEI_TLLI, NULL, 
4949       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4950
4951     { BSSGP_IEI_TAG, NULL, 
4952       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4953
4954     { BSSGP_IEI_MS_BUCKET_SIZE, NULL, 
4955       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4956
4957     { BSSGP_IEI_BUCKET_LEAK_RATE, NULL, 
4958       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4959
4960     { BSSGP_IEI_BUCKET_FULL_RATIO, NULL, 
4961       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4962
4963     { BSSGP_IEI_PFC_FLOW_CONTROL_PARAMETERS, NULL, 
4964       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
4965   };
4966   bi->dl_data = FALSE;
4967   bi->ul_data = TRUE;
4968
4969   decode_pdu_general(ies, 6, bi);
4970 }
4971
4972 static void 
4973 decode_pdu_flow_control_pfc_ack(build_info_t *bi) {
4974   bssgp_ie_t ies[] = {
4975     { BSSGP_IEI_TLLI, NULL, 
4976       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
4977
4978     { BSSGP_IEI_TAG, NULL, 
4979       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4980   };
4981   bi->dl_data = TRUE;
4982   bi->ul_data = FALSE;
4983
4984   decode_pdu_general(ies, 2, bi);
4985 }
4986
4987 static void 
4988 decode_pdu_sgsn_invoke_trace(build_info_t *bi) {
4989   bssgp_ie_t ies[] = {
4990     { BSSGP_IEI_TRACE_TYPE, NULL, 
4991       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
4992
4993     { BSSGP_IEI_TRACE_REFERENCE, NULL, 
4994       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
4995
4996     { BSSGP_IEI_TRIGGER_ID, NULL, 
4997       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
4998
4999     { BSSGP_IEI_MOBILE_ID, NULL, 
5000       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5001
5002     { BSSGP_IEI_OMC_ID, NULL, 
5003       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5004
5005     { BSSGP_IEI_TRANSACTION_ID, NULL, 
5006       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
5007   };
5008   bi->dl_data = TRUE;
5009   bi->ul_data = FALSE;
5010
5011   decode_pdu_general(ies, 6, bi);
5012 }
5013
5014 static void 
5015 decode_pdu_status(build_info_t *bi) {
5016   bssgp_ie_t ies[] = {
5017     { BSSGP_IEI_CAUSE, NULL, 
5018       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5019
5020     { BSSGP_IEI_BVCI, NULL, 
5021       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
5022
5023     { BSSGP_IEI_PDU_IN_ERROR, NULL, 
5024       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5025   };
5026   bi->dl_data = TRUE;
5027   bi->ul_data = TRUE;
5028
5029   decode_pdu_general(ies, 3, bi);
5030 }
5031
5032 static void 
5033 decode_pdu_download_bss_pfc(build_info_t *bi) {
5034   bssgp_ie_t ies[] = {
5035     { BSSGP_IEI_TLLI, NULL, 
5036       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
5037
5038     { BSSGP_IEI_PFI, NULL, 
5039       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5040   };
5041   bi->dl_data = FALSE;
5042   bi->ul_data = TRUE;
5043
5044   decode_pdu_general(ies, 2, bi);
5045 }
5046
5047 static void 
5048 decode_pdu_create_bss_pfc(build_info_t *bi) {
5049   bssgp_ie_t ies[] = {
5050     { BSSGP_IEI_TLLI, NULL, 
5051       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
5052
5053     { BSSGP_IEI_IMSI, NULL, 
5054       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5055
5056     { BSSGP_IEI_PFI, NULL, 
5057       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5058
5059     { BSSGP_IEI_GPRS_TIMER, "PFT", 
5060       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5061
5062     { BSSGP_IEI_ABQP, NULL, 
5063       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5064
5065     { BSSGP_IEI_SERVICE_UTRAN_CCO, NULL, 
5066       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5067
5068     { BSSGP_IEI_MS_RADIO_ACCESS_CAPABILITY, NULL, 
5069       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5070
5071     { BSSGP_IEI_PRIORITY, "Allocation/Retention Priority", 
5072       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5073
5074     { BSSGP_IEI_GPRS_TIMER, "T10", 
5075       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5076   };
5077   bi->dl_data = TRUE;
5078   bi->ul_data = FALSE;
5079
5080   decode_pdu_general(ies, 9, bi);
5081 }
5082
5083 static void 
5084 decode_pdu_create_bss_pfc_ack(build_info_t *bi) {
5085   bssgp_ie_t ies[] = {
5086     { BSSGP_IEI_TLLI, NULL, 
5087       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
5088
5089     { BSSGP_IEI_PFI, NULL, 
5090       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5091
5092     { BSSGP_IEI_ABQP, NULL, 
5093       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5094
5095     { BSSGP_IEI_CAUSE, NULL, 
5096       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5097   };
5098   bi->dl_data = FALSE;
5099   bi->ul_data = TRUE;
5100
5101   decode_pdu_general(ies, 4, bi);
5102 }
5103
5104 static void 
5105 decode_pdu_create_bss_pfc_nack(build_info_t *bi) {
5106   bssgp_ie_t ies[] = {
5107     { BSSGP_IEI_TLLI, NULL, 
5108       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
5109
5110     { BSSGP_IEI_PFI, NULL, 
5111       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5112
5113     { BSSGP_IEI_CAUSE, NULL, 
5114       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5115   };
5116   bi->dl_data = FALSE;
5117   bi->ul_data = TRUE;
5118
5119   decode_pdu_general(ies, 3, bi);
5120 }
5121
5122 static void 
5123 decode_pdu_modify_bss_pfc(build_info_t *bi) {
5124   bssgp_ie_t ies[] = {
5125     { BSSGP_IEI_TLLI, NULL, 
5126       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
5127
5128     { BSSGP_IEI_PFI, NULL, 
5129       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5130
5131     { BSSGP_IEI_ABQP, NULL, 
5132       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5133   };
5134   bi->dl_data = FALSE;
5135   bi->ul_data = TRUE;
5136
5137   decode_pdu_general(ies, 3, bi);
5138 }
5139
5140 static void 
5141 decode_pdu_modify_bss_pfc_ack(build_info_t *bi) {
5142   bssgp_ie_t ies[] = {
5143     { BSSGP_IEI_TLLI, NULL, 
5144       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
5145
5146     { BSSGP_IEI_PFI, NULL, 
5147       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5148
5149     { BSSGP_IEI_GPRS_TIMER, "PFT", 
5150       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5151
5152     { BSSGP_IEI_ABQP, NULL, 
5153       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5154   };
5155   bi->dl_data = TRUE;
5156   bi->ul_data = FALSE;
5157
5158   decode_pdu_general(ies, 4, bi);
5159 }
5160
5161 static void 
5162 decode_pdu_delete_bss_pfc(build_info_t *bi) {
5163   bssgp_ie_t ies[] = {
5164     { BSSGP_IEI_TLLI, NULL, 
5165       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
5166
5167     { BSSGP_IEI_PFI, NULL, 
5168       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5169   };
5170   bi->dl_data = TRUE;
5171   bi->ul_data = FALSE;
5172
5173   decode_pdu_general(ies, 2, bi);
5174 }
5175
5176 static void 
5177 decode_pdu_delete_bss_pfc_ack(build_info_t *bi) {
5178   bssgp_ie_t ies[] = {
5179     { BSSGP_IEI_TLLI, NULL, 
5180       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
5181
5182     { BSSGP_IEI_PFI, NULL, 
5183       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5184   };
5185   bi->dl_data = FALSE;
5186   bi->ul_data = TRUE;
5187
5188   decode_pdu_general(ies, 2, bi);
5189 }
5190
5191 static void 
5192 decode_pdu_delete_bss_pfc_req(build_info_t *bi) {
5193   bssgp_ie_t ies[] = {
5194     { BSSGP_IEI_TLLI, NULL, 
5195       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
5196
5197     { BSSGP_IEI_PFI, NULL, 
5198       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5199
5200     { BSSGP_IEI_CAUSE, NULL, 
5201       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5202   };
5203   bi->dl_data = FALSE;
5204   bi->ul_data = TRUE;
5205
5206   decode_pdu_general(ies, 3, bi);
5207 }
5208
5209 static void 
5210 decode_pdu_perform_location_request(build_info_t *bi) {
5211   bssgp_ie_t ies[] = {
5212     { BSSGP_IEI_TLLI, NULL, 
5213       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
5214
5215     { BSSGP_IEI_IMSI, NULL, 
5216       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5217
5218     { BSSGP_IEI_DRX_PARAMETERS, NULL, 
5219       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
5220
5221     { BSSGP_IEI_BVCI, "BVCI (PCU-PTP)", 
5222       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
5223
5224     { BSSGP_IEI_NSEI, "NSEI (PCU-PTP)", 
5225       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5226
5227     { BSSGP_IEI_LOCATION_TYPE, NULL, 
5228       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5229
5230     { BSSGP_IEI_CELL_IDENTIFIER, NULL, 
5231       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 10 },
5232
5233     { BSSGP_IEI_LCS_CAPABILITY, NULL, 
5234       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5235
5236     { BSSGP_IEI_LCS_PRIORITY, NULL, 
5237       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5238
5239     { BSSGP_IEI_LCS_QOS, NULL, 
5240       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5241
5242     { BSSGP_IEI_LCS_CLIENT_TYPE, NULL, 
5243       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5244
5245     { BSSGP_IEI_REQUESTED_GPS_ASSISTANCE_DATA, NULL, 
5246       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5247   };
5248   bi->dl_data = TRUE;
5249   bi->ul_data = FALSE;
5250
5251   decode_pdu_general(ies, 12, bi);
5252 }
5253
5254 static void 
5255 decode_pdu_perform_location_response(build_info_t *bi) {
5256   bssgp_ie_t ies[] = {
5257     { BSSGP_IEI_TLLI, NULL, 
5258       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
5259
5260     { BSSGP_IEI_BVCI, "BVCI (PCU-PTP)", 
5261       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
5262
5263     { BSSGP_IEI_LOCATION_ESTIMATE, NULL, 
5264       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5265
5266     { BSSGP_IEI_POSITIONING_DATA, NULL, 
5267       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5268
5269     { BSSGP_IEI_DECIPHERING_KEYS, NULL, 
5270       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5271
5272     { BSSGP_IEI_LCS_CAUSE, NULL, 
5273       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5274   };
5275   bi->dl_data = FALSE;
5276   bi->ul_data = TRUE;
5277
5278   decode_pdu_general(ies, 6, bi);
5279 }
5280
5281 static void 
5282 decode_pdu_perform_location_abort(build_info_t *bi) {
5283   bssgp_ie_t ies[] = {
5284     { BSSGP_IEI_TLLI, NULL, 
5285       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
5286
5287     { BSSGP_IEI_BVCI, "BVCI (PCU-PTP)", 
5288       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
5289
5290     { BSSGP_IEI_LCS_CAUSE, NULL, 
5291       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5292   };
5293   bi->dl_data = TRUE;
5294   bi->ul_data = FALSE;
5295
5296   decode_pdu_general(ies, 3, bi);
5297 }
5298
5299 static void 
5300 decode_pdu_position_command(build_info_t *bi) {
5301   bssgp_ie_t ies[] = {
5302     { BSSGP_IEI_TLLI, NULL, 
5303       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
5304
5305     { BSSGP_IEI_BVCI, "BVCI (PCU-PTP)", 
5306       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
5307
5308     { BSSGP_IEI_RRLP_FLAGS, NULL, 
5309       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5310
5311     { BSSGP_IEI_RRLP_APDU, NULL, 
5312       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5313   };
5314   bi->dl_data = FALSE;
5315   bi->ul_data = TRUE;
5316
5317   decode_pdu_general(ies, 4, bi);
5318 }
5319
5320 static void 
5321 decode_pdu_position_response(build_info_t *bi) {
5322   bssgp_ie_t ies[] = {
5323     { BSSGP_IEI_TLLI, NULL, 
5324       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 6 },
5325
5326     { BSSGP_IEI_BVCI, "BVCI (PCU-PTP)", 
5327       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
5328
5329     { BSSGP_IEI_RRLP_FLAGS, NULL, 
5330       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5331
5332     { BSSGP_IEI_RRLP_APDU, NULL, 
5333       BSSGP_IE_PRESENCE_C, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5334
5335     { BSSGP_IEI_LCS_CAUSE, NULL, 
5336       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5337   };
5338   bi->dl_data = TRUE;
5339   bi->ul_data = FALSE;
5340
5341   decode_pdu_general(ies, 5, bi);
5342 }
5343
5344
5345 static void 
5346 decode_pdu_ran_information(build_info_t *bi) {
5347   bssgp_ie_t ies[] = {
5348     { BSSGP_IEI_CELL_IDENTIFIER, "Destination Cell identifier", 
5349       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 10 },
5350
5351     { BSSGP_IEI_CELL_IDENTIFIER, "Source Cell Identifier", 
5352       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 10 },
5353
5354     { BSSGP_IEI_RIM_APPLICATION_IDENTITY, NULL, 
5355       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5356
5357     { BSSGP_IEI_RIM_SEQUENCE_NUMBER, "Sequence Number", 
5358       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
5359
5360     { BSSGP_IEI_RAN_INFORMATION_INDICATIONS, NULL, 
5361       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5362
5363     { BSSGP_IEI_CAUSE, "RIM Cause", 
5364       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5365
5366     { BSSGP_IEI_NUMBER_OF_CONTAINER_UNITS, NULL, 
5367       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5368
5369     { BSSGP_IEI_RAN_INFORMATION_CONTAINER_UNIT, "Container Unit", 
5370       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5371   };
5372   bi->dl_data = TRUE;
5373   bi->ul_data = TRUE;
5374
5375   decode_pdu_general(ies, 7, bi);
5376
5377   while (tvb_length_remaining(bi->tvb, bi->offset) >= 4) {
5378     guint32 org_offset = bi->offset;
5379
5380     decode_ie(&ies[7], bi);
5381
5382     /* prevent an endless loop */
5383     if(org_offset == bi->offset) {
5384         THROW(ReportedBoundsError);
5385     }
5386   }
5387 }
5388
5389 static void 
5390 decode_pdu_ran_information_request(build_info_t *bi) {
5391   const guint8 MASK_EVENT_MR = 0x01;
5392   guint8 value;
5393   
5394   bssgp_ie_t ies[] = {
5395     { BSSGP_IEI_CELL_IDENTIFIER, "Destination Cell Identifier", 
5396       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 10 },
5397
5398     { BSSGP_IEI_CELL_IDENTIFIER, "Source Cell Identifier", 
5399       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 10 },
5400
5401     { BSSGP_IEI_RIM_APPLICATION_IDENTITY, NULL, 
5402       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5403
5404     { BSSGP_IEI_RIM_SEQUENCE_NUMBER, "Sequence Number", 
5405       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
5406     /* Unknown IEI! 
5407        { BSSGP_IEI_RAN_INFORMATION_REQUEST_INDICATIONS, NULL, 
5408        BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5409     */
5410     { BSSGP_IEI_RAN_INFORMATION_REQUEST_CONTAINER_UNIT, "Container Unit", 
5411       BSSGP_IE_PRESENCE_O, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5412   };
5413
5414   bi->dl_data = TRUE;
5415   bi->ul_data = TRUE;
5416   
5417   decode_pdu_general(ies, 4, bi);
5418
5419   /* Account for type and length; assume length field = 1 as total length = 3: */
5420   bi->offset += 2; 
5421   if (bi->bssgp_tree) {
5422     value = tvb_get_masked_guint8(bi->tvb, bi->offset, MASK_EVENT_MR);
5423     proto_tree_add_text(bi->bssgp_tree, bi->tvb, bi->offset - 2, 3, 
5424                         "RAN Information Request Indications: Event MR = %u: %s-driven multiple reports requested",
5425                         value, 
5426                         value == 0 ? "No event" : "Event");
5427   }
5428   bi->offset++;
5429   decode_pdu_general(&ies[5], 1, bi);
5430 }
5431
5432 static void 
5433 decode_pdu_ran_information_ack(build_info_t *bi) {
5434   bssgp_ie_t ies[] = {
5435     { BSSGP_IEI_CELL_IDENTIFIER, "Destination Cell Identifier", 
5436       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 10 },
5437
5438     { BSSGP_IEI_CELL_IDENTIFIER, "Source Cell Identifier", 
5439       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 10 },
5440
5441     { BSSGP_IEI_RIM_APPLICATION_IDENTITY, NULL, 
5442       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5443
5444     { BSSGP_IEI_RIM_SEQUENCE_NUMBER, "Sequence Number", 
5445       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 4 },
5446   };
5447   bi->dl_data = TRUE;
5448   bi->ul_data = TRUE;
5449
5450   decode_pdu_general(ies, 4, bi);
5451 }
5452
5453 static void 
5454 decode_pdu_ran_information_error(build_info_t *bi) {
5455   bssgp_ie_t ies[] = {
5456     { BSSGP_IEI_CELL_IDENTIFIER, "Destination Cell Identifier", 
5457       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 10 },
5458
5459     { BSSGP_IEI_CELL_IDENTIFIER, "Source Cell Identifier", 
5460       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 10 },
5461
5462     { BSSGP_IEI_RIM_APPLICATION_IDENTITY, NULL, 
5463       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5464
5465     { BSSGP_IEI_CAUSE, "RIM Cause", 
5466       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, 3 },
5467
5468     { BSSGP_IEI_PDU_IN_ERROR, NULL, 
5469       BSSGP_IE_PRESENCE_M, BSSGP_IE_FORMAT_TLV, BSSGP_UNKNOWN, BSSGP_UNKNOWN },
5470   };
5471   bi->dl_data = TRUE;
5472   bi->ul_data = TRUE;
5473
5474   decode_pdu_general(ies, 5, bi);
5475 }
5476
5477 static void
5478 decode_pdu(guint8 pdutype, build_info_t *bi) {
5479
5480   switch (pdutype) {
5481   case BSSGP_PDU_DL_UNITDATA:
5482     decode_pdu_dl_unitdata(bi);
5483     break;
5484   case BSSGP_PDU_UL_UNITDATA:
5485     decode_pdu_ul_unitdata(bi);
5486     break; 
5487   case BSSGP_PDU_RA_CAPABILITY:
5488     decode_pdu_ra_capability(bi);
5489     break;
5490   case BSSGP_PDU_PTM_UNITDATA:
5491     decode_pdu_ptm_unitdata(bi);
5492     break;
5493   case BSSGP_PDU_PAGING_PS:
5494     decode_pdu_paging_ps(bi);
5495     break;
5496   case BSSGP_PDU_PAGING_CS:
5497     decode_pdu_paging_cs(bi);
5498     break;
5499   case BSSGP_PDU_RA_CAPABILITY_UPDATE:
5500     decode_pdu_ra_capability_update(bi);
5501     break;
5502   case BSSGP_PDU_RA_CAPABILITY_UPDATE_ACK:
5503     decode_pdu_ra_capability_update_ack(bi);
5504     break;
5505   case BSSGP_PDU_RADIO_STATUS:
5506     decode_pdu_radio_status(bi);
5507     break;
5508   case BSSGP_PDU_SUSPEND:
5509     decode_pdu_suspend(bi);
5510     break;
5511   case BSSGP_PDU_SUSPEND_ACK:
5512     decode_pdu_suspend_ack(bi);
5513     break;
5514   case BSSGP_PDU_SUSPEND_NACK:
5515     decode_pdu_suspend_nack(bi);
5516     break;
5517   case BSSGP_PDU_RESUME:
5518     decode_pdu_resume(bi);
5519     break;
5520   case BSSGP_PDU_RESUME_ACK:
5521     decode_pdu_resume_ack(bi);
5522     break;
5523   case BSSGP_PDU_RESUME_NACK:
5524     decode_pdu_resume_nack(bi);
5525     break;
5526   case BSSGP_PDU_BVC_BLOCK:
5527     decode_pdu_bvc_block(bi);
5528     break;
5529   case BSSGP_PDU_BVC_BLOCK_ACK:
5530     decode_pdu_bvc_block_ack(bi);
5531     break;
5532   case BSSGP_PDU_BVC_RESET:
5533     decode_pdu_bvc_reset(bi);
5534     break;
5535   case BSSGP_PDU_BVC_RESET_ACK:
5536     decode_pdu_bvc_reset_ack(bi);
5537     break;
5538   case BSSGP_PDU_BVC_UNBLOCK:
5539     decode_pdu_bvc_unblock(bi);
5540     break;
5541   case BSSGP_PDU_BVC_UNBLOCK_ACK:
5542     decode_pdu_bvc_unblock_ack(bi);
5543     break;
5544   case BSSGP_PDU_FLOW_CONTROL_BVC:
5545     decode_pdu_flow_control_bvc(bi);
5546     break;
5547   case BSSGP_PDU_FLOW_CONTROL_BVC_ACK:
5548     decode_pdu_flow_control_bvc_ack(bi);
5549     break;
5550   case BSSGP_PDU_FLOW_CONTROL_MS:
5551     decode_pdu_flow_control_ms(bi);
5552     break;
5553   case BSSGP_PDU_FLOW_CONTROL_MS_ACK:
5554     decode_pdu_flow_control_ms_ack(bi);
5555     break;
5556   case BSSGP_PDU_FLUSH_LL:
5557     decode_pdu_flush_ll(bi);
5558     break;
5559   case BSSGP_PDU_FLUSH_LL_ACK:
5560     decode_pdu_flush_ll_ack(bi);
5561     break;
5562   case BSSGP_PDU_LLC_DISCARDED:
5563     decode_pdu_llc_discarded(bi);
5564     break;
5565   case BSSGP_PDU_FLOW_CONTROL_PFC:
5566     decode_pdu_flow_control_pfc(bi);
5567     break;
5568   case BSSGP_PDU_FLOW_CONTROL_PFC_ACK:
5569     decode_pdu_flow_control_pfc_ack(bi);
5570     break;
5571   case BSSGP_PDU_SGSN_INVOKE_TRACE:
5572     decode_pdu_sgsn_invoke_trace(bi);
5573     break;
5574   case BSSGP_PDU_STATUS:
5575     decode_pdu_status(bi);
5576     break;
5577   case BSSGP_PDU_DOWNLOAD_BSS_PFC:
5578     decode_pdu_download_bss_pfc(bi);
5579     break;
5580   case BSSGP_PDU_CREATE_BSS_PFC:
5581     decode_pdu_create_bss_pfc(bi);
5582     break;
5583   case BSSGP_PDU_CREATE_BSS_PFC_ACK:
5584     decode_pdu_create_bss_pfc_ack(bi);
5585     break;
5586   case BSSGP_PDU_CREATE_BSS_PFC_NACK:
5587     decode_pdu_create_bss_pfc_nack(bi);
5588     break;
5589   case BSSGP_PDU_MODIFY_BSS_PFC:
5590     decode_pdu_modify_bss_pfc(bi);
5591     break;
5592   case BSSGP_PDU_MODIFY_BSS_PFC_ACK:
5593     decode_pdu_modify_bss_pfc_ack(bi);
5594     break;
5595   case BSSGP_PDU_DELETE_BSS_PFC:
5596     decode_pdu_delete_bss_pfc(bi);
5597     break;
5598   case BSSGP_PDU_DELETE_BSS_PFC_ACK:
5599     decode_pdu_delete_bss_pfc_ack(bi);
5600     break;
5601   case BSSGP_PDU_DELETE_BSS_PFC_REQ:
5602     decode_pdu_delete_bss_pfc_req(bi);
5603     break;
5604   case BSSGP_PDU_PERFORM_LOCATION_REQUEST:
5605     decode_pdu_perform_location_request(bi);
5606     break;
5607   case BSSGP_PDU_PERFORM_LOCATION_RESPONSE:
5608     decode_pdu_perform_location_response(bi);
5609     break;
5610   case BSSGP_PDU_PERFORM_LOCATION_ABORT:
5611     decode_pdu_perform_location_abort(bi);
5612     break;
5613   case BSSGP_PDU_POSITION_COMMAND:
5614     decode_pdu_position_command(bi);
5615     break;
5616   case BSSGP_PDU_POSITION_RESPONSE:
5617     decode_pdu_position_response(bi);
5618     break;
5619   case BSSGP_PDU_RAN_INFORMATION:
5620     decode_pdu_ran_information(bi);
5621     break;
5622   case BSSGP_PDU_RAN_INFORMATION_REQUEST:
5623     decode_pdu_ran_information_request(bi);
5624     break;
5625   case BSSGP_PDU_RAN_INFORMATION_ACK:
5626     decode_pdu_ran_information_ack(bi);
5627     break;
5628   case BSSGP_PDU_RAN_INFORMATION_ERROR:
5629     decode_pdu_ran_information_error(bi);
5630     break;
5631   default:
5632     ;
5633   }
5634 }
5635
5636 static void
5637 dissect_bssgp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
5638 {
5639   guint8 pdutype;
5640   build_info_t bi = { NULL, 0, NULL, NULL, NULL, FALSE, FALSE };
5641
5642   proto_item *ti;
5643   proto_tree *bssgp_tree;
5644
5645   bi.tvb = tvb;
5646   bi.pinfo = pinfo;
5647   bi.parent_tree = tree;
5648
5649   pinfo->current_proto = "BSSGP";
5650
5651   if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
5652     col_set_str(pinfo->cinfo, COL_PROTOCOL, "BSSGP");
5653     
5654   if (check_col(pinfo->cinfo, COL_INFO)) 
5655     col_clear(pinfo->cinfo, COL_INFO);
5656
5657   pdutype = tvb_get_guint8(tvb, 0);
5658   bi.offset++;
5659
5660   if (tree) {
5661     ti = proto_tree_add_item(tree, proto_bssgp, tvb, 0, -1, FALSE);
5662     bssgp_tree = proto_item_add_subtree(ti, ett_bssgp);
5663     proto_tree_add_uint_format(bssgp_tree, hf_bssgp_pdu_type, tvb, 0, 1, 
5664                                pdutype,
5665                                "PDU Type: %s (%#02x)",
5666                                val_to_str(pdutype, tab_bssgp_pdu_types, 
5667                                           "Unknown"), pdutype);
5668     bi.bssgp_tree = bssgp_tree;
5669   }
5670   
5671   if (check_col(pinfo->cinfo, COL_INFO)) {
5672     col_add_str(pinfo->cinfo, COL_INFO, val_to_str(pdutype, 
5673                                                    tab_bssgp_pdu_types, 
5674                                                    "Unknown PDU type"));
5675   }
5676   decode_pdu(pdutype, &bi);
5677 }
5678
5679 void
5680 proto_register_bssgp(void)
5681 {                 
5682   static hf_register_info hf[] = {
5683     { &hf_bssgp_pdu_type,
5684       { "PDU Type", "bssgp.pdu_type",
5685         FT_UINT8, BASE_HEX, VALS(tab_bssgp_pdu_types), 0x0,          
5686         "", HFILL }
5687     },
5688     { &hf_bssgp_ie_type,
5689       { "IE Type", "bssgp.ie_type",
5690         FT_UINT8, BASE_HEX, VALS(tab_bssgp_ie_types), 0x0,          
5691         "Information element type", HFILL }
5692     },
5693     { &hf_bssgp_bvci,
5694       { "BVCI", "bssgp.bvci",
5695         FT_UINT16, BASE_HEX, NULL, 0x0,          
5696         "", HFILL }
5697     },
5698     { &hf_bssgp_tlli,
5699       { "TLLI", "bssgp.tlli",
5700         FT_UINT32, BASE_HEX, NULL, 0x0,          
5701         "", HFILL }
5702     },
5703     { &hf_bssgp_nsei,
5704       { "NSEI", "bssgp.nsei",
5705         FT_UINT16, BASE_HEX, NULL, 0x0,          
5706         "", HFILL }
5707     },
5708     { &hf_bssgp_mcc,
5709       { "MCC", "bssgp.mcc",
5710         FT_UINT8, BASE_DEC, NULL, 0x0,
5711         "", HFILL }
5712     },
5713     { &hf_bssgp_mnc,
5714       { "MNC", "bssgp.mnc",
5715         FT_UINT8, BASE_DEC, NULL, 0x0,
5716         "", HFILL }
5717     },
5718     { &hf_bssgp_lac,
5719       { "LAC", "bssgp.lac",
5720         FT_UINT16, BASE_DEC, NULL, 0x0,
5721         "", HFILL }
5722     },
5723     { &hf_bssgp_rac,
5724       { "RAC", "bssgp.rac",
5725         FT_UINT8, BASE_DEC, NULL, 0x0,
5726         "", HFILL }
5727     },
5728     { &hf_bssgp_ci,
5729       { "CI", "bssgp.ci",
5730         FT_UINT16, BASE_DEC, NULL, 0x0,
5731         "Cell Identity", HFILL }
5732     },
5733     { &hf_bssgp_tmsi_ptmsi,
5734       { "TMSI/PTMSI", "bssgp.tmsi_ptmsi",
5735         FT_UINT32, BASE_HEX, NULL, 0x0,
5736         "", HFILL }
5737     },
5738     { &hf_bssgp_imsi,
5739       { "IMSI", "bssgp.imsi",
5740         FT_STRING, BASE_NONE, NULL, 0x0,
5741         "", HFILL }
5742     },
5743     { &hf_bssgp_imei,
5744       { "IMEI", "bssgp.imei",
5745         FT_STRING, BASE_NONE, NULL, 0x0,
5746         "", HFILL }
5747     },
5748     { &hf_bssgp_imeisv,
5749       { "IMEISV", "bssgp.imeisv",
5750         FT_STRING, BASE_NONE, NULL, 0x0,
5751         "", HFILL }
5752     },
5753     { &hf_bssgp_nri,
5754       { "NRI", "bssgp.nri",
5755         FT_UINT16, BASE_DEC, NULL, 0x0,
5756         "", HFILL }
5757     },
5758   };
5759
5760   /* Setup protocol subtree array */
5761   static gint *ett[] = {
5762     &ett_bssgp,
5763     &ett_bssgp_qos_profile,
5764     &ett_bssgp_gprs_timer,
5765     &ett_bssgp_cell_identifier,
5766     &ett_bssgp_channel_needed,
5767     &ett_bssgp_drx_parameters,
5768     &ett_bssgp_mobile_identity,
5769     &ett_bssgp_priority,
5770     &ett_bssgp_lsa_identifier_list,
5771     &ett_bssgp_lsa_information,
5772     &ett_bssgp_lsa_information_lsa_identification_and_attributes,
5773     &ett_bssgp_abqp,
5774     &ett_bssgp_lcs_qos,
5775     &ett_bssgp_lcs_client_type,
5776     &ett_bssgp_requested_gps_assistance_data,
5777     &ett_bssgp_requested_gps_assistance_data_satellite,
5778     &ett_bssgp_location_type,
5779     &ett_bssgp_positioning_data_positioning_method,
5780     &ett_bssgp_lcs_cause,
5781     &ett_bssgp_lcs_capability,
5782     &ett_bssgp_rrlp_flags,
5783     &ett_bssgp_ran_information_indications,
5784     &ett_bssgp_mcc,
5785     &ett_bssgp_mnc,
5786     &ett_bssgp_routeing_area,
5787     &ett_bssgp_location_area,
5788     &ett_bssgp_rai_ci,
5789     &ett_bssgp_ran_information_request_container_unit,
5790     &ett_bssgp_ran_information_container_unit,
5791     &ett_bssgp_pfc_flow_control_parameters,
5792     &ett_bssgp_pfc_flow_control_parameters_pfc,
5793     &ett_bssgp_global_cn_id,
5794     &ett_bssgp_ms_radio_access_capability,
5795     &ett_bssgp_feature_bitmap,
5796     &ett_bssgp_positioning_data,
5797     &ett_bssgp_msrac_value_part,
5798     &ett_bssgp_msrac_additional_access_technologies,
5799     &ett_bssgp_msrac_access_capabilities,
5800     &ett_bssgp_msrac_a5_bits,
5801     &ett_bssgp_msrac_multislot_capability,
5802     &ett_bssgp_tlli,
5803   };
5804
5805   /* Register the protocol name and description */
5806   proto_bssgp = proto_register_protocol("Base Station Subsystem GPRS Protocol", "BSSGP", "bssgp");
5807
5808   /* Required function calls to register the header fields and subtrees used */
5809   proto_register_field_array(proto_bssgp, hf, array_length(hf));
5810   proto_register_subtree_array(ett, array_length(ett));
5811   register_dissector("bssgp", dissect_bssgp, proto_bssgp);
5812   
5813   /* Register configuration options */
5814   bssgp_module = prefs_register_protocol(proto_bssgp, proto_reg_handoff_bssgp);
5815   prefs_register_bool_preference(bssgp_module, "decode_nri",
5816                                  "Decode NRI",
5817                                  "Decode NRI (for use with SGSN in Pool)",
5818                                  &bssgp_decode_nri);
5819   prefs_register_uint_preference(bssgp_module, "nri_length", "NRI length",
5820                                  "NRI length, in bits",
5821                                  10, &bssgp_nri_length); 
5822 }
5823
5824 /* If this dissector uses sub-dissector registration add a registration routine.
5825 */
5826 void
5827 proto_reg_handoff_bssgp(void)
5828 {
5829   bssgp_handle = create_dissector_handle(dissect_bssgp, proto_bssgp);
5830   llc_handle = find_dissector("llcgprs");
5831   rrlp_handle = find_dissector("rrlp");
5832   data_handle = find_dissector("data");  
5833 }