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