/src/wireshark/epan/dissectors/packet-pana.c
Line | Count | Source |
1 | | /* packet-pana.c |
2 | | * Routines for Protocol for carrying Authentication for Network Access dissection |
3 | | * Copyright 2006, Peter Racz <racz@ifi.unizh.ch> |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | /* This protocol implements PANA as of the IETF RFC 5191. |
12 | | * (Note: This dissector was updated to reflect |
13 | | * draft-ietf-pana-pana-18 which is a workitem of the ietf workgroup |
14 | | * internet area/pana. I believe draft-18 then became RFC 5191). |
15 | | */ |
16 | | |
17 | | #include "config.h" |
18 | | |
19 | | #include <epan/packet.h> |
20 | | #include <epan/conversation.h> |
21 | | #include <epan/tfs.h> |
22 | | |
23 | | #include <wsutil/array.h> |
24 | | #include <wsutil/ws_padding_to.h> |
25 | | |
26 | | void proto_register_pana(void); |
27 | | void proto_reg_handoff_pana(void); |
28 | | |
29 | | static dissector_handle_t pana_handle; |
30 | | |
31 | | #if 0 |
32 | | #define PANA_UDP_PORT 3001 |
33 | | #endif |
34 | | |
35 | 0 | #define MIN_AVP_SIZE 8 |
36 | | |
37 | 15 | #define PANA_FLAG_R 0x8000 |
38 | 15 | #define PANA_FLAG_S 0x4000 |
39 | 15 | #define PANA_FLAG_C 0x2000 |
40 | 15 | #define PANA_FLAG_A 0x1000 |
41 | 15 | #define PANA_FLAG_P 0x0800 |
42 | 15 | #define PANA_FLAG_I 0x0400 |
43 | | #if 0 |
44 | | #define PANA_FLAG_RES6 0x0200 |
45 | | #define PANA_FLAG_RES7 0x0100 |
46 | | #define PANA_FLAG_RES8 0x0080 |
47 | | #define PANA_FLAG_RES9 0x0040 |
48 | | #define PANA_FLAG_RES10 0x0020 |
49 | | #define PANA_FLAG_RES11 0x0010 |
50 | | #define PANA_FLAG_RES12 0x0008 |
51 | | #define PANA_FLAG_RES13 0x0004 |
52 | | #define PANA_FLAG_RES14 0x0002 |
53 | | #define PANA_FLAG_RES15 0x0001 |
54 | | #endif |
55 | 4 | #define PANA_FLAG_RESERVED 0x03ff |
56 | | |
57 | 15 | #define PANA_AVP_FLAG_V 0x8000 |
58 | | #if 0 |
59 | | #define PANA_AVP_FLAG_RES1 0x4000 |
60 | | #define PANA_AVP_FLAG_RES2 0x2000 |
61 | | #define PANA_AVP_FLAG_RES3 0x1000 |
62 | | #define PANA_AVP_FLAG_RES4 0x0800 |
63 | | #define PANA_AVP_FLAG_RES5 0x0400 |
64 | | #define PANA_AVP_FLAG_RES6 0x0200 |
65 | | #define PANA_AVP_FLAG_RES7 0x0100 |
66 | | #define PANA_AVP_FLAG_RES8 0x0080 |
67 | | #define PANA_AVP_FLAG_RES9 0x0040 |
68 | | #define PANA_AVP_FLAG_RES10 0x0020 |
69 | | #define PANA_AVP_FLAG_RES11 0x0010 |
70 | | #define PANA_AVP_FLAG_RES12 0x0008 |
71 | | #define PANA_AVP_FLAG_RES13 0x0004 |
72 | | #define PANA_AVP_FLAG_RES14 0x0002 |
73 | | #define PANA_AVP_FLAG_RES15 0x0001 |
74 | | #endif |
75 | 0 | #define PANA_AVP_FLAG_RESERVED 0x7fff |
76 | | |
77 | | static dissector_handle_t eap_handle; |
78 | | |
79 | | /* Initialize the protocol and registered fields */ |
80 | | static int proto_pana; |
81 | | static int hf_pana_reserved_type; |
82 | | static int hf_pana_length_type; |
83 | | static int hf_pana_msg_type; |
84 | | static int hf_pana_session_id; |
85 | | static int hf_pana_seqnumber; |
86 | | static int hf_pana_response_in; |
87 | | static int hf_pana_response_to; |
88 | | static int hf_pana_response_time; |
89 | | |
90 | | static int hf_pana_flags; |
91 | | static int hf_pana_flag_r; |
92 | | static int hf_pana_flag_s; |
93 | | static int hf_pana_flag_c; |
94 | | static int hf_pana_flag_a; |
95 | | static int hf_pana_flag_p; |
96 | | static int hf_pana_flag_i; |
97 | | static int hf_pana_avp_code; |
98 | | static int hf_pana_avp_data_length; |
99 | | static int hf_pana_avp_flags; |
100 | | static int hf_pana_avp_flag_v; |
101 | | static int hf_pana_avp_reserved; |
102 | | static int hf_pana_avp_vendorid; |
103 | | |
104 | | static int hf_pana_avp_data_uint64; |
105 | | static int hf_pana_avp_data_int64; |
106 | | static int hf_pana_avp_data_uint32; |
107 | | static int hf_pana_avp_data_int32; |
108 | | static int hf_pana_avp_data_bytes; |
109 | | static int hf_pana_avp_data_string; |
110 | | static int hf_pana_avp_data_enumerated; |
111 | | |
112 | 2 | #define MSG_TYPE_MAX 5 |
113 | | static const value_string msg_type_names[] = { |
114 | | { 1, "PANA-Client-Initiation" }, |
115 | | { 2, "PANA-Auth" }, |
116 | | { 3, "PANA-Termination" }, |
117 | | { 4, "PANA-Notification" }, |
118 | | { 5, "PANA-Relay" }, |
119 | | { 0, NULL } |
120 | | }; |
121 | | |
122 | | static const value_string msg_subtype_names[] = { |
123 | | { 0x0000, "Answer" }, |
124 | | { 0x8000, "Request" }, |
125 | | { 0, NULL } |
126 | | }; |
127 | | |
128 | 0 | #define AVP_CODE_MAX 13 |
129 | | static const value_string avp_code_names[] = { |
130 | | { 1, "AUTH AVP" }, |
131 | | { 2, "EAP-Payload AVP" }, |
132 | | { 3, "Integrity-Algorithm AVP" }, |
133 | | { 4, "Key-Id AVP" }, |
134 | | { 5, "Nonce AVP" }, |
135 | | { 6, "PRF-Algorithm AVP" }, |
136 | | { 7, "Result-Code" }, |
137 | | { 8, "Session-Lifetime" }, |
138 | | { 9, "Termination-Cause" }, |
139 | | { 10, "PaC-Information" }, |
140 | | { 11, "Relayed-Message" }, |
141 | | { 12, "Encryption-Encap" }, |
142 | | { 13, "Encryption-Algorithm" }, |
143 | | { 0, NULL } |
144 | | }; |
145 | | |
146 | | #if 0 |
147 | | static const value_string avp_resultcode_names[] = { |
148 | | { 0, "PANA_SUCCESS" }, |
149 | | { 1, "PANA_AUTHENTICATION_REJECTED" }, |
150 | | { 2, "PANA_AUTHORIZATION_REJECTED" }, |
151 | | { 0, NULL } |
152 | | }; |
153 | | #endif |
154 | | |
155 | | typedef enum { |
156 | | PANA_OCTET_STRING = 1, |
157 | | PANA_INTEGER32, |
158 | | PANA_INTEGER64, |
159 | | PANA_UNSIGNED32, |
160 | | PANA_UNSIGNED64, |
161 | | PANA_FLOAT32, |
162 | | PANA_FLOAT64, |
163 | | PANA_FLOAT128, |
164 | | PANA_GROUPED, |
165 | | PANA_ENUMERATED, |
166 | | PANA_UTF8STRING, |
167 | | PANA_EAP, |
168 | | PANA_RESULT_CODE, |
169 | | PANA_ENCAPSULATED |
170 | | } pana_avp_types; |
171 | | |
172 | | static const value_string avp_type_names[]={ |
173 | | { PANA_OCTET_STRING, "OctetString" }, |
174 | | { PANA_INTEGER32, "Integer32" }, |
175 | | { PANA_INTEGER64, "Integer64" }, |
176 | | { PANA_UNSIGNED32, "Unsigned32" }, |
177 | | { PANA_UNSIGNED64, "Unsigned64" }, |
178 | | { PANA_FLOAT32, "Float32" }, |
179 | | { PANA_FLOAT64, "Float64" }, |
180 | | { PANA_FLOAT128, "Float128" }, |
181 | | { PANA_GROUPED, "Grouped" }, |
182 | | { PANA_ENUMERATED, "Enumerated" }, |
183 | | { PANA_UTF8STRING, "UTF8String" }, |
184 | | { PANA_EAP, "OctetString" }, |
185 | | { PANA_RESULT_CODE, "Unsigned32" }, |
186 | | { PANA_ENCAPSULATED, "Encapsulated" }, |
187 | | { 0, NULL } |
188 | | }; |
189 | | |
190 | | |
191 | | /* Initialize the subtree pointers */ |
192 | | static int ett_pana; |
193 | | static int ett_pana_flags; |
194 | | static int ett_pana_avp; |
195 | | static int ett_pana_avp_info; |
196 | | static int ett_pana_avp_flags; |
197 | | |
198 | | |
199 | | typedef struct _pana_transaction_t { |
200 | | uint32_t req_frame; |
201 | | uint32_t rep_frame; |
202 | | nstime_t req_time; |
203 | | } pana_transaction_t; |
204 | | |
205 | | typedef struct _pana_conv_info_t { |
206 | | wmem_map_t *pdus; |
207 | | } pana_conv_info_t; |
208 | | |
209 | | static void |
210 | | dissect_pana_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); |
211 | | |
212 | | /* |
213 | | * Function for the PANA flags dissector. |
214 | | */ |
215 | | static void |
216 | | dissect_pana_flags(proto_tree *parent_tree, tvbuff_t *tvb, int offset, uint16_t flags) |
217 | 0 | { |
218 | 0 | static int * const flag_fields[] = { |
219 | 0 | &hf_pana_flag_r, |
220 | 0 | &hf_pana_flag_s, |
221 | 0 | &hf_pana_flag_c, |
222 | 0 | &hf_pana_flag_a, |
223 | 0 | &hf_pana_flag_p, |
224 | 0 | &hf_pana_flag_i, |
225 | 0 | NULL, |
226 | 0 | }; |
227 | |
|
228 | 0 | proto_tree_add_bitmask_value_with_flags(parent_tree, tvb, offset, hf_pana_flags, |
229 | 0 | ett_pana_flags, flag_fields, flags, BMT_NO_TFS|BMT_NO_FALSE); |
230 | 0 | } |
231 | | |
232 | | |
233 | | /* |
234 | | * Function for AVP flags dissector. |
235 | | */ |
236 | | static void |
237 | | dissect_pana_avp_flags(proto_tree *parent_tree, tvbuff_t *tvb, int offset, uint16_t flags) |
238 | 0 | { |
239 | 0 | static int * const flag_fields[] = { |
240 | 0 | &hf_pana_avp_flag_v, |
241 | 0 | NULL, |
242 | 0 | }; |
243 | |
|
244 | 0 | proto_tree_add_bitmask_value_with_flags(parent_tree, tvb, offset, hf_pana_avp_flags, |
245 | 0 | ett_pana_avp_flags, flag_fields, flags, BMT_NO_TFS|BMT_NO_FALSE); |
246 | 0 | } |
247 | | |
248 | | |
249 | | /* |
250 | | * Map AVP code to AVP type |
251 | | */ |
252 | | static pana_avp_types |
253 | | pana_avp_get_type(uint16_t avp_code, uint32_t vendor_id) |
254 | 0 | { |
255 | |
|
256 | 0 | if(vendor_id == 0) { |
257 | 0 | switch(avp_code) { |
258 | 0 | case 1: return PANA_OCTET_STRING; /* AUTH AVP */ |
259 | 0 | case 2: return PANA_EAP; /* EAP-Payload AVP */ |
260 | 0 | case 3: return PANA_UNSIGNED32; /* Integrity-Algorithm AVP */ |
261 | 0 | case 4: return PANA_INTEGER32; /* Key-Id AVP */ |
262 | 0 | case 5: return PANA_OCTET_STRING; /* Nonce AVP */ |
263 | 0 | case 6: return PANA_UNSIGNED32; /* PRF-Algorithm AVP */ |
264 | 0 | case 7: return PANA_RESULT_CODE; /* Result-Code AVP */ |
265 | 0 | case 8: return PANA_UNSIGNED32; /* Session-Lifetime AVP */ |
266 | 0 | case 9: return PANA_ENUMERATED; /* Termination-Cause AVP */ |
267 | 0 | case 10: return PANA_OCTET_STRING; /* PaC-Information AVP */ |
268 | 0 | case 11: return PANA_ENCAPSULATED; /* Relayed-Message AVP */ |
269 | 0 | case 12: return PANA_OCTET_STRING; /* Encryption-Encap AVP */ |
270 | 0 | case 13: return PANA_UNSIGNED32; /* Encryption-Algorithm AVP */ |
271 | 0 | default: return PANA_OCTET_STRING; |
272 | 0 | } |
273 | 0 | } else { |
274 | 0 | return PANA_OCTET_STRING; |
275 | 0 | } |
276 | |
|
277 | 0 | } |
278 | | |
279 | | |
280 | | /* |
281 | | * Function for AVP dissector. |
282 | | */ |
283 | | static void |
284 | | // NOLINTNEXTLINE(misc-no-recursion) |
285 | | dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree) |
286 | 0 | { |
287 | |
|
288 | 0 | int offset; |
289 | 0 | uint16_t avp_code; |
290 | 0 | uint16_t avp_flags; |
291 | 0 | uint32_t avp_length; |
292 | 0 | uint16_t avp_type; |
293 | 0 | uint32_t vendor_id; |
294 | 0 | uint32_t avp_hdr_length; |
295 | 0 | uint32_t avp_data_length, result_code; |
296 | 0 | uint32_t padding; |
297 | |
|
298 | 0 | int32_t buffer_length; |
299 | |
|
300 | 0 | tvbuff_t *group_tvb; |
301 | 0 | tvbuff_t *eap_tvb; |
302 | 0 | tvbuff_t *encap_tvb; |
303 | 0 | proto_tree *single_avp_tree; |
304 | 0 | proto_tree *avp_eap_tree; |
305 | 0 | proto_tree *avp_encap_tree; |
306 | |
|
307 | 0 | offset = 0; |
308 | 0 | buffer_length = tvb_reported_length(tvb); |
309 | | |
310 | | /* Go through all AVPs */ |
311 | 0 | while (buffer_length > 0) { |
312 | 0 | avp_code = tvb_get_ntohs(tvb, offset); |
313 | 0 | avp_flags = tvb_get_ntohs(tvb, offset + 2); |
314 | 0 | avp_data_length = tvb_get_ntohs(tvb, offset + 4); |
315 | | |
316 | | /* Check AVP flags for vendor specific AVP */ |
317 | 0 | if (avp_flags & PANA_AVP_FLAG_V) { |
318 | 0 | vendor_id = tvb_get_ntohl(tvb, 8); |
319 | 0 | avp_hdr_length = 12; |
320 | 0 | } else { |
321 | 0 | vendor_id = 0; |
322 | 0 | avp_hdr_length = 8; |
323 | 0 | } |
324 | |
|
325 | 0 | avp_length = avp_hdr_length + avp_data_length; |
326 | | |
327 | | /* Check AVP type */ |
328 | 0 | avp_type = pana_avp_get_type(avp_code, vendor_id); |
329 | | |
330 | | |
331 | | /* Check padding */ |
332 | 0 | padding = WS_PADDING_TO_4(avp_length); |
333 | |
|
334 | 0 | single_avp_tree = proto_tree_add_subtree_format(avp_tree, tvb, offset, avp_length + padding, |
335 | 0 | ett_pana_avp_info, NULL, "%s (%s) length: %d bytes (%d padded bytes)", |
336 | 0 | val_to_str(pinfo->pool, avp_code, avp_code_names, "Unknown (%d)"), |
337 | 0 | val_to_str(pinfo->pool, avp_type, avp_type_names, "Unknown (%d)"), |
338 | 0 | avp_length, |
339 | 0 | avp_length + padding); |
340 | | |
341 | | /* AVP Code */ |
342 | 0 | proto_tree_add_uint_format_value(single_avp_tree, hf_pana_avp_code, tvb, |
343 | 0 | offset, 2, avp_code, "%s (%u)", |
344 | 0 | val_to_str(pinfo->pool, avp_code, avp_code_names, "Unknown (%d)"), |
345 | 0 | avp_code); |
346 | 0 | offset += 2; |
347 | | |
348 | | /* AVP Flags */ |
349 | 0 | dissect_pana_avp_flags(single_avp_tree, tvb, offset, avp_flags); |
350 | 0 | offset += 2; |
351 | | |
352 | | /* AVP Length */ |
353 | 0 | proto_tree_add_item(single_avp_tree, hf_pana_avp_data_length, tvb, offset, 2, ENC_BIG_ENDIAN); |
354 | 0 | offset += 2; |
355 | | |
356 | | /* Reserved */ |
357 | 0 | proto_tree_add_item(single_avp_tree, hf_pana_avp_reserved, tvb, offset, 2, ENC_NA); |
358 | 0 | offset += 2; |
359 | |
|
360 | 0 | if (avp_flags & PANA_AVP_FLAG_V) { |
361 | | /* Vendor ID */ |
362 | 0 | proto_tree_add_item(single_avp_tree, hf_pana_avp_vendorid, tvb, offset, 4, ENC_BIG_ENDIAN); |
363 | 0 | offset += 4; |
364 | 0 | } |
365 | 0 | if (! (avp_flags & PANA_AVP_FLAG_V)) { |
366 | | /* AVP Value */ |
367 | 0 | switch(avp_type) { |
368 | 0 | case PANA_GROUPED: { |
369 | 0 | proto_tree *avp_group_tree; |
370 | 0 | avp_group_tree = proto_tree_add_subtree(single_avp_tree, |
371 | 0 | tvb, offset, avp_data_length, |
372 | 0 | ett_pana_avp, NULL, "Grouped AVP"); |
373 | 0 | group_tvb = tvb_new_subset_length(tvb, offset, avp_data_length); |
374 | | // We recurse here, but we'll run out of packet before we run out of stack. |
375 | 0 | dissect_avps(group_tvb, pinfo, avp_group_tree); |
376 | 0 | break; |
377 | 0 | } |
378 | 0 | case PANA_UTF8STRING: { |
379 | 0 | proto_tree_add_item(single_avp_tree, hf_pana_avp_data_string, tvb, |
380 | 0 | offset, avp_data_length, ENC_UTF_8); |
381 | 0 | break; |
382 | 0 | } |
383 | 0 | case PANA_OCTET_STRING: { |
384 | 0 | proto_tree_add_item(single_avp_tree, hf_pana_avp_data_bytes, tvb, |
385 | 0 | offset, avp_data_length, ENC_NA); |
386 | 0 | break; |
387 | 0 | } |
388 | 0 | case PANA_INTEGER32: { |
389 | 0 | proto_tree_add_item(single_avp_tree, hf_pana_avp_data_int32, tvb, |
390 | 0 | offset, 4, ENC_BIG_ENDIAN); |
391 | 0 | break; |
392 | 0 | } |
393 | 0 | case PANA_UNSIGNED32: { |
394 | 0 | proto_tree_add_item(single_avp_tree, hf_pana_avp_data_uint32, tvb, |
395 | 0 | offset, 4, ENC_BIG_ENDIAN); |
396 | 0 | break; |
397 | 0 | } |
398 | 0 | case PANA_INTEGER64: { |
399 | 0 | proto_tree_add_item(single_avp_tree, hf_pana_avp_data_int64, tvb, |
400 | 0 | offset, 8, ENC_BIG_ENDIAN); |
401 | 0 | break; |
402 | 0 | } |
403 | 0 | case PANA_UNSIGNED64: { |
404 | 0 | proto_tree_add_item(single_avp_tree, hf_pana_avp_data_uint64, tvb, |
405 | 0 | offset, 8, ENC_BIG_ENDIAN); |
406 | 0 | break; |
407 | 0 | } |
408 | 0 | case PANA_ENUMERATED: { |
409 | 0 | proto_tree_add_item(single_avp_tree, hf_pana_avp_data_enumerated, tvb, |
410 | 0 | offset, 4, ENC_BIG_ENDIAN); |
411 | 0 | break; |
412 | 0 | } |
413 | 0 | case PANA_RESULT_CODE: { |
414 | 0 | result_code = tvb_get_ntohl(tvb, offset); |
415 | 0 | proto_tree_add_uint_format(single_avp_tree, hf_pana_avp_code, tvb, offset, avp_data_length, |
416 | 0 | result_code, "Value: %d (%s)", |
417 | 0 | result_code, |
418 | 0 | val_to_str(pinfo->pool, result_code, avp_code_names, "Unknown (%d)")); |
419 | 0 | break; |
420 | 0 | } |
421 | 0 | case PANA_EAP: { |
422 | 0 | avp_eap_tree = proto_tree_add_subtree(single_avp_tree, |
423 | 0 | tvb, offset, avp_data_length, |
424 | 0 | ett_pana_avp, NULL, "AVP Value (EAP packet)"); |
425 | 0 | eap_tvb = tvb_new_subset_length(tvb, offset, avp_data_length); |
426 | 0 | DISSECTOR_ASSERT_HINT(eap_handle, "EAP Dissector not available"); |
427 | 0 | call_dissector(eap_handle, eap_tvb, pinfo, avp_eap_tree); |
428 | 0 | break; |
429 | 0 | } |
430 | 0 | case PANA_ENCAPSULATED: { |
431 | 0 | avp_encap_tree = proto_tree_add_subtree(single_avp_tree, |
432 | 0 | tvb, offset, avp_data_length, |
433 | 0 | ett_pana_avp, NULL, "AVP Value (PANA packet)"); |
434 | 0 | encap_tvb = tvb_new_subset_length(tvb, offset, avp_data_length); |
435 | | // We recurse here, but we'll run out of packet before we run out of stack. |
436 | 0 | dissect_pana_pdu(encap_tvb, pinfo, avp_encap_tree); |
437 | 0 | break; |
438 | 0 | } |
439 | 0 | } |
440 | 0 | } |
441 | 0 | offset += avp_data_length + padding; |
442 | | |
443 | | /* Update the buffer length */ |
444 | 0 | buffer_length -= avp_length + padding; |
445 | 0 | } |
446 | |
|
447 | 0 | } |
448 | | |
449 | | |
450 | | /* |
451 | | * Function for the PANA PDU dissector. |
452 | | */ |
453 | | static void |
454 | | // NOLINTNEXTLINE(misc-no-recursion) |
455 | | dissect_pana_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) |
456 | 0 | { |
457 | |
|
458 | 0 | proto_tree *pana_tree = NULL; |
459 | 0 | uint16_t flags; |
460 | 0 | uint16_t msg_type; |
461 | 0 | uint32_t msg_length; |
462 | 0 | uint32_t avp_length; |
463 | 0 | uint32_t seq_num; |
464 | 0 | conversation_t *conversation; |
465 | 0 | pana_conv_info_t *pana_info; |
466 | 0 | pana_transaction_t *pana_trans; |
467 | 0 | unsigned offset = 0; |
468 | |
|
469 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "PANA"); |
470 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
471 | | |
472 | | /* Get message length, type and flags */ |
473 | 0 | msg_length = tvb_get_ntohs(tvb, 2); |
474 | 0 | flags = tvb_get_ntohs(tvb, 4); |
475 | 0 | msg_type = tvb_get_ntohs(tvb, 6); |
476 | 0 | seq_num = tvb_get_ntohl(tvb, 12); |
477 | 0 | avp_length = msg_length - 16; |
478 | |
|
479 | 0 | col_add_fstr(pinfo->cinfo, COL_INFO, "Type %s-%s", |
480 | 0 | val_to_str(pinfo->pool, msg_type, msg_type_names, "Unknown (%d)"), |
481 | 0 | val_to_str(pinfo->pool, flags & PANA_FLAG_R, msg_subtype_names, "Unknown (%d)")); |
482 | | |
483 | | /* Make the protocol tree */ |
484 | 0 | if (tree) { |
485 | 0 | proto_item *ti; |
486 | 0 | ti = proto_tree_add_item(tree, proto_pana, tvb, 0, -1, ENC_NA); |
487 | 0 | pana_tree = proto_item_add_subtree(ti, ett_pana); |
488 | 0 | } |
489 | | |
490 | | |
491 | | /* |
492 | | * We need to track some state for this protocol on a per conversation |
493 | | * basis so we can do neat things like request/response tracking |
494 | | */ |
495 | 0 | conversation = find_or_create_conversation(pinfo); |
496 | | |
497 | | /* |
498 | | * Do we already have a state structure for this conv |
499 | | */ |
500 | 0 | pana_info = (pana_conv_info_t *)conversation_get_proto_data(conversation, proto_pana); |
501 | 0 | if (!pana_info) { |
502 | | /* No. Attach that information to the conversation, and add |
503 | | * it to the list of information structures. |
504 | | */ |
505 | 0 | pana_info = wmem_new(wmem_file_scope(), pana_conv_info_t); |
506 | 0 | pana_info->pdus=wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); |
507 | |
|
508 | 0 | conversation_add_proto_data(conversation, proto_pana, pana_info); |
509 | 0 | } |
510 | |
|
511 | 0 | if(!pinfo->fd->visited){ |
512 | 0 | if(flags&PANA_FLAG_R){ |
513 | | /* This is a request */ |
514 | 0 | pana_trans=wmem_new(wmem_file_scope(), pana_transaction_t); |
515 | 0 | pana_trans->req_frame=pinfo->num; |
516 | 0 | pana_trans->rep_frame=0; |
517 | 0 | pana_trans->req_time=pinfo->abs_ts; |
518 | 0 | wmem_map_insert(pana_info->pdus, GUINT_TO_POINTER(seq_num), (void *)pana_trans); |
519 | 0 | } else { |
520 | 0 | pana_trans=(pana_transaction_t *)wmem_map_lookup(pana_info->pdus, GUINT_TO_POINTER(seq_num)); |
521 | 0 | if(pana_trans){ |
522 | 0 | pana_trans->rep_frame=pinfo->num; |
523 | 0 | } |
524 | 0 | } |
525 | 0 | } else { |
526 | 0 | pana_trans=(pana_transaction_t *)wmem_map_lookup(pana_info->pdus, GUINT_TO_POINTER(seq_num)); |
527 | 0 | } |
528 | |
|
529 | 0 | if(!pana_trans){ |
530 | | /* create a "fake" pana_trans structure */ |
531 | 0 | pana_trans=wmem_new(pinfo->pool, pana_transaction_t); |
532 | 0 | pana_trans->req_frame=0; |
533 | 0 | pana_trans->rep_frame=0; |
534 | 0 | pana_trans->req_time=pinfo->abs_ts; |
535 | 0 | } |
536 | | |
537 | | /* print state tracking in the tree */ |
538 | 0 | if(flags&PANA_FLAG_R){ |
539 | | /* This is a request */ |
540 | 0 | if(pana_trans->rep_frame){ |
541 | 0 | proto_item *it; |
542 | |
|
543 | 0 | it=proto_tree_add_uint(pana_tree, hf_pana_response_in, tvb, 0, 0, pana_trans->rep_frame); |
544 | 0 | proto_item_set_generated(it); |
545 | 0 | } |
546 | 0 | } else { |
547 | | /* This is a reply */ |
548 | 0 | if(pana_trans->req_frame){ |
549 | 0 | proto_item *it; |
550 | 0 | nstime_t ns; |
551 | |
|
552 | 0 | it=proto_tree_add_uint(pana_tree, hf_pana_response_to, tvb, 0, 0, pana_trans->req_frame); |
553 | 0 | proto_item_set_generated(it); |
554 | |
|
555 | 0 | nstime_delta(&ns, &pinfo->abs_ts, &pana_trans->req_time); |
556 | 0 | it=proto_tree_add_time(pana_tree, hf_pana_response_time, tvb, 0, 0, &ns); |
557 | 0 | proto_item_set_generated(it); |
558 | 0 | } |
559 | 0 | } |
560 | | |
561 | | /* Reserved field */ |
562 | 0 | proto_tree_add_item(pana_tree, hf_pana_reserved_type, tvb, offset, 2, ENC_NA); |
563 | 0 | offset += 2; |
564 | | |
565 | | /* Length */ |
566 | 0 | proto_tree_add_item(pana_tree, hf_pana_length_type, tvb, offset, 2, ENC_BIG_ENDIAN); |
567 | 0 | offset += 2; |
568 | | |
569 | | /* Flags */ |
570 | 0 | dissect_pana_flags(pana_tree, tvb, offset, flags); |
571 | 0 | offset += 2; |
572 | | |
573 | | /* Message Type */ |
574 | 0 | proto_tree_add_uint_format_value(pana_tree, hf_pana_msg_type, tvb, |
575 | 0 | offset, 2, msg_type, "%s-%s (%d)", |
576 | 0 | val_to_str(pinfo->pool, msg_type, msg_type_names, "Unknown (%d)"), |
577 | 0 | val_to_str(pinfo->pool, flags & PANA_FLAG_R, msg_subtype_names, "Unknown (%d)"), |
578 | 0 | msg_type); |
579 | 0 | offset += 2; |
580 | | |
581 | | /* Session ID */ |
582 | 0 | proto_tree_add_item(pana_tree, hf_pana_session_id, tvb, offset, 4, ENC_BIG_ENDIAN); |
583 | 0 | offset += 4; |
584 | | |
585 | | /* Sequence Number */ |
586 | 0 | proto_tree_add_item(pana_tree, hf_pana_seqnumber, tvb, offset, 4, ENC_BIG_ENDIAN); |
587 | 0 | offset += 4; |
588 | | |
589 | | /* AVPs */ |
590 | 0 | if(avp_length != 0){ |
591 | 0 | tvbuff_t *avp_tvb; |
592 | 0 | proto_tree *avp_tree; |
593 | 0 | avp_tvb = tvb_new_subset_length(tvb, offset, avp_length); |
594 | 0 | avp_tree = proto_tree_add_subtree(pana_tree, tvb, offset, avp_length, ett_pana_avp, NULL, "Attribute Value Pairs"); |
595 | |
|
596 | 0 | dissect_avps(avp_tvb, pinfo, avp_tree); |
597 | 0 | } |
598 | |
|
599 | 0 | } |
600 | | |
601 | | |
602 | | /* |
603 | | * Function for the PANA dissector. |
604 | | * |
605 | | * Called directly as a non-heuristic dissecotr or called by the heuristic |
606 | | * dissector. |
607 | | */ |
608 | | static int |
609 | | dissect_pana(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
610 | 1.43k | { |
611 | | |
612 | 1.43k | uint16_t pana_res; |
613 | 1.43k | uint32_t msg_length; |
614 | 1.43k | uint16_t flags; |
615 | 1.43k | uint32_t buffer_length; |
616 | 1.43k | uint16_t msg_type; |
617 | 1.43k | uint32_t avp_length; |
618 | | |
619 | | /* Get actual buffer length */ |
620 | 1.43k | buffer_length = tvb_captured_length(tvb); |
621 | | |
622 | | /* Check minimum buffer length */ |
623 | 1.43k | if(buffer_length < 12) { |
624 | 511 | return 0; |
625 | 511 | } |
626 | | |
627 | | /* Check minimum packet length */ |
628 | 920 | msg_length = tvb_get_ntohs(tvb, 2); |
629 | 920 | if(msg_length < 16) { |
630 | 145 | return 0; |
631 | 145 | } |
632 | | |
633 | | /* Check the packet length */ |
634 | 775 | if(msg_length != tvb_reported_length(tvb)) { |
635 | 770 | return 0; |
636 | 770 | } |
637 | | |
638 | | /* check that the reserved field is zero */ |
639 | 5 | pana_res = tvb_get_ntohs(tvb, 0); |
640 | 5 | if (pana_res != 0) { |
641 | 1 | return 0; |
642 | 1 | } |
643 | | |
644 | | /* verify that none of the reserved bits are set */ |
645 | 4 | flags = tvb_get_ntohs(tvb, 4); |
646 | 4 | if (flags & PANA_FLAG_RESERVED) { |
647 | 2 | return 0; |
648 | 2 | } |
649 | | |
650 | | /* verify that we recognize the message type */ |
651 | 2 | msg_type = tvb_get_ntohs(tvb, 6); |
652 | 2 | if ((msg_type > MSG_TYPE_MAX) || (msg_type == 0)) { |
653 | 2 | return 0; |
654 | 2 | } |
655 | | |
656 | 0 | avp_length = msg_length - 16; |
657 | | |
658 | | /* For bug 1908: check the length of the first AVP, too */ |
659 | |
|
660 | 0 | if (avp_length != 0) { |
661 | 0 | uint32_t avp_offset; |
662 | 0 | uint16_t avp_code; |
663 | 0 | uint32_t first_avp_length; |
664 | 0 | uint16_t avp_flags; |
665 | |
|
666 | 0 | if (avp_length < MIN_AVP_SIZE) { |
667 | 0 | return 0; |
668 | 0 | } |
669 | 0 | avp_offset = 16; |
670 | | /* Make sure no exceptions since we're just doing a preliminary heuristic check */ |
671 | 0 | if ((avp_offset + 8) > buffer_length ) { |
672 | 0 | return 0; |
673 | 0 | } |
674 | 0 | avp_code = tvb_get_ntohs(tvb, avp_offset); |
675 | 0 | if ((avp_code == 0) || (avp_code > AVP_CODE_MAX)) { |
676 | 0 | return 0; |
677 | 0 | } |
678 | 0 | avp_flags = tvb_get_ntohs(tvb, avp_offset + 2); |
679 | 0 | if (avp_flags & PANA_AVP_FLAG_RESERVED) { |
680 | 0 | return 0; |
681 | 0 | } |
682 | | /* check whether is the V (vendor) flag on or not */ |
683 | 0 | if (avp_flags & PANA_AVP_FLAG_V) { |
684 | 0 | first_avp_length = 12; |
685 | 0 | } else { |
686 | 0 | first_avp_length = 8; |
687 | 0 | } |
688 | |
|
689 | 0 | first_avp_length += tvb_get_ntohs(tvb, avp_offset + 4); |
690 | |
|
691 | 0 | if (first_avp_length > avp_length) { |
692 | 0 | return 0; |
693 | 0 | } |
694 | 0 | } |
695 | | |
696 | 0 | dissect_pana_pdu(tvb, pinfo, tree); |
697 | |
|
698 | 0 | return tvb_reported_length(tvb); |
699 | |
|
700 | 0 | } |
701 | | |
702 | | static bool |
703 | | dissect_pana_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
704 | 1.43k | { |
705 | 1.43k | return dissect_pana(tvb, pinfo, tree, data) != 0; |
706 | 1.43k | } |
707 | | |
708 | | /* |
709 | | * Register the protocol with Wireshark |
710 | | */ |
711 | | void |
712 | | proto_register_pana(void) |
713 | 15 | { |
714 | | |
715 | 15 | static hf_register_info hf[] = { |
716 | 15 | { &hf_pana_response_in, |
717 | 15 | { "Response In", "pana.response_in", |
718 | 15 | FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0, |
719 | 15 | "The response to this PANA request is in this frame", HFILL } |
720 | 15 | }, |
721 | 15 | { &hf_pana_response_to, |
722 | 15 | { "Request In", "pana.response_to", |
723 | 15 | FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0, |
724 | 15 | "This is a response to the PANA request in this frame", HFILL } |
725 | 15 | }, |
726 | 15 | { &hf_pana_response_time, |
727 | 15 | { "Response Time", "pana.response_time", |
728 | 15 | FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, |
729 | 15 | "The time between the Call and the Reply", HFILL } |
730 | 15 | }, |
731 | 15 | { &hf_pana_reserved_type, |
732 | 15 | { "PANA Reserved", "pana.reserved", |
733 | 15 | FT_BYTES, BASE_NONE, NULL, 0x0, |
734 | 15 | NULL, HFILL } |
735 | 15 | }, |
736 | 15 | { &hf_pana_length_type, |
737 | 15 | { "PANA Message Length", "pana.length", |
738 | 15 | FT_UINT16, BASE_DEC, NULL, 0x0, |
739 | 15 | NULL, HFILL } |
740 | 15 | }, |
741 | | |
742 | | |
743 | 15 | { &hf_pana_flags, |
744 | 15 | { "Flags", "pana.flags", |
745 | 15 | FT_UINT8, BASE_HEX, NULL, 0x0, |
746 | 15 | NULL, HFILL } |
747 | 15 | }, |
748 | 15 | { &hf_pana_flag_r, |
749 | 15 | { "Request", "pana.flags.r", |
750 | 15 | FT_BOOLEAN, 16, TFS(&tfs_set_notset), PANA_FLAG_R, |
751 | 15 | NULL, HFILL } |
752 | 15 | }, |
753 | 15 | { &hf_pana_flag_s, |
754 | 15 | { "Start", "pana.flags.s", |
755 | 15 | FT_BOOLEAN, 16, TFS(&tfs_set_notset), PANA_FLAG_S, |
756 | 15 | NULL, HFILL } |
757 | 15 | }, |
758 | 15 | { &hf_pana_flag_c, |
759 | 15 | { "Complete","pana.flags.c", |
760 | 15 | FT_BOOLEAN, 16, TFS(&tfs_set_notset), PANA_FLAG_C, |
761 | 15 | NULL, HFILL } |
762 | 15 | }, |
763 | 15 | { &hf_pana_flag_a, |
764 | 15 | { "Auth","pana.flags.a", |
765 | 15 | FT_BOOLEAN, 16, TFS(&tfs_set_notset), PANA_FLAG_A, |
766 | 15 | NULL, HFILL } |
767 | 15 | }, |
768 | 15 | { &hf_pana_flag_p, |
769 | 15 | { "Ping","pana.flags.p", |
770 | 15 | FT_BOOLEAN, 16, TFS(&tfs_set_notset), PANA_FLAG_P, |
771 | 15 | NULL, HFILL } |
772 | 15 | }, |
773 | 15 | { &hf_pana_flag_i, |
774 | 15 | { "IP Reconfig","pana.flags.i", |
775 | 15 | FT_BOOLEAN, 16, TFS(&tfs_set_notset), PANA_FLAG_I, |
776 | 15 | NULL, HFILL } |
777 | 15 | }, |
778 | | |
779 | 15 | { &hf_pana_msg_type, |
780 | 15 | { "PANA Message Type", "pana.type", |
781 | 15 | FT_UINT16, BASE_DEC, NULL, 0x0, |
782 | 15 | NULL, HFILL } |
783 | 15 | }, |
784 | 15 | { &hf_pana_session_id, |
785 | 15 | { "PANA Session ID", "pana.sid", |
786 | 15 | FT_UINT32, BASE_HEX, NULL, 0x0, |
787 | 15 | NULL, HFILL } |
788 | 15 | }, |
789 | 15 | { &hf_pana_seqnumber, |
790 | 15 | { "PANA Sequence Number", "pana.seq", |
791 | 15 | FT_UINT32, BASE_HEX, NULL, 0x0, |
792 | 15 | NULL, HFILL } |
793 | 15 | }, |
794 | | |
795 | | |
796 | 15 | { &hf_pana_avp_code, |
797 | 15 | { "AVP Code", "pana.avp.code", |
798 | 15 | FT_UINT16, BASE_DEC, NULL, 0x0, |
799 | 15 | NULL, HFILL } |
800 | 15 | }, |
801 | 15 | { &hf_pana_avp_data_length, |
802 | 15 | { "AVP Data Length", "pana.avp.data_length", |
803 | 15 | FT_UINT16, BASE_DEC, NULL, 0x0, |
804 | 15 | NULL, HFILL } |
805 | 15 | }, |
806 | 15 | { &hf_pana_avp_flags, |
807 | 15 | { "AVP Flags", "pana.avp.flags", |
808 | 15 | FT_UINT16, BASE_HEX, NULL, 0x0, |
809 | 15 | NULL, HFILL } |
810 | 15 | }, |
811 | 15 | { &hf_pana_avp_flag_v, |
812 | 15 | { "Vendor", "pana.avp.flags.v", |
813 | 15 | FT_BOOLEAN, 16, TFS(&tfs_set_notset), PANA_AVP_FLAG_V, |
814 | 15 | NULL, HFILL } |
815 | 15 | }, |
816 | 15 | { &hf_pana_avp_reserved, |
817 | 15 | { "AVP Reserved", "pana.avp.reserved", |
818 | 15 | FT_BYTES, BASE_NONE, NULL, 0x0, |
819 | 15 | NULL, HFILL } |
820 | 15 | }, |
821 | 15 | { &hf_pana_avp_vendorid, |
822 | 15 | { "AVP Vendor ID", "pana.avp.vendorid", |
823 | 15 | FT_UINT32, BASE_HEX, NULL, 0x0, |
824 | 15 | NULL, HFILL } |
825 | 15 | }, |
826 | | |
827 | | |
828 | 15 | { &hf_pana_avp_data_uint64, |
829 | 15 | { "Value", "pana.avp.data.uint64", |
830 | 15 | FT_UINT64, BASE_HEX, NULL, 0x0, |
831 | 15 | NULL, HFILL } |
832 | 15 | }, |
833 | 15 | { &hf_pana_avp_data_int64, |
834 | 15 | { "Value", "pana.avp.data.int64", |
835 | 15 | FT_INT64, BASE_DEC, NULL, 0x0, |
836 | 15 | NULL, HFILL } |
837 | 15 | }, |
838 | 15 | { &hf_pana_avp_data_uint32, |
839 | 15 | { "Value", "pana.avp.data.uint32", |
840 | 15 | FT_UINT32, BASE_HEX, NULL, 0x0, |
841 | 15 | NULL, HFILL } |
842 | 15 | }, |
843 | 15 | { &hf_pana_avp_data_int32, |
844 | 15 | { "Value", "pana.avp.data.int32", |
845 | 15 | FT_INT32, BASE_DEC, NULL, 0x0, |
846 | 15 | NULL, HFILL } |
847 | 15 | }, |
848 | 15 | { &hf_pana_avp_data_bytes, |
849 | 15 | { "Value", "pana.avp.data.bytes", |
850 | 15 | FT_BYTES, BASE_NONE, NULL, 0x0, |
851 | 15 | NULL, HFILL } |
852 | 15 | }, |
853 | 15 | { &hf_pana_avp_data_string, |
854 | 15 | { "UTF8String", "pana.avp.data.string", |
855 | 15 | FT_STRING, BASE_NONE, NULL, 0x0, |
856 | 15 | NULL, HFILL } |
857 | 15 | }, |
858 | 15 | { &hf_pana_avp_data_enumerated, |
859 | 15 | { "Value", "pana.avp.data.enum", |
860 | 15 | FT_INT32, BASE_DEC, NULL, 0x0, |
861 | 15 | NULL, HFILL } |
862 | 15 | } |
863 | | |
864 | 15 | }; |
865 | | |
866 | | /* Setup protocol subtree array */ |
867 | 15 | static int *ett[] = { |
868 | 15 | &ett_pana, |
869 | 15 | &ett_pana_flags, |
870 | 15 | &ett_pana_avp, |
871 | 15 | &ett_pana_avp_info, |
872 | 15 | &ett_pana_avp_flags |
873 | 15 | }; |
874 | | |
875 | | /* Register the protocol name and description */ |
876 | 15 | proto_pana = proto_register_protocol("Protocol for carrying Authentication for Network Access", "PANA", "pana"); |
877 | | |
878 | | /* Required function calls to register the header fields and subtrees used */ |
879 | 15 | proto_register_field_array(proto_pana, hf, array_length(hf)); |
880 | 15 | proto_register_subtree_array(ett, array_length(ett)); |
881 | | |
882 | | /* Register the dissector handle */ |
883 | 15 | pana_handle = register_dissector("pana", dissect_pana, proto_pana); |
884 | 15 | } |
885 | | |
886 | | |
887 | | void |
888 | | proto_reg_handoff_pana(void) |
889 | 15 | { |
890 | 15 | heur_dissector_add("udp", dissect_pana_heur, "PANA over UDP", "pana_udp", proto_pana, HEURISTIC_ENABLE); |
891 | | |
892 | 15 | dissector_add_for_decode_as_with_preference("udp.port", pana_handle); |
893 | | |
894 | 15 | eap_handle = find_dissector_add_dependency("eap", proto_pana); |
895 | | |
896 | 15 | } |
897 | | |
898 | | /* |
899 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
900 | | * |
901 | | * Local variables: |
902 | | * c-basic-offset: 8 |
903 | | * tab-width: 8 |
904 | | * indent-tabs-mode: nil |
905 | | * End: |
906 | | * |
907 | | * vi: set shiftwidth=8 tabstop=8 expandtab: |
908 | | * :indentSize=8:tabSize=8:noTabs=true: |
909 | | */ |