xref: /titanic_54/usr/src/common/net/dhcp/scan.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 1996-2001, 2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  *
26*7c478bd9Sstevel@tonic-gate  * Routines used to extract/insert DHCP options. Must be kept MT SAFE,
27*7c478bd9Sstevel@tonic-gate  * as they are called from different threads.
28*7c478bd9Sstevel@tonic-gate  */
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
33*7c478bd9Sstevel@tonic-gate #include "dhcp_impl.h"
34*7c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT)
35*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
36*7c478bd9Sstevel@tonic-gate #else
37*7c478bd9Sstevel@tonic-gate #include <strings.h>
38*7c478bd9Sstevel@tonic-gate #endif	/* _KERNEL && !_BOOT */
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate static uint8_t	bootmagic[] = BOOTMAGIC;
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate /*
43*7c478bd9Sstevel@tonic-gate  * Scan field for options.
44*7c478bd9Sstevel@tonic-gate  */
45*7c478bd9Sstevel@tonic-gate static void
46*7c478bd9Sstevel@tonic-gate field_scan(uint8_t *start, uint8_t *end, DHCP_OPT **options,
47*7c478bd9Sstevel@tonic-gate     uint8_t last_option)
48*7c478bd9Sstevel@tonic-gate {
49*7c478bd9Sstevel@tonic-gate 	uint8_t		*current;
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate 	while (start < end) {
52*7c478bd9Sstevel@tonic-gate 		if (*start == CD_PAD) {
53*7c478bd9Sstevel@tonic-gate 			start++;
54*7c478bd9Sstevel@tonic-gate 			continue;
55*7c478bd9Sstevel@tonic-gate 		}
56*7c478bd9Sstevel@tonic-gate 		if (*start == CD_END)
57*7c478bd9Sstevel@tonic-gate 			break;		/* done */
58*7c478bd9Sstevel@tonic-gate 		if (*start > last_option) {
59*7c478bd9Sstevel@tonic-gate 			if (++start < end)
60*7c478bd9Sstevel@tonic-gate 				start += *start + 1;
61*7c478bd9Sstevel@tonic-gate 			continue;	/* unrecognized option */
62*7c478bd9Sstevel@tonic-gate 		}
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 		current = start;
65*7c478bd9Sstevel@tonic-gate 		if (++start < end)
66*7c478bd9Sstevel@tonic-gate 			start += *start + 1; /* advance to next option */
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate 		/* all options besides CD_END and CD_PAD should have a len */
69*7c478bd9Sstevel@tonic-gate 		if ((current + 1) >= end)
70*7c478bd9Sstevel@tonic-gate 			continue;
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate 		/* Ignores duplicate options. */
73*7c478bd9Sstevel@tonic-gate 		if (options[*current] == NULL) {
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate 			options[*current] = (DHCP_OPT *)current;
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate 			/* verify that len won't go beyond end */
78*7c478bd9Sstevel@tonic-gate 			if ((current + options[*current]->len + 1) >= end) {
79*7c478bd9Sstevel@tonic-gate 				options[*current] = NULL;
80*7c478bd9Sstevel@tonic-gate 				continue;
81*7c478bd9Sstevel@tonic-gate 			}
82*7c478bd9Sstevel@tonic-gate 		}
83*7c478bd9Sstevel@tonic-gate 	}
84*7c478bd9Sstevel@tonic-gate }
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate /*
87*7c478bd9Sstevel@tonic-gate  * Scan Vendor field for options.
88*7c478bd9Sstevel@tonic-gate  */
89*7c478bd9Sstevel@tonic-gate static void
90*7c478bd9Sstevel@tonic-gate vendor_scan(PKT_LIST *pl)
91*7c478bd9Sstevel@tonic-gate {
92*7c478bd9Sstevel@tonic-gate 	uint8_t	*start, *end, len;
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate 	if (pl->opts[CD_VENDOR_SPEC] == NULL)
95*7c478bd9Sstevel@tonic-gate 		return;
96*7c478bd9Sstevel@tonic-gate 	len = pl->opts[CD_VENDOR_SPEC]->len;
97*7c478bd9Sstevel@tonic-gate 	start = pl->opts[CD_VENDOR_SPEC]->value;
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	/* verify that len won't go beyond the end of the packet */
100*7c478bd9Sstevel@tonic-gate 	if (((start - (uint8_t *)pl->pkt) + len) > pl->len)
101*7c478bd9Sstevel@tonic-gate 		return;
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate 	end = start + len;
104*7c478bd9Sstevel@tonic-gate 	field_scan(start, end, pl->vs, VS_OPTION_END);
105*7c478bd9Sstevel@tonic-gate }
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate /*
108*7c478bd9Sstevel@tonic-gate  * Load opts table in PKT_LIST entry with PKT's options.
109*7c478bd9Sstevel@tonic-gate  * Returns 0 if no fatal errors occur, otherwise...
110*7c478bd9Sstevel@tonic-gate  */
111*7c478bd9Sstevel@tonic-gate int
112*7c478bd9Sstevel@tonic-gate dhcp_options_scan(PKT_LIST *pl, boolean_t scan_vendor)
113*7c478bd9Sstevel@tonic-gate {
114*7c478bd9Sstevel@tonic-gate 	PKT 	*pkt = pl->pkt;
115*7c478bd9Sstevel@tonic-gate 	uint_t	opt_size = pl->len - BASE_PKT_SIZE;
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	/*
118*7c478bd9Sstevel@tonic-gate 	 * bcmp() is used here instead of memcmp() since kernel/standalone
119*7c478bd9Sstevel@tonic-gate 	 * doesn't have a memcmp().
120*7c478bd9Sstevel@tonic-gate 	 */
121*7c478bd9Sstevel@tonic-gate 	if (pl->len < BASE_PKT_SIZE ||
122*7c478bd9Sstevel@tonic-gate 	    bcmp(pl->pkt->cookie, bootmagic, sizeof (pl->pkt->cookie)) != 0) {
123*7c478bd9Sstevel@tonic-gate 		pl->rfc1048 = 0;
124*7c478bd9Sstevel@tonic-gate 		return (0);
125*7c478bd9Sstevel@tonic-gate 	}
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 	pl->rfc1048 = 1;
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate 	/* check the options field */
130*7c478bd9Sstevel@tonic-gate 	field_scan(pkt->options, &pkt->options[opt_size], pl->opts,
131*7c478bd9Sstevel@tonic-gate 	    DHCP_LAST_OPT);
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	/*
134*7c478bd9Sstevel@tonic-gate 	 * process vendor specific options. We look at the vendor options
135*7c478bd9Sstevel@tonic-gate 	 * here, simply because a BOOTP server could fake DHCP vendor
136*7c478bd9Sstevel@tonic-gate 	 * options. This increases our interoperability with BOOTP.
137*7c478bd9Sstevel@tonic-gate 	 */
138*7c478bd9Sstevel@tonic-gate 	if (scan_vendor && (pl->opts[CD_VENDOR_SPEC] != NULL))
139*7c478bd9Sstevel@tonic-gate 		vendor_scan(pl);
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 	if (pl->opts[CD_DHCP_TYPE] == NULL)
142*7c478bd9Sstevel@tonic-gate 		return (0);
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	if (pl->opts[CD_DHCP_TYPE]->len != 1)
145*7c478bd9Sstevel@tonic-gate 		return (DHCP_GARBLED_MSG_TYPE);
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	if (*pl->opts[CD_DHCP_TYPE]->value < DISCOVER ||
148*7c478bd9Sstevel@tonic-gate 	    *pl->opts[CD_DHCP_TYPE]->value > INFORM)
149*7c478bd9Sstevel@tonic-gate 		return (DHCP_WRONG_MSG_TYPE);
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 	if (pl->opts[CD_OPTION_OVERLOAD]) {
152*7c478bd9Sstevel@tonic-gate 		if (pl->opts[CD_OPTION_OVERLOAD]->len != 1) {
153*7c478bd9Sstevel@tonic-gate 			pl->opts[CD_OPTION_OVERLOAD] = NULL;
154*7c478bd9Sstevel@tonic-gate 			return (DHCP_BAD_OPT_OVLD);
155*7c478bd9Sstevel@tonic-gate 		}
156*7c478bd9Sstevel@tonic-gate 		switch (*pl->opts[CD_OPTION_OVERLOAD]->value) {
157*7c478bd9Sstevel@tonic-gate 		case 1:
158*7c478bd9Sstevel@tonic-gate 			field_scan(pkt->file, &pkt->cookie[0], pl->opts,
159*7c478bd9Sstevel@tonic-gate 			    DHCP_LAST_OPT);
160*7c478bd9Sstevel@tonic-gate 			break;
161*7c478bd9Sstevel@tonic-gate 		case 2:
162*7c478bd9Sstevel@tonic-gate 			field_scan(pkt->sname, &pkt->file[0], pl->opts,
163*7c478bd9Sstevel@tonic-gate 			    DHCP_LAST_OPT);
164*7c478bd9Sstevel@tonic-gate 			break;
165*7c478bd9Sstevel@tonic-gate 		case 3:
166*7c478bd9Sstevel@tonic-gate 			field_scan(pkt->file, &pkt->cookie[0], pl->opts,
167*7c478bd9Sstevel@tonic-gate 			    DHCP_LAST_OPT);
168*7c478bd9Sstevel@tonic-gate 			field_scan(pkt->sname, &pkt->file[0], pl->opts,
169*7c478bd9Sstevel@tonic-gate 			    DHCP_LAST_OPT);
170*7c478bd9Sstevel@tonic-gate 			break;
171*7c478bd9Sstevel@tonic-gate 		default:
172*7c478bd9Sstevel@tonic-gate 			pl->opts[CD_OPTION_OVERLOAD] = NULL;
173*7c478bd9Sstevel@tonic-gate 			return (DHCP_BAD_OPT_OVLD);
174*7c478bd9Sstevel@tonic-gate 		}
175*7c478bd9Sstevel@tonic-gate 	}
176*7c478bd9Sstevel@tonic-gate 	return (0);
177*7c478bd9Sstevel@tonic-gate }
178