xref: /reactos/base/services/dhcpcsvc/dhcp/dhclient.c (revision 803b5e13)
1 /*	$OpenBSD: dhclient.c,v 1.62 2004/12/05 18:35:51 deraadt Exp $	*/
2 
3 /*
4  * Copyright 2004 Henning Brauer <henning@openbsd.org>
5  * Copyright (c) 1995, 1996, 1997, 1998, 1999
6  * The Internet Software Consortium.    All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of The Internet Software Consortium nor the names
18  *    of its contributors may be used to endorse or promote products derived
19  *    from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
22  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
26  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * This software has been written for the Internet Software Consortium
36  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
37  * Enterprises.  To learn more about the Internet Software Consortium,
38  * see ``http://www.vix.com/isc''.  To learn more about Vixie
39  * Enterprises, see ``http://www.vix.com''.
40  *
41  * This client was substantially modified and enhanced by Elliot Poger
42  * for use on Linux while he was working on the MosquitoNet project at
43  * Stanford.
44  *
45  * The current version owes much to Elliot's Linux enhancements, but
46  * was substantially reorganized and partially rewritten by Ted Lemon
47  * so as to use the same networking framework that the Internet Software
48  * Consortium DHCP server uses.   Much system-specific configuration code
49  * was moved into a shell script so that as support for more operating
50  * systems is added, it will not be necessary to port and maintain
51  * system-specific configuration code to these operating systems - instead,
52  * the shell script can invoke the native tools to accomplish the same
53  * purpose.
54  */
55 
56 #include <rosdhcp.h>
57 
58 #define	PERIOD 0x2e
59 #define	hyphenchar(c) ((c) == 0x2d)
60 #define	bslashchar(c) ((c) == 0x5c)
61 #define	periodchar(c) ((c) == PERIOD)
62 #define	asterchar(c) ((c) == 0x2a)
63 #define	alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
64 	    ((c) >= 0x61 && (c) <= 0x7a))
65 #define	digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
66 
67 #define	borderchar(c) (alphachar(c) || digitchar(c))
68 #define	middlechar(c) (borderchar(c) || hyphenchar(c))
69 #define	domainchar(c) ((c) > 0x20 && (c) < 0x7f)
70 
71 unsigned long debug_trace_level = 0; /* DEBUG_ULTRA */
72 
73 char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
74 char *path_dhclient_db = NULL;
75 
76 int log_perror = 1;
77 int privfd;
78 //int nullfd = -1;
79 
80 struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
81 struct in_addr inaddr_any;
82 struct sockaddr_in sockaddr_broadcast;
83 
84 /*
85  * ASSERT_STATE() does nothing now; it used to be
86  * assert (state_is == state_shouldbe).
87  */
88 #define ASSERT_STATE(state_is, state_shouldbe) {}
89 
90 #define TIME_MAX 2147483647
91 
92 int		log_priority;
93 int		no_daemon;
94 int		unknown_ok = 1;
95 int		routefd;
96 
97 void		 usage(void);
98 int		 check_option(struct client_lease *l, int option);
99 int		 ipv4addrs(char * buf);
100 int		 res_hnok(const char *dn);
101 char		*option_as_string(unsigned int code, unsigned char *data, int len);
102 int		 fork_privchld(int, int);
103 int              check_arp( struct interface_info *ip, struct client_lease *lp );
104 
105 #define	ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
106 
107 time_t	scripttime;
108 
109 
110 int
111 init_client(void)
112 {
113     ApiInit();
114     AdapterInit();
115 
116     tzset();
117 
118     memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
119     sockaddr_broadcast.sin_family = AF_INET;
120     sockaddr_broadcast.sin_port = htons(REMOTE_PORT);
121     sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
122     inaddr_any.s_addr = INADDR_ANY;
123     bootp_packet_handler = do_packet;
124 
125     if (PipeInit() == INVALID_HANDLE_VALUE)
126     {
127         DbgPrint("DHCPCSVC: PipeInit() failed!\n");
128         AdapterStop();
129         ApiFree();
130         return 0; // FALSE
131     }
132 
133     return 1; // TRUE
134 }
135 
136 void
137 stop_client(void)
138 {
139     // AdapterStop();
140     // ApiFree();
141     /* FIXME: Close pipe and kill pipe thread */
142 }
143 
144 /* XXX Implement me */
145 int check_arp( struct interface_info *ip, struct client_lease *lp ) {
146     return 1;
147 }
148 
149 /*
150  * Individual States:
151  *
152  * Each routine is called from the dhclient_state_machine() in one of
153  * these conditions:
154  * -> entering INIT state
155  * -> recvpacket_flag == 0: timeout in this state
156  * -> otherwise: received a packet in this state
157  *
158  * Return conditions as handled by dhclient_state_machine():
159  * Returns 1, sendpacket_flag = 1: send packet, reset timer.
160  * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
161  * Returns 0: finish the nap which was interrupted for no good reason.
162  *
163  * Several per-interface variables are used to keep track of the process:
164  *   active_lease: the lease that is being used on the interface
165  *                 (null pointer if not configured yet).
166  *   offered_leases: leases corresponding to DHCPOFFER messages that have
167  *                   been sent to us by DHCP servers.
168  *   acked_leases: leases corresponding to DHCPACK messages that have been
169  *                 sent to us by DHCP servers.
170  *   sendpacket: DHCP packet we're trying to send.
171  *   destination: IP address to send sendpacket to
172  * In addition, there are several relevant per-lease variables.
173  *   T1_expiry, T2_expiry, lease_expiry: lease milestones
174  * In the active lease, these control the process of renewing the lease;
175  * In leases on the acked_leases list, this simply determines when we
176  * can no longer legitimately use the lease.
177  */
178 
179 void
180 state_reboot(void *ipp)
181 {
182 	struct interface_info *ip = ipp;
183 	ULONG foo = (ULONG) GetTickCount();
184 
185 	/* If we don't remember an active lease, go straight to INIT. */
186 	if (!ip->client->active || ip->client->active->is_bootp) {
187 		state_init(ip);
188 		return;
189 	}
190 
191 	/* We are in the rebooting state. */
192 	ip->client->state = S_REBOOTING;
193 
194 	/* make_request doesn't initialize xid because it normally comes
195 	   from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
196 	   so pick an xid now. */
197 	ip->client->xid = RtlRandom(&foo);
198 
199 	/* Make a DHCPREQUEST packet, and set appropriate per-interface
200 	   flags. */
201 	make_request(ip, ip->client->active);
202 	ip->client->destination = iaddr_broadcast;
203 	time(&ip->client->first_sending);
204 	ip->client->interval = ip->client->config->initial_interval;
205 
206 	/* Zap the medium list... */
207 	ip->client->medium = NULL;
208 
209 	/* Send out the first DHCPREQUEST packet. */
210 	send_request(ip);
211 }
212 
213 /*
214  * Called when a lease has completely expired and we've
215  * been unable to renew it.
216  */
217 void
218 state_init(void *ipp)
219 {
220 	struct interface_info *ip = ipp;
221 
222 	ASSERT_STATE(state, S_INIT);
223 
224 	/* Make a DHCPDISCOVER packet, and set appropriate per-interface
225 	   flags. */
226 	make_discover(ip, ip->client->active);
227 	ip->client->xid = ip->client->packet.xid;
228 	ip->client->destination = iaddr_broadcast;
229 	ip->client->state = S_SELECTING;
230 	time(&ip->client->first_sending);
231 	ip->client->interval = ip->client->config->initial_interval;
232 
233 	/* Add an immediate timeout to cause the first DHCPDISCOVER packet
234 	   to go out. */
235 	send_discover(ip);
236 }
237 
238 /*
239  * state_selecting is called when one or more DHCPOFFER packets
240  * have been received and a configurable period of time has passed.
241  */
242 void
243 state_selecting(void *ipp)
244 {
245 	struct interface_info *ip = ipp;
246 	struct client_lease *lp, *next, *picked;
247         time_t cur_time;
248 
249 	ASSERT_STATE(state, S_SELECTING);
250 
251         time(&cur_time);
252 
253 	/* Cancel state_selecting and send_discover timeouts, since either
254 	   one could have got us here. */
255 	cancel_timeout(state_selecting, ip);
256 	cancel_timeout(send_discover, ip);
257 
258 	/* We have received one or more DHCPOFFER packets.   Currently,
259 	   the only criterion by which we judge leases is whether or
260 	   not we get a response when we arp for them. */
261 	picked = NULL;
262 	for (lp = ip->client->offered_leases; lp; lp = next) {
263 		next = lp->next;
264 
265 		/* Check to see if we got an ARPREPLY for the address
266 		   in this particular lease. */
267 		if (!picked) {
268                     if( !check_arp(ip,lp) ) goto freeit;
269                     picked = lp;
270                     picked->next = NULL;
271 		} else {
272 freeit:
273 			free_client_lease(lp);
274 		}
275 	}
276 	ip->client->offered_leases = NULL;
277 
278 	/* If we just tossed all the leases we were offered, go back
279 	   to square one. */
280 	if (!picked) {
281 		ip->client->state = S_INIT;
282 		state_init(ip);
283 		return;
284 	}
285 
286 	/* If it was a BOOTREPLY, we can just take the address right now. */
287 	if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
288 		ip->client->new = picked;
289 
290 		/* Make up some lease expiry times
291 		   XXX these should be configurable. */
292 		ip->client->new->expiry = cur_time + 12000;
293 		ip->client->new->renewal += cur_time + 8000;
294 		ip->client->new->rebind += cur_time + 10000;
295 
296 		ip->client->state = S_REQUESTING;
297 
298 		/* Bind to the address we received. */
299 		bind_lease(ip);
300 		return;
301 	}
302 
303 	/* Go to the REQUESTING state. */
304 	ip->client->destination = iaddr_broadcast;
305 	ip->client->state = S_REQUESTING;
306 	ip->client->first_sending = cur_time;
307 	ip->client->interval = ip->client->config->initial_interval;
308 
309 	/* Make a DHCPREQUEST packet from the lease we picked. */
310 	make_request(ip, picked);
311 	ip->client->xid = ip->client->packet.xid;
312 
313 	/* Toss the lease we picked - we'll get it back in a DHCPACK. */
314 	free_client_lease(picked);
315 
316 	/* Add an immediate timeout to send the first DHCPREQUEST packet. */
317 	send_request(ip);
318 }
319 
320 /* state_requesting is called when we receive a DHCPACK message after
321    having sent out one or more DHCPREQUEST packets. */
322 
323 void
324 dhcpack(struct packet *packet)
325 {
326 	struct interface_info *ip = packet->interface;
327 	struct client_lease *lease;
328         time_t cur_time;
329 
330         time(&cur_time);
331 
332 	/* If we're not receptive to an offer right now, or if the offer
333 	   has an unrecognizable transaction id, then just drop it. */
334 	if (packet->interface->client->xid != packet->raw->xid ||
335 	    (packet->interface->hw_address.hlen != packet->raw->hlen) ||
336 	    (memcmp(packet->interface->hw_address.haddr,
337 	    packet->raw->chaddr, packet->raw->hlen)))
338 		return;
339 
340 	if (ip->client->state != S_REBOOTING &&
341 	    ip->client->state != S_REQUESTING &&
342 	    ip->client->state != S_RENEWING &&
343 	    ip->client->state != S_REBINDING)
344 		return;
345 
346 	note("DHCPACK from %s", piaddr(packet->client_addr));
347 
348 	lease = packet_to_lease(packet);
349 	if (!lease) {
350 		note("packet_to_lease failed.");
351 		return;
352 	}
353 
354 	ip->client->new = lease;
355 
356 	/* Stop resending DHCPREQUEST. */
357 	cancel_timeout(send_request, ip);
358 
359 	/* Figure out the lease time. */
360 	if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data)
361 		ip->client->new->expiry = getULong(
362 		    ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
363 	else
364 		ip->client->new->expiry = DHCP_DEFAULT_LEASE_TIME;
365 	/* A number that looks negative here is really just very large,
366 	   because the lease expiry offset is unsigned. */
367 	if (ip->client->new->expiry < 0)
368 		ip->client->new->expiry = TIME_MAX;
369 	/* XXX should be fixed by resetting the client state */
370 	if (ip->client->new->expiry < 60)
371 		ip->client->new->expiry = 60;
372 
373 	/* Take the server-provided renewal time if there is one;
374 	   otherwise figure it out according to the spec. */
375 	if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len)
376 		ip->client->new->renewal = getULong(
377 		    ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data);
378 	else
379 		ip->client->new->renewal = ip->client->new->expiry / 2;
380 
381 	/* Same deal with the rebind time. */
382 	if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len)
383 		ip->client->new->rebind = getULong(
384 		    ip->client->new->options[DHO_DHCP_REBINDING_TIME].data);
385 	else
386 		ip->client->new->rebind = ip->client->new->renewal +
387 		    ip->client->new->renewal / 2 + ip->client->new->renewal / 4;
388 
389 #ifdef __REACTOS__
390 	ip->client->new->obtained = cur_time;
391 #endif
392 	ip->client->new->expiry += cur_time;
393 	/* Lease lengths can never be negative. */
394 	if (ip->client->new->expiry < cur_time)
395 		ip->client->new->expiry = TIME_MAX;
396 	ip->client->new->renewal += cur_time;
397 	if (ip->client->new->renewal < cur_time)
398 		ip->client->new->renewal = TIME_MAX;
399 	ip->client->new->rebind += cur_time;
400 	if (ip->client->new->rebind < cur_time)
401 		ip->client->new->rebind = TIME_MAX;
402 
403 	bind_lease(ip);
404 }
405 
406 void set_name_servers( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) {
407     CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
408     HKEY RegKey;
409 
410     strcat(Buffer, Adapter->DhclientInfo.name);
411     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &RegKey ) != ERROR_SUCCESS)
412         return;
413 
414 
415     if( new_lease->options[DHO_DOMAIN_NAME_SERVERS].len ) {
416 
417         struct iaddr nameserver;
418         char *nsbuf;
419         int i, addrs =
420             new_lease->options[DHO_DOMAIN_NAME_SERVERS].len / sizeof(ULONG);
421 
422         nsbuf = malloc( addrs * sizeof(IP_ADDRESS_STRING) );
423 
424         if( nsbuf) {
425             nsbuf[0] = 0;
426             for( i = 0; i < addrs; i++ ) {
427                 nameserver.len = sizeof(ULONG);
428                 memcpy( nameserver.iabuf,
429                         new_lease->options[DHO_DOMAIN_NAME_SERVERS].data +
430                         (i * sizeof(ULONG)), sizeof(ULONG) );
431                 strcat( nsbuf, piaddr(nameserver) );
432                 if( i != addrs-1 ) strcat( nsbuf, "," );
433             }
434 
435             DH_DbgPrint(MID_TRACE,("Setting DhcpNameserver: %s\n", nsbuf));
436 
437             RegSetValueExA( RegKey, "DhcpNameServer", 0, REG_SZ,
438                            (LPBYTE)nsbuf, strlen(nsbuf) + 1 );
439             free( nsbuf );
440         }
441 
442     } else {
443             RegDeleteValueW( RegKey, L"DhcpNameServer" );
444     }
445 
446     RegCloseKey( RegKey );
447 
448 }
449 
450 void
451 set_domain(PDHCP_ADAPTER Adapter,
452            struct client_lease *new_lease)
453 {
454     CHAR Buffer1[MAX_PATH] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
455     CHAR Buffer2[MAX_PATH] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
456     HKEY RegKey1, RegKey2;
457 
458     strcat(Buffer1, Adapter->DhclientInfo.name);
459 
460     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer1, 0, KEY_WRITE, &RegKey1 ) != ERROR_SUCCESS)
461     {
462         return;
463     }
464 
465     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer2, 0, KEY_WRITE, &RegKey2 ) != ERROR_SUCCESS)
466     {
467         RegCloseKey(RegKey1);
468         return;
469     }
470 
471     if (new_lease->options[DHO_DOMAIN_NAME].len)
472     {
473         DH_DbgPrint(MID_TRACE, ("Setting DhcpDomain: %s\n", new_lease->options[DHO_DOMAIN_NAME].data));
474 
475         RegSetValueExA(RegKey1,
476                        "DhcpDomain",
477                        0,
478                        REG_SZ,
479                        (LPBYTE)new_lease->options[DHO_DOMAIN_NAME].data,
480                        new_lease->options[DHO_DOMAIN_NAME].len);
481 
482         RegSetValueExA(RegKey2,
483                        "DhcpDomain",
484                        0,
485                        REG_SZ,
486                        (LPBYTE)new_lease->options[DHO_DOMAIN_NAME].data,
487                        new_lease->options[DHO_DOMAIN_NAME].len);
488     }
489     else
490     {
491         RegDeleteValueW(RegKey1, L"DhcpDomain");
492         RegDeleteValueW(RegKey2, L"DhcpDomain");
493     }
494 
495     RegCloseKey(RegKey1);
496     RegCloseKey(RegKey2);
497 
498 }
499 
500 void setup_adapter( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) {
501     CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
502     struct iaddr netmask;
503     HKEY hkey;
504     int i;
505     DWORD dwEnableDHCP;
506 
507     strcat(Buffer, Adapter->DhclientInfo.name);
508     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &hkey) != ERROR_SUCCESS)
509         hkey = NULL;
510 
511 
512     if( Adapter->NteContext )
513     {
514         DeleteIPAddress( Adapter->NteContext );
515         Adapter->NteContext = 0;
516     }
517 
518     /* Set up our default router if we got one from the DHCP server */
519     if( new_lease->options[DHO_SUBNET_MASK].len ) {
520         NTSTATUS Status;
521 
522         memcpy( netmask.iabuf,
523                 new_lease->options[DHO_SUBNET_MASK].data,
524                 new_lease->options[DHO_SUBNET_MASK].len );
525         Status = AddIPAddress
526             ( *((ULONG*)new_lease->address.iabuf),
527               *((ULONG*)netmask.iabuf),
528               Adapter->IfMib.dwIndex,
529               &Adapter->NteContext,
530               &Adapter->NteInstance );
531         if (hkey) {
532             RegSetValueExA(hkey, "DhcpIPAddress", 0, REG_SZ, (LPBYTE)piaddr(new_lease->address), strlen(piaddr(new_lease->address))+1);
533             Buffer[0] = '\0';
534             for(i = 0; i < new_lease->options[DHO_SUBNET_MASK].len; i++)
535             {
536                 sprintf(&Buffer[strlen(Buffer)], "%u", new_lease->options[DHO_SUBNET_MASK].data[i]);
537                 if (i + 1 < new_lease->options[DHO_SUBNET_MASK].len)
538                     strcat(Buffer, ".");
539             }
540             RegSetValueExA(hkey, "DhcpSubnetMask", 0, REG_SZ, (LPBYTE)Buffer, strlen(Buffer)+1);
541             dwEnableDHCP = 1;
542             RegSetValueExA(hkey, "EnableDHCP", 0, REG_DWORD, (LPBYTE)&dwEnableDHCP, sizeof(DWORD));
543         }
544 
545         if( !NT_SUCCESS(Status) )
546             warning("AddIPAddress: %lx\n", Status);
547     }
548 
549     if( new_lease->options[DHO_ROUTERS].len ) {
550         NTSTATUS Status;
551 
552         Adapter->RouterMib.dwForwardDest = 0; /* Default route */
553         Adapter->RouterMib.dwForwardMask = 0;
554         Adapter->RouterMib.dwForwardMetric1 = 1;
555         Adapter->RouterMib.dwForwardIfIndex = Adapter->IfMib.dwIndex;
556 
557         if( Adapter->RouterMib.dwForwardNextHop ) {
558             /* If we set a default route before, delete it before continuing */
559             DeleteIpForwardEntry( &Adapter->RouterMib );
560         }
561 
562         Adapter->RouterMib.dwForwardNextHop =
563             *((ULONG*)new_lease->options[DHO_ROUTERS].data);
564 
565         Status = CreateIpForwardEntry( &Adapter->RouterMib );
566 
567         if( !NT_SUCCESS(Status) )
568             warning("CreateIpForwardEntry: %lx\n", Status);
569 
570         if (hkey) {
571             Buffer[0] = '\0';
572             for(i = 0; i < new_lease->options[DHO_ROUTERS].len; i++)
573             {
574                 sprintf(&Buffer[strlen(Buffer)], "%u", new_lease->options[DHO_ROUTERS].data[i]);
575                 if (i + 1 < new_lease->options[DHO_ROUTERS].len)
576                     strcat(Buffer, ".");
577             }
578             RegSetValueExA(hkey, "DhcpDefaultGateway", 0, REG_SZ, (LPBYTE)Buffer, strlen(Buffer)+1);
579         }
580     }
581 
582     if (hkey)
583         RegCloseKey(hkey);
584 }
585 
586 
587 void
588 bind_lease(struct interface_info *ip)
589 {
590     PDHCP_ADAPTER Adapter;
591     struct client_lease *new_lease = ip->client->new;
592     time_t cur_time;
593 
594     time(&cur_time);
595 
596     /* Remember the medium. */
597     ip->client->new->medium = ip->client->medium;
598 
599     /* Replace the old active lease with the new one. */
600     if (ip->client->active)
601         free_client_lease(ip->client->active);
602     ip->client->active = ip->client->new;
603     ip->client->new = NULL;
604 
605     /* Set up a timeout to start the renewal process. */
606     /* Timeout of zero means no timeout (some implementations seem to use
607      * one day).
608      */
609     if( ip->client->active->renewal - cur_time )
610         add_timeout(ip->client->active->renewal, state_bound, ip);
611 
612     note("bound to %s -- renewal in %ld seconds.",
613          piaddr(ip->client->active->address),
614          (long int)(ip->client->active->renewal - cur_time));
615 
616     ip->client->state = S_BOUND;
617 
618     Adapter = AdapterFindInfo( ip );
619 
620     if( Adapter )  setup_adapter( Adapter, new_lease );
621     else {
622         warning("Could not find adapter for info %p\n", ip);
623         return;
624     }
625     set_name_servers( Adapter, new_lease );
626     set_domain( Adapter, new_lease );
627 }
628 
629 /*
630  * state_bound is called when we've successfully bound to a particular
631  * lease, but the renewal time on that lease has expired.   We are
632  * expected to unicast a DHCPREQUEST to the server that gave us our
633  * original lease.
634  */
635 void
636 state_bound(void *ipp)
637 {
638 	struct interface_info *ip = ipp;
639 
640 	ASSERT_STATE(state, S_BOUND);
641 
642 	/* T1 has expired. */
643 	make_request(ip, ip->client->active);
644 	ip->client->xid = ip->client->packet.xid;
645 
646 	if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
647 		memcpy(ip->client->destination.iabuf, ip->client->active->
648 		    options[DHO_DHCP_SERVER_IDENTIFIER].data, 4);
649 		ip->client->destination.len = 4;
650 	} else
651 		ip->client->destination = iaddr_broadcast;
652 
653 	time(&ip->client->first_sending);
654 	ip->client->interval = ip->client->config->initial_interval;
655 	ip->client->state = S_RENEWING;
656 
657 	/* Send the first packet immediately. */
658 	send_request(ip);
659 }
660 
661 void
662 bootp(struct packet *packet)
663 {
664 	struct iaddrlist *ap;
665 
666 	if (packet->raw->op != BOOTREPLY)
667 		return;
668 
669 	/* If there's a reject list, make sure this packet's sender isn't
670 	   on it. */
671 	for (ap = packet->interface->client->config->reject_list;
672 	    ap; ap = ap->next) {
673 		if (addr_eq(packet->client_addr, ap->addr)) {
674 			note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
675 			return;
676 		}
677 	}
678 	dhcpoffer(packet);
679 }
680 
681 void
682 dhcp(struct packet *packet)
683 {
684 	struct iaddrlist *ap;
685 	void (*handler)(struct packet *);
686 	char *type;
687 
688 	switch (packet->packet_type) {
689 	case DHCPOFFER:
690 		handler = dhcpoffer;
691 		type = "DHCPOFFER";
692 		break;
693 	case DHCPNAK:
694 		handler = dhcpnak;
695 		type = "DHCPNACK";
696 		break;
697 	case DHCPACK:
698 		handler = dhcpack;
699 		type = "DHCPACK";
700 		break;
701 	default:
702 		return;
703 	}
704 
705 	/* If there's a reject list, make sure this packet's sender isn't
706 	   on it. */
707 	for (ap = packet->interface->client->config->reject_list;
708 	    ap; ap = ap->next) {
709 		if (addr_eq(packet->client_addr, ap->addr)) {
710 			note("%s from %s rejected.", type, piaddr(ap->addr));
711 			return;
712 		}
713 	}
714 	(*handler)(packet);
715 }
716 
717 void
718 dhcpoffer(struct packet *packet)
719 {
720 	struct interface_info *ip = packet->interface;
721 	struct client_lease *lease, *lp;
722 	int i;
723 	int arp_timeout_needed = 0, stop_selecting;
724 	char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
725 	    "DHCPOFFER" : "BOOTREPLY";
726         time_t cur_time;
727 
728         time(&cur_time);
729 
730 	/* If we're not receptive to an offer right now, or if the offer
731 	   has an unrecognizable transaction id, then just drop it. */
732 	if (ip->client->state != S_SELECTING ||
733             packet->interface->client->xid != packet->raw->xid ||
734             (packet->interface->hw_address.hlen != packet->raw->hlen) ||
735 	    (memcmp(packet->interface->hw_address.haddr,
736 	    packet->raw->chaddr, packet->raw->hlen)))
737 		return;
738 
739 	note("%s from %s", name, piaddr(packet->client_addr));
740 
741 
742 	/* If this lease doesn't supply the minimum required parameters,
743 	   blow it off. */
744 	for (i = 0; ip->client->config->required_options[i]; i++) {
745 		if (!packet->options[ip->client->config->
746 		    required_options[i]].len) {
747 			note("%s isn't satisfactory.", name);
748 			return;
749 		}
750 	}
751 
752 	/* If we've already seen this lease, don't record it again. */
753 	for (lease = ip->client->offered_leases;
754 	    lease; lease = lease->next) {
755 		if (lease->address.len == sizeof(packet->raw->yiaddr) &&
756 		    !memcmp(lease->address.iabuf,
757 		    &packet->raw->yiaddr, lease->address.len)) {
758 			debug("%s already seen.", name);
759 			return;
760 		}
761 	}
762 
763 	lease = packet_to_lease(packet);
764 	if (!lease) {
765 		note("packet_to_lease failed.");
766 		return;
767 	}
768 
769 	/* If this lease was acquired through a BOOTREPLY, record that
770 	   fact. */
771 	if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
772 		lease->is_bootp = 1;
773 
774 	/* Record the medium under which this lease was offered. */
775 	lease->medium = ip->client->medium;
776 
777 	/* Send out an ARP Request for the offered IP address. */
778         if( !check_arp( ip, lease ) ) {
779             note("Arp check failed\n");
780             return;
781         }
782 
783 	/* Figure out when we're supposed to stop selecting. */
784 	stop_selecting =
785 	    ip->client->first_sending + ip->client->config->select_interval;
786 
787 	/* If this is the lease we asked for, put it at the head of the
788 	   list, and don't mess with the arp request timeout. */
789 	if (lease->address.len == ip->client->requested_address.len &&
790 	    !memcmp(lease->address.iabuf,
791 	    ip->client->requested_address.iabuf,
792 	    ip->client->requested_address.len)) {
793 		lease->next = ip->client->offered_leases;
794 		ip->client->offered_leases = lease;
795 	} else {
796 		/* If we already have an offer, and arping for this
797 		   offer would take us past the selection timeout,
798 		   then don't extend the timeout - just hope for the
799 		   best. */
800 		if (ip->client->offered_leases &&
801 		    (cur_time + arp_timeout_needed) > stop_selecting)
802 			arp_timeout_needed = 0;
803 
804 		/* Put the lease at the end of the list. */
805 		lease->next = NULL;
806 		if (!ip->client->offered_leases)
807 			ip->client->offered_leases = lease;
808 		else {
809 			for (lp = ip->client->offered_leases; lp->next;
810 			    lp = lp->next)
811 				;	/* nothing */
812 			lp->next = lease;
813 		}
814 	}
815 
816 	/* If we're supposed to stop selecting before we've had time
817 	   to wait for the ARPREPLY, add some delay to wait for
818 	   the ARPREPLY. */
819 	if (stop_selecting - cur_time < arp_timeout_needed)
820 		stop_selecting = cur_time + arp_timeout_needed;
821 
822 	/* If the selecting interval has expired, go immediately to
823 	   state_selecting().  Otherwise, time out into
824 	   state_selecting at the select interval. */
825 	if (stop_selecting <= 0)
826 		state_selecting(ip);
827 	else {
828 		add_timeout(stop_selecting, state_selecting, ip);
829 		cancel_timeout(send_discover, ip);
830 	}
831 }
832 
833 /* Allocate a client_lease structure and initialize it from the parameters
834    in the specified packet. */
835 
836 struct client_lease *
837 packet_to_lease(struct packet *packet)
838 {
839 	struct client_lease *lease;
840 	int i;
841 
842 	lease = malloc(sizeof(struct client_lease));
843 
844 	if (!lease) {
845 		warning("dhcpoffer: no memory to record lease.");
846 		return (NULL);
847 	}
848 
849 	memset(lease, 0, sizeof(*lease));
850 
851 	/* Copy the lease options. */
852 	for (i = 0; i < 256; i++) {
853 		if (packet->options[i].len) {
854 			lease->options[i].data =
855 			    malloc(packet->options[i].len + 1);
856 			if (!lease->options[i].data) {
857 				warning("dhcpoffer: no memory for option %d", i);
858 				free_client_lease(lease);
859 				return (NULL);
860 			} else {
861 				memcpy(lease->options[i].data,
862 				    packet->options[i].data,
863 				    packet->options[i].len);
864 				lease->options[i].len =
865 				    packet->options[i].len;
866 				lease->options[i].data[lease->options[i].len] =
867 				    0;
868 			}
869 			if (!check_option(lease,i)) {
870 				/* ignore a bogus lease offer */
871 				warning("Invalid lease option - ignoring offer");
872 				free_client_lease(lease);
873 				return (NULL);
874 			}
875 		}
876 	}
877 
878 	lease->address.len = sizeof(packet->raw->yiaddr);
879 	memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
880 #ifdef __REACTOS__
881 	lease->serveraddress.len = sizeof(packet->raw->siaddr);
882 	memcpy(lease->serveraddress.iabuf, &packet->raw->siaddr, lease->address.len);
883 #endif
884 
885 	/* If the server name was filled out, copy it. */
886 	if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
887 	    !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
888 	    packet->raw->sname[0]) {
889 		lease->server_name = malloc(DHCP_SNAME_LEN + 1);
890 		if (!lease->server_name) {
891 			warning("dhcpoffer: no memory for server name.");
892 			free_client_lease(lease);
893 			return (NULL);
894 		}
895 		memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
896 		lease->server_name[DHCP_SNAME_LEN]='\0';
897 		if (!res_hnok(lease->server_name) ) {
898 			warning("Bogus server name %s",  lease->server_name );
899 			free_client_lease(lease);
900 			return (NULL);
901 		}
902 
903 	}
904 
905 	/* Ditto for the filename. */
906 	if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
907 	    !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
908 	    packet->raw->file[0]) {
909 		/* Don't count on the NUL terminator. */
910 		lease->filename = malloc(DHCP_FILE_LEN + 1);
911 		if (!lease->filename) {
912 			warning("dhcpoffer: no memory for filename.");
913 			free_client_lease(lease);
914 			return (NULL);
915 		}
916 		memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
917 		lease->filename[DHCP_FILE_LEN]='\0';
918 	}
919 	return lease;
920 }
921 
922 void
923 dhcpnak(struct packet *packet)
924 {
925 	struct interface_info *ip = packet->interface;
926 
927 	/* If we're not receptive to an offer right now, or if the offer
928 	   has an unrecognizable transaction id, then just drop it. */
929 	if (packet->interface->client->xid != packet->raw->xid ||
930 	    (packet->interface->hw_address.hlen != packet->raw->hlen) ||
931 	    (memcmp(packet->interface->hw_address.haddr,
932 	    packet->raw->chaddr, packet->raw->hlen)))
933 		return;
934 
935 	if (ip->client->state != S_REBOOTING &&
936 	    ip->client->state != S_REQUESTING &&
937 	    ip->client->state != S_RENEWING &&
938 	    ip->client->state != S_REBINDING)
939 		return;
940 
941 	note("DHCPNAK from %s", piaddr(packet->client_addr));
942 
943 	if (!ip->client->active) {
944 		note("DHCPNAK with no active lease.\n");
945 		return;
946 	}
947 
948 	free_client_lease(ip->client->active);
949 	ip->client->active = NULL;
950 
951 	/* Stop sending DHCPREQUEST packets... */
952 	cancel_timeout(send_request, ip);
953 
954 	ip->client->state = S_INIT;
955 	state_init(ip);
956 }
957 
958 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
959    one after the right interval has expired.  If we don't get an offer by
960    the time we reach the panic interval, call the panic function. */
961 
962 void
963 send_discover(void *ipp)
964 {
965 	struct interface_info *ip = ipp;
966 	int interval, increase = 1;
967         time_t cur_time;
968 
969         DH_DbgPrint(MID_TRACE,("Doing discover on interface %p\n",ip));
970 
971         time(&cur_time);
972 
973 	/* Figure out how long it's been since we started transmitting. */
974 	interval = cur_time - ip->client->first_sending;
975 
976 	/* If we're past the panic timeout, call the script and tell it
977 	   we haven't found anything for this interface yet. */
978 	if (interval > ip->client->config->timeout) {
979 		state_panic(ip);
980         ip->client->first_sending = cur_time;
981 	}
982 
983 	/* If we're selecting media, try the whole list before doing
984 	   the exponential backoff, but if we've already received an
985 	   offer, stop looping, because we obviously have it right. */
986 	if (!ip->client->offered_leases &&
987 	    ip->client->config->media) {
988 		int fail = 0;
989 
990 		if (ip->client->medium) {
991 			ip->client->medium = ip->client->medium->next;
992 			increase = 0;
993 		}
994 		if (!ip->client->medium) {
995 			if (fail)
996 				error("No valid media types for %s!", ip->name);
997 			ip->client->medium = ip->client->config->media;
998 			increase = 1;
999 		}
1000 
1001 		note("Trying medium \"%s\" %d", ip->client->medium->string,
1002 		    increase);
1003                 /* XXX Support other media types eventually */
1004 	}
1005 
1006 	/*
1007 	 * If we're supposed to increase the interval, do so.  If it's
1008 	 * currently zero (i.e., we haven't sent any packets yet), set
1009 	 * it to one; otherwise, add to it a random number between zero
1010 	 * and two times itself.  On average, this means that it will
1011 	 * double with every transmission.
1012 	 */
1013 	if (increase) {
1014 		if (!ip->client->interval)
1015 			ip->client->interval =
1016 			    ip->client->config->initial_interval;
1017 		else {
1018 			ip->client->interval += (rand() >> 2) %
1019 			    (2 * ip->client->interval);
1020 		}
1021 
1022 		/* Don't backoff past cutoff. */
1023 		if (ip->client->interval >
1024 		    ip->client->config->backoff_cutoff)
1025 			ip->client->interval =
1026 				((ip->client->config->backoff_cutoff / 2)
1027 				 + ((rand() >> 2) %
1028 				    ip->client->config->backoff_cutoff));
1029 	} else if (!ip->client->interval)
1030 		ip->client->interval =
1031 			ip->client->config->initial_interval;
1032 
1033 	/* If the backoff would take us to the panic timeout, just use that
1034 	   as the interval. */
1035 	if (cur_time + ip->client->interval >
1036 	    ip->client->first_sending + ip->client->config->timeout)
1037 		ip->client->interval =
1038 			(ip->client->first_sending +
1039 			 ip->client->config->timeout) - cur_time + 1;
1040 
1041 	/* Record the number of seconds since we started sending. */
1042 	if (interval < 65536)
1043 		ip->client->packet.secs = htons(interval);
1044 	else
1045 		ip->client->packet.secs = htons(65535);
1046 	ip->client->secs = ip->client->packet.secs;
1047 
1048 	note("DHCPDISCOVER on %s to %s port %d interval %ld",
1049 	    ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
1050 	    ntohs(sockaddr_broadcast.sin_port), (long int)ip->client->interval);
1051 
1052 	/* Send out a packet. */
1053 	(void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
1054 	    inaddr_any, &sockaddr_broadcast, NULL);
1055 
1056         DH_DbgPrint(MID_TRACE,("discover timeout: now %x -> then %x\n",
1057                                cur_time, cur_time + ip->client->interval));
1058 
1059 	add_timeout(cur_time + ip->client->interval, send_discover, ip);
1060 }
1061 
1062 /*
1063  * state_panic gets called if we haven't received any offers in a preset
1064  * amount of time.   When this happens, we try to use existing leases
1065  * that haven't yet expired, and failing that, we call the client script
1066  * and hope it can do something.
1067  */
1068 void
1069 state_panic(void *ipp)
1070 {
1071 	struct interface_info *ip = ipp;
1072         PDHCP_ADAPTER Adapter = AdapterFindInfo(ip);
1073 
1074 	note("No DHCPOFFERS received.");
1075 
1076         if (!Adapter->NteContext)
1077         {
1078             /* Generate an automatic private address */
1079             DbgPrint("DHCPCSVC: Failed to receive a response from a DHCP server. An automatic private address will be assigned.\n");
1080 
1081             /* FIXME: The address generation code sucks */
1082             AddIPAddress(htonl(0xA9FE0000 | (rand() % 0xFFFF)), //169.254.X.X
1083                          htonl(0xFFFF0000), //255.255.0.0
1084                          Adapter->IfMib.dwIndex,
1085                          &Adapter->NteContext,
1086                          &Adapter->NteInstance);
1087         }
1088 }
1089 
1090 void
1091 send_request(void *ipp)
1092 {
1093 	struct interface_info *ip = ipp;
1094 	struct sockaddr_in destination;
1095 	struct in_addr from;
1096 	int interval;
1097         time_t cur_time;
1098 
1099         time(&cur_time);
1100 
1101 	/* Figure out how long it's been since we started transmitting. */
1102 	interval = cur_time - ip->client->first_sending;
1103 
1104 	/* If we're in the INIT-REBOOT or REQUESTING state and we're
1105 	   past the reboot timeout, go to INIT and see if we can
1106 	   DISCOVER an address... */
1107 	/* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1108 	   means either that we're on a network with no DHCP server,
1109 	   or that our server is down.  In the latter case, assuming
1110 	   that there is a backup DHCP server, DHCPDISCOVER will get
1111 	   us a new address, but we could also have successfully
1112 	   reused our old address.  In the former case, we're hosed
1113 	   anyway.  This is not a win-prone situation. */
1114 	if ((ip->client->state == S_REBOOTING ||
1115 	    ip->client->state == S_REQUESTING) &&
1116 	    interval > ip->client->config->reboot_timeout) {
1117 		ip->client->state = S_INIT;
1118 		cancel_timeout(send_request, ip);
1119 		state_init(ip);
1120 		return;
1121 	}
1122 
1123 	/* If we're in the reboot state, make sure the media is set up
1124 	   correctly. */
1125 	if (ip->client->state == S_REBOOTING &&
1126 	    !ip->client->medium &&
1127 	    ip->client->active->medium ) {
1128 		/* If the medium we chose won't fly, go to INIT state. */
1129                 /* XXX Nothing for now */
1130 
1131 		/* Record the medium. */
1132 		ip->client->medium = ip->client->active->medium;
1133 	}
1134 
1135 	/* If the lease has expired, relinquish the address and go back
1136 	   to the INIT state. */
1137 	if (ip->client->state != S_REQUESTING &&
1138 	    cur_time > ip->client->active->expiry) {
1139             PDHCP_ADAPTER Adapter = AdapterFindInfo( ip );
1140             /* Run the client script with the new parameters. */
1141             /* No script actions necessary in the expiry case */
1142             /* Now do a preinit on the interface so that we can
1143                discover a new address. */
1144 
1145             if( Adapter )
1146             {
1147                 DeleteIPAddress( Adapter->NteContext );
1148                 Adapter->NteContext = 0;
1149             }
1150 
1151             ip->client->state = S_INIT;
1152             state_init(ip);
1153             return;
1154 	}
1155 
1156 	/* Do the exponential backoff... */
1157 	if (!ip->client->interval)
1158 		ip->client->interval = ip->client->config->initial_interval;
1159 	else
1160 		ip->client->interval += ((rand() >> 2) %
1161 		    (2 * ip->client->interval));
1162 
1163 	/* Don't backoff past cutoff. */
1164 	if (ip->client->interval >
1165 	    ip->client->config->backoff_cutoff)
1166 		ip->client->interval =
1167 		    ((ip->client->config->backoff_cutoff / 2) +
1168 		    ((rand() >> 2) % ip->client->interval));
1169 
1170 	/* If the backoff would take us to the expiry time, just set the
1171 	   timeout to the expiry time. */
1172 	if (ip->client->state != S_REQUESTING &&
1173 	    cur_time + ip->client->interval >
1174 	    ip->client->active->expiry)
1175 		ip->client->interval =
1176 		    ip->client->active->expiry - cur_time + 1;
1177 
1178 	/* If the lease T2 time has elapsed, or if we're not yet bound,
1179 	   broadcast the DHCPREQUEST rather than unicasting. */
1180 	memset(&destination, 0, sizeof(destination));
1181 	if (ip->client->state == S_REQUESTING ||
1182 	    ip->client->state == S_REBOOTING ||
1183 	    cur_time > ip->client->active->rebind)
1184 		destination.sin_addr.s_addr = INADDR_BROADCAST;
1185 	else
1186 		memcpy(&destination.sin_addr.s_addr,
1187 		    ip->client->destination.iabuf,
1188 		    sizeof(destination.sin_addr.s_addr));
1189 	destination.sin_port = htons(REMOTE_PORT);
1190 	destination.sin_family = AF_INET;
1191 //	destination.sin_len = sizeof(destination);
1192 
1193 	if (ip->client->state != S_REQUESTING)
1194 		memcpy(&from, ip->client->active->address.iabuf,
1195 		    sizeof(from));
1196 	else
1197 		from.s_addr = INADDR_ANY;
1198 
1199 	/* Record the number of seconds since we started sending. */
1200 	if (ip->client->state == S_REQUESTING)
1201 		ip->client->packet.secs = ip->client->secs;
1202 	else {
1203 		if (interval < 65536)
1204 			ip->client->packet.secs = htons(interval);
1205 		else
1206 			ip->client->packet.secs = htons(65535);
1207 	}
1208 
1209 	note("DHCPREQUEST on %s to %s port %d", ip->name,
1210 	    inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
1211 
1212 	/* Send out a packet. */
1213 	(void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1214 	    from, &destination, NULL);
1215 
1216 	add_timeout(cur_time + ip->client->interval, send_request, ip);
1217 }
1218 
1219 void
1220 send_decline(void *ipp)
1221 {
1222 	struct interface_info *ip = ipp;
1223 
1224 	note("DHCPDECLINE on %s to %s port %d", ip->name,
1225 	    inet_ntoa(sockaddr_broadcast.sin_addr),
1226 	    ntohs(sockaddr_broadcast.sin_port));
1227 
1228 	/* Send out a packet. */
1229 	(void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1230 	    inaddr_any, &sockaddr_broadcast, NULL);
1231 }
1232 
1233 void
1234 make_discover(struct interface_info *ip, struct client_lease *lease)
1235 {
1236 	unsigned char discover = DHCPDISCOVER;
1237 	struct tree_cache *options[256];
1238 	struct tree_cache option_elements[256];
1239 	int i;
1240 	ULONG foo = (ULONG) GetTickCount();
1241 
1242 	memset(option_elements, 0, sizeof(option_elements));
1243 	memset(options, 0, sizeof(options));
1244 	memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1245 
1246 	/* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1247 	i = DHO_DHCP_MESSAGE_TYPE;
1248 	options[i] = &option_elements[i];
1249 	options[i]->value = &discover;
1250 	options[i]->len = sizeof(discover);
1251 	options[i]->buf_size = sizeof(discover);
1252 	options[i]->timeout = 0xFFFFFFFF;
1253 
1254 	/* Request the options we want */
1255 	i  = DHO_DHCP_PARAMETER_REQUEST_LIST;
1256 	options[i] = &option_elements[i];
1257 	options[i]->value = ip->client->config->requested_options;
1258 	options[i]->len = ip->client->config->requested_option_count;
1259 	options[i]->buf_size =
1260 		ip->client->config->requested_option_count;
1261 	options[i]->timeout = 0xFFFFFFFF;
1262 
1263 	/* If we had an address, try to get it again. */
1264 	if (lease) {
1265 		ip->client->requested_address = lease->address;
1266 		i = DHO_DHCP_REQUESTED_ADDRESS;
1267 		options[i] = &option_elements[i];
1268 		options[i]->value = lease->address.iabuf;
1269 		options[i]->len = lease->address.len;
1270 		options[i]->buf_size = lease->address.len;
1271 		options[i]->timeout = 0xFFFFFFFF;
1272 	} else
1273 		ip->client->requested_address.len = 0;
1274 
1275 	/* Send any options requested in the config file. */
1276 	for (i = 0; i < 256; i++)
1277 		if (!options[i] &&
1278 		    ip->client->config->send_options[i].data) {
1279 			options[i] = &option_elements[i];
1280 			options[i]->value =
1281 			    ip->client->config->send_options[i].data;
1282 			options[i]->len =
1283 			    ip->client->config->send_options[i].len;
1284 			options[i]->buf_size =
1285 			    ip->client->config->send_options[i].len;
1286 			options[i]->timeout = 0xFFFFFFFF;
1287 		}
1288 
1289 	/* Set up the option buffer... */
1290 	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1291 	    options);
1292 	if (ip->client->packet_length < BOOTP_MIN_LEN)
1293 		ip->client->packet_length = BOOTP_MIN_LEN;
1294 
1295 	ip->client->packet.op = BOOTREQUEST;
1296 	ip->client->packet.htype = ip->hw_address.htype;
1297 	ip->client->packet.hlen = ip->hw_address.hlen;
1298 	ip->client->packet.hops = 0;
1299 	ip->client->packet.xid = RtlRandom(&foo);
1300 	ip->client->packet.secs = 0; /* filled in by send_discover. */
1301 	ip->client->packet.flags = 0;
1302 
1303 	memset(&(ip->client->packet.ciaddr),
1304 	    0, sizeof(ip->client->packet.ciaddr));
1305 	memset(&(ip->client->packet.yiaddr),
1306 	    0, sizeof(ip->client->packet.yiaddr));
1307 	memset(&(ip->client->packet.siaddr),
1308 	    0, sizeof(ip->client->packet.siaddr));
1309 	memset(&(ip->client->packet.giaddr),
1310 	    0, sizeof(ip->client->packet.giaddr));
1311 	memcpy(ip->client->packet.chaddr,
1312 	    ip->hw_address.haddr, ip->hw_address.hlen);
1313 }
1314 
1315 
1316 void
1317 make_request(struct interface_info *ip, struct client_lease * lease)
1318 {
1319 	unsigned char request = DHCPREQUEST;
1320 	struct tree_cache *options[256];
1321 	struct tree_cache option_elements[256];
1322 	int i;
1323 
1324 	memset(options, 0, sizeof(options));
1325 	memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1326 
1327 	/* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1328 	i = DHO_DHCP_MESSAGE_TYPE;
1329 	options[i] = &option_elements[i];
1330 	options[i]->value = &request;
1331 	options[i]->len = sizeof(request);
1332 	options[i]->buf_size = sizeof(request);
1333 	options[i]->timeout = 0xFFFFFFFF;
1334 
1335 	/* Request the options we want */
1336 	i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1337 	options[i] = &option_elements[i];
1338 	options[i]->value = ip->client->config->requested_options;
1339 	options[i]->len = ip->client->config->requested_option_count;
1340 	options[i]->buf_size =
1341 		ip->client->config->requested_option_count;
1342 	options[i]->timeout = 0xFFFFFFFF;
1343 
1344 	/* If we are requesting an address that hasn't yet been assigned
1345 	   to us, use the DHCP Requested Address option. */
1346 	if (ip->client->state == S_REQUESTING) {
1347 		/* Send back the server identifier... */
1348 		i = DHO_DHCP_SERVER_IDENTIFIER;
1349 		options[i] = &option_elements[i];
1350 		options[i]->value = lease->options[i].data;
1351 		options[i]->len = lease->options[i].len;
1352 		options[i]->buf_size = lease->options[i].len;
1353 		options[i]->timeout = 0xFFFFFFFF;
1354 	}
1355 	if (ip->client->state == S_REQUESTING ||
1356 	    ip->client->state == S_REBOOTING) {
1357 		ip->client->requested_address = lease->address;
1358 		i = DHO_DHCP_REQUESTED_ADDRESS;
1359 		options[i] = &option_elements[i];
1360 		options[i]->value = lease->address.iabuf;
1361 		options[i]->len = lease->address.len;
1362 		options[i]->buf_size = lease->address.len;
1363 		options[i]->timeout = 0xFFFFFFFF;
1364 	} else
1365 		ip->client->requested_address.len = 0;
1366 
1367 	/* Send any options requested in the config file. */
1368 	for (i = 0; i < 256; i++)
1369 		if (!options[i] &&
1370 		    ip->client->config->send_options[i].data) {
1371 			options[i] = &option_elements[i];
1372 			options[i]->value =
1373 			    ip->client->config->send_options[i].data;
1374 			options[i]->len =
1375 			    ip->client->config->send_options[i].len;
1376 			options[i]->buf_size =
1377 			    ip->client->config->send_options[i].len;
1378 			options[i]->timeout = 0xFFFFFFFF;
1379 		}
1380 
1381 	/* Set up the option buffer... */
1382 	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1383 	    options);
1384 	if (ip->client->packet_length < BOOTP_MIN_LEN)
1385 		ip->client->packet_length = BOOTP_MIN_LEN;
1386 
1387 	ip->client->packet.op = BOOTREQUEST;
1388 	ip->client->packet.htype = ip->hw_address.htype;
1389 	ip->client->packet.hlen = ip->hw_address.hlen;
1390 	ip->client->packet.hops = 0;
1391 	ip->client->packet.xid = ip->client->xid;
1392 	ip->client->packet.secs = 0; /* Filled in by send_request. */
1393 
1394 	/* If we own the address we're requesting, put it in ciaddr;
1395 	   otherwise set ciaddr to zero. */
1396 	if (ip->client->state == S_BOUND ||
1397 	    ip->client->state == S_RENEWING ||
1398 	    ip->client->state == S_REBINDING) {
1399 		memcpy(&ip->client->packet.ciaddr,
1400 		    lease->address.iabuf, lease->address.len);
1401 		ip->client->packet.flags = 0;
1402 	} else {
1403 		memset(&ip->client->packet.ciaddr, 0,
1404 		    sizeof(ip->client->packet.ciaddr));
1405 		ip->client->packet.flags = 0;
1406 	}
1407 
1408 	memset(&ip->client->packet.yiaddr, 0,
1409 	    sizeof(ip->client->packet.yiaddr));
1410 	memset(&ip->client->packet.siaddr, 0,
1411 	    sizeof(ip->client->packet.siaddr));
1412 	memset(&ip->client->packet.giaddr, 0,
1413 	    sizeof(ip->client->packet.giaddr));
1414 	memcpy(ip->client->packet.chaddr,
1415 	    ip->hw_address.haddr, ip->hw_address.hlen);
1416 }
1417 
1418 void
1419 make_decline(struct interface_info *ip, struct client_lease *lease)
1420 {
1421 	struct tree_cache *options[256], message_type_tree;
1422 	struct tree_cache requested_address_tree;
1423 	struct tree_cache server_id_tree, client_id_tree;
1424 	unsigned char decline = DHCPDECLINE;
1425 	int i;
1426 
1427 	memset(options, 0, sizeof(options));
1428 	memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1429 
1430 	/* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1431 	i = DHO_DHCP_MESSAGE_TYPE;
1432 	options[i] = &message_type_tree;
1433 	options[i]->value = &decline;
1434 	options[i]->len = sizeof(decline);
1435 	options[i]->buf_size = sizeof(decline);
1436 	options[i]->timeout = 0xFFFFFFFF;
1437 
1438 	/* Send back the server identifier... */
1439 	i = DHO_DHCP_SERVER_IDENTIFIER;
1440 	options[i] = &server_id_tree;
1441 	options[i]->value = lease->options[i].data;
1442 	options[i]->len = lease->options[i].len;
1443 	options[i]->buf_size = lease->options[i].len;
1444 	options[i]->timeout = 0xFFFFFFFF;
1445 
1446 	/* Send back the address we're declining. */
1447 	i = DHO_DHCP_REQUESTED_ADDRESS;
1448 	options[i] = &requested_address_tree;
1449 	options[i]->value = lease->address.iabuf;
1450 	options[i]->len = lease->address.len;
1451 	options[i]->buf_size = lease->address.len;
1452 	options[i]->timeout = 0xFFFFFFFF;
1453 
1454 	/* Send the uid if the user supplied one. */
1455 	i = DHO_DHCP_CLIENT_IDENTIFIER;
1456 	if (ip->client->config->send_options[i].len) {
1457 		options[i] = &client_id_tree;
1458 		options[i]->value = ip->client->config->send_options[i].data;
1459 		options[i]->len = ip->client->config->send_options[i].len;
1460 		options[i]->buf_size = ip->client->config->send_options[i].len;
1461 		options[i]->timeout = 0xFFFFFFFF;
1462 	}
1463 
1464 
1465 	/* Set up the option buffer... */
1466 	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1467 	    options);
1468 	if (ip->client->packet_length < BOOTP_MIN_LEN)
1469 		ip->client->packet_length = BOOTP_MIN_LEN;
1470 
1471 	ip->client->packet.op = BOOTREQUEST;
1472 	ip->client->packet.htype = ip->hw_address.htype;
1473 	ip->client->packet.hlen = ip->hw_address.hlen;
1474 	ip->client->packet.hops = 0;
1475 	ip->client->packet.xid = ip->client->xid;
1476 	ip->client->packet.secs = 0; /* Filled in by send_request. */
1477 	ip->client->packet.flags = 0;
1478 
1479 	/* ciaddr must always be zero. */
1480 	memset(&ip->client->packet.ciaddr, 0,
1481 	    sizeof(ip->client->packet.ciaddr));
1482 	memset(&ip->client->packet.yiaddr, 0,
1483 	    sizeof(ip->client->packet.yiaddr));
1484 	memset(&ip->client->packet.siaddr, 0,
1485 	    sizeof(ip->client->packet.siaddr));
1486 	memset(&ip->client->packet.giaddr, 0,
1487 	    sizeof(ip->client->packet.giaddr));
1488 	memcpy(ip->client->packet.chaddr,
1489 	    ip->hw_address.haddr, ip->hw_address.hlen);
1490 }
1491 
1492 void
1493 free_client_lease(struct client_lease *lease)
1494 {
1495 	int i;
1496 
1497 	if (lease->server_name)
1498 		free(lease->server_name);
1499 	if (lease->filename)
1500 		free(lease->filename);
1501 	for (i = 0; i < 256; i++) {
1502 		if (lease->options[i].len)
1503 			free(lease->options[i].data);
1504 	}
1505 	free(lease);
1506 }
1507 
1508 FILE *leaseFile;
1509 
1510 void
1511 rewrite_client_leases(struct interface_info *ifi)
1512 {
1513 	struct client_lease *lp;
1514 
1515 	if (!leaseFile) {
1516 		leaseFile = fopen(path_dhclient_db, "w");
1517 		if (!leaseFile)
1518 			error("can't create %s", path_dhclient_db);
1519 	} else {
1520 		fflush(leaseFile);
1521 		rewind(leaseFile);
1522 	}
1523 
1524 	for (lp = ifi->client->leases; lp; lp = lp->next)
1525 		write_client_lease(ifi, lp, 1);
1526 	if (ifi->client->active)
1527 		write_client_lease(ifi, ifi->client->active, 1);
1528 
1529 	fflush(leaseFile);
1530 }
1531 
1532 void
1533 write_client_lease(struct interface_info *ip, struct client_lease *lease,
1534     int rewrite)
1535 {
1536 	static int leases_written;
1537 	struct tm *t;
1538 	int i;
1539 
1540 	if (!rewrite) {
1541 		if (leases_written++ > 20) {
1542 			rewrite_client_leases(ip);
1543 			leases_written = 0;
1544 		}
1545 	}
1546 
1547 	/* If the lease came from the config file, we don't need to stash
1548 	   a copy in the lease database. */
1549 	if (lease->is_static)
1550 		return;
1551 
1552 	if (!leaseFile) {	/* XXX */
1553 		leaseFile = fopen(path_dhclient_db, "w");
1554 		if (!leaseFile) {
1555 			error("can't create %s", path_dhclient_db);
1556                         return;
1557                 }
1558 	}
1559 
1560 	fprintf(leaseFile, "lease {\n");
1561 	if (lease->is_bootp)
1562 		fprintf(leaseFile, "  bootp;\n");
1563 	fprintf(leaseFile, "  interface \"%s\";\n", ip->name);
1564 	fprintf(leaseFile, "  fixed-address %s;\n", piaddr(lease->address));
1565 	if (lease->filename)
1566 		fprintf(leaseFile, "  filename \"%s\";\n", lease->filename);
1567 	if (lease->server_name)
1568 		fprintf(leaseFile, "  server-name \"%s\";\n",
1569 		    lease->server_name);
1570 	if (lease->medium)
1571 		fprintf(leaseFile, "  medium \"%s\";\n", lease->medium->string);
1572 	for (i = 0; i < 256; i++)
1573 		if (lease->options[i].len)
1574 			fprintf(leaseFile, "  option %s %s;\n",
1575 			    dhcp_options[i].name,
1576 			    pretty_print_option(i, lease->options[i].data,
1577 			    lease->options[i].len, 1, 1));
1578 
1579 	t = gmtime(&lease->renewal);
1580         if (t)
1581 	    fprintf(leaseFile, "  renew %d %d/%d/%d %02d:%02d:%02d;\n",
1582 	        t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1583 	        t->tm_hour, t->tm_min, t->tm_sec);
1584 	t = gmtime(&lease->rebind);
1585         if (t)
1586 	    fprintf(leaseFile, "  rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1587 	         t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1588 	         t->tm_hour, t->tm_min, t->tm_sec);
1589 	t = gmtime(&lease->expiry);
1590         if (t)
1591 	    fprintf(leaseFile, "  expire %d %d/%d/%d %02d:%02d:%02d;\n",
1592 	        t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1593 	        t->tm_hour, t->tm_min, t->tm_sec);
1594 	fprintf(leaseFile, "}\n");
1595 	fflush(leaseFile);
1596 }
1597 
1598 void
1599 priv_script_init(struct interface_info *ip, char *reason, char *medium)
1600 {
1601 	if (ip) {
1602             // XXX Do we need to do anything?
1603         }
1604 }
1605 
1606 void
1607 priv_script_write_params(struct interface_info *ip, char *prefix, struct client_lease *lease)
1608 {
1609 	u_int8_t dbuf[1500];
1610 	int i, len = 0;
1611 
1612 #if 0
1613 	script_set_env(ip->client, prefix, "ip_address",
1614 	    piaddr(lease->address));
1615 #endif
1616 
1617 	if (lease->options[DHO_SUBNET_MASK].len &&
1618 	    (lease->options[DHO_SUBNET_MASK].len <
1619 	    sizeof(lease->address.iabuf))) {
1620 		struct iaddr netmask, subnet, broadcast;
1621 
1622 		memcpy(netmask.iabuf, lease->options[DHO_SUBNET_MASK].data,
1623 		    lease->options[DHO_SUBNET_MASK].len);
1624 		netmask.len = lease->options[DHO_SUBNET_MASK].len;
1625 
1626 		subnet = subnet_number(lease->address, netmask);
1627 		if (subnet.len) {
1628 #if 0
1629 			script_set_env(ip->client, prefix, "network_number",
1630 			    piaddr(subnet));
1631 #endif
1632 			if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
1633 				broadcast = broadcast_addr(subnet, netmask);
1634 				if (broadcast.len)
1635 #if 0
1636 					script_set_env(ip->client, prefix,
1637 					    "broadcast_address",
1638 					    piaddr(broadcast));
1639 #else
1640                                 ;
1641 #endif
1642 			}
1643 		}
1644 	}
1645 
1646 #if 0
1647 	if (lease->filename)
1648 		script_set_env(ip->client, prefix, "filename", lease->filename);
1649 	if (lease->server_name)
1650 		script_set_env(ip->client, prefix, "server_name",
1651 		    lease->server_name);
1652 #endif
1653 
1654 	for (i = 0; i < 256; i++) {
1655 		u_int8_t *dp = NULL;
1656 
1657 		if (ip->client->config->defaults[i].len) {
1658 			if (lease->options[i].len) {
1659 				switch (
1660 				    ip->client->config->default_actions[i]) {
1661 				case ACTION_DEFAULT:
1662 					dp = lease->options[i].data;
1663 					len = lease->options[i].len;
1664 					break;
1665 				case ACTION_SUPERSEDE:
1666 supersede:
1667 					dp = ip->client->
1668 						config->defaults[i].data;
1669 					len = ip->client->
1670 						config->defaults[i].len;
1671 					break;
1672 				case ACTION_PREPEND:
1673 					len = ip->client->
1674 					    config->defaults[i].len +
1675 					    lease->options[i].len;
1676 					if (len >= sizeof(dbuf)) {
1677 						warning("no space to %s %s",
1678 						    "prepend option",
1679 						    dhcp_options[i].name);
1680 						goto supersede;
1681 					}
1682 					dp = dbuf;
1683 					memcpy(dp,
1684 						ip->client->
1685 						config->defaults[i].data,
1686 						ip->client->
1687 						config->defaults[i].len);
1688 					memcpy(dp + ip->client->
1689 						config->defaults[i].len,
1690 						lease->options[i].data,
1691 						lease->options[i].len);
1692 					dp[len] = '\0';
1693 					break;
1694 				case ACTION_APPEND:
1695 					len = ip->client->
1696 					    config->defaults[i].len +
1697 					    lease->options[i].len + 1;
1698 					if (len > sizeof(dbuf)) {
1699 						warning("no space to %s %s",
1700 						    "append option",
1701 						    dhcp_options[i].name);
1702 						goto supersede;
1703 					}
1704 					dp = dbuf;
1705 					memcpy(dp,
1706 						lease->options[i].data,
1707 						lease->options[i].len);
1708 					memcpy(dp + lease->options[i].len,
1709 						ip->client->
1710 						config->defaults[i].data,
1711 						ip->client->
1712 						config->defaults[i].len);
1713 					dp[len-1] = '\0';
1714 				}
1715 			} else {
1716 				dp = ip->client->
1717 					config->defaults[i].data;
1718 				len = ip->client->
1719 					config->defaults[i].len;
1720 			}
1721 		} else if (lease->options[i].len) {
1722 			len = lease->options[i].len;
1723 			dp = lease->options[i].data;
1724 		} else {
1725 			len = 0;
1726 		}
1727 #if 0
1728 		if (len) {
1729 			char name[256];
1730 
1731 			if (dhcp_option_ev_name(name, sizeof(name),
1732 			    &dhcp_options[i]))
1733 				script_set_env(ip->client, prefix, name,
1734 				    pretty_print_option(i, dp, len, 0, 0));
1735 		}
1736 #endif
1737 	}
1738 #if 0
1739 	snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
1740 	script_set_env(ip->client, prefix, "expiry", tbuf);
1741 #endif
1742 }
1743 
1744 int
1745 dhcp_option_ev_name(char *buf, size_t buflen, struct dhcp_option *option)
1746 {
1747 	int i;
1748 
1749 	for (i = 0; option->name[i]; i++) {
1750 		if (i + 1 == buflen)
1751 			return 0;
1752 		if (option->name[i] == '-')
1753 			buf[i] = '_';
1754 		else
1755 			buf[i] = option->name[i];
1756 	}
1757 
1758 	buf[i] = 0;
1759 	return 1;
1760 }
1761 
1762 #if 0
1763 void
1764 go_daemon(void)
1765 {
1766 	static int state = 0;
1767 
1768 	if (no_daemon || state)
1769 		return;
1770 
1771 	state = 1;
1772 
1773 	/* Stop logging to stderr... */
1774 	log_perror = 0;
1775 
1776 	if (daemon(1, 0) == -1)
1777 		error("daemon");
1778 
1779 	/* we are chrooted, daemon(3) fails to open /dev/null */
1780 	if (nullfd != -1) {
1781 		dup2(nullfd, STDIN_FILENO);
1782 		dup2(nullfd, STDOUT_FILENO);
1783 		dup2(nullfd, STDERR_FILENO);
1784 		close(nullfd);
1785 		nullfd = -1;
1786 	}
1787 }
1788 #endif
1789 
1790 int
1791 check_option(struct client_lease *l, int option)
1792 {
1793 	char *opbuf;
1794 	char *sbuf;
1795 
1796 	/* we use this, since this is what gets passed to dhclient-script */
1797 
1798 	opbuf = pretty_print_option(option, l->options[option].data,
1799 	    l->options[option].len, 0, 0);
1800 
1801 	sbuf = option_as_string(option, l->options[option].data,
1802 	    l->options[option].len);
1803 
1804 	switch (option) {
1805 	case DHO_SUBNET_MASK:
1806 	case DHO_TIME_SERVERS:
1807 	case DHO_NAME_SERVERS:
1808 	case DHO_ROUTERS:
1809 	case DHO_DOMAIN_NAME_SERVERS:
1810 	case DHO_LOG_SERVERS:
1811 	case DHO_COOKIE_SERVERS:
1812 	case DHO_LPR_SERVERS:
1813 	case DHO_IMPRESS_SERVERS:
1814 	case DHO_RESOURCE_LOCATION_SERVERS:
1815 	case DHO_SWAP_SERVER:
1816 	case DHO_BROADCAST_ADDRESS:
1817 	case DHO_NIS_SERVERS:
1818 	case DHO_NTP_SERVERS:
1819 	case DHO_NETBIOS_NAME_SERVERS:
1820 	case DHO_NETBIOS_DD_SERVER:
1821 	case DHO_FONT_SERVERS:
1822 	case DHO_DHCP_SERVER_IDENTIFIER:
1823 		if (!ipv4addrs(opbuf)) {
1824                         warning("Invalid IP address in option(%d): %s", option, opbuf);
1825 			return (0);
1826 		}
1827 		return (1)  ;
1828 	case DHO_HOST_NAME:
1829 	case DHO_DOMAIN_NAME:
1830 	case DHO_NIS_DOMAIN:
1831 		if (!res_hnok(sbuf))
1832 			warning("Bogus Host Name option %d: %s (%s)", option,
1833 			    sbuf, opbuf);
1834 		return (1);
1835 	case DHO_PAD:
1836 	case DHO_TIME_OFFSET:
1837 	case DHO_BOOT_SIZE:
1838 	case DHO_MERIT_DUMP:
1839 	case DHO_ROOT_PATH:
1840 	case DHO_EXTENSIONS_PATH:
1841 	case DHO_IP_FORWARDING:
1842 	case DHO_NON_LOCAL_SOURCE_ROUTING:
1843 	case DHO_POLICY_FILTER:
1844 	case DHO_MAX_DGRAM_REASSEMBLY:
1845 	case DHO_DEFAULT_IP_TTL:
1846 	case DHO_PATH_MTU_AGING_TIMEOUT:
1847 	case DHO_PATH_MTU_PLATEAU_TABLE:
1848 	case DHO_INTERFACE_MTU:
1849 	case DHO_ALL_SUBNETS_LOCAL:
1850 	case DHO_PERFORM_MASK_DISCOVERY:
1851 	case DHO_MASK_SUPPLIER:
1852 	case DHO_ROUTER_DISCOVERY:
1853 	case DHO_ROUTER_SOLICITATION_ADDRESS:
1854 	case DHO_STATIC_ROUTES:
1855 	case DHO_TRAILER_ENCAPSULATION:
1856 	case DHO_ARP_CACHE_TIMEOUT:
1857 	case DHO_IEEE802_3_ENCAPSULATION:
1858 	case DHO_DEFAULT_TCP_TTL:
1859 	case DHO_TCP_KEEPALIVE_INTERVAL:
1860 	case DHO_TCP_KEEPALIVE_GARBAGE:
1861 	case DHO_VENDOR_ENCAPSULATED_OPTIONS:
1862 	case DHO_NETBIOS_NODE_TYPE:
1863 	case DHO_NETBIOS_SCOPE:
1864 	case DHO_X_DISPLAY_MANAGER:
1865 	case DHO_DHCP_REQUESTED_ADDRESS:
1866 	case DHO_DHCP_LEASE_TIME:
1867 	case DHO_DHCP_OPTION_OVERLOAD:
1868 	case DHO_DHCP_MESSAGE_TYPE:
1869 	case DHO_DHCP_PARAMETER_REQUEST_LIST:
1870 	case DHO_DHCP_MESSAGE:
1871 	case DHO_DHCP_MAX_MESSAGE_SIZE:
1872 	case DHO_DHCP_RENEWAL_TIME:
1873 	case DHO_DHCP_REBINDING_TIME:
1874 	case DHO_DHCP_CLASS_IDENTIFIER:
1875 	case DHO_DHCP_CLIENT_IDENTIFIER:
1876 	case DHO_DHCP_USER_CLASS_ID:
1877 	case DHO_END:
1878 		return (1);
1879 	default:
1880 		warning("unknown dhcp option value 0x%x", option);
1881 		return (unknown_ok);
1882 	}
1883 }
1884 
1885 int
1886 res_hnok(const char *dn)
1887 {
1888 	int pch = PERIOD, ch = *dn++;
1889 
1890 	while (ch != '\0') {
1891 		int nch = *dn++;
1892 
1893 		if (periodchar(ch)) {
1894 			;
1895 		} else if (periodchar(pch)) {
1896 			if (!borderchar(ch))
1897 				return (0);
1898 		} else if (periodchar(nch) || nch == '\0') {
1899 			if (!borderchar(ch))
1900 				return (0);
1901 		} else {
1902 			if (!middlechar(ch))
1903 				return (0);
1904 		}
1905 		pch = ch, ch = nch;
1906 	}
1907 	return (1);
1908 }
1909 
1910 /* Does buf consist only of dotted decimal ipv4 addrs?
1911  * return how many if so,
1912  * otherwise, return 0
1913  */
1914 int
1915 ipv4addrs(char * buf)
1916 {
1917     char *tmp;
1918     struct in_addr jnk;
1919     int i = 0;
1920 
1921     note("Input: %s", buf);
1922 
1923     do {
1924         tmp = strtok(buf, " ");
1925         note("got %s", tmp);
1926 		if( tmp && inet_aton(tmp, &jnk) ) i++;
1927         buf = NULL;
1928     } while( tmp );
1929 
1930     return (i);
1931 }
1932 
1933 
1934 char *
1935 option_as_string(unsigned int code, unsigned char *data, int len)
1936 {
1937 	static char optbuf[32768]; /* XXX */
1938 	char *op = optbuf;
1939 	int opleft = sizeof(optbuf);
1940 	unsigned char *dp = data;
1941 
1942 	if (code > 255)
1943 		error("option_as_string: bad code %d", code);
1944 
1945 	for (; dp < data + len; dp++) {
1946 		if (!isascii(*dp) || !isprint(*dp)) {
1947 			if (dp + 1 != data + len || *dp != 0) {
1948 				_snprintf(op, opleft, "\\%03o", *dp);
1949 				op += 4;
1950 				opleft -= 4;
1951 			}
1952 		} else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
1953 		    *dp == '`' || *dp == '\\') {
1954 			*op++ = '\\';
1955 			*op++ = *dp;
1956 			opleft -= 2;
1957 		} else {
1958 			*op++ = *dp;
1959 			opleft--;
1960 		}
1961 	}
1962 	if (opleft < 1)
1963 		goto toobig;
1964 	*op = 0;
1965 	return optbuf;
1966 toobig:
1967 	warning("dhcp option too large");
1968 	return "<error>";
1969 }
1970 
1971