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
63 #define hyphenchar(c) ((c) == 0x2d)
64 #define bslashchar(c) ((c) == 0x5c)
65 #define periodchar(c) ((c) == PERIOD)
66 #define asterchar(c) ((c) == 0x2a)
67 #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
68 ((c) >= 0x61 && (c) <= 0x7a))
69 #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
71 #define borderchar(c) (alphachar(c) || digitchar(c))
72 #define middlechar(c) (borderchar(c) || hyphenchar(c))
73 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
75 unsigned long debug_trace_level
= 0; /* DEBUG_ULTRA */
77 char *path_dhclient_conf
= _PATH_DHCLIENT_CONF
;
78 char *path_dhclient_db
= NULL
;
84 struct iaddr iaddr_broadcast
= { 4, { 255, 255, 255, 255 } };
85 struct in_addr inaddr_any
;
86 struct sockaddr_in sockaddr_broadcast
;
89 * ASSERT_STATE() does nothing now; it used to be
90 * assert (state_is == state_shouldbe).
92 #define ASSERT_STATE(state_is, state_shouldbe) {}
94 #define TIME_MAX 2147483647
102 int check_option(struct client_lease
*l
, int option
);
103 int ipv4addrs(char * buf
);
104 int res_hnok(const char *dn
);
105 char *option_as_string(unsigned int code
, unsigned char *data
, int len
);
106 int fork_privchld(int, int);
107 int check_arp( struct interface_info
*ip
, struct client_lease
*lp
);
109 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
114 static VOID CALLBACK
ServiceMain(DWORD argc
, LPWSTR
*argv
);
115 static WCHAR ServiceName
[] = L
"DHCP";
116 static SERVICE_TABLE_ENTRYW ServiceTable
[] =
118 {ServiceName
, ServiceMain
},
122 SERVICE_STATUS_HANDLE ServiceStatusHandle
;
123 SERVICE_STATUS ServiceStatus
;
126 /* XXX Implement me */
127 int check_arp( struct interface_info
*ip
, struct client_lease
*lp
) {
133 UpdateServiceStatus(DWORD dwState
)
135 ServiceStatus
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
136 ServiceStatus
.dwCurrentState
= dwState
;
138 ServiceStatus
.dwControlsAccepted
= 0;
140 ServiceStatus
.dwWin32ExitCode
= 0;
141 ServiceStatus
.dwServiceSpecificExitCode
= 0;
142 ServiceStatus
.dwCheckPoint
= 0;
144 if (dwState
== SERVICE_START_PENDING
||
145 dwState
== SERVICE_STOP_PENDING
||
146 dwState
== SERVICE_PAUSE_PENDING
||
147 dwState
== SERVICE_CONTINUE_PENDING
)
148 ServiceStatus
.dwWaitHint
= 10000;
150 ServiceStatus
.dwWaitHint
= 0;
152 SetServiceStatus(ServiceStatusHandle
,
158 ServiceControlHandler(DWORD dwControl
,
165 case SERVICE_CONTROL_STOP
:
166 UpdateServiceStatus(SERVICE_STOP_PENDING
);
167 UpdateServiceStatus(SERVICE_STOPPED
);
168 return ERROR_SUCCESS
;
170 case SERVICE_CONTROL_PAUSE
:
171 UpdateServiceStatus(SERVICE_PAUSED
);
172 return ERROR_SUCCESS
;
174 case SERVICE_CONTROL_CONTINUE
:
175 UpdateServiceStatus(SERVICE_START_PENDING
);
176 UpdateServiceStatus(SERVICE_RUNNING
);
177 return ERROR_SUCCESS
;
179 case SERVICE_CONTROL_INTERROGATE
:
180 SetServiceStatus(ServiceStatusHandle
,
182 return ERROR_SUCCESS
;
184 case SERVICE_CONTROL_SHUTDOWN
:
185 UpdateServiceStatus(SERVICE_STOP_PENDING
);
186 UpdateServiceStatus(SERVICE_STOPPED
);
187 return ERROR_SUCCESS
;
190 return ERROR_CALL_NOT_IMPLEMENTED
;
196 ServiceMain(DWORD argc
, LPWSTR
*argv
)
198 ServiceStatusHandle
= RegisterServiceCtrlHandlerExW(ServiceName
,
199 ServiceControlHandler
,
201 if (!ServiceStatusHandle
)
206 UpdateServiceStatus(SERVICE_START_PENDING
);
208 UpdateServiceStatus(SERVICE_RUNNING
);
215 main(int argc
, char *argv
[])
223 memset(&sockaddr_broadcast
, 0, sizeof(sockaddr_broadcast
));
224 sockaddr_broadcast
.sin_family
= AF_INET
;
225 sockaddr_broadcast
.sin_port
= htons(REMOTE_PORT
);
226 sockaddr_broadcast
.sin_addr
.s_addr
= INADDR_BROADCAST
;
227 inaddr_any
.s_addr
= INADDR_ANY
;
229 DH_DbgPrint(MID_TRACE
,("DHCP Service Started\n"));
231 bootp_packet_handler
= do_packet
;
233 DH_DbgPrint(MID_TRACE
,("Going into dispatch()\n"));
235 StartServiceCtrlDispatcherW(ServiceTable
);
244 // extern char *__progname;
246 // fprintf(stderr, "usage: %s [-dqu] ", __progname);
247 fprintf(stderr
, "usage: dhclient [-dqu] ");
248 fprintf(stderr
, "[-c conffile] [-l leasefile] interface\n");
255 * Each routine is called from the dhclient_state_machine() in one of
257 * -> entering INIT state
258 * -> recvpacket_flag == 0: timeout in this state
259 * -> otherwise: received a packet in this state
261 * Return conditions as handled by dhclient_state_machine():
262 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
263 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
264 * Returns 0: finish the nap which was interrupted for no good reason.
266 * Several per-interface variables are used to keep track of the process:
267 * active_lease: the lease that is being used on the interface
268 * (null pointer if not configured yet).
269 * offered_leases: leases corresponding to DHCPOFFER messages that have
270 * been sent to us by DHCP servers.
271 * acked_leases: leases corresponding to DHCPACK messages that have been
272 * sent to us by DHCP servers.
273 * sendpacket: DHCP packet we're trying to send.
274 * destination: IP address to send sendpacket to
275 * In addition, there are several relevant per-lease variables.
276 * T1_expiry, T2_expiry, lease_expiry: lease milestones
277 * In the active lease, these control the process of renewing the lease;
278 * In leases on the acked_leases list, this simply determines when we
279 * can no longer legitimately use the lease.
283 state_reboot(void *ipp
)
285 struct interface_info
*ip
= ipp
;
286 ULONG foo
= (ULONG
) GetTickCount();
288 /* If we don't remember an active lease, go straight to INIT. */
289 if (!ip
->client
->active
|| ip
->client
->active
->is_bootp
) {
294 /* We are in the rebooting state. */
295 ip
->client
->state
= S_REBOOTING
;
297 /* make_request doesn't initialize xid because it normally comes
298 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
299 so pick an xid now. */
300 ip
->client
->xid
= RtlRandom(&foo
);
302 /* Make a DHCPREQUEST packet, and set appropriate per-interface
304 make_request(ip
, ip
->client
->active
);
305 ip
->client
->destination
= iaddr_broadcast
;
306 time(&ip
->client
->first_sending
);
307 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
309 /* Zap the medium list... */
310 ip
->client
->medium
= NULL
;
312 /* Send out the first DHCPREQUEST packet. */
317 * Called when a lease has completely expired and we've
318 * been unable to renew it.
321 state_init(void *ipp
)
323 struct interface_info
*ip
= ipp
;
325 ASSERT_STATE(state
, S_INIT
);
327 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
329 make_discover(ip
, ip
->client
->active
);
330 ip
->client
->xid
= ip
->client
->packet
.xid
;
331 ip
->client
->destination
= iaddr_broadcast
;
332 ip
->client
->state
= S_SELECTING
;
333 time(&ip
->client
->first_sending
);
334 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
336 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
342 * state_selecting is called when one or more DHCPOFFER packets
343 * have been received and a configurable period of time has passed.
346 state_selecting(void *ipp
)
348 struct interface_info
*ip
= ipp
;
349 struct client_lease
*lp
, *next
, *picked
;
352 ASSERT_STATE(state
, S_SELECTING
);
356 /* Cancel state_selecting and send_discover timeouts, since either
357 one could have got us here. */
358 cancel_timeout(state_selecting
, ip
);
359 cancel_timeout(send_discover
, ip
);
361 /* We have received one or more DHCPOFFER packets. Currently,
362 the only criterion by which we judge leases is whether or
363 not we get a response when we arp for them. */
365 for (lp
= ip
->client
->offered_leases
; lp
; lp
= next
) {
368 /* Check to see if we got an ARPREPLY for the address
369 in this particular lease. */
371 if( !check_arp(ip
,lp
) ) goto freeit
;
376 free_client_lease(lp
);
379 ip
->client
->offered_leases
= NULL
;
381 /* If we just tossed all the leases we were offered, go back
384 ip
->client
->state
= S_INIT
;
389 /* If it was a BOOTREPLY, we can just take the address right now. */
390 if (!picked
->options
[DHO_DHCP_MESSAGE_TYPE
].len
) {
391 ip
->client
->new = picked
;
393 /* Make up some lease expiry times
394 XXX these should be configurable. */
395 ip
->client
->new->expiry
= cur_time
+ 12000;
396 ip
->client
->new->renewal
+= cur_time
+ 8000;
397 ip
->client
->new->rebind
+= cur_time
+ 10000;
399 ip
->client
->state
= S_REQUESTING
;
401 /* Bind to the address we received. */
406 /* Go to the REQUESTING state. */
407 ip
->client
->destination
= iaddr_broadcast
;
408 ip
->client
->state
= S_REQUESTING
;
409 ip
->client
->first_sending
= cur_time
;
410 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
412 /* Make a DHCPREQUEST packet from the lease we picked. */
413 make_request(ip
, picked
);
414 ip
->client
->xid
= ip
->client
->packet
.xid
;
416 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
417 free_client_lease(picked
);
419 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
423 /* state_requesting is called when we receive a DHCPACK message after
424 having sent out one or more DHCPREQUEST packets. */
427 dhcpack(struct packet
*packet
)
429 struct interface_info
*ip
= packet
->interface
;
430 struct client_lease
*lease
;
435 /* If we're not receptive to an offer right now, or if the offer
436 has an unrecognizable transaction id, then just drop it. */
437 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
438 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
439 (memcmp(packet
->interface
->hw_address
.haddr
,
440 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
443 if (ip
->client
->state
!= S_REBOOTING
&&
444 ip
->client
->state
!= S_REQUESTING
&&
445 ip
->client
->state
!= S_RENEWING
&&
446 ip
->client
->state
!= S_REBINDING
)
449 note("DHCPACK from %s", piaddr(packet
->client_addr
));
451 lease
= packet_to_lease(packet
);
453 note("packet_to_lease failed.");
457 ip
->client
->new = lease
;
459 /* Stop resending DHCPREQUEST. */
460 cancel_timeout(send_request
, ip
);
462 /* Figure out the lease time. */
463 if (ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
)
464 ip
->client
->new->expiry
= getULong(
465 ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
);
467 ip
->client
->new->expiry
= DHCP_DEFAULT_LEASE_TIME
;
468 /* A number that looks negative here is really just very large,
469 because the lease expiry offset is unsigned. */
470 if (ip
->client
->new->expiry
< 0)
471 ip
->client
->new->expiry
= TIME_MAX
;
472 /* XXX should be fixed by resetting the client state */
473 if (ip
->client
->new->expiry
< 60)
474 ip
->client
->new->expiry
= 60;
476 /* Take the server-provided renewal time if there is one;
477 otherwise figure it out according to the spec. */
478 if (ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].len
)
479 ip
->client
->new->renewal
= getULong(
480 ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].data
);
482 ip
->client
->new->renewal
= ip
->client
->new->expiry
/ 2;
484 /* Same deal with the rebind time. */
485 if (ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].len
)
486 ip
->client
->new->rebind
= getULong(
487 ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].data
);
489 ip
->client
->new->rebind
= ip
->client
->new->renewal
+
490 ip
->client
->new->renewal
/ 2 + ip
->client
->new->renewal
/ 4;
493 ip
->client
->new->obtained
= cur_time
;
495 ip
->client
->new->expiry
+= cur_time
;
496 /* Lease lengths can never be negative. */
497 if (ip
->client
->new->expiry
< cur_time
)
498 ip
->client
->new->expiry
= TIME_MAX
;
499 ip
->client
->new->renewal
+= cur_time
;
500 if (ip
->client
->new->renewal
< cur_time
)
501 ip
->client
->new->renewal
= TIME_MAX
;
502 ip
->client
->new->rebind
+= cur_time
;
503 if (ip
->client
->new->rebind
< cur_time
)
504 ip
->client
->new->rebind
= TIME_MAX
;
509 void set_name_servers( PDHCP_ADAPTER Adapter
, struct client_lease
*new_lease
) {
510 CHAR Buffer
[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
513 strcat(Buffer
, Adapter
->DhclientInfo
.name
);
514 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, Buffer
, 0, KEY_WRITE
, &RegKey
) != ERROR_SUCCESS
)
518 if( new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
) {
520 struct iaddr nameserver
;
523 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
/ sizeof(ULONG
);
525 nsbuf
= malloc( addrs
* sizeof(IP_ADDRESS_STRING
) );
529 for( i
= 0; i
< addrs
; i
++ ) {
530 nameserver
.len
= sizeof(ULONG
);
531 memcpy( nameserver
.iabuf
,
532 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].data
+
533 (i
* sizeof(ULONG
)), sizeof(ULONG
) );
534 strcat( nsbuf
, piaddr(nameserver
) );
535 if( i
!= addrs
-1 ) strcat( nsbuf
, "," );
538 DH_DbgPrint(MID_TRACE
,("Setting DhcpNameserver: %s\n", nsbuf
));
540 RegSetValueExA( RegKey
, "DhcpNameServer", 0, REG_SZ
,
541 (LPBYTE
)nsbuf
, strlen(nsbuf
) + 1 );
546 RegDeleteValueW( RegKey
, L
"DhcpNameServer" );
549 RegCloseKey( RegKey
);
553 void setup_adapter( PDHCP_ADAPTER Adapter
, struct client_lease
*new_lease
) {
554 CHAR Buffer
[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
555 struct iaddr netmask
;
560 strcat(Buffer
, Adapter
->DhclientInfo
.name
);
561 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, Buffer
, 0, KEY_WRITE
, &hkey
) != ERROR_SUCCESS
)
565 if( Adapter
->NteContext
)
566 DeleteIPAddress( Adapter
->NteContext
);
568 /* Set up our default router if we got one from the DHCP server */
569 if( new_lease
->options
[DHO_SUBNET_MASK
].len
) {
572 memcpy( netmask
.iabuf
,
573 new_lease
->options
[DHO_SUBNET_MASK
].data
,
574 new_lease
->options
[DHO_SUBNET_MASK
].len
);
575 Status
= AddIPAddress
576 ( *((ULONG
*)new_lease
->address
.iabuf
),
577 *((ULONG
*)netmask
.iabuf
),
578 Adapter
->IfMib
.dwIndex
,
579 &Adapter
->NteContext
,
580 &Adapter
->NteInstance
);
582 RegSetValueExA(hkey
, "DhcpIPAddress", 0, REG_SZ
, (LPBYTE
)piaddr(new_lease
->address
), strlen(piaddr(new_lease
->address
))+1);
584 for(i
= 0; i
< new_lease
->options
[DHO_SUBNET_MASK
].len
; i
++)
586 sprintf(&Buffer
[strlen(Buffer
)], "%u", new_lease
->options
[DHO_SUBNET_MASK
].data
[i
]);
587 if (i
+ 1 < new_lease
->options
[DHO_SUBNET_MASK
].len
)
590 RegSetValueExA(hkey
, "DhcpSubnetMask", 0, REG_SZ
, (LPBYTE
)Buffer
, strlen(Buffer
)+1);
591 RegSetValueExA(hkey
, "IPAddress", 0, REG_SZ
, (LPBYTE
)"0.0.0.0", 8);
592 RegSetValueExA(hkey
, "SubnetMask", 0, REG_SZ
, (LPBYTE
)"0.0.0.0", 8);
594 RegSetValueExA(hkey
, "EnableDHCP", 0, REG_DWORD
, (LPBYTE
)&dwEnableDHCP
, sizeof(DWORD
));
597 if( !NT_SUCCESS(Status
) )
598 warning("AddIPAddress: %lx\n", Status
);
601 if( new_lease
->options
[DHO_ROUTERS
].len
) {
604 Adapter
->RouterMib
.dwForwardDest
= 0; /* Default route */
605 Adapter
->RouterMib
.dwForwardMask
= 0;
606 Adapter
->RouterMib
.dwForwardMetric1
= 1;
607 Adapter
->RouterMib
.dwForwardIfIndex
= Adapter
->IfMib
.dwIndex
;
609 if( Adapter
->RouterMib
.dwForwardNextHop
) {
610 /* If we set a default route before, delete it before continuing */
611 DeleteIpForwardEntry( &Adapter
->RouterMib
);
614 Adapter
->RouterMib
.dwForwardNextHop
=
615 *((ULONG
*)new_lease
->options
[DHO_ROUTERS
].data
);
617 Status
= CreateIpForwardEntry( &Adapter
->RouterMib
);
619 if( !NT_SUCCESS(Status
) )
620 warning("CreateIpForwardEntry: %lx\n", Status
);
624 for(i
= 0; i
< new_lease
->options
[DHO_ROUTERS
].len
; i
++)
626 sprintf(&Buffer
[strlen(Buffer
)], "%u", new_lease
->options
[DHO_ROUTERS
].data
[i
]);
627 if (i
+ 1 < new_lease
->options
[DHO_ROUTERS
].len
)
630 RegSetValueExA(hkey
, "DhcpDefaultGateway", 0, REG_SZ
, (LPBYTE
)Buffer
, strlen(Buffer
)+1);
631 RegSetValueExA(hkey
, "DefaultGateway", 0, REG_SZ
, (LPBYTE
)"0.0.0.0", 8);
641 bind_lease(struct interface_info
*ip
)
643 PDHCP_ADAPTER Adapter
;
644 struct client_lease
*new_lease
= ip
->client
->new;
649 /* Remember the medium. */
650 ip
->client
->new->medium
= ip
->client
->medium
;
651 ip
->client
->active
= ip
->client
->new;
652 ip
->client
->new = NULL
;
654 /* Set up a timeout to start the renewal process. */
655 /* Timeout of zero means no timeout (some implementations seem to use
658 if( ip
->client
->active
->renewal
- cur_time
)
659 add_timeout(ip
->client
->active
->renewal
, state_bound
, ip
);
661 note("bound to %s -- renewal in %ld seconds.",
662 piaddr(ip
->client
->active
->address
),
663 (long int)(ip
->client
->active
->renewal
- cur_time
));
665 ip
->client
->state
= S_BOUND
;
667 Adapter
= AdapterFindInfo( ip
);
669 if( Adapter
) setup_adapter( Adapter
, new_lease
);
671 warning("Could not find adapter for info %p\n", ip
);
674 set_name_servers( Adapter
, new_lease
);
678 * state_bound is called when we've successfully bound to a particular
679 * lease, but the renewal time on that lease has expired. We are
680 * expected to unicast a DHCPREQUEST to the server that gave us our
684 state_bound(void *ipp
)
686 struct interface_info
*ip
= ipp
;
688 ASSERT_STATE(state
, S_BOUND
);
690 /* T1 has expired. */
691 make_request(ip
, ip
->client
->active
);
692 ip
->client
->xid
= ip
->client
->packet
.xid
;
694 if (ip
->client
->active
->options
[DHO_DHCP_SERVER_IDENTIFIER
].len
== 4) {
695 memcpy(ip
->client
->destination
.iabuf
, ip
->client
->active
->
696 options
[DHO_DHCP_SERVER_IDENTIFIER
].data
, 4);
697 ip
->client
->destination
.len
= 4;
699 ip
->client
->destination
= iaddr_broadcast
;
701 time(&ip
->client
->first_sending
);
702 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
703 ip
->client
->state
= S_RENEWING
;
705 /* Send the first packet immediately. */
710 bootp(struct packet
*packet
)
712 struct iaddrlist
*ap
;
714 if (packet
->raw
->op
!= BOOTREPLY
)
717 /* If there's a reject list, make sure this packet's sender isn't
719 for (ap
= packet
->interface
->client
->config
->reject_list
;
721 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
722 note("BOOTREPLY from %s rejected.", piaddr(ap
->addr
));
730 dhcp(struct packet
*packet
)
732 struct iaddrlist
*ap
;
733 void (*handler
)(struct packet
*);
736 switch (packet
->packet_type
) {
753 /* If there's a reject list, make sure this packet's sender isn't
755 for (ap
= packet
->interface
->client
->config
->reject_list
;
757 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
758 note("%s from %s rejected.", type
, piaddr(ap
->addr
));
766 dhcpoffer(struct packet
*packet
)
768 struct interface_info
*ip
= packet
->interface
;
769 struct client_lease
*lease
, *lp
;
771 int arp_timeout_needed
= 0, stop_selecting
;
772 char *name
= packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
?
773 "DHCPOFFER" : "BOOTREPLY";
778 /* If we're not receptive to an offer right now, or if the offer
779 has an unrecognizable transaction id, then just drop it. */
780 if (ip
->client
->state
!= S_SELECTING
||
781 packet
->interface
->client
->xid
!= packet
->raw
->xid
||
782 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
783 (memcmp(packet
->interface
->hw_address
.haddr
,
784 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
787 note("%s from %s", name
, piaddr(packet
->client_addr
));
790 /* If this lease doesn't supply the minimum required parameters,
792 for (i
= 0; ip
->client
->config
->required_options
[i
]; i
++) {
793 if (!packet
->options
[ip
->client
->config
->
794 required_options
[i
]].len
) {
795 note("%s isn't satisfactory.", name
);
800 /* If we've already seen this lease, don't record it again. */
801 for (lease
= ip
->client
->offered_leases
;
802 lease
; lease
= lease
->next
) {
803 if (lease
->address
.len
== sizeof(packet
->raw
->yiaddr
) &&
804 !memcmp(lease
->address
.iabuf
,
805 &packet
->raw
->yiaddr
, lease
->address
.len
)) {
806 debug("%s already seen.", name
);
811 lease
= packet_to_lease(packet
);
813 note("packet_to_lease failed.");
817 /* If this lease was acquired through a BOOTREPLY, record that
819 if (!packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
)
822 /* Record the medium under which this lease was offered. */
823 lease
->medium
= ip
->client
->medium
;
825 /* Send out an ARP Request for the offered IP address. */
826 if( !check_arp( ip
, lease
) ) {
827 note("Arp check failed\n");
831 /* Figure out when we're supposed to stop selecting. */
833 ip
->client
->first_sending
+ ip
->client
->config
->select_interval
;
835 /* If this is the lease we asked for, put it at the head of the
836 list, and don't mess with the arp request timeout. */
837 if (lease
->address
.len
== ip
->client
->requested_address
.len
&&
838 !memcmp(lease
->address
.iabuf
,
839 ip
->client
->requested_address
.iabuf
,
840 ip
->client
->requested_address
.len
)) {
841 lease
->next
= ip
->client
->offered_leases
;
842 ip
->client
->offered_leases
= lease
;
844 /* If we already have an offer, and arping for this
845 offer would take us past the selection timeout,
846 then don't extend the timeout - just hope for the
848 if (ip
->client
->offered_leases
&&
849 (cur_time
+ arp_timeout_needed
) > stop_selecting
)
850 arp_timeout_needed
= 0;
852 /* Put the lease at the end of the list. */
854 if (!ip
->client
->offered_leases
)
855 ip
->client
->offered_leases
= lease
;
857 for (lp
= ip
->client
->offered_leases
; lp
->next
;
864 /* If we're supposed to stop selecting before we've had time
865 to wait for the ARPREPLY, add some delay to wait for
867 if (stop_selecting
- cur_time
< arp_timeout_needed
)
868 stop_selecting
= cur_time
+ arp_timeout_needed
;
870 /* If the selecting interval has expired, go immediately to
871 state_selecting(). Otherwise, time out into
872 state_selecting at the select interval. */
873 if (stop_selecting
<= 0)
876 add_timeout(stop_selecting
, state_selecting
, ip
);
877 cancel_timeout(send_discover
, ip
);
881 /* Allocate a client_lease structure and initialize it from the parameters
882 in the specified packet. */
884 struct client_lease
*
885 packet_to_lease(struct packet
*packet
)
887 struct client_lease
*lease
;
890 lease
= malloc(sizeof(struct client_lease
));
893 warning("dhcpoffer: no memory to record lease.");
897 memset(lease
, 0, sizeof(*lease
));
899 /* Copy the lease options. */
900 for (i
= 0; i
< 256; i
++) {
901 if (packet
->options
[i
].len
) {
902 lease
->options
[i
].data
=
903 malloc(packet
->options
[i
].len
+ 1);
904 if (!lease
->options
[i
].data
) {
905 warning("dhcpoffer: no memory for option %d", i
);
906 free_client_lease(lease
);
909 memcpy(lease
->options
[i
].data
,
910 packet
->options
[i
].data
,
911 packet
->options
[i
].len
);
912 lease
->options
[i
].len
=
913 packet
->options
[i
].len
;
914 lease
->options
[i
].data
[lease
->options
[i
].len
] =
917 if (!check_option(lease
,i
)) {
918 /* ignore a bogus lease offer */
919 warning("Invalid lease option - ignoring offer");
920 free_client_lease(lease
);
926 lease
->address
.len
= sizeof(packet
->raw
->yiaddr
);
927 memcpy(lease
->address
.iabuf
, &packet
->raw
->yiaddr
, lease
->address
.len
);
929 lease
->serveraddress
.len
= sizeof(packet
->raw
->siaddr
);
930 memcpy(lease
->serveraddress
.iabuf
, &packet
->raw
->siaddr
, lease
->address
.len
);
933 /* If the server name was filled out, copy it. */
934 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
935 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 2)) &&
936 packet
->raw
->sname
[0]) {
937 lease
->server_name
= malloc(DHCP_SNAME_LEN
+ 1);
938 if (!lease
->server_name
) {
939 warning("dhcpoffer: no memory for server name.");
940 free_client_lease(lease
);
943 memcpy(lease
->server_name
, packet
->raw
->sname
, DHCP_SNAME_LEN
);
944 lease
->server_name
[DHCP_SNAME_LEN
]='\0';
945 if (!res_hnok(lease
->server_name
) ) {
946 warning("Bogus server name %s", lease
->server_name
);
947 free_client_lease(lease
);
953 /* Ditto for the filename. */
954 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
955 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 1)) &&
956 packet
->raw
->file
[0]) {
957 /* Don't count on the NUL terminator. */
958 lease
->filename
= malloc(DHCP_FILE_LEN
+ 1);
959 if (!lease
->filename
) {
960 warning("dhcpoffer: no memory for filename.");
961 free_client_lease(lease
);
964 memcpy(lease
->filename
, packet
->raw
->file
, DHCP_FILE_LEN
);
965 lease
->filename
[DHCP_FILE_LEN
]='\0';
971 dhcpnak(struct packet
*packet
)
973 struct interface_info
*ip
= packet
->interface
;
975 /* If we're not receptive to an offer right now, or if the offer
976 has an unrecognizable transaction id, then just drop it. */
977 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
978 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
979 (memcmp(packet
->interface
->hw_address
.haddr
,
980 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
983 if (ip
->client
->state
!= S_REBOOTING
&&
984 ip
->client
->state
!= S_REQUESTING
&&
985 ip
->client
->state
!= S_RENEWING
&&
986 ip
->client
->state
!= S_REBINDING
)
989 note("DHCPNAK from %s", piaddr(packet
->client_addr
));
991 if (!ip
->client
->active
) {
992 note("DHCPNAK with no active lease.\n");
996 free_client_lease(ip
->client
->active
);
997 ip
->client
->active
= NULL
;
999 /* Stop sending DHCPREQUEST packets... */
1000 cancel_timeout(send_request
, ip
);
1002 ip
->client
->state
= S_INIT
;
1006 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
1007 one after the right interval has expired. If we don't get an offer by
1008 the time we reach the panic interval, call the panic function. */
1011 send_discover(void *ipp
)
1013 struct interface_info
*ip
= ipp
;
1014 int interval
, increase
= 1;
1017 DH_DbgPrint(MID_TRACE
,("Doing discover on interface %p\n",ip
));
1021 /* Figure out how long it's been since we started transmitting. */
1022 interval
= cur_time
- ip
->client
->first_sending
;
1024 /* If we're past the panic timeout, call the script and tell it
1025 we haven't found anything for this interface yet. */
1026 if (interval
> ip
->client
->config
->timeout
) {
1031 /* If we're selecting media, try the whole list before doing
1032 the exponential backoff, but if we've already received an
1033 offer, stop looping, because we obviously have it right. */
1034 if (!ip
->client
->offered_leases
&&
1035 ip
->client
->config
->media
) {
1038 if (ip
->client
->medium
) {
1039 ip
->client
->medium
= ip
->client
->medium
->next
;
1042 if (!ip
->client
->medium
) {
1044 error("No valid media types for %s!", ip
->name
);
1045 ip
->client
->medium
= ip
->client
->config
->media
;
1049 note("Trying medium \"%s\" %d", ip
->client
->medium
->string
,
1051 /* XXX Support other media types eventually */
1055 * If we're supposed to increase the interval, do so. If it's
1056 * currently zero (i.e., we haven't sent any packets yet), set
1057 * it to one; otherwise, add to it a random number between zero
1058 * and two times itself. On average, this means that it will
1059 * double with every transmission.
1062 if (!ip
->client
->interval
)
1063 ip
->client
->interval
=
1064 ip
->client
->config
->initial_interval
;
1066 ip
->client
->interval
+= (rand() >> 2) %
1067 (2 * ip
->client
->interval
);
1070 /* Don't backoff past cutoff. */
1071 if (ip
->client
->interval
>
1072 ip
->client
->config
->backoff_cutoff
)
1073 ip
->client
->interval
=
1074 ((ip
->client
->config
->backoff_cutoff
/ 2)
1076 ip
->client
->config
->backoff_cutoff
));
1077 } else if (!ip
->client
->interval
)
1078 ip
->client
->interval
=
1079 ip
->client
->config
->initial_interval
;
1081 /* If the backoff would take us to the panic timeout, just use that
1083 if (cur_time
+ ip
->client
->interval
>
1084 ip
->client
->first_sending
+ ip
->client
->config
->timeout
)
1085 ip
->client
->interval
=
1086 (ip
->client
->first_sending
+
1087 ip
->client
->config
->timeout
) - cur_time
+ 1;
1089 /* Record the number of seconds since we started sending. */
1090 if (interval
< 65536)
1091 ip
->client
->packet
.secs
= htons(interval
);
1093 ip
->client
->packet
.secs
= htons(65535);
1094 ip
->client
->secs
= ip
->client
->packet
.secs
;
1096 note("DHCPDISCOVER on %s to %s port %d interval %ld",
1097 ip
->name
, inet_ntoa(sockaddr_broadcast
.sin_addr
),
1098 ntohs(sockaddr_broadcast
.sin_port
), (long int)ip
->client
->interval
);
1100 /* Send out a packet. */
1101 (void)send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1102 inaddr_any
, &sockaddr_broadcast
, NULL
);
1104 DH_DbgPrint(MID_TRACE
,("discover timeout: now %x -> then %x\n",
1105 cur_time
, cur_time
+ ip
->client
->interval
));
1107 add_timeout(cur_time
+ ip
->client
->interval
, send_discover
, ip
);
1111 * state_panic gets called if we haven't received any offers in a preset
1112 * amount of time. When this happens, we try to use existing leases
1113 * that haven't yet expired, and failing that, we call the client script
1114 * and hope it can do something.
1117 state_panic(void *ipp
)
1119 struct interface_info
*ip
= ipp
;
1120 struct client_lease
*loop
= ip
->client
->active
;
1121 struct client_lease
*lp
;
1124 note("No DHCPOFFERS received.");
1128 /* We may not have an active lease, but we may have some
1129 predefined leases that we can try. */
1130 if (!ip
->client
->active
&& ip
->client
->leases
)
1133 /* Run through the list of leases and see if one can be used. */
1134 while (ip
->client
->active
) {
1135 if (ip
->client
->active
->expiry
> cur_time
) {
1136 note("Trying recorded lease %s",
1137 piaddr(ip
->client
->active
->address
));
1138 /* Run the client script with the existing
1140 script_init("TIMEOUT",
1141 ip
->client
->active
->medium
);
1142 script_write_params("new_", ip
->client
->active
);
1143 if (ip
->client
->alias
)
1144 script_write_params("alias_",
1147 /* If the old lease is still good and doesn't
1148 yet need renewal, go into BOUND state and
1149 timeout at the renewal time. */
1151 ip
->client
->active
->renewal
) {
1152 ip
->client
->state
= S_BOUND
;
1153 note("bound: renewal in %ld seconds.",
1154 (long int)(ip
->client
->active
->renewal
-
1157 ip
->client
->active
->renewal
,
1160 ip
->client
->state
= S_BOUND
;
1161 note("bound: immediate renewal.");
1167 /* If there are no other leases, give up. */
1168 if (!ip
->client
->leases
) {
1169 ip
->client
->leases
= ip
->client
->active
;
1170 ip
->client
->active
= NULL
;
1175 /* Otherwise, put the active lease at the end of the
1176 lease list, and try another lease.. */
1177 for (lp
= ip
->client
->leases
; lp
->next
; lp
= lp
->next
)
1179 lp
->next
= ip
->client
->active
;
1181 lp
->next
->next
= NULL
;
1182 ip
->client
->active
= ip
->client
->leases
;
1183 ip
->client
->leases
= ip
->client
->leases
->next
;
1185 /* If we already tried this lease, we've exhausted the
1186 set of leases, so we might as well give up for
1188 if (ip
->client
->active
== loop
)
1191 loop
= ip
->client
->active
;
1194 /* No leases were available, or what was available didn't work, so
1195 tell the shell script that we failed to allocate an address,
1196 and try again later. */
1197 note("No working leases in persistent database - sleeping.\n");
1198 ip
->client
->state
= S_INIT
;
1199 add_timeout(cur_time
+ ip
->client
->config
->retry_interval
, state_init
,
1201 /* XXX Take any failure actions necessary */
1205 send_request(void *ipp
)
1207 struct interface_info
*ip
= ipp
;
1208 struct sockaddr_in destination
;
1209 struct in_addr from
;
1215 /* Figure out how long it's been since we started transmitting. */
1216 interval
= cur_time
- ip
->client
->first_sending
;
1218 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1219 past the reboot timeout, go to INIT and see if we can
1220 DISCOVER an address... */
1221 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1222 means either that we're on a network with no DHCP server,
1223 or that our server is down. In the latter case, assuming
1224 that there is a backup DHCP server, DHCPDISCOVER will get
1225 us a new address, but we could also have successfully
1226 reused our old address. In the former case, we're hosed
1227 anyway. This is not a win-prone situation. */
1228 if ((ip
->client
->state
== S_REBOOTING
||
1229 ip
->client
->state
== S_REQUESTING
) &&
1230 interval
> ip
->client
->config
->reboot_timeout
) {
1231 ip
->client
->state
= S_INIT
;
1232 cancel_timeout(send_request
, ip
);
1237 /* If we're in the reboot state, make sure the media is set up
1239 if (ip
->client
->state
== S_REBOOTING
&&
1240 !ip
->client
->medium
&&
1241 ip
->client
->active
->medium
) {
1242 script_init("MEDIUM", ip
->client
->active
->medium
);
1244 /* If the medium we chose won't fly, go to INIT state. */
1245 /* XXX Nothing for now */
1247 /* Record the medium. */
1248 ip
->client
->medium
= ip
->client
->active
->medium
;
1251 /* If the lease has expired, relinquish the address and go back
1252 to the INIT state. */
1253 if (ip
->client
->state
!= S_REQUESTING
&&
1254 cur_time
> ip
->client
->active
->expiry
) {
1255 PDHCP_ADAPTER Adapter
= AdapterFindInfo( ip
);
1256 /* Run the client script with the new parameters. */
1257 /* No script actions necessary in the expiry case */
1258 /* Now do a preinit on the interface so that we can
1259 discover a new address. */
1262 DeleteIPAddress( Adapter
->NteContext
);
1264 ip
->client
->state
= S_INIT
;
1269 /* Do the exponential backoff... */
1270 if (!ip
->client
->interval
)
1271 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
1273 ip
->client
->interval
+= ((rand() >> 2) %
1274 (2 * ip
->client
->interval
));
1276 /* Don't backoff past cutoff. */
1277 if (ip
->client
->interval
>
1278 ip
->client
->config
->backoff_cutoff
)
1279 ip
->client
->interval
=
1280 ((ip
->client
->config
->backoff_cutoff
/ 2) +
1281 ((rand() >> 2) % ip
->client
->interval
));
1283 /* If the backoff would take us to the expiry time, just set the
1284 timeout to the expiry time. */
1285 if (ip
->client
->state
!= S_REQUESTING
&&
1286 cur_time
+ ip
->client
->interval
>
1287 ip
->client
->active
->expiry
)
1288 ip
->client
->interval
=
1289 ip
->client
->active
->expiry
- cur_time
+ 1;
1291 /* If the lease T2 time has elapsed, or if we're not yet bound,
1292 broadcast the DHCPREQUEST rather than unicasting. */
1293 memset(&destination
, 0, sizeof(destination
));
1294 if (ip
->client
->state
== S_REQUESTING
||
1295 ip
->client
->state
== S_REBOOTING
||
1296 cur_time
> ip
->client
->active
->rebind
)
1297 destination
.sin_addr
.s_addr
= INADDR_BROADCAST
;
1299 memcpy(&destination
.sin_addr
.s_addr
,
1300 ip
->client
->destination
.iabuf
,
1301 sizeof(destination
.sin_addr
.s_addr
));
1302 destination
.sin_port
= htons(REMOTE_PORT
);
1303 destination
.sin_family
= AF_INET
;
1304 // destination.sin_len = sizeof(destination);
1306 if (ip
->client
->state
!= S_REQUESTING
)
1307 memcpy(&from
, ip
->client
->active
->address
.iabuf
,
1310 from
.s_addr
= INADDR_ANY
;
1312 /* Record the number of seconds since we started sending. */
1313 if (ip
->client
->state
== S_REQUESTING
)
1314 ip
->client
->packet
.secs
= ip
->client
->secs
;
1316 if (interval
< 65536)
1317 ip
->client
->packet
.secs
= htons(interval
);
1319 ip
->client
->packet
.secs
= htons(65535);
1322 note("DHCPREQUEST on %s to %s port %d", ip
->name
,
1323 inet_ntoa(destination
.sin_addr
), ntohs(destination
.sin_port
));
1325 /* Send out a packet. */
1326 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1327 from
, &destination
, NULL
);
1329 add_timeout(cur_time
+ ip
->client
->interval
, send_request
, ip
);
1333 send_decline(void *ipp
)
1335 struct interface_info
*ip
= ipp
;
1337 note("DHCPDECLINE on %s to %s port %d", ip
->name
,
1338 inet_ntoa(sockaddr_broadcast
.sin_addr
),
1339 ntohs(sockaddr_broadcast
.sin_port
));
1341 /* Send out a packet. */
1342 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1343 inaddr_any
, &sockaddr_broadcast
, NULL
);
1347 make_discover(struct interface_info
*ip
, struct client_lease
*lease
)
1349 unsigned char discover
= DHCPDISCOVER
;
1350 struct tree_cache
*options
[256];
1351 struct tree_cache option_elements
[256];
1353 ULONG foo
= (ULONG
) GetTickCount();
1355 memset(option_elements
, 0, sizeof(option_elements
));
1356 memset(options
, 0, sizeof(options
));
1357 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1359 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1360 i
= DHO_DHCP_MESSAGE_TYPE
;
1361 options
[i
] = &option_elements
[i
];
1362 options
[i
]->value
= &discover
;
1363 options
[i
]->len
= sizeof(discover
);
1364 options
[i
]->buf_size
= sizeof(discover
);
1365 options
[i
]->timeout
= 0xFFFFFFFF;
1367 /* Request the options we want */
1368 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1369 options
[i
] = &option_elements
[i
];
1370 options
[i
]->value
= ip
->client
->config
->requested_options
;
1371 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1372 options
[i
]->buf_size
=
1373 ip
->client
->config
->requested_option_count
;
1374 options
[i
]->timeout
= 0xFFFFFFFF;
1376 /* If we had an address, try to get it again. */
1378 ip
->client
->requested_address
= lease
->address
;
1379 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1380 options
[i
] = &option_elements
[i
];
1381 options
[i
]->value
= lease
->address
.iabuf
;
1382 options
[i
]->len
= lease
->address
.len
;
1383 options
[i
]->buf_size
= lease
->address
.len
;
1384 options
[i
]->timeout
= 0xFFFFFFFF;
1386 ip
->client
->requested_address
.len
= 0;
1388 /* Send any options requested in the config file. */
1389 for (i
= 0; i
< 256; i
++)
1391 ip
->client
->config
->send_options
[i
].data
) {
1392 options
[i
] = &option_elements
[i
];
1394 ip
->client
->config
->send_options
[i
].data
;
1396 ip
->client
->config
->send_options
[i
].len
;
1397 options
[i
]->buf_size
=
1398 ip
->client
->config
->send_options
[i
].len
;
1399 options
[i
]->timeout
= 0xFFFFFFFF;
1402 /* Set up the option buffer... */
1403 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1404 options
, 0, 0, 0, NULL
, 0);
1405 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1406 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1408 ip
->client
->packet
.op
= BOOTREQUEST
;
1409 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1410 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1411 ip
->client
->packet
.hops
= 0;
1412 ip
->client
->packet
.xid
= RtlRandom(&foo
);
1413 ip
->client
->packet
.secs
= 0; /* filled in by send_discover. */
1414 ip
->client
->packet
.flags
= 0;
1416 memset(&(ip
->client
->packet
.ciaddr
),
1417 0, sizeof(ip
->client
->packet
.ciaddr
));
1418 memset(&(ip
->client
->packet
.yiaddr
),
1419 0, sizeof(ip
->client
->packet
.yiaddr
));
1420 memset(&(ip
->client
->packet
.siaddr
),
1421 0, sizeof(ip
->client
->packet
.siaddr
));
1422 memset(&(ip
->client
->packet
.giaddr
),
1423 0, sizeof(ip
->client
->packet
.giaddr
));
1424 memcpy(ip
->client
->packet
.chaddr
,
1425 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1430 make_request(struct interface_info
*ip
, struct client_lease
* lease
)
1432 unsigned char request
= DHCPREQUEST
;
1433 struct tree_cache
*options
[256];
1434 struct tree_cache option_elements
[256];
1437 memset(options
, 0, sizeof(options
));
1438 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1440 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1441 i
= DHO_DHCP_MESSAGE_TYPE
;
1442 options
[i
] = &option_elements
[i
];
1443 options
[i
]->value
= &request
;
1444 options
[i
]->len
= sizeof(request
);
1445 options
[i
]->buf_size
= sizeof(request
);
1446 options
[i
]->timeout
= 0xFFFFFFFF;
1448 /* Request the options we want */
1449 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1450 options
[i
] = &option_elements
[i
];
1451 options
[i
]->value
= ip
->client
->config
->requested_options
;
1452 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1453 options
[i
]->buf_size
=
1454 ip
->client
->config
->requested_option_count
;
1455 options
[i
]->timeout
= 0xFFFFFFFF;
1457 /* If we are requesting an address that hasn't yet been assigned
1458 to us, use the DHCP Requested Address option. */
1459 if (ip
->client
->state
== S_REQUESTING
) {
1460 /* Send back the server identifier... */
1461 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1462 options
[i
] = &option_elements
[i
];
1463 options
[i
]->value
= lease
->options
[i
].data
;
1464 options
[i
]->len
= lease
->options
[i
].len
;
1465 options
[i
]->buf_size
= lease
->options
[i
].len
;
1466 options
[i
]->timeout
= 0xFFFFFFFF;
1468 if (ip
->client
->state
== S_REQUESTING
||
1469 ip
->client
->state
== S_REBOOTING
) {
1470 ip
->client
->requested_address
= lease
->address
;
1471 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1472 options
[i
] = &option_elements
[i
];
1473 options
[i
]->value
= lease
->address
.iabuf
;
1474 options
[i
]->len
= lease
->address
.len
;
1475 options
[i
]->buf_size
= lease
->address
.len
;
1476 options
[i
]->timeout
= 0xFFFFFFFF;
1478 ip
->client
->requested_address
.len
= 0;
1480 /* Send any options requested in the config file. */
1481 for (i
= 0; i
< 256; i
++)
1483 ip
->client
->config
->send_options
[i
].data
) {
1484 options
[i
] = &option_elements
[i
];
1486 ip
->client
->config
->send_options
[i
].data
;
1488 ip
->client
->config
->send_options
[i
].len
;
1489 options
[i
]->buf_size
=
1490 ip
->client
->config
->send_options
[i
].len
;
1491 options
[i
]->timeout
= 0xFFFFFFFF;
1494 /* Set up the option buffer... */
1495 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1496 options
, 0, 0, 0, NULL
, 0);
1497 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1498 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1500 ip
->client
->packet
.op
= BOOTREQUEST
;
1501 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1502 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1503 ip
->client
->packet
.hops
= 0;
1504 ip
->client
->packet
.xid
= ip
->client
->xid
;
1505 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1507 /* If we own the address we're requesting, put it in ciaddr;
1508 otherwise set ciaddr to zero. */
1509 if (ip
->client
->state
== S_BOUND
||
1510 ip
->client
->state
== S_RENEWING
||
1511 ip
->client
->state
== S_REBINDING
) {
1512 memcpy(&ip
->client
->packet
.ciaddr
,
1513 lease
->address
.iabuf
, lease
->address
.len
);
1514 ip
->client
->packet
.flags
= 0;
1516 memset(&ip
->client
->packet
.ciaddr
, 0,
1517 sizeof(ip
->client
->packet
.ciaddr
));
1518 ip
->client
->packet
.flags
= 0;
1521 memset(&ip
->client
->packet
.yiaddr
, 0,
1522 sizeof(ip
->client
->packet
.yiaddr
));
1523 memset(&ip
->client
->packet
.siaddr
, 0,
1524 sizeof(ip
->client
->packet
.siaddr
));
1525 memset(&ip
->client
->packet
.giaddr
, 0,
1526 sizeof(ip
->client
->packet
.giaddr
));
1527 memcpy(ip
->client
->packet
.chaddr
,
1528 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1532 make_decline(struct interface_info
*ip
, struct client_lease
*lease
)
1534 struct tree_cache
*options
[256], message_type_tree
;
1535 struct tree_cache requested_address_tree
;
1536 struct tree_cache server_id_tree
, client_id_tree
;
1537 unsigned char decline
= DHCPDECLINE
;
1540 memset(options
, 0, sizeof(options
));
1541 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1543 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1544 i
= DHO_DHCP_MESSAGE_TYPE
;
1545 options
[i
] = &message_type_tree
;
1546 options
[i
]->value
= &decline
;
1547 options
[i
]->len
= sizeof(decline
);
1548 options
[i
]->buf_size
= sizeof(decline
);
1549 options
[i
]->timeout
= 0xFFFFFFFF;
1551 /* Send back the server identifier... */
1552 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1553 options
[i
] = &server_id_tree
;
1554 options
[i
]->value
= lease
->options
[i
].data
;
1555 options
[i
]->len
= lease
->options
[i
].len
;
1556 options
[i
]->buf_size
= lease
->options
[i
].len
;
1557 options
[i
]->timeout
= 0xFFFFFFFF;
1559 /* Send back the address we're declining. */
1560 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1561 options
[i
] = &requested_address_tree
;
1562 options
[i
]->value
= lease
->address
.iabuf
;
1563 options
[i
]->len
= lease
->address
.len
;
1564 options
[i
]->buf_size
= lease
->address
.len
;
1565 options
[i
]->timeout
= 0xFFFFFFFF;
1567 /* Send the uid if the user supplied one. */
1568 i
= DHO_DHCP_CLIENT_IDENTIFIER
;
1569 if (ip
->client
->config
->send_options
[i
].len
) {
1570 options
[i
] = &client_id_tree
;
1571 options
[i
]->value
= ip
->client
->config
->send_options
[i
].data
;
1572 options
[i
]->len
= ip
->client
->config
->send_options
[i
].len
;
1573 options
[i
]->buf_size
= ip
->client
->config
->send_options
[i
].len
;
1574 options
[i
]->timeout
= 0xFFFFFFFF;
1578 /* Set up the option buffer... */
1579 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1580 options
, 0, 0, 0, NULL
, 0);
1581 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1582 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1584 ip
->client
->packet
.op
= BOOTREQUEST
;
1585 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1586 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1587 ip
->client
->packet
.hops
= 0;
1588 ip
->client
->packet
.xid
= ip
->client
->xid
;
1589 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1590 ip
->client
->packet
.flags
= 0;
1592 /* ciaddr must always be zero. */
1593 memset(&ip
->client
->packet
.ciaddr
, 0,
1594 sizeof(ip
->client
->packet
.ciaddr
));
1595 memset(&ip
->client
->packet
.yiaddr
, 0,
1596 sizeof(ip
->client
->packet
.yiaddr
));
1597 memset(&ip
->client
->packet
.siaddr
, 0,
1598 sizeof(ip
->client
->packet
.siaddr
));
1599 memset(&ip
->client
->packet
.giaddr
, 0,
1600 sizeof(ip
->client
->packet
.giaddr
));
1601 memcpy(ip
->client
->packet
.chaddr
,
1602 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1606 free_client_lease(struct client_lease
*lease
)
1610 if (lease
->server_name
)
1611 free(lease
->server_name
);
1612 if (lease
->filename
)
1613 free(lease
->filename
);
1614 for (i
= 0; i
< 256; i
++) {
1615 if (lease
->options
[i
].len
)
1616 free(lease
->options
[i
].data
);
1624 rewrite_client_leases(struct interface_info
*ifi
)
1626 struct client_lease
*lp
;
1629 leaseFile
= fopen(path_dhclient_db
, "w");
1631 error("can't create %s", path_dhclient_db
);
1637 for (lp
= ifi
->client
->leases
; lp
; lp
= lp
->next
)
1638 write_client_lease(ifi
, lp
, 1);
1639 if (ifi
->client
->active
)
1640 write_client_lease(ifi
, ifi
->client
->active
, 1);
1646 write_client_lease(struct interface_info
*ip
, struct client_lease
*lease
,
1649 static int leases_written
;
1654 if (leases_written
++ > 20) {
1655 rewrite_client_leases(ip
);
1660 /* If the lease came from the config file, we don't need to stash
1661 a copy in the lease database. */
1662 if (lease
->is_static
)
1665 if (!leaseFile
) { /* XXX */
1666 leaseFile
= fopen(path_dhclient_db
, "w");
1668 error("can't create %s", path_dhclient_db
);
1673 fprintf(leaseFile
, "lease {\n");
1674 if (lease
->is_bootp
)
1675 fprintf(leaseFile
, " bootp;\n");
1676 fprintf(leaseFile
, " interface \"%s\";\n", ip
->name
);
1677 fprintf(leaseFile
, " fixed-address %s;\n", piaddr(lease
->address
));
1678 if (lease
->filename
)
1679 fprintf(leaseFile
, " filename \"%s\";\n", lease
->filename
);
1680 if (lease
->server_name
)
1681 fprintf(leaseFile
, " server-name \"%s\";\n",
1682 lease
->server_name
);
1684 fprintf(leaseFile
, " medium \"%s\";\n", lease
->medium
->string
);
1685 for (i
= 0; i
< 256; i
++)
1686 if (lease
->options
[i
].len
)
1687 fprintf(leaseFile
, " option %s %s;\n",
1688 dhcp_options
[i
].name
,
1689 pretty_print_option(i
, lease
->options
[i
].data
,
1690 lease
->options
[i
].len
, 1, 1));
1692 t
= gmtime(&lease
->renewal
);
1694 fprintf(leaseFile
, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1695 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1696 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1697 t
= gmtime(&lease
->rebind
);
1699 fprintf(leaseFile
, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1700 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1701 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1702 t
= gmtime(&lease
->expiry
);
1704 fprintf(leaseFile
, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1705 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1706 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1707 fprintf(leaseFile
, "}\n");
1712 script_init(char *reason
, struct string_list
*medium
)
1714 size_t len
, mediumlen
= 0;
1715 struct imsg_hdr hdr
;
1719 if (medium
!= NULL
&& medium
->string
!= NULL
)
1720 mediumlen
= strlen(medium
->string
);
1722 hdr
.code
= IMSG_SCRIPT_INIT
;
1723 hdr
.len
= sizeof(struct imsg_hdr
) +
1724 sizeof(size_t) + mediumlen
+
1725 sizeof(size_t) + strlen(reason
);
1727 if ((buf
= buf_open(hdr
.len
)) == NULL
)
1731 errs
+= buf_add(buf
, &hdr
, sizeof(hdr
));
1732 errs
+= buf_add(buf
, &mediumlen
, sizeof(mediumlen
));
1734 errs
+= buf_add(buf
, medium
->string
, mediumlen
);
1735 len
= strlen(reason
);
1736 errs
+= buf_add(buf
, &len
, sizeof(len
));
1737 errs
+= buf_add(buf
, reason
, len
);
1740 error("buf_add: %d", WSAGetLastError());
1742 if (buf_close(privfd
, buf
) == -1)
1743 error("buf_close: %d", WSAGetLastError());
1747 priv_script_init(struct interface_info
*ip
, char *reason
, char *medium
)
1750 // XXX Do we need to do anything?
1755 priv_script_write_params(struct interface_info
*ip
, char *prefix
, struct client_lease
*lease
)
1757 u_int8_t dbuf
[1500];
1761 script_set_env(ip
->client
, prefix
, "ip_address",
1762 piaddr(lease
->address
));
1765 if (lease
->options
[DHO_SUBNET_MASK
].len
&&
1766 (lease
->options
[DHO_SUBNET_MASK
].len
<
1767 sizeof(lease
->address
.iabuf
))) {
1768 struct iaddr netmask
, subnet
, broadcast
;
1770 memcpy(netmask
.iabuf
, lease
->options
[DHO_SUBNET_MASK
].data
,
1771 lease
->options
[DHO_SUBNET_MASK
].len
);
1772 netmask
.len
= lease
->options
[DHO_SUBNET_MASK
].len
;
1774 subnet
= subnet_number(lease
->address
, netmask
);
1777 script_set_env(ip
->client
, prefix
, "network_number",
1780 if (!lease
->options
[DHO_BROADCAST_ADDRESS
].len
) {
1781 broadcast
= broadcast_addr(subnet
, netmask
);
1784 script_set_env(ip
->client
, prefix
,
1785 "broadcast_address",
1795 if (lease
->filename
)
1796 script_set_env(ip
->client
, prefix
, "filename", lease
->filename
);
1797 if (lease
->server_name
)
1798 script_set_env(ip
->client
, prefix
, "server_name",
1799 lease
->server_name
);
1802 for (i
= 0; i
< 256; i
++) {
1803 u_int8_t
*dp
= NULL
;
1805 if (ip
->client
->config
->defaults
[i
].len
) {
1806 if (lease
->options
[i
].len
) {
1808 ip
->client
->config
->default_actions
[i
]) {
1809 case ACTION_DEFAULT
:
1810 dp
= lease
->options
[i
].data
;
1811 len
= lease
->options
[i
].len
;
1813 case ACTION_SUPERSEDE
:
1816 config
->defaults
[i
].data
;
1818 config
->defaults
[i
].len
;
1820 case ACTION_PREPEND
:
1822 config
->defaults
[i
].len
+
1823 lease
->options
[i
].len
;
1824 if (len
>= sizeof(dbuf
)) {
1825 warning("no space to %s %s",
1827 dhcp_options
[i
].name
);
1833 config
->defaults
[i
].data
,
1835 config
->defaults
[i
].len
);
1836 memcpy(dp
+ ip
->client
->
1837 config
->defaults
[i
].len
,
1838 lease
->options
[i
].data
,
1839 lease
->options
[i
].len
);
1844 config
->defaults
[i
].len
+
1845 lease
->options
[i
].len
+ 1;
1846 if (len
> sizeof(dbuf
)) {
1847 warning("no space to %s %s",
1849 dhcp_options
[i
].name
);
1854 lease
->options
[i
].data
,
1855 lease
->options
[i
].len
);
1856 memcpy(dp
+ lease
->options
[i
].len
,
1858 config
->defaults
[i
].data
,
1860 config
->defaults
[i
].len
);
1865 config
->defaults
[i
].data
;
1867 config
->defaults
[i
].len
;
1869 } else if (lease
->options
[i
].len
) {
1870 len
= lease
->options
[i
].len
;
1871 dp
= lease
->options
[i
].data
;
1879 if (dhcp_option_ev_name(name
, sizeof(name
),
1881 script_set_env(ip
->client
, prefix
, name
,
1882 pretty_print_option(i
, dp
, len
, 0, 0));
1887 snprintf(tbuf
, sizeof(tbuf
), "%d", (int)lease
->expiry
);
1888 script_set_env(ip
->client
, prefix
, "expiry", tbuf
);
1893 script_write_params(char *prefix
, struct client_lease
*lease
)
1895 size_t fn_len
= 0, sn_len
= 0, pr_len
= 0;
1896 struct imsg_hdr hdr
;
1900 if (lease
->filename
!= NULL
)
1901 fn_len
= strlen(lease
->filename
);
1902 if (lease
->server_name
!= NULL
)
1903 sn_len
= strlen(lease
->server_name
);
1905 pr_len
= strlen(prefix
);
1907 hdr
.code
= IMSG_SCRIPT_WRITE_PARAMS
;
1908 hdr
.len
= sizeof(hdr
) + sizeof(struct client_lease
) +
1909 sizeof(size_t) + fn_len
+ sizeof(size_t) + sn_len
+
1910 sizeof(size_t) + pr_len
;
1912 for (i
= 0; i
< 256; i
++)
1913 hdr
.len
+= sizeof(int) + lease
->options
[i
].len
;
1915 scripttime
= time(NULL
);
1917 if ((buf
= buf_open(hdr
.len
)) == NULL
)
1921 errs
+= buf_add(buf
, &hdr
, sizeof(hdr
));
1922 errs
+= buf_add(buf
, lease
, sizeof(struct client_lease
));
1923 errs
+= buf_add(buf
, &fn_len
, sizeof(fn_len
));
1924 errs
+= buf_add(buf
, lease
->filename
, fn_len
);
1925 errs
+= buf_add(buf
, &sn_len
, sizeof(sn_len
));
1926 errs
+= buf_add(buf
, lease
->server_name
, sn_len
);
1927 errs
+= buf_add(buf
, &pr_len
, sizeof(pr_len
));
1928 errs
+= buf_add(buf
, prefix
, pr_len
);
1930 for (i
= 0; i
< 256; i
++) {
1931 errs
+= buf_add(buf
, &lease
->options
[i
].len
,
1932 sizeof(lease
->options
[i
].len
));
1933 errs
+= buf_add(buf
, lease
->options
[i
].data
,
1934 lease
->options
[i
].len
);
1938 error("buf_add: %d", WSAGetLastError());
1940 if (buf_close(privfd
, buf
) == -1)
1941 error("buf_close: %d", WSAGetLastError());
1945 dhcp_option_ev_name(char *buf
, size_t buflen
, struct dhcp_option
*option
)
1949 for (i
= 0; option
->name
[i
]; i
++) {
1950 if (i
+ 1 == buflen
)
1952 if (option
->name
[i
] == '-')
1955 buf
[i
] = option
->name
[i
];
1966 static int state
= 0;
1968 if (no_daemon
|| state
)
1973 /* Stop logging to stderr... */
1976 if (daemon(1, 0) == -1)
1979 /* we are chrooted, daemon(3) fails to open /dev/null */
1981 dup2(nullfd
, STDIN_FILENO
);
1982 dup2(nullfd
, STDOUT_FILENO
);
1983 dup2(nullfd
, STDERR_FILENO
);
1991 check_option(struct client_lease
*l
, int option
)
1996 /* we use this, since this is what gets passed to dhclient-script */
1998 opbuf
= pretty_print_option(option
, l
->options
[option
].data
,
1999 l
->options
[option
].len
, 0, 0);
2001 sbuf
= option_as_string(option
, l
->options
[option
].data
,
2002 l
->options
[option
].len
);
2005 case DHO_SUBNET_MASK
:
2006 case DHO_TIME_SERVERS
:
2007 case DHO_NAME_SERVERS
:
2009 case DHO_DOMAIN_NAME_SERVERS
:
2010 case DHO_LOG_SERVERS
:
2011 case DHO_COOKIE_SERVERS
:
2012 case DHO_LPR_SERVERS
:
2013 case DHO_IMPRESS_SERVERS
:
2014 case DHO_RESOURCE_LOCATION_SERVERS
:
2015 case DHO_SWAP_SERVER
:
2016 case DHO_BROADCAST_ADDRESS
:
2017 case DHO_NIS_SERVERS
:
2018 case DHO_NTP_SERVERS
:
2019 case DHO_NETBIOS_NAME_SERVERS
:
2020 case DHO_NETBIOS_DD_SERVER
:
2021 case DHO_FONT_SERVERS
:
2022 case DHO_DHCP_SERVER_IDENTIFIER
:
2023 if (!ipv4addrs(opbuf
)) {
2024 warning("Invalid IP address in option(%d): %s", option
, opbuf
);
2029 case DHO_DOMAIN_NAME
:
2030 case DHO_NIS_DOMAIN
:
2031 if (!res_hnok(sbuf
))
2032 warning("Bogus Host Name option %d: %s (%s)", option
,
2036 case DHO_TIME_OFFSET
:
2038 case DHO_MERIT_DUMP
:
2040 case DHO_EXTENSIONS_PATH
:
2041 case DHO_IP_FORWARDING
:
2042 case DHO_NON_LOCAL_SOURCE_ROUTING
:
2043 case DHO_POLICY_FILTER
:
2044 case DHO_MAX_DGRAM_REASSEMBLY
:
2045 case DHO_DEFAULT_IP_TTL
:
2046 case DHO_PATH_MTU_AGING_TIMEOUT
:
2047 case DHO_PATH_MTU_PLATEAU_TABLE
:
2048 case DHO_INTERFACE_MTU
:
2049 case DHO_ALL_SUBNETS_LOCAL
:
2050 case DHO_PERFORM_MASK_DISCOVERY
:
2051 case DHO_MASK_SUPPLIER
:
2052 case DHO_ROUTER_DISCOVERY
:
2053 case DHO_ROUTER_SOLICITATION_ADDRESS
:
2054 case DHO_STATIC_ROUTES
:
2055 case DHO_TRAILER_ENCAPSULATION
:
2056 case DHO_ARP_CACHE_TIMEOUT
:
2057 case DHO_IEEE802_3_ENCAPSULATION
:
2058 case DHO_DEFAULT_TCP_TTL
:
2059 case DHO_TCP_KEEPALIVE_INTERVAL
:
2060 case DHO_TCP_KEEPALIVE_GARBAGE
:
2061 case DHO_VENDOR_ENCAPSULATED_OPTIONS
:
2062 case DHO_NETBIOS_NODE_TYPE
:
2063 case DHO_NETBIOS_SCOPE
:
2064 case DHO_X_DISPLAY_MANAGER
:
2065 case DHO_DHCP_REQUESTED_ADDRESS
:
2066 case DHO_DHCP_LEASE_TIME
:
2067 case DHO_DHCP_OPTION_OVERLOAD
:
2068 case DHO_DHCP_MESSAGE_TYPE
:
2069 case DHO_DHCP_PARAMETER_REQUEST_LIST
:
2070 case DHO_DHCP_MESSAGE
:
2071 case DHO_DHCP_MAX_MESSAGE_SIZE
:
2072 case DHO_DHCP_RENEWAL_TIME
:
2073 case DHO_DHCP_REBINDING_TIME
:
2074 case DHO_DHCP_CLASS_IDENTIFIER
:
2075 case DHO_DHCP_CLIENT_IDENTIFIER
:
2076 case DHO_DHCP_USER_CLASS_ID
:
2080 warning("unknown dhcp option value 0x%x", option
);
2081 return (unknown_ok
);
2086 res_hnok(const char *dn
)
2088 int pch
= PERIOD
, ch
= *dn
++;
2090 while (ch
!= '\0') {
2093 if (periodchar(ch
)) {
2095 } else if (periodchar(pch
)) {
2096 if (!borderchar(ch
))
2098 } else if (periodchar(nch
) || nch
== '\0') {
2099 if (!borderchar(ch
))
2102 if (!middlechar(ch
))
2110 /* Does buf consist only of dotted decimal ipv4 addrs?
2111 * return how many if so,
2112 * otherwise, return 0
2115 ipv4addrs(char * buf
)
2121 note("Input: %s", buf
);
2124 tmp
= strtok(buf
, " ");
2125 note("got %s", tmp
);
2126 if( tmp
&& inet_aton(tmp
, &jnk
) ) i
++;
2135 option_as_string(unsigned int code
, unsigned char *data
, int len
)
2137 static char optbuf
[32768]; /* XXX */
2139 int opleft
= sizeof(optbuf
);
2140 unsigned char *dp
= data
;
2143 error("option_as_string: bad code %d", code
);
2145 for (; dp
< data
+ len
; dp
++) {
2146 if (!isascii(*dp
) || !isprint(*dp
)) {
2147 if (dp
+ 1 != data
+ len
|| *dp
!= 0) {
2148 _snprintf(op
, opleft
, "\\%03o", *dp
);
2152 } else if (*dp
== '"' || *dp
== '\'' || *dp
== '$' ||
2153 *dp
== '`' || *dp
== '\\') {
2167 warning("dhcp option too large");