xref: /illumos-gate/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c (revision 489f6310fe8952e87fc1dce8af87990fcfd90f18)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
25  *
26  * REQUESTING state of the client state machine.
27  */
28 
29 #include <stdlib.h>
30 #include <string.h>
31 #include <search.h>
32 #include <sys/types.h>
33 #include <netinet/in.h>
34 #include <netinet/dhcp.h>
35 #include <netinet/udp.h>
36 #include <netinet/ip_var.h>
37 #include <netinet/udp_var.h>
38 #include <arpa/inet.h>
39 #include <dhcp_hostconf.h>
40 #include <dhcpagent_util.h>
41 #include <dhcpmsg.h>
42 
43 #include "states.h"
44 #include "util.h"
45 #include "packet.h"
46 #include "interface.h"
47 #include "agent.h"
48 
49 static PKT_LIST		*select_best(dhcp_smach_t *);
50 static void		request_failed(dhcp_smach_t *);
51 static stop_func_t	stop_requesting;
52 
53 /*
54  * send_v6_request(): sends a DHCPv6 Request message and switches to REQUESTING
55  *		      state.  This is a separate function because a NoBinding
56  *		      response can also cause us to do this.
57  *
58  *   input: dhcp_smach_t *: the state machine
59  *  output: none
60  */
61 
62 void
63 send_v6_request(dhcp_smach_t *dsmp)
64 {
65 	dhcp_pkt_t *dpkt;
66 	dhcpv6_ia_na_t d6in;
67 
68 	dpkt = init_pkt(dsmp, DHCPV6_MSG_REQUEST);
69 	(void) add_pkt_opt(dpkt, DHCPV6_OPT_SERVERID, dsmp->dsm_serverid,
70 	    dsmp->dsm_serveridlen);
71 
72 	/* Add an IA_NA option for our controlling LIF */
73 	d6in.d6in_iaid = htonl(dsmp->dsm_lif->lif_iaid);
74 	d6in.d6in_t1 = htonl(0);
75 	d6in.d6in_t2 = htonl(0);
76 	(void) add_pkt_opt(dpkt, DHCPV6_OPT_IA_NA,
77 	    (dhcpv6_option_t *)&d6in + 1,
78 	    sizeof (d6in) - sizeof (dhcpv6_option_t));
79 
80 	/* Add required Option Request option */
81 	(void) add_pkt_prl(dpkt, dsmp);
82 
83 	(void) send_pkt_v6(dsmp, dpkt, dsmp->dsm_server, stop_requesting,
84 	    DHCPV6_REQ_TIMEOUT, DHCPV6_REQ_MAX_RT);
85 
86 	/* For DHCPv6, state switch cannot fail */
87 	(void) set_smach_state(dsmp, REQUESTING);
88 }
89 
90 /*
91  * server_unicast_option(): determines the server address to use based on the
92  *			    DHCPv6 Server Unicast option present in the given
93  *			    packet.
94  *
95  *   input: dhcp_smach_t *: the state machine
96  *	    PKT_LIST *: received packet (Advertisement or Reply)
97  *  output: none
98  */
99 
100 void
101 server_unicast_option(dhcp_smach_t *dsmp, PKT_LIST *plp)
102 {
103 	const dhcpv6_option_t *d6o;
104 	uint_t olen;
105 
106 	d6o = dhcpv6_pkt_option(plp, NULL, DHCPV6_OPT_UNICAST, &olen);
107 	olen -= sizeof (*d6o);
108 	/* LINTED: no consequent */
109 	if (d6o == NULL) {
110 		/* No Server Unicast option specified */
111 	} else if (olen != sizeof (dsmp->dsm_server)) {
112 		dhcpmsg(MSG_WARNING, "server_unicast_option: %s has Server "
113 		    "Unicast option with bad length",
114 		    pkt_type_to_string(pkt_recv_type(plp), B_TRUE));
115 	} else {
116 		in6_addr_t addr;
117 
118 		(void) memcpy(&addr, d6o + 1, olen);
119 		if (IN6_IS_ADDR_UNSPECIFIED(&addr)) {
120 			dhcpmsg(MSG_WARNING, "server_unicast_option: unicast "
121 			    "to unspecified address ignored");
122 		} else if (IN6_IS_ADDR_MULTICAST(&addr)) {
123 			dhcpmsg(MSG_WARNING, "server_unicast_option: unicast "
124 			    "to multicast address ignored");
125 		} else if (IN6_IS_ADDR_V4COMPAT(&addr) ||
126 		    IN6_IS_ADDR_V4MAPPED(&addr)) {
127 			dhcpmsg(MSG_WARNING, "server_unicast_option: unicast "
128 			    "to invalid address ignored");
129 		} else {
130 			dsmp->dsm_server = addr;
131 		}
132 	}
133 }
134 
135 /*
136  * dhcp_requesting(): checks if OFFER packets to come in from DHCP servers.
137  *		      if so, chooses the best one, sends a REQUEST to the
138  *		      server and registers an event handler to receive
139  *		      the ACK/NAK.  This may be called by the offer timer or
140  *		      by any function that wants to check for offers after
141  *		      canceling that timer.
142  *
143  *   input: iu_tq_t *: timer queue; non-NULL if this is a timer callback
144  *	    void *: the state machine receiving OFFER packets
145  *  output: void
146  */
147 
148 void
149 dhcp_requesting(iu_tq_t *tqp, void *arg)
150 {
151 	dhcp_smach_t		*dsmp = arg;
152 	dhcp_pkt_t		*dpkt;
153 	PKT_LIST		*offer;
154 	lease_t			lease;
155 	boolean_t		isv6 = dsmp->dsm_isv6;
156 
157 	/*
158 	 * We assume here that if tqp is set, then this means we're being
159 	 * called back by the offer wait timer.  If so, then drop our hold
160 	 * on the state machine.  Otherwise, cancel the timer if it's running.
161 	 */
162 	if (tqp != NULL) {
163 		dhcpmsg(MSG_VERBOSE,
164 		    "dhcp_requesting: offer wait timer on v%d %s",
165 		    isv6 ? 6 : 4, dsmp->dsm_name);
166 		dsmp->dsm_offer_timer = -1;
167 		if (!verify_smach(dsmp))
168 			return;
169 	} else {
170 		cancel_offer_timer(dsmp);
171 	}
172 
173 	/*
174 	 * select the best OFFER; all others pitched.
175 	 */
176 
177 	offer = select_best(dsmp);
178 	if (offer == NULL) {
179 
180 		dhcpmsg(MSG_VERBOSE,
181 		    "no OFFERs/Advertisements on %s, waiting...",
182 		    dsmp->dsm_name);
183 
184 		/*
185 		 * no acceptable OFFERs have come in.  reschedule
186 		 * ourself for callback.
187 		 */
188 
189 		if ((dsmp->dsm_offer_timer = iu_schedule_timer(tq,
190 		    dsmp->dsm_offer_wait, dhcp_requesting, dsmp)) == -1) {
191 
192 			/*
193 			 * ugh.  the best we can do at this point is
194 			 * revert back to INIT and wait for a user to
195 			 * restart us.
196 			 */
197 
198 			dhcpmsg(MSG_WARNING, "dhcp_requesting: cannot "
199 			    "reschedule callback, reverting to INIT state on "
200 			    "%s", dsmp->dsm_name);
201 
202 			stop_pkt_retransmission(dsmp);
203 			(void) set_smach_state(dsmp, INIT);
204 			dsmp->dsm_dflags |= DHCP_IF_FAILED;
205 			ipc_action_finish(dsmp, DHCP_IPC_E_MEMORY);
206 		} else {
207 			hold_smach(dsmp);
208 		}
209 
210 		return;
211 	}
212 
213 	/*
214 	 * With IPv4, the DHCPREQUEST packet we're about to transmit implicitly
215 	 * declines all other offers we've received.  We can no longer use any
216 	 * cached offers, so we must discard them now.  With DHCPv6, though,
217 	 * we're permitted to hang onto the advertisements (offers) and try
218 	 * them if the preferred one doesn't pan out.
219 	 */
220 	if (!isv6)
221 		free_pkt_list(&dsmp->dsm_recv_pkt_list);
222 
223 	/* stop collecting packets. */
224 
225 	stop_pkt_retransmission(dsmp);
226 
227 	/*
228 	 * For IPv4, check to see whether we got an OFFER or a BOOTP packet.
229 	 * If we got a BOOTP packet, go to the BOUND state now.
230 	 */
231 	if (!isv6 && offer->opts[CD_DHCP_TYPE] == NULL) {
232 		free_pkt_list(&dsmp->dsm_recv_pkt_list);
233 
234 		if (!set_smach_state(dsmp, REQUESTING)) {
235 			dhcp_restart(dsmp);
236 			return;
237 		}
238 
239 		if (!dhcp_bound(dsmp, offer)) {
240 			dhcpmsg(MSG_WARNING, "dhcp_requesting: dhcp_bound "
241 			    "failed for %s", dsmp->dsm_name);
242 			dhcp_restart(dsmp);
243 			return;
244 		}
245 
246 		return;
247 	}
248 
249 	save_domainname(dsmp, offer);
250 
251 	if (isv6) {
252 		const char *estr, *msg;
253 		const dhcpv6_option_t *d6o;
254 		uint_t olen, msglen;
255 
256 		/* If there's a Status Code option, print the message */
257 		d6o = dhcpv6_pkt_option(offer, NULL, DHCPV6_OPT_STATUS_CODE,
258 		    &olen);
259 		(void) dhcpv6_status_code(d6o, olen, &estr, &msg, &msglen);
260 		print_server_msg(dsmp, msg, msglen);
261 
262 		/* Copy in the Server ID (guaranteed to be present now) */
263 		if (!save_server_id(dsmp, offer))
264 			goto failure;
265 
266 		/*
267 		 * Determine how to send this message.  If the Advertisement
268 		 * (offer) has the unicast option, then use the address
269 		 * specified in the option.  Otherwise, send via multicast.
270 		 */
271 		server_unicast_option(dsmp, offer);
272 
273 		send_v6_request(dsmp);
274 	} else {
275 		/* if we got a message from the server, display it. */
276 		if (offer->opts[CD_MESSAGE] != NULL) {
277 			print_server_msg(dsmp,
278 			    (char *)offer->opts[CD_MESSAGE]->value,
279 			    offer->opts[CD_MESSAGE]->len);
280 		}
281 
282 		/*
283 		 * assemble a DHCPREQUEST, with the ciaddr field set to 0,
284 		 * since we got here from the INIT state.
285 		 */
286 
287 		dpkt = init_pkt(dsmp, REQUEST);
288 
289 		/*
290 		 * Grab the lease out of the OFFER; we know it's valid because
291 		 * select_best() already checked.  The max dhcp message size
292 		 * option is set to the interface max, minus the size of the
293 		 * udp and ip headers.
294 		 */
295 
296 		(void) memcpy(&lease, offer->opts[CD_LEASE_TIME]->value,
297 		    sizeof (lease_t));
298 
299 		(void) add_pkt_opt32(dpkt, CD_LEASE_TIME, lease);
300 		(void) add_pkt_opt16(dpkt, CD_MAX_DHCP_SIZE,
301 		    htons(dsmp->dsm_lif->lif_pif->pif_mtu -
302 		    sizeof (struct udpiphdr)));
303 		(void) add_pkt_opt32(dpkt, CD_REQUESTED_IP_ADDR,
304 		    offer->pkt->yiaddr.s_addr);
305 		(void) add_pkt_opt(dpkt, CD_SERVER_ID,
306 		    offer->opts[CD_SERVER_ID]->value,
307 		    offer->opts[CD_SERVER_ID]->len);
308 
309 		if (class_id_len != 0) {
310 			(void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id,
311 			    class_id_len);
312 		}
313 		(void) add_pkt_prl(dpkt, dsmp);
314 
315 		/*
316 		 * dsm_reqhost was set for this state machine in
317 		 * dhcp_selecting() if the DF_REQUEST_HOSTNAME option set and a
318 		 * host name was found
319 		 */
320 		if (!dhcp_add_fqdn_opt(dpkt, dsmp) &&
321 		    dsmp->dsm_reqhost != NULL) {
322 			(void) add_pkt_opt(dpkt, CD_HOSTNAME, dsmp->dsm_reqhost,
323 			    strlen(dsmp->dsm_reqhost));
324 		}
325 		(void) add_pkt_opt(dpkt, CD_END, NULL, 0);
326 
327 		/*
328 		 * send out the REQUEST, trying retransmissions.  either a NAK
329 		 * or too many REQUEST attempts will revert us to SELECTING.
330 		 */
331 
332 		if (!set_smach_state(dsmp, REQUESTING)) {
333 			dhcpmsg(MSG_ERROR, "dhcp_requesting: cannot switch to "
334 			    "REQUESTING state; reverting to INIT on %s",
335 			    dsmp->dsm_name);
336 			goto failure;
337 		}
338 
339 		(void) send_pkt(dsmp, dpkt, htonl(INADDR_BROADCAST),
340 		    stop_requesting);
341 	}
342 
343 	/* all done with the offer */
344 	free_pkt_entry(offer);
345 
346 	return;
347 
348 failure:
349 	dsmp->dsm_dflags |= DHCP_IF_FAILED;
350 	(void) set_smach_state(dsmp, INIT);
351 	ipc_action_finish(dsmp, DHCP_IPC_E_MEMORY);
352 	free_pkt_list(&dsmp->dsm_recv_pkt_list);
353 }
354 
355 /*
356  * compute_points_v6(): compute the number of "points" for a given v6
357  *			advertisement.
358  *
359  *   input: const PKT_LIST *: packet to inspect
360  *	    const dhcp_smach_t *: state machine that received the packet
361  *  output: int: -1 to discard, -2 to accept immediately, >=0 for preference.
362  */
363 
364 static int
365 compute_points_v6(const PKT_LIST *pkt, const dhcp_smach_t *dsmp)
366 {
367 	char abuf[INET6_ADDRSTRLEN];
368 	int points = 0;
369 	const dhcpv6_option_t *d6o, *d6so;
370 	uint_t olen, solen;
371 	int i;
372 	const char *estr, *msg;
373 	uint_t msglen;
374 
375 	/*
376 	 * Look through the packet contents.  Valid packets must have our
377 	 * client ID and a server ID, which has already been checked by
378 	 * dhcp_packet_lif.  Bonus points for each option.
379 	 */
380 
381 	/* One point for having a valid message. */
382 	points++;
383 
384 	/*
385 	 * Per RFC 3315, if the Advertise message says, "yes, we have no
386 	 * bananas today," then ignore the entire message.  (Why it's just
387 	 * _this_ error and no other is a bit of a mystery, but a standard is a
388 	 * standard.)
389 	 */
390 	d6o = dhcpv6_pkt_option(pkt, NULL, DHCPV6_OPT_STATUS_CODE, &olen);
391 	if (dhcpv6_status_code(d6o, olen, &estr, &msg, &msglen) ==
392 	    DHCPV6_STAT_NOADDRS) {
393 		dhcpmsg(MSG_INFO,
394 		    "discard advertisement from %s on %s: no address status",
395 		    inet_ntop(AF_INET6,
396 		    &((struct sockaddr_in6 *)&pkt->pktfrom)->sin6_addr,
397 		    abuf, sizeof (abuf)), dsmp->dsm_name);
398 		return (-1);
399 	}
400 
401 	/* Two points for each batch of offered IP addresses */
402 	d6o = NULL;
403 	while ((d6o = dhcpv6_pkt_option(pkt, d6o, DHCPV6_OPT_IA_NA,
404 	    &olen)) != NULL) {
405 
406 		/*
407 		 * Note that it's possible to have "no bananas" on an
408 		 * individual IA.  We must look for that here.
409 		 *
410 		 * RFC 3315 section 17.1.3 does not refer to the status code
411 		 * embedded in the IA itself.  However, the TAHI test suite
412 		 * checks for this specific case.  Because it's extremely
413 		 * unlikely that any usable server is going to report that it
414 		 * has no addresses on a network using DHCP for address
415 		 * assignment, we allow such messages to be dropped.
416 		 */
417 		d6so = dhcpv6_find_option(
418 		    (const char *)d6o + sizeof (dhcpv6_ia_na_t),
419 		    olen - sizeof (dhcpv6_ia_na_t), NULL,
420 		    DHCPV6_OPT_STATUS_CODE, &solen);
421 		if (dhcpv6_status_code(d6so, solen, &estr, &msg, &msglen) ==
422 		    DHCPV6_STAT_NOADDRS)
423 			return (-1);
424 		points += 2;
425 	}
426 
427 	/*
428 	 * Note that we drive on in the case where there are no addresses.  The
429 	 * hope here is that we'll at least get some useful configuration
430 	 * information.
431 	 */
432 
433 	/* One point for each requested option */
434 	for (i = 0; i < dsmp->dsm_prllen; i++) {
435 		if (dhcpv6_pkt_option(pkt, NULL, dsmp->dsm_prl[i], NULL) !=
436 		    NULL)
437 			points++;
438 	}
439 
440 	/*
441 	 * Ten points for each point of "preference."  Note: the value 255 is
442 	 * special.  It means "stop right now and select this server."
443 	 */
444 	d6o = dhcpv6_pkt_option(pkt, NULL, DHCPV6_OPT_PREFERENCE, &olen);
445 	if (d6o != NULL && olen == sizeof (*d6o) + 1) {
446 		int pref = *(const uchar_t *)(d6o + 1);
447 
448 		if (pref == 255)
449 			return (-2);
450 		points += 10 * pref;
451 	}
452 
453 	return (points);
454 }
455 
456 /*
457  * compute_points_v4(): compute the number of "points" for a given v4 offer.
458  *
459  *   input: const PKT_LIST *: packet to inspect
460  *	    const dhcp_smach_t *: state machine that received the packet
461  *  output: int: -1 to discard, >=0 for preference.
462  */
463 
464 static int
465 compute_points_v4(const PKT_LIST *pkt)
466 {
467 	int points = 0;
468 
469 	if (pkt->opts[CD_DHCP_TYPE] == NULL) {
470 		dhcpmsg(MSG_VERBOSE, "compute_points_v4: valid BOOTP reply");
471 		goto valid_offer;
472 	}
473 
474 	if (pkt->opts[CD_LEASE_TIME] == NULL) {
475 		dhcpmsg(MSG_WARNING, "compute_points_v4: OFFER without lease "
476 		    "time");
477 		return (-1);
478 	}
479 
480 	if (pkt->opts[CD_LEASE_TIME]->len != sizeof (lease_t)) {
481 		dhcpmsg(MSG_WARNING, "compute_points_v4: OFFER with garbled "
482 		    "lease time");
483 		return (-1);
484 	}
485 
486 	if (pkt->opts[CD_SERVER_ID] == NULL) {
487 		dhcpmsg(MSG_WARNING, "compute_points_v4: OFFER without server "
488 		    "id");
489 		return (-1);
490 	}
491 
492 	if (pkt->opts[CD_SERVER_ID]->len != sizeof (ipaddr_t)) {
493 		dhcpmsg(MSG_WARNING, "compute_points_v4: OFFER with garbled "
494 		    "server id");
495 		return (-1);
496 	}
497 
498 	/* valid DHCP OFFER.  see if we got our parameters. */
499 	dhcpmsg(MSG_VERBOSE, "compute_points_v4: valid OFFER packet");
500 	points += 30;
501 
502 valid_offer:
503 	if (pkt->rfc1048)
504 		points += 5;
505 
506 	/*
507 	 * also could be faked, though more difficult because the encapsulation
508 	 * is hard to encode on a BOOTP server; plus there's not as much real
509 	 * estate in the packet for options, so it's likely this option would
510 	 * get dropped.
511 	 */
512 
513 	if (pkt->opts[CD_VENDOR_SPEC] != NULL)
514 		points += 80;
515 
516 	if (pkt->opts[CD_SUBNETMASK] != NULL)
517 		points++;
518 
519 	if (pkt->opts[CD_ROUTER] != NULL)
520 		points++;
521 
522 	if (pkt->opts[CD_HOSTNAME] != NULL)
523 		points += 5;
524 
525 	return (points);
526 }
527 
528 /*
529  * select_best(): selects the best offer from a list of IPv4 OFFER packets or
530  *		  DHCPv6 Advertise packets.
531  *
532  *   input: dhcp_smach_t *: state machine with enqueued offers
533  *  output: PKT_LIST *: the best packet, or NULL if none are acceptable
534  */
535 
536 static PKT_LIST *
537 select_best(dhcp_smach_t *dsmp)
538 {
539 	PKT_LIST	*current = dsmp->dsm_recv_pkt_list;
540 	PKT_LIST	*next, *best = NULL;
541 	int		points, best_points = -1;
542 
543 	/*
544 	 * pick out the best offer.  point system.
545 	 * what's important for IPv4?
546 	 *
547 	 *	0) DHCP (30 points)
548 	 *	1) no option overload
549 	 *	2) encapsulated vendor option (80 points)
550 	 *	3) non-null sname and siaddr fields
551 	 *	4) non-null file field
552 	 *	5) hostname (5 points)
553 	 *	6) subnetmask (1 point)
554 	 *	7) router (1 point)
555 	 */
556 
557 	for (; current != NULL; current = next) {
558 		next = current->next;
559 
560 		points = current->isv6 ?
561 		    compute_points_v6(current, dsmp) :
562 		    compute_points_v4(current);
563 
564 		/*
565 		 * Just discard any unacceptable entries we encounter.
566 		 */
567 		if (points == -1) {
568 			remque(current);
569 			free_pkt_entry(current);
570 			continue;
571 		}
572 
573 		dhcpmsg(MSG_DEBUG, "select_best: OFFER had %d points", points);
574 
575 		/* Special case: stop now and select */
576 		if (points == -2) {
577 			best = current;
578 			break;
579 		}
580 
581 		if (points >= best_points) {
582 			best_points = points;
583 			best = current;
584 		}
585 	}
586 
587 	if (best != NULL) {
588 		dhcpmsg(MSG_DEBUG, "select_best: most points: %d", best_points);
589 		remque(best);
590 	} else {
591 		dhcpmsg(MSG_DEBUG, "select_best: no valid OFFER/BOOTP reply");
592 	}
593 
594 	return (best);
595 }
596 
597 /*
598  * accept_v4_acknak(): determine what to do with a DHCPv4 ACK/NAK based on the
599  *		       current state.  If we're renewing or rebinding, the ACK
600  *		       must be for the same address and must have a new lease
601  *		       time.  If it's a NAK, then our cache is garbage, and we
602  *		       must restart.  Finally, call dhcp_bound on accepted
603  *		       ACKs.
604  *
605  *   input: dhcp_smach_t *: the state machine to handle the ACK/NAK
606  *	    PKT_LIST *: the ACK/NAK message
607  *  output: void
608  */
609 
610 static void
611 accept_v4_acknak(dhcp_smach_t *dsmp, PKT_LIST *plp)
612 {
613 	/* Account for received and processed messages */
614 	dsmp->dsm_received++;
615 
616 	if (*plp->opts[CD_DHCP_TYPE]->value == ACK) {
617 		if (dsmp->dsm_state != INFORM_SENT &&
618 		    dsmp->dsm_state != INFORMATION &&
619 		    (plp->opts[CD_LEASE_TIME] == NULL ||
620 		    plp->opts[CD_LEASE_TIME]->len != sizeof (lease_t))) {
621 			dhcpmsg(MSG_WARNING, "accept_v4_acknak: ACK packet on "
622 			    "%s missing mandatory lease option, ignored",
623 			    dsmp->dsm_name);
624 			dsmp->dsm_bad_offers++;
625 			free_pkt_entry(plp);
626 			return;
627 		}
628 		if ((dsmp->dsm_state == RENEWING ||
629 		    dsmp->dsm_state == REBINDING) &&
630 		    dsmp->dsm_leases->dl_lifs->lif_addr !=
631 		    plp->pkt->yiaddr.s_addr) {
632 			dhcpmsg(MSG_WARNING, "accept_v4_acknak: renewal ACK "
633 			    "packet has a different IP address (%s), ignored",
634 			    inet_ntoa(plp->pkt->yiaddr));
635 			dsmp->dsm_bad_offers++;
636 			free_pkt_entry(plp);
637 			return;
638 		}
639 	}
640 
641 	/*
642 	 * looks good; cancel the retransmission timer and unregister
643 	 * the acknak handler. ACK to BOUND, NAK back to SELECTING.
644 	 */
645 
646 	stop_pkt_retransmission(dsmp);
647 
648 	if (*plp->opts[CD_DHCP_TYPE]->value == NAK) {
649 		dhcpmsg(MSG_WARNING, "accept_v4_acknak: NAK on interface %s",
650 		    dsmp->dsm_name);
651 		dsmp->dsm_bad_offers++;
652 		free_pkt_entry(plp);
653 		dhcp_restart(dsmp);
654 
655 		/*
656 		 * remove any bogus cached configuration we might have
657 		 * around (right now would only happen if we got here
658 		 * from INIT_REBOOT).
659 		 */
660 
661 		(void) remove_hostconf(dsmp->dsm_name, dsmp->dsm_isv6);
662 		return;
663 	}
664 
665 	if (plp->opts[CD_SERVER_ID] == NULL ||
666 	    plp->opts[CD_SERVER_ID]->len != sizeof (ipaddr_t)) {
667 		dhcpmsg(MSG_ERROR, "accept_v4_acknak: ACK with no valid "
668 		    "server id on %s", dsmp->dsm_name);
669 		dsmp->dsm_bad_offers++;
670 		free_pkt_entry(plp);
671 		dhcp_restart(dsmp);
672 		return;
673 	}
674 
675 	if (plp->opts[CD_MESSAGE] != NULL) {
676 		print_server_msg(dsmp, (char *)plp->opts[CD_MESSAGE]->value,
677 		    plp->opts[CD_MESSAGE]->len);
678 	}
679 
680 	dhcpmsg(MSG_VERBOSE, "accept_v4_acknak: ACK on %s", dsmp->dsm_name);
681 	if (!dhcp_bound(dsmp, plp)) {
682 		dhcpmsg(MSG_WARNING, "accept_v4_acknak: dhcp_bound failed "
683 		    "for %s", dsmp->dsm_name);
684 		dhcp_restart(dsmp);
685 	}
686 }
687 
688 /*
689  * accept_v6_message(): determine what to do with a DHCPv6 message based on the
690  *			current state.
691  *
692  *   input: dhcp_smach_t *: the state machine to handle the message
693  *	    PKT_LIST *: the DHCPv6 message
694  *	    const char *: type of message (for logging)
695  *	    uchar_t: type of message (extracted from packet)
696  *  output: void
697  */
698 
699 static void
700 accept_v6_message(dhcp_smach_t *dsmp, PKT_LIST *plp, const char *pname,
701     uchar_t recv_type)
702 {
703 	const dhcpv6_option_t *d6o;
704 	uint_t olen;
705 	const char *estr, *msg;
706 	uint_t msglen;
707 	int status;
708 
709 	/* Account for received and processed messages */
710 	dsmp->dsm_received++;
711 
712 	/* We don't yet support Reconfigure at all. */
713 	if (recv_type == DHCPV6_MSG_RECONFIGURE) {
714 		dhcpmsg(MSG_VERBOSE, "accept_v6_message: ignored Reconfigure "
715 		    "on %s", dsmp->dsm_name);
716 		free_pkt_entry(plp);
717 		return;
718 	}
719 
720 	/*
721 	 * All valid DHCPv6 messages must have our Client ID specified.
722 	 */
723 	d6o = dhcpv6_pkt_option(plp, NULL, DHCPV6_OPT_CLIENTID, &olen);
724 	olen -= sizeof (*d6o);
725 	if (d6o == NULL || olen != dsmp->dsm_cidlen ||
726 	    memcmp(d6o + 1, dsmp->dsm_cid, olen) != 0) {
727 		dhcpmsg(MSG_VERBOSE,
728 		    "accept_v6_message: discarded %s on %s: %s Client ID",
729 		    pname, dsmp->dsm_name, d6o == NULL ? "no" : "wrong");
730 		free_pkt_entry(plp);
731 		return;
732 	}
733 
734 	/*
735 	 * All valid DHCPv6 messages must have a Server ID specified.
736 	 *
737 	 * If this is a Reply and it's not in response to Solicit, Confirm,
738 	 * Rebind, or Information-Request, then it must also match the Server
739 	 * ID we're expecting.
740 	 *
741 	 * For Reply in the Solicit, Confirm, Rebind, and Information-Request
742 	 * cases, the Server ID needs to be saved.  This is done inside of
743 	 * dhcp_bound().
744 	 */
745 	d6o = dhcpv6_pkt_option(plp, NULL, DHCPV6_OPT_SERVERID, &olen);
746 	if (d6o == NULL) {
747 		dhcpmsg(MSG_DEBUG,
748 		    "accept_v6_message: discarded %s on %s: no Server ID",
749 		    pname, dsmp->dsm_name);
750 		free_pkt_entry(plp);
751 		return;
752 	}
753 	if (recv_type == DHCPV6_MSG_REPLY && dsmp->dsm_state != SELECTING &&
754 	    dsmp->dsm_state != INIT_REBOOT && dsmp->dsm_state != REBINDING &&
755 	    dsmp->dsm_state != INFORM_SENT) {
756 		olen -= sizeof (*d6o);
757 		if (olen != dsmp->dsm_serveridlen ||
758 		    memcmp(d6o + 1, dsmp->dsm_serverid, olen) != 0) {
759 			dhcpmsg(MSG_DEBUG, "accept_v6_message: discarded %s on "
760 			    "%s: wrong Server ID", pname, dsmp->dsm_name);
761 			free_pkt_entry(plp);
762 			return;
763 		}
764 	}
765 
766 	/*
767 	 * Break out of the switch if the input message needs to be discarded.
768 	 * Return from the function if the message has been enqueued or
769 	 * consumed.
770 	 */
771 	switch (dsmp->dsm_state) {
772 	case SELECTING:
773 		/* A Reply message signifies a Rapid-Commit. */
774 		if (recv_type == DHCPV6_MSG_REPLY) {
775 			if (dhcpv6_pkt_option(plp, NULL,
776 			    DHCPV6_OPT_RAPID_COMMIT, &olen) == NULL) {
777 				dhcpmsg(MSG_DEBUG, "accept_v6_message: Reply "
778 				    "on %s lacks Rapid-Commit; ignoring",
779 				    dsmp->dsm_name);
780 				break;
781 			}
782 			dhcpmsg(MSG_VERBOSE,
783 			    "accept_v6_message: rapid-commit Reply on %s",
784 			    dsmp->dsm_name);
785 			cancel_offer_timer(dsmp);
786 			goto rapid_commit;
787 		}
788 
789 		/* Otherwise, we're looking for Advertisements. */
790 		if (recv_type != DHCPV6_MSG_ADVERTISE)
791 			break;
792 
793 		/*
794 		 * Special case: if this advertisement has preference 255, then
795 		 * we must stop right now and select this server.
796 		 */
797 		d6o = dhcpv6_pkt_option(plp, NULL, DHCPV6_OPT_PREFERENCE,
798 		    &olen);
799 		if (d6o != NULL && olen == sizeof (*d6o) + 1 &&
800 		    *(const uchar_t *)(d6o + 1) == 255) {
801 			pkt_smach_enqueue(dsmp, plp);
802 			dhcpmsg(MSG_DEBUG, "accept_v6_message: preference 255;"
803 			    " immediate Request on %s", dsmp->dsm_name);
804 			dhcp_requesting(NULL, dsmp);
805 		} else {
806 			pkt_smach_enqueue(dsmp, plp);
807 		}
808 		return;
809 
810 	case PRE_BOUND:
811 	case BOUND:
812 		/*
813 		 * Not looking for anything in these states.  (If we
814 		 * implemented reconfigure, that might go here.)
815 		 */
816 		break;
817 
818 	case REQUESTING:
819 	case INIT_REBOOT:
820 	case RENEWING:
821 	case REBINDING:
822 	case INFORM_SENT:
823 		/*
824 		 * We're looking for Reply messages.
825 		 */
826 		if (recv_type != DHCPV6_MSG_REPLY)
827 			break;
828 		dhcpmsg(MSG_VERBOSE,
829 		    "accept_v6_message: received Reply message on %s",
830 		    dsmp->dsm_name);
831 	rapid_commit:
832 		/*
833 		 * Extract the status code option.  If one is present and the
834 		 * request failed, then try to go to another advertisement in
835 		 * the list or restart the selection machinery.
836 		 */
837 		d6o = dhcpv6_pkt_option(plp, NULL, DHCPV6_OPT_STATUS_CODE,
838 		    &olen);
839 		status = dhcpv6_status_code(d6o, olen, &estr, &msg, &msglen);
840 		/*
841 		 * Check for the UseMulticast status code.  If this is present,
842 		 * and if we were actually using unicast, then drop back and
843 		 * try again.  If we weren't using unicast, then just pretend
844 		 * we never saw this message -- the peer is confused.  (TAHI
845 		 * does this.)
846 		 */
847 		if (status == DHCPV6_STAT_USEMCAST) {
848 			if (IN6_IS_ADDR_MULTICAST(
849 			    &dsmp->dsm_send_dest.v6.sin6_addr)) {
850 				break;
851 			} else {
852 				free_pkt_entry(plp);
853 				dsmp->dsm_send_dest.v6.sin6_addr =
854 				    ipv6_all_dhcp_relay_and_servers;
855 				retransmit_now(dsmp);
856 				return;
857 			}
858 		}
859 		print_server_msg(dsmp, msg, msglen);
860 		/*
861 		 * We treat NoBinding at the top level as "success."  Granted,
862 		 * this doesn't make much sense, but the TAHI test suite does
863 		 * this.  NoBinding really only makes sense in the context of a
864 		 * specific IA, as it refers to the GUID:IAID binding, so
865 		 * ignoring it at the top level is safe.
866 		 */
867 		if (status == DHCPV6_STAT_SUCCESS ||
868 		    status == DHCPV6_STAT_NOBINDING) {
869 			if (dhcp_bound(dsmp, plp)) {
870 				/*
871 				 * dhcp_bound will stop retransmission on
872 				 * success, if that's called for.
873 				 */
874 				server_unicast_option(dsmp, plp);
875 			} else {
876 				stop_pkt_retransmission(dsmp);
877 				dhcpmsg(MSG_WARNING, "accept_v6_message: "
878 				    "dhcp_bound failed for %s", dsmp->dsm_name);
879 				(void) remove_hostconf(dsmp->dsm_name,
880 				    dsmp->dsm_isv6);
881 				dhcp_restart(dsmp);
882 			}
883 		} else {
884 			dhcpmsg(MSG_WARNING, "accept_v6_message: Reply: %s",
885 			    estr);
886 			stop_pkt_retransmission(dsmp);
887 			free_pkt_entry(plp);
888 			if (dsmp->dsm_state == INFORM_SENT) {
889 				(void) set_smach_state(dsmp, INIT);
890 				ipc_action_finish(dsmp, DHCP_IPC_E_SRVFAILED);
891 			} else {
892 				(void) remove_hostconf(dsmp->dsm_name,
893 				    dsmp->dsm_isv6);
894 				request_failed(dsmp);
895 			}
896 		}
897 		return;
898 
899 	case DECLINING:
900 		/*
901 		 * We're looking for Reply messages.
902 		 */
903 		if (recv_type != DHCPV6_MSG_REPLY)
904 			break;
905 		stop_pkt_retransmission(dsmp);
906 		/*
907 		 * Extract the status code option.  Note that it's not a
908 		 * failure if the server reports an error.
909 		 */
910 		d6o = dhcpv6_pkt_option(plp, NULL, DHCPV6_OPT_STATUS_CODE,
911 		    &olen);
912 		if (dhcpv6_status_code(d6o, olen, &estr, &msg,
913 		    &msglen) == DHCPV6_STAT_SUCCESS) {
914 			print_server_msg(dsmp, msg, msglen);
915 		} else {
916 			dhcpmsg(MSG_WARNING, "accept_v6_message: Reply: %s",
917 			    estr);
918 		}
919 		free_pkt_entry(plp);
920 		if (dsmp->dsm_leases == NULL) {
921 			dhcpmsg(MSG_VERBOSE, "accept_v6_message: %s has no "
922 			    "leases left", dsmp->dsm_name);
923 			dhcp_restart(dsmp);
924 		} else if (dsmp->dsm_lif_wait == 0) {
925 			(void) set_smach_state(dsmp, BOUND);
926 		} else {
927 			(void) set_smach_state(dsmp, PRE_BOUND);
928 		}
929 		return;
930 
931 	case RELEASING:
932 		/*
933 		 * We're looking for Reply messages.
934 		 */
935 		if (recv_type != DHCPV6_MSG_REPLY)
936 			break;
937 		stop_pkt_retransmission(dsmp);
938 		/*
939 		 * Extract the status code option.
940 		 */
941 		d6o = dhcpv6_pkt_option(plp, NULL, DHCPV6_OPT_STATUS_CODE,
942 		    &olen);
943 		if (dhcpv6_status_code(d6o, olen, &estr, &msg,
944 		    &msglen) == DHCPV6_STAT_SUCCESS) {
945 			print_server_msg(dsmp, msg, msglen);
946 		} else {
947 			dhcpmsg(MSG_WARNING, "accept_v6_message: Reply: %s",
948 			    estr);
949 		}
950 		free_pkt_entry(plp);
951 		finished_smach(dsmp, DHCP_IPC_SUCCESS);
952 		return;
953 	}
954 
955 	/*
956 	 * Break from above switch means that the message must be discarded.
957 	 */
958 	dhcpmsg(MSG_VERBOSE,
959 	    "accept_v6_message: discarded v6 %s on %s; state %s",
960 	    pname, dsmp->dsm_name, dhcp_state_to_string(dsmp->dsm_state));
961 	free_pkt_entry(plp);
962 }
963 
964 /*
965  * dhcp_acknak_global(): Processes reception of an ACK or NAK packet on the
966  *			 global socket -- broadcast packets for IPv4, all
967  *			 packets for DHCPv6.
968  *
969  *   input: iu_eh_t *: unused
970  *	    int: the global file descriptor the ACK/NAK arrived on
971  *	    short: unused
972  *	    iu_event_id_t: unused
973  *	    void *: unused
974  *  output: void
975  */
976 
977 /* ARGSUSED */
978 void
979 dhcp_acknak_global(iu_eh_t *ehp, int fd, short events, iu_event_id_t id,
980     void *arg)
981 {
982 	PKT_LIST	*plp;
983 	dhcp_pif_t	*pif;
984 	uchar_t		recv_type;
985 	const char	*pname;
986 	uint_t		xid;
987 	dhcp_smach_t	*dsmp;
988 	boolean_t	isv6 = (fd == v6_sock_fd);
989 	struct sockaddr_in sin;
990 	const char	*reason;
991 	size_t		sinlen = sizeof (sin);
992 	int		sock;
993 
994 	plp = recv_pkt(fd, get_max_mtu(isv6), isv6);
995 	if (plp == NULL)
996 		return;
997 
998 	recv_type = pkt_recv_type(plp);
999 	pname = pkt_type_to_string(recv_type, isv6);
1000 
1001 	/*
1002 	 * Find the corresponding state machine and pif.
1003 	 *
1004 	 * Note that DHCPv6 Reconfigure would be special: it's not the reply to
1005 	 * any transaction, and thus we would need to search on transaction ID
1006 	 * zero (all state machines) to find the match.	 However, Reconfigure
1007 	 * is not yet supported.
1008 	 */
1009 	xid = pkt_get_xid(plp->pkt, isv6);
1010 
1011 	for (dsmp = lookup_smach_by_xid(xid, NULL, isv6); dsmp != NULL;
1012 	    dsmp = lookup_smach_by_xid(xid, dsmp, isv6)) {
1013 		pif = dsmp->dsm_lif->lif_pif;
1014 		if (pif->pif_index == plp->ifindex ||
1015 		    pif->pif_under_ipmp && pif->pif_grindex == plp->ifindex)
1016 			break;
1017 	}
1018 
1019 	if (dsmp == NULL) {
1020 		dhcpmsg(MSG_VERBOSE, "dhcp_acknak_global: ignored v%d %s packet"
1021 		    " on ifindex %d: unknown state machine", isv6 ? 6 : 4,
1022 		    pname, plp->ifindex);
1023 		free_pkt_entry(plp);
1024 		return;
1025 	}
1026 
1027 	if (!isv6 && !pkt_v4_match(recv_type, DHCP_PACK|DHCP_PNAK)) {
1028 		reason = "not ACK or NAK";
1029 		goto drop;
1030 	}
1031 
1032 	/*
1033 	 * For IPv4, most packets will be handled by dhcp_packet_lif().  The
1034 	 * only exceptions are broadcast packets sent when lif_sock_ip_fd has
1035 	 * bound to something other than INADDR_ANY.
1036 	 */
1037 	if (!isv6) {
1038 		sock = dsmp->dsm_lif->lif_sock_ip_fd;
1039 
1040 		if (getsockname(sock, (struct sockaddr *)&sin, &sinlen) != -1 &&
1041 		    sin.sin_addr.s_addr == INADDR_ANY) {
1042 			reason = "handled by lif_sock_ip_fd";
1043 			goto drop;
1044 		}
1045 	}
1046 
1047 	/*
1048 	 * We've got a packet; make sure it's acceptable and cancel the REQUEST
1049 	 * retransmissions.
1050 	 */
1051 	if (isv6)
1052 		accept_v6_message(dsmp, plp, pname, recv_type);
1053 	else
1054 		accept_v4_acknak(dsmp, plp);
1055 	return;
1056 drop:
1057 	dhcpmsg(MSG_VERBOSE, "dhcp_acknak_global: ignored v%d %s packet for %s "
1058 	    "received on global socket: %s", isv6 ? 6 : 4, pname, pif->pif_name,
1059 	    reason);
1060 	free_pkt_entry(plp);
1061 }
1062 
1063 /*
1064  * request_failed(): Attempt to request an address has failed.  Take an
1065  *		     appropriate action.
1066  *
1067  *   input: dhcp_smach_t *: state machine that has failed
1068  *  output: void
1069  */
1070 
1071 static void
1072 request_failed(dhcp_smach_t *dsmp)
1073 {
1074 	PKT_LIST *offer;
1075 
1076 	dsmp->dsm_server = ipv6_all_dhcp_relay_and_servers;
1077 	if ((offer = select_best(dsmp)) != NULL) {
1078 		insque(offer, &dsmp->dsm_recv_pkt_list);
1079 		dhcp_requesting(NULL, dsmp);
1080 	} else {
1081 		dhcpmsg(MSG_INFO, "no offers left on %s; restarting",
1082 		    dsmp->dsm_name);
1083 		dhcp_selecting(dsmp);
1084 	}
1085 }
1086 
1087 /*
1088  * dhcp_packet_lif(): Processes reception of an ACK, NAK, or OFFER packet on
1089  *		      a given logical interface for IPv4 (only).
1090  *
1091  *   input: iu_eh_t *: unused
1092  *	    int: the file descriptor the packet arrived on
1093  *	    short: unused
1094  *	    iu_event_id_t: the id of this event callback with the handler
1095  *	    void *: pointer to logical interface receiving message
1096  *  output: void
1097  */
1098 
1099 /* ARGSUSED */
1100 void
1101 dhcp_packet_lif(iu_eh_t *ehp, int fd, short events, iu_event_id_t id,
1102     void *arg)
1103 {
1104 	dhcp_lif_t	*lif = arg;
1105 	PKT_LIST	*plp;
1106 	uchar_t		recv_type;
1107 	const char	*pname;
1108 	uint_t		xid;
1109 	dhcp_smach_t	*dsmp;
1110 
1111 	if ((plp = recv_pkt(fd, lif->lif_pif->pif_mtu, B_FALSE)) == NULL)
1112 		return;
1113 
1114 	recv_type = pkt_recv_type(plp);
1115 	pname = pkt_type_to_string(recv_type, B_FALSE);
1116 
1117 	if (!pkt_v4_match(recv_type,
1118 	    DHCP_PACK | DHCP_PNAK | DHCP_PUNTYPED | DHCP_POFFER)) {
1119 		dhcpmsg(MSG_VERBOSE, "dhcp_packet_lif: ignored v4 %s packet "
1120 		    "received via LIF %s", pname, lif->lif_name);
1121 		free_pkt_entry(plp);
1122 		return;
1123 	}
1124 
1125 	/*
1126 	 * Find the corresponding state machine.
1127 	 */
1128 	xid = pkt_get_xid(plp->pkt, B_FALSE);
1129 	for (dsmp = lookup_smach_by_xid(xid, NULL, B_FALSE); dsmp != NULL;
1130 	    dsmp = lookup_smach_by_xid(xid, dsmp, B_FALSE)) {
1131 		if (dsmp->dsm_lif == lif)
1132 			break;
1133 	}
1134 
1135 	if (dsmp == NULL)
1136 		goto drop;
1137 
1138 	if (pkt_v4_match(recv_type, DHCP_PACK|DHCP_PNAK)) {
1139 		/*
1140 		 * We've got an ACK/NAK; make sure it's acceptable and cancel
1141 		 * the REQUEST retransmissions.
1142 		 */
1143 		accept_v4_acknak(dsmp, plp);
1144 	} else {
1145 		if (is_bound_state(dsmp->dsm_state))
1146 			goto drop;
1147 		/*
1148 		 * Must be an OFFER or a BOOTP message: enqueue it for later
1149 		 * processing by select_best().
1150 		 */
1151 		pkt_smach_enqueue(dsmp, plp);
1152 	}
1153 	return;
1154 drop:
1155 	dhcpmsg(MSG_VERBOSE, "dhcp_packet_lif: ignored %s packet xid "
1156 	    "%x received via LIF %s; %s", pname, xid, lif->lif_name,
1157 	    dsmp == NULL ? "unknown state machine" : "bound");
1158 	free_pkt_entry(plp);
1159 }
1160 
1161 /*
1162  * dhcp_restart(): restarts DHCP (from INIT) on a given state machine, but only
1163  *		   if we're leasing addresses.  Doesn't restart for information-
1164  *		   only interfaces.
1165  *
1166  *   input: dhcp_smach_t *: the state machine to restart DHCP on
1167  *  output: void
1168  */
1169 
1170 void
1171 dhcp_restart(dhcp_smach_t *dsmp)
1172 {
1173 	if (dsmp->dsm_state == INFORM_SENT || dsmp->dsm_state == INFORMATION)
1174 		return;
1175 
1176 	/*
1177 	 * As we're returning to INIT state, we need to discard any leases we
1178 	 * may have, and (for v4) canonize the LIF.  There's a bit of tension
1179 	 * between keeping around a possibly still working address, and obeying
1180 	 * the RFCs.  A more elaborate design would be to mark the addresses as
1181 	 * DEPRECATED, and then start a removal timer.  Such a design would
1182 	 * probably compromise testing.
1183 	 */
1184 	deprecate_leases(dsmp);
1185 
1186 	if (!set_start_timer(dsmp)) {
1187 		dhcpmsg(MSG_ERROR, "dhcp_restart: cannot schedule dhcp_start, "
1188 		    "reverting to INIT state on %s", dsmp->dsm_name);
1189 
1190 		(void) set_smach_state(dsmp, INIT);
1191 		dsmp->dsm_dflags |= DHCP_IF_FAILED;
1192 		ipc_action_finish(dsmp, DHCP_IPC_E_MEMORY);
1193 	} else {
1194 		dhcpmsg(MSG_DEBUG, "dhcp_restart: restarting DHCP on %s",
1195 		    dsmp->dsm_name);
1196 	}
1197 }
1198 
1199 /*
1200  * stop_requesting(): decides when to stop retransmitting REQUESTs
1201  *
1202  *   input: dhcp_smach_t *: the state machine REQUESTs are being sent from
1203  *	    unsigned int: the number of REQUESTs sent so far
1204  *  output: boolean_t: B_TRUE if retransmissions should stop
1205  */
1206 
1207 static boolean_t
1208 stop_requesting(dhcp_smach_t *dsmp, unsigned int n_requests)
1209 {
1210 	uint_t maxreq;
1211 
1212 	maxreq = dsmp->dsm_isv6 ? DHCPV6_REQ_MAX_RC : DHCP_MAX_REQUESTS;
1213 	if (n_requests >= maxreq) {
1214 
1215 		dhcpmsg(MSG_INFO, "no ACK/NAK/Reply to REQUEST on %s",
1216 		    dsmp->dsm_name);
1217 
1218 		request_failed(dsmp);
1219 		return (B_TRUE);
1220 	} else {
1221 		return (B_FALSE);
1222 	}
1223 }
1224