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