1 /* $OpenBSD: dhclient.c,v 1.62 2004/12/05 18:35:51 deraadt Exp $ */
4 * Copyright 2004 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 1995, 1996, 1997, 1998, 1999
6 * The Internet Software Consortium. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
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''.
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
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
62 #define hyphenchar(c) ((c) == 0x2d)
63 #define bslashchar(c) ((c) == 0x5c)
64 #define periodchar(c) ((c) == PERIOD)
65 #define asterchar(c) ((c) == 0x2a)
66 #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
67 ((c) >= 0x61 && (c) <= 0x7a))
68 #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
70 #define borderchar(c) (alphachar(c) || digitchar(c))
71 #define middlechar(c) (borderchar(c) || hyphenchar(c))
72 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
74 unsigned long debug_trace_level
= 0; /* DEBUG_ULTRA */
76 time_t default_lease_time
= 43200; /* 12 hours... */
78 char *path_dhclient_conf
= _PATH_DHCLIENT_CONF
;
79 char *path_dhclient_db
= NULL
;
85 struct iaddr iaddr_broadcast
= { 4, { 255, 255, 255, 255 } };
86 struct in_addr inaddr_any
;
87 struct sockaddr_in sockaddr_broadcast
;
88 unsigned long old_default_route
= 0;
91 * ASSERT_STATE() does nothing now; it used to be
92 * assert (state_is == state_shouldbe).
94 #define ASSERT_STATE(state_is, state_shouldbe) {}
96 #define TIME_MAX 2147483647
103 struct interface_info
*ifi
= NULL
;
106 int check_option(struct client_lease
*l
, int option
);
107 int ipv4addrs(char * buf
);
108 int res_hnok(const char *dn
);
109 char *option_as_string(unsigned int code
, unsigned char *data
, int len
);
110 int fork_privchld(int, int);
111 int check_arp( struct interface_info
*ip
, struct client_lease
*lp
);
113 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
117 /* XXX Implement me */
118 int check_arp( struct interface_info
*ip
, struct client_lease
*lp
) {
123 DispatchMain(DWORD argc
, LPTSTR
*argv
)
128 static SERVICE_TABLE_ENTRY ServiceTable
[2] =
130 {TEXT("DHCP"), DispatchMain
},
135 main(int argc
, char *argv
[])
145 memset(&sockaddr_broadcast
, 0, sizeof(sockaddr_broadcast
));
146 sockaddr_broadcast
.sin_family
= AF_INET
;
147 sockaddr_broadcast
.sin_port
= htons(REMOTE_PORT
);
148 sockaddr_broadcast
.sin_addr
.s_addr
= INADDR_BROADCAST
;
149 inaddr_any
.s_addr
= INADDR_ANY
;
151 DH_DbgPrint(MID_TRACE
,("DHCP Service Started\n"));
155 if (!interface_link_status(ifi
->name
)) {
156 DH_DbgPrint(MID_TRACE
,("%s: no link ", ifi
->name
));
158 while (!interface_link_status(ifi
->name
)) {
159 DH_DbgPrint(MID_TRACE
,("."));
161 DH_DbgPrint(MID_TRACE
,("Giving up for now on adapter [%s]\n", ifi
->name
));
165 DH_DbgPrint(MID_TRACE
,("Got link on [%s]\n", ifi
->name
));
168 DH_DbgPrint(MID_TRACE
,("Discover Interfaces\n"));
170 /* If no adapters were found, just idle for now ... If any show up,
171 * then we'll start it later */
173 /* set up the interface */
174 discover_interfaces(ifi
);
178 ("Setting init state and restarting interface %p\n",ifi
));
181 bootp_packet_handler
= do_packet
;
183 DH_DbgPrint(MID_TRACE
,("Going into dispatch()\n"));
185 StartServiceCtrlDispatcher(ServiceTable
);
194 // extern char *__progname;
196 // fprintf(stderr, "usage: %s [-dqu] ", __progname);
197 fprintf(stderr
, "usage: dhclient [-dqu] ");
198 fprintf(stderr
, "[-c conffile] [-l leasefile] interface\n");
205 * Each routine is called from the dhclient_state_machine() in one of
207 * -> entering INIT state
208 * -> recvpacket_flag == 0: timeout in this state
209 * -> otherwise: received a packet in this state
211 * Return conditions as handled by dhclient_state_machine():
212 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
213 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
214 * Returns 0: finish the nap which was interrupted for no good reason.
216 * Several per-interface variables are used to keep track of the process:
217 * active_lease: the lease that is being used on the interface
218 * (null pointer if not configured yet).
219 * offered_leases: leases corresponding to DHCPOFFER messages that have
220 * been sent to us by DHCP servers.
221 * acked_leases: leases corresponding to DHCPACK messages that have been
222 * sent to us by DHCP servers.
223 * sendpacket: DHCP packet we're trying to send.
224 * destination: IP address to send sendpacket to
225 * In addition, there are several relevant per-lease variables.
226 * T1_expiry, T2_expiry, lease_expiry: lease milestones
227 * In the active lease, these control the process of renewing the lease;
228 * In leases on the acked_leases list, this simply determines when we
229 * can no longer legitimately use the lease.
233 state_reboot(void *ipp
)
235 struct interface_info
*ip
= ipp
;
236 ULONG foo
= (ULONG
) GetTickCount();
238 /* If we don't remember an active lease, go straight to INIT. */
239 if (!ip
->client
->active
|| ip
->client
->active
->is_bootp
) {
244 /* We are in the rebooting state. */
245 ip
->client
->state
= S_REBOOTING
;
247 /* make_request doesn't initialize xid because it normally comes
248 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
249 so pick an xid now. */
250 ip
->client
->xid
= RtlRandom(&foo
);
252 /* Make a DHCPREQUEST packet, and set appropriate per-interface
254 make_request(ip
, ip
->client
->active
);
255 ip
->client
->destination
= iaddr_broadcast
;
256 ip
->client
->first_sending
= cur_time
;
257 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
259 /* Zap the medium list... */
260 ip
->client
->medium
= NULL
;
262 /* Send out the first DHCPREQUEST packet. */
267 * Called when a lease has completely expired and we've
268 * been unable to renew it.
271 state_init(void *ipp
)
273 struct interface_info
*ip
= ipp
;
275 ASSERT_STATE(state
, S_INIT
);
277 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
279 make_discover(ip
, ip
->client
->active
);
280 ip
->client
->xid
= ip
->client
->packet
.xid
;
281 ip
->client
->destination
= iaddr_broadcast
;
282 ip
->client
->state
= S_SELECTING
;
283 ip
->client
->first_sending
= cur_time
;
284 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
286 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
292 * state_selecting is called when one or more DHCPOFFER packets
293 * have been received and a configurable period of time has passed.
296 state_selecting(void *ipp
)
298 struct interface_info
*ip
= ipp
;
299 struct client_lease
*lp
, *next
, *picked
;
301 ASSERT_STATE(state
, S_SELECTING
);
303 /* Cancel state_selecting and send_discover timeouts, since either
304 one could have got us here. */
305 cancel_timeout(state_selecting
, ip
);
306 cancel_timeout(send_discover
, ip
);
308 /* We have received one or more DHCPOFFER packets. Currently,
309 the only criterion by which we judge leases is whether or
310 not we get a response when we arp for them. */
312 for (lp
= ip
->client
->offered_leases
; lp
; lp
= next
) {
315 /* Check to see if we got an ARPREPLY for the address
316 in this particular lease. */
318 if( !check_arp(ip
,lp
) ) goto freeit
;
323 free_client_lease(lp
);
326 ip
->client
->offered_leases
= NULL
;
328 /* If we just tossed all the leases we were offered, go back
331 ip
->client
->state
= S_INIT
;
336 /* If it was a BOOTREPLY, we can just take the address right now. */
337 if (!picked
->options
[DHO_DHCP_MESSAGE_TYPE
].len
) {
338 ip
->client
->new = picked
;
340 /* Make up some lease expiry times
341 XXX these should be configurable. */
342 ip
->client
->new->expiry
= cur_time
+ 12000;
343 ip
->client
->new->renewal
+= cur_time
+ 8000;
344 ip
->client
->new->rebind
+= cur_time
+ 10000;
346 ip
->client
->state
= S_REQUESTING
;
348 /* Bind to the address we received. */
353 /* Go to the REQUESTING state. */
354 ip
->client
->destination
= iaddr_broadcast
;
355 ip
->client
->state
= S_REQUESTING
;
356 ip
->client
->first_sending
= cur_time
;
357 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
359 /* Make a DHCPREQUEST packet from the lease we picked. */
360 make_request(ip
, picked
);
361 ip
->client
->xid
= ip
->client
->packet
.xid
;
363 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
364 free_client_lease(picked
);
366 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
370 /* state_requesting is called when we receive a DHCPACK message after
371 having sent out one or more DHCPREQUEST packets. */
374 dhcpack(struct packet
*packet
)
376 struct interface_info
*ip
= packet
->interface
;
377 struct client_lease
*lease
;
379 /* If we're not receptive to an offer right now, or if the offer
380 has an unrecognizable transaction id, then just drop it. */
381 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
382 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
383 (memcmp(packet
->interface
->hw_address
.haddr
,
384 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
387 if (ip
->client
->state
!= S_REBOOTING
&&
388 ip
->client
->state
!= S_REQUESTING
&&
389 ip
->client
->state
!= S_RENEWING
&&
390 ip
->client
->state
!= S_REBINDING
)
393 note("DHCPACK from %s", piaddr(packet
->client_addr
));
395 lease
= packet_to_lease(packet
);
397 note("packet_to_lease failed.");
401 ip
->client
->new = lease
;
403 /* Stop resending DHCPREQUEST. */
404 cancel_timeout(send_request
, ip
);
406 /* Figure out the lease time. */
407 if (ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
)
408 ip
->client
->new->expiry
= getULong(
409 ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
);
411 ip
->client
->new->expiry
= default_lease_time
;
412 /* A number that looks negative here is really just very large,
413 because the lease expiry offset is unsigned. */
414 if (ip
->client
->new->expiry
< 0)
415 ip
->client
->new->expiry
= TIME_MAX
;
416 /* XXX should be fixed by resetting the client state */
417 if (ip
->client
->new->expiry
< 60)
418 ip
->client
->new->expiry
= 60;
420 /* Take the server-provided renewal time if there is one;
421 otherwise figure it out according to the spec. */
422 if (ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].len
)
423 ip
->client
->new->renewal
= getULong(
424 ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].data
);
426 ip
->client
->new->renewal
= ip
->client
->new->expiry
/ 2;
428 /* Same deal with the rebind time. */
429 if (ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].len
)
430 ip
->client
->new->rebind
= getULong(
431 ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].data
);
433 ip
->client
->new->rebind
= ip
->client
->new->renewal
+
434 ip
->client
->new->renewal
/ 2 + ip
->client
->new->renewal
/ 4;
437 ip
->client
->new->obtained
= cur_time
;
439 ip
->client
->new->expiry
+= cur_time
;
440 /* Lease lengths can never be negative. */
441 if (ip
->client
->new->expiry
< cur_time
)
442 ip
->client
->new->expiry
= TIME_MAX
;
443 ip
->client
->new->renewal
+= cur_time
;
444 if (ip
->client
->new->renewal
< cur_time
)
445 ip
->client
->new->renewal
= TIME_MAX
;
446 ip
->client
->new->rebind
+= cur_time
;
447 if (ip
->client
->new->rebind
< cur_time
)
448 ip
->client
->new->rebind
= TIME_MAX
;
453 void set_name_servers( PDHCP_ADAPTER Adapter
, struct client_lease
*new_lease
) {
454 CHAR Buffer
[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
457 strcat(Buffer
, Adapter
->DhclientInfo
.name
);
458 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, Buffer
, 0, KEY_WRITE
, &RegKey
) != ERROR_SUCCESS
)
462 if( new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
) {
464 struct iaddr nameserver
;
467 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
/ sizeof(ULONG
);
469 /* XXX I'm setting addrs to 1 until we are ready up the chain */
471 nsbuf
= malloc( addrs
* sizeof(IP_ADDRESS_STRING
) );
475 for( i
= 0; i
< addrs
; i
++ ) {
476 nameserver
.len
= sizeof(ULONG
);
477 memcpy( nameserver
.iabuf
,
478 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].data
+
479 (i
* sizeof(ULONG
)), sizeof(ULONG
) );
480 strcat( nsbuf
, piaddr(nameserver
) );
481 if( i
!= addrs
-1 ) strcat( nsbuf
, "," );
484 DH_DbgPrint(MID_TRACE
,("Setting DhcpNameserver: %s\n", nsbuf
));
486 RegSetValueExA( RegKey
, "DhcpNameServer", 0, REG_SZ
,
487 (LPBYTE
)nsbuf
, strlen(nsbuf
) + 1 );
492 RegDeleteValueW( RegKey
, L
"DhcpNameServer" );
495 RegCloseKey( RegKey
);
499 void setup_adapter( PDHCP_ADAPTER Adapter
, struct client_lease
*new_lease
) {
500 CHAR Buffer
[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
501 struct iaddr netmask
;
506 strcat(Buffer
, Adapter
->DhclientInfo
.name
);
507 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, Buffer
, 0, KEY_WRITE
, &hkey
) != ERROR_SUCCESS
)
511 if( Adapter
->NteContext
)
512 DeleteIPAddress( Adapter
->NteContext
);
514 /* Set up our default router if we got one from the DHCP server */
515 if( new_lease
->options
[DHO_SUBNET_MASK
].len
) {
518 memcpy( netmask
.iabuf
,
519 new_lease
->options
[DHO_SUBNET_MASK
].data
,
520 new_lease
->options
[DHO_SUBNET_MASK
].len
);
521 Status
= AddIPAddress
522 ( *((ULONG
*)new_lease
->address
.iabuf
),
523 *((ULONG
*)netmask
.iabuf
),
524 Adapter
->IfMib
.dwIndex
,
525 &Adapter
->NteContext
,
526 &Adapter
->NteInstance
);
528 RegSetValueExA(hkey
, "DhcpIPAddress", 0, REG_SZ
, (LPBYTE
)piaddr(new_lease
->address
), strlen(piaddr(new_lease
->address
))+1);
530 for(i
= 0; i
< new_lease
->options
[DHO_SUBNET_MASK
].len
; i
++)
532 sprintf(&Buffer
[strlen(Buffer
)], "%u", new_lease
->options
[DHO_SUBNET_MASK
].data
[i
]);
533 if (i
+ 1 < new_lease
->options
[DHO_SUBNET_MASK
].len
)
536 RegSetValueExA(hkey
, "DhcpSubnetMask", 0, REG_SZ
, (LPBYTE
)Buffer
, strlen(Buffer
)+1);
537 RegSetValueExA(hkey
, "IPAddress", 0, REG_SZ
, (LPBYTE
)"0.0.0.0", 8);
538 RegSetValueExA(hkey
, "SubnetMask", 0, REG_SZ
, (LPBYTE
)"0.0.0.0", 8);
540 RegSetValueExA(hkey
, "EnableDHCP", 0, REG_DWORD
, (LPBYTE
)&dwEnableDHCP
, sizeof(DWORD
));
543 if( !NT_SUCCESS(Status
) )
544 warning("AddIPAddress: %lx\n", Status
);
547 if( new_lease
->options
[DHO_ROUTERS
].len
) {
548 MIB_IPFORWARDROW RouterMib
;
551 RouterMib
.dwForwardDest
= 0; /* Default route */
552 RouterMib
.dwForwardMask
= 0;
553 RouterMib
.dwForwardMetric1
= 1;
555 if( old_default_route
) {
556 /* If we set a default route before, delete it before continuing */
557 RouterMib
.dwForwardDest
= old_default_route
;
558 DeleteIpForwardEntry( &RouterMib
);
561 RouterMib
.dwForwardNextHop
=
562 *((ULONG
*)new_lease
->options
[DHO_ROUTERS
].data
);
564 Status
= CreateIpForwardEntry( &RouterMib
);
566 if( !NT_SUCCESS(Status
) )
567 warning("CreateIpForwardEntry: %lx\n", Status
);
569 old_default_route
= RouterMib
.dwForwardNextHop
;
573 for(i
= 0; i
< new_lease
->options
[DHO_ROUTERS
].len
; i
++)
575 sprintf(&Buffer
[strlen(Buffer
)], "%u", new_lease
->options
[DHO_ROUTERS
].data
[i
]);
576 if (i
+ 1 < new_lease
->options
[DHO_ROUTERS
].len
)
579 RegSetValueExA(hkey
, "DhcpDefaultGateway", 0, REG_SZ
, (LPBYTE
)Buffer
, strlen(Buffer
)+1);
580 RegSetValueExA(hkey
, "DefaultGateway", 0, REG_SZ
, (LPBYTE
)"0.0.0.0", 8);
590 bind_lease(struct interface_info
*ip
)
592 PDHCP_ADAPTER Adapter
;
593 struct client_lease
*new_lease
= ip
->client
->new;
595 /* Remember the medium. */
596 ip
->client
->new->medium
= ip
->client
->medium
;
597 ip
->client
->active
= ip
->client
->new;
598 ip
->client
->new = NULL
;
600 /* Set up a timeout to start the renewal process. */
601 /* Timeout of zero means no timeout (some implementations seem to use
604 if( ip
->client
->active
->renewal
- cur_time
)
605 add_timeout(ip
->client
->active
->renewal
, state_bound
, ip
);
607 note("bound to %s -- renewal in %ld seconds.",
608 piaddr(ip
->client
->active
->address
),
609 ip
->client
->active
->renewal
- cur_time
);
611 ip
->client
->state
= S_BOUND
;
613 Adapter
= AdapterFindInfo( ip
);
615 if( Adapter
) setup_adapter( Adapter
, new_lease
);
616 else warning("Could not find adapter for info %p\n", ip
);
618 set_name_servers( Adapter
, new_lease
);
620 reinitialize_interfaces();
624 * state_bound is called when we've successfully bound to a particular
625 * lease, but the renewal time on that lease has expired. We are
626 * expected to unicast a DHCPREQUEST to the server that gave us our
630 state_bound(void *ipp
)
632 struct interface_info
*ip
= ipp
;
634 ASSERT_STATE(state
, S_BOUND
);
636 /* T1 has expired. */
637 make_request(ip
, ip
->client
->active
);
638 ip
->client
->xid
= ip
->client
->packet
.xid
;
640 if (ip
->client
->active
->options
[DHO_DHCP_SERVER_IDENTIFIER
].len
== 4) {
641 memcpy(ip
->client
->destination
.iabuf
, ip
->client
->active
->
642 options
[DHO_DHCP_SERVER_IDENTIFIER
].data
, 4);
643 ip
->client
->destination
.len
= 4;
645 ip
->client
->destination
= iaddr_broadcast
;
647 ip
->client
->first_sending
= cur_time
;
648 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
649 ip
->client
->state
= S_RENEWING
;
651 /* Send the first packet immediately. */
656 bootp(struct packet
*packet
)
658 struct iaddrlist
*ap
;
660 if (packet
->raw
->op
!= BOOTREPLY
)
663 /* If there's a reject list, make sure this packet's sender isn't
665 for (ap
= packet
->interface
->client
->config
->reject_list
;
667 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
668 note("BOOTREPLY from %s rejected.", piaddr(ap
->addr
));
676 dhcp(struct packet
*packet
)
678 struct iaddrlist
*ap
;
679 void (*handler
)(struct packet
*);
682 switch (packet
->packet_type
) {
699 /* If there's a reject list, make sure this packet's sender isn't
701 for (ap
= packet
->interface
->client
->config
->reject_list
;
703 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
704 note("%s from %s rejected.", type
, piaddr(ap
->addr
));
712 dhcpoffer(struct packet
*packet
)
714 struct interface_info
*ip
= packet
->interface
;
715 struct client_lease
*lease
, *lp
;
717 int arp_timeout_needed
= 0, stop_selecting
;
718 char *name
= packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
?
719 "DHCPOFFER" : "BOOTREPLY";
721 /* If we're not receptive to an offer right now, or if the offer
722 has an unrecognizable transaction id, then just drop it. */
723 if (ip
->client
->state
!= S_SELECTING
||
724 packet
->interface
->client
->xid
!= packet
->raw
->xid
||
725 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
726 (memcmp(packet
->interface
->hw_address
.haddr
,
727 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
730 note("%s from %s", name
, piaddr(packet
->client_addr
));
733 /* If this lease doesn't supply the minimum required parameters,
735 for (i
= 0; ip
->client
->config
->required_options
[i
]; i
++) {
736 if (!packet
->options
[ip
->client
->config
->
737 required_options
[i
]].len
) {
738 note("%s isn't satisfactory.", name
);
743 /* If we've already seen this lease, don't record it again. */
744 for (lease
= ip
->client
->offered_leases
;
745 lease
; lease
= lease
->next
) {
746 if (lease
->address
.len
== sizeof(packet
->raw
->yiaddr
) &&
747 !memcmp(lease
->address
.iabuf
,
748 &packet
->raw
->yiaddr
, lease
->address
.len
)) {
749 debug("%s already seen.", name
);
754 lease
= packet_to_lease(packet
);
756 note("packet_to_lease failed.");
760 /* If this lease was acquired through a BOOTREPLY, record that
762 if (!packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
)
765 /* Record the medium under which this lease was offered. */
766 lease
->medium
= ip
->client
->medium
;
768 /* Send out an ARP Request for the offered IP address. */
769 if( !check_arp( ip
, lease
) ) {
770 note("Arp check failed\n");
774 /* Figure out when we're supposed to stop selecting. */
776 ip
->client
->first_sending
+ ip
->client
->config
->select_interval
;
778 /* If this is the lease we asked for, put it at the head of the
779 list, and don't mess with the arp request timeout. */
780 if (lease
->address
.len
== ip
->client
->requested_address
.len
&&
781 !memcmp(lease
->address
.iabuf
,
782 ip
->client
->requested_address
.iabuf
,
783 ip
->client
->requested_address
.len
)) {
784 lease
->next
= ip
->client
->offered_leases
;
785 ip
->client
->offered_leases
= lease
;
787 /* If we already have an offer, and arping for this
788 offer would take us past the selection timeout,
789 then don't extend the timeout - just hope for the
791 if (ip
->client
->offered_leases
&&
792 (cur_time
+ arp_timeout_needed
) > stop_selecting
)
793 arp_timeout_needed
= 0;
795 /* Put the lease at the end of the list. */
797 if (!ip
->client
->offered_leases
)
798 ip
->client
->offered_leases
= lease
;
800 for (lp
= ip
->client
->offered_leases
; lp
->next
;
807 /* If we're supposed to stop selecting before we've had time
808 to wait for the ARPREPLY, add some delay to wait for
810 if (stop_selecting
- cur_time
< arp_timeout_needed
)
811 stop_selecting
= cur_time
+ arp_timeout_needed
;
813 /* If the selecting interval has expired, go immediately to
814 state_selecting(). Otherwise, time out into
815 state_selecting at the select interval. */
816 if (stop_selecting
<= 0)
819 add_timeout(stop_selecting
, state_selecting
, ip
);
820 cancel_timeout(send_discover
, ip
);
824 /* Allocate a client_lease structure and initialize it from the parameters
825 in the specified packet. */
827 struct client_lease
*
828 packet_to_lease(struct packet
*packet
)
830 struct client_lease
*lease
;
833 lease
= malloc(sizeof(struct client_lease
));
836 warning("dhcpoffer: no memory to record lease.");
840 memset(lease
, 0, sizeof(*lease
));
842 /* Copy the lease options. */
843 for (i
= 0; i
< 256; i
++) {
844 if (packet
->options
[i
].len
) {
845 lease
->options
[i
].data
=
846 malloc(packet
->options
[i
].len
+ 1);
847 if (!lease
->options
[i
].data
) {
848 warning("dhcpoffer: no memory for option %d", i
);
849 free_client_lease(lease
);
852 memcpy(lease
->options
[i
].data
,
853 packet
->options
[i
].data
,
854 packet
->options
[i
].len
);
855 lease
->options
[i
].len
=
856 packet
->options
[i
].len
;
857 lease
->options
[i
].data
[lease
->options
[i
].len
] =
860 if (!check_option(lease
,i
)) {
861 /* ignore a bogus lease offer */
862 warning("Invalid lease option - ignoring offer");
863 free_client_lease(lease
);
869 lease
->address
.len
= sizeof(packet
->raw
->yiaddr
);
870 memcpy(lease
->address
.iabuf
, &packet
->raw
->yiaddr
, lease
->address
.len
);
872 lease
->serveraddress
.len
= sizeof(packet
->raw
->siaddr
);
873 memcpy(lease
->serveraddress
.iabuf
, &packet
->raw
->siaddr
, lease
->address
.len
);
876 /* If the server name was filled out, copy it. */
877 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
878 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 2)) &&
879 packet
->raw
->sname
[0]) {
880 lease
->server_name
= malloc(DHCP_SNAME_LEN
+ 1);
881 if (!lease
->server_name
) {
882 warning("dhcpoffer: no memory for server name.");
883 free_client_lease(lease
);
886 memcpy(lease
->server_name
, packet
->raw
->sname
, DHCP_SNAME_LEN
);
887 lease
->server_name
[DHCP_SNAME_LEN
]='\0';
888 if (!res_hnok(lease
->server_name
) ) {
889 warning("Bogus server name %s", lease
->server_name
);
890 free_client_lease(lease
);
896 /* Ditto for the filename. */
897 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
898 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 1)) &&
899 packet
->raw
->file
[0]) {
900 /* Don't count on the NUL terminator. */
901 lease
->filename
= malloc(DHCP_FILE_LEN
+ 1);
902 if (!lease
->filename
) {
903 warning("dhcpoffer: no memory for filename.");
904 free_client_lease(lease
);
907 memcpy(lease
->filename
, packet
->raw
->file
, DHCP_FILE_LEN
);
908 lease
->filename
[DHCP_FILE_LEN
]='\0';
914 dhcpnak(struct packet
*packet
)
916 struct interface_info
*ip
= packet
->interface
;
918 /* If we're not receptive to an offer right now, or if the offer
919 has an unrecognizable transaction id, then just drop it. */
920 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
921 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
922 (memcmp(packet
->interface
->hw_address
.haddr
,
923 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
926 if (ip
->client
->state
!= S_REBOOTING
&&
927 ip
->client
->state
!= S_REQUESTING
&&
928 ip
->client
->state
!= S_RENEWING
&&
929 ip
->client
->state
!= S_REBINDING
)
932 note("DHCPNAK from %s", piaddr(packet
->client_addr
));
934 if (!ip
->client
->active
) {
935 note("DHCPNAK with no active lease.\n");
939 free_client_lease(ip
->client
->active
);
940 ip
->client
->active
= NULL
;
942 /* Stop sending DHCPREQUEST packets... */
943 cancel_timeout(send_request
, ip
);
945 ip
->client
->state
= S_INIT
;
949 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
950 one after the right interval has expired. If we don't get an offer by
951 the time we reach the panic interval, call the panic function. */
954 send_discover(void *ipp
)
956 struct interface_info
*ip
= ipp
;
957 int interval
, increase
= 1;
959 DH_DbgPrint(MID_TRACE
,("Doing discover on interface %p\n",ip
));
961 /* Figure out how long it's been since we started transmitting. */
962 interval
= cur_time
- ip
->client
->first_sending
;
964 /* If we're past the panic timeout, call the script and tell it
965 we haven't found anything for this interface yet. */
966 if (interval
> ip
->client
->config
->timeout
) {
971 /* If we're selecting media, try the whole list before doing
972 the exponential backoff, but if we've already received an
973 offer, stop looping, because we obviously have it right. */
974 if (!ip
->client
->offered_leases
&&
975 ip
->client
->config
->media
) {
978 if (ip
->client
->medium
) {
979 ip
->client
->medium
= ip
->client
->medium
->next
;
982 if (!ip
->client
->medium
) {
984 error("No valid media types for %s!", ip
->name
);
985 ip
->client
->medium
= ip
->client
->config
->media
;
989 note("Trying medium \"%s\" %d", ip
->client
->medium
->string
,
991 /* XXX Support other media types eventually */
995 * If we're supposed to increase the interval, do so. If it's
996 * currently zero (i.e., we haven't sent any packets yet), set
997 * it to one; otherwise, add to it a random number between zero
998 * and two times itself. On average, this means that it will
999 * double with every transmission.
1002 if (!ip
->client
->interval
)
1003 ip
->client
->interval
=
1004 ip
->client
->config
->initial_interval
;
1006 ip
->client
->interval
+= (rand() >> 2) %
1007 (2 * ip
->client
->interval
);
1010 /* Don't backoff past cutoff. */
1011 if (ip
->client
->interval
>
1012 ip
->client
->config
->backoff_cutoff
)
1013 ip
->client
->interval
=
1014 ((ip
->client
->config
->backoff_cutoff
/ 2)
1016 ip
->client
->config
->backoff_cutoff
));
1017 } else if (!ip
->client
->interval
)
1018 ip
->client
->interval
=
1019 ip
->client
->config
->initial_interval
;
1021 /* If the backoff would take us to the panic timeout, just use that
1023 if (cur_time
+ ip
->client
->interval
>
1024 ip
->client
->first_sending
+ ip
->client
->config
->timeout
)
1025 ip
->client
->interval
=
1026 (ip
->client
->first_sending
+
1027 ip
->client
->config
->timeout
) - cur_time
+ 1;
1029 /* Record the number of seconds since we started sending. */
1030 if (interval
< 65536)
1031 ip
->client
->packet
.secs
= htons(interval
);
1033 ip
->client
->packet
.secs
= htons(65535);
1034 ip
->client
->secs
= ip
->client
->packet
.secs
;
1036 note("DHCPDISCOVER on %s to %s port %d interval %ld",
1037 ip
->name
, inet_ntoa(sockaddr_broadcast
.sin_addr
),
1038 ntohs(sockaddr_broadcast
.sin_port
), ip
->client
->interval
);
1040 /* Send out a packet. */
1041 (void)send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1042 inaddr_any
, &sockaddr_broadcast
, NULL
);
1044 DH_DbgPrint(MID_TRACE
,("discover timeout: now %x -> then %x\n",
1045 cur_time
, cur_time
+ ip
->client
->interval
));
1047 add_timeout(cur_time
+ ip
->client
->interval
, send_discover
, ip
);
1051 * state_panic gets called if we haven't received any offers in a preset
1052 * amount of time. When this happens, we try to use existing leases
1053 * that haven't yet expired, and failing that, we call the client script
1054 * and hope it can do something.
1057 state_panic(void *ipp
)
1059 struct interface_info
*ip
= ipp
;
1060 struct client_lease
*loop
= ip
->client
->active
;
1061 struct client_lease
*lp
;
1063 note("No DHCPOFFERS received.");
1065 /* We may not have an active lease, but we may have some
1066 predefined leases that we can try. */
1067 if (!ip
->client
->active
&& ip
->client
->leases
)
1070 /* Run through the list of leases and see if one can be used. */
1071 while (ip
->client
->active
) {
1072 if (ip
->client
->active
->expiry
> cur_time
) {
1073 note("Trying recorded lease %s",
1074 piaddr(ip
->client
->active
->address
));
1075 /* Run the client script with the existing
1077 script_init("TIMEOUT",
1078 ip
->client
->active
->medium
);
1079 script_write_params("new_", ip
->client
->active
);
1080 if (ip
->client
->alias
)
1081 script_write_params("alias_",
1084 /* If the old lease is still good and doesn't
1085 yet need renewal, go into BOUND state and
1086 timeout at the renewal time. */
1088 ip
->client
->active
->renewal
) {
1089 ip
->client
->state
= S_BOUND
;
1090 note("bound: renewal in %ld seconds.",
1091 ip
->client
->active
->renewal
-
1094 ip
->client
->active
->renewal
,
1097 ip
->client
->state
= S_BOUND
;
1098 note("bound: immediate renewal.");
1101 reinitialize_interfaces();
1105 /* If there are no other leases, give up. */
1106 if (!ip
->client
->leases
) {
1107 ip
->client
->leases
= ip
->client
->active
;
1108 ip
->client
->active
= NULL
;
1113 /* Otherwise, put the active lease at the end of the
1114 lease list, and try another lease.. */
1115 for (lp
= ip
->client
->leases
; lp
->next
; lp
= lp
->next
)
1117 lp
->next
= ip
->client
->active
;
1119 lp
->next
->next
= NULL
;
1120 ip
->client
->active
= ip
->client
->leases
;
1121 ip
->client
->leases
= ip
->client
->leases
->next
;
1123 /* If we already tried this lease, we've exhausted the
1124 set of leases, so we might as well give up for
1126 if (ip
->client
->active
== loop
)
1129 loop
= ip
->client
->active
;
1132 /* No leases were available, or what was available didn't work, so
1133 tell the shell script that we failed to allocate an address,
1134 and try again later. */
1135 note("No working leases in persistent database - sleeping.\n");
1136 ip
->client
->state
= S_INIT
;
1137 add_timeout(cur_time
+ ip
->client
->config
->retry_interval
, state_init
,
1139 /* XXX Take any failure actions necessary */
1143 send_request(void *ipp
)
1145 struct interface_info
*ip
= ipp
;
1146 struct sockaddr_in destination
;
1147 struct in_addr from
;
1150 /* Figure out how long it's been since we started transmitting. */
1151 interval
= cur_time
- ip
->client
->first_sending
;
1153 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1154 past the reboot timeout, go to INIT and see if we can
1155 DISCOVER an address... */
1156 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1157 means either that we're on a network with no DHCP server,
1158 or that our server is down. In the latter case, assuming
1159 that there is a backup DHCP server, DHCPDISCOVER will get
1160 us a new address, but we could also have successfully
1161 reused our old address. In the former case, we're hosed
1162 anyway. This is not a win-prone situation. */
1163 if ((ip
->client
->state
== S_REBOOTING
||
1164 ip
->client
->state
== S_REQUESTING
) &&
1165 interval
> ip
->client
->config
->reboot_timeout
) {
1166 ip
->client
->state
= S_INIT
;
1167 cancel_timeout(send_request
, ip
);
1172 /* If we're in the reboot state, make sure the media is set up
1174 if (ip
->client
->state
== S_REBOOTING
&&
1175 !ip
->client
->medium
&&
1176 ip
->client
->active
->medium
) {
1177 script_init("MEDIUM", ip
->client
->active
->medium
);
1179 /* If the medium we chose won't fly, go to INIT state. */
1180 /* XXX Nothing for now */
1182 /* Record the medium. */
1183 ip
->client
->medium
= ip
->client
->active
->medium
;
1186 /* If the lease has expired, relinquish the address and go back
1187 to the INIT state. */
1188 if (ip
->client
->state
!= S_REQUESTING
&&
1189 cur_time
> ip
->client
->active
->expiry
) {
1190 PDHCP_ADAPTER Adapter
= AdapterFindInfo( ip
);
1191 /* Run the client script with the new parameters. */
1192 /* No script actions necessary in the expiry case */
1193 /* Now do a preinit on the interface so that we can
1194 discover a new address. */
1197 DeleteIPAddress( Adapter
->NteContext
);
1199 ip
->client
->state
= S_INIT
;
1204 /* Do the exponential backoff... */
1205 if (!ip
->client
->interval
)
1206 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
1208 ip
->client
->interval
+= ((rand() >> 2) %
1209 (2 * ip
->client
->interval
));
1211 /* Don't backoff past cutoff. */
1212 if (ip
->client
->interval
>
1213 ip
->client
->config
->backoff_cutoff
)
1214 ip
->client
->interval
=
1215 ((ip
->client
->config
->backoff_cutoff
/ 2) +
1216 ((rand() >> 2) % ip
->client
->interval
));
1218 /* If the backoff would take us to the expiry time, just set the
1219 timeout to the expiry time. */
1220 if (ip
->client
->state
!= S_REQUESTING
&&
1221 cur_time
+ ip
->client
->interval
>
1222 ip
->client
->active
->expiry
)
1223 ip
->client
->interval
=
1224 ip
->client
->active
->expiry
- cur_time
+ 1;
1226 /* If the lease T2 time has elapsed, or if we're not yet bound,
1227 broadcast the DHCPREQUEST rather than unicasting. */
1228 memset(&destination
, 0, sizeof(destination
));
1229 if (ip
->client
->state
== S_REQUESTING
||
1230 ip
->client
->state
== S_REBOOTING
||
1231 cur_time
> ip
->client
->active
->rebind
)
1232 destination
.sin_addr
.s_addr
= INADDR_BROADCAST
;
1234 memcpy(&destination
.sin_addr
.s_addr
,
1235 ip
->client
->destination
.iabuf
,
1236 sizeof(destination
.sin_addr
.s_addr
));
1237 destination
.sin_port
= htons(REMOTE_PORT
);
1238 destination
.sin_family
= AF_INET
;
1239 // destination.sin_len = sizeof(destination);
1241 if (ip
->client
->state
!= S_REQUESTING
)
1242 memcpy(&from
, ip
->client
->active
->address
.iabuf
,
1245 from
.s_addr
= INADDR_ANY
;
1247 /* Record the number of seconds since we started sending. */
1248 if (ip
->client
->state
== S_REQUESTING
)
1249 ip
->client
->packet
.secs
= ip
->client
->secs
;
1251 if (interval
< 65536)
1252 ip
->client
->packet
.secs
= htons(interval
);
1254 ip
->client
->packet
.secs
= htons(65535);
1257 note("DHCPREQUEST on %s to %s port %d", ip
->name
,
1258 inet_ntoa(destination
.sin_addr
), ntohs(destination
.sin_port
));
1260 /* Send out a packet. */
1261 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1262 from
, &destination
, NULL
);
1264 add_timeout(cur_time
+ ip
->client
->interval
, send_request
, ip
);
1268 send_decline(void *ipp
)
1270 struct interface_info
*ip
= ipp
;
1272 note("DHCPDECLINE on %s to %s port %d", ip
->name
,
1273 inet_ntoa(sockaddr_broadcast
.sin_addr
),
1274 ntohs(sockaddr_broadcast
.sin_port
));
1276 /* Send out a packet. */
1277 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1278 inaddr_any
, &sockaddr_broadcast
, NULL
);
1282 make_discover(struct interface_info
*ip
, struct client_lease
*lease
)
1284 unsigned char discover
= DHCPDISCOVER
;
1285 struct tree_cache
*options
[256];
1286 struct tree_cache option_elements
[256];
1288 ULONG foo
= (ULONG
) GetTickCount();
1290 memset(option_elements
, 0, sizeof(option_elements
));
1291 memset(options
, 0, sizeof(options
));
1292 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1294 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1295 i
= DHO_DHCP_MESSAGE_TYPE
;
1296 options
[i
] = &option_elements
[i
];
1297 options
[i
]->value
= &discover
;
1298 options
[i
]->len
= sizeof(discover
);
1299 options
[i
]->buf_size
= sizeof(discover
);
1300 options
[i
]->timeout
= 0xFFFFFFFF;
1302 /* Request the options we want */
1303 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1304 options
[i
] = &option_elements
[i
];
1305 options
[i
]->value
= ip
->client
->config
->requested_options
;
1306 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1307 options
[i
]->buf_size
=
1308 ip
->client
->config
->requested_option_count
;
1309 options
[i
]->timeout
= 0xFFFFFFFF;
1311 /* If we had an address, try to get it again. */
1313 ip
->client
->requested_address
= lease
->address
;
1314 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1315 options
[i
] = &option_elements
[i
];
1316 options
[i
]->value
= lease
->address
.iabuf
;
1317 options
[i
]->len
= lease
->address
.len
;
1318 options
[i
]->buf_size
= lease
->address
.len
;
1319 options
[i
]->timeout
= 0xFFFFFFFF;
1321 ip
->client
->requested_address
.len
= 0;
1323 /* Send any options requested in the config file. */
1324 for (i
= 0; i
< 256; i
++)
1326 ip
->client
->config
->send_options
[i
].data
) {
1327 options
[i
] = &option_elements
[i
];
1329 ip
->client
->config
->send_options
[i
].data
;
1331 ip
->client
->config
->send_options
[i
].len
;
1332 options
[i
]->buf_size
=
1333 ip
->client
->config
->send_options
[i
].len
;
1334 options
[i
]->timeout
= 0xFFFFFFFF;
1337 /* Set up the option buffer... */
1338 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1339 options
, 0, 0, 0, NULL
, 0);
1340 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1341 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1343 ip
->client
->packet
.op
= BOOTREQUEST
;
1344 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1345 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1346 ip
->client
->packet
.hops
= 0;
1347 ip
->client
->packet
.xid
= RtlRandom(&foo
);
1348 ip
->client
->packet
.secs
= 0; /* filled in by send_discover. */
1349 ip
->client
->packet
.flags
= 0;
1351 memset(&(ip
->client
->packet
.ciaddr
),
1352 0, sizeof(ip
->client
->packet
.ciaddr
));
1353 memset(&(ip
->client
->packet
.yiaddr
),
1354 0, sizeof(ip
->client
->packet
.yiaddr
));
1355 memset(&(ip
->client
->packet
.siaddr
),
1356 0, sizeof(ip
->client
->packet
.siaddr
));
1357 memset(&(ip
->client
->packet
.giaddr
),
1358 0, sizeof(ip
->client
->packet
.giaddr
));
1359 memcpy(ip
->client
->packet
.chaddr
,
1360 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1365 make_request(struct interface_info
*ip
, struct client_lease
* lease
)
1367 unsigned char request
= DHCPREQUEST
;
1368 struct tree_cache
*options
[256];
1369 struct tree_cache option_elements
[256];
1372 memset(options
, 0, sizeof(options
));
1373 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1375 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1376 i
= DHO_DHCP_MESSAGE_TYPE
;
1377 options
[i
] = &option_elements
[i
];
1378 options
[i
]->value
= &request
;
1379 options
[i
]->len
= sizeof(request
);
1380 options
[i
]->buf_size
= sizeof(request
);
1381 options
[i
]->timeout
= 0xFFFFFFFF;
1383 /* Request the options we want */
1384 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1385 options
[i
] = &option_elements
[i
];
1386 options
[i
]->value
= ip
->client
->config
->requested_options
;
1387 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1388 options
[i
]->buf_size
=
1389 ip
->client
->config
->requested_option_count
;
1390 options
[i
]->timeout
= 0xFFFFFFFF;
1392 /* If we are requesting an address that hasn't yet been assigned
1393 to us, use the DHCP Requested Address option. */
1394 if (ip
->client
->state
== S_REQUESTING
) {
1395 /* Send back the server identifier... */
1396 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1397 options
[i
] = &option_elements
[i
];
1398 options
[i
]->value
= lease
->options
[i
].data
;
1399 options
[i
]->len
= lease
->options
[i
].len
;
1400 options
[i
]->buf_size
= lease
->options
[i
].len
;
1401 options
[i
]->timeout
= 0xFFFFFFFF;
1403 if (ip
->client
->state
== S_REQUESTING
||
1404 ip
->client
->state
== S_REBOOTING
) {
1405 ip
->client
->requested_address
= lease
->address
;
1406 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1407 options
[i
] = &option_elements
[i
];
1408 options
[i
]->value
= lease
->address
.iabuf
;
1409 options
[i
]->len
= lease
->address
.len
;
1410 options
[i
]->buf_size
= lease
->address
.len
;
1411 options
[i
]->timeout
= 0xFFFFFFFF;
1413 ip
->client
->requested_address
.len
= 0;
1415 /* Send any options requested in the config file. */
1416 for (i
= 0; i
< 256; i
++)
1418 ip
->client
->config
->send_options
[i
].data
) {
1419 options
[i
] = &option_elements
[i
];
1421 ip
->client
->config
->send_options
[i
].data
;
1423 ip
->client
->config
->send_options
[i
].len
;
1424 options
[i
]->buf_size
=
1425 ip
->client
->config
->send_options
[i
].len
;
1426 options
[i
]->timeout
= 0xFFFFFFFF;
1429 /* Set up the option buffer... */
1430 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1431 options
, 0, 0, 0, NULL
, 0);
1432 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1433 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1435 ip
->client
->packet
.op
= BOOTREQUEST
;
1436 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1437 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1438 ip
->client
->packet
.hops
= 0;
1439 ip
->client
->packet
.xid
= ip
->client
->xid
;
1440 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1442 /* If we own the address we're requesting, put it in ciaddr;
1443 otherwise set ciaddr to zero. */
1444 if (ip
->client
->state
== S_BOUND
||
1445 ip
->client
->state
== S_RENEWING
||
1446 ip
->client
->state
== S_REBINDING
) {
1447 memcpy(&ip
->client
->packet
.ciaddr
,
1448 lease
->address
.iabuf
, lease
->address
.len
);
1449 ip
->client
->packet
.flags
= 0;
1451 memset(&ip
->client
->packet
.ciaddr
, 0,
1452 sizeof(ip
->client
->packet
.ciaddr
));
1453 ip
->client
->packet
.flags
= 0;
1456 memset(&ip
->client
->packet
.yiaddr
, 0,
1457 sizeof(ip
->client
->packet
.yiaddr
));
1458 memset(&ip
->client
->packet
.siaddr
, 0,
1459 sizeof(ip
->client
->packet
.siaddr
));
1460 memset(&ip
->client
->packet
.giaddr
, 0,
1461 sizeof(ip
->client
->packet
.giaddr
));
1462 memcpy(ip
->client
->packet
.chaddr
,
1463 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1467 make_decline(struct interface_info
*ip
, struct client_lease
*lease
)
1469 struct tree_cache
*options
[256], message_type_tree
;
1470 struct tree_cache requested_address_tree
;
1471 struct tree_cache server_id_tree
, client_id_tree
;
1472 unsigned char decline
= DHCPDECLINE
;
1475 memset(options
, 0, sizeof(options
));
1476 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1478 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1479 i
= DHO_DHCP_MESSAGE_TYPE
;
1480 options
[i
] = &message_type_tree
;
1481 options
[i
]->value
= &decline
;
1482 options
[i
]->len
= sizeof(decline
);
1483 options
[i
]->buf_size
= sizeof(decline
);
1484 options
[i
]->timeout
= 0xFFFFFFFF;
1486 /* Send back the server identifier... */
1487 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1488 options
[i
] = &server_id_tree
;
1489 options
[i
]->value
= lease
->options
[i
].data
;
1490 options
[i
]->len
= lease
->options
[i
].len
;
1491 options
[i
]->buf_size
= lease
->options
[i
].len
;
1492 options
[i
]->timeout
= 0xFFFFFFFF;
1494 /* Send back the address we're declining. */
1495 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1496 options
[i
] = &requested_address_tree
;
1497 options
[i
]->value
= lease
->address
.iabuf
;
1498 options
[i
]->len
= lease
->address
.len
;
1499 options
[i
]->buf_size
= lease
->address
.len
;
1500 options
[i
]->timeout
= 0xFFFFFFFF;
1502 /* Send the uid if the user supplied one. */
1503 i
= DHO_DHCP_CLIENT_IDENTIFIER
;
1504 if (ip
->client
->config
->send_options
[i
].len
) {
1505 options
[i
] = &client_id_tree
;
1506 options
[i
]->value
= ip
->client
->config
->send_options
[i
].data
;
1507 options
[i
]->len
= ip
->client
->config
->send_options
[i
].len
;
1508 options
[i
]->buf_size
= ip
->client
->config
->send_options
[i
].len
;
1509 options
[i
]->timeout
= 0xFFFFFFFF;
1513 /* Set up the option buffer... */
1514 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1515 options
, 0, 0, 0, NULL
, 0);
1516 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1517 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1519 ip
->client
->packet
.op
= BOOTREQUEST
;
1520 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1521 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1522 ip
->client
->packet
.hops
= 0;
1523 ip
->client
->packet
.xid
= ip
->client
->xid
;
1524 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1525 ip
->client
->packet
.flags
= 0;
1527 /* ciaddr must always be zero. */
1528 memset(&ip
->client
->packet
.ciaddr
, 0,
1529 sizeof(ip
->client
->packet
.ciaddr
));
1530 memset(&ip
->client
->packet
.yiaddr
, 0,
1531 sizeof(ip
->client
->packet
.yiaddr
));
1532 memset(&ip
->client
->packet
.siaddr
, 0,
1533 sizeof(ip
->client
->packet
.siaddr
));
1534 memset(&ip
->client
->packet
.giaddr
, 0,
1535 sizeof(ip
->client
->packet
.giaddr
));
1536 memcpy(ip
->client
->packet
.chaddr
,
1537 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1541 free_client_lease(struct client_lease
*lease
)
1545 if (lease
->server_name
)
1546 free(lease
->server_name
);
1547 if (lease
->filename
)
1548 free(lease
->filename
);
1549 for (i
= 0; i
< 256; i
++) {
1550 if (lease
->options
[i
].len
)
1551 free(lease
->options
[i
].data
);
1559 rewrite_client_leases(void)
1561 struct client_lease
*lp
;
1564 leaseFile
= fopen(path_dhclient_db
, "w");
1566 error("can't create %s: %m", path_dhclient_db
);
1572 for (lp
= ifi
->client
->leases
; lp
; lp
= lp
->next
)
1573 write_client_lease(ifi
, lp
, 1);
1574 if (ifi
->client
->active
)
1575 write_client_lease(ifi
, ifi
->client
->active
, 1);
1581 write_client_lease(struct interface_info
*ip
, struct client_lease
*lease
,
1584 static int leases_written
;
1589 if (leases_written
++ > 20) {
1590 rewrite_client_leases();
1595 /* If the lease came from the config file, we don't need to stash
1596 a copy in the lease database. */
1597 if (lease
->is_static
)
1600 if (!leaseFile
) { /* XXX */
1601 leaseFile
= fopen(path_dhclient_db
, "w");
1603 error("can't create %s: %m", path_dhclient_db
);
1606 fprintf(leaseFile
, "lease {\n");
1607 if (lease
->is_bootp
)
1608 fprintf(leaseFile
, " bootp;\n");
1609 fprintf(leaseFile
, " interface \"%s\";\n", ip
->name
);
1610 fprintf(leaseFile
, " fixed-address %s;\n", piaddr(lease
->address
));
1611 if (lease
->filename
)
1612 fprintf(leaseFile
, " filename \"%s\";\n", lease
->filename
);
1613 if (lease
->server_name
)
1614 fprintf(leaseFile
, " server-name \"%s\";\n",
1615 lease
->server_name
);
1617 fprintf(leaseFile
, " medium \"%s\";\n", lease
->medium
->string
);
1618 for (i
= 0; i
< 256; i
++)
1619 if (lease
->options
[i
].len
)
1620 fprintf(leaseFile
, " option %s %s;\n",
1621 dhcp_options
[i
].name
,
1622 pretty_print_option(i
, lease
->options
[i
].data
,
1623 lease
->options
[i
].len
, 1, 1));
1625 t
= gmtime(&lease
->renewal
);
1626 fprintf(leaseFile
, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1627 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1628 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1629 t
= gmtime(&lease
->rebind
);
1630 fprintf(leaseFile
, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1631 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1632 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1633 t
= gmtime(&lease
->expiry
);
1634 fprintf(leaseFile
, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1635 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1636 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1637 fprintf(leaseFile
, "}\n");
1642 script_init(char *reason
, struct string_list
*medium
)
1644 size_t len
, mediumlen
= 0;
1645 struct imsg_hdr hdr
;
1649 if (medium
!= NULL
&& medium
->string
!= NULL
)
1650 mediumlen
= strlen(medium
->string
);
1652 hdr
.code
= IMSG_SCRIPT_INIT
;
1653 hdr
.len
= sizeof(struct imsg_hdr
) +
1654 sizeof(size_t) + mediumlen
+
1655 sizeof(size_t) + strlen(reason
);
1657 if ((buf
= buf_open(hdr
.len
)) == NULL
)
1658 error("buf_open: %m");
1661 errs
+= buf_add(buf
, &hdr
, sizeof(hdr
));
1662 errs
+= buf_add(buf
, &mediumlen
, sizeof(mediumlen
));
1664 errs
+= buf_add(buf
, medium
->string
, mediumlen
);
1665 len
= strlen(reason
);
1666 errs
+= buf_add(buf
, &len
, sizeof(len
));
1667 errs
+= buf_add(buf
, reason
, len
);
1670 error("buf_add: %m");
1672 if (buf_close(privfd
, buf
) == -1)
1673 error("buf_close: %m");
1677 priv_script_init(char *reason
, char *medium
)
1679 struct interface_info
*ip
= ifi
;
1682 // XXX Do we need to do anything?
1687 priv_script_write_params(char *prefix
, struct client_lease
*lease
)
1689 struct interface_info
*ip
= ifi
;
1690 u_int8_t dbuf
[1500];
1694 script_set_env(ip
->client
, prefix
, "ip_address",
1695 piaddr(lease
->address
));
1698 if (lease
->options
[DHO_SUBNET_MASK
].len
&&
1699 (lease
->options
[DHO_SUBNET_MASK
].len
<
1700 sizeof(lease
->address
.iabuf
))) {
1701 struct iaddr netmask
, subnet
, broadcast
;
1703 memcpy(netmask
.iabuf
, lease
->options
[DHO_SUBNET_MASK
].data
,
1704 lease
->options
[DHO_SUBNET_MASK
].len
);
1705 netmask
.len
= lease
->options
[DHO_SUBNET_MASK
].len
;
1707 subnet
= subnet_number(lease
->address
, netmask
);
1710 script_set_env(ip
->client
, prefix
, "network_number",
1713 if (!lease
->options
[DHO_BROADCAST_ADDRESS
].len
) {
1714 broadcast
= broadcast_addr(subnet
, netmask
);
1717 script_set_env(ip
->client
, prefix
,
1718 "broadcast_address",
1728 if (lease
->filename
)
1729 script_set_env(ip
->client
, prefix
, "filename", lease
->filename
);
1730 if (lease
->server_name
)
1731 script_set_env(ip
->client
, prefix
, "server_name",
1732 lease
->server_name
);
1735 for (i
= 0; i
< 256; i
++) {
1736 u_int8_t
*dp
= NULL
;
1738 if (ip
->client
->config
->defaults
[i
].len
) {
1739 if (lease
->options
[i
].len
) {
1741 ip
->client
->config
->default_actions
[i
]) {
1742 case ACTION_DEFAULT
:
1743 dp
= lease
->options
[i
].data
;
1744 len
= lease
->options
[i
].len
;
1746 case ACTION_SUPERSEDE
:
1749 config
->defaults
[i
].data
;
1751 config
->defaults
[i
].len
;
1753 case ACTION_PREPEND
:
1755 config
->defaults
[i
].len
+
1756 lease
->options
[i
].len
;
1757 if (len
>= sizeof(dbuf
)) {
1758 warning("no space to %s %s",
1760 dhcp_options
[i
].name
);
1766 config
->defaults
[i
].data
,
1768 config
->defaults
[i
].len
);
1769 memcpy(dp
+ ip
->client
->
1770 config
->defaults
[i
].len
,
1771 lease
->options
[i
].data
,
1772 lease
->options
[i
].len
);
1777 config
->defaults
[i
].len
+
1778 lease
->options
[i
].len
;
1779 if (len
> sizeof(dbuf
)) {
1780 warning("no space to %s %s",
1782 dhcp_options
[i
].name
);
1787 lease
->options
[i
].data
,
1788 lease
->options
[i
].len
);
1789 memcpy(dp
+ lease
->options
[i
].len
,
1791 config
->defaults
[i
].data
,
1793 config
->defaults
[i
].len
);
1798 config
->defaults
[i
].data
;
1800 config
->defaults
[i
].len
;
1802 } else if (lease
->options
[i
].len
) {
1803 len
= lease
->options
[i
].len
;
1804 dp
= lease
->options
[i
].data
;
1812 if (dhcp_option_ev_name(name
, sizeof(name
),
1814 script_set_env(ip
->client
, prefix
, name
,
1815 pretty_print_option(i
, dp
, len
, 0, 0));
1820 snprintf(tbuf
, sizeof(tbuf
), "%d", (int)lease
->expiry
);
1821 script_set_env(ip
->client
, prefix
, "expiry", tbuf
);
1826 script_write_params(char *prefix
, struct client_lease
*lease
)
1828 size_t fn_len
= 0, sn_len
= 0, pr_len
= 0;
1829 struct imsg_hdr hdr
;
1833 if (lease
->filename
!= NULL
)
1834 fn_len
= strlen(lease
->filename
);
1835 if (lease
->server_name
!= NULL
)
1836 sn_len
= strlen(lease
->server_name
);
1838 pr_len
= strlen(prefix
);
1840 hdr
.code
= IMSG_SCRIPT_WRITE_PARAMS
;
1841 hdr
.len
= sizeof(hdr
) + sizeof(struct client_lease
) +
1842 sizeof(size_t) + fn_len
+ sizeof(size_t) + sn_len
+
1843 sizeof(size_t) + pr_len
;
1845 for (i
= 0; i
< 256; i
++)
1846 hdr
.len
+= sizeof(int) + lease
->options
[i
].len
;
1848 scripttime
= time(NULL
);
1850 if ((buf
= buf_open(hdr
.len
)) == NULL
)
1851 error("buf_open: %m");
1854 errs
+= buf_add(buf
, &hdr
, sizeof(hdr
));
1855 errs
+= buf_add(buf
, lease
, sizeof(struct client_lease
));
1856 errs
+= buf_add(buf
, &fn_len
, sizeof(fn_len
));
1857 errs
+= buf_add(buf
, lease
->filename
, fn_len
);
1858 errs
+= buf_add(buf
, &sn_len
, sizeof(sn_len
));
1859 errs
+= buf_add(buf
, lease
->server_name
, sn_len
);
1860 errs
+= buf_add(buf
, &pr_len
, sizeof(pr_len
));
1861 errs
+= buf_add(buf
, prefix
, pr_len
);
1863 for (i
= 0; i
< 256; i
++) {
1864 errs
+= buf_add(buf
, &lease
->options
[i
].len
,
1865 sizeof(lease
->options
[i
].len
));
1866 errs
+= buf_add(buf
, lease
->options
[i
].data
,
1867 lease
->options
[i
].len
);
1871 error("buf_add: %m");
1873 if (buf_close(privfd
, buf
) == -1)
1874 error("buf_close: %m");
1878 dhcp_option_ev_name(char *buf
, size_t buflen
, struct dhcp_option
*option
)
1882 for (i
= 0; option
->name
[i
]; i
++) {
1883 if (i
+ 1 == buflen
)
1885 if (option
->name
[i
] == '-')
1888 buf
[i
] = option
->name
[i
];
1899 static int state
= 0;
1901 if (no_daemon
|| state
)
1906 /* Stop logging to stderr... */
1909 if (daemon(1, 0) == -1)
1912 /* we are chrooted, daemon(3) fails to open /dev/null */
1914 dup2(nullfd
, STDIN_FILENO
);
1915 dup2(nullfd
, STDOUT_FILENO
);
1916 dup2(nullfd
, STDERR_FILENO
);
1924 check_option(struct client_lease
*l
, int option
)
1929 /* we use this, since this is what gets passed to dhclient-script */
1931 opbuf
= pretty_print_option(option
, l
->options
[option
].data
,
1932 l
->options
[option
].len
, 0, 0);
1934 sbuf
= option_as_string(option
, l
->options
[option
].data
,
1935 l
->options
[option
].len
);
1938 case DHO_SUBNET_MASK
:
1939 case DHO_TIME_SERVERS
:
1940 case DHO_NAME_SERVERS
:
1942 case DHO_DOMAIN_NAME_SERVERS
:
1943 case DHO_LOG_SERVERS
:
1944 case DHO_COOKIE_SERVERS
:
1945 case DHO_LPR_SERVERS
:
1946 case DHO_IMPRESS_SERVERS
:
1947 case DHO_RESOURCE_LOCATION_SERVERS
:
1948 case DHO_SWAP_SERVER
:
1949 case DHO_BROADCAST_ADDRESS
:
1950 case DHO_NIS_SERVERS
:
1951 case DHO_NTP_SERVERS
:
1952 case DHO_NETBIOS_NAME_SERVERS
:
1953 case DHO_NETBIOS_DD_SERVER
:
1954 case DHO_FONT_SERVERS
:
1955 case DHO_DHCP_SERVER_IDENTIFIER
:
1956 if (!ipv4addrs(opbuf
)) {
1957 warning("Invalid IP address in option(%d): %s", option
, opbuf
);
1962 case DHO_DOMAIN_NAME
:
1963 case DHO_NIS_DOMAIN
:
1964 if (!res_hnok(sbuf
)) {
1965 warning("Bogus Host Name option %d: %s (%s)", option
,
1971 case DHO_TIME_OFFSET
:
1973 case DHO_MERIT_DUMP
:
1975 case DHO_EXTENSIONS_PATH
:
1976 case DHO_IP_FORWARDING
:
1977 case DHO_NON_LOCAL_SOURCE_ROUTING
:
1978 case DHO_POLICY_FILTER
:
1979 case DHO_MAX_DGRAM_REASSEMBLY
:
1980 case DHO_DEFAULT_IP_TTL
:
1981 case DHO_PATH_MTU_AGING_TIMEOUT
:
1982 case DHO_PATH_MTU_PLATEAU_TABLE
:
1983 case DHO_INTERFACE_MTU
:
1984 case DHO_ALL_SUBNETS_LOCAL
:
1985 case DHO_PERFORM_MASK_DISCOVERY
:
1986 case DHO_MASK_SUPPLIER
:
1987 case DHO_ROUTER_DISCOVERY
:
1988 case DHO_ROUTER_SOLICITATION_ADDRESS
:
1989 case DHO_STATIC_ROUTES
:
1990 case DHO_TRAILER_ENCAPSULATION
:
1991 case DHO_ARP_CACHE_TIMEOUT
:
1992 case DHO_IEEE802_3_ENCAPSULATION
:
1993 case DHO_DEFAULT_TCP_TTL
:
1994 case DHO_TCP_KEEPALIVE_INTERVAL
:
1995 case DHO_TCP_KEEPALIVE_GARBAGE
:
1996 case DHO_VENDOR_ENCAPSULATED_OPTIONS
:
1997 case DHO_NETBIOS_NODE_TYPE
:
1998 case DHO_NETBIOS_SCOPE
:
1999 case DHO_X_DISPLAY_MANAGER
:
2000 case DHO_DHCP_REQUESTED_ADDRESS
:
2001 case DHO_DHCP_LEASE_TIME
:
2002 case DHO_DHCP_OPTION_OVERLOAD
:
2003 case DHO_DHCP_MESSAGE_TYPE
:
2004 case DHO_DHCP_PARAMETER_REQUEST_LIST
:
2005 case DHO_DHCP_MESSAGE
:
2006 case DHO_DHCP_MAX_MESSAGE_SIZE
:
2007 case DHO_DHCP_RENEWAL_TIME
:
2008 case DHO_DHCP_REBINDING_TIME
:
2009 case DHO_DHCP_CLASS_IDENTIFIER
:
2010 case DHO_DHCP_CLIENT_IDENTIFIER
:
2011 case DHO_DHCP_USER_CLASS_ID
:
2015 warning("unknown dhcp option value 0x%x", option
);
2016 return (unknown_ok
);
2021 res_hnok(const char *dn
)
2023 int pch
= PERIOD
, ch
= *dn
++;
2025 while (ch
!= '\0') {
2028 if (periodchar(ch
)) {
2030 } else if (periodchar(pch
)) {
2031 if (!borderchar(ch
))
2033 } else if (periodchar(nch
) || nch
== '\0') {
2034 if (!borderchar(ch
))
2037 if (!middlechar(ch
))
2045 /* Does buf consist only of dotted decimal ipv4 addrs?
2046 * return how many if so,
2047 * otherwise, return 0
2050 ipv4addrs(char * buf
)
2056 note("Input: %s", buf
);
2059 tmp
= strtok(buf
, " ");
2060 note("got %s", tmp
);
2061 if( tmp
&& inet_aton(tmp
, &jnk
) ) i
++;
2070 option_as_string(unsigned int code
, unsigned char *data
, int len
)
2072 static char optbuf
[32768]; /* XXX */
2074 int opleft
= sizeof(optbuf
);
2075 unsigned char *dp
= data
;
2078 error("option_as_string: bad code %d", code
);
2080 for (; dp
< data
+ len
; dp
++) {
2081 if (!isascii(*dp
) || !isprint(*dp
)) {
2082 if (dp
+ 1 != data
+ len
|| *dp
!= 0) {
2083 _snprintf(op
, opleft
, "\\%03o", *dp
);
2087 } else if (*dp
== '"' || *dp
== '\'' || *dp
== '$' ||
2088 *dp
== '`' || *dp
== '\\') {
2102 warning("dhcp option too large");
2108 fork_privchld(int fd
, int fd2
)
2110 struct pollfd pfd
[1];
2115 error("cannot fork");
2122 setproctitle("%s [priv]", ifi
->name
);
2124 dup2(nullfd
, STDIN_FILENO
);
2125 dup2(nullfd
, STDOUT_FILENO
);
2126 dup2(nullfd
, STDERR_FILENO
);
2132 pfd
[0].events
= POLLIN
;
2133 if ((nfds
= poll(pfd
, 1, INFTIM
)) == -1)
2135 error("poll error");
2137 if (nfds
== 0 || !(pfd
[0].revents
& POLLIN
))