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
136static 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
203static const struct tok rfc4675_tagged[] = {
204    { RFC4675_TAGGED,   "Tagged" },
205    { RFC4675_UNTAGGED, "Untagged" },
206    { 0, NULL}
207};
208
209
210static void print_attr_string(netdissect_options *, const u_char *, u_int, u_short );
211static void print_attr_num(netdissect_options *, const u_char *, u_int, u_short );
212static void print_vendor_attr(netdissect_options *, const u_char *, u_int, u_short );
213static void print_attr_address(netdissect_options *, const u_char *, u_int, u_short);
214static void print_attr_address6(netdissect_options *, const u_char *, u_int, u_short);
215static void print_attr_netmask6(netdissect_options *, const u_char *, u_int, u_short);
216static void print_attr_mip6_home_link_prefix(netdissect_options *, const u_char *, u_int, u_short);
217static void print_attr_operator_name(netdissect_options *, const u_char *, u_int, u_short);
218static void print_attr_location_information(netdissect_options *, const u_char *, u_int, u_short);
219static void print_attr_location_data(netdissect_options *, const u_char *, u_int, u_short);
220static void print_basic_location_policy_rules(netdissect_options *, const u_char *, u_int, u_short);
221static void print_attr_time(netdissect_options *, const u_char *, u_int, u_short);
222static void print_attr_vector64(netdissect_options *, register const u_char *, u_int, u_short);
223static void print_attr_strange(netdissect_options *, const u_char *, u_int, u_short);
224
225
226struct 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
234struct 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 */
241static 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 */
267static 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 */
279static 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 */
287static 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 */
295static 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 */
309static const char *term_action[]={ "Default",
310                                   "RADIUS-Request",
311                                 };
312
313/* Ingress-Filters Attribute standard values */
314static 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 */
321static 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 */
373static 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 */
394static 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 */
403static 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 */
433static 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 */
452static 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 */
473static 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 */
481static 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
505static 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
541static 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
564static 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
575static 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
584static 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 */
591static 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 */
612static 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/*****************************/
773static void
774print_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 */
842static void
843print_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/******************************/
904static void
905print_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/*****************************/
1021static void
1022print_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/*****************************/
1057static void
1058print_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
1070static void
1071print_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
1103static void
1104print_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
1127static void
1128print_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
1151static void
1152print_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
1200static void
1201print_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
1232static void
1233print_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/*************************************/
1274static void
1275print_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
1294static void
1295print_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/***********************************/
1331static void
1332print_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
1403static void
1404radius_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
1459trunc:
1460   nd_print_trunc(ndo);
1461}
1462
1463void
1464radius_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
1507trunc:
1508   nd_print_trunc(ndo);
1509}
1510