Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

SRC/pcdhcp.c

Go to the documentation of this file.
00001 00008 /* Copyright (c) 1997-2007 Gisle Vanem <giva@bgnett.no> 00009 * 00010 * Redistribution and use in source and binary forms, with or without 00011 * modification, are permitted provided that the following conditions 00012 * are met: 00013 * 1. Redistributions of source code must retain the above copyright 00014 * notice, this list of conditions and the following disclaimer. 00015 * 2. Redistributions in binary form must reproduce the above copyright 00016 * notice, this list of conditions and the following disclaimer in the 00017 * documentation and/or other materials provided with the distribution. 00018 * 3. All advertising materials mentioning features or use of this software 00019 * must display the following acknowledgement: 00020 * This product includes software developed by Gisle Vanem 00021 * Bergen, Norway. 00022 * 00023 * THIS SOFTWARE IS PROVIDED BY ME (Gisle Vanem) AND CONTRIBUTORS ``AS IS'' 00024 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00025 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00026 * ARE DISCLAIMED. IN NO EVENT SHALL I OR CONTRIBUTORS BE LIABLE FOR ANY 00027 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00028 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00029 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00030 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00031 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 00032 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 */ 00034 00035 /* \version 0.5: Oct 28, 1996 : 00036 * G. Vanem - implemented from RFC1541 with help from pcbootp.c. 00037 * 00038 * \version 0.6: May 18, 1997 : 00039 * G. Vanem - added RFC2131 DHCPINFORM message. 00040 * 00041 * \version 0.7: Apr 25, 2002 : 00042 * G. Vanem - added RFC3004 User Class option. 00043 * 00044 * \version 0.8: Jul 24, 2002 : 00045 * G. Vanem - Rewitten as a non-blocking FSM. 00046 * - Removed DHCPINFORM message. 00047 * 00048 * \version 0.9: Nov 08, 2002 : 00049 * G. Vanem - added handling of option 60 (Vendor Class) 00050 * 00051 * \version 0.91: Feb 21, 2003 : 00052 * Greg Bredthauer found some bugs in DHCP_request(); DHCP_USER_CLASS 00053 * and DHCP_CLASS_ID tags had 2 bytes of zeros in them. 00054 * Added sending DHCP_CLIENT_ID in DHCP_request() since some DHCP-servers 00055 * doesn't reply without it. 00056 * 00057 * \version 0.92: Jul 17, 2003: 00058 * Riccardo De Agostini contibuted changes for application hooking of 00059 * transient configuration; dhcp_set_config_func() etc. 00060 * 00061 * \version 0.93: Jul 2, 2004: 00062 * Fixed logic around reading transient config. 00063 * 00064 * \version 0.94: Oct 22, 2007: 00065 * Fixed for Linux dhcp servers: parse dhcp options in ACK msgs. 00066 * Changed DHCP_do_boot() to handle renew and rebind as well as init. 00067 * Renegotiate lease if past the renew or rebind times. 00068 */ 00069 00070 #include <stdio.h> 00071 #include <stdlib.h> 00072 #include <string.h> 00073 #include <time.h> 00074 #include <io.h> 00075 #include <ctype.h> 00076 #include <errno.h> 00077 00078 #define DHCP_COMPILATION 00079 00080 #include "wattcp.h" 00081 #include "strings.h" 00082 #include "language.h" 00083 #include "misc.h" 00084 #include "timer.h" 00085 #include "udp_dom.h" 00086 #include "netaddr.h" 00087 #include "bsdname.h" 00088 #include "ip4_out.h" 00089 #include "syslog2.h" 00090 #include "sock_ini.h" 00091 #include "printk.h" 00092 #include "tftp.h" 00093 #include "pctcp.h" 00094 #include "pcsed.h" 00095 #include "pcarp.h" 00096 #include "pcqueue.h" 00097 #include "pcdbug.h" 00098 #include "pcpkt.h" 00099 #include "pcconfig.h" 00100 #include "pcbootp.h" 00101 #include "pcdhcp.h" 00102 00103 #if defined(USE_DHCP) 00104 00105 #define BROADCAST_FLAG intel16 (0x8000) /* network order (LSB=1) */ 00106 00107 BOOL dhcp_did_gratuitous_arp = FALSE; 00108 00109 static WattDHCPConfigFunc config_func = NULL; 00110 00111 static DWORD exchange_id; 00112 static DWORD router, nameserver; 00113 static DWORD dhcp_server = 0; 00114 static DWORD dhcp_renewal = 0; 00115 static DWORD dhcp_rebind = 0; 00116 static DWORD dhcp_iplease = 0; 00117 static DWORD suggest_lease = 0; 00118 static DWORD old_ip_addr = 0; 00119 00120 static BOOL bcast_flag = TRUE; 00121 static BOOL got_offer = FALSE; 00122 static BOOL configured = FALSE; 00123 static BOOL arp_check_ip = FALSE; 00124 static BOOL cfg_read = FALSE; 00125 static BOOL cfg_saved = FALSE; 00126 00127 static int dhcp_timeout = 10; 00128 static int max_retries = 3; 00129 static int discover_loops = 0; 00130 00131 static struct dhcp dhcp_in, dhcp_out; 00132 00133 static void (*DHCP_state) (int) = NULL; 00134 static time_t renewal_timeout; 00135 static time_t rebind_timeout; 00136 static time_t lease_timeout; 00137 static DWORD send_timeout; 00138 static BOOL trace_on = FALSE; 00139 00140 static char config_file [MAX_VALUELEN+1] = ""; 00141 static sock_type *sock = NULL; 00142 00143 /* Default list of DHCP request values 00144 */ 00145 static const BYTE default_request_list[] = { 00146 DHCP_OPT_SUBNET_MASK, 00147 DHCP_OPT_ROUTERS_ON_SNET, 00148 DHCP_OPT_DNS_SRV, 00149 DHCP_OPT_COOKIE_SRV, 00150 DHCP_OPT_LPR_SRV, 00151 DHCP_OPT_HOST_NAME, 00152 DHCP_OPT_DOMAIN_NAME, 00153 DHCP_OPT_IP_DEFAULT_TTL, 00154 DHCP_OPT_IF_MTU, 00155 DHCP_OPT_ARP_CACHE_TIMEOUT, 00156 DHCP_OPT_ETHERNET_ENCAPSULATION, 00157 DHCP_OPT_TCP_DEFAULT_TTL, 00158 #if defined(USE_BSD_API) 00159 DHCP_OPT_LOG_SRV, /* links in syslog2.c */ 00160 DHCP_OPT_NBIOS_NAME_SRV, /* SMB-lib needs these */ 00161 DHCP_OPT_NBIOS_NODE_TYPE, 00162 DHCP_OPT_NBIOS_SCOPE, 00163 #endif 00164 #if defined(USE_TFTP) 00165 DHCP_OPT_TFTP_SERVER, 00166 DHCP_OPT_BOOT_FILENAME 00167 #endif 00168 }; 00169 00170 static struct DHCP_list request_list = { 00171 (BYTE*) &default_request_list, 00172 sizeof (default_request_list) 00173 }; 00174 00175 static struct DHCP_list extra_options = { NULL, 0 }; 00176 static struct DHCP_list user_class = { NULL, 0 }; 00177 static struct DHCP_list vend_class = { (BYTE*)"Watt-32", 7 }; 00178 00179 static void DHCP_state_INIT (int event); 00180 static void DHCP_state_BOUND (int event); 00181 static void DHCP_state_RENEWING (int event); 00182 static void DHCP_state_REQUESTING (int event); 00183 static void DHCP_state_SELECTING (int event); 00184 static void DHCP_state_REBINDING (int event); 00185 00186 static void dhcp_fsm (void); 00187 static void dhcp_options_add (const BYTE *opt, unsigned max); 00188 static void dhcp_set_timers (void); 00189 static void change_ip_addr (void); 00190 static BYTE *put_request_list (BYTE *opt, int filled); 00191 static int write_config (void); 00192 static void erase_config (void); 00193 00194 #define DHCP_SEND(end) sock_fastwrite (sock, (const BYTE*)&dhcp_out, \ 00195 end - (BYTE*)&dhcp_out) 00196 00197 #if defined(USE_DEBUG) 00198 #define TRACE(x) do { if (trace_on) (*_printf) x; } while (0) 00199 #define INET_NTOA(x) _inet_ntoa (NULL, x) 00200 #else 00201 #define TRACE(x) ((void)0) 00202 #define INET_NTOA(x) ((void)0) 00203 #endif 00204 00205 #if defined(USE_DEBUG) 00206 00209 static const char *state_name (void) 00210 { 00211 return (DHCP_state == DHCP_state_INIT ? "INIT" : 00212 DHCP_state == DHCP_state_BOUND ? "BOUND" : 00213 DHCP_state == DHCP_state_RENEWING ? "RENEWING" : 00214 DHCP_state == DHCP_state_REQUESTING ? "REQUESTING" : 00215 DHCP_state == DHCP_state_SELECTING ? "SELECTING" : 00216 DHCP_state == DHCP_state_REBINDING ? "REBINDING" : "??"); 00217 } 00218 00222 static const char *period (DWORD sec) 00223 { 00224 static char buf[20]; 00225 DWORD hours = sec / 3600UL; 00226 00227 if (sec < 60UL) 00228 sprintf (buf, "%lus", sec); 00229 else if (sec < 3600UL) 00230 sprintf (buf, "%lu:%02lu", sec/60, sec % 60); 00231 else sprintf (buf, "%lu:%02lu:%02lu", hours, sec/60-hours*60, sec % 60); 00232 return (buf); 00233 } 00234 #endif 00235 00239 static BYTE *make_boot_header (void) 00240 { 00241 DWORD my_ip = 0UL; 00242 00243 if (DHCP_state == DHCP_state_BOUND || 00244 DHCP_state == DHCP_state_RENEWING || 00245 DHCP_state == DHCP_state_REBINDING) 00246 my_ip = intel (my_ip_addr); 00247 00248 memset (&dhcp_out, 0, sizeof(dhcp_out)); 00249 00250 _eth_get_hwtype (&dhcp_out.dh_htype, &dhcp_out.dh_hlen); 00251 00252 dhcp_out.dh_op = BOOTP_REQUEST; 00253 dhcp_out.dh_xid = exchange_id; 00254 dhcp_out.dh_secs = 0; 00255 dhcp_out.dh_flags = bcast_flag ? BROADCAST_FLAG : 0; 00256 dhcp_out.dh_yiaddr = 0; 00257 dhcp_out.dh_ciaddr = my_ip; 00258 dhcp_out.dh_giaddr = 0; 00259 memcpy (dhcp_out.dh_chaddr, _eth_addr, _eth_mac_len); 00260 *(DWORD*) &dhcp_out.dh_opt[0] = DHCP_MAGIC_COOKIE; 00261 return (&dhcp_out.dh_opt[4]); 00262 } 00263 00267 static BYTE *put_hardware_opt (BYTE *opt) 00268 { 00269 BYTE hw_type, hw_len; 00270 00271 _eth_get_hwtype (&hw_type, &hw_len); 00272 *opt++ = DHCP_OPT_CLIENT_ID; 00273 *opt++ = hw_len + 1; 00274 *opt++ = hw_type; 00275 memcpy (opt, _eth_addr, hw_len); 00276 opt += hw_len; 00277 return (opt); 00278 } 00279 00283 static int DHCP_discover (void) 00284 { 00285 BYTE *opt, *start; 00286 00287 exchange_id = set_timeout (0); /* random exchange ID */ 00288 opt = start = make_boot_header(); 00289 *opt++ = DHCP_OPT_MSG_TYPE; 00290 *opt++ = 1; 00291 *opt++ = DHCP_DISCOVER; 00292 00293 opt = put_hardware_opt (opt); 00294 00295 *opt++ = DHCP_OPT_MAX_MSG_SIZE; /* Maximum DHCP message size */ 00296 *opt++ = 2; 00297 *(WORD*)opt = intel16 (sizeof(struct dhcp)); 00298 opt += 2; 00299 00300 if (suggest_lease) 00301 { 00302 *opt++ = DHCP_OPT_IP_ADDR_LEASE_TIME; 00303 *opt++ = sizeof (suggest_lease); 00304 *(DWORD*)opt = intel (suggest_lease); 00305 opt += sizeof (suggest_lease); 00306 } 00307 opt = put_request_list (opt, opt-start); 00308 *opt++ = DHCP_OPT_END; 00309 return DHCP_SEND (opt); 00310 } 00311 00315 static int DHCP_request (BOOL renew) 00316 { 00317 BYTE *opt = make_boot_header(); 00318 00319 *opt++ = DHCP_OPT_MSG_TYPE; 00320 *opt++ = 1; 00321 *opt++ = DHCP_REQUEST; 00322 00323 if (!renew) 00324 { 00325 *opt++ = DHCP_OPT_SRV_IDENTIFIER; 00326 *opt++ = sizeof (dhcp_server); 00327 *(DWORD*)opt = intel (dhcp_server); 00328 opt += sizeof (dhcp_server); 00329 *opt++ = DHCP_OPT_REQUESTED_IP_ADDR; 00330 *opt++ = sizeof (my_ip_addr); 00331 *(DWORD*)opt = intel (my_ip_addr); 00332 opt += sizeof (my_ip_addr); 00333 } 00334 00335 /* Some DHCP-daemons require this tag in a REQUEST. 00336 */ 00337 opt = put_hardware_opt (opt); 00338 00339 /* ... don't know why we would ever renew a lease 00340 * for the time remaining on our current lease... 00341 */ 00342 #if 0 00343 if (dhcp_iplease && dhcp_iplease < (DWORD)-1) 00344 { 00345 *opt++ = DHCP_OPT_IP_ADDR_LEASE_TIME; 00346 *opt++ = sizeof (dhcp_iplease); 00347 *(DWORD*)opt = intel (dhcp_iplease); 00348 opt += sizeof (dhcp_iplease); 00349 } 00350 #endif 00351 00352 if (user_class.data) 00353 { 00354 *opt++ = DHCP_OPT_USER_CLASS; 00355 *opt++ = user_class.size; 00356 memcpy (opt, user_class.data, user_class.size); 00357 opt += user_class.size; 00358 } 00359 00360 if (vend_class.data) 00361 { 00362 *opt++ = DHCP_OPT_CLASS_ID; 00363 *opt++ = vend_class.size; 00364 memcpy (opt, vend_class.data, vend_class.size); 00365 opt += vend_class.size; 00366 } 00367 00368 *opt++ = DHCP_OPT_END; 00369 TRACE (("DHCP req: renew(%d) dst(%s)\n", 00370 renew, INET_NTOA(sock->udp.hisaddr))); 00371 return DHCP_SEND (opt); 00372 } 00373 00379 static int DHCP_release_decline (int msg_type, const char *msg) 00380 { 00381 BYTE *opt; 00382 00383 exchange_id = set_timeout (0); /* new exchange ID */ 00384 opt = make_boot_header(); 00385 00386 *opt++ = DHCP_OPT_MSG_TYPE; 00387 *opt++ = 1; 00388 *opt++ = msg_type; 00389 *opt++ = DHCP_OPT_SRV_IDENTIFIER; 00390 *opt++ = sizeof (dhcp_server); 00391 *(DWORD*)opt = intel (dhcp_server); 00392 opt += sizeof (dhcp_server); 00393 00394 if (msg) 00395 { 00396 const BYTE *end = &dhcp_out.dh_opt [sizeof(dhcp_out.dh_opt)-1]; 00397 size_t len = strlen (msg); 00398 00399 len = min (len, 255); 00400 len = min (len, (size_t)(end-opt-3)); 00401 *opt++ = DHCP_OPT_MSG; 00402 *opt++ = (BYTE)len; 00403 memcpy (opt, msg, len); 00404 opt += len; 00405 } 00406 *opt++ = DHCP_OPT_END; 00407 return DHCP_SEND (opt); 00408 } 00409 00417 static BOOL DHCP_arp_check (DWORD my_ip) 00418 { 00419 eth_address eth; 00420 DWORD bcast_ip; 00421 00422 if (_pktserial) 00423 return (TRUE); 00424 00425 bcast_ip = my_ip | ~sin_mask; 00426 00427 /* ARP broadcast to announce our new IP 00428 */ 00429 _arp_reply (NULL, intel(bcast_ip), intel(my_ip)); 00430 dhcp_did_gratuitous_arp = TRUE; 00431 00432 if (!arp_check_ip) 00433 return (TRUE); 00434 00435 /* Check if IP is used by anybody else 00436 */ 00437 TRACE (("Checking ARP..")); 00438 00439 if (!_arp_check_own_ip(&eth)) 00440 { 00441 TRACE (("station %s claims to have my IP %s! Declining..\n", 00442 MAC_address(&eth), INET_NTOA(my_ip))); 00443 if (!trace_on) 00444 outsnl ("Someone claims to have my IP! Declining..\7"); 00445 return (FALSE); 00446 } 00447 TRACE (("\n")); 00448 return (TRUE); 00449 } 00450 00455 static int DHCP_offer (const struct dhcp *in) 00456 { 00457 int len; 00458 DWORD ip; 00459 const BYTE *opt = (const BYTE*) &in->dh_opt[4]; 00460 00461 while (opt < in->dh_opt + sizeof(in->dh_opt)) 00462 { 00463 switch (*opt) 00464 { 00465 case DHCP_OPT_PAD: 00466 opt++; 00467 continue; 00468 00469 case DHCP_OPT_SUBNET_MASK: 00470 sin_mask = intel (*(DWORD*)(opt+2)); 00471 TRACE (("Net-mask: %s\n", INET_NTOA(sin_mask))); 00472 break; 00473 00474 case DHCP_OPT_TIME_OFFSET: 00475 #if defined(USE_DEBUG) 00476 { 00477 long ofs = *(long*)(opt+2); 00478 TRACE (("Time-ofs: %.2fh\n", (double)ofs/3600.0)); 00479 } 00480 #endif 00481 break; 00482 00483 case DHCP_OPT_ROUTERS_ON_SNET: 00484 { 00485 static BOOL gw_added = FALSE; 00486 00487 if (!gw_added) 00488 _arp_kill_gateways(); /* delete gateways from cfg-file */ 00489 gw_added = TRUE; 00490 router = intel (*(DWORD*)(opt+2)); 00491 _arp_add_gateway (NULL, router); 00492 TRACE (("Gateway: %s\n", INET_NTOA(router))); 00493 } 00494 break; 00495 00496 case DHCP_OPT_DNS_SRV: 00497 { 00498 static BOOL dns_added = FALSE; 00499 00500 for (len = 0; len < *(opt+1); len += sizeof(DWORD)) 00501 { 00502 ip = intel (*(DWORD*)(opt+2+len)); 00503 if (!dns_added) 00504 last_nameserver = 0; /* delete nameserver from cfg-file */ 00505 00506 /* 00507 * !!fix-me: Add only first name-server cause resolve() doesn't 00508 * handle multiple servers (in different nets) very well 00509 */ 00510 if (len == 0) 00511 { 00512 nameserver = ip; 00513 _add_server (&last_nameserver, 00514 MAX_NAMESERVERS, def_nameservers, ip); 00515 } 00516 dns_added = TRUE; 00517 TRACE (("DNS: %s\n", INET_NTOA(ip))); 00518 } 00519 } 00520 break; 00521 00522 #if defined(USE_BSD_API) 00523 case DHCP_OPT_LOG_SRV: 00524 if (!syslog_host_name[0] && /* not already set */ 00525 opt[1] % 4 == 0) /* length = n * 4 */ 00526 { 00527 ip = intel (*(DWORD*)(opt+2)); /* select 1st host */ 00528 StrLcpy (syslog_host_name, _inet_ntoa(NULL,ip), 00529 sizeof(syslog_host_name)); 00530 TRACE (("Syslog: %s\n", syslog_host_name)); 00531 } 00532 break; 00533 00534 case DHCP_OPT_NBIOS_NAME_SRV: 00535 ip = intel (*(DWORD*)(opt+2)); 00536 TRACE (("WINS: %s\n", INET_NTOA(ip))); 00538 break; 00539 00540 case DHCP_OPT_NBIOS_NODE_TYPE: 00541 TRACE (("NBT node: %02X\n", opt[2])); 00542 break; 00543 00544 case DHCP_OPT_NBIOS_SCOPE: 00545 TRACE (("NBT scope: %.*s\n", opt[1], opt+2)); 00546 break; 00547 #endif 00548 case DHCP_OPT_HOST_NAME: 00549 /* Don't use sethostname() because '*(opt+2)' is not a FQDN. 00550 */ 00551 len = min (opt[1], sizeof(hostname)); 00552 memcpy (hostname, opt+2, len); 00553 hostname[len] = '\0'; 00554 TRACE (("Host name: `%s'\n", hostname)); 00555 break; 00556 00557 case DHCP_OPT_DOMAIN_NAME: 00558 len = min (opt[1], sizeof(defaultdomain)-1); 00559 setdomainname ((const char*)(opt+2), len+1); 00560 TRACE (("Domain: `%s'\n", def_domain)); 00561 break; 00562 00563 case DHCP_OPT_IP_DEFAULT_TTL: 00564 case DHCP_OPT_TCP_DEFAULT_TTL: 00565 _default_ttl = opt[2]; 00566 break; 00567 00568 case DHCP_OPT_MSG_TYPE: 00569 if (opt[2] == DHCP_OFFER) 00570 got_offer = TRUE; 00571 break; 00572 00573 case DHCP_OPT_MSG: 00574 outsn ((const char*)(opt+2), *(opt+1)); 00575 break; 00576 00577 case DHCP_OPT_SRV_IDENTIFIER: 00578 dhcp_server = intel (*(DWORD*)(opt+2)); 00579 TRACE (("Server: %s\n", INET_NTOA(dhcp_server))); 00580 break; 00581 00582 case DHCP_OPT_IP_ADDR_LEASE_TIME: 00583 dhcp_iplease = intel (*(DWORD*)(opt+2)); 00584 TRACE (("IP lease: %s\n", period(dhcp_iplease))); 00585 break; 00586 00587 case DHCP_OPT_T1_VALUE: 00588 dhcp_renewal = intel (*(DWORD*)(opt+2)); 00589 TRACE (("Renewal: %s\n", period(dhcp_renewal))); 00590 break; 00591 00592 case DHCP_OPT_T2_VALUE: 00593 dhcp_rebind = intel (*(DWORD*)(opt+2)); 00594 TRACE (("Rebind: %s\n", period(dhcp_rebind))); 00595 break; 00596 00597 case DHCP_OPT_TCP_KEEPALIVE_INTERVAL: 00598 #if !defined(USE_UDP_ONLY) 00599 tcp_keep_intvl = intel (*(DWORD*)(opt+2)); 00600 #endif 00601 break; 00602 00603 case DHCP_OPT_OVERLOAD: 00604 switch (opt[2]) 00605 { 00606 case 1: 00607 TRACE (("Overload: `dh_file' options\n")); 00608 dhcp_options_add (in->dh_file, sizeof(in->dh_file)); 00609 break; 00610 case 2: 00611 TRACE (("Overload: `dh_sname' options\n")); 00612 dhcp_options_add (in->dh_sname, sizeof(in->dh_sname)); 00613 break; 00614 case 3: 00615 TRACE (("Overload: `dh_file/dh_sname' options\n")); 00616 dhcp_options_add (in->dh_file, sizeof(in->dh_file)); 00617 dhcp_options_add (in->dh_sname, sizeof(in->dh_sname)); 00618 break; 00619 } 00620 break; 00621 00622 #if defined(USE_TFTP) 00623 case DHCP_OPT_TFTP_SERVER: 00624 { 00625 const char *serv; 00626 len = opt[1]; 00627 serv = tftp_set_server ((const char*)(opt+2), len); 00628 TRACE (("TFTP-serv: `%s'\n", serv)); 00629 } 00630 break; 00631 00632 case DHCP_OPT_BOOT_FILENAME: 00633 { 00634 const char *file; 00635 len = opt[1]; 00636 file = tftp_set_boot_fname ((const char*)(opt+2), len); 00637 TRACE (("BOOT-file: `%s'\n", file)); 00638 } 00639 break; 00640 #endif 00641 00642 case DHCP_OPT_USER_CLASS: /* these options are ignored in replies */ 00643 case DHCP_OPT_CLASS_ID: 00644 break; 00645 00646 case DHCP_OPT_GRUB_MENU: /* GRUB loader config-file */ 00647 TRACE (("GRUB: %.*s\n", opt[1], opt+2)); 00648 break; 00649 00650 case DHCP_OPT_ETHERNET_ENCAPSULATION: 00651 TRACE (("Encap: %s\n", opt[2] ? "IEEE 802.3" : "Ethernet II")); 00652 if (opt[2] != 0) 00653 outsnl (_LANG("Only Ethernet II encapsulation supported")); 00654 break; 00655 00656 case DHCP_OPT_END: 00657 TRACE (("got end-option\n")); 00658 return (got_offer); 00659 00660 default: 00661 TRACE (("Ignoring option %d\n", *opt)); 00662 break; 00663 } 00664 opt += *(opt+1) + 2; 00665 } 00666 00667 if (extra_options.data) 00668 { 00669 struct dhcp ext; 00670 00671 len = min (extra_options.size, sizeof(ext.dh_opt)); 00672 extra_options.data [len] = DHCP_OPT_END; 00673 memcpy (ext.dh_opt, extra_options.data, len); 00674 DHCP_offer (&ext); 00675 } 00676 return (got_offer); 00677 } 00678 00682 static int DHCP_is_ack (void) 00683 { 00684 const BYTE *opt = (const BYTE*) &dhcp_in.dh_opt[4]; 00685 00686 return (opt[0] == DHCP_OPT_MSG_TYPE && opt[1] == 1 && opt[2] == DHCP_ACK); 00687 } 00688 00692 static int DHCP_is_nack (void) 00693 { 00694 const BYTE *opt = (const BYTE*) &dhcp_in.dh_opt[4]; 00695 00696 return (opt[0] == DHCP_OPT_MSG_TYPE && opt[1] == 1 && opt[2] == DHCP_NAK); 00697 } 00698 00705 void DHCP_release (BOOL force) 00706 { 00707 if (force) 00708 { 00709 TRACE (("Sending DHCP release 01\n")); 00710 DHCP_release_decline (DHCP_RELEASE, NULL); 00711 } 00712 else if (configured) 00713 { 00714 /* Don't release if: 00715 * DHCP-config is saved on disk and remaining lease is 00716 * above minimum. 00717 */ 00718 if (!(cfg_saved && 00719 (lease_timeout && (lease_timeout - time(NULL) > DHCP_MIN_LEASE)))) 00720 { 00721 TRACE (("Sending DHCP release 02\n")); 00722 DHCP_release_decline (DHCP_RELEASE, NULL); 00723 } 00724 } 00725 delwattcpd (dhcp_fsm); 00726 if (sock) 00727 { 00728 sock_close (sock); 00729 free (sock); 00730 sock = NULL; 00731 } 00732 } 00733 00737 DWORD DHCP_get_server (void) 00738 { 00739 return (dhcp_server); 00740 } 00741 00745 static sock_type *dhcp_open (const char *msg, BOOL use_broadcast) 00746 { 00747 struct _udp_Socket *sock = malloc (sizeof(*sock)); 00748 DWORD host; 00749 00750 if (!sock) 00751 { 00752 outs (_LANG("DHCP: malloc failed\n")); 00753 return (NULL); 00754 } 00755 00756 if (msg && (trace_on || debug_on)) 00757 outs (msg); 00758 00759 if (use_broadcast) 00760 host = IP_BCAST_ADDR; /* 255.255.255.255 */ 00761 else host = dhcp_server; /* default is 0.0.0.0 which maps to 255.255.255.255 */ 00762 00763 if (!udp_open (sock, IPPORT_BOOTPC, host, IPPORT_BOOTPS, NULL)) 00764 { 00765 if (trace_on || debug_on) 00766 { 00767 outs ("DHCP: "); 00768 outsnl (sock->err_msg); 00769 } 00770 free (sock); 00771 sock = NULL; 00772 } 00773 TRACE (("DHCP open: bc(%d) srvr(%s)\n", 00774 use_broadcast, INET_NTOA(dhcp_server))); 00775 return (sock_type*)sock; /* sock is free'd in DHCP_exit() */ 00776 } 00777 00781 static void arp_add_server (void) 00782 { 00783 if ((_pktdevclass == PDCLASS_ETHER || _pktdevclass == PDCLASS_TOKEN) && 00784 memcmp(sock->udp.his_ethaddr, _eth_brdcast, sizeof(_eth_brdcast))) 00785 { 00786 const eth_address *eth = (const eth_address*) sock->udp.his_ethaddr; 00787 _arp_add_cache (dhcp_server, eth, TRUE); 00788 } 00789 } 00790 00795 static void DHCP_state_BOUND (int event) 00796 { 00797 if (event == EVENT_T1_TIMEOUT) /* renewal timeout */ 00798 { 00799 old_ip_addr = my_ip_addr; /* remember current address */ 00800 got_offer = FALSE; 00801 00802 TRACE (("Sending DHCP request 01\n")); 00803 DHCP_request (1); 00804 DHCP_state = DHCP_state_RENEWING; 00805 } 00806 } 00807 00814 static void DHCP_state_REQUESTING (int event) 00815 { 00816 if (event == EVENT_SEND_TIMEOUT) 00817 { 00818 TRACE (("Sending DHCP request 00\n")); 00819 DHCP_request (0); 00820 00821 /*UPDATE: 05MAR2006 paul.suggs@vgt.net 00822 * There is a timing condition within the FSM where the state has changed 00823 * to REQUESTING but in dhcp_fsm(), chk_timeout() will be evaluated true 00824 * which sets send_timeout to 0 before the first execution of this state 00825 * handler. Once set to 0, we have to wait for rollover to resend the 00826 * above request if it is lost for some reason 00827 */ 00828 send_timeout = set_timeout (Random(4000,6000)); 00829 } 00830 else if (event == EVENT_ACK) 00831 { 00832 TRACE (("Got DHCP ack while requesting\n")); 00833 00834 if (!DHCP_arp_check(my_ip_addr)) 00835 { 00836 my_ip_addr = 0; /* decline from 0.0.0.0 */ 00837 DHCP_release_decline (DHCP_DECLINE, "IP is not free"); 00838 send_timeout = set_timeout (Random(4000,6000)); 00839 DHCP_state = DHCP_state_INIT; 00840 } 00841 else 00842 { 00843 DHCP_offer (&dhcp_in); /* parse options in the ack too */ 00844 configured = 1; /* we are (re)configured */ 00845 if (dhcp_server) 00846 arp_add_server(); 00847 dhcp_set_timers(); 00848 send_timeout = 0UL; 00849 DHCP_state = DHCP_state_BOUND; 00850 } 00851 } 00852 else if (event == EVENT_NAK) 00853 { 00854 send_timeout = set_timeout (Random(4000,6000)); 00855 my_ip_addr = 0UL; 00856 DHCP_state = DHCP_state_INIT; 00857 } 00858 } 00859 00865 static void DHCP_state_REBINDING (int event) 00866 { 00867 if (event == EVENT_ACK) 00868 { 00869 TRACE (("Got DHCP ack while rebinding\n")); 00870 dhcp_set_timers(); 00871 DHCP_offer (&dhcp_in); 00872 change_ip_addr(); 00873 DHCP_state = DHCP_state_BOUND; 00874 } 00875 else if (event == EVENT_NAK) 00876 { 00877 send_timeout = set_timeout (Random(4000,6000)); 00878 my_ip_addr = 0UL; 00879 DHCP_state = DHCP_state_INIT; 00880 } 00881 } 00882 00890 static void DHCP_state_RENEWING (int event) 00891 { 00892 if (event == EVENT_SEND_TIMEOUT) 00893 { 00894 TRACE (("Sending DHCP request for renew\n")); 00895 DHCP_request (1); 00896 } 00897 else if (event == EVENT_T2_TIMEOUT) 00898 { 00899 TRACE (("Sending DHCP request for rebind\n")); 00900 bcast_flag = TRUE; 00901 DHCP_request (1); 00902 DHCP_state = DHCP_state_REBINDING; 00903 } 00904 else if (event == EVENT_ACK) 00905 { 00906 TRACE (("Got DHCP ack while renewing\n")); 00907 dhcp_set_timers(); 00908 DHCP_offer (&dhcp_in); 00909 change_ip_addr(); 00910 DHCP_state = DHCP_state_BOUND; 00911 } 00912 else if (event == EVENT_NAK) 00913 { 00914 TRACE (("Got DHCP nack while renewing\n")); 00915 send_timeout = set_timeout (Random(4000,6000)); 00916 my_ip_addr = 0; 00917 DHCP_state = DHCP_state_INIT; 00918 } 00919 } 00920 00926 static void DHCP_state_SELECTING (int event) 00927 { 00928 if (event == EVENT_OFFER && !got_offer && DHCP_offer(&dhcp_in)) 00929 { 00930 TRACE (("Got DHCP offer\n")); 00931 send_timeout = set_timeout (Random(100,500)); 00932 00933 if (dhcp_renewal == 0L) 00934 dhcp_renewal = dhcp_iplease / 2; /* default T1 time */ 00935 if (dhcp_rebind == 0) 00936 dhcp_rebind = dhcp_iplease * 7 / 8; /* default T2 time */ 00937 00938 /* Remember my_ip_addr from OFFER because WinNT server 00939 * doesn't include it in ACK message. 00940 */ 00941 my_ip_addr = ((_udp_Socket*)sock)->myaddr = intel (dhcp_in.dh_yiaddr); 00942 TRACE (("my_ip_addr = %s\n", INET_NTOA(my_ip_addr))); 00943 send_timeout = set_timeout (100); 00944 DHCP_state = DHCP_state_REQUESTING; 00945 } 00946 else if (event == EVENT_SEND_TIMEOUT) /* retransmit timeout */ 00947 { 00948 DHCP_state = DHCP_state_INIT; 00949 (*DHCP_state) (event); 00950 } 00951 } 00952 00957 static void DHCP_state_INIT (int event) 00958 { 00959 if (event == EVENT_SEND_TIMEOUT) 00960 { 00961 discover_loops++; 00962 exchange_id = set_timeout (0); /* random exchange ID */ 00963 00964 TRACE (("Sending DHCP discover (%d)\n", discover_loops)); 00965 00966 send_timeout = set_timeout (1000 * dhcp_timeout); 00967 DHCP_discover(); 00968 DHCP_state = DHCP_state_SELECTING; 00969 } 00970 } 00971 00972 #ifdef NOT_USED 00973 00976 static void DHCP_state_REBOOTING (int event) 00977 { 00978 if (event == EVENT_ACK) 00979 { 00980 DHCP_state = DHCP_state_BOUND; 00981 } 00982 else if (event == EVENT_NAK) 00983 { 00984 send_timeout = set_timeout (Random(4000,6000)); 00985 DHCP_state = DHCP_state_INIT; 00986 } 00987 } 00988 #endif 00989 00993 static void dhcp_fsm (void) 00994 { 00995 if (sock_dataready(sock)) 00996 { 00997 int len = sock_fastread (sock, (BYTE*)&dhcp_in, sizeof(dhcp_in)); 00998 00999 if (len >= DHCP_MIN_SIZE && /* packet large enough */ 01000 dhcp_in.dh_op == BOOTP_REPLY && /* got a BOOTP reply */ 01001 dhcp_in.dh_xid == dhcp_out.dh_xid && /* got our exchange ID */ 01002 !memcmp(dhcp_in.dh_chaddr, _eth_addr, /* correct hardware addr */ 01003 sizeof(eth_address))) 01004 { 01005 if (DHCP_is_ack()) 01006 { 01007 TRACE (("%s/ACK: ", state_name())); 01008 (*DHCP_state) (EVENT_ACK); 01009 } 01010 else if (DHCP_is_nack()) 01011 { 01012 TRACE (("%s/NAK: ", state_name())); 01013 (*DHCP_state) (EVENT_NAK); 01014 } 01015 else 01016 { 01017 TRACE (("%s/OFFER: ", state_name())); 01018 (*DHCP_state) (EVENT_OFFER); 01019 } 01020 } 01021 } 01022 01023 if (chk_timeout(send_timeout)) 01024 { 01025 send_timeout = 0UL; 01026 TRACE (("%s/SEND_TIMEOUT: ", state_name())); 01027 (*DHCP_state) (EVENT_SEND_TIMEOUT); 01028 } 01029 01030 if (renewal_timeout && time(NULL) >= renewal_timeout) 01031 { 01032 renewal_timeout = 0UL; 01033 TRACE (("%s/T1_TIMEOUT: ", state_name())); 01034 (*DHCP_state) (EVENT_T1_TIMEOUT); 01035 } 01036 01037 if (rebind_timeout && time(NULL) >= rebind_timeout) 01038 { 01039 rebind_timeout = 0UL; 01040 TRACE (("%s/T2_TIMEOUT: ", state_name())); 01041 (*DHCP_state) (EVENT_T2_TIMEOUT); 01042 } 01043 } 01044 01054 int DHCP_do_boot (void) 01055 { 01056 int save_mtu = _mtu; 01057 01058 if (cfg_read) /* DHCP_read_config() okay */ 01059 return (1); 01060 01061 outs (_LANG("Configuring through DHCP..")); 01062 if (!sock) 01063 sock = dhcp_open (NULL, bcast_flag); 01064 if (!sock) 01065 return (0); 01066 01067 if (DHCP_state != DHCP_state_RENEWING && 01068 DHCP_state != DHCP_state_REBINDING) 01069 { 01070 my_ip_addr = 0; 01071 sin_mask = 0; 01072 } 01073 01074 _mtu = ETH_MAX_DATA; 01075 discover_loops = 0; 01076 01077 erase_config(); /* delete old configuration */ 01078 addwattcpd (dhcp_fsm); /* add "background" daemon */ 01079 01080 /* kick start DISCOVER message 01081 */ 01082 send_timeout = set_timeout (100); 01083 01084 if (DHCP_state != DHCP_state_RENEWING && 01085 DHCP_state != DHCP_state_REBINDING) 01086 DHCP_state = DHCP_state_INIT; 01087 01088 while (DHCP_state != DHCP_state_BOUND) 01089 { 01090 tcp_tick (NULL); 01091 if (discover_loops >= max_retries) /* retries exhaused */ 01092 break; 01093 } 01094 01095 got_offer = FALSE; /* ready for next cycle */ 01096 _mtu = save_mtu; 01097 01098 if (my_ip_addr) 01099 { 01100 cfg_saved = write_config() > 0; 01101 return (1); 01102 } 01103 return (0); 01104 } 01105 01109 static void dhcp_options_add (const BYTE *opt, unsigned max) 01110 { 01111 int len = 0; 01112 char *add; 01113 const BYTE *end = opt + max; 01114 01115 extra_options.data = (BYTE*) realloc (extra_options.data, max); 01116 if (!extra_options.data) 01117 return; 01118 01119 add = (char*)&extra_options.data + extra_options.size; 01120 01121 /* Loop over `opt' and append to `add'. Strip away DHCP_OPT_END 01122 * and DHCP_OPT_PAD options. 01123 */ 01124 while (opt < end) 01125 { 01126 if (*opt == DHCP_OPT_PAD) 01127 continue; 01128 if (*opt == DHCP_OPT_END) 01129 return; 01130 01131 len = opt[1]; 01132 memcpy (add, opt, len+2); 01133 add += len + 2; 01134 opt += len + 2; 01135 extra_options.size += len + 2; 01136 } 01137 } 01138 01142 static void dhcp_set_timers (void) 01143 { 01144 time_t now = time (NULL); 01145 01146 if (dhcp_iplease == 0UL) 01147 lease_timeout = (time_t)-1; 01148 else lease_timeout = now + dhcp_iplease; 01149 01150 if (dhcp_renewal == 0UL) 01151 renewal_timeout = (time_t)-1; 01152 else renewal_timeout = now + dhcp_renewal; 01153 01154 if (dhcp_rebind == 0UL) 01155 rebind_timeout = (time_t)-1; 01156 else 01157 { 01158 rebind_timeout = now + dhcp_rebind; 01159 if (rebind_timeout == renewal_timeout) 01160 rebind_timeout += 10; /* add 10 seconds */ 01161 } 01162 if (dhcp_iplease == 0UL) 01163 TRACE (("Infinite lease!!\n")); 01164 } 01165 01169 static void change_ip_addr (void) 01170 { 01171 if (my_ip_addr == old_ip_addr) 01172 return; 01173 01174 #if !defined(USE_UDP_ONLY) 01175 { 01176 _tcp_Socket *tcp; 01177 for (tcp = _tcp_allsocs; tcp; tcp = tcp->next) 01178 if (tcp->myaddr) 01179 tcp->myaddr = my_ip_addr; 01180 } 01181 #endif 01182 01183 { 01184 _udp_Socket *udp; 01185 for (udp = _udp_allsocs; udp; udp = udp->next) 01186 if (udp->myaddr) 01187 udp->myaddr = my_ip_addr; 01188 } 01189 } 01190 01195 static int set_request_list (char *options) 01196 { 01197 static BOOL init = FALSE; 01198 int num = 0; 01199 int maxreq = 312 - 27; /* sizeof(dh_opt) - min size of rest */ 01200 BYTE *list, *start, *tok, *end; 01201 01202 if (init || (list = calloc(maxreq,1)) == NULL) 01203 return (0); 01204 01205 init = TRUE; 01206 start = list; 01207 end = start + maxreq - 1; 01208 tok = (BYTE*) strtok (options, ", \t"); 01209 01210 while (tok && list < end) 01211 { 01212 *list = ATOI ((const char*)tok); 01213 tok = (BYTE*) strtok (NULL, ", \t"); 01214 01215 /* If request list start with Pad option ("DHCP.REQ_LIST=0"), 01216 * disable options all-together. 01217 */ 01218 if (num == 0 && *list == '0') 01219 break; 01220 num++; 01221 list++; 01222 } 01223 01224 request_list.data = start; 01225 request_list.size = num; 01226 01227 #if 0 /* test */ 01228 { 01229 int i; 01230 for (i = 0; i < request_list.size; i++) 01231 printf ("%2d, ", request_list.data[i]); 01232 puts (""); 01233 } 01234 #endif 01235 return (1); 01236 } 01237 01241 static BYTE *put_request_list (BYTE *opt, int filled) 01242 { 01243 size_t size = min (request_list.size, sizeof(dhcp_out.dh_opt)-filled-1); 01244 /* room for DHCP_OPT_END ^ */ 01245 if (size > 0 && request_list.data) 01246 { 01247 size = min (size, 255); 01248 *opt++ = DHCP_OPT_PARAM_REQUEST; 01249 *opt++ = (BYTE)size; 01250 memcpy (opt, request_list.data, size); 01251 opt += size; 01252 } 01253 return (opt); 01254 } 01255 01261 static int set_user_class (const char *value) 01262 { 01263 static BOOL init = FALSE; 01264 int total = 0; 01265 int maxreq = sizeof(dhcp_out.dh_opt) - 27; /* adjust for rest */ 01266 char *list, *list_start; 01267 char *list_end; 01268 const char *value_end; 01269 01270 if (init || (list = (char*)calloc(maxreq,1)) == NULL) 01271 return (0); 01272 01273 init = TRUE; 01274 list_start = list; 01275 list_end = list + maxreq - 1; 01276 value_end = value + strlen (value); 01277 01278 while (list < list_end && value < value_end) 01279 { 01280 const char *comma = strchr (value, ','); 01281 int size; 01282 01283 if (comma) 01284 size = comma - value; /* "xxx,xxx" */ 01285 else size = strlen (value); /* "xxxx" */ 01286 *list++ = size; 01287 memcpy (list, value, size); 01288 list += size; 01289 value += size + 1; 01290 total += size + 1; 01291 } 01292 01293 user_class.data = (BYTE*) list_start; 01294 user_class.size = total; 01295 01296 #if 0 /* test */ 01297 { 01298 size_t i; 01299 for (i = 0; i < user_class.size; i++) 01300 { 01301 int ch = user_class.data[i]; 01302 01303 if (isprint(ch)) 01304 printf ("%c", ch); 01305 else printf ("\\x%02X", ch); 01306 } 01307 puts (""); 01308 } 01309 #endif 01310 return (1); 01311 } 01312 01316 static int set_vend_class (const char *value) 01317 { 01319 ARGSUSED (value); 01320 return (0); 01321 } 01322 01323 /*-------------------------------------------------------------------*/ 01324 01325 static void (*prev_hook) (const char*, const char*) = NULL; 01326 01327 /* Absolute times for expiry of lease, renewal and rebind 01328 * read from user (config_func) or transient config file. 01329 */ 01330 static time_t cfg_dhcp_iplease; 01331 static time_t cfg_dhcp_renewal; 01332 static time_t cfg_dhcp_rebind; 01333 01339 static void DHCP_cfg_hook (const char *name, const char *value) 01340 { 01341 static const struct config_table dhcp_cfg[] = { 01342 { "REQ_LIST", ARG_FUNC, (void*)set_request_list }, 01343 { "TRACE", ARG_ATOI, (void*)&trace_on }, 01344 { "BCAST", ARG_ATOI, (void*)&bcast_flag }, 01345 { "TIMEOUT", ARG_ATOI, (void*)&dhcp_timeout }, 01346 { "RETRIES", ARG_ATOI, (void*)&max_retries }, 01347 { "ARPCHECK", ARG_ATOI, (void*)&arp_check_ip }, 01348 { "HOST", ARG_RESOLVE,(void*)&dhcp_server }, 01349 { "USERCLASS",ARG_FUNC, (void*)set_user_class }, 01350 { "VENDCLASS",ARG_FUNC, (void*)set_vend_class }, 01351 { "CONFIG", ARG_STRCPY, (void*)&config_file }, 01352 { NULL, 0, NULL } 01353 }; 01354 01355 if (!parse_config_table(&dhcp_cfg[0], "DHCP.", name, value) && prev_hook) 01356 (*prev_hook) (name, value); 01357 } 01358 01362 static void DHCP_exit (void) 01363 { 01364 if (_watt_fatal_error) 01365 return; 01366 01367 DO_FREE (user_class.data); 01368 DO_FREE (extra_options.data); 01369 DO_FREE (sock); 01370 if (request_list.data != (BYTE*)&default_request_list) 01371 DO_FREE (request_list.data); 01372 01373 #if defined(USE_BSD_API) 01374 syslog_host_name[0] = '\0'; 01375 #endif 01376 } 01377 01381 void DHCP_init (void) 01382 { 01383 prev_hook = usr_init; 01384 usr_init = DHCP_cfg_hook; 01385 RUNDOWN_ADD (DHCP_exit, 259); 01386 } 01387 01391 static void set_my_ip (const char *value) 01392 { 01393 TRACE (("DHCP: using previous address %s\n", value)); 01394 my_ip_addr = aton (value); 01395 } 01396 01397 static void set_netmask (const char *value) 01398 { 01399 TRACE (("DHCP: using previous netmask %s\n", value)); 01400 sin_mask = aton (value); 01401 } 01402 01403 static void set_gateway (const char *value) 01404 { 01405 router = aton (value); 01406 if (router) 01407 { 01408 _arp_kill_gateways(); /* delete gateways from cfg-file */ 01409 TRACE (("DHCP: using previous gateway %s\n", value)); 01410 _arp_add_gateway (NULL, router); 01411 } 01412 else 01413 TRACE (("DHCP: previous gateway is 0.0.0.0!\n")); 01414 } 01415 01416 static void set_nameserv (const char *value) 01417 { 01418 TRACE (("DHCP: using previous nameserv %s\n", value)); 01419 nameserver = aton (value); 01420 _add_server (&last_nameserver, MAX_NAMESERVERS, def_nameservers, nameserver); 01421 } 01422 01423 static void set_server (const char *value) 01424 { 01425 TRACE (("DHCP: using previous server %s\n", value)); 01426 dhcp_server = aton (value); 01427 } 01428 01429 static void set_domain (const char *value) 01430 { 01431 TRACE (("DHCP: using previous domain %s\n", value)); 01432 setdomainname (value, strlen(value)+1); 01433 } 01434 01435 static void set_lease (const char *value) 01436 { 01437 cfg_dhcp_iplease = ATOL (value); 01438 } 01439 01440 static void set_renew (const char *value) 01441 { 01442 cfg_dhcp_renewal = ATOL (value); 01443 } 01444 01445 static void set_rebind (const char *value) 01446 { 01447 cfg_dhcp_rebind = ATOL (value); 01448 } 01449 01461 static BOOL eval_timers (void) 01462 { 01463 time_t now = time (NULL); 01464 01465 TRACE (("DHCP: IP-lease expires %s", ctime(&cfg_dhcp_iplease))); 01466 TRACE (("DHCP: rebinding expires %s", ctime(&cfg_dhcp_rebind))); 01467 TRACE (("DHCP: renewal expires %s", ctime(&cfg_dhcp_renewal))); 01468 01469 if (cfg_dhcp_iplease < now) 01470 dhcp_iplease = DHCP_MIN_LEASE; 01471 else dhcp_iplease = (DWORD)(cfg_dhcp_iplease - now); 01472 01473 if (cfg_dhcp_renewal < now) 01474 dhcp_renewal = dhcp_iplease / 2; 01475 else dhcp_renewal = (DWORD)(cfg_dhcp_renewal - now); 01476 01477 if (cfg_dhcp_rebind < now) 01478 dhcp_rebind = dhcp_iplease * 7 / 8; 01479 else dhcp_rebind = (DWORD)(cfg_dhcp_rebind - now); 01480 01481 discover_loops = 0; 01482 01483 if (now < cfg_dhcp_renewal) 01484 { 01485 TRACE (("DHCP: BOUND\n")); 01486 DHCP_state = DHCP_state_BOUND; /* no action, goto BOUND */ 01487 return (TRUE); 01488 } 01489 01490 if (now >= cfg_dhcp_renewal && now < cfg_dhcp_rebind) 01491 { 01492 TRACE (("DHCP: RENEWING\n")); 01493 DHCP_state = DHCP_state_BOUND; 01494 (*DHCP_state) (EVENT_T1_TIMEOUT); /* goto RENEWING */ 01495 return (FALSE); 01496 } 01497 01498 if (now >= cfg_dhcp_rebind && now < cfg_dhcp_iplease) 01499 { 01500 TRACE (("DHCP: REBINDING\n")); 01501 DHCP_state = DHCP_state_RENEWING; 01502 (*DHCP_state) (EVENT_T2_TIMEOUT); /* goto REBINDING */ 01503 return (FALSE); 01504 } 01505 return (FALSE); 01506 } 01507 01514 static const struct config_table transient_cfg[] = { 01515 { "DHCP.LEASE", ARG_FUNC, (void*)set_lease }, 01516 { "DHCP.RENEW", ARG_FUNC, (void*)set_renew }, 01517 { "DHCP.REBIND", ARG_FUNC, (void*)set_rebind }, 01518 { "DHCP.MY_IP", ARG_FUNC, (void*)set_my_ip }, 01519 { "DHCP.NETMASK", ARG_FUNC, (void*)set_netmask }, 01520 { "DHCP.GATEWAY", ARG_FUNC, (void*)set_gateway }, 01521 { "DHCP.NAMESERV", ARG_FUNC, (void*)set_nameserv }, 01522 { "DHCP.SERVER", ARG_FUNC, (void*)set_server }, 01523 { "DHCP.DOMAIN", ARG_FUNC, (void*)set_domain }, 01524 { "DHCP.HOSTNAME", ARG_STRCPY, (void*)hostname }, 01525 #if defined(USE_BSD_API) 01526 { "DHCP.LOGHOST", ARG_STRCPY, (void*)&syslog_host_name }, 01527 #endif 01528 { "DHCP.DEF_TTL", ARG_ATOI, (void*)&_default_ttl }, 01529 #if !defined(USE_UDP_ONLY) 01530 { "DHCP.TCP_KEEP", ARG_ATOI, (void*)&tcp_keep_intvl }, 01531 #endif 01532 { NULL, 0, NULL } 01533 }; 01534 01535 /* 01536 * Return name of transient config-file. 01537 */ 01538 static const char *get_config_file (void) 01539 { 01540 if (config_file[0]) 01541 return (config_file); 01542 return ExpandVarStr ("$(TEMP)\\W32DHCP.TMP"); 01543 } 01544 01545 /* 01546 * The standard DHCP config eraser. 01547 */ 01548 static void std_erase_config (void) 01549 { 01550 unlink (get_config_file()); 01551 } 01552 01553 /* 01554 * The standard DHCP config reader. 01555 */ 01556 static int std_read_config (void) 01557 { 01558 WFILE file; 01559 const char *fname = get_config_file(); 01560 01561 if (!FOPEN(file, fname)) 01562 { 01563 TRACE (("`%s' not found\n", fname)); 01564 return (0); 01565 } 01566 01567 prev_hook = usr_init; 01568 usr_init = NULL; /* don't chain to other parsers */ 01569 tcp_parse_file (file, &transient_cfg[0]); 01570 usr_init = prev_hook; 01571 01572 FCLOSE (file); 01573 return (1); 01574 } 01575 01581 static int std_write_config (void) 01582 { 01583 char buf[20]; 01584 FILE *file; 01585 time_t tim, now = time (NULL); 01586 int rc = 0; 01587 const char *fname = get_config_file(); 01588 01589 if (access(fname,0)) /* file not found, create */ 01590 { 01591 file = fopen (fname, "w+t"); 01592 if (!file) 01593 goto fail; 01594 01595 rc = fprintf (file, 01596 "#\n" 01597 "# GENERATED FILE. DO NOT EDIT!\n" 01598 "#\n" 01599 "# DHCP transient configuration; values that must\n" 01600 "# be known between consecutive runs of applications.\n" 01601 "# Version: %s\n" 01602 "#\n", wattcpVersion()); 01603 } 01604 else 01605 { 01606 #if defined(WIN32) 01607 SetFileAttributes (fname, FILE_ATTRIBUTE_NORMAL); 01608 #else 01609 _dos_setfileattr (fname, _A_NORMAL); 01610 #endif 01611 file = fopen (fname, "at"); /* append to file */ 01612 if (!file) 01613 goto fail; 01614 } 01615 01616 rc += fprintf (file, "# This file saved at %s#\n", ctime(&now)); 01617 01618 tim = dhcp_iplease + now; 01619 rc += fprintf (file, "DHCP.LEASE = %-20lu # lease expires %s", 01620 (DWORD)tim, ctime(&tim)); 01621 01622 tim = dhcp_renewal + now; 01623 rc += fprintf (file, "DHCP.RENEW = %-20lu # renew expires %s", 01624 (DWORD)tim, ctime(&tim)); 01625 01626 tim = dhcp_rebind + now; 01627 rc += fprintf (file, 01628 "DHCP.REBIND = %-20lu # rebind expires %s" 01629 "DHCP.MY_IP = %-20s # assigned ip-address\n", 01630 (DWORD)tim, ctime(&tim), _inet_ntoa(buf,my_ip_addr)); 01631 01632 rc += fprintf (file, "DHCP.NETMASK = %-20s # assigned netmask\n", 01633 _inet_ntoa(buf,sin_mask)); 01634 01635 rc += fprintf (file, "DHCP.GATEWAY = %-20s # assigned gateway\n", 01636 _inet_ntoa(buf,router)); 01637 01638 rc += fprintf (file, "DHCP.NAMESERV = %-20s # assigned nameserver\n", 01639 _inet_ntoa(buf,nameserver)); 01640 01641 rc += fprintf (file, "DHCP.SERVER = %-20s # DHCP server\n", 01642 _inet_ntoa(buf,dhcp_server)); 01643 01644 rc += fprintf (file, "DHCP.HOSTNAME = %-20s # assigned hostname\n", 01645 hostname); 01646 01647 rc += fprintf (file, "DHCP.DOMAIN = %-20s # assigned domain\n", 01648 def_domain); 01649 01650 #if defined(USE_BSD_API) 01651 if (syslog_host_name[0]) 01652 rc += fprintf (file, "DHCP.LOGHOST = %-20s # assigned syslog host\n", 01653 syslog_host_name); 01654 #endif 01655 01656 rc += fprintf (file, "DHCP.DEF_TTL = %-20d # default TTL\n", 01657 _default_ttl); 01658 01659 #if !defined(USE_UDP_ONLY) 01660 rc += fprintf (file, "DHCP.TCP_KEEP = %-20d # TCP keepalive interval\n", 01661 tcp_keep_intvl); 01662 #endif 01663 01664 fclose (file); 01665 return (rc); 01666 01667 fail: 01668 TCP_CONSOLE_MSG (0, ("Writing %s failed; %s\n", fname, strerror(errno))); 01669 return (0); 01670 } 01671 01672 /* 01673 * The user-defined DHCP config eraser. 01674 */ 01675 static void usr_erase_config (void) 01676 { 01677 (*config_func) (DHCP_OP_ERASE, NULL); 01678 } 01679 01680 static int usr_read_config (void) 01681 { 01682 struct DHCP_config cfg; 01683 01684 memset (&cfg, 0, sizeof(cfg)); 01685 01686 if (!(*config_func)(DHCP_OP_READ, &cfg)) 01687 return (0); 01688 01689 TRACE (("DHCP: using previous address %s\n", INET_NTOA(cfg.my_ip))); 01690 my_ip_addr = cfg.my_ip; 01691 01692 TRACE (("DHCP: using previous netmask %s\n", INET_NTOA(cfg.netmask))); 01693 sin_mask = cfg.netmask; 01694 01695 if (!_arp_have_default_gw()) 01696 { 01697 TRACE (("DHCP: using previous gateway %s\n", INET_NTOA(cfg.gateway))); 01698 router = cfg.gateway; 01699 _arp_add_gateway (NULL, router); 01700 } 01701 else 01702 TRACE (("DHCP: already have default gateway\n")); 01703 01704 TRACE (("DHCP: using previous nameserv %s\n", INET_NTOA(cfg.nameserver))); 01705 nameserver = cfg.nameserver; 01706 _add_server (&last_nameserver, MAX_NAMESERVERS, def_nameservers, nameserver); 01707 01708 TRACE (("DHCP: using previous server %s\n", INET_NTOA(cfg.server))); 01709 dhcp_server = cfg.server; 01710 01711 cfg_dhcp_iplease = cfg.iplease; 01712 cfg_dhcp_renewal = cfg.renewal; 01713 cfg_dhcp_rebind = cfg.rebind; 01714 01715 _default_ttl = cfg.default_ttl; 01716 #if !defined(USE_UDP_ONLY) 01717 tcp_keep_intvl = cfg.tcp_keep_intvl; 01718 #endif 01719 01720 StrLcpy (hostname, cfg.hostname, sizeof(hostname)); 01721 01722 TRACE (("DHCP: using previous domain %s\n", cfg.domain)); 01723 setdomainname (cfg.domain, strlen(cfg.domain)+1); 01724 01725 #if defined(USE_BSD_API) 01726 if (cfg.loghost[0]) 01727 StrLcpy (syslog_host_name, cfg.loghost, sizeof(syslog_host_name)); 01728 #endif 01729 01730 return (1); 01731 } 01732 01733 static int usr_write_config (void) 01734 { 01735 struct DHCP_config cfg; 01736 time_t now = time (NULL); 01737 01738 memset (&cfg, 0, sizeof(cfg)); 01739 cfg.my_ip = my_ip_addr; 01740 cfg.netmask = sin_mask; 01741 cfg.gateway = router; 01742 cfg.nameserver = nameserver; 01743 cfg.server = dhcp_server; 01744 cfg.iplease = (DWORD)now + dhcp_iplease; 01745 cfg.renewal = (DWORD)now + dhcp_renewal; 01746 cfg.rebind = (DWORD)now + dhcp_rebind; 01747 cfg.default_ttl = _default_ttl; 01748 #if !defined(USE_UDP_ONLY) 01749 cfg.tcp_keep_intvl = tcp_keep_intvl; 01750 #endif 01751 01752 StrLcpy (cfg.hostname, hostname, sizeof(cfg.hostname)); 01753 StrLcpy (cfg.domain, def_domain, sizeof(cfg.domain)); 01754 01755 #if defined(USE_BSD_API) 01756 if (syslog_host_name[0]) 01757 StrLcpy (cfg.loghost, syslog_host_name, sizeof(cfg.loghost)); 01758 #endif 01759 01760 return (*config_func) (DHCP_OP_WRITE, &cfg); 01761 } 01762 01766 static void erase_config (void) 01767 { 01768 config_func ? usr_erase_config() : std_erase_config(); 01769 } 01770 01776 int DHCP_read_config (void) 01777 { 01778 cfg_read = FALSE; 01779 01780 if (config_func ? usr_read_config() : std_read_config() > 0) 01781 { 01782 sock = dhcp_open (NULL, bcast_flag); 01783 if (!sock) 01784 return (0); 01785 01786 if (eval_timers()) 01787 { 01788 cfg_read = TRUE; 01789 dhcp_set_timers(); 01790 return (1); 01791 } 01792 TRACE (("DHCP: config too old.\n")); 01793 sock->udp.myaddr = 0; 01794 sock->udp.hisaddr = IP_BCAST_ADDR; 01795 } 01796 01797 /* Reading config failed or timers expired; must do the whole 01798 * DHCP configuration when sock_init.c calls DHCP_do_boot(). 01799 */ 01800 return (0); 01801 } 01802 01807 static int write_config (void) 01808 { 01809 return (config_func ? usr_write_config() : std_write_config()); 01810 } 01811 01815 WattDHCPConfigFunc dhcp_set_config_func (WattDHCPConfigFunc fn) 01816 { 01817 WattDHCPConfigFunc old_fn = config_func; 01818 config_func = fn; 01819 return (old_fn); 01820 } 01821 #endif /* USE_DHCP */

Generated on Wed Aug 4 08:55:51 2010 for Watt-32 tcp/ip by doxygen 1.3.8