xref: /netbsd-src/external/bsd/tcpdump/dist/print-radius.c (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
1 /*
2  * Copyright (C) 2000 Alfredo Andres Omella.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   1. Redistributions of source code must retain the above copyright
9  *      notice, this list of conditions and the following disclaimer.
10  *   2. Redistributions in binary form must reproduce the above copyright
11  *      notice, this list of conditions and the following disclaimer in
12  *      the documentation and/or other materials provided with the
13  *      distribution.
14  *   3. The names of the authors may not be used to endorse or promote
15  *      products derived from this software without specific prior
16  *      written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21  */
22 
23 /* \summary: Radius protocol printer */
24 
25 /*
26  * Radius printer routines as specified on:
27  *
28  * RFC 2865:
29  *      "Remote Authentication Dial In User Service (RADIUS)"
30  *
31  * RFC 2866:
32  *      "RADIUS Accounting"
33  *
34  * RFC 2867:
35  *      "RADIUS Accounting Modifications for Tunnel Protocol Support"
36  *
37  * RFC 2868:
38  *      "RADIUS Attributes for Tunnel Protocol Support"
39  *
40  * RFC 2869:
41  *      "RADIUS Extensions"
42  *
43  * RFC 3162:
44  *      "RADIUS and IPv6"
45  *
46  * RFC 3580:
47  *      "IEEE 802.1X Remote Authentication Dial In User Service (RADIUS)"
48  *      "Usage Guidelines"
49  *
50  * RFC 4072:
51  *      "Diameter Extensible Authentication Protocol (EAP) Application"
52  *
53  * RFC 4675:
54  *      "RADIUS Attributes for Virtual LAN and Priority Support"
55  *
56  * RFC 4818:
57  *      "RADIUS Delegated-IPv6-Prefix Attribute"
58  *
59  * RFC 4849:
60  *      "RADIUS Filter Rule Attribute"
61  *
62  * RFC 5090:
63  *      "RADIUS Extension for Digest Authentication"
64  *
65  * RFC 5176:
66  *      "Dynamic Authorization Extensions to RADIUS"
67  *
68  * RFC 5447:
69  *      "Diameter Mobile IPv6"
70  *
71  * RFC 5580:
72  *      "Carrying Location Objects in RADIUS and Diameter"
73  *
74  * RFC 6572:
75  *      "RADIUS Support for Proxy Mobile IPv6"
76  *
77  * RFC 7155:
78  *      "Diameter Network Access Server Application"
79  *
80  * Alfredo Andres Omella (aandres@s21sec.com) v0.1 2000/09/15
81  *
82  * TODO: Among other things to print ok MacIntosh and Vendor values
83  */
84 
85 #include <sys/cdefs.h>
86 #ifndef lint
87 __RCSID("$NetBSD: print-radius.c,v 1.10 2023/08/17 20:19:40 christos Exp $");
88 #endif
89 
90 #ifdef HAVE_CONFIG_H
91 #include <config.h>
92 #endif
93 
94 #include "netdissect-stdinc.h"
95 
96 #include <string.h>
97 
98 #include "netdissect-ctype.h"
99 
100 #include "netdissect.h"
101 #include "addrtoname.h"
102 #include "extract.h"
103 #include "oui.h"
104 #include "ntp.h"
105 
106 
107 #define TAM_SIZE(x) (sizeof(x)/sizeof(x[0]) )
108 
109 #define PRINT_HEX(bytes_len, ptr_data)                               \
110            while(bytes_len)                                          \
111            {                                                         \
112               ND_PRINT("%02X", GET_U_1(ptr_data));                   \
113               ptr_data++;                                            \
114               bytes_len--;                                           \
115            }
116 
117 
118 /* Radius packet codes */
119 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-27 */
120 #define RADCMD_ACCESS_REQ   1 /* Access-Request      */
121 #define RADCMD_ACCESS_ACC   2 /* Access-Accept       */
122 #define RADCMD_ACCESS_REJ   3 /* Access-Reject       */
123 #define RADCMD_ACCOUN_REQ   4 /* Accounting-Request  */
124 #define RADCMD_ACCOUN_RES   5 /* Accounting-Response */
125 #define RADCMD_ACCESS_CHA  11 /* Access-Challenge    */
126 #define RADCMD_STATUS_SER  12 /* Status-Server       */
127 #define RADCMD_STATUS_CLI  13 /* Status-Client       */
128 #define RADCMD_DISCON_REQ  40 /* Disconnect-Request  */
129 #define RADCMD_DISCON_ACK  41 /* Disconnect-ACK      */
130 #define RADCMD_DISCON_NAK  42 /* Disconnect-NAK      */
131 #define RADCMD_COA_REQ     43 /* CoA-Request         */
132 #define RADCMD_COA_ACK     44 /* CoA-ACK             */
133 #define RADCMD_COA_NAK     45 /* CoA-NAK             */
134 #define RADCMD_RESERVED   255 /* Reserved            */
135 
136 static const struct tok radius_command_values[] = {
137     { RADCMD_ACCESS_REQ, "Access-Request" },
138     { RADCMD_ACCESS_ACC, "Access-Accept" },
139     { RADCMD_ACCESS_REJ, "Access-Reject" },
140     { RADCMD_ACCOUN_REQ, "Accounting-Request" },
141     { RADCMD_ACCOUN_RES, "Accounting-Response" },
142     { RADCMD_ACCESS_CHA, "Access-Challenge" },
143     { RADCMD_STATUS_SER, "Status-Server" },
144     { RADCMD_STATUS_CLI, "Status-Client" },
145     { RADCMD_DISCON_REQ, "Disconnect-Request" },
146     { RADCMD_DISCON_ACK, "Disconnect-ACK" },
147     { RADCMD_DISCON_NAK, "Disconnect-NAK" },
148     { RADCMD_COA_REQ,    "CoA-Request" },
149     { RADCMD_COA_ACK,    "CoA-ACK" },
150     { RADCMD_COA_NAK,    "CoA-NAK" },
151     { RADCMD_RESERVED,   "Reserved" },
152     { 0, NULL}
153 };
154 
155 /********************************/
156 /* Begin Radius Attribute types */
157 /********************************/
158 #define SERV_TYPE    6
159 #define FRM_IPADDR   8
160 #define LOG_IPHOST  14
161 #define LOG_SERVICE 15
162 #define FRM_IPX     23
163 #define SESSION_TIMEOUT   27
164 #define IDLE_TIMEOUT      28
165 #define FRM_ATALK_LINK    37
166 #define FRM_ATALK_NETWORK 38
167 
168 #define ACCT_DELAY        41
169 #define ACCT_SESSION_TIME 46
170 
171 #define EGRESS_VLAN_ID   56
172 #define EGRESS_VLAN_NAME 58
173 
174 #define TUNNEL_TYPE        64
175 #define TUNNEL_MEDIUM      65
176 #define TUNNEL_CLIENT_END  66
177 #define TUNNEL_SERVER_END  67
178 #define TUNNEL_PASS        69
179 
180 #define ARAP_PASS          70
181 #define ARAP_FEATURES      71
182 
183 #define EAP_MESSAGE        79
184 
185 #define TUNNEL_PRIV_GROUP  81
186 #define TUNNEL_ASSIGN_ID   82
187 #define TUNNEL_PREFERENCE  83
188 
189 #define ARAP_CHALLENGE_RESP 84
190 #define ACCT_INT_INTERVAL   85
191 
192 #define TUNNEL_CLIENT_AUTH 90
193 #define TUNNEL_SERVER_AUTH 91
194 
195 #define ERROR_CAUSE 101
196 /********************************/
197 /* End Radius Attribute types */
198 /********************************/
199 
200 #define RFC4675_TAGGED   0x31
201 #define RFC4675_UNTAGGED 0x32
202 
203 static const struct tok rfc4675_tagged[] = {
204     { RFC4675_TAGGED,   "Tagged" },
205     { RFC4675_UNTAGGED, "Untagged" },
206     { 0, NULL}
207 };
208 
209 
210 static void print_attr_string(netdissect_options *, const u_char *, u_int, u_short );
211 static void print_attr_num(netdissect_options *, const u_char *, u_int, u_short );
212 static void print_vendor_attr(netdissect_options *, const u_char *, u_int, u_short );
213 static void print_attr_address(netdissect_options *, const u_char *, u_int, u_short);
214 static void print_attr_address6(netdissect_options *, const u_char *, u_int, u_short);
215 static void print_attr_netmask6(netdissect_options *, const u_char *, u_int, u_short);
216 static void print_attr_mip6_home_link_prefix(netdissect_options *, const u_char *, u_int, u_short);
217 static void print_attr_operator_name(netdissect_options *, const u_char *, u_int, u_short);
218 static void print_attr_location_information(netdissect_options *, const u_char *, u_int, u_short);
219 static void print_attr_location_data(netdissect_options *, const u_char *, u_int, u_short);
220 static void print_basic_location_policy_rules(netdissect_options *, const u_char *, u_int, u_short);
221 static void print_attr_time(netdissect_options *, const u_char *, u_int, u_short);
222 static void print_attr_vector64(netdissect_options *, register const u_char *, u_int, u_short);
223 static void print_attr_strange(netdissect_options *, const u_char *, u_int, u_short);
224 
225 
226 struct radius_hdr { nd_uint8_t  code;     /* Radius packet code  */
227                     nd_uint8_t  id;       /* Radius packet id    */
228                     nd_uint16_t len;      /* Radius total length */
229                     nd_byte     auth[16]; /* Authenticator   */
230                   };
231 
232 #define MIN_RADIUS_LEN	20
233 
234 struct radius_attr { nd_uint8_t type; /* Attribute type   */
235                      nd_uint8_t len;  /* Attribute length */
236                    };
237 
238 
239 /* Service-Type Attribute standard values */
240 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-4 */
241 static const char *serv_type[]={ NULL,
242                                 "Login",
243                                 "Framed",
244                                 "Callback Login",
245                                 "Callback Framed",
246                                 "Outbound",
247                                 "Administrative",
248                                 "NAS Prompt",
249                                 "Authenticate Only",
250                                 "Callback NAS Prompt",
251                                 /* ^ [0, 9] ^ */
252                                 "Call Check",
253                                 "Callback Administrative",
254                                 "Voice",
255                                 "Fax",
256                                 "Modem Relay",
257                                 "IAPP-Register",
258                                 "IAPP-AP-Check",
259                                 "Authorize Only",
260                                 "Framed-Management",
261                                 "Additional-Authorization",
262                                 /* ^ [10, 19] ^ */
263                                };
264 
265 /* Framed-Protocol Attribute standard values */
266 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-5 */
267 static const char *frm_proto[]={ NULL,
268                                  "PPP",
269                                  "SLIP",
270                                  "ARAP",
271                                  "Gandalf proprietary",
272                                  "Xylogics IPX/SLIP",
273                                  "X.75 Synchronous",
274                                  "GPRS PDP Context",
275                                };
276 
277 /* Framed-Routing Attribute standard values */
278 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-6 */
279 static const char *frm_routing[]={ "None",
280                                    "Send",
281                                    "Listen",
282                                    "Send&Listen",
283                                  };
284 
285 /* Framed-Compression Attribute standard values */
286 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-7 */
287 static const char *frm_comp[]={ "None",
288                                 "VJ TCP/IP",
289                                 "IPX",
290                                 "Stac-LZS",
291                               };
292 
293 /* Login-Service Attribute standard values */
294 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-8 */
295 static const char *login_serv[]={ "Telnet",
296                                   "Rlogin",
297                                   "TCP Clear",
298                                   "PortMaster(proprietary)",
299                                   "LAT",
300                                   "X.25-PAD",
301                                   "X.25-T3POS",
302                                   "Unassigned",
303                                   "TCP Clear Quiet",
304                                 };
305 
306 
307 /* Termination-Action Attribute standard values */
308 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-9 */
309 static const char *term_action[]={ "Default",
310                                    "RADIUS-Request",
311                                  };
312 
313 /* Ingress-Filters Attribute standard values */
314 static const char *ingress_filters[]={ NULL,
315                                        "Enabled",
316                                        "Disabled",
317                                      };
318 
319 /* NAS-Port-Type Attribute standard values */
320 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-13 */
321 static const char *nas_port_type[]={ "Async",
322                                      "Sync",
323                                      "ISDN Sync",
324                                      "ISDN Async V.120",
325                                      "ISDN Async V.110",
326                                      "Virtual",
327                                      "PIAFS",
328                                      "HDLC Clear Channel",
329                                      "X.25",
330                                      "X.75",
331                                      /* ^ [0, 9] ^ */
332                                      "G.3 Fax",
333                                      "SDSL",
334                                      "ADSL-CAP",
335                                      "ADSL-DMT",
336                                      "ISDN-DSL",
337                                      "Ethernet",
338                                      "xDSL",
339                                      "Cable",
340                                      "Wireless - Other",
341                                      "Wireless - IEEE 802.11",
342                                      /* ^ [10, 19] ^ */
343                                      "Token-Ring",
344                                      "FDDI",
345                                      "Wireless - CDMA200",
346                                      "Wireless - UMTS",
347                                      "Wireless - 1X-EV",
348                                      "IAPP",
349                                      "FTTP",
350                                      "Wireless - IEEE 802.16",
351                                      "Wireless - IEEE 802.20",
352                                      "Wireless - IEEE 802.22",
353                                      /* ^ [20, 29] ^ */
354                                      "PPPoA",
355                                      "PPPoEoA",
356                                      "PPPoEoE",
357                                      "PPPoEoVLAN",
358                                      "PPPoEoQinQ",
359                                      "xPON",
360                                      "Wireless - XGP",
361                                      "WiMAX Pre-Release 8 IWK Function",
362                                      "WIMAX-WIFI-IWK",
363                                      "WIMAX-SFF",
364                                      /* ^ [30, 39] ^ */
365                                      "WIMAX-HA-LMA",
366                                      "WIMAX-DHCP",
367                                      "WIMAX-LBS",
368                                      "WIMAX-WVS",
369                                    };
370 
371 /* Acct-Status-Type Accounting Attribute standard values */
372 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-10 */
373 static const char *acct_status[]={ NULL,
374                                    "Start",
375                                    "Stop",
376                                    "Interim-Update",
377                                    "Unassigned",
378                                    "Unassigned",
379                                    "Unassigned",
380                                    "Accounting-On",
381                                    "Accounting-Off",
382                                    "Tunnel-Start",
383                                      /* ^ [0, 9] ^ */
384                                    "Tunnel-Stop",
385                                    "Tunnel-Reject",
386                                    "Tunnel-Link-Start",
387                                    "Tunnel-Link-Stop",
388                                    "Tunnel-Link-Reject",
389                                    "Failed",
390                                  };
391 
392 /* Acct-Authentic Accounting Attribute standard values */
393 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-11 */
394 static const char *acct_auth[]={ NULL,
395                                  "RADIUS",
396                                  "Local",
397                                  "Remote",
398                                  "Diameter",
399                                };
400 
401 /* Acct-Terminate-Cause Accounting Attribute standard values */
402 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-12 */
403 static const char *acct_term[]={ NULL,
404                                  "User Request",
405                                  "Lost Carrier",
406                                  "Lost Service",
407                                  "Idle Timeout",
408                                  "Session Timeout",
409                                  "Admin Reset",
410                                  "Admin Reboot",
411                                  "Port Error",
412                                  "NAS Error",
413                                  /* ^ [0, 9] ^ */
414                                  "NAS Request",
415                                  "NAS Reboot",
416                                  "Port Unneeded",
417                                  "Port Preempted",
418                                  "Port Suspended",
419                                  "Service Unavailable",
420                                  "Callback",
421                                  "User Error",
422                                  "Host Request",
423                                  "Supplicant Restart",
424                                  /* ^ [10, 19] ^ */
425                                  "Reauthentication Failure",
426                                  "Port Reinitialized",
427                                  "Port Administratively Disabled",
428                                  "Lost Power",
429                                };
430 
431 /* Tunnel-Type Attribute standard values */
432 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-14 */
433 static const char *tunnel_type[]={ NULL,
434                                    "PPTP",
435                                    "L2F",
436                                    "L2TP",
437                                    "ATMP",
438                                    "VTP",
439                                    "AH",
440                                    "IP-IP",
441                                    "MIN-IP-IP",
442                                    "ESP",
443                                    /* ^ [0, 9] ^ */
444                                    "GRE",
445                                    "DVS",
446                                    "IP-in-IP Tunneling",
447                                    "VLAN",
448                                  };
449 
450 /* Tunnel-Medium-Type Attribute standard values */
451 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-15 */
452 static const char *tunnel_medium[]={ NULL,
453                                      "IPv4",
454                                      "IPv6",
455                                      "NSAP",
456                                      "HDLC",
457                                      "BBN 1822",
458                                      "802",
459                                      "E.163",
460                                      "E.164",
461                                      "F.69",
462                                      /* ^ [0, 9] ^ */
463                                      "X.121",
464                                      "IPX",
465                                      "Appletalk",
466                                      "Decnet IV",
467                                      "Banyan Vines",
468                                      "E.164 with NSAP subaddress",
469                                    };
470 
471 /* ARAP-Zone-Access Attribute standard values */
472 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-16 */
473 static const char *arap_zone[]={ NULL,
474                                  "Only access to dfl zone",
475                                  "Use zone filter inc.",
476                                  "Not used",
477                                  "Use zone filter exc.",
478                                };
479 
480 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-17 */
481 static const char *prompt[]={ "No Echo",
482                               "Echo",
483                             };
484 
485 /* Error-Cause standard values */
486 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-18 */
487 #define ERROR_CAUSE_RESIDUAL_CONTEXT_REMOVED 201
488 #define ERROR_CAUSE_INVALID_EAP_PACKET 202
489 #define ERROR_CAUSE_UNSUPPORTED_ATTRIBUTE 401
490 #define ERROR_CAUSE_MISSING_ATTRIBUTE 402
491 #define ERROR_CAUSE_NAS_IDENTIFICATION_MISMATCH 403
492 #define ERROR_CAUSE_INVALID_REQUEST 404
493 #define ERROR_CAUSE_UNSUPPORTED_SERVICE 405
494 #define ERROR_CAUSE_UNSUPPORTED_EXTENSION 406
495 #define ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE 407
496 #define ERROR_CAUSE_ADMINISTRATIVELY_PROHIBITED 501
497 #define ERROR_CAUSE_PROXY_REQUEST_NOT_ROUTABLE 502
498 #define ERROR_CAUSE_SESSION_CONTEXT_NOT_FOUND 503
499 #define ERROR_CAUSE_SESSION_CONTEXT_NOT_REMOVABLE 504
500 #define ERROR_CAUSE_PROXY_PROCESSING_ERROR 505
501 #define ERROR_CAUSE_RESOURCES_UNAVAILABLE 506
502 #define ERROR_CAUSE_REQUEST_INITIATED 507
503 #define ERROR_CAUSE_MULTIPLE_SESSION_SELECTION_UNSUPPORTED 508
504 #define ERROR_CAUSE_LOCATION_INFO_REQUIRED 509
505 static const struct tok errorcausetype[] = {
506                                  { ERROR_CAUSE_RESIDUAL_CONTEXT_REMOVED,               "Residual Session Context Removed" },
507                                  { ERROR_CAUSE_INVALID_EAP_PACKET,                     "Invalid EAP Packet (Ignored)" },
508                                  { ERROR_CAUSE_UNSUPPORTED_ATTRIBUTE,                  "Unsupported Attribute" },
509                                  { ERROR_CAUSE_MISSING_ATTRIBUTE,                      "Missing Attribute" },
510                                  { ERROR_CAUSE_NAS_IDENTIFICATION_MISMATCH,            "NAS Identification Mismatch" },
511                                  { ERROR_CAUSE_INVALID_REQUEST,                        "Invalid Request" },
512                                  { ERROR_CAUSE_UNSUPPORTED_SERVICE,                    "Unsupported Service" },
513                                  { ERROR_CAUSE_UNSUPPORTED_EXTENSION,                  "Unsupported Extension" },
514                                  { ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE,                "Invalid Attribute Value" },
515                                  { ERROR_CAUSE_ADMINISTRATIVELY_PROHIBITED,            "Administratively Prohibited" },
516                                  { ERROR_CAUSE_PROXY_REQUEST_NOT_ROUTABLE,             "Request Not Routable (Proxy)" },
517                                  { ERROR_CAUSE_SESSION_CONTEXT_NOT_FOUND,              "Session Context Not Found" },
518                                  { ERROR_CAUSE_SESSION_CONTEXT_NOT_REMOVABLE,          "Session Context Not Removable" },
519                                  { ERROR_CAUSE_PROXY_PROCESSING_ERROR,                 "Other Proxy Processing Error" },
520                                  { ERROR_CAUSE_RESOURCES_UNAVAILABLE,                  "Resources Unavailable" },
521                                  { ERROR_CAUSE_REQUEST_INITIATED,                      "Request Initiated" },
522                                  { ERROR_CAUSE_MULTIPLE_SESSION_SELECTION_UNSUPPORTED, "Multiple Session Selection Unsupported" },
523                                  { ERROR_CAUSE_LOCATION_INFO_REQUIRED,                 "Location Info Required" },
524 																 { 0, NULL }
525                                };
526 
527 /* MIP6-Feature-Vector standard values */
528 /* https://www.iana.org/assignments/aaa-parameters/aaa-parameters.xhtml */
529 #define MIP6_INTEGRATED 0x0000000000000001
530 #define LOCAL_HOME_AGENT_ASSIGNMENT 0x0000000000000002
531 #define PMIP6_SUPPORTED 0x0000010000000000
532 #define IP4_HOA_SUPPORTED 0x0000020000000000
533 #define LOCAL_MAG_ROUTING_SUPPORTED 0x0000040000000000
534 #define ASSIGN_LOCAL_IP 0x0000080000000000
535 #define MIP4_SUPPORTED 0x0000100000000000
536 #define OPTIMIZED_IDLE_MODE_MOBILITY 0x0000200000000000
537 #define GTPv2_SUPPORTED 0x0000400000000000
538 #define IP4_TRANSPORT_SUPPORTED 0x0000800000000000
539 #define IP4_HOA_ONLY_SUPPORTED 0x0001000000000000
540 #define INTER_MAG_ROUTING_SUPPORTED 0x0002000000000000
541 static const struct mip6_feature_vector {
542                   uint64_t v;
543                   const char *s;
544                 } mip6_feature_vector[] = {
545                                  { MIP6_INTEGRATED,             "MIP6_INTEGRATED" },
546                                  { LOCAL_HOME_AGENT_ASSIGNMENT, "LOCAL_HOME_AGENT_ASSIGNMENT" },
547                                  { PMIP6_SUPPORTED,             "PMIP6_SUPPORTED" },
548                                  { IP4_HOA_SUPPORTED,           "IP4_HOA_SUPPORTED" },
549                                  { LOCAL_MAG_ROUTING_SUPPORTED, "LOCAL_MAG_ROUTING_SUPPORTED" },
550                                  { ASSIGN_LOCAL_IP,             "ASSIGN_LOCAL_IP" },
551                                  { MIP4_SUPPORTED,              "MIP4_SUPPORTED" },
552                                  { OPTIMIZED_IDLE_MODE_MOBILITY, "OPTIMIZED_IDLE_MODE_MOBILITY" },
553                                  { GTPv2_SUPPORTED,             "GTPv2_SUPPORTED" },
554                                  { IP4_TRANSPORT_SUPPORTED,     "IP4_TRANSPORT_SUPPORTED" },
555                                  { IP4_HOA_ONLY_SUPPORTED,      "IP4_HOA_ONLY_SUPPORTED" },
556                                  { INTER_MAG_ROUTING_SUPPORTED, "INTER_MAG_ROUTING_SUPPORTED" },
557                                };
558 
559 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-19 */
560 #define OPERATOR_NAME_TADIG 0x30
561 #define OPERATOR_NAME_REALM 0x31
562 #define OPERATOR_NAME_E212  0x32
563 #define OPERATOR_NAME_ICC   0x33
564 static const struct tok operator_name_vector[] = {
565                                  { OPERATOR_NAME_TADIG, "TADIG" },
566                                  { OPERATOR_NAME_REALM, "REALM" },
567                                  { OPERATOR_NAME_E212,  "E212"  },
568                                  { OPERATOR_NAME_ICC,   "ICC"   },
569                                  { 0, NULL }
570                                };
571 
572 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-20 */
573 #define LOCATION_INFORMATION_CODE_CIVIC      0
574 #define LOCATION_INFORMATION_CODE_GEOSPATIAL 1
575 static const struct tok location_information_code_vector[] = {
576                                  { LOCATION_INFORMATION_CODE_CIVIC     , "Civic"      },
577                                  { LOCATION_INFORMATION_CODE_GEOSPATIAL, "Geospatial" },
578                                  { 0, NULL }
579                                };
580 
581 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-21 */
582 #define LOCATION_INFORMATION_ENTITY_USER   0
583 #define LOCATION_INFORMATION_ENTITY_RADIUS 1
584 static const struct tok location_information_entity_vector[] = {
585                                  { LOCATION_INFORMATION_ENTITY_USER,   "User"   },
586                                  { LOCATION_INFORMATION_ENTITY_RADIUS, "RADIUS" },
587                                  { 0, NULL }
588                                };
589 
590 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-22 */
591 static const struct tok blpr_bm[] = {
592                                  { 0x0001, "MBZ-15" },
593                                  { 0x0002, "MBZ-14" },
594                                  { 0x0004, "MBZ-13" },
595                                  { 0x0008, "MBZ-12" },
596                                  { 0x0010, "MBZ-11" },
597                                  { 0x0020, "MBZ-10" },
598                                  { 0x0040, "MBZ-9" },
599                                  { 0x0080, "MBZ-8" },
600                                  { 0x0100, "MBZ-7" },
601                                  { 0x0200, "MBZ-6" },
602                                  { 0x0400, "MBZ-5" },
603                                  { 0x0800, "MBZ-4" },
604                                  { 0x1000, "MBZ-3" },
605                                  { 0x2000, "MBZ-2" },
606                                  { 0x4000, "MBZ-1" },
607                                  { 0x8000, "Retransmission Allowed" },
608                                  { 0, NULL }
609                                };
610 
611 /* https://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-2 */
612 static const struct attrtype {
613                   const char *name;      /* Attribute name                 */
614                   const char **subtypes; /* Standard Values (if any)       */
615                   u_char siz_subtypes;   /* Size of total standard values  */
616                   u_char first_subtype;  /* First standard value is 0 or 1 */
617                   void (*print_func)(netdissect_options *, const u_char *, u_int, u_short);
618                 } attr_type[]=
619   {
620      { NULL,                              NULL, 0, 0, NULL               },
621      { "User-Name",                       NULL, 0, 0, print_attr_string  },
622      { "User-Password",                   NULL, 0, 0, NULL               },
623      { "CHAP-Password",                   NULL, 0, 0, NULL               },
624      { "NAS-IP-Address",                  NULL, 0, 0, print_attr_address },
625      { "NAS-Port",                        NULL, 0, 0, print_attr_num     },
626      { "Service-Type",                    serv_type, TAM_SIZE(serv_type)-1, 1, print_attr_num },
627      { "Framed-Protocol",                 frm_proto, TAM_SIZE(frm_proto)-1, 1, print_attr_num },
628      { "Framed-IP-Address",               NULL, 0, 0, print_attr_address },
629      { "Framed-IP-Netmask",               NULL, 0, 0, print_attr_address },
630      /* ^ [0, 9] ^ */
631      { "Framed-Routing",                  frm_routing, TAM_SIZE(frm_routing), 0, print_attr_num },
632      { "Filter-Id",                       NULL, 0, 0, print_attr_string  },
633      { "Framed-MTU",                      NULL, 0, 0, print_attr_num     },
634      { "Framed-Compression",              frm_comp, TAM_SIZE(frm_comp),   0, print_attr_num },
635      { "Login-IP-Host",                   NULL, 0, 0, print_attr_address },
636      { "Login-Service",                   login_serv, TAM_SIZE(login_serv), 0, print_attr_num },
637      { "Login-TCP-Port",                  NULL, 0, 0, print_attr_num     },
638      { "Unassigned",                      NULL, 0, 0, NULL }, /*17*/
639      { "Reply-Message",                   NULL, 0, 0, print_attr_string },
640      { "Callback-Number",                 NULL, 0, 0, print_attr_string },
641      /* ^ [10, 19] ^ */
642      { "Callback-Id",                     NULL, 0, 0, print_attr_string },
643      { "Unassigned",                      NULL, 0, 0, NULL }, /*21*/
644      { "Framed-Route",                    NULL, 0, 0, print_attr_string },
645      { "Framed-IPX-Network",              NULL, 0, 0, print_attr_num    },
646      { "State",                           NULL, 0, 0, print_attr_string },
647      { "Class",                           NULL, 0, 0, print_attr_string },
648      { "Vendor-Specific",                 NULL, 0, 0, print_vendor_attr },
649      { "Session-Timeout",                 NULL, 0, 0, print_attr_num    },
650      { "Idle-Timeout",                    NULL, 0, 0, print_attr_num    },
651      { "Termination-Action",              term_action, TAM_SIZE(term_action), 0, print_attr_num },
652      /* ^ [20, 29] ^ */
653      { "Called-Station-Id",               NULL, 0, 0, print_attr_string },
654      { "Calling-Station-Id",              NULL, 0, 0, print_attr_string },
655      { "NAS-Identifier",                  NULL, 0, 0, print_attr_string },
656      { "Proxy-State",                     NULL, 0, 0, print_attr_string },
657      { "Login-LAT-Service",               NULL, 0, 0, print_attr_string },
658      { "Login-LAT-Node",                  NULL, 0, 0, print_attr_string },
659      { "Login-LAT-Group",                 NULL, 0, 0, print_attr_string },
660      { "Framed-AppleTalk-Link",           NULL, 0, 0, print_attr_num    },
661      { "Framed-AppleTalk-Network",        NULL, 0, 0, print_attr_num    },
662      { "Framed-AppleTalk-Zone",           NULL, 0, 0, print_attr_string },
663      /* ^ [30, 39] ^ */
664      { "Acct-Status-Type",                acct_status, TAM_SIZE(acct_status)-1, 1, print_attr_num },
665      { "Acct-Delay-Time",                 NULL, 0, 0, print_attr_num    },
666      { "Acct-Input-Octets",               NULL, 0, 0, print_attr_num    },
667      { "Acct-Output-Octets",              NULL, 0, 0, print_attr_num    },
668      { "Acct-Session-Id",                 NULL, 0, 0, print_attr_string },
669      { "Acct-Authentic",                  acct_auth, TAM_SIZE(acct_auth)-1, 1, print_attr_num },
670      { "Acct-Session-Time",               NULL, 0, 0, print_attr_num },
671      { "Acct-Input-Packets",              NULL, 0, 0, print_attr_num },
672      { "Acct-Output-Packets",             NULL, 0, 0, print_attr_num },
673      { "Acct-Terminate-Cause",            acct_term, TAM_SIZE(acct_term)-1, 1, print_attr_num },
674      /* ^ [40, 49] ^ */
675      { "Acct-Multi-Session-Id",           NULL, 0, 0, print_attr_string },
676      { "Acct-Link-Count",                 NULL, 0, 0, print_attr_num },
677      { "Acct-Input-Gigawords",            NULL, 0, 0, print_attr_num },
678      { "Acct-Output-Gigawords",           NULL, 0, 0, print_attr_num },
679      { "Unassigned",                      NULL, 0, 0, NULL }, /*54*/
680      { "Event-Timestamp",                 NULL, 0, 0, print_attr_time },
681      { "Egress-VLANID",                   NULL, 0, 0, print_attr_num },
682      { "Ingress-Filters",                 ingress_filters, TAM_SIZE(ingress_filters)-1, 1, print_attr_num },
683      { "Egress-VLAN-Name",                NULL, 0, 0, print_attr_string },
684      { "User-Priority-Table",             NULL, 0, 0, NULL },
685      /* ^ [50, 59] ^ */
686      { "CHAP-Challenge",                  NULL, 0, 0, print_attr_string },
687      { "NAS-Port-Type",                   nas_port_type, TAM_SIZE(nas_port_type), 0, print_attr_num },
688      { "Port-Limit",                      NULL, 0, 0, print_attr_num },
689      { "Login-LAT-Port",                  NULL, 0, 0, print_attr_string }, /*63*/
690      { "Tunnel-Type",                     tunnel_type, TAM_SIZE(tunnel_type)-1, 1, print_attr_num },
691      { "Tunnel-Medium-Type",              tunnel_medium, TAM_SIZE(tunnel_medium)-1, 1, print_attr_num },
692      { "Tunnel-Client-Endpoint",          NULL, 0, 0, print_attr_string },
693      { "Tunnel-Server-Endpoint",          NULL, 0, 0, print_attr_string },
694      { "Acct-Tunnel-Connection",          NULL, 0, 0, print_attr_string },
695      { "Tunnel-Password",                 NULL, 0, 0, print_attr_string  },
696      /* ^ [60, 69] ^ */
697      { "ARAP-Password",                   NULL, 0, 0, print_attr_strange },
698      { "ARAP-Features",                   NULL, 0, 0, print_attr_strange },
699      { "ARAP-Zone-Access",                arap_zone, TAM_SIZE(arap_zone)-1, 1, print_attr_num }, /*72*/
700      { "ARAP-Security",                   NULL, 0, 0, print_attr_string },
701      { "ARAP-Security-Data",              NULL, 0, 0, print_attr_string },
702      { "Password-Retry",                  NULL, 0, 0, print_attr_num    },
703      { "Prompt",                          prompt, TAM_SIZE(prompt), 0, print_attr_num },
704      { "Connect-Info",                    NULL, 0, 0, print_attr_string   },
705      { "Configuration-Token",             NULL, 0, 0, print_attr_string   },
706      { "EAP-Message",                     NULL, 0, 0, print_attr_string   },
707      /* ^ [70, 79] ^ */
708      { "Message-Authenticator",           NULL, 0, 0, print_attr_string }, /*80*/
709      { "Tunnel-Private-Group-ID",         NULL, 0, 0, print_attr_string },
710      { "Tunnel-Assignment-ID",            NULL, 0, 0, print_attr_string },
711      { "Tunnel-Preference",               NULL, 0, 0, print_attr_num    },
712      { "ARAP-Challenge-Response",         NULL, 0, 0, print_attr_strange },
713      { "Acct-Interim-Interval",           NULL, 0, 0, print_attr_num     },
714      { "Acct-Tunnel-Packets-Lost",        NULL, 0, 0, print_attr_num }, /*86*/
715      { "NAS-Port-Id",                     NULL, 0, 0, print_attr_string },
716      { "Framed-Pool",                     NULL, 0, 0, print_attr_string },
717      { "CUI",                             NULL, 0, 0, print_attr_string },
718      /* ^ [80, 89] ^ */
719      { "Tunnel-Client-Auth-ID",           NULL, 0, 0, print_attr_string },
720      { "Tunnel-Server-Auth-ID",           NULL, 0, 0, print_attr_string },
721      { "NAS-Filter-Rule",                 NULL, 0, 0, print_attr_string },
722      { "Unassigned",                      NULL, 0, 0, NULL },  /*93*/
723      { "Originating-Line-Info",           NULL, 0, 0, NULL },
724      { "NAS-IPv6-Address",                NULL, 0, 0, print_attr_address6 },
725      { "Framed-Interface-ID",             NULL, 0, 0, NULL },
726      { "Framed-IPv6-Prefix",              NULL, 0, 0, print_attr_netmask6 },
727      { "Login-IPv6-Host",                 NULL, 0, 0, print_attr_address6 },
728      { "Framed-IPv6-Route",               NULL, 0, 0, print_attr_string },
729      /* ^ [90, 99] ^ */
730      { "Framed-IPv6-Pool",                NULL, 0, 0, print_attr_string },
731      { "Error-Cause",                     NULL, 0, 0, print_attr_strange },
732      { "EAP-Key-Name",                    NULL, 0, 0, NULL },
733      { "Digest-Response",                 NULL, 0, 0, print_attr_string },
734      { "Digest-Realm",                    NULL, 0, 0, print_attr_string },
735      { "Digest-Nonce",                    NULL, 0, 0, print_attr_string },
736      { "Digest-Response-Auth",            NULL, 0, 0, print_attr_string },
737      { "Digest-Nextnonce",                NULL, 0, 0, print_attr_string },
738      { "Digest-Method",                   NULL, 0, 0, print_attr_string },
739      { "Digest-URI",                      NULL, 0, 0, print_attr_string },
740      /* ^ [100, 109] ^ */
741      { "Digest-Qop",                      NULL, 0, 0, print_attr_string },
742      { "Digest-Algorithm",                NULL, 0, 0, print_attr_string },
743      { "Digest-Entity-Body-Hash",         NULL, 0, 0, print_attr_string },
744      { "Digest-CNonce",                   NULL, 0, 0, print_attr_string },
745      { "Digest-Nonce-Count",              NULL, 0, 0, print_attr_string },
746      { "Digest-Username",                 NULL, 0, 0, print_attr_string },
747      { "Digest-Opaque",                   NULL, 0, 0, print_attr_string },
748      { "Digest-Auth-Param",               NULL, 0, 0, print_attr_string },
749      { "Digest-AKA-Auts",                 NULL, 0, 0, print_attr_string },
750      { "Digest-Domain",                   NULL, 0, 0, print_attr_string },
751      /* ^ [110, 119] ^ */
752      { "Digest-Stale",                    NULL, 0, 0, print_attr_string },
753      { "Digest-HA1",                      NULL, 0, 0, print_attr_string },
754      { "SIP-AOR",                         NULL, 0, 0, print_attr_string },
755      { "Delegated-IPv6-Prefix",           NULL, 0, 0, print_attr_netmask6 },
756      { "MIP6-Feature-Vector",             NULL, 0, 0, print_attr_vector64 },
757      { "MIP6-Home-Link-Prefix",           NULL, 0, 0, print_attr_mip6_home_link_prefix },
758      { "Operator-Name",                   NULL, 0, 0, print_attr_operator_name },
759      { "Location-Information",            NULL, 0, 0, print_attr_location_information },
760      { "Location-Data",                   NULL, 0, 0, print_attr_location_data },
761      { "Basic-Location-Policy-Rules",     NULL, 0, 0, print_basic_location_policy_rules }
762      /* ^ [120, 129] ^ */
763   };
764 
765 
766 /*****************************/
767 /* Print an attribute string */
768 /* value pointed by 'data'   */
769 /* and 'length' size.        */
770 /*****************************/
771 /* Returns nothing.          */
772 /*****************************/
773 static void
774 print_attr_string(netdissect_options *ndo,
775                   const u_char *data, u_int length, u_short attr_code)
776 {
777    u_int i;
778 
779    ND_TCHECK_LEN(data, length);
780 
781    switch(attr_code)
782    {
783       case TUNNEL_PASS:
784            if (length < 3)
785               goto trunc;
786            if (GET_U_1(data) && (GET_U_1(data) <= 0x1F))
787               ND_PRINT("Tag[%u] ", GET_U_1(data));
788            else
789               ND_PRINT("Tag[Unused] ");
790            data++;
791            length--;
792            ND_PRINT("Salt %u ", GET_BE_U_2(data));
793            data+=2;
794            length-=2;
795         break;
796       case TUNNEL_CLIENT_END:
797       case TUNNEL_SERVER_END:
798       case TUNNEL_PRIV_GROUP:
799       case TUNNEL_ASSIGN_ID:
800       case TUNNEL_CLIENT_AUTH:
801       case TUNNEL_SERVER_AUTH:
802            if (GET_U_1(data) <= 0x1F)
803            {
804               if (length < 1)
805                  goto trunc;
806               if (GET_U_1(data))
807                 ND_PRINT("Tag[%u] ", GET_U_1(data));
808               else
809                 ND_PRINT("Tag[Unused] ");
810               data++;
811               length--;
812            }
813         break;
814       case EGRESS_VLAN_NAME:
815            if (length < 1)
816               goto trunc;
817            ND_PRINT("%s (0x%02x) ",
818                   tok2str(rfc4675_tagged,"Unknown tag",GET_U_1(data)),
819                   GET_U_1(data));
820            data++;
821            length--;
822         break;
823       case EAP_MESSAGE:
824            if (length < 1)
825               goto trunc;
826            eap_print(ndo, data, length);
827            return;
828    }
829 
830    for (i=0; i < length && GET_U_1(data); i++, data++)
831        ND_PRINT("%c", ND_ASCII_ISPRINT(GET_U_1(data)) ? GET_U_1(data) : '.');
832 
833    return;
834 
835    trunc:
836       nd_print_trunc(ndo);
837 }
838 
839 /*
840  * print vendor specific attributes
841  */
842 static void
843 print_vendor_attr(netdissect_options *ndo,
844                   const u_char *data, u_int length, u_short attr_code _U_)
845 {
846     u_int idx;
847     u_int vendor_id;
848     u_int vendor_type;
849     u_int vendor_length;
850 
851     if (length < 4)
852         goto trunc;
853     vendor_id = GET_BE_U_4(data);
854     data+=4;
855     length-=4;
856 
857     ND_PRINT("Vendor: %s (%u)",
858            tok2str(smi_values,"Unknown",vendor_id),
859            vendor_id);
860 
861     while (length >= 2) {
862         vendor_type = GET_U_1(data);
863         vendor_length = GET_U_1(data + 1);
864 
865         if (vendor_length < 2)
866         {
867             ND_PRINT("\n\t    Vendor Attribute: %u, Length: %u (bogus, must be >= 2)",
868                    vendor_type,
869                    vendor_length);
870             return;
871         }
872         if (vendor_length > length)
873         {
874             ND_PRINT("\n\t    Vendor Attribute: %u, Length: %u (bogus, goes past end of vendor-specific attribute)",
875                    vendor_type,
876                    vendor_length);
877             return;
878         }
879         data+=2;
880         vendor_length-=2;
881         length-=2;
882 	ND_TCHECK_LEN(data, vendor_length);
883 
884         ND_PRINT("\n\t    Vendor Attribute: %u, Length: %u, Value: ",
885                vendor_type,
886                vendor_length);
887         for (idx = 0; idx < vendor_length ; idx++, data++)
888             ND_PRINT("%c", ND_ASCII_ISPRINT(GET_U_1(data)) ? GET_U_1(data) : '.');
889         length-=vendor_length;
890     }
891     return;
892 
893    trunc:
894      nd_print_trunc(ndo);
895 }
896 
897 /******************************/
898 /* Print an attribute numeric */
899 /* value pointed by 'data'    */
900 /* and 'length' size.         */
901 /******************************/
902 /* Returns nothing.           */
903 /******************************/
904 static void
905 print_attr_num(netdissect_options *ndo,
906                const u_char *data, u_int length, u_short attr_code)
907 {
908    uint32_t timeout;
909 
910    if (length != 4)
911    {
912        ND_PRINT("ERROR: length %u != 4", length);
913        return;
914    }
915 
916                           /* This attribute has standard values */
917    if (attr_type[attr_code].siz_subtypes)
918    {
919       static const char **table;
920       uint32_t data_value;
921       table = attr_type[attr_code].subtypes;
922 
923       if ( (attr_code == TUNNEL_TYPE) || (attr_code == TUNNEL_MEDIUM) )
924       {
925          if (!GET_U_1(data))
926             ND_PRINT("Tag[Unused] ");
927          else
928             ND_PRINT("Tag[%u] ", GET_U_1(data));
929          data++;
930          data_value = GET_BE_U_3(data);
931       }
932       else
933       {
934          data_value = GET_BE_U_4(data);
935       }
936       if ( data_value <= (uint32_t)(attr_type[attr_code].siz_subtypes - 1 +
937             attr_type[attr_code].first_subtype) &&
938 	   data_value >= attr_type[attr_code].first_subtype )
939          ND_PRINT("%s", table[data_value]);
940       else
941          ND_PRINT("#%u", data_value);
942    }
943    else
944    {
945       switch(attr_code) /* Be aware of special cases... */
946       {
947         case FRM_IPX:
948              if (GET_BE_U_4(data) == 0xFFFFFFFE )
949                 ND_PRINT("NAS Select");
950              else
951                 ND_PRINT("%u", GET_BE_U_4(data));
952           break;
953 
954         case SESSION_TIMEOUT:
955         case IDLE_TIMEOUT:
956         case ACCT_DELAY:
957         case ACCT_SESSION_TIME:
958         case ACCT_INT_INTERVAL:
959              timeout = GET_BE_U_4(data);
960              if ( timeout < 60 )
961                 ND_PRINT("%02d secs", timeout);
962              else
963              {
964                 if ( timeout < 3600 )
965                    ND_PRINT("%02d:%02d min",
966                           timeout / 60, timeout % 60);
967                 else
968                    ND_PRINT("%02d:%02d:%02d hours",
969                           timeout / 3600, (timeout % 3600) / 60,
970                           timeout % 60);
971              }
972           break;
973 
974         case FRM_ATALK_LINK:
975              if (GET_BE_U_4(data))
976                 ND_PRINT("%u", GET_BE_U_4(data));
977              else
978                 ND_PRINT("Unnumbered");
979           break;
980 
981         case FRM_ATALK_NETWORK:
982              if (GET_BE_U_4(data))
983                 ND_PRINT("%u", GET_BE_U_4(data));
984              else
985                 ND_PRINT("NAS assigned");
986           break;
987 
988         case TUNNEL_PREFERENCE:
989             if (GET_U_1(data))
990                ND_PRINT("Tag[%u] ", GET_U_1(data));
991             else
992                ND_PRINT("Tag[Unused] ");
993             data++;
994             ND_PRINT("%u", GET_BE_U_3(data));
995           break;
996 
997         case EGRESS_VLAN_ID:
998             ND_PRINT("%s (0x%02x) ",
999                    tok2str(rfc4675_tagged,"Unknown tag",GET_U_1(data)),
1000                    GET_U_1(data));
1001             data++;
1002             ND_PRINT("%u", GET_BE_U_3(data));
1003           break;
1004 
1005         default:
1006              ND_PRINT("%u", GET_BE_U_4(data));
1007           break;
1008 
1009       } /* switch */
1010 
1011    } /* if-else */
1012 }
1013 
1014 /*****************************/
1015 /* Print an attribute IPv4   */
1016 /* address value pointed by  */
1017 /* 'data' and 'length' size. */
1018 /*****************************/
1019 /* Returns nothing.          */
1020 /*****************************/
1021 static void
1022 print_attr_address(netdissect_options *ndo,
1023                    const u_char *data, u_int length, u_short attr_code)
1024 {
1025    if (length != 4)
1026    {
1027        ND_PRINT("ERROR: length %u != 4", length);
1028        return;
1029    }
1030 
1031    switch(attr_code)
1032    {
1033       case FRM_IPADDR:
1034       case LOG_IPHOST:
1035            if (GET_BE_U_4(data) == 0xFFFFFFFF )
1036               ND_PRINT("User Selected");
1037            else
1038               if (GET_BE_U_4(data) == 0xFFFFFFFE )
1039                  ND_PRINT("NAS Select");
1040               else
1041                  ND_PRINT("%s",GET_IPADDR_STRING(data));
1042       break;
1043 
1044       default:
1045           ND_PRINT("%s", GET_IPADDR_STRING(data));
1046       break;
1047    }
1048 }
1049 
1050 /*****************************/
1051 /* Print an attribute IPv6   */
1052 /* address value pointed by  */
1053 /* 'data' and 'length' size. */
1054 /*****************************/
1055 /* Returns nothing.          */
1056 /*****************************/
1057 static void
1058 print_attr_address6(netdissect_options *ndo,
1059                    const u_char *data, u_int length, u_short attr_code _U_)
1060 {
1061    if (length != 16)
1062    {
1063        ND_PRINT("ERROR: length %u != 16", length);
1064        return;
1065    }
1066 
1067    ND_PRINT("%s", GET_IP6ADDR_STRING(data));
1068 }
1069 
1070 static void
1071 print_attr_netmask6(netdissect_options *ndo,
1072                     const u_char *data, u_int length, u_short attr_code _U_)
1073 {
1074    u_char data2[16];
1075 
1076    if (length < 2 || length > 18)
1077    {
1078        ND_PRINT("ERROR: length %u not in range (2..18)", length);
1079        return;
1080    }
1081    ND_TCHECK_LEN(data, length);
1082    if (GET_U_1(data + 1) > 128)
1083    {
1084       ND_PRINT("ERROR: netmask %u not in range (0..128)", GET_U_1(data + 1));
1085       return;
1086    }
1087 
1088    memset(data2, 0, sizeof(data2));
1089    if (length > 2)
1090       memcpy(data2, data+2, length-2);
1091 
1092    ND_PRINT("%s/%u", ip6addr_string(ndo, data2), GET_U_1(data + 1)); /* local buffer, not packet data; don't use GET_IP6ADDR_STRING() */
1093 
1094    if (GET_U_1(data + 1) > 8 * (length - 2))
1095       ND_PRINT(" (inconsistent prefix length)");
1096 
1097    return;
1098 
1099    trunc:
1100      nd_print_trunc(ndo);
1101 }
1102 
1103 static void
1104 print_attr_mip6_home_link_prefix(netdissect_options *ndo,
1105                     const u_char *data, u_int length, u_short attr_code _U_)
1106 {
1107    if (length != 17)
1108    {
1109       ND_PRINT("ERROR: length %u != 17", length);
1110       return;
1111    }
1112    ND_TCHECK_LEN(data, length);
1113    if (GET_U_1(data) > 128)
1114    {
1115       ND_PRINT("ERROR: netmask %u not in range (0..128)", GET_U_1(data));
1116       return;
1117    }
1118 
1119    ND_PRINT("%s/%u", GET_IP6ADDR_STRING(data + 1), GET_U_1(data));
1120 
1121    return;
1122 
1123    trunc:
1124      nd_print_trunc(ndo);
1125 }
1126 
1127 static void
1128 print_attr_operator_name(netdissect_options *ndo,
1129                     const u_char *data, u_int length, u_short attr_code _U_)
1130 {
1131    u_int namespace_value;
1132 
1133    ND_TCHECK_LEN(data, length);
1134    if (length < 2)
1135    {
1136       ND_PRINT("ERROR: length %u < 2", length);
1137       return;
1138    }
1139    namespace_value = GET_U_1(data);
1140    data++;
1141    ND_PRINT("[%s] ", tok2str(operator_name_vector, "unknown namespace %u", namespace_value));
1142 
1143    (void)nd_printn(ndo, data, length - 1, NULL);
1144 
1145    return;
1146 
1147    trunc:
1148       nd_print_trunc(ndo);
1149 }
1150 
1151 static void
1152 print_attr_location_information(netdissect_options *ndo,
1153                     const u_char *data, u_int length, u_short attr_code _U_)
1154 {
1155    uint16_t index;
1156    uint8_t code, entity;
1157 
1158    ND_TCHECK_LEN(data, length);
1159    if (length < 21)
1160    {
1161      ND_PRINT("ERROR: length %u < 21", length);
1162       return;
1163    }
1164 
1165    index = GET_BE_U_2(data);
1166    data += 2;
1167 
1168    code = GET_U_1(data);
1169    data++;
1170 
1171    entity = GET_U_1(data);
1172    data++;
1173 
1174    ND_PRINT("index %u, code %s, entity %s, ",
1175        index,
1176        tok2str(location_information_code_vector, "Unknown (%u)", code),
1177        tok2str(location_information_entity_vector, "Unknown (%u)", entity)
1178    );
1179 
1180    ND_PRINT("sighting time ");
1181    p_ntp_time(ndo, (const struct l_fixedpt *)data);
1182    ND_PRINT(", ");
1183    data += 8;
1184 
1185    ND_PRINT("time to live ");
1186    p_ntp_time(ndo, (const struct l_fixedpt *)data);
1187    ND_PRINT(", ");
1188    data += 8;
1189 
1190    ND_PRINT("method \"");
1191    (void)nd_printn(ndo, data, length - 20, NULL);
1192    ND_PRINT("\"");
1193 
1194    return;
1195 
1196    trunc:
1197       nd_print_trunc(ndo);
1198 }
1199 
1200 static void
1201 print_attr_location_data(netdissect_options *ndo,
1202                     const u_char *data, u_int length, u_short attr_code _U_)
1203 {
1204    uint16_t index;
1205 
1206    ND_TCHECK_LEN(data, length);
1207    if (length < 3)
1208    {
1209      ND_PRINT("ERROR: length %u < 3", length);
1210       return;
1211    }
1212 
1213    index = GET_BE_U_2(data);
1214    data += 2;
1215    ND_PRINT("index %u, location", index);
1216 
1217    /* The Location field of the String field of the Location-Data attribute
1218     * can have two completely different structures depending on the value of
1219     * the Code field of a Location-Info attribute, which supposedly precedes
1220     * the current attribute. Unfortunately, this choice of encoding makes it
1221     * non-trivial to decode the Location field without preserving some state
1222     * between the attributes.
1223     */
1224    hex_and_ascii_print(ndo, "\n\t    ", data, length - 2);
1225 
1226    return;
1227 
1228    trunc:
1229       nd_print_trunc(ndo);
1230 }
1231 
1232 static void
1233 print_basic_location_policy_rules(netdissect_options *ndo,
1234                     const u_char *data, u_int length, u_short attr_code _U_)
1235 {
1236    uint16_t flags;
1237 
1238    ND_TCHECK_LEN(data, length);
1239    if (length < 10)
1240    {
1241      ND_PRINT("ERROR: length %u < 10", length);
1242       return;
1243    }
1244 
1245    flags = GET_BE_U_2(data);
1246    data += 2;
1247    ND_PRINT("flags [%s], ", bittok2str(blpr_bm, "none", flags));
1248 
1249    ND_PRINT("retention expires ");
1250    p_ntp_time(ndo, (const struct l_fixedpt *)data);
1251    data += 8;
1252 
1253    if (length > 10) {
1254       ND_PRINT(", note well \"");
1255       (void)nd_printn(ndo, data, length - 10, NULL);
1256       ND_PRINT("\"");
1257    }
1258 
1259    return;
1260 
1261    trunc:
1262       nd_print_trunc(ndo);
1263 }
1264 
1265 
1266 /*************************************/
1267 /* Print an attribute of 'secs since */
1268 /* January 1, 1970 00:00 UTC' value  */
1269 /* pointed by 'data' and 'length'    */
1270 /* size.                             */
1271 /*************************************/
1272 /* Returns nothing.                  */
1273 /*************************************/
1274 static void
1275 print_attr_time(netdissect_options *ndo,
1276                 const u_char *data, u_int length, u_short attr_code _U_)
1277 {
1278    time_t attr_time;
1279    char string[26];
1280 
1281    if (length != 4)
1282    {
1283        ND_PRINT("ERROR: length %u != 4", length);
1284        return;
1285    }
1286 
1287    attr_time = GET_BE_U_4(data);
1288    strlcpy(string, ctime(&attr_time), sizeof(string));
1289    /* Get rid of the newline */
1290    string[24] = '\0';
1291    ND_PRINT("%.24s", string);
1292 }
1293 
1294 static void
1295 print_attr_vector64(netdissect_options *ndo,
1296                  register const u_char *data, u_int length, u_short attr_code _U_)
1297 {
1298    uint64_t data_value, i;
1299    const char *sep = "";
1300 
1301    if (length != 8)
1302    {
1303        ND_PRINT("ERROR: length %u != 8", length);
1304        return;
1305    }
1306 
1307    ND_PRINT("[");
1308 
1309    data_value = GET_BE_U_8(data);
1310    /* Print the 64-bit field in a format similar to bittok2str(), less
1311     * flagging any unknown bits. This way it should be easier to replace
1312     * the custom code with a library function later.
1313     */
1314    for (i = 0; i < TAM_SIZE(mip6_feature_vector); i++) {
1315        if (data_value & mip6_feature_vector[i].v) {
1316            ND_PRINT("%s%s", sep, mip6_feature_vector[i].s);
1317            sep = ", ";
1318        }
1319    }
1320 
1321    ND_PRINT("]");
1322 }
1323 
1324 /***********************************/
1325 /* Print an attribute of 'strange' */
1326 /* data format pointed by 'data'   */
1327 /* and 'length' size.              */
1328 /***********************************/
1329 /* Returns nothing.                */
1330 /***********************************/
1331 static void
1332 print_attr_strange(netdissect_options *ndo,
1333                    const u_char *data, u_int length, u_short attr_code)
1334 {
1335    u_short len_data;
1336    u_int error_cause_value;
1337 
1338    switch(attr_code)
1339    {
1340       case ARAP_PASS:
1341            if (length != 16)
1342            {
1343                ND_PRINT("ERROR: length %u != 16", length);
1344                return;
1345            }
1346            ND_PRINT("User_challenge (");
1347            len_data = 8;
1348            PRINT_HEX(len_data, data);
1349            ND_PRINT(") User_resp(");
1350            len_data = 8;
1351            PRINT_HEX(len_data, data);
1352            ND_PRINT(")");
1353         break;
1354 
1355       case ARAP_FEATURES:
1356            if (length != 14)
1357            {
1358                ND_PRINT("ERROR: length %u != 14", length);
1359                return;
1360            }
1361            if (GET_U_1(data))
1362               ND_PRINT("User can change password");
1363            else
1364               ND_PRINT("User cannot change password");
1365            data++;
1366            ND_PRINT(", Min password length: %u", GET_U_1(data));
1367            data++;
1368            ND_PRINT(", created at: ");
1369            len_data = 4;
1370            PRINT_HEX(len_data, data);
1371            ND_PRINT(", expires in: ");
1372            len_data = 4;
1373            PRINT_HEX(len_data, data);
1374            ND_PRINT(", Current Time: ");
1375            len_data = 4;
1376            PRINT_HEX(len_data, data);
1377         break;
1378 
1379       case ARAP_CHALLENGE_RESP:
1380            if (length < 8)
1381            {
1382                ND_PRINT("ERROR: length %u != 8", length);
1383                return;
1384            }
1385            len_data = 8;
1386            PRINT_HEX(len_data, data);
1387         break;
1388 
1389       case ERROR_CAUSE:
1390            if (length != 4)
1391            {
1392                ND_PRINT("Error: length %u != 4", length);
1393                return;
1394            }
1395 
1396            error_cause_value = GET_BE_U_4(data);
1397            ND_PRINT("Error cause %u: %s", error_cause_value, tok2str(errorcausetype, "Error-Cause %u not known", error_cause_value));
1398         break;
1399    }
1400    return;
1401 }
1402 
1403 static void
1404 radius_attrs_print(netdissect_options *ndo,
1405                    const u_char *attr, u_int length)
1406 {
1407    const struct radius_attr *rad_attr = (const struct radius_attr *)attr;
1408    const char *attr_string;
1409    uint8_t type, len;
1410 
1411    while (length > 0)
1412    {
1413      if (length < 2)
1414         goto trunc;
1415      ND_TCHECK_SIZE(rad_attr);
1416 
1417      type = GET_U_1(rad_attr->type);
1418      len = GET_U_1(rad_attr->len);
1419      if (type != 0 && type < TAM_SIZE(attr_type))
1420 	attr_string = attr_type[type].name;
1421      else
1422 	attr_string = "Unknown";
1423 
1424      ND_PRINT("\n\t  %s Attribute (%u), length: %u",
1425                attr_string,
1426                type,
1427                len);
1428      if (len < 2)
1429      {
1430        ND_PRINT(" (bogus, must be >= 2)");
1431        return;
1432      }
1433      if (len > length)
1434      {
1435         ND_PRINT(" (bogus, goes past end of packet)");
1436         return;
1437      }
1438      ND_PRINT(", Value: ");
1439 
1440      if (type < TAM_SIZE(attr_type))
1441      {
1442          if (len > 2)
1443          {
1444              if ( attr_type[type].print_func )
1445                  (*attr_type[type].print_func)(
1446                      ndo, ((const u_char *)(rad_attr+1)),
1447                      len - 2, type);
1448          }
1449      }
1450      /* do we also want to see a hex dump ? */
1451      if (ndo->ndo_vflag> 1)
1452          print_unknown_data(ndo, (const u_char *)rad_attr+2, "\n\t    ", (len)-2);
1453 
1454      length-=(len);
1455      rad_attr = (const struct radius_attr *)( ((const char *)(rad_attr))+len);
1456    }
1457    return;
1458 
1459 trunc:
1460    nd_print_trunc(ndo);
1461 }
1462 
1463 void
1464 radius_print(netdissect_options *ndo,
1465              const u_char *dat, u_int length)
1466 {
1467    const struct radius_hdr *rad;
1468    u_int len, auth_idx;
1469 
1470    ndo->ndo_protocol = "radius";
1471    ND_TCHECK_LEN(dat, MIN_RADIUS_LEN);
1472    rad = (const struct radius_hdr *)dat;
1473    len = GET_BE_U_2(rad->len);
1474 
1475    if (len < MIN_RADIUS_LEN)
1476    {
1477 	  nd_print_trunc(ndo);
1478 	  return;
1479    }
1480 
1481    if (len > length)
1482 	  len = length;
1483 
1484    if (ndo->ndo_vflag < 1) {
1485        ND_PRINT("RADIUS, %s (%u), id: 0x%02x length: %u",
1486               tok2str(radius_command_values,"Unknown Command",GET_U_1(rad->code)),
1487               GET_U_1(rad->code),
1488               GET_U_1(rad->id),
1489               len);
1490        return;
1491    }
1492    else {
1493        ND_PRINT("RADIUS, length: %u\n\t%s (%u), id: 0x%02x, Authenticator: ",
1494               len,
1495               tok2str(radius_command_values,"Unknown Command",GET_U_1(rad->code)),
1496               GET_U_1(rad->code),
1497               GET_U_1(rad->id));
1498 
1499        for(auth_idx=0; auth_idx < 16; auth_idx++)
1500             ND_PRINT("%02x", rad->auth[auth_idx]);
1501    }
1502 
1503    if (len > MIN_RADIUS_LEN)
1504       radius_attrs_print(ndo, dat + MIN_RADIUS_LEN, len - MIN_RADIUS_LEN);
1505    return;
1506 
1507 trunc:
1508    nd_print_trunc(ndo);
1509 }
1510