ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

dhclient.c
Go to the documentation of this file.
00001 /*  $OpenBSD: dhclient.c,v 1.62 2004/12/05 18:35:51 deraadt Exp $   */
00002 
00003 /*
00004  * Copyright 2004 Henning Brauer <henning@openbsd.org>
00005  * Copyright (c) 1995, 1996, 1997, 1998, 1999
00006  * The Internet Software Consortium.    All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  *
00012  * 1. Redistributions of source code must retain the above copyright
00013  *    notice, this list of conditions and the following disclaimer.
00014  * 2. Redistributions in binary form must reproduce the above copyright
00015  *    notice, this list of conditions and the following disclaimer in the
00016  *    documentation and/or other materials provided with the distribution.
00017  * 3. Neither the name of The Internet Software Consortium nor the names
00018  *    of its contributors may be used to endorse or promote products derived
00019  *    from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
00022  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
00023  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00024  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00025  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
00026  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00027  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00028  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
00029  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00030  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00031  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00033  * SUCH DAMAGE.
00034  *
00035  * This software has been written for the Internet Software Consortium
00036  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
00037  * Enterprises.  To learn more about the Internet Software Consortium,
00038  * see ``http://www.vix.com/isc''.  To learn more about Vixie
00039  * Enterprises, see ``http://www.vix.com''.
00040  *
00041  * This client was substantially modified and enhanced by Elliot Poger
00042  * for use on Linux while he was working on the MosquitoNet project at
00043  * Stanford.
00044  *
00045  * The current version owes much to Elliot's Linux enhancements, but
00046  * was substantially reorganized and partially rewritten by Ted Lemon
00047  * so as to use the same networking framework that the Internet Software
00048  * Consortium DHCP server uses.   Much system-specific configuration code
00049  * was moved into a shell script so that as support for more operating
00050  * systems is added, it will not be necessary to port and maintain
00051  * system-specific configuration code to these operating systems - instead,
00052  * the shell script can invoke the native tools to accomplish the same
00053  * purpose.
00054  */
00055 
00056 #include "rosdhcp.h"
00057 
00058 #define PERIOD 0x2e
00059 #define hyphenchar(c) ((c) == 0x2d)
00060 #define bslashchar(c) ((c) == 0x5c)
00061 #define periodchar(c) ((c) == PERIOD)
00062 #define asterchar(c) ((c) == 0x2a)
00063 #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
00064         ((c) >= 0x61 && (c) <= 0x7a))
00065 #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
00066 
00067 #define borderchar(c) (alphachar(c) || digitchar(c))
00068 #define middlechar(c) (borderchar(c) || hyphenchar(c))
00069 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
00070 
00071 unsigned long debug_trace_level = 0; /* DEBUG_ULTRA */
00072 
00073 char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
00074 char *path_dhclient_db = NULL;
00075 
00076 int log_perror = 1;
00077 int privfd;
00078 //int nullfd = -1;
00079 
00080 struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
00081 struct in_addr inaddr_any;
00082 struct sockaddr_in sockaddr_broadcast;
00083 
00084 /*
00085  * ASSERT_STATE() does nothing now; it used to be
00086  * assert (state_is == state_shouldbe).
00087  */
00088 #define ASSERT_STATE(state_is, state_shouldbe) {}
00089 
00090 #define TIME_MAX 2147483647
00091 
00092 int     log_priority;
00093 int     no_daemon;
00094 int     unknown_ok = 1;
00095 int     routefd;
00096 
00097 void         usage(void);
00098 int      check_option(struct client_lease *l, int option);
00099 int      ipv4addrs(char * buf);
00100 int      res_hnok(const char *dn);
00101 char        *option_as_string(unsigned int code, unsigned char *data, int len);
00102 int      fork_privchld(int, int);
00103 int              check_arp( struct interface_info *ip, struct client_lease *lp );
00104 
00105 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
00106 
00107 time_t  scripttime;
00108 
00109 static WCHAR ServiceName[] = L"DHCP";
00110 
00111 SERVICE_STATUS_HANDLE ServiceStatusHandle = 0;
00112 SERVICE_STATUS ServiceStatus;
00113 
00114 
00115 /* XXX Implement me */
00116 int check_arp( struct interface_info *ip, struct client_lease *lp ) {
00117     return 1;
00118 }
00119 
00120 
00121 static VOID
00122 UpdateServiceStatus(DWORD dwState)
00123 {
00124     ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
00125     ServiceStatus.dwCurrentState = dwState;
00126 
00127     ServiceStatus.dwControlsAccepted = 0;
00128 
00129     ServiceStatus.dwWin32ExitCode = 0;
00130     ServiceStatus.dwServiceSpecificExitCode = 0;
00131     ServiceStatus.dwCheckPoint = 0;
00132 
00133     if (dwState == SERVICE_START_PENDING ||
00134         dwState == SERVICE_STOP_PENDING ||
00135         dwState == SERVICE_PAUSE_PENDING ||
00136         dwState == SERVICE_CONTINUE_PENDING)
00137         ServiceStatus.dwWaitHint = 10000;
00138     else
00139         ServiceStatus.dwWaitHint = 0;
00140 
00141     SetServiceStatus(ServiceStatusHandle,
00142                      &ServiceStatus);
00143 }
00144 
00145 
00146 static DWORD WINAPI
00147 ServiceControlHandler(DWORD dwControl,
00148                       DWORD dwEventType,
00149                       LPVOID lpEventData,
00150                       LPVOID lpContext)
00151 {
00152     switch (dwControl)
00153     {
00154         case SERVICE_CONTROL_STOP:
00155             UpdateServiceStatus(SERVICE_STOP_PENDING);
00156             UpdateServiceStatus(SERVICE_STOPPED);
00157             return ERROR_SUCCESS;
00158 
00159         case SERVICE_CONTROL_PAUSE:
00160             UpdateServiceStatus(SERVICE_PAUSED);
00161             return ERROR_SUCCESS;
00162 
00163         case SERVICE_CONTROL_CONTINUE:
00164             UpdateServiceStatus(SERVICE_START_PENDING);
00165             UpdateServiceStatus(SERVICE_RUNNING);
00166             return ERROR_SUCCESS;
00167 
00168         case SERVICE_CONTROL_INTERROGATE:
00169             SetServiceStatus(ServiceStatusHandle,
00170                              &ServiceStatus);
00171             return ERROR_SUCCESS;
00172 
00173         case SERVICE_CONTROL_SHUTDOWN:
00174             UpdateServiceStatus(SERVICE_STOP_PENDING);
00175             UpdateServiceStatus(SERVICE_STOPPED);
00176             return ERROR_SUCCESS;
00177 
00178         default :
00179             return ERROR_CALL_NOT_IMPLEMENTED;
00180     }
00181 }
00182 
00183 
00184 VOID NTAPI
00185 ServiceMain(DWORD argc, LPWSTR *argv)
00186 {
00187     ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
00188                                                         ServiceControlHandler,
00189                                                         NULL);
00190     if (!ServiceStatusHandle)
00191     {
00192         DbgPrint("DHCPCSVC: Unable to register service control handler (%lx)\n", GetLastError());
00193         return;
00194     }
00195 
00196     UpdateServiceStatus(SERVICE_START_PENDING);
00197 
00198     ApiInit();
00199     AdapterInit();
00200 
00201     tzset();
00202 
00203     memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
00204     sockaddr_broadcast.sin_family = AF_INET;
00205     sockaddr_broadcast.sin_port = htons(REMOTE_PORT);
00206     sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
00207     inaddr_any.s_addr = INADDR_ANY;
00208     bootp_packet_handler = do_packet;
00209 
00210     if (PipeInit() == INVALID_HANDLE_VALUE)
00211     {
00212         DbgPrint("DHCPCSVC: PipeInit() failed!\n");
00213         AdapterStop();
00214         ApiFree();
00215         UpdateServiceStatus(SERVICE_STOPPED);
00216     }
00217 
00218     DH_DbgPrint(MID_TRACE,("DHCP Service Started\n"));
00219 
00220     UpdateServiceStatus(SERVICE_RUNNING);
00221 
00222     DH_DbgPrint(MID_TRACE,("Going into dispatch()\n"));
00223 
00224     DbgPrint("DHCPCSVC: DHCP service is starting up\n");
00225 
00226     dispatch();
00227 
00228     DbgPrint("DHCPCSVC: DHCP service is shutting down\n");
00229 
00230     //AdapterStop();
00231     //ApiFree();
00232     /* FIXME: Close pipe and kill pipe thread */
00233 
00234     UpdateServiceStatus(SERVICE_STOPPED);
00235 }
00236 
00237 /*
00238  * Individual States:
00239  *
00240  * Each routine is called from the dhclient_state_machine() in one of
00241  * these conditions:
00242  * -> entering INIT state
00243  * -> recvpacket_flag == 0: timeout in this state
00244  * -> otherwise: received a packet in this state
00245  *
00246  * Return conditions as handled by dhclient_state_machine():
00247  * Returns 1, sendpacket_flag = 1: send packet, reset timer.
00248  * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
00249  * Returns 0: finish the nap which was interrupted for no good reason.
00250  *
00251  * Several per-interface variables are used to keep track of the process:
00252  *   active_lease: the lease that is being used on the interface
00253  *                 (null pointer if not configured yet).
00254  *   offered_leases: leases corresponding to DHCPOFFER messages that have
00255  *                   been sent to us by DHCP servers.
00256  *   acked_leases: leases corresponding to DHCPACK messages that have been
00257  *                 sent to us by DHCP servers.
00258  *   sendpacket: DHCP packet we're trying to send.
00259  *   destination: IP address to send sendpacket to
00260  * In addition, there are several relevant per-lease variables.
00261  *   T1_expiry, T2_expiry, lease_expiry: lease milestones
00262  * In the active lease, these control the process of renewing the lease;
00263  * In leases on the acked_leases list, this simply determines when we
00264  * can no longer legitimately use the lease.
00265  */
00266 
00267 void
00268 state_reboot(void *ipp)
00269 {
00270     struct interface_info *ip = ipp;
00271     ULONG foo = (ULONG) GetTickCount();
00272 
00273     /* If we don't remember an active lease, go straight to INIT. */
00274     if (!ip->client->active || ip->client->active->is_bootp) {
00275         state_init(ip);
00276         return;
00277     }
00278 
00279     /* We are in the rebooting state. */
00280     ip->client->state = S_REBOOTING;
00281 
00282     /* make_request doesn't initialize xid because it normally comes
00283        from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
00284        so pick an xid now. */
00285     ip->client->xid = RtlRandom(&foo);
00286 
00287     /* Make a DHCPREQUEST packet, and set appropriate per-interface
00288        flags. */
00289     make_request(ip, ip->client->active);
00290     ip->client->destination = iaddr_broadcast;
00291     time(&ip->client->first_sending);
00292     ip->client->interval = ip->client->config->initial_interval;
00293 
00294     /* Zap the medium list... */
00295     ip->client->medium = NULL;
00296 
00297     /* Send out the first DHCPREQUEST packet. */
00298     send_request(ip);
00299 }
00300 
00301 /*
00302  * Called when a lease has completely expired and we've
00303  * been unable to renew it.
00304  */
00305 void
00306 state_init(void *ipp)
00307 {
00308     struct interface_info *ip = ipp;
00309 
00310     ASSERT_STATE(state, S_INIT);
00311 
00312     /* Make a DHCPDISCOVER packet, and set appropriate per-interface
00313        flags. */
00314     make_discover(ip, ip->client->active);
00315     ip->client->xid = ip->client->packet.xid;
00316     ip->client->destination = iaddr_broadcast;
00317     ip->client->state = S_SELECTING;
00318     time(&ip->client->first_sending);
00319     ip->client->interval = ip->client->config->initial_interval;
00320 
00321     /* Add an immediate timeout to cause the first DHCPDISCOVER packet
00322        to go out. */
00323     send_discover(ip);
00324 }
00325 
00326 /*
00327  * state_selecting is called when one or more DHCPOFFER packets
00328  * have been received and a configurable period of time has passed.
00329  */
00330 void
00331 state_selecting(void *ipp)
00332 {
00333     struct interface_info *ip = ipp;
00334     struct client_lease *lp, *next, *picked;
00335         time_t cur_time;
00336 
00337     ASSERT_STATE(state, S_SELECTING);
00338 
00339         time(&cur_time);
00340 
00341     /* Cancel state_selecting and send_discover timeouts, since either
00342        one could have got us here. */
00343     cancel_timeout(state_selecting, ip);
00344     cancel_timeout(send_discover, ip);
00345 
00346     /* We have received one or more DHCPOFFER packets.   Currently,
00347        the only criterion by which we judge leases is whether or
00348        not we get a response when we arp for them. */
00349     picked = NULL;
00350     for (lp = ip->client->offered_leases; lp; lp = next) {
00351         next = lp->next;
00352 
00353         /* Check to see if we got an ARPREPLY for the address
00354            in this particular lease. */
00355         if (!picked) {
00356                     if( !check_arp(ip,lp) ) goto freeit;
00357                     picked = lp;
00358                     picked->next = NULL;
00359         } else {
00360 freeit:
00361             free_client_lease(lp);
00362         }
00363     }
00364     ip->client->offered_leases = NULL;
00365 
00366     /* If we just tossed all the leases we were offered, go back
00367        to square one. */
00368     if (!picked) {
00369         ip->client->state = S_INIT;
00370         state_init(ip);
00371         return;
00372     }
00373 
00374     /* If it was a BOOTREPLY, we can just take the address right now. */
00375     if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
00376         ip->client->new = picked;
00377 
00378         /* Make up some lease expiry times
00379            XXX these should be configurable. */
00380         ip->client->new->expiry = cur_time + 12000;
00381         ip->client->new->renewal += cur_time + 8000;
00382         ip->client->new->rebind += cur_time + 10000;
00383 
00384         ip->client->state = S_REQUESTING;
00385 
00386         /* Bind to the address we received. */
00387         bind_lease(ip);
00388         return;
00389     }
00390 
00391     /* Go to the REQUESTING state. */
00392     ip->client->destination = iaddr_broadcast;
00393     ip->client->state = S_REQUESTING;
00394     ip->client->first_sending = cur_time;
00395     ip->client->interval = ip->client->config->initial_interval;
00396 
00397     /* Make a DHCPREQUEST packet from the lease we picked. */
00398     make_request(ip, picked);
00399     ip->client->xid = ip->client->packet.xid;
00400 
00401     /* Toss the lease we picked - we'll get it back in a DHCPACK. */
00402     free_client_lease(picked);
00403 
00404     /* Add an immediate timeout to send the first DHCPREQUEST packet. */
00405     send_request(ip);
00406 }
00407 
00408 /* state_requesting is called when we receive a DHCPACK message after
00409    having sent out one or more DHCPREQUEST packets. */
00410 
00411 void
00412 dhcpack(struct packet *packet)
00413 {
00414     struct interface_info *ip = packet->interface;
00415     struct client_lease *lease;
00416         time_t cur_time;
00417 
00418         time(&cur_time);
00419 
00420     /* If we're not receptive to an offer right now, or if the offer
00421        has an unrecognizable transaction id, then just drop it. */
00422     if (packet->interface->client->xid != packet->raw->xid ||
00423         (packet->interface->hw_address.hlen != packet->raw->hlen) ||
00424         (memcmp(packet->interface->hw_address.haddr,
00425         packet->raw->chaddr, packet->raw->hlen)))
00426         return;
00427 
00428     if (ip->client->state != S_REBOOTING &&
00429         ip->client->state != S_REQUESTING &&
00430         ip->client->state != S_RENEWING &&
00431         ip->client->state != S_REBINDING)
00432         return;
00433 
00434     note("DHCPACK from %s", piaddr(packet->client_addr));
00435 
00436     lease = packet_to_lease(packet);
00437     if (!lease) {
00438         note("packet_to_lease failed.");
00439         return;
00440     }
00441 
00442     ip->client->new = lease;
00443 
00444     /* Stop resending DHCPREQUEST. */
00445     cancel_timeout(send_request, ip);
00446 
00447     /* Figure out the lease time. */
00448     if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data)
00449         ip->client->new->expiry = getULong(
00450             ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
00451     else
00452         ip->client->new->expiry = DHCP_DEFAULT_LEASE_TIME;
00453     /* A number that looks negative here is really just very large,
00454        because the lease expiry offset is unsigned. */
00455     if (ip->client->new->expiry < 0)
00456         ip->client->new->expiry = TIME_MAX;
00457     /* XXX should be fixed by resetting the client state */
00458     if (ip->client->new->expiry < 60)
00459         ip->client->new->expiry = 60;
00460 
00461     /* Take the server-provided renewal time if there is one;
00462        otherwise figure it out according to the spec. */
00463     if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len)
00464         ip->client->new->renewal = getULong(
00465             ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data);
00466     else
00467         ip->client->new->renewal = ip->client->new->expiry / 2;
00468 
00469     /* Same deal with the rebind time. */
00470     if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len)
00471         ip->client->new->rebind = getULong(
00472             ip->client->new->options[DHO_DHCP_REBINDING_TIME].data);
00473     else
00474         ip->client->new->rebind = ip->client->new->renewal +
00475             ip->client->new->renewal / 2 + ip->client->new->renewal / 4;
00476 
00477 #ifdef __REACTOS__
00478     ip->client->new->obtained = cur_time;
00479 #endif
00480     ip->client->new->expiry += cur_time;
00481     /* Lease lengths can never be negative. */
00482     if (ip->client->new->expiry < cur_time)
00483         ip->client->new->expiry = TIME_MAX;
00484     ip->client->new->renewal += cur_time;
00485     if (ip->client->new->renewal < cur_time)
00486         ip->client->new->renewal = TIME_MAX;
00487     ip->client->new->rebind += cur_time;
00488     if (ip->client->new->rebind < cur_time)
00489         ip->client->new->rebind = TIME_MAX;
00490 
00491     bind_lease(ip);
00492 }
00493 
00494 void set_name_servers( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) {
00495     CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
00496     HKEY RegKey;
00497 
00498     strcat(Buffer, Adapter->DhclientInfo.name);
00499     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &RegKey ) != ERROR_SUCCESS)
00500         return;
00501 
00502 
00503     if( new_lease->options[DHO_DOMAIN_NAME_SERVERS].len ) {
00504 
00505         struct iaddr nameserver;
00506         char *nsbuf;
00507         int i, addrs =
00508             new_lease->options[DHO_DOMAIN_NAME_SERVERS].len / sizeof(ULONG);
00509 
00510         nsbuf = malloc( addrs * sizeof(IP_ADDRESS_STRING) );
00511 
00512         if( nsbuf) {
00513             nsbuf[0] = 0;
00514             for( i = 0; i < addrs; i++ ) {
00515                 nameserver.len = sizeof(ULONG);
00516                 memcpy( nameserver.iabuf,
00517                         new_lease->options[DHO_DOMAIN_NAME_SERVERS].data +
00518                         (i * sizeof(ULONG)), sizeof(ULONG) );
00519                 strcat( nsbuf, piaddr(nameserver) );
00520                 if( i != addrs-1 ) strcat( nsbuf, "," );
00521             }
00522 
00523             DH_DbgPrint(MID_TRACE,("Setting DhcpNameserver: %s\n", nsbuf));
00524 
00525             RegSetValueExA( RegKey, "DhcpNameServer", 0, REG_SZ,
00526                            (LPBYTE)nsbuf, strlen(nsbuf) + 1 );
00527             free( nsbuf );
00528         }
00529 
00530     } else {
00531             RegDeleteValueW( RegKey, L"DhcpNameServer" );
00532     }
00533 
00534     RegCloseKey( RegKey );
00535 
00536 }
00537 
00538 void setup_adapter( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) {
00539     CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
00540     struct iaddr netmask;
00541     HKEY hkey;
00542     int i;
00543     DWORD dwEnableDHCP;
00544 
00545     strcat(Buffer, Adapter->DhclientInfo.name);
00546     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &hkey) != ERROR_SUCCESS)
00547         hkey = NULL;
00548 
00549 
00550     if( Adapter->NteContext )
00551     {
00552         DeleteIPAddress( Adapter->NteContext );
00553         Adapter->NteContext = 0;
00554     }
00555 
00556     /* Set up our default router if we got one from the DHCP server */
00557     if( new_lease->options[DHO_SUBNET_MASK].len ) {
00558         NTSTATUS Status;
00559 
00560         memcpy( netmask.iabuf,
00561                 new_lease->options[DHO_SUBNET_MASK].data,
00562                 new_lease->options[DHO_SUBNET_MASK].len );
00563         Status = AddIPAddress
00564             ( *((ULONG*)new_lease->address.iabuf),
00565               *((ULONG*)netmask.iabuf),
00566               Adapter->IfMib.dwIndex,
00567               &Adapter->NteContext,
00568               &Adapter->NteInstance );
00569         if (hkey) {
00570             RegSetValueExA(hkey, "DhcpIPAddress", 0, REG_SZ, (LPBYTE)piaddr(new_lease->address), strlen(piaddr(new_lease->address))+1);
00571             Buffer[0] = '\0';
00572             for(i = 0; i < new_lease->options[DHO_SUBNET_MASK].len; i++)
00573             {
00574                 sprintf(&Buffer[strlen(Buffer)], "%u", new_lease->options[DHO_SUBNET_MASK].data[i]);
00575                 if (i + 1 < new_lease->options[DHO_SUBNET_MASK].len)
00576                     strcat(Buffer, ".");
00577             }
00578             RegSetValueExA(hkey, "DhcpSubnetMask", 0, REG_SZ, (LPBYTE)Buffer, strlen(Buffer)+1);
00579             dwEnableDHCP = 1;
00580             RegSetValueExA(hkey, "EnableDHCP", 0, REG_DWORD, (LPBYTE)&dwEnableDHCP, sizeof(DWORD));
00581         }
00582 
00583         if( !NT_SUCCESS(Status) )
00584             warning("AddIPAddress: %lx\n", Status);
00585     }
00586 
00587     if( new_lease->options[DHO_ROUTERS].len ) {
00588         NTSTATUS Status;
00589 
00590         Adapter->RouterMib.dwForwardDest = 0; /* Default route */
00591         Adapter->RouterMib.dwForwardMask = 0;
00592         Adapter->RouterMib.dwForwardMetric1 = 1;
00593         Adapter->RouterMib.dwForwardIfIndex = Adapter->IfMib.dwIndex;
00594 
00595         if( Adapter->RouterMib.dwForwardNextHop ) {
00596             /* If we set a default route before, delete it before continuing */
00597             DeleteIpForwardEntry( &Adapter->RouterMib );
00598         }
00599 
00600         Adapter->RouterMib.dwForwardNextHop =
00601             *((ULONG*)new_lease->options[DHO_ROUTERS].data);
00602 
00603         Status = CreateIpForwardEntry( &Adapter->RouterMib );
00604 
00605         if( !NT_SUCCESS(Status) )
00606             warning("CreateIpForwardEntry: %lx\n", Status);
00607 
00608         if (hkey) {
00609             Buffer[0] = '\0';
00610             for(i = 0; i < new_lease->options[DHO_ROUTERS].len; i++)
00611             {
00612                 sprintf(&Buffer[strlen(Buffer)], "%u", new_lease->options[DHO_ROUTERS].data[i]);
00613                 if (i + 1 < new_lease->options[DHO_ROUTERS].len)
00614                     strcat(Buffer, ".");
00615             }
00616             RegSetValueExA(hkey, "DhcpDefaultGateway", 0, REG_SZ, (LPBYTE)Buffer, strlen(Buffer)+1);
00617         }
00618     }
00619 
00620     if (hkey)
00621         RegCloseKey(hkey);
00622 }
00623 
00624 
00625 void
00626 bind_lease(struct interface_info *ip)
00627 {
00628     PDHCP_ADAPTER Adapter;
00629     struct client_lease *new_lease = ip->client->new;
00630     time_t cur_time;
00631 
00632     time(&cur_time);
00633 
00634     /* Remember the medium. */
00635     ip->client->new->medium = ip->client->medium;
00636     ip->client->active = ip->client->new;
00637     ip->client->new = NULL;
00638 
00639     /* Set up a timeout to start the renewal process. */
00640     /* Timeout of zero means no timeout (some implementations seem to use
00641      * one day).
00642      */
00643     if( ip->client->active->renewal - cur_time )
00644         add_timeout(ip->client->active->renewal, state_bound, ip);
00645 
00646     note("bound to %s -- renewal in %ld seconds.",
00647          piaddr(ip->client->active->address),
00648          (long int)(ip->client->active->renewal - cur_time));
00649 
00650     ip->client->state = S_BOUND;
00651 
00652     Adapter = AdapterFindInfo( ip );
00653 
00654     if( Adapter )  setup_adapter( Adapter, new_lease );
00655     else {
00656         warning("Could not find adapter for info %p\n", ip);
00657         return;
00658     }
00659     set_name_servers( Adapter, new_lease );
00660 }
00661 
00662 /*
00663  * state_bound is called when we've successfully bound to a particular
00664  * lease, but the renewal time on that lease has expired.   We are
00665  * expected to unicast a DHCPREQUEST to the server that gave us our
00666  * original lease.
00667  */
00668 void
00669 state_bound(void *ipp)
00670 {
00671     struct interface_info *ip = ipp;
00672 
00673     ASSERT_STATE(state, S_BOUND);
00674 
00675     /* T1 has expired. */
00676     make_request(ip, ip->client->active);
00677     ip->client->xid = ip->client->packet.xid;
00678 
00679     if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
00680         memcpy(ip->client->destination.iabuf, ip->client->active->
00681             options[DHO_DHCP_SERVER_IDENTIFIER].data, 4);
00682         ip->client->destination.len = 4;
00683     } else
00684         ip->client->destination = iaddr_broadcast;
00685 
00686     time(&ip->client->first_sending);
00687     ip->client->interval = ip->client->config->initial_interval;
00688     ip->client->state = S_RENEWING;
00689 
00690     /* Send the first packet immediately. */
00691     send_request(ip);
00692 }
00693 
00694 void
00695 bootp(struct packet *packet)
00696 {
00697     struct iaddrlist *ap;
00698 
00699     if (packet->raw->op != BOOTREPLY)
00700         return;
00701 
00702     /* If there's a reject list, make sure this packet's sender isn't
00703        on it. */
00704     for (ap = packet->interface->client->config->reject_list;
00705         ap; ap = ap->next) {
00706         if (addr_eq(packet->client_addr, ap->addr)) {
00707             note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
00708             return;
00709         }
00710     }
00711     dhcpoffer(packet);
00712 }
00713 
00714 void
00715 dhcp(struct packet *packet)
00716 {
00717     struct iaddrlist *ap;
00718     void (*handler)(struct packet *);
00719     char *type;
00720 
00721     switch (packet->packet_type) {
00722     case DHCPOFFER:
00723         handler = dhcpoffer;
00724         type = "DHCPOFFER";
00725         break;
00726     case DHCPNAK:
00727         handler = dhcpnak;
00728         type = "DHCPNACK";
00729         break;
00730     case DHCPACK:
00731         handler = dhcpack;
00732         type = "DHCPACK";
00733         break;
00734     default:
00735         return;
00736     }
00737 
00738     /* If there's a reject list, make sure this packet's sender isn't
00739        on it. */
00740     for (ap = packet->interface->client->config->reject_list;
00741         ap; ap = ap->next) {
00742         if (addr_eq(packet->client_addr, ap->addr)) {
00743             note("%s from %s rejected.", type, piaddr(ap->addr));
00744             return;
00745         }
00746     }
00747     (*handler)(packet);
00748 }
00749 
00750 void
00751 dhcpoffer(struct packet *packet)
00752 {
00753     struct interface_info *ip = packet->interface;
00754     struct client_lease *lease, *lp;
00755     int i;
00756     int arp_timeout_needed = 0, stop_selecting;
00757     char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
00758         "DHCPOFFER" : "BOOTREPLY";
00759         time_t cur_time;
00760 
00761         time(&cur_time);
00762 
00763     /* If we're not receptive to an offer right now, or if the offer
00764        has an unrecognizable transaction id, then just drop it. */
00765     if (ip->client->state != S_SELECTING ||
00766             packet->interface->client->xid != packet->raw->xid ||
00767             (packet->interface->hw_address.hlen != packet->raw->hlen) ||
00768         (memcmp(packet->interface->hw_address.haddr,
00769         packet->raw->chaddr, packet->raw->hlen)))
00770         return;
00771 
00772     note("%s from %s", name, piaddr(packet->client_addr));
00773 
00774 
00775     /* If this lease doesn't supply the minimum required parameters,
00776        blow it off. */
00777     for (i = 0; ip->client->config->required_options[i]; i++) {
00778         if (!packet->options[ip->client->config->
00779             required_options[i]].len) {
00780             note("%s isn't satisfactory.", name);
00781             return;
00782         }
00783     }
00784 
00785     /* If we've already seen this lease, don't record it again. */
00786     for (lease = ip->client->offered_leases;
00787         lease; lease = lease->next) {
00788         if (lease->address.len == sizeof(packet->raw->yiaddr) &&
00789             !memcmp(lease->address.iabuf,
00790             &packet->raw->yiaddr, lease->address.len)) {
00791             debug("%s already seen.", name);
00792             return;
00793         }
00794     }
00795 
00796     lease = packet_to_lease(packet);
00797     if (!lease) {
00798         note("packet_to_lease failed.");
00799         return;
00800     }
00801 
00802     /* If this lease was acquired through a BOOTREPLY, record that
00803        fact. */
00804     if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
00805         lease->is_bootp = 1;
00806 
00807     /* Record the medium under which this lease was offered. */
00808     lease->medium = ip->client->medium;
00809 
00810     /* Send out an ARP Request for the offered IP address. */
00811         if( !check_arp( ip, lease ) ) {
00812             note("Arp check failed\n");
00813             return;
00814         }
00815 
00816     /* Figure out when we're supposed to stop selecting. */
00817     stop_selecting =
00818         ip->client->first_sending + ip->client->config->select_interval;
00819 
00820     /* If this is the lease we asked for, put it at the head of the
00821        list, and don't mess with the arp request timeout. */
00822     if (lease->address.len == ip->client->requested_address.len &&
00823         !memcmp(lease->address.iabuf,
00824         ip->client->requested_address.iabuf,
00825         ip->client->requested_address.len)) {
00826         lease->next = ip->client->offered_leases;
00827         ip->client->offered_leases = lease;
00828     } else {
00829         /* If we already have an offer, and arping for this
00830            offer would take us past the selection timeout,
00831            then don't extend the timeout - just hope for the
00832            best. */
00833         if (ip->client->offered_leases &&
00834             (cur_time + arp_timeout_needed) > stop_selecting)
00835             arp_timeout_needed = 0;
00836 
00837         /* Put the lease at the end of the list. */
00838         lease->next = NULL;
00839         if (!ip->client->offered_leases)
00840             ip->client->offered_leases = lease;
00841         else {
00842             for (lp = ip->client->offered_leases; lp->next;
00843                 lp = lp->next)
00844                 ;   /* nothing */
00845             lp->next = lease;
00846         }
00847     }
00848 
00849     /* If we're supposed to stop selecting before we've had time
00850        to wait for the ARPREPLY, add some delay to wait for
00851        the ARPREPLY. */
00852     if (stop_selecting - cur_time < arp_timeout_needed)
00853         stop_selecting = cur_time + arp_timeout_needed;
00854 
00855     /* If the selecting interval has expired, go immediately to
00856        state_selecting().  Otherwise, time out into
00857        state_selecting at the select interval. */
00858     if (stop_selecting <= 0)
00859         state_selecting(ip);
00860     else {
00861         add_timeout(stop_selecting, state_selecting, ip);
00862         cancel_timeout(send_discover, ip);
00863     }
00864 }
00865 
00866 /* Allocate a client_lease structure and initialize it from the parameters
00867    in the specified packet. */
00868 
00869 struct client_lease *
00870 packet_to_lease(struct packet *packet)
00871 {
00872     struct client_lease *lease;
00873     int i;
00874 
00875     lease = malloc(sizeof(struct client_lease));
00876 
00877     if (!lease) {
00878         warning("dhcpoffer: no memory to record lease.");
00879         return (NULL);
00880     }
00881 
00882     memset(lease, 0, sizeof(*lease));
00883 
00884     /* Copy the lease options. */
00885     for (i = 0; i < 256; i++) {
00886         if (packet->options[i].len) {
00887             lease->options[i].data =
00888                 malloc(packet->options[i].len + 1);
00889             if (!lease->options[i].data) {
00890                 warning("dhcpoffer: no memory for option %d", i);
00891                 free_client_lease(lease);
00892                 return (NULL);
00893             } else {
00894                 memcpy(lease->options[i].data,
00895                     packet->options[i].data,
00896                     packet->options[i].len);
00897                 lease->options[i].len =
00898                     packet->options[i].len;
00899                 lease->options[i].data[lease->options[i].len] =
00900                     0;
00901             }
00902             if (!check_option(lease,i)) {
00903                 /* ignore a bogus lease offer */
00904                 warning("Invalid lease option - ignoring offer");
00905                 free_client_lease(lease);
00906                 return (NULL);
00907             }
00908         }
00909     }
00910 
00911     lease->address.len = sizeof(packet->raw->yiaddr);
00912     memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
00913 #ifdef __REACTOS__
00914     lease->serveraddress.len = sizeof(packet->raw->siaddr);
00915     memcpy(lease->serveraddress.iabuf, &packet->raw->siaddr, lease->address.len);
00916 #endif
00917 
00918     /* If the server name was filled out, copy it. */
00919     if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
00920         !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
00921         packet->raw->sname[0]) {
00922         lease->server_name = malloc(DHCP_SNAME_LEN + 1);
00923         if (!lease->server_name) {
00924             warning("dhcpoffer: no memory for server name.");
00925             free_client_lease(lease);
00926             return (NULL);
00927         }
00928         memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
00929         lease->server_name[DHCP_SNAME_LEN]='\0';
00930         if (!res_hnok(lease->server_name) ) {
00931             warning("Bogus server name %s",  lease->server_name );
00932             free_client_lease(lease);
00933             return (NULL);
00934         }
00935 
00936     }
00937 
00938     /* Ditto for the filename. */
00939     if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
00940         !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
00941         packet->raw->file[0]) {
00942         /* Don't count on the NUL terminator. */
00943         lease->filename = malloc(DHCP_FILE_LEN + 1);
00944         if (!lease->filename) {
00945             warning("dhcpoffer: no memory for filename.");
00946             free_client_lease(lease);
00947             return (NULL);
00948         }
00949         memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
00950         lease->filename[DHCP_FILE_LEN]='\0';
00951     }
00952     return lease;
00953 }
00954 
00955 void
00956 dhcpnak(struct packet *packet)
00957 {
00958     struct interface_info *ip = packet->interface;
00959 
00960     /* If we're not receptive to an offer right now, or if the offer
00961        has an unrecognizable transaction id, then just drop it. */
00962     if (packet->interface->client->xid != packet->raw->xid ||
00963         (packet->interface->hw_address.hlen != packet->raw->hlen) ||
00964         (memcmp(packet->interface->hw_address.haddr,
00965         packet->raw->chaddr, packet->raw->hlen)))
00966         return;
00967 
00968     if (ip->client->state != S_REBOOTING &&
00969         ip->client->state != S_REQUESTING &&
00970         ip->client->state != S_RENEWING &&
00971         ip->client->state != S_REBINDING)
00972         return;
00973 
00974     note("DHCPNAK from %s", piaddr(packet->client_addr));
00975 
00976     if (!ip->client->active) {
00977         note("DHCPNAK with no active lease.\n");
00978         return;
00979     }
00980 
00981     free_client_lease(ip->client->active);
00982     ip->client->active = NULL;
00983 
00984     /* Stop sending DHCPREQUEST packets... */
00985     cancel_timeout(send_request, ip);
00986 
00987     ip->client->state = S_INIT;
00988     state_init(ip);
00989 }
00990 
00991 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
00992    one after the right interval has expired.  If we don't get an offer by
00993    the time we reach the panic interval, call the panic function. */
00994 
00995 void
00996 send_discover(void *ipp)
00997 {
00998     struct interface_info *ip = ipp;
00999     int interval, increase = 1;
01000         time_t cur_time;
01001 
01002         DH_DbgPrint(MID_TRACE,("Doing discover on interface %p\n",ip));
01003 
01004         time(&cur_time);
01005 
01006     /* Figure out how long it's been since we started transmitting. */
01007     interval = cur_time - ip->client->first_sending;
01008 
01009     /* If we're past the panic timeout, call the script and tell it
01010        we haven't found anything for this interface yet. */
01011     if (interval > ip->client->config->timeout) {
01012         state_panic(ip);
01013         ip->client->first_sending = cur_time;
01014     }
01015 
01016     /* If we're selecting media, try the whole list before doing
01017        the exponential backoff, but if we've already received an
01018        offer, stop looping, because we obviously have it right. */
01019     if (!ip->client->offered_leases &&
01020         ip->client->config->media) {
01021         int fail = 0;
01022 
01023         if (ip->client->medium) {
01024             ip->client->medium = ip->client->medium->next;
01025             increase = 0;
01026         }
01027         if (!ip->client->medium) {
01028             if (fail)
01029                 error("No valid media types for %s!", ip->name);
01030             ip->client->medium = ip->client->config->media;
01031             increase = 1;
01032         }
01033 
01034         note("Trying medium \"%s\" %d", ip->client->medium->string,
01035             increase);
01036                 /* XXX Support other media types eventually */
01037     }
01038 
01039     /*
01040      * If we're supposed to increase the interval, do so.  If it's
01041      * currently zero (i.e., we haven't sent any packets yet), set
01042      * it to one; otherwise, add to it a random number between zero
01043      * and two times itself.  On average, this means that it will
01044      * double with every transmission.
01045      */
01046     if (increase) {
01047         if (!ip->client->interval)
01048             ip->client->interval =
01049                 ip->client->config->initial_interval;
01050         else {
01051             ip->client->interval += (rand() >> 2) %
01052                 (2 * ip->client->interval);
01053         }
01054 
01055         /* Don't backoff past cutoff. */
01056         if (ip->client->interval >
01057             ip->client->config->backoff_cutoff)
01058             ip->client->interval =
01059                 ((ip->client->config->backoff_cutoff / 2)
01060                  + ((rand() >> 2) %
01061                     ip->client->config->backoff_cutoff));
01062     } else if (!ip->client->interval)
01063         ip->client->interval =
01064             ip->client->config->initial_interval;
01065 
01066     /* If the backoff would take us to the panic timeout, just use that
01067        as the interval. */
01068     if (cur_time + ip->client->interval >
01069         ip->client->first_sending + ip->client->config->timeout)
01070         ip->client->interval =
01071             (ip->client->first_sending +
01072              ip->client->config->timeout) - cur_time + 1;
01073 
01074     /* Record the number of seconds since we started sending. */
01075     if (interval < 65536)
01076         ip->client->packet.secs = htons(interval);
01077     else
01078         ip->client->packet.secs = htons(65535);
01079     ip->client->secs = ip->client->packet.secs;
01080 
01081     note("DHCPDISCOVER on %s to %s port %d interval %ld",
01082         ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
01083         ntohs(sockaddr_broadcast.sin_port), (long int)ip->client->interval);
01084 
01085     /* Send out a packet. */
01086     (void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
01087         inaddr_any, &sockaddr_broadcast, NULL);
01088 
01089         DH_DbgPrint(MID_TRACE,("discover timeout: now %x -> then %x\n",
01090                                cur_time, cur_time + ip->client->interval));
01091 
01092     add_timeout(cur_time + ip->client->interval, send_discover, ip);
01093 }
01094 
01095 /*
01096  * state_panic gets called if we haven't received any offers in a preset
01097  * amount of time.   When this happens, we try to use existing leases
01098  * that haven't yet expired, and failing that, we call the client script
01099  * and hope it can do something.
01100  */
01101 void
01102 state_panic(void *ipp)
01103 {
01104     struct interface_info *ip = ipp;
01105         PDHCP_ADAPTER Adapter = AdapterFindInfo(ip);
01106 
01107     note("No DHCPOFFERS received.");
01108 
01109         if (!Adapter->NteContext)
01110         {
01111             /* Generate an automatic private address */
01112             DbgPrint("DHCPCSVC: Failed to receive a response from a DHCP server. An automatic private address will be assigned.\n");
01113 
01114             /* FIXME: The address generation code sucks */
01115             AddIPAddress(htonl(0xA9FE0000 | (rand() % 0xFFFF)), //169.254.X.X
01116                          htonl(0xFFFF0000), //255.255.0.0
01117                          Adapter->IfMib.dwIndex,
01118                          &Adapter->NteContext,
01119                          &Adapter->NteInstance);
01120         }
01121 }
01122 
01123 void
01124 send_request(void *ipp)
01125 {
01126     struct interface_info *ip = ipp;
01127     struct sockaddr_in destination;
01128     struct in_addr from;
01129     int interval;
01130         time_t cur_time;
01131 
01132         time(&cur_time); 
01133 
01134     /* Figure out how long it's been since we started transmitting. */
01135     interval = cur_time - ip->client->first_sending;
01136 
01137     /* If we're in the INIT-REBOOT or REQUESTING state and we're
01138        past the reboot timeout, go to INIT and see if we can
01139        DISCOVER an address... */
01140     /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
01141        means either that we're on a network with no DHCP server,
01142        or that our server is down.  In the latter case, assuming
01143        that there is a backup DHCP server, DHCPDISCOVER will get
01144        us a new address, but we could also have successfully
01145        reused our old address.  In the former case, we're hosed
01146        anyway.  This is not a win-prone situation. */
01147     if ((ip->client->state == S_REBOOTING ||
01148         ip->client->state == S_REQUESTING) &&
01149         interval > ip->client->config->reboot_timeout) {
01150         ip->client->state = S_INIT;
01151         cancel_timeout(send_request, ip);
01152         state_init(ip);
01153         return;
01154     }
01155 
01156     /* If we're in the reboot state, make sure the media is set up
01157        correctly. */
01158     if (ip->client->state == S_REBOOTING &&
01159         !ip->client->medium &&
01160         ip->client->active->medium ) {
01161         /* If the medium we chose won't fly, go to INIT state. */
01162                 /* XXX Nothing for now */
01163 
01164         /* Record the medium. */
01165         ip->client->medium = ip->client->active->medium;
01166     }
01167 
01168     /* If the lease has expired, relinquish the address and go back
01169        to the INIT state. */
01170     if (ip->client->state != S_REQUESTING &&
01171         cur_time > ip->client->active->expiry) {
01172             PDHCP_ADAPTER Adapter = AdapterFindInfo( ip );
01173             /* Run the client script with the new parameters. */
01174             /* No script actions necessary in the expiry case */
01175             /* Now do a preinit on the interface so that we can
01176                discover a new address. */
01177 
01178             if( Adapter )
01179             {
01180                 DeleteIPAddress( Adapter->NteContext );
01181                 Adapter->NteContext = 0;
01182             }
01183 
01184             ip->client->state = S_INIT;
01185             state_init(ip);
01186             return;
01187     }
01188 
01189     /* Do the exponential backoff... */
01190     if (!ip->client->interval)
01191         ip->client->interval = ip->client->config->initial_interval;
01192     else
01193         ip->client->interval += ((rand() >> 2) %
01194             (2 * ip->client->interval));
01195 
01196     /* Don't backoff past cutoff. */
01197     if (ip->client->interval >
01198         ip->client->config->backoff_cutoff)
01199         ip->client->interval =
01200             ((ip->client->config->backoff_cutoff / 2) +
01201             ((rand() >> 2) % ip->client->interval));
01202 
01203     /* If the backoff would take us to the expiry time, just set the
01204        timeout to the expiry time. */
01205     if (ip->client->state != S_REQUESTING &&
01206         cur_time + ip->client->interval >
01207         ip->client->active->expiry)
01208         ip->client->interval =
01209             ip->client->active->expiry - cur_time + 1;
01210 
01211     /* If the lease T2 time has elapsed, or if we're not yet bound,
01212        broadcast the DHCPREQUEST rather than unicasting. */
01213     memset(&destination, 0, sizeof(destination));
01214     if (ip->client->state == S_REQUESTING ||
01215         ip->client->state == S_REBOOTING ||
01216         cur_time > ip->client->active->rebind)
01217         destination.sin_addr.s_addr = INADDR_BROADCAST;
01218     else
01219         memcpy(&destination.sin_addr.s_addr,
01220             ip->client->destination.iabuf,
01221             sizeof(destination.sin_addr.s_addr));
01222     destination.sin_port = htons(REMOTE_PORT);
01223     destination.sin_family = AF_INET;
01224 //  destination.sin_len = sizeof(destination);
01225 
01226     if (ip->client->state != S_REQUESTING)
01227         memcpy(&from, ip->client->active->address.iabuf,
01228             sizeof(from));
01229     else
01230         from.s_addr = INADDR_ANY;
01231 
01232     /* Record the number of seconds since we started sending. */
01233     if (ip->client->state == S_REQUESTING)
01234         ip->client->packet.secs = ip->client->secs;
01235     else {
01236         if (interval < 65536)
01237             ip->client->packet.secs = htons(interval);
01238         else
01239             ip->client->packet.secs = htons(65535);
01240     }
01241 
01242     note("DHCPREQUEST on %s to %s port %d", ip->name,
01243         inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
01244 
01245     /* Send out a packet. */
01246     (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
01247         from, &destination, NULL);
01248 
01249     add_timeout(cur_time + ip->client->interval, send_request, ip);
01250 }
01251 
01252 void
01253 send_decline(void *ipp)
01254 {
01255     struct interface_info *ip = ipp;
01256 
01257     note("DHCPDECLINE on %s to %s port %d", ip->name,
01258         inet_ntoa(sockaddr_broadcast.sin_addr),
01259         ntohs(sockaddr_broadcast.sin_port));
01260 
01261     /* Send out a packet. */
01262     (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
01263         inaddr_any, &sockaddr_broadcast, NULL);
01264 }
01265 
01266 void
01267 make_discover(struct interface_info *ip, struct client_lease *lease)
01268 {
01269     unsigned char discover = DHCPDISCOVER;
01270     struct tree_cache *options[256];
01271     struct tree_cache option_elements[256];
01272     int i;
01273     ULONG foo = (ULONG) GetTickCount();
01274 
01275     memset(option_elements, 0, sizeof(option_elements));
01276     memset(options, 0, sizeof(options));
01277     memset(&ip->client->packet, 0, sizeof(ip->client->packet));
01278 
01279     /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
01280     i = DHO_DHCP_MESSAGE_TYPE;
01281     options[i] = &option_elements[i];
01282     options[i]->value = &discover;
01283     options[i]->len = sizeof(discover);
01284     options[i]->buf_size = sizeof(discover);
01285     options[i]->timeout = 0xFFFFFFFF;
01286 
01287     /* Request the options we want */
01288     i  = DHO_DHCP_PARAMETER_REQUEST_LIST;
01289     options[i] = &option_elements[i];
01290     options[i]->value = ip->client->config->requested_options;
01291     options[i]->len = ip->client->config->requested_option_count;
01292     options[i]->buf_size =
01293         ip->client->config->requested_option_count;
01294     options[i]->timeout = 0xFFFFFFFF;
01295 
01296     /* If we had an address, try to get it again. */
01297     if (lease) {
01298         ip->client->requested_address = lease->address;
01299         i = DHO_DHCP_REQUESTED_ADDRESS;
01300         options[i] = &option_elements[i];
01301         options[i]->value = lease->address.iabuf;
01302         options[i]->len = lease->address.len;
01303         options[i]->buf_size = lease->address.len;
01304         options[i]->timeout = 0xFFFFFFFF;
01305     } else
01306         ip->client->requested_address.len = 0;
01307 
01308     /* Send any options requested in the config file. */
01309     for (i = 0; i < 256; i++)
01310         if (!options[i] &&
01311             ip->client->config->send_options[i].data) {
01312             options[i] = &option_elements[i];
01313             options[i]->value =
01314                 ip->client->config->send_options[i].data;
01315             options[i]->len =
01316                 ip->client->config->send_options[i].len;
01317             options[i]->buf_size =
01318                 ip->client->config->send_options[i].len;
01319             options[i]->timeout = 0xFFFFFFFF;
01320         }
01321 
01322     /* Set up the option buffer... */
01323     ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
01324         options, 0, 0, 0, NULL, 0);
01325     if (ip->client->packet_length < BOOTP_MIN_LEN)
01326         ip->client->packet_length = BOOTP_MIN_LEN;
01327 
01328     ip->client->packet.op = BOOTREQUEST;
01329     ip->client->packet.htype = ip->hw_address.htype;
01330     ip->client->packet.hlen = ip->hw_address.hlen;
01331     ip->client->packet.hops = 0;
01332     ip->client->packet.xid = RtlRandom(&foo);
01333     ip->client->packet.secs = 0; /* filled in by send_discover. */
01334     ip->client->packet.flags = 0;
01335 
01336     memset(&(ip->client->packet.ciaddr),
01337         0, sizeof(ip->client->packet.ciaddr));
01338     memset(&(ip->client->packet.yiaddr),
01339         0, sizeof(ip->client->packet.yiaddr));
01340     memset(&(ip->client->packet.siaddr),
01341         0, sizeof(ip->client->packet.siaddr));
01342     memset(&(ip->client->packet.giaddr),
01343         0, sizeof(ip->client->packet.giaddr));
01344     memcpy(ip->client->packet.chaddr,
01345         ip->hw_address.haddr, ip->hw_address.hlen);
01346 }
01347 
01348 
01349 void
01350 make_request(struct interface_info *ip, struct client_lease * lease)
01351 {
01352     unsigned char request = DHCPREQUEST;
01353     struct tree_cache *options[256];
01354     struct tree_cache option_elements[256];
01355     int i;
01356 
01357     memset(options, 0, sizeof(options));
01358     memset(&ip->client->packet, 0, sizeof(ip->client->packet));
01359 
01360     /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
01361     i = DHO_DHCP_MESSAGE_TYPE;
01362     options[i] = &option_elements[i];
01363     options[i]->value = &request;
01364     options[i]->len = sizeof(request);
01365     options[i]->buf_size = sizeof(request);
01366     options[i]->timeout = 0xFFFFFFFF;
01367 
01368     /* Request the options we want */
01369     i = DHO_DHCP_PARAMETER_REQUEST_LIST;
01370     options[i] = &option_elements[i];
01371     options[i]->value = ip->client->config->requested_options;
01372     options[i]->len = ip->client->config->requested_option_count;
01373     options[i]->buf_size =
01374         ip->client->config->requested_option_count;
01375     options[i]->timeout = 0xFFFFFFFF;
01376 
01377     /* If we are requesting an address that hasn't yet been assigned
01378        to us, use the DHCP Requested Address option. */
01379     if (ip->client->state == S_REQUESTING) {
01380         /* Send back the server identifier... */
01381         i = DHO_DHCP_SERVER_IDENTIFIER;
01382         options[i] = &option_elements[i];
01383         options[i]->value = lease->options[i].data;
01384         options[i]->len = lease->options[i].len;
01385         options[i]->buf_size = lease->options[i].len;
01386         options[i]->timeout = 0xFFFFFFFF;
01387     }
01388     if (ip->client->state == S_REQUESTING ||
01389         ip->client->state == S_REBOOTING) {
01390         ip->client->requested_address = lease->address;
01391         i = DHO_DHCP_REQUESTED_ADDRESS;
01392         options[i] = &option_elements[i];
01393         options[i]->value = lease->address.iabuf;
01394         options[i]->len = lease->address.len;
01395         options[i]->buf_size = lease->address.len;
01396         options[i]->timeout = 0xFFFFFFFF;
01397     } else
01398         ip->client->requested_address.len = 0;
01399 
01400     /* Send any options requested in the config file. */
01401     for (i = 0; i < 256; i++)
01402         if (!options[i] &&
01403             ip->client->config->send_options[i].data) {
01404             options[i] = &option_elements[i];
01405             options[i]->value =
01406                 ip->client->config->send_options[i].data;
01407             options[i]->len =
01408                 ip->client->config->send_options[i].len;
01409             options[i]->buf_size =
01410                 ip->client->config->send_options[i].len;
01411             options[i]->timeout = 0xFFFFFFFF;
01412         }
01413 
01414     /* Set up the option buffer... */
01415     ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
01416         options, 0, 0, 0, NULL, 0);
01417     if (ip->client->packet_length < BOOTP_MIN_LEN)
01418         ip->client->packet_length = BOOTP_MIN_LEN;
01419 
01420     ip->client->packet.op = BOOTREQUEST;
01421     ip->client->packet.htype = ip->hw_address.htype;
01422     ip->client->packet.hlen = ip->hw_address.hlen;
01423     ip->client->packet.hops = 0;
01424     ip->client->packet.xid = ip->client->xid;
01425     ip->client->packet.secs = 0; /* Filled in by send_request. */
01426 
01427     /* If we own the address we're requesting, put it in ciaddr;
01428        otherwise set ciaddr to zero. */
01429     if (ip->client->state == S_BOUND ||
01430         ip->client->state == S_RENEWING ||
01431         ip->client->state == S_REBINDING) {
01432         memcpy(&ip->client->packet.ciaddr,
01433             lease->address.iabuf, lease->address.len);
01434         ip->client->packet.flags = 0;
01435     } else {
01436         memset(&ip->client->packet.ciaddr, 0,
01437             sizeof(ip->client->packet.ciaddr));
01438         ip->client->packet.flags = 0;
01439     }
01440 
01441     memset(&ip->client->packet.yiaddr, 0,
01442         sizeof(ip->client->packet.yiaddr));
01443     memset(&ip->client->packet.siaddr, 0,
01444         sizeof(ip->client->packet.siaddr));
01445     memset(&ip->client->packet.giaddr, 0,
01446         sizeof(ip->client->packet.giaddr));
01447     memcpy(ip->client->packet.chaddr,
01448         ip->hw_address.haddr, ip->hw_address.hlen);
01449 }
01450 
01451 void
01452 make_decline(struct interface_info *ip, struct client_lease *lease)
01453 {
01454     struct tree_cache *options[256], message_type_tree;
01455     struct tree_cache requested_address_tree;
01456     struct tree_cache server_id_tree, client_id_tree;
01457     unsigned char decline = DHCPDECLINE;
01458     int i;
01459 
01460     memset(options, 0, sizeof(options));
01461     memset(&ip->client->packet, 0, sizeof(ip->client->packet));
01462 
01463     /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
01464     i = DHO_DHCP_MESSAGE_TYPE;
01465     options[i] = &message_type_tree;
01466     options[i]->value = &decline;
01467     options[i]->len = sizeof(decline);
01468     options[i]->buf_size = sizeof(decline);
01469     options[i]->timeout = 0xFFFFFFFF;
01470 
01471     /* Send back the server identifier... */
01472     i = DHO_DHCP_SERVER_IDENTIFIER;
01473     options[i] = &server_id_tree;
01474     options[i]->value = lease->options[i].data;
01475     options[i]->len = lease->options[i].len;
01476     options[i]->buf_size = lease->options[i].len;
01477     options[i]->timeout = 0xFFFFFFFF;
01478 
01479     /* Send back the address we're declining. */
01480     i = DHO_DHCP_REQUESTED_ADDRESS;
01481     options[i] = &requested_address_tree;
01482     options[i]->value = lease->address.iabuf;
01483     options[i]->len = lease->address.len;
01484     options[i]->buf_size = lease->address.len;
01485     options[i]->timeout = 0xFFFFFFFF;
01486 
01487     /* Send the uid if the user supplied one. */
01488     i = DHO_DHCP_CLIENT_IDENTIFIER;
01489     if (ip->client->config->send_options[i].len) {
01490         options[i] = &client_id_tree;
01491         options[i]->value = ip->client->config->send_options[i].data;
01492         options[i]->len = ip->client->config->send_options[i].len;
01493         options[i]->buf_size = ip->client->config->send_options[i].len;
01494         options[i]->timeout = 0xFFFFFFFF;
01495     }
01496 
01497 
01498     /* Set up the option buffer... */
01499     ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
01500         options, 0, 0, 0, NULL, 0);
01501     if (ip->client->packet_length < BOOTP_MIN_LEN)
01502         ip->client->packet_length = BOOTP_MIN_LEN;
01503 
01504     ip->client->packet.op = BOOTREQUEST;
01505     ip->client->packet.htype = ip->hw_address.htype;
01506     ip->client->packet.hlen = ip->hw_address.hlen;
01507     ip->client->packet.hops = 0;
01508     ip->client->packet.xid = ip->client->xid;
01509     ip->client->packet.secs = 0; /* Filled in by send_request. */
01510     ip->client->packet.flags = 0;
01511 
01512     /* ciaddr must always be zero. */
01513     memset(&ip->client->packet.ciaddr, 0,
01514         sizeof(ip->client->packet.ciaddr));
01515     memset(&ip->client->packet.yiaddr, 0,
01516         sizeof(ip->client->packet.yiaddr));
01517     memset(&ip->client->packet.siaddr, 0,
01518         sizeof(ip->client->packet.siaddr));
01519     memset(&ip->client->packet.giaddr, 0,
01520         sizeof(ip->client->packet.giaddr));
01521     memcpy(ip->client->packet.chaddr,
01522         ip->hw_address.haddr, ip->hw_address.hlen);
01523 }
01524 
01525 void
01526 free_client_lease(struct client_lease *lease)
01527 {
01528     int i;
01529 
01530     if (lease->server_name)
01531         free(lease->server_name);
01532     if (lease->filename)
01533         free(lease->filename);
01534     for (i = 0; i < 256; i++) {
01535         if (lease->options[i].len)
01536             free(lease->options[i].data);
01537     }
01538     free(lease);
01539 }
01540 
01541 FILE *leaseFile;
01542 
01543 void
01544 rewrite_client_leases(struct interface_info *ifi)
01545 {
01546     struct client_lease *lp;
01547 
01548     if (!leaseFile) {
01549         leaseFile = fopen(path_dhclient_db, "w");
01550         if (!leaseFile)
01551             error("can't create %s", path_dhclient_db);
01552     } else {
01553         fflush(leaseFile);
01554         rewind(leaseFile);
01555     }
01556 
01557     for (lp = ifi->client->leases; lp; lp = lp->next)
01558         write_client_lease(ifi, lp, 1);
01559     if (ifi->client->active)
01560         write_client_lease(ifi, ifi->client->active, 1);
01561 
01562     fflush(leaseFile);
01563 }
01564 
01565 void
01566 write_client_lease(struct interface_info *ip, struct client_lease *lease,
01567     int rewrite)
01568 {
01569     static int leases_written;
01570     struct tm *t;
01571     int i;
01572 
01573     if (!rewrite) {
01574         if (leases_written++ > 20) {
01575             rewrite_client_leases(ip);
01576             leases_written = 0;
01577         }
01578     }
01579 
01580     /* If the lease came from the config file, we don't need to stash
01581        a copy in the lease database. */
01582     if (lease->is_static)
01583         return;
01584 
01585     if (!leaseFile) {   /* XXX */
01586         leaseFile = fopen(path_dhclient_db, "w");
01587         if (!leaseFile) {
01588             error("can't create %s", path_dhclient_db);
01589                         return;
01590                 }
01591     }
01592 
01593     fprintf(leaseFile, "lease {\n");
01594     if (lease->is_bootp)
01595         fprintf(leaseFile, "  bootp;\n");
01596     fprintf(leaseFile, "  interface \"%s\";\n", ip->name);
01597     fprintf(leaseFile, "  fixed-address %s;\n", piaddr(lease->address));
01598     if (lease->filename)
01599         fprintf(leaseFile, "  filename \"%s\";\n", lease->filename);
01600     if (lease->server_name)
01601         fprintf(leaseFile, "  server-name \"%s\";\n",
01602             lease->server_name);
01603     if (lease->medium)
01604         fprintf(leaseFile, "  medium \"%s\";\n", lease->medium->string);
01605     for (i = 0; i < 256; i++)
01606         if (lease->options[i].len)
01607             fprintf(leaseFile, "  option %s %s;\n",
01608                 dhcp_options[i].name,
01609                 pretty_print_option(i, lease->options[i].data,
01610                 lease->options[i].len, 1, 1));
01611 
01612     t = gmtime(&lease->renewal);
01613         if (t)
01614         fprintf(leaseFile, "  renew %d %d/%d/%d %02d:%02d:%02d;\n",
01615             t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
01616             t->tm_hour, t->tm_min, t->tm_sec);
01617     t = gmtime(&lease->rebind);
01618         if (t)
01619         fprintf(leaseFile, "  rebind %d %d/%d/%d %02d:%02d:%02d;\n",
01620              t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
01621              t->tm_hour, t->tm_min, t->tm_sec);
01622     t = gmtime(&lease->expiry);
01623         if (t)
01624         fprintf(leaseFile, "  expire %d %d/%d/%d %02d:%02d:%02d;\n",
01625             t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
01626             t->tm_hour, t->tm_min, t->tm_sec);
01627     fprintf(leaseFile, "}\n");
01628     fflush(leaseFile);
01629 }
01630 
01631 void
01632 priv_script_init(struct interface_info *ip, char *reason, char *medium)
01633 {
01634     if (ip) {
01635             // XXX Do we need to do anything?
01636         }
01637 }
01638 
01639 void
01640 priv_script_write_params(struct interface_info *ip, char *prefix, struct client_lease *lease)
01641 {
01642     u_int8_t dbuf[1500];
01643     int i, len = 0;
01644 
01645 #if 0
01646     script_set_env(ip->client, prefix, "ip_address",
01647         piaddr(lease->address));
01648 #endif
01649 
01650     if (lease->options[DHO_SUBNET_MASK].len &&
01651         (lease->options[DHO_SUBNET_MASK].len <
01652         sizeof(lease->address.iabuf))) {
01653         struct iaddr netmask, subnet, broadcast;
01654 
01655         memcpy(netmask.iabuf, lease->options[DHO_SUBNET_MASK].data,
01656             lease->options[DHO_SUBNET_MASK].len);
01657         netmask.len = lease->options[DHO_SUBNET_MASK].len;
01658 
01659         subnet = subnet_number(lease->address, netmask);
01660         if (subnet.len) {
01661 #if 0
01662             script_set_env(ip->client, prefix, "network_number",
01663                 piaddr(subnet));
01664 #endif
01665             if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
01666                 broadcast = broadcast_addr(subnet, netmask);
01667                 if (broadcast.len)
01668 #if 0
01669                     script_set_env(ip->client, prefix,
01670                         "broadcast_address",
01671                         piaddr(broadcast));
01672 #else
01673                                 ;
01674 #endif
01675             }
01676         }
01677     }
01678 
01679 #if 0
01680     if (lease->filename)
01681         script_set_env(ip->client, prefix, "filename", lease->filename);
01682     if (lease->server_name)
01683         script_set_env(ip->client, prefix, "server_name",
01684             lease->server_name);
01685 #endif
01686 
01687     for (i = 0; i < 256; i++) {
01688         u_int8_t *dp = NULL;
01689 
01690         if (ip->client->config->defaults[i].len) {
01691             if (lease->options[i].len) {
01692                 switch (
01693                     ip->client->config->default_actions[i]) {
01694                 case ACTION_DEFAULT:
01695                     dp = lease->options[i].data;
01696                     len = lease->options[i].len;
01697                     break;
01698                 case ACTION_SUPERSEDE:
01699 supersede:
01700                     dp = ip->client->
01701                         config->defaults[i].data;
01702                     len = ip->client->
01703                         config->defaults[i].len;
01704                     break;
01705                 case ACTION_PREPEND:
01706                     len = ip->client->
01707                         config->defaults[i].len +
01708                         lease->options[i].len;
01709                     if (len >= sizeof(dbuf)) {
01710                         warning("no space to %s %s",
01711                             "prepend option",
01712                             dhcp_options[i].name);
01713                         goto supersede;
01714                     }
01715                     dp = dbuf;
01716                     memcpy(dp,
01717                         ip->client->
01718                         config->defaults[i].data,
01719                         ip->client->
01720                         config->defaults[i].len);
01721                     memcpy(dp + ip->client->
01722                         config->defaults[i].len,
01723                         lease->options[i].data,
01724                         lease->options[i].len);
01725                     dp[len] = '\0';
01726                     break;
01727                 case ACTION_APPEND:
01728                     len = ip->client->
01729                         config->defaults[i].len +
01730                         lease->options[i].len + 1;
01731                     if (len > sizeof(dbuf)) {
01732                         warning("no space to %s %s",
01733                             "append option",
01734                             dhcp_options[i].name);
01735                         goto supersede;
01736                     }
01737                     dp = dbuf;
01738                     memcpy(dp,
01739                         lease->options[i].data,
01740                         lease->options[i].len);
01741                     memcpy(dp + lease->options[i].len,
01742                         ip->client->
01743                         config->defaults[i].data,
01744                         ip->client->
01745                         config->defaults[i].len);
01746                     dp[len-1] = '\0';
01747                 }
01748             } else {
01749                 dp = ip->client->
01750                     config->defaults[i].data;
01751                 len = ip->client->
01752                     config->defaults[i].len;
01753             }
01754         } else if (lease->options[i].len) {
01755             len = lease->options[i].len;
01756             dp = lease->options[i].data;
01757         } else {
01758             len = 0;
01759         }
01760 #if 0
01761         if (len) {
01762             char name[256];
01763 
01764             if (dhcp_option_ev_name(name, sizeof(name),
01765                 &dhcp_options[i]))
01766                 script_set_env(ip->client, prefix, name,
01767                     pretty_print_option(i, dp, len, 0, 0));
01768         }
01769 #endif
01770     }
01771 #if 0
01772     snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
01773     script_set_env(ip->client, prefix, "expiry", tbuf);
01774 #endif
01775 }
01776 
01777 int
01778 dhcp_option_ev_name(char *buf, size_t buflen, struct dhcp_option *option)
01779 {
01780     int i;
01781 
01782     for (i = 0; option->name[i]; i++) {
01783         if (i + 1 == buflen)
01784             return 0;
01785         if (option->name[i] == '-')
01786             buf[i] = '_';
01787         else
01788             buf[i] = option->name[i];
01789     }
01790 
01791     buf[i] = 0;
01792     return 1;
01793 }
01794 
01795 #if 0
01796 void
01797 go_daemon(void)
01798 {
01799     static int state = 0;
01800 
01801     if (no_daemon || state)
01802         return;
01803 
01804     state = 1;
01805 
01806     /* Stop logging to stderr... */
01807     log_perror = 0;
01808 
01809     if (daemon(1, 0) == -1)
01810         error("daemon");
01811 
01812     /* we are chrooted, daemon(3) fails to open /dev/null */
01813     if (nullfd != -1) {
01814         dup2(nullfd, STDIN_FILENO);
01815         dup2(nullfd, STDOUT_FILENO);
01816         dup2(nullfd, STDERR_FILENO);
01817         close(nullfd);
01818         nullfd = -1;
01819     }
01820 }
01821 #endif
01822 
01823 int
01824 check_option(struct client_lease *l, int option)
01825 {
01826     char *opbuf;
01827     char *sbuf;
01828 
01829     /* we use this, since this is what gets passed to dhclient-script */
01830 
01831     opbuf = pretty_print_option(option, l->options[option].data,
01832         l->options[option].len, 0, 0);
01833 
01834     sbuf = option_as_string(option, l->options[option].data,
01835         l->options[option].len);
01836 
01837     switch (option) {
01838     case DHO_SUBNET_MASK:
01839     case DHO_TIME_SERVERS:
01840     case DHO_NAME_SERVERS:
01841     case DHO_ROUTERS:
01842     case DHO_DOMAIN_NAME_SERVERS:
01843     case DHO_LOG_SERVERS:
01844     case DHO_COOKIE_SERVERS:
01845     case DHO_LPR_SERVERS:
01846     case DHO_IMPRESS_SERVERS:
01847     case DHO_RESOURCE_LOCATION_SERVERS:
01848     case DHO_SWAP_SERVER:
01849     case DHO_BROADCAST_ADDRESS:
01850     case DHO_NIS_SERVERS:
01851     case DHO_NTP_SERVERS:
01852     case DHO_NETBIOS_NAME_SERVERS:
01853     case DHO_NETBIOS_DD_SERVER:
01854     case DHO_FONT_SERVERS:
01855     case DHO_DHCP_SERVER_IDENTIFIER:
01856         if (!ipv4addrs(opbuf)) {
01857                         warning("Invalid IP address in option(%d): %s", option, opbuf);
01858             return (0);
01859         }
01860         return (1)  ;
01861     case DHO_HOST_NAME:
01862     case DHO_DOMAIN_NAME:
01863     case DHO_NIS_DOMAIN:
01864         if (!res_hnok(sbuf))
01865             warning("Bogus Host Name option %d: %s (%s)", option,
01866                 sbuf, opbuf);
01867         return (1);
01868     case DHO_PAD:
01869     case DHO_TIME_OFFSET:
01870     case DHO_BOOT_SIZE:
01871     case DHO_MERIT_DUMP:
01872     case DHO_ROOT_PATH:
01873     case DHO_EXTENSIONS_PATH:
01874     case DHO_IP_FORWARDING:
01875     case DHO_NON_LOCAL_SOURCE_ROUTING:
01876     case DHO_POLICY_FILTER:
01877     case DHO_MAX_DGRAM_REASSEMBLY:
01878     case DHO_DEFAULT_IP_TTL:
01879     case DHO_PATH_MTU_AGING_TIMEOUT:
01880     case DHO_PATH_MTU_PLATEAU_TABLE:
01881     case DHO_INTERFACE_MTU:
01882     case DHO_ALL_SUBNETS_LOCAL:
01883     case DHO_PERFORM_MASK_DISCOVERY:
01884     case DHO_MASK_SUPPLIER:
01885     case DHO_ROUTER_DISCOVERY:
01886     case DHO_ROUTER_SOLICITATION_ADDRESS:
01887     case DHO_STATIC_ROUTES:
01888     case DHO_TRAILER_ENCAPSULATION:
01889     case DHO_ARP_CACHE_TIMEOUT:
01890     case DHO_IEEE802_3_ENCAPSULATION:
01891     case DHO_DEFAULT_TCP_TTL:
01892     case DHO_TCP_KEEPALIVE_INTERVAL:
01893     case DHO_TCP_KEEPALIVE_GARBAGE:
01894     case DHO_VENDOR_ENCAPSULATED_OPTIONS:
01895     case DHO_NETBIOS_NODE_TYPE:
01896     case DHO_NETBIOS_SCOPE:
01897     case DHO_X_DISPLAY_MANAGER:
01898     case DHO_DHCP_REQUESTED_ADDRESS:
01899     case DHO_DHCP_LEASE_TIME:
01900     case DHO_DHCP_OPTION_OVERLOAD:
01901     case DHO_DHCP_MESSAGE_TYPE:
01902     case DHO_DHCP_PARAMETER_REQUEST_LIST:
01903     case DHO_DHCP_MESSAGE:
01904     case DHO_DHCP_MAX_MESSAGE_SIZE:
01905     case DHO_DHCP_RENEWAL_TIME:
01906     case DHO_DHCP_REBINDING_TIME:
01907     case DHO_DHCP_CLASS_IDENTIFIER:
01908     case DHO_DHCP_CLIENT_IDENTIFIER:
01909     case DHO_DHCP_USER_CLASS_ID:
01910     case DHO_END:
01911         return (1);
01912     default:
01913         warning("unknown dhcp option value 0x%x", option);
01914         return (unknown_ok);
01915     }
01916 }
01917 
01918 int
01919 res_hnok(const char *dn)
01920 {
01921     int pch = PERIOD, ch = *dn++;
01922 
01923     while (ch != '\0') {
01924         int nch = *dn++;
01925 
01926         if (periodchar(ch)) {
01927             ;
01928         } else if (periodchar(pch)) {
01929             if (!borderchar(ch))
01930                 return (0);
01931         } else if (periodchar(nch) || nch == '\0') {
01932             if (!borderchar(ch))
01933                 return (0);
01934         } else {
01935             if (!middlechar(ch))
01936                 return (0);
01937         }
01938         pch = ch, ch = nch;
01939     }
01940     return (1);
01941 }
01942 
01943 /* Does buf consist only of dotted decimal ipv4 addrs?
01944  * return how many if so,
01945  * otherwise, return 0
01946  */
01947 int
01948 ipv4addrs(char * buf)
01949 {
01950     char *tmp;
01951     struct in_addr jnk;
01952     int i = 0;
01953 
01954     note("Input: %s", buf);
01955 
01956     do {
01957         tmp = strtok(buf, " ");
01958         note("got %s", tmp);
01959         if( tmp && inet_aton(tmp, &jnk) ) i++;
01960         buf = NULL;
01961     } while( tmp );
01962 
01963     return (i);
01964 }
01965 
01966 
01967 char *
01968 option_as_string(unsigned int code, unsigned char *data, int len)
01969 {
01970     static char optbuf[32768]; /* XXX */
01971     char *op = optbuf;
01972     int opleft = sizeof(optbuf);
01973     unsigned char *dp = data;
01974 
01975     if (code > 255)
01976         error("option_as_string: bad code %d", code);
01977 
01978     for (; dp < data + len; dp++) {
01979         if (!isascii(*dp) || !isprint(*dp)) {
01980             if (dp + 1 != data + len || *dp != 0) {
01981                 _snprintf(op, opleft, "\\%03o", *dp);
01982                 op += 4;
01983                 opleft -= 4;
01984             }
01985         } else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
01986             *dp == '`' || *dp == '\\') {
01987             *op++ = '\\';
01988             *op++ = *dp;
01989             opleft -= 2;
01990         } else {
01991             *op++ = *dp;
01992             opleft--;
01993         }
01994     }
01995     if (opleft < 1)
01996         goto toobig;
01997     *op = 0;
01998     return optbuf;
01999 toobig:
02000     warning("dhcp option too large");
02001     return "<error>";
02002 }
02003 

Generated on Sun May 27 2012 04:23:27 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.