4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/sysmacros.h>
35 #include <netinet/in.h>
36 #include <netinet/dhcp.h>
37 #include <arpa/inet.h>
38 #include <dhcp_inittab.h>
39 #include <dhcp_symbol.h>
42 static const char *show_msgtype(unsigned char);
43 static int show_options(unsigned char *, int);
44 static void display_ip(int, char *, char *, unsigned char **);
45 static void display_ascii(char *, char *, unsigned char **);
46 static void display_number(char *, char *, unsigned char **);
47 static void display_ascii_hex(char *, unsigned char **);
48 static unsigned char bootmagic
[] = BOOTMAGIC
; /* rfc 1048 */
50 static char *option_types
[] = {
52 "Subnet Mask", /* 1 */
53 "UTC Time Offset", /* 2 */
55 "RFC868 Time Servers", /* 4 */
56 "IEN 116 Name Servers", /* 5 */
57 "DNS Servers", /* 6 */
58 "UDP LOG Servers", /* 7 */
59 "RFC 865 Cookie Servers", /* 8 */
60 "RFC 1179 Line Printer Servers (LPR)", /* 9 */
61 "Impress Servers", /* 10 */
62 "RFC 887 Resource Location Servers", /* 11 */
63 "Client Hostname", /* 12 */
64 "Boot File size in 512 byte Blocks", /* 13 */
65 "Merit Dump File", /* 14 */
66 "DNS Domain Name", /* 15 */
67 "SWAP Server", /* 16 */
68 "Client Root Path", /* 17 */
69 "BOOTP options extensions path", /* 18 */
70 "IP Forwarding Flag", /* 19 */
71 "NonLocal Source Routing Flag", /* 20 */
72 "Policy Filters for NonLocal Routing", /* 21 */
73 "Maximum Datagram Reassembly Size", /* 22 */
74 "Default IP Time To Live", /* 23 */
75 "Path MTU Aging Timeout", /* 24 */
76 "Path MTU Size Plateau Table", /* 25 */
77 "Interface MTU Size", /* 26 */
78 "All Subnets are Local Flag", /* 27 */
79 "Broadcast Address", /* 28 */
80 "Perform Mask Discovery Flag", /* 29 */
81 "Mask Supplier Flag", /* 30 */
82 "Perform Router Discovery Flag", /* 31 */
83 "Router Solicitation Address", /* 32 */
84 "Static Routes", /* 33 */
85 "Trailer Encapsulation Flag", /* 34 */
86 "ARP Cache Timeout Seconds", /* 35 */
87 "Ethernet Encapsulation Flag", /* 36 */
88 "TCP Default Time To Live", /* 37 */
89 "TCP Keepalive Interval Seconds", /* 38 */
90 "TCP Keepalive Garbage Flag", /* 39 */
91 "NIS Domainname", /* 40 */
92 "NIS Servers", /* 41 */
93 "Network Time Protocol Servers", /* 42 */
94 "Vendor Specific Options", /* 43 */
95 "NetBIOS RFC 1001/1002 Name Servers", /* 44 */
96 "NetBIOS Datagram Dist. Servers", /* 45 */
97 "NetBIOS Node Type", /* 46 */
98 "NetBIOS Scope", /* 47 */
99 "X Window Font Servers", /* 48 */
100 "X Window Display Manager Servers", /* 49 */
101 "Requested IP Address", /* 50 */
102 "IP Address Lease Time", /* 51 */
103 "Option Field Overload Flag", /* 52 */
104 "DHCP Message Type", /* 53 */
105 "DHCP Server Identifier", /* 54 */
106 "Option Request List", /* 55 */
107 "Error Message", /* 56 */
108 "Maximum DHCP Message Size", /* 57 */
109 "Renewal (T1) Time Value", /* 58 */
110 "Rebinding (T2) Time Value", /* 59 */
111 "Client Class Identifier =", /* 60 */
112 "Client Identifier =", /* 61 */
113 "Netware IP Domain =", /* 62 */
114 "Netware IP Options =", /* 63 */
115 "NIS+ v3 Client Domain Name =", /* 64 */
116 "NIS+ v3 Server Addresses =", /* 65 */
117 "TFTP Server Name", /* 66 */
118 "Option BootFile Name", /* 67 */
119 "Mobile IP Agents", /* 68 */
120 "Simple Mail (SMTP) Servers", /* 69 */
121 "Post Office (POP3) Servers", /* 70 */
122 "Net News (NNTP) Servers", /* 71 */
123 "WorldWideWeb Servers", /* 72 */
124 "Finger Servers", /* 73 */
125 "Internet Relay Chat (IRC) Servers", /* 74 */
126 "StreetTalk Servers", /* 75 */
127 "StreetTalk Directory Assist. Servers", /* 76 */
128 "User Class Identifier", /* 77 */
131 #define OPTIONS_ARRAY_SIZE 78
134 interpret_dhcp(int flags
, struct dhcp
*dp
, int len
)
137 if ((memcmp(dp
->cookie
, bootmagic
, sizeof (bootmagic
)) == 0) &&
138 (len
>= BASE_PKT_SIZE
+ 3) &&
139 dp
->options
[0] == CD_DHCP_TYPE
) {
140 (void) sprintf(get_sum_line(),
141 "DHCP/BOOTP %s", show_msgtype(dp
->options
[2]));
143 switch (ntohs(dp
->op
)) {
145 (void) sprintf(get_sum_line(),
146 "DHCP/BOOTP BOOTREQUEST");
149 (void) sprintf(get_sum_line(),
150 "DHCP/BOOTP BOOTREPLY");
155 if (flags
& F_DTAIL
) {
156 show_header("DHCP: ", "Dynamic Host Configuration Protocol",
159 (void) sprintf(get_line((char *)(uintptr_t)dp
->htype
-
161 "Hardware address type (htype) = %d (%s)", dp
->htype
,
162 arp_htype(dp
->htype
));
163 (void) sprintf(get_line((char *)(uintptr_t)dp
->hlen
-
165 "Hardware address length (hlen) = %d octets", dp
->hlen
);
166 (void) sprintf(get_line((char *)(uintptr_t)dp
->hops
-
168 "Relay agent hops = %d", dp
->hops
);
169 (void) sprintf(get_line((char *)(uintptr_t)dp
->xid
-
171 "Transaction ID = 0x%x", ntohl(dp
->xid
));
172 (void) sprintf(get_line((char *)(uintptr_t)dp
->secs
-
174 "Time since boot = %d seconds", ntohs(dp
->secs
));
175 (void) sprintf(get_line((char *)(uintptr_t)dp
->flags
-
177 "Flags = 0x%.4x", ntohs(dp
->flags
));
178 (void) sprintf(get_line((char *)&dp
->ciaddr
- dlc_header
, 4),
179 "Client address (ciaddr) = %s", inet_ntoa(dp
->ciaddr
));
180 (void) sprintf(get_line((char *)&dp
->yiaddr
- dlc_header
, 4),
181 "Your client address (yiaddr) = %s",
182 inet_ntoa(dp
->yiaddr
));
183 (void) sprintf(get_line((char *)&dp
->siaddr
- dlc_header
, 4),
184 "Next server address (siaddr) = %s",
185 inet_ntoa(dp
->siaddr
));
186 (void) sprintf(get_line((char *)&dp
->giaddr
- dlc_header
, 4),
187 "Relay agent address (giaddr) = %s",
188 inet_ntoa(dp
->giaddr
));
189 if (dp
->htype
== 1) {
190 (void) sprintf(get_line((char *)dp
->chaddr
-
191 dlc_header
, dp
->hlen
),
192 "Client hardware address (chaddr) = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
201 * Check cookie, process options
203 if (memcmp(dp
->cookie
, bootmagic
, sizeof (bootmagic
)) != 0) {
204 (void) sprintf(get_line(0, 0),
205 "Unrecognized cookie: 0x%.2X%.2X%.2X%.2X\n",
213 show_header("DHCP: ", "(Options) field options", len
);
215 switch (show_options(dp
->options
, (len
- BASE_PKT_SIZE
))) {
217 /* No option overloading */
218 if (*(unsigned char *)(dp
->sname
) != '\0') {
219 (void) sprintf(get_line(0, 0),
220 "Server Name = %s", dp
->sname
);
222 if (*(unsigned char *)(dp
->file
) != '\0') {
223 (void) sprintf(get_line(0, 0),
224 "Boot File Name = %s", dp
->file
);
228 /* file field used */
229 if (*(unsigned char *)(dp
->sname
) != '\0') {
230 (void) sprintf(get_line(0, 0),
231 "Server Name = %s", dp
->sname
);
234 show_header("DHCP: ", "(File) field options", len
);
236 (void) show_options(dp
->file
, 128);
239 /* sname field used for options */
240 if (*(unsigned char *)(dp
->file
) != '\0') {
241 (void) sprintf(get_line(0, 0),
242 "Boot File Name = %s", dp
->file
);
245 show_header("DHCP: ", "(Sname) field options", len
);
247 (void) show_options(dp
->sname
, 64);
251 show_header("DHCP: ", "(File) field options", len
);
253 (void) show_options(dp
->file
, 128);
255 show_header("DHCP: ", "(Sname) field options", len
);
257 (void) show_options(dp
->sname
, 64);
265 show_options(unsigned char *cp
, int len
)
268 unsigned char *end
, *vend
;
269 unsigned char *start
, save
;
275 dhcp_symbol_t
*entry
;
280 end
= (unsigned char *)cp
+ len
;
282 while (start
< end
) {
283 if (*start
== CD_PAD
) {
287 if (*start
== CD_END
)
292 /* Network order IP address(es) */
294 case CD_ROUTER_SOLICIT_SERV
:
295 case CD_BROADCASTADDR
:
296 case CD_REQUESTED_IP_ADDR
:
298 /* Single IP address */
300 (void) sprintf(get_line(0, 0),
301 "Error: Bad %s", option_types
[save
]);
304 display_ip(1, "%s = %s", option_types
[save
],
310 case CD_IEN116_NAME_SERV
:
315 case CD_IMPRESS_SERV
:
316 case CD_RESOURCE_SERV
:
320 case CD_NETBIOS_NAME_SERV
:
321 case CD_NETBIOS_DIST_SERV
:
322 case CD_XWIN_FONT_SERV
:
323 case CD_XWIN_DISP_SERV
:
324 case CD_MOBILE_IP_AGENT
:
329 case CD_FINGER_SERVS
:
331 case CD_STREETTALK_SERVS
:
332 case CD_STREETTALK_DA_SERVS
:
333 /* Multiple IP addresses */
334 if ((*start
% 4) != 0) {
335 (void) sprintf(get_line(0, 0),
336 "Error: Bad %s address",
339 items
= *start
++ / 4;
340 display_ip(items
, "%s at = %s",
341 option_types
[save
], &start
);
344 case CD_TFTP_SERV_NAME
:
350 case CD_NETBIOS_SCOPE
:
352 case CD_OPT_BOOTFILE_NAME
:
353 case CD_USER_CLASS_ID
:
355 display_ascii("%s = %s", option_types
[save
], &start
);
359 case CD_PATH_MTU_TIMEOUT
:
362 case CD_TCP_KALIVE_INTVL
:
366 /* Number: seconds */
367 display_number("%s = %d seconds", option_types
[save
],
370 case CD_IP_FORWARDING_ON
:
371 case CD_NON_LCL_ROUTE_ON
:
372 case CD_ALL_SUBNETS_LCL_ON
:
373 case CD_MASK_DISCVRY_ON
:
374 case CD_MASK_SUPPLIER_ON
:
375 case CD_ROUTER_DISCVRY_ON
:
376 case CD_TRAILER_ENCAPS_ON
:
377 case CD_ETHERNET_ENCAPS_ON
:
378 case CD_TCP_KALIVE_GRBG_ON
:
379 /* Number: hex flag */
380 display_number("%s flag = 0x%x", option_types
[save
],
385 case CD_MAX_DHCP_SIZE
:
387 display_number("%s = %d bytes", option_types
[save
],
392 case CD_NW_IP_DOMAIN
:
393 case CD_NW_IP_OPTIONS
:
394 /* Hex ascii strings */
395 display_ascii_hex(option_types
[save
], &start
);
398 display_number("%s = %d 512 byte blocks",
399 "Boot file size", &start
);
401 case CD_POLICY_FILTER
:
402 if ((*start
% 8) != 0) {
403 (void) sprintf(get_line(0, 0),
404 "Error: Bad Policy Filter option");
406 items
= *start
++ / 8;
407 for (i
= 0; i
< items
; i
++) {
410 "Policy Destination",
412 display_ip(1, "%s = %s", "Mask",
417 case CD_PATH_MTU_TABLE_SZ
:
418 if (*start
% 2 != 0) {
419 (void) sprintf(get_line(0, 0),
420 "Error: Bad Path MTU Table");
422 (void) sprintf(get_line(0, 0),
423 "\tPath MTU Plateau Table:");
424 (void) sprintf(get_line(0, 0),
425 "\t=======================");
426 items
= *start
/ sizeof (ushort_t
);
428 for (i
= 0; i
< items
; i
++) {
429 if (IS_P2ALIGNED(start
,
430 sizeof (ushort_t
))) {
431 /* LINTED: improper alignment */
432 s_buf
= *(ushort_t
*)start
;
434 memcpy((char *)&s_buf
,
435 start
, sizeof (short));
437 (void) sprintf(get_line(0, 0),
438 "\t\tEntry %d:\t\t%d", i
,
440 start
+= sizeof (ushort_t
);
444 case CD_STATIC_ROUTE
:
445 if ((*start
% 8) != 0) {
446 (void) sprintf(get_line(0, 0),
447 "Error: Bad Static Route option: %d",
450 items
= *start
++ / 8;
451 for (i
= 0; i
< items
; i
++) {
452 memcpy((char *)&tmp
, start
,
453 sizeof (struct in_addr
));
454 (void) strcpy(scratch
, inet_ntoa(tmp
));
455 start
+= sizeof (ulong_t
);
456 memcpy((char *)&tmp
, start
,
457 sizeof (struct in_addr
));
458 (void) sprintf(get_line(0, 0),
459 "Static route from %s to %s",
460 scratch
, inet_ntoa(tmp
));
461 start
+= sizeof (ulong_t
);
467 (void) sprintf(get_line(0, 0),
468 "Vendor-specific Options (%d total octets):", i
);
470 * We don't know what these things are, so just
471 * display the option number, length, and value
474 vend
= (uchar_t
*)((uchar_t
*)start
+ i
);
475 while (start
< vend
&& *start
!= CD_END
) {
476 if (*start
== CD_PAD
) {
480 (void) sprintf(scratch
,
481 "\t(%.2d) %.2d octets", *start
,
482 *(uchar_t
*)((uchar_t
*)start
+ 1));
484 display_ascii_hex(scratch
, &start
);
486 start
= vend
; /* in case CD_END found */
488 case CD_NETBIOS_NODE_TYPE
:
490 (void) sprintf(get_line(0, 0),
491 "Error: Bad '%s' parameter",
492 option_types
[CD_NETBIOS_NODE_TYPE
]);
498 type
= "Broadcast Node";
501 type
= "Point To Point Node";
504 type
= "Mixed Mode Node";
507 type
= "Hybrid Node";
513 (void) sprintf(get_line(0, 0),
515 option_types
[CD_NETBIOS_NODE_TYPE
],
520 case CD_OPTION_OVERLOAD
:
522 (void) sprintf(get_line(0, 0),
523 "Bad Option Overload value.");
526 nooverload
= *start
++;
530 if (*start
< 1 || *start
> 7) {
531 (void) sprintf(get_line(0, 0),
532 "Bad DHCP Message Type.");
535 (void) sprintf(get_line(0, 0),
537 show_msgtype(*start
));
541 case CD_REQUEST_LIST
:
543 (void) sprintf(get_line(0, 0),
544 "Requested Options:");
545 for (i
= 0; i
< opt_len
; i
++) {
547 if (*start
< OPTIONS_ARRAY_SIZE
) {
548 prmpt
= option_types
[*start
];
550 entry
= inittab_getbycode(
551 ITAB_CAT_STANDARD
|ITAB_CAT_SITE
,
552 ITAB_CONS_SNOOP
, *start
);
554 if (*start
>= DHCP_SITE_OPT
&&
555 *start
<= DHCP_END_SITE
) {
556 prmpt
= "Site Option";
558 prmpt
= "Unrecognized "
562 prmpt
= entry
->ds_name
;
565 (void) sprintf(get_line(0, 0),
566 "\t%2d (%s)", *start
, prmpt
);
573 entry
= inittab_getbycode(
574 ITAB_CAT_STANDARD
|ITAB_CAT_SITE
,
575 ITAB_CONS_SNOOP
, save
);
577 if (save
>= DHCP_SITE_OPT
&&
578 save
<= DHCP_END_SITE
)
581 prmpt
= "Unrecognized";
584 if (save
< OPTIONS_ARRAY_SIZE
) {
585 prmpt
= option_types
[save
];
587 prmpt
= entry
->ds_name
;
589 decoded_opt
= inittab_decode(entry
, start
,
592 if (decoded_opt
== NULL
) {
593 (void) sprintf(get_line(0, 0),
594 "%s Option = %d, length = %d octets",
595 prmpt
, save
, opt_len
);
597 display_ascii_hex("\tValue =", &start
);
599 (void) sprintf(get_line(0, 0), "%s = %s", prmpt
,
612 show_msgtype(unsigned char type
)
615 * note: the ordering here allows direct indexing of the table
616 * based on the RFC2131 packet type value passed in.
619 static const char *types
[] = {
621 "DHCPDISCOVER", "DHCPOFFER", "DHCPREQUEST", "DHCPDECLINE",
622 "DHCPACK", "DHCPNAK", "DHCPRELEASE", "DHCPINFORM"
625 if (type
>= (sizeof (types
) / sizeof (*types
)) || types
[type
] == NULL
)
628 return (types
[type
]);
632 display_ip(int items
, char *fmt
, char *msg
, unsigned char **opt
)
637 for (i
= 0; i
< items
; i
++) {
638 memcpy((char *)&tmp
, *opt
, sizeof (struct in_addr
));
639 (void) sprintf(get_line(0, 0), fmt
, msg
, inet_ntoa(tmp
));
645 display_ascii(char *fmt
, char *msg
, unsigned char **opt
)
647 static unsigned char buf
[256];
649 unsigned char slen
= len
;
651 if (len
>= sizeof (buf
))
652 len
= sizeof (buf
) - 1;
654 memcpy(buf
, *opt
, len
);
655 *(unsigned char *)(buf
+ len
) = '\0';
656 (void) sprintf(get_line(0, 0), fmt
, msg
, buf
);
661 display_number(char *fmt
, char *msg
, unsigned char **opt
)
664 unsigned long l_buf
= 0;
665 unsigned short s_buf
= 0;
669 (void) sprintf(get_line(0, 0), fmt
, msg
, 0xdeadbeef);
673 case sizeof (uchar_t
):
675 (void) sprintf(get_line(0, 0), fmt
, msg
, **opt
);
677 case sizeof (ushort_t
):
679 if (IS_P2ALIGNED(*opt
, sizeof (ushort_t
)))
680 /* LINTED: improper alignment */
681 s_buf
= *(unsigned short *)*opt
;
683 memcpy((char *)&s_buf
, *opt
, len
);
684 (void) sprintf(get_line(0, 0), fmt
, msg
, ntohs(s_buf
));
686 case sizeof (ulong_t
):
688 if (IS_P2ALIGNED(*opt
, sizeof (ulong_t
)))
689 /* LINTED: improper alignment */
690 l_buf
= *(unsigned long *)*opt
;
692 memcpy((char *)&l_buf
, *opt
, len
);
693 (void) sprintf(get_line(0, 0), fmt
, msg
, ntohl(l_buf
));
700 display_ascii_hex(char *msg
, unsigned char **opt
)
704 char *line
, *tmp
, *ap
, *fmt
;
707 line
= get_line(0, 0);
712 (void) sprintf(line
, "\t%s <TOO LONG>", msg
);
716 for (printable
= 1, tmp
= (char *)(*opt
), ap
= buffer
;
717 tmp
< (char *)&((*opt
)[len
]); tmp
++) {
728 for (tmp
= (char *)(*opt
), ap
= buffer
;
729 (tmp
< (char *)&((*opt
)[len
])) && ((ap
+ 5) < &buffer
[512]);
731 ap
+= sprintf(ap
, "0x%02X ", *(uchar_t
*)(tmp
));
733 /* Truncate the trailing space */
735 /* More bytes to print in hex but no space in buffer */
736 if (tmp
< (char *)&((*opt
)[len
])) {
742 fmt
= "%s\t%s (unprintable)";
747 (void) sprintf(line
, fmt
, msg
, buffer
);