/src/wireshark/epan/dissectors/packet-oer.c
Line | Count | Source |
1 | | /* packet-oer.c |
2 | | * Routines for ASN1 Octet Encoding Rules |
3 | | * |
4 | | * Copyright 2018, Anders Broman <anders.broman@ericsson.com> |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | * Ref: ITU-T X.696 (08/2015) https://www.itu.int/itu-t/recommendations/rec.aspx?rec=12487 |
12 | | * Based on the BER and PER dissectors by Ronnie Sahlberg. |
13 | | */ |
14 | | |
15 | | #include "config.h" |
16 | | |
17 | | #include <epan/packet.h> |
18 | | #include <epan/oids.h> |
19 | | #include <epan/asn1.h> |
20 | | #include <epan/expert.h> |
21 | | #include <epan/exceptions.h> |
22 | | #include <epan/to_str.h> |
23 | | |
24 | | #include <wsutil/array.h> |
25 | | |
26 | | #include "packet-oer.h" |
27 | | |
28 | | void proto_register_oer(void); |
29 | | void proto_reg_handoff_oer(void); |
30 | | |
31 | | /* Initialize the protocol and registered fields */ |
32 | | static int proto_oer; |
33 | | |
34 | | static int hf_oer_optional_field_bit; |
35 | | static int hf_oer_class; |
36 | | static int hf_oer_tag; |
37 | | static int hf_oer_length_determinant; |
38 | | static int hf_oer_extension_present_bit; |
39 | | static int hf_oer_open_type_length; |
40 | | |
41 | | /* Initialize the subtree pointers */ |
42 | | static int ett_oer; |
43 | | static int ett_oer_sequence_of_item; |
44 | | static int ett_oer_open_type; |
45 | | static int ett_oer_named_bits; |
46 | | |
47 | | static expert_field ei_oer_not_decoded_yet; |
48 | | static expert_field ei_oer_undecoded; |
49 | | static expert_field ei_oer_open_type; |
50 | | |
51 | | /* whether the OER helpers should put the internal OER fields into the tree or not. */ |
52 | | static bool display_internal_oer_fields; |
53 | | |
54 | | /* |
55 | | #define DEBUG_ENTRY(x) \ |
56 | | printf("#%u %s tvb:0x%08x\n",actx->pinfo->num,x,(int)tvb); |
57 | | */ |
58 | | #define DEBUG_ENTRY(x) \ |
59 | 9.97k | ; |
60 | | |
61 | 4.73k | #define SEQ_MAX_COMPONENTS 128 |
62 | | |
63 | | /* |
64 | | * XXX - if the specified length is less than the remaining length |
65 | | * of data in the tvbuff, either 1) the specified length is bad and |
66 | | * we should report that with an expert info or 2) the tvbuff is |
67 | | * unreassembled and we should make the new tvbuff also be an |
68 | | * unreassembled tvbuff. |
69 | | */ |
70 | | static tvbuff_t * |
71 | | oer_tvb_new_subset_length(tvbuff_t *tvb, const int backing_offset, const int backing_length) |
72 | 14 | { |
73 | 14 | int length_remaining; |
74 | | |
75 | 14 | length_remaining = tvb_reported_length_remaining(tvb, backing_offset); |
76 | 14 | return tvb_new_subset_length(tvb, backing_offset, (length_remaining > backing_length) ? backing_length : length_remaining); |
77 | 14 | } |
78 | | |
79 | | static void |
80 | | dissect_oer_not_decoded_yet(proto_tree* tree, packet_info* pinfo, tvbuff_t *tvb, const char* reason) |
81 | 35 | { |
82 | 35 | proto_tree_add_expert_format(tree, pinfo, &ei_oer_undecoded, tvb, 0, 0, "something unknown here [%s]", reason); |
83 | 35 | col_append_fstr(pinfo->cinfo, COL_INFO, "[UNKNOWN OER: %s]", reason); |
84 | 35 | THROW(ReportedBoundsError); |
85 | 35 | } |
86 | | |
87 | | /* Given the ordinal of the option in the sequence, print the name. eg find the 1:th then the 2:nd etc*/ |
88 | | static const char * |
89 | | index_get_optional_name(const oer_sequence_t *sequence, int idx) |
90 | 5.05k | { |
91 | 5.05k | int i; |
92 | 5.05k | header_field_info *hfi; |
93 | | |
94 | 28.7k | for (i = 0; sequence[i].p_id; i++) { |
95 | 28.7k | if ((sequence[i].extension != ASN1_NOT_EXTENSION_ROOT) && (sequence[i].optional == ASN1_OPTIONAL)) { |
96 | 15.8k | if (idx == 0) { |
97 | 5.05k | hfi = proto_registrar_get_nth(*sequence[i].p_id); |
98 | 5.05k | return (hfi) ? hfi->name : "<unknown field>"; |
99 | 5.05k | } |
100 | 10.8k | idx--; |
101 | 10.8k | } |
102 | 28.7k | } |
103 | 0 | return "<unknown type>"; |
104 | 5.05k | } |
105 | | |
106 | | |
107 | | static const char * |
108 | | index_get_field_name(const oer_sequence_t *sequence, int idx) |
109 | 0 | { |
110 | 0 | header_field_info *hfi; |
111 | |
|
112 | 0 | hfi = proto_registrar_get_nth(*sequence[idx].p_id); |
113 | 0 | return (hfi) ? hfi->name : "<unknown field>"; |
114 | 0 | } |
115 | | |
116 | | |
117 | | /* 8.6 Length determinant */ |
118 | | static uint32_t |
119 | | dissect_oer_length_determinant(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, uint32_t *length) |
120 | 3.22k | { |
121 | 3.22k | proto_item *item; |
122 | 3.22k | uint8_t oct, value_len; |
123 | 3.22k | uint32_t len; |
124 | | |
125 | 3.22k | if (!length) { |
126 | 0 | length = &len; |
127 | 0 | } |
128 | | |
129 | 3.22k | *length = 0; |
130 | | |
131 | | /* 8.6.3 There are two forms of length determinant - a short form and a long form... |
132 | | * 8.6.4 The short form of length determinant consists of a single octet. Bit 8 of this octet shall be set to '0', |
133 | | * and bits 7 to 1 of this octet shall contain the length (0 to 127) encoded as an unsigned binary integer into 7 bits. |
134 | | */ |
135 | 3.22k | oct = tvb_get_uint8(tvb, offset); |
136 | 3.22k | if ((oct & 0x80) == 0) { |
137 | | /* Short form */ |
138 | 3.11k | *length = oct; |
139 | 3.11k | if (hf_index > 0) { |
140 | 2.01k | item = proto_tree_add_item(tree, hf_index, tvb, offset, 1, ENC_BIG_ENDIAN); |
141 | 2.01k | if (!display_internal_oer_fields) proto_item_set_hidden(item); |
142 | 2.01k | } |
143 | 3.11k | offset++; |
144 | | |
145 | 3.11k | return offset; |
146 | 3.11k | } |
147 | 102 | offset++; |
148 | | /* Long form */ |
149 | | /* 8.6.5 The long form of length determinant consists of an initial octet followed by one or more subsequent octets. |
150 | | * Bit 8 of the initial octet shall be set to 1, and bits 7 to 1 of this octet shall indicate the number of subsequent octets (1 to 127). |
151 | | * The length shall be encoded as a variable-size unsigned number into the subsequent octets. |
152 | | */ |
153 | 102 | value_len = oct & 0x7f; |
154 | 102 | switch (value_len) { |
155 | 5 | case 1: |
156 | 5 | *length = tvb_get_uint8(tvb, offset); |
157 | 5 | offset++; |
158 | 5 | break; |
159 | 9 | case 2: |
160 | 9 | *length = tvb_get_ntohs(tvb, offset); |
161 | 9 | offset+=2; |
162 | 9 | break; |
163 | 5 | case 3: |
164 | 5 | *length = tvb_get_ntoh24(tvb, offset); |
165 | 5 | offset+=3; |
166 | 5 | break; |
167 | 4 | case 4: |
168 | 4 | *length = tvb_get_ntohl(tvb, offset); |
169 | 4 | offset+=4; |
170 | 4 | break; |
171 | 49 | default: |
172 | 49 | proto_tree_add_expert_format(tree, actx->pinfo, &ei_oer_not_decoded_yet, tvb, offset, 1, |
173 | 49 | "Length determinant: Long form %u octets not handled", value_len); |
174 | 49 | return tvb_reported_length(tvb); |
175 | 102 | } |
176 | | |
177 | 23 | return offset; |
178 | | |
179 | 102 | } |
180 | | |
181 | | /* 9 Encoding of Boolean values */ |
182 | | uint32_t dissect_oer_boolean(tvbuff_t* tvb, uint32_t offset, asn1_ctx_t* actx, proto_tree* tree, int hf_index, bool* bool_val) |
183 | 0 | { |
184 | 0 | bool val = false; |
185 | 0 | DEBUG_ENTRY("dissect_oer_boolean"); |
186 | |
|
187 | 0 | actx->created_item = proto_tree_add_item_ret_boolean(tree, hf_index, tvb, offset, 1, ENC_BIG_ENDIAN, &val); |
188 | 0 | offset++; |
189 | |
|
190 | 0 | if (bool_val) { |
191 | 0 | *bool_val = (bool)val; |
192 | 0 | } |
193 | |
|
194 | 0 | return offset; |
195 | 0 | } |
196 | | |
197 | | /* 10 Encoding of integer values */ |
198 | | |
199 | | uint32_t |
200 | | dissect_oer_constrained_integer(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int64_t min, int64_t max, uint32_t *value, bool has_extension) |
201 | 4.73k | { |
202 | 4.73k | DEBUG_ENTRY("dissect_oer_constrained_integer"); |
203 | 4.73k | uint32_t val = 0; |
204 | | |
205 | 4.73k | if (has_extension) { |
206 | 0 | return dissect_oer_integer(tvb, offset, actx, tree, hf_index, (int32_t*)value); |
207 | 0 | } |
208 | | |
209 | 4.73k | if (min >= 0) { |
210 | | /* 10.2 There are two main cases: |
211 | | * a) The effective value constraint has a lower bound, and that lower bound is zero or positive. |
212 | | */ |
213 | 3.53k | if (max < 0x100) { |
214 | | /* One octet */ |
215 | 2.17k | proto_tree_add_item_ret_uint(tree, hf_index, tvb, offset, 1, ENC_BIG_ENDIAN, &val); |
216 | 2.17k | offset++; |
217 | 2.17k | } else if (max < 0x10000) { |
218 | | /* Two octets */ |
219 | 1.01k | proto_tree_add_item_ret_uint(tree, hf_index, tvb, offset, 2, ENC_BIG_ENDIAN, &val); |
220 | 1.01k | offset += 2; |
221 | 1.01k | } else if (max <= 0xFFFFFFFF) { |
222 | | /* Four octets */ |
223 | 340 | proto_tree_add_item_ret_uint(tree, hf_index, tvb, offset, 4, ENC_BIG_ENDIAN, &val); |
224 | 340 | offset += 4; |
225 | 340 | } else { |
226 | | /* To large not handlet yet*/ |
227 | 0 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer to large value"); |
228 | 0 | } |
229 | | |
230 | 3.53k | } else { |
231 | | /* b) The effective value constraint has either a negative lower bound or no lower bound. */ |
232 | 1.20k | if ((min >= -128) && (max <= 127)) { |
233 | | /* 10.4 a a) If the lower bound is greater than or equal to -2^7 (-128) and the upper bound is less than or equal to 2^7-1 (127), |
234 | | * then every value of the integer type shall be encoded as a fixed-size signed number in a one-octet word; |
235 | | */ |
236 | 0 | proto_tree_add_item_ret_int(tree, hf_index, tvb, offset, 1, ENC_BIG_ENDIAN, (int32_t*)&val); |
237 | 0 | offset++; |
238 | 1.20k | } else if ((min >= -32768) && (max <= 32767)) { |
239 | | /* if the lower bound is greater than or equal to -2^15 (-32768) and the upper bound is less than or equal to 2^15-1 (32767), |
240 | | * then every value of the integer type shall be encoded as a fixed-size signed number in a two octet word; |
241 | | */ |
242 | 0 | proto_tree_add_item_ret_int(tree, hf_index, tvb, offset, 2, ENC_BIG_ENDIAN, (int32_t*)&val); |
243 | 0 | offset += 2; |
244 | 1.20k | } else if ((min >= -2147483648LL) && (max <= 2147483647)) { |
245 | | /* if the lower bound is greater than or equal to -2^31 (-2147483648) and the upper bound is less than or equal to 2^31-1 (2147483647), |
246 | | * then every value of the integer type shall be encoded as a fixed-size signed number in a four-octet word |
247 | | */ |
248 | 1.20k | proto_tree_add_item_ret_int(tree, hf_index, tvb, offset, 4, ENC_BIG_ENDIAN, (int32_t*)&val); |
249 | 1.20k | offset += 4; |
250 | 1.20k | } else { |
251 | | /* To large not handlet yet*/ |
252 | 0 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer to large value"); |
253 | 0 | } |
254 | | |
255 | 1.20k | } |
256 | | |
257 | 4.73k | if (value) { |
258 | 0 | *value = val; |
259 | 0 | } |
260 | | |
261 | 4.73k | return offset; |
262 | | |
263 | 4.73k | } |
264 | | |
265 | | uint32_t |
266 | | dissect_oer_constrained_integer_64b(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int64_t min, uint64_t max, uint64_t *value, bool has_extension) |
267 | 40 | { |
268 | 40 | uint64_t val = 0; |
269 | | |
270 | 40 | if (has_extension) { |
271 | 0 | return dissect_oer_integer_64b(tvb, offset, actx, tree, hf_index, (int64_t*)value); |
272 | 0 | } |
273 | | |
274 | 40 | if (min >= 0) { |
275 | | /* 10.2 There are two main cases: |
276 | | * a) The effective value constraint has a lower bound, and that lower bound is zero or positive. |
277 | | */ |
278 | | /* 10.3 */ |
279 | 40 | if (max < 0x100) { |
280 | | /* One octet, upper bound is less than or equal to 2 exp 8 - 1 (255) */ |
281 | 0 | proto_tree_add_item_ret_uint64(tree, hf_index, tvb, offset, 1, ENC_BIG_ENDIAN, &val); |
282 | 0 | offset++; |
283 | 40 | } else if (max < 0x10000) { |
284 | | /* Two octets, upper bound is less than or equal to 2 exp 16 - 1 (65535), */ |
285 | 0 | proto_tree_add_item_ret_uint64(tree, hf_index, tvb, offset, 2, ENC_BIG_ENDIAN, &val); |
286 | 0 | offset += 2; |
287 | 40 | } else if (max < 0x100000000) { |
288 | | /* Four octets, upper bound is less than or equal to 2 exp 32 - 1 (4294967295), */ |
289 | 0 | proto_tree_add_item_ret_uint64(tree, hf_index, tvb, offset, 4, ENC_BIG_ENDIAN, &val); |
290 | 0 | offset += 4; |
291 | 40 | } else if (max <= UINT64_C(18446744073709551615)) { |
292 | | /* Eight octets, upper bound is less than or equal to 2 exp 64 - 1 (18446744073709551615), */ |
293 | 40 | proto_tree_add_item_ret_uint64(tree, hf_index, tvb, offset, 8, ENC_BIG_ENDIAN, &val); |
294 | 40 | offset += 8; |
295 | 40 | } else { |
296 | | /* To large not handlet yet*/ |
297 | 0 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer to large value"); |
298 | 0 | } |
299 | | |
300 | 40 | } else { |
301 | | /* b) The effective value constraint has either a negative lower bound or no lower bound. */ |
302 | 0 | if ((min >= -128) && (max <= 127)) { |
303 | | /* 10.4 a a) If the lower bound is greater than or equal to -2^7 (-128) and the upper bound is less than or equal to 2^7-1 (127), |
304 | | * then every value of the integer type shall be encoded as a fixed-size signed number in a one-octet word; |
305 | | */ |
306 | 0 | proto_tree_add_item_ret_int64(tree, hf_index, tvb, offset, 1, ENC_BIG_ENDIAN, (int64_t*)&val); |
307 | 0 | offset++; |
308 | 0 | } else if ((min >= -32768) && (max <= 32767)) { |
309 | | /* if the lower bound is greater than or equal to -2^15 (-32768) and the upper bound is less than or equal to 2^15-1 (32767), |
310 | | * then every value of the integer type shall be encoded as a fixed-size signed number in a two octet word; |
311 | | */ |
312 | 0 | proto_tree_add_item_ret_int64(tree, hf_index, tvb, offset, 2, ENC_BIG_ENDIAN, (int64_t*)&val); |
313 | 0 | offset += 2; |
314 | 0 | } else if ((min >= -2147483648LL) && (max <= 2147483647)) { |
315 | | /* if the lower bound is greater than or equal to -2^31 (-2147483648) and the upper bound is less than or equal to 2^31-1 (2147483647), |
316 | | * then every value of the integer type shall be encoded as a fixed-size signed number in a four-octet word |
317 | | */ |
318 | 0 | proto_tree_add_item_ret_int64(tree, hf_index, tvb, offset, 4, ENC_BIG_ENDIAN, (int64_t*)&val); |
319 | 0 | offset += 4; |
320 | 0 | } else if (max <= INT64_C(9223372036854775807)) { |
321 | | /* if the lower bound is greater than or equal to –2^63 (–9223372036854775808) and the upper bound is less than or equal to 2^63 – 1 (9223372036854775807), |
322 | | * then every value of the integer type shall be encoded as a fixed-size signed number in an eight-octet words |
323 | | */ |
324 | 0 | proto_tree_add_item_ret_int64(tree, hf_index, tvb, offset, 8, ENC_BIG_ENDIAN, (int64_t*)&val); |
325 | 0 | offset += 8; |
326 | 0 | } else { |
327 | | /* To large not handlet yet*/ |
328 | 0 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer to large value"); |
329 | 0 | } |
330 | 0 | } |
331 | | |
332 | 40 | if (value) { |
333 | 0 | *value = val; |
334 | 0 | } |
335 | | |
336 | 40 | return offset; |
337 | | |
338 | 40 | } |
339 | | |
340 | | uint32_t |
341 | | dissect_oer_constrained_integer_64b_no_ub(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int64_t min, uint64_t max _U_, uint64_t *value, bool has_extension _U_) |
342 | 237 | { |
343 | 237 | uint64_t val = 0; |
344 | 237 | uint32_t length; |
345 | | |
346 | | /* Negative numbers ???*/ |
347 | 237 | if (min >= 0) { |
348 | | |
349 | | /* (the effective value constraint has either an upper bound greater than 2 exp 64-1 or no upper bound) |
350 | | * every value of the integer type shall be encoded as a length determinant (see 8.6) |
351 | | * followed by a variable-size unsigned number |
352 | | * (occupying at least as many whole octets as are necessary to carry the value). |
353 | | */ |
354 | 237 | offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); |
355 | 237 | if (length > 0) { |
356 | 228 | if (length < 5) { |
357 | 223 | proto_tree_add_item_ret_uint64(tree, hf_index, tvb, offset, length, ENC_BIG_ENDIAN, &val); |
358 | 223 | offset += length; |
359 | 223 | } else { |
360 | 5 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer NO_BOUND to many octets"); |
361 | 5 | } |
362 | 228 | } else { |
363 | 9 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer unexpected length"); |
364 | 9 | } |
365 | 237 | } |
366 | 237 | if (value) { |
367 | 221 | *value = val; |
368 | 221 | } |
369 | | |
370 | 237 | return offset; |
371 | | |
372 | 237 | } |
373 | | |
374 | | uint32_t |
375 | | dissect_oer_integer(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int32_t *value) |
376 | 21 | { |
377 | 21 | int32_t val = 0; |
378 | 21 | uint32_t length; |
379 | | /* 10.4 e) (the effective value constraint has a lower bound less than -263, no lower bound, |
380 | | * an upper bound greater than 2 exp 63-1, or no upper bound) every value of the integer type |
381 | | * shall be encoded as a length determinant (see 8.6) followed by a variable-size signed number |
382 | | * (occupying at least as many whole octets as are necessary to carry the value). |
383 | | */ |
384 | 21 | offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); |
385 | 21 | if (length > 0) { |
386 | 19 | if (length < 5) { |
387 | | /* extend sign bit for signed fields */ |
388 | 16 | enum ftenum type = FT_INT32; |
389 | | /* This should be signed, because the field should only be |
390 | | * unsigned if there's a constraint, and then we don't get here. */ |
391 | 16 | if (hf_index > 0) { |
392 | 16 | type = proto_registrar_get_ftype(hf_index); |
393 | 16 | } |
394 | 16 | uint8_t first = tvb_get_uint8(tvb, offset); |
395 | 16 | if (first & 0x80 && FT_IS_INT(type)) { |
396 | 2 | val = -1; |
397 | 2 | } |
398 | 60 | for (unsigned i = 0; i < length; i++) { |
399 | 44 | val = ((uint32_t)val << 8) | tvb_get_uint8(tvb, offset); |
400 | 44 | offset++; |
401 | 44 | } |
402 | 16 | } else { |
403 | 3 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer NO_BOUND too many octets"); |
404 | 3 | } |
405 | 19 | } else { |
406 | 2 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer unexpected length"); |
407 | 2 | } |
408 | | |
409 | 21 | if (hf_index > 0) { |
410 | 16 | header_field_info* hfi; |
411 | 16 | hfi = proto_registrar_get_nth(hf_index); |
412 | 16 | if (FT_IS_UINT32(hfi->type)) { |
413 | 0 | actx->created_item = proto_tree_add_uint(tree, hf_index, tvb, offset - length, length, (uint32_t)val); |
414 | 16 | } else if (FT_IS_INT32(hfi->type)) { |
415 | 16 | actx->created_item = proto_tree_add_int(tree, hf_index, tvb, offset - length, length, val); |
416 | 16 | } else { |
417 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
418 | 0 | } |
419 | 16 | } |
420 | | |
421 | 21 | if (value) { |
422 | 0 | *value = val; |
423 | 0 | } |
424 | | |
425 | 21 | return offset; |
426 | | |
427 | 21 | } |
428 | | |
429 | | uint32_t |
430 | | dissect_oer_integer_64b(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int64_t *value) |
431 | 0 | { |
432 | 0 | int64_t val = 0; |
433 | 0 | uint32_t length; |
434 | | /* 10.4 e) (the effective value constraint has a lower bound less than -263, no lower bound, |
435 | | * an upper bound greater than 2 exp 63-1, or no upper bound) every value of the integer type |
436 | | * shall be encoded as a length determinant (see 8.6) followed by a variable-size signed number |
437 | | * (occupying at least as many whole octets as are necessary to carry the value). |
438 | | */ |
439 | 0 | offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); |
440 | 0 | if (length > 0) { |
441 | 0 | if (length < 9) { |
442 | | /* extend sign bit for signed fields */ |
443 | 0 | enum ftenum type = FT_INT64; |
444 | | /* This should be signed, because the field should only be |
445 | | * unsigned if there's a constraint, and then we don't get here. */ |
446 | 0 | if (hf_index > 0) { |
447 | 0 | type = proto_registrar_get_ftype(hf_index); |
448 | 0 | } |
449 | 0 | uint8_t first = tvb_get_uint8(tvb, offset); |
450 | 0 | if (first & 0x80 && FT_IS_INT(type)) { |
451 | 0 | val = -1; |
452 | 0 | } |
453 | 0 | for (unsigned i = 0; i < length; i++) { |
454 | 0 | val = ((uint64_t)val << 8) | tvb_get_uint8(tvb, offset); |
455 | 0 | offset++; |
456 | 0 | } |
457 | 0 | } else { |
458 | 0 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer NO_BOUND too many octets"); |
459 | 0 | } |
460 | 0 | } else { |
461 | 0 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "constrained_integer unexpected length"); |
462 | 0 | } |
463 | |
|
464 | 0 | if (hf_index > 0) { |
465 | 0 | header_field_info* hfi; |
466 | 0 | hfi = proto_registrar_get_nth(hf_index); |
467 | 0 | if (FT_IS_UINT64(hfi->type)) { |
468 | 0 | actx->created_item = proto_tree_add_uint64(tree, hf_index, tvb, offset - length, length, (uint64_t)val); |
469 | 0 | } else if (FT_IS_INT64(hfi->type)) { |
470 | 0 | actx->created_item = proto_tree_add_int64(tree, hf_index, tvb, offset - length, length, val); |
471 | 0 | } else { |
472 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
473 | 0 | } |
474 | 0 | } |
475 | |
|
476 | 0 | if (value) { |
477 | 0 | *value = val; |
478 | 0 | } |
479 | |
|
480 | 0 | return offset; |
481 | |
|
482 | 0 | } |
483 | | |
484 | | /* 11 Encoding of enumerated values */ |
485 | | uint32_t |
486 | | dissect_oer_enumerated(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, uint32_t root_num _U_, uint32_t *value, bool has_extension _U_, uint32_t ext_num _U_, const uint32_t *value_map _U_) |
487 | 938 | { |
488 | 938 | int old_offset = offset; |
489 | 938 | uint32_t val; |
490 | | /* 11.2 There are two forms of enumerated type encoding - a short form and a long form... */ |
491 | | |
492 | 938 | offset = dissect_oer_length_determinant(tvb, offset, actx, tree, -1 /*Don't show length value as internal field*/, &val); |
493 | 938 | actx->created_item = proto_tree_add_uint(tree, hf_index, tvb, old_offset, offset - old_offset, val); |
494 | | |
495 | 938 | if (value) { |
496 | 0 | *value = val; |
497 | 0 | } |
498 | | |
499 | 938 | return offset; |
500 | | |
501 | | |
502 | 938 | } |
503 | | |
504 | | static uint32_t |
505 | | dissect_oer_bit_string_unconstr(tvbuff_t *tvb, uint32_t offset _U_, asn1_ctx_t *actx, proto_tree *tree, int hf_index _U_, int min_len _U_, int max_len _U_, bool has_extension _U_, int * const *named_bits _U_, int num_named_bits _U_, tvbuff_t **value_tvb _U_, uint8_t * const values, unsigned values_size, int *len) |
506 | 181 | { |
507 | 181 | uint32_t length; |
508 | 181 | uint8_t unused_bit_count = 0; |
509 | | |
510 | 181 | offset = dissect_oer_length_determinant(tvb, offset, actx, tree, -1 /*Don't show length value as internal field*/, &length); |
511 | 181 | if (length > 0) { |
512 | 160 | unused_bit_count = tvb_get_uint8(tvb, offset); |
513 | 160 | if (unused_bit_count > 7) { |
514 | 5 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "too high unused bit count"); |
515 | 5 | return offset + length; |
516 | 5 | } |
517 | 155 | offset += 1; |
518 | 155 | length -= 1; |
519 | 155 | } |
520 | | |
521 | 176 | *len = length; |
522 | 176 | if (values) { |
523 | 174 | memset(values, 0, values_size); |
524 | 174 | if (length > values_size) { |
525 | 2 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "too many bitstring elements"); |
526 | 2 | } |
527 | 336 | for (size_t i = 0; i < length; i++) { |
528 | 162 | uint8_t value = tvb_get_uint8(tvb, offset); |
529 | 162 | if (i + 1 == length) { |
530 | | /* unused bits of the last octet shall be set to zeros */ |
531 | 56 | value &= (0xFF << unused_bit_count); |
532 | 56 | } |
533 | 162 | if (i < values_size) { |
534 | 161 | values[i] = value; |
535 | 161 | } |
536 | 162 | offset += 1; |
537 | 162 | } |
538 | 174 | } |
539 | | |
540 | 176 | return offset; |
541 | 181 | } |
542 | | |
543 | | static tvbuff_t *dissect_oer_bit_string_display(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, header_field_info *hfi, uint32_t length, int * const *named_bits, int num_named_bits _U_) |
544 | 9 | { |
545 | 9 | tvbuff_t *out_tvb = NULL; |
546 | 9 | uint32_t pad_length=0; |
547 | 9 | uint64_t value; |
548 | | |
549 | 9 | DISSECTOR_ASSERT(length > 0); |
550 | | |
551 | 9 | uint32_t byte_length = (length + 7) / 8; |
552 | 9 | out_tvb = oer_tvb_new_subset_length(tvb, offset, byte_length); |
553 | 9 | add_new_data_source(actx->pinfo, out_tvb, "Bitstring tvb"); |
554 | | |
555 | 9 | if (hfi) { |
556 | 9 | actx->created_item = proto_tree_add_item(tree, hf_index, out_tvb, 0, -1, ENC_BIG_ENDIAN); |
557 | 9 | proto_item_append_text(actx->created_item, " [bit length %u", length); |
558 | 9 | if (length%8) { |
559 | 0 | pad_length = 8-(length%8); |
560 | 0 | proto_item_append_text(actx->created_item, ", %u LSB pad bits", pad_length); |
561 | 0 | } |
562 | | |
563 | 9 | if (length<=64) { /* if read into 64 bits also handle length <= 24, 40, 48, 56 bits */ |
564 | 9 | if (length<=8) { |
565 | 9 | value = tvb_get_bits8(out_tvb, 0, length); |
566 | 9 | }else if (length<=16) { |
567 | 0 | value = tvb_get_bits16(out_tvb, 0, length, ENC_BIG_ENDIAN); |
568 | 0 | }else if (length<=24) { /* first read 16 and then the remaining bits */ |
569 | 0 | value = tvb_get_bits16(out_tvb, 0, 16, ENC_BIG_ENDIAN); |
570 | 0 | value <<= 8 - pad_length; |
571 | 0 | value |= tvb_get_bits8(out_tvb, 16, length - 16); |
572 | 0 | }else if (length<=32) { |
573 | 0 | value = tvb_get_bits32(out_tvb, 0, length, ENC_BIG_ENDIAN); |
574 | 0 | }else if (length<=40) { /* first read 32 and then the remaining bits */ |
575 | 0 | value = tvb_get_bits32(out_tvb, 0, 32, ENC_BIG_ENDIAN); |
576 | 0 | value <<= 8 - pad_length; |
577 | 0 | value |= tvb_get_bits8(out_tvb, 32, length - 32); |
578 | 0 | }else if (length<=48) { /* first read 32 and then the remaining bits */ |
579 | 0 | value = tvb_get_bits32(out_tvb, 0, 32, ENC_BIG_ENDIAN); |
580 | 0 | value <<= 16 - pad_length; |
581 | 0 | value |= tvb_get_bits16(out_tvb, 32, length - 32, ENC_BIG_ENDIAN); |
582 | 0 | }else if (length<=56) { /* first read 32 and 16 then the remaining bits */ |
583 | 0 | value = tvb_get_bits32(out_tvb, 0, 32, ENC_BIG_ENDIAN); |
584 | 0 | value <<= 16; |
585 | 0 | value |= tvb_get_bits16(out_tvb, 32, 16, ENC_BIG_ENDIAN); |
586 | 0 | value <<= 8 - pad_length; |
587 | 0 | value |= tvb_get_bits8(out_tvb, 48, length - 48); |
588 | 0 | }else { |
589 | 0 | value = tvb_get_bits64(out_tvb, 0, length, ENC_BIG_ENDIAN); |
590 | 0 | } |
591 | 9 | proto_item_append_text(actx->created_item, ", %s decimal value %" PRIu64, |
592 | 9 | decode_bits_in_field(actx->pinfo->pool, 0, length, value, ENC_BIG_ENDIAN), value); |
593 | 9 | if (named_bits) { |
594 | 7 | const uint32_t named_bits_bytelen = (num_named_bits + 7) / 8; |
595 | 7 | proto_tree *subtree = proto_item_add_subtree(actx->created_item, ett_oer_named_bits); |
596 | 14 | for (uint32_t i = 0; i < named_bits_bytelen; i++) { |
597 | | // If less data is available than the number of named bits, then |
598 | | // the trailing (right) bits are assumed to be 0. |
599 | 7 | value = 0; |
600 | 7 | const uint32_t bit_offset = 8 * i; |
601 | 7 | if (bit_offset < length) { |
602 | 7 | value = tvb_get_uint8(out_tvb, i); |
603 | 7 | } |
604 | | |
605 | | // Process 8 bits at a time instead of 64, each field masks a |
606 | | // single byte. |
607 | 7 | int* const * section_named_bits = named_bits + bit_offset; |
608 | 7 | int* flags[9]; |
609 | 7 | if (num_named_bits - bit_offset > 8) { |
610 | 0 | memcpy(&flags[0], named_bits + bit_offset, 8 * sizeof(int*)); |
611 | 0 | flags[8] = NULL; |
612 | 0 | section_named_bits = flags; |
613 | 0 | } |
614 | | |
615 | | // TODO should non-zero pad bits be masked from the value? |
616 | | // When trailing zeroes are not present in the data, mark the |
617 | | // last byte for the lack of a better alternative. |
618 | 7 | proto_tree_add_bitmask_list_value(subtree, out_tvb, offset + MIN(i, length - 1), 1, section_named_bits, value); |
619 | 7 | } |
620 | 7 | } |
621 | 9 | } |
622 | 9 | proto_item_append_text(actx->created_item, "]"); |
623 | 9 | } |
624 | | |
625 | 9 | return out_tvb; |
626 | 9 | } |
627 | | |
628 | | static uint32_t |
629 | | dissect_oer_bit_string_unconstr_with_display(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, header_field_info * hfi, int * const *named_bits, int num_named_bits, tvbuff_t **value_tvb, uint32_t *len) |
630 | 0 | { |
631 | 0 | uint32_t length = 0; |
632 | 0 | uint8_t unused_bit_count = 0; |
633 | 0 | tvbuff_t* tmp_tvb = NULL; |
634 | |
|
635 | 0 | offset = dissect_oer_length_determinant(tvb, offset, actx, tree, -1, &length); |
636 | |
|
637 | 0 | if (length > 0) { |
638 | 0 | unused_bit_count = tvb_get_uint8(tvb, offset); |
639 | 0 | if (unused_bit_count > 7) { |
640 | 0 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "too high unused bit count"); |
641 | 0 | return offset + length; |
642 | 0 | } |
643 | 0 | offset += 1; |
644 | 0 | length -= 1; |
645 | 0 | } else { |
646 | 0 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "Zero length determinant"); |
647 | 0 | return offset; |
648 | 0 | } |
649 | | |
650 | 0 | if(length > 0) { |
651 | 0 | uint32_t bit_len = (length * 8) - unused_bit_count; |
652 | |
|
653 | 0 | tmp_tvb = dissect_oer_bit_string_display(tvb, |
654 | 0 | offset, |
655 | 0 | actx, |
656 | 0 | tree, |
657 | 0 | hf_index, |
658 | 0 | hfi, |
659 | 0 | bit_len, |
660 | 0 | named_bits, |
661 | 0 | num_named_bits); |
662 | 0 | } |
663 | |
|
664 | 0 | if(NULL != value_tvb) { |
665 | 0 | *value_tvb = tmp_tvb; |
666 | 0 | } |
667 | 0 | if(NULL != len) { |
668 | 0 | *len = length; |
669 | 0 | } |
670 | |
|
671 | 0 | offset += length; |
672 | |
|
673 | 0 | return offset; |
674 | 0 | } |
675 | | |
676 | | /* 13 Encoding of bitstring values */ |
677 | | |
678 | | /* 13.1 General |
679 | | * The encoding of a bitstring value depends on the effective size constraint of the bitstring type (see 8.2.8). |
680 | | * If the lower and upper bounds of the effective size constraint are identical, 13.2 applies, otherwise 13.3 applies. |
681 | | */ |
682 | | uint32_t |
683 | | dissect_oer_bit_string(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, bool has_extension, int * const *named_bits, int num_named_bits, tvbuff_t **value_tvb, int *len) |
684 | 9 | { |
685 | 9 | tvbuff_t *out_tvb = NULL; |
686 | 9 | header_field_info *hfi = (hf_index <= 0) ? NULL : proto_registrar_get_nth(hf_index); |
687 | | |
688 | 9 | if((min_len < 0) || (max_len < 0)) { |
689 | 0 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "Encoding of bitstring with negative min_len or max_len values are invalid"); |
690 | 0 | return offset; |
691 | 0 | } |
692 | | |
693 | 9 | if(max_len == 0) { |
694 | 0 | if(NULL != value_tvb) { |
695 | 0 | *value_tvb = out_tvb; |
696 | 0 | } |
697 | 0 | if(NULL != len) { |
698 | 0 | *len = 0; |
699 | 0 | } |
700 | 0 | return offset; |
701 | 0 | } |
702 | | |
703 | 9 | if(has_extension || (min_len != max_len)) { |
704 | 0 | uint32_t length; |
705 | 0 | offset = dissect_oer_bit_string_unconstr_with_display(tvb, |
706 | 0 | offset, |
707 | 0 | actx, |
708 | 0 | tree, |
709 | 0 | hf_index, |
710 | 0 | hfi, |
711 | 0 | named_bits, |
712 | 0 | num_named_bits, |
713 | 0 | value_tvb, |
714 | 0 | &length); |
715 | 0 | if(NULL != len) { |
716 | 0 | *len = length; |
717 | 0 | } |
718 | 9 | } else { |
719 | 9 | uint32_t byte_len = (min_len + 7) / 8; |
720 | 9 | out_tvb = dissect_oer_bit_string_display(tvb, offset, actx, tree, hf_index, hfi, min_len, named_bits, num_named_bits); |
721 | 9 | offset += byte_len; |
722 | | |
723 | 9 | if(NULL != value_tvb) { |
724 | 0 | *value_tvb = out_tvb; |
725 | 0 | } |
726 | 9 | if(NULL != len) { |
727 | 0 | *len = byte_len; |
728 | 0 | } |
729 | 9 | } |
730 | | |
731 | 9 | return offset; |
732 | 9 | } |
733 | | |
734 | | /* 14 Encoding of octet string values */ |
735 | | uint32_t |
736 | | dissect_oer_octet_string(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, bool has_extension _U_, tvbuff_t **value_tvb) |
737 | 2.23k | { |
738 | 2.23k | unsigned length; |
739 | | /* 14.1 For an octetstring type in which the lower and upper bounds of the effective size constraint are identical, |
740 | | * the encoding shall consist of the octets of the octetstring value (zero or more octets), with no length determinant. |
741 | | */ |
742 | 2.23k | if ((min_len != NO_BOUND ) && (min_len == max_len)) { |
743 | 1.27k | actx->created_item = proto_tree_add_item(tree, hf_index, tvb, offset, min_len, ENC_NA); |
744 | 1.27k | if (value_tvb) { |
745 | 0 | *value_tvb = oer_tvb_new_subset_length(tvb, offset, min_len); |
746 | 0 | } |
747 | 1.27k | return offset + min_len; |
748 | 1.27k | } |
749 | | |
750 | | /* 14.2 For any other octetstring type, the encoding shall consist of a length determinant (see 8.6) |
751 | | * followed by the octets of the octetstring value (zero or more octets). |
752 | | */ |
753 | 967 | offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); |
754 | 967 | actx->created_item = proto_tree_add_item(tree, hf_index, tvb, offset, length, ENC_NA); |
755 | 967 | if (value_tvb) { |
756 | 5 | *value_tvb = oer_tvb_new_subset_length(tvb, offset, length); |
757 | 5 | } |
758 | | |
759 | 967 | offset = offset + length; |
760 | | |
761 | 967 | return offset; |
762 | | |
763 | 2.23k | } |
764 | | |
765 | | /* 15 Encoding of the null value */ |
766 | | uint32_t |
767 | | dissect_oer_null(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx _U_, proto_tree *tree, int hf_index) |
768 | 337 | { |
769 | | /* The encoding of the null value shall be empty. */ |
770 | 337 | proto_item *ti_tmp; |
771 | | |
772 | 337 | ti_tmp = proto_tree_add_item(tree, hf_index, tvb, offset, 1, ENC_BIG_ENDIAN); |
773 | 337 | proto_item_append_text(ti_tmp, ": NULL"); |
774 | | |
775 | 337 | return offset; |
776 | 337 | } |
777 | | |
778 | | static const value_string oer_class_vals[] = { |
779 | | { 0, "universal" }, |
780 | | { 1, "application" }, |
781 | | { 2, "context-specific" }, |
782 | | { 3, "private" }, |
783 | | { 0, NULL } |
784 | | }; |
785 | | |
786 | | static const value_string oer_extension_present_bit_vals[] = { |
787 | | { 0, "Not present" }, |
788 | | { 1, "Present" }, |
789 | | { 0, NULL } |
790 | | }; |
791 | | |
792 | | |
793 | | |
794 | | /* 16 Encoding of sequence values */ |
795 | | uint32_t |
796 | | dissect_oer_sequence(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *parent_tree, int hf_index, int ett_index, const oer_sequence_t *sequence) |
797 | 4.55k | { |
798 | 4.55k | uint64_t optional_field_flag; |
799 | 4.55k | proto_item *item; |
800 | 4.55k | proto_tree *tree; |
801 | 4.55k | uint32_t old_offset = offset; |
802 | 4.55k | uint32_t i, j, num_opts; |
803 | 4.55k | uint32_t optional_mask[SEQ_MAX_COMPONENTS >> 5]; |
804 | 4.55k | int bit_offset = 0; |
805 | 4.55k | uint64_t extensions_present = 0; |
806 | | |
807 | 4.55k | DEBUG_ENTRY("dissect_oer_sequence"); |
808 | | |
809 | 4.55k | item = proto_tree_add_item(parent_tree, hf_index, tvb, offset, 0, ENC_BIG_ENDIAN); |
810 | 4.55k | tree = proto_item_add_subtree(item, ett_index); |
811 | | |
812 | | |
813 | | /* first check if there should be an extension bit for this SEQUENSE. |
814 | | * we do this by just checking the first entry |
815 | | */ |
816 | 4.55k | bit_offset = offset << 3; |
817 | 4.55k | if (sequence[0].extension == ASN1_NO_EXTENSIONS) { |
818 | | /*extension_present=0; ?? */ |
819 | 3.64k | } else { |
820 | | /* 16.2.2 The extension bit shall be present (as bit 8 of the first octet of the preamble) |
821 | | * if, and only if, the sequence type definition contains an extension marker... |
822 | | */ |
823 | 911 | actx->created_item = proto_tree_add_bits_ret_val(tree, hf_oer_extension_present_bit, tvb, bit_offset, 1, &extensions_present, ENC_BIG_ENDIAN); |
824 | 911 | bit_offset++; |
825 | 911 | if (!display_internal_oer_fields) proto_item_set_hidden(actx->created_item); |
826 | 911 | } |
827 | | /* The presence bitmap is encoded as a bit string with a fixed size constraint (see 16.2.3), |
828 | | * and has one bit for each field of the sequence type that has the keyword OPTIONAL or DEFAULT, |
829 | | * in specification order. |
830 | | */ |
831 | 4.55k | num_opts = 0; |
832 | 22.7k | for (i = 0; sequence[i].p_id; i++) { |
833 | 18.1k | if ((sequence[i].extension != ASN1_NOT_EXTENSION_ROOT) && (sequence[i].optional == ASN1_OPTIONAL)) { |
834 | 5.06k | num_opts++; |
835 | 5.06k | } |
836 | 18.1k | } |
837 | 4.55k | if (num_opts > SEQ_MAX_COMPONENTS) { |
838 | 0 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "too many optional/default components"); |
839 | 0 | } |
840 | | |
841 | 4.55k | memset(optional_mask, 0, sizeof(optional_mask)); |
842 | 9.60k | for (i = 0; i<num_opts; i++) { |
843 | 5.05k | actx->created_item = proto_tree_add_bits_ret_val(tree, hf_oer_optional_field_bit, tvb, bit_offset, 1, &optional_field_flag, ENC_BIG_ENDIAN); |
844 | 5.05k | bit_offset++; |
845 | 5.05k | if (tree) { |
846 | 5.05k | proto_item_append_text(actx->created_item, " (%s %s present)", |
847 | 5.05k | index_get_optional_name(sequence, i), optional_field_flag ? "is" : "is NOT"); |
848 | 5.05k | } |
849 | 5.05k | if (!display_internal_oer_fields) proto_item_set_hidden(actx->created_item); |
850 | 5.05k | if (optional_field_flag) { |
851 | 1.27k | optional_mask[i >> 5] |= 0x80000000 >> (i & 0x1f); |
852 | 1.27k | } |
853 | 5.05k | } |
854 | | /* 16.2.1 preamble as a whole (including extension bit) occupies a whole number of octets */ |
855 | 4.55k | offset = (bit_offset + 7) >> 3; |
856 | | |
857 | | /* */ |
858 | 20.4k | for (i = 0, j = 0; sequence[i].p_id; i++) { |
859 | 15.8k | if ((sequence[i].extension == ASN1_NO_EXTENSIONS) |
860 | 13.9k | || (sequence[i].extension == ASN1_EXTENSION_ROOT)) { |
861 | 13.9k | if (sequence[i].optional == ASN1_OPTIONAL) { |
862 | 4.25k | bool is_present; |
863 | 4.25k | if (num_opts == 0) { |
864 | 0 | continue; |
865 | 0 | } |
866 | 4.25k | is_present = (0x80000000 >> (j & 0x1f))&optional_mask[j >> 5]; |
867 | 4.25k | num_opts--; |
868 | 4.25k | j++; |
869 | 4.25k | if (!is_present) { |
870 | 3.36k | continue; |
871 | 3.36k | } |
872 | 4.25k | } |
873 | 10.6k | if (sequence[i].func) { |
874 | 10.6k | offset = sequence[i].func(tvb, offset, actx, tree, *sequence[i].p_id); |
875 | 10.6k | } else { |
876 | 0 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, index_get_field_name(sequence, i)); |
877 | 0 | } |
878 | 10.6k | } |
879 | 15.8k | } |
880 | | |
881 | 4.55k | if (extensions_present) { |
882 | | /* Parse the Extension Bitmap */ |
883 | 181 | int ext_bmp_len; |
884 | 181 | uint8_t extension_mask[SEQ_MAX_COMPONENTS >> 3]; |
885 | 181 | offset = dissect_oer_bit_string_unconstr(tvb, offset, actx, tree, hf_index, NO_BOUND, NO_BOUND, false, NULL, 0, NULL, extension_mask, SEQ_MAX_COMPONENTS >> 3, &ext_bmp_len); |
886 | | |
887 | | /* find first extension */ |
888 | 181 | int seq_pos; |
889 | 978 | for (seq_pos = 0; sequence[seq_pos].p_id; seq_pos++) { |
890 | 962 | if (sequence[seq_pos].extension == ASN1_NOT_EXTENSION_ROOT) { |
891 | 165 | break; |
892 | 165 | } |
893 | 962 | } |
894 | 289 | for (int bitstr_pos = 0; bitstr_pos < ext_bmp_len; bitstr_pos++) { |
895 | 108 | int8_t octet = extension_mask[bitstr_pos]; |
896 | 808 | for (int octet_pos = 0; octet_pos < 8; octet_pos++) { |
897 | 700 | bool ext_present = ((octet << octet_pos) & (0x80)) >> 7; |
898 | 700 | if (ext_present) { |
899 | | /* If any extensions still known - use functions */ |
900 | 147 | if (sequence[seq_pos].p_id) { |
901 | 44 | unsigned length; |
902 | 44 | offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); |
903 | 44 | if (sequence[seq_pos].func) { |
904 | 43 | offset = sequence[seq_pos].func(tvb, offset, actx, tree, *sequence[seq_pos].p_id); |
905 | 43 | } else { |
906 | 1 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, index_get_field_name(sequence, seq_pos )); |
907 | 1 | } |
908 | 103 | } else { |
909 | 103 | offset = dissect_oer_octet_string(tvb, offset, actx, tree, hf_index, NO_BOUND, NO_BOUND, false, NULL); |
910 | 103 | } |
911 | 147 | } |
912 | | /* if still within known sequence elements - move to next */ |
913 | 700 | if (sequence[seq_pos].p_id) { |
914 | 102 | seq_pos++; |
915 | 102 | } |
916 | 700 | } |
917 | 108 | } |
918 | | |
919 | 181 | } |
920 | | |
921 | 4.55k | proto_item_set_len(item, offset - old_offset); |
922 | 4.55k | actx->created_item = item; |
923 | 4.55k | return offset; |
924 | 4.55k | } |
925 | | |
926 | | /* 17 Encoding of sequence-of values */ |
927 | | |
928 | | static uint32_t |
929 | | dissect_oer_sequence_of_helper(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *tree, oer_type_fn func, int hf_index, uint32_t length) |
930 | 328 | { |
931 | 328 | uint32_t i; |
932 | | |
933 | 328 | DEBUG_ENTRY("dissect_oer_sequence_of_helper"); |
934 | 3.15k | for (i = 0; i<length; i++) { |
935 | 2.82k | uint32_t lold_offset = offset; |
936 | 2.82k | proto_item *litem; |
937 | 2.82k | proto_tree *ltree; |
938 | | |
939 | 2.82k | ltree = proto_tree_add_subtree_format(tree, tvb, offset, 0, ett_oer_sequence_of_item, &litem, "Item %d", i); |
940 | | |
941 | 2.82k | offset = (*func)(tvb, offset, actx, ltree, hf_index); |
942 | 2.82k | proto_item_set_len(litem, offset - lold_offset); |
943 | 2.82k | } |
944 | | |
945 | 328 | return offset; |
946 | 328 | } |
947 | | |
948 | | uint32_t |
949 | | dissect_oer_sequence_of(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *parent_tree, int hf_index, int ett_index, const oer_sequence_t *seq) |
950 | 358 | { |
951 | 358 | proto_item *item; |
952 | 358 | proto_tree *tree; |
953 | 358 | uint32_t old_offset = offset; |
954 | 358 | uint32_t occ_len, occurrence; |
955 | 358 | header_field_info *hfi; |
956 | | |
957 | 358 | DEBUG_ENTRY("dissect_oer_sequence_of"); |
958 | | |
959 | | /* 17.1 The encoding of a sequence-of value shall consist of a quantity field...*/ |
960 | | |
961 | | /* 17.2 The quantity field shall be a non-negative integer value indicating the number of occurrences. |
962 | | * This number shall be encoded as a length determinant (see 8.6) followed by a variable-size unsigned number |
963 | | * (occupying at least as many whole octets as are necessary to carry the value). |
964 | | */ |
965 | 358 | offset = dissect_oer_length_determinant(tvb, offset, actx, parent_tree, hf_oer_length_determinant, &occ_len); |
966 | | |
967 | 358 | switch (occ_len) { |
968 | 120 | case 1: |
969 | 120 | occurrence = tvb_get_uint8(tvb, offset); |
970 | 120 | break; |
971 | 159 | case 2: |
972 | 159 | occurrence = tvb_get_ntohs(tvb, offset); |
973 | 159 | break; |
974 | 40 | case 3: |
975 | 40 | occurrence = tvb_get_ntoh24(tvb, offset); |
976 | 40 | break; |
977 | 9 | case 4: |
978 | 9 | occurrence = tvb_get_ntohl(tvb, offset); |
979 | 9 | break; |
980 | 24 | default: |
981 | 24 | proto_tree_add_expert_format(parent_tree, actx->pinfo, &ei_oer_not_decoded_yet, tvb, offset, 1, |
982 | 24 | "sequence_of Occurrence %u octets not handled", occ_len); |
983 | 24 | return tvb_reported_length(tvb); |
984 | 358 | } |
985 | | |
986 | 328 | offset = offset + occ_len; |
987 | 328 | hfi = proto_registrar_get_nth(hf_index); |
988 | 328 | if (FT_IS_UINT(hfi->type)) { |
989 | 328 | item = proto_tree_add_uint(parent_tree, hf_index, tvb, old_offset, occ_len, occurrence); |
990 | 328 | proto_item_append_text(item, (occurrence == 1) ? " item" : " items"); |
991 | 328 | } else { |
992 | 0 | item = proto_tree_add_item(parent_tree, hf_index, tvb, old_offset, 0, ENC_BIG_ENDIAN); |
993 | 0 | } |
994 | 328 | tree = proto_item_add_subtree(item, ett_index); |
995 | | |
996 | 328 | offset = dissect_oer_sequence_of_helper(tvb, offset, actx, tree, seq->func, *seq->p_id, occurrence); |
997 | | |
998 | | |
999 | 328 | proto_item_set_len(item, offset - old_offset); |
1000 | 328 | return offset; |
1001 | | |
1002 | 358 | } |
1003 | | |
1004 | | /* As we are using the per ASN1 generator define this "dummy" function */ |
1005 | | uint32_t |
1006 | | dissect_oer_constrained_sequence_of(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *parent_tree, int hf_index, int ett_index, const oer_sequence_t *seq, int min_len _U_, int max_len _U_ , bool has_extension _U_) |
1007 | 31 | { |
1008 | 31 | return dissect_oer_sequence_of(tvb, offset, actx, parent_tree, hf_index, ett_index, seq); |
1009 | | |
1010 | 31 | } |
1011 | | /* 20 Encoding of choice values */ |
1012 | | uint32_t |
1013 | | dissect_oer_choice(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int ett_index, const oer_choice_t *choice, int *value) |
1014 | 3.57k | { |
1015 | 3.57k | proto_tree *choice_tree; |
1016 | 3.57k | proto_item *item, *choice_item; |
1017 | 3.57k | int bit_offset = offset << 3; |
1018 | 3.57k | uint64_t oer_class; |
1019 | 3.57k | uint8_t tag, oct; |
1020 | 3.57k | int old_offset = offset; |
1021 | | |
1022 | | /* 20.1 The encoding of a value of a choice type shall consist of the encoding of the outermost tag of the type of the chosen alternative |
1023 | | * as specified in 8.7, followed by the encoding of the value of the chosen alternative. |
1024 | | */ |
1025 | | |
1026 | | /* 8.7.2.1 Bits 8 and 7 of the first octet shall denote the tag class */ |
1027 | 3.57k | item = proto_tree_add_bits_ret_val(tree, hf_oer_class, tvb, bit_offset, 2, &oer_class, ENC_BIG_ENDIAN); |
1028 | 3.57k | if (!display_internal_oer_fields) proto_item_set_hidden(item); |
1029 | 3.57k | bit_offset += 2; |
1030 | | |
1031 | 3.57k | tag = tvb_get_bits8(tvb, bit_offset, 6); |
1032 | 3.57k | offset++; |
1033 | | /* 8.7.2.3 If the tag number is greater or equal to 63, Bits 6 to 1 of the initial octet shall be set to '111111'B.*/ |
1034 | 3.57k | if (tag == 0x3f) { |
1035 | | /* The tag number shall be encoded into bits 7 to 1 of each subsequent octet (seven bits in each octet), |
1036 | | * with bit 1 of the final subsequent octet containing the least significant bit of the tag number ("big-endian" encoding). |
1037 | | */ |
1038 | 152 | oct = tvb_get_uint8(tvb, offset); |
1039 | 152 | if ((oct & 0x80) == 0x80) { |
1040 | 9 | dissect_oer_not_decoded_yet(tree, actx->pinfo, tvb, "Choice, Tag value > 0x7f not implemented yet"); |
1041 | 143 | } else { |
1042 | | /* Bits 7 to 1 of the first subsequent octet shall not be all set to 0.*/ |
1043 | 143 | tag = oct; |
1044 | 143 | item = proto_tree_add_uint(tree, hf_oer_tag, tvb, offset, 1, tag); |
1045 | 143 | if (!display_internal_oer_fields) proto_item_set_hidden(item); |
1046 | 143 | } |
1047 | 3.42k | } else { |
1048 | | /* Tag value in first octet */ |
1049 | 3.42k | item = proto_tree_add_bits_item(tree, hf_oer_tag, tvb, bit_offset, 6, ENC_BIG_ENDIAN); |
1050 | 3.42k | if (!display_internal_oer_fields) proto_item_set_hidden(item); |
1051 | 3.42k | } |
1052 | | |
1053 | | /* 20.2 If the choice type contains an extension marker in the "AlternativeTypeLists" and the chosen alternative |
1054 | | * is one of the extension additions, then the value of the chosen alternative shall be encoded as if it were contained |
1055 | | * in an open type (see clause 30), otherwise it shall be encoded normally. |
1056 | | */ |
1057 | 3.57k | if (value) { |
1058 | 0 | (*value) = -1; |
1059 | 0 | } |
1060 | | |
1061 | | /* XXX Extension handling is not implemented */ |
1062 | 8.91k | while (choice->func) { |
1063 | 8.10k | if (choice->value == tag) { |
1064 | 2.76k | choice_item = proto_tree_add_uint(tree, hf_index, tvb, old_offset, 0, choice->value); |
1065 | 2.76k | choice_tree = proto_item_add_subtree(choice_item, ett_index); |
1066 | | /* For known extensions parse length prefix */ |
1067 | 2.76k | if (choice->extension == ASN1_NOT_EXTENSION_ROOT) { |
1068 | 151 | unsigned length; |
1069 | 151 | offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); |
1070 | 151 | } |
1071 | 2.76k | offset = choice->func(tvb, offset, actx, choice_tree, *choice->p_id); |
1072 | 2.76k | proto_item_set_len(choice_item, offset - old_offset); |
1073 | 2.76k | if (value) { |
1074 | 0 | (*value) = tag; |
1075 | 0 | } |
1076 | 2.76k | return offset; |
1077 | 2.76k | } |
1078 | 5.33k | choice++; |
1079 | 5.33k | } |
1080 | | /* None of the known choice options matched, parse the contents as an extension */ |
1081 | | // XXX : should check if the extensions are present in the CHOICE definition |
1082 | 807 | offset = dissect_oer_octet_string(tvb, offset, actx, tree, hf_index, NO_BOUND, NO_BOUND, false, NULL); |
1083 | | |
1084 | 807 | return offset; |
1085 | 3.57k | } |
1086 | | |
1087 | | /* 21 Encoding of object identifier values |
1088 | | * The encoding of an object identifier value shall consist of a length determinant (see 8.6) followed by a series of octets, |
1089 | | * which are the contents octets of BER encoding of the object identifier value (see Rec. ITU-T X.690 | ISO/IEC 8825-1,8.19). |
1090 | | */ |
1091 | | static uint32_t |
1092 | | dissect_oer_any_oid(tvbuff_t* tvb, uint32_t offset, asn1_ctx_t* actx, proto_tree* tree, int hf_index, tvbuff_t** value_tvb, |
1093 | | bool is_absolute) |
1094 | 0 | { |
1095 | 0 | unsigned length; |
1096 | 0 | const char* str; |
1097 | 0 | header_field_info* hfi; |
1098 | |
|
1099 | 0 | DEBUG_ENTRY("dissect_oer_any_oid"); |
1100 | |
|
1101 | 0 | offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); |
1102 | |
|
1103 | 0 | actx->created_item = NULL; |
1104 | 0 | hfi = proto_registrar_get_nth(hf_index); |
1105 | 0 | if ((is_absolute && hfi->type == FT_OID) || (!is_absolute && hfi->type == FT_REL_OID)) { |
1106 | 0 | actx->created_item = proto_tree_add_item(tree, hf_index, tvb, offset, length, ENC_BIG_ENDIAN); |
1107 | 0 | } |
1108 | 0 | else if (FT_IS_STRING(hfi->type)) { |
1109 | 0 | str = oid_encoded2string(actx->pinfo->pool, tvb_get_ptr(tvb, offset, length), length); |
1110 | 0 | actx->created_item = proto_tree_add_string(tree, hf_index, tvb, offset, length, str); |
1111 | 0 | if (actx->created_item) { |
1112 | | /* see if we know the name of this oid */ |
1113 | 0 | str = oid_resolved_from_encoded(actx->pinfo->pool, tvb_get_ptr(tvb, offset, length), length); |
1114 | 0 | if (str) { |
1115 | 0 | proto_item_append_text(actx->created_item, " (%s)", str); |
1116 | 0 | } |
1117 | 0 | } |
1118 | 0 | } |
1119 | 0 | else { |
1120 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
1121 | 0 | } |
1122 | |
|
1123 | 0 | if (value_tvb) |
1124 | 0 | *value_tvb = tvb_new_subset_length(tvb, offset, length); |
1125 | |
|
1126 | 0 | return offset; |
1127 | 0 | } |
1128 | | |
1129 | | uint32_t |
1130 | | dissect_oer_object_identifier(tvbuff_t* tvb, uint32_t offset, asn1_ctx_t* actx, proto_tree* tree, int hf_index, tvbuff_t** value_tvb) |
1131 | 0 | { |
1132 | 0 | return dissect_oer_any_oid(tvb, offset, actx, tree, hf_index, value_tvb, true); |
1133 | 0 | } |
1134 | | |
1135 | | /* 27 Encoding of values of the restricted character string types |
1136 | | * 27.1 The encoding of a restricted character string type depends on whether the type is a known-multiplier character |
1137 | | * string type or not. The following types are known-multiplier character string types: |
1138 | | * IA5String, VisibleString, ISO646String, PrintableString, NumericString, BMPString, and UniversalString. |
1139 | | */ |
1140 | | |
1141 | | |
1142 | | uint32_t |
1143 | | dissect_oer_IA5String(tvbuff_t* tvb, uint32_t offset, asn1_ctx_t* actx, proto_tree* tree, int hf_index, int min_len, int max_len, bool has_extension _U_) |
1144 | 0 | { |
1145 | 0 | uint32_t length = 0; |
1146 | | |
1147 | | /* 27.2 For a known-multiplier character string type in which the lower and upper bounds of the effective size constraint |
1148 | | * are identical, the encoding shall consist of the series of octets specified in 27.4, with no length determinant. |
1149 | | */ |
1150 | 0 | if ((min_len == max_len) && (min_len != NO_BOUND )){ |
1151 | 0 | length = min_len; |
1152 | 0 | } |
1153 | 0 | else { |
1154 | 0 | offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); |
1155 | 0 | } |
1156 | 0 | actx->created_item = proto_tree_add_item(tree, hf_index, tvb, offset, length, ENC_ASCII | ENC_NA); |
1157 | |
|
1158 | 0 | return offset + length; |
1159 | |
|
1160 | 0 | } |
1161 | | |
1162 | | uint32_t |
1163 | | dissect_oer_UTF8String(tvbuff_t *tvb, uint32_t offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len _U_, int max_len _U_, bool has_extension _U_) |
1164 | 131 | { |
1165 | 131 | uint32_t length = 0; |
1166 | | /* 27.3 For every other character string type, the encoding shall consist of a length determinant |
1167 | | * (see 8.6) followed by the series of octets specified in 27.4. |
1168 | | */ |
1169 | 131 | offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_length_determinant, &length); |
1170 | 131 | actx->created_item = proto_tree_add_item( tree, hf_index, tvb, offset, length, ENC_UTF_8 | ENC_NA); |
1171 | | |
1172 | 131 | return offset + length; |
1173 | | |
1174 | 131 | } |
1175 | | |
1176 | | /* 30 Encoding of open type values |
1177 | | *NOTE – An open type is an ASN.1 type that can take any abstract value of any ASN.1 type. Each value of an open type consists |
1178 | | * of: |
1179 | | * a) a contained type; and |
1180 | | * b) a value of the contained type. |
1181 | | * The encoding of an open type value shall consist of a length determinant (see 8.6) followed by a series of octets, which |
1182 | | * are the encoding of the value of the contained type. |
1183 | | */ |
1184 | | |
1185 | | static uint32_t |
1186 | | dissect_oer_open_type_internal(tvbuff_t* tvb, uint32_t offset, asn1_ctx_t* actx, proto_tree* tree, int hf_index, void* type_cb, asn1_cb_variant variant) |
1187 | 192 | { |
1188 | 192 | int start_offset; |
1189 | 192 | uint32_t type_length; |
1190 | 192 | tvbuff_t* val_tvb = NULL; |
1191 | 192 | proto_tree* subtree = tree; |
1192 | | |
1193 | 192 | start_offset = offset; |
1194 | | |
1195 | | |
1196 | 192 | offset = dissect_oer_length_determinant(tvb, offset, actx, tree, hf_oer_open_type_length, &type_length); |
1197 | 192 | val_tvb = tvb_new_subset_length(tvb, offset, type_length); |
1198 | | |
1199 | 192 | actx->created_item = proto_tree_add_item(tree, hf_index, val_tvb, 0, type_length, ENC_BIG_ENDIAN); |
1200 | 192 | subtree = proto_item_add_subtree(actx->created_item, ett_oer_open_type); |
1201 | | |
1202 | 192 | if (variant == CB_NEW_DISSECTOR) { |
1203 | 0 | add_new_data_source(actx->pinfo, val_tvb, "OCTET STRING"); |
1204 | 0 | } |
1205 | | |
1206 | 192 | if (type_cb) { |
1207 | 0 | switch (variant) { |
1208 | 0 | case CB_ASN1_ENC: |
1209 | 0 | ((oer_type_fn)type_cb)(val_tvb, 0, actx, tree, hf_index); |
1210 | 0 | break; |
1211 | 0 | case CB_NEW_DISSECTOR: |
1212 | | /* Pas actx->private_data as "data" to the called function */ |
1213 | 0 | ((dissector_t)type_cb)(val_tvb, actx->pinfo, subtree, actx->private_data); |
1214 | 0 | break; |
1215 | 0 | case CB_DISSECTOR_HANDLE: |
1216 | 0 | break; |
1217 | 0 | } |
1218 | 0 | } |
1219 | 192 | else { |
1220 | 192 | actx->created_item = proto_tree_add_expert(tree, actx->pinfo, &ei_oer_open_type, tvb, start_offset, offset - start_offset); |
1221 | 192 | } |
1222 | | |
1223 | 192 | return offset; |
1224 | 192 | } |
1225 | | uint32_t |
1226 | | dissect_oer_open_type(tvbuff_t* tvb, uint32_t offset, asn1_ctx_t* actx, proto_tree* tree, int hf_index, oer_type_fn type_cb) |
1227 | 192 | { |
1228 | 192 | return dissect_oer_open_type_internal(tvb, offset, actx, tree, hf_index, (void*)type_cb, CB_ASN1_ENC); |
1229 | 192 | } |
1230 | | |
1231 | | /*--- proto_register_oer ----------------------------------------------*/ |
1232 | 16 | void proto_register_oer(void) { |
1233 | | |
1234 | | /* List of fields */ |
1235 | 16 | static hf_register_info hf[] = { |
1236 | 16 | { &hf_oer_optional_field_bit, |
1237 | 16 | { "Optional Field Bit", "oer.optional_field_bit", |
1238 | 16 | FT_UINT8, BASE_DEC, NULL, 0x0, |
1239 | 16 | NULL, HFILL } |
1240 | 16 | }, |
1241 | 16 | { &hf_oer_class, |
1242 | 16 | { "Class", "oer.class", |
1243 | 16 | FT_UINT8, BASE_DEC, VALS(oer_class_vals), 0x0, |
1244 | 16 | NULL, HFILL } |
1245 | 16 | }, |
1246 | 16 | { &hf_oer_tag, |
1247 | 16 | { "Tag", "oer.tag", |
1248 | 16 | FT_UINT32, BASE_DEC, NULL, 0x0, |
1249 | 16 | NULL, HFILL } |
1250 | 16 | }, |
1251 | 16 | { &hf_oer_length_determinant, |
1252 | 16 | { "length_determinant", "oer.length_determinant", |
1253 | 16 | FT_UINT32, BASE_DEC, NULL, 0x0, |
1254 | 16 | NULL, HFILL } |
1255 | 16 | }, |
1256 | 16 | { &hf_oer_extension_present_bit, |
1257 | 16 | { "Extension Present Bit", "oer.extension_present_bit", |
1258 | 16 | FT_UINT8, BASE_DEC, VALS(oer_extension_present_bit_vals), 0x00, |
1259 | 16 | NULL, HFILL } }, |
1260 | 16 | { &hf_oer_open_type_length, |
1261 | 16 | { "Open Type Length", "oer.open_type_length", |
1262 | 16 | FT_UINT32, BASE_DEC, NULL, 0x0, |
1263 | 16 | NULL, HFILL } |
1264 | 16 | }, |
1265 | | |
1266 | 16 | }; |
1267 | | |
1268 | | /* List of subtrees hf_oer_extension*/ |
1269 | 16 | static int *ett[] = { |
1270 | 16 | &ett_oer, |
1271 | 16 | &ett_oer_sequence_of_item, |
1272 | 16 | &ett_oer_open_type, |
1273 | 16 | &ett_oer_named_bits, |
1274 | 16 | }; |
1275 | | |
1276 | 16 | module_t *oer_module; |
1277 | 16 | expert_module_t* expert_oer; |
1278 | | |
1279 | | /* Register protocol */ |
1280 | 16 | proto_oer = proto_register_protocol("Octet Encoding Rules (ASN.1)", "OER", "oer"); |
1281 | | |
1282 | | /* Register fields and subtrees */ |
1283 | 16 | proto_register_field_array(proto_oer, hf, array_length(hf)); |
1284 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
1285 | | |
1286 | 16 | static ei_register_info ei[] = { |
1287 | 16 | { &ei_oer_not_decoded_yet, |
1288 | 16 | { "oer.not_decoded_yet", PI_UNDECODED, PI_WARN, "Not decoded yet", EXPFILL }}, |
1289 | 16 | { &ei_oer_undecoded, |
1290 | 16 | { "oer.error.undecoded", PI_UNDECODED, PI_WARN, "OER: Something unknown here", EXPFILL } }, |
1291 | 16 | { &ei_oer_open_type, |
1292 | 16 | { "oer.open_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown Open Type", EXPFILL }}, |
1293 | 16 | }; |
1294 | | |
1295 | 16 | expert_oer = expert_register_protocol(proto_oer); |
1296 | 16 | expert_register_field_array(expert_oer, ei, array_length(ei)); |
1297 | | |
1298 | 16 | oer_module = prefs_register_protocol(proto_oer, NULL); |
1299 | 16 | prefs_register_bool_preference(oer_module, "display_internal_oer_fields", |
1300 | 16 | "Display the internal OER fields in the tree", |
1301 | 16 | "Whether the dissector should put the internal OER data in the tree or if it should hide it", |
1302 | 16 | &display_internal_oer_fields); |
1303 | | |
1304 | | |
1305 | 16 | proto_set_cant_toggle(proto_oer); |
1306 | | |
1307 | 16 | } |
1308 | | |
1309 | | |
1310 | | /*--- proto_reg_handoff_oer -------------------------------------------*/ |
1311 | 16 | void proto_reg_handoff_oer(void) { |
1312 | | |
1313 | 16 | } |
1314 | | |
1315 | | /* |
1316 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
1317 | | * |
1318 | | * Local variables: |
1319 | | * c-basic-offset: 4 |
1320 | | * tab-width: 8 |
1321 | | * indent-tabs-mode: nil |
1322 | | * End: |
1323 | | * |
1324 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
1325 | | * :indentSize=4:tabSize=8:noTabs=true: |
1326 | | */ |