First import of DHCP client service. No pipe created yet. Event model up and running. Does not produce a dhcp offer yet but working on that. Added: trunk/reactos/subsys/system/dhcp/ Added: trunk/reactos/subsys/system/dhcp/Makefile Added: trunk/reactos/subsys/system/dhcp/adapter.c Added: trunk/reactos/subsys/system/dhcp/alloc.c Added: trunk/reactos/subsys/system/dhcp/compat.c Added: trunk/reactos/subsys/system/dhcp/design.txt Added: trunk/reactos/subsys/system/dhcp/dhclient.c Added: trunk/reactos/subsys/system/dhcp/dhcp.rc Added: trunk/reactos/subsys/system/dhcp/dhcpmain.c Added: trunk/reactos/subsys/system/dhcp/dispatch.c Added: trunk/reactos/subsys/system/dhcp/hash.c Added: trunk/reactos/subsys/system/dhcp/include/ Added: trunk/reactos/subsys/system/dhcp/include/cdefs.h Added: trunk/reactos/subsys/system/dhcp/include/debug.h Added: trunk/reactos/subsys/system/dhcp/include/dhcp.h Added: trunk/reactos/subsys/system/dhcp/include/dhcpd.h Added: trunk/reactos/subsys/system/dhcp/include/dhctoken.h Added: trunk/reactos/subsys/system/dhcp/include/hash.h Added: trunk/reactos/subsys/system/dhcp/include/inet.h Added: trunk/reactos/subsys/system/dhcp/include/osdep.h Added: trunk/reactos/subsys/system/dhcp/include/predec.h Added: trunk/reactos/subsys/system/dhcp/include/privsep.h Added: trunk/reactos/subsys/system/dhcp/include/rosdhcp.h Added: trunk/reactos/subsys/system/dhcp/include/site.h Added: trunk/reactos/subsys/system/dhcp/include/stdint.h Added: trunk/reactos/subsys/system/dhcp/include/sysconf.h Added: trunk/reactos/subsys/system/dhcp/include/tree.h Added: trunk/reactos/subsys/system/dhcp/include/version.h Added: trunk/reactos/subsys/system/dhcp/memory.c Added: trunk/reactos/subsys/system/dhcp/options.c Added: trunk/reactos/subsys/system/dhcp/privsep.c Added: trunk/reactos/subsys/system/dhcp/socket.c Added: trunk/reactos/subsys/system/dhcp/tables.c Added: trunk/reactos/subsys/system/dhcp/timer.c Added: trunk/reactos/subsys/system/dhcp/tree.c Added: trunk/reactos/subsys/system/dhcp/util.c _____
Added: trunk/reactos/subsys/system/dhcp/Makefile --- trunk/reactos/subsys/system/dhcp/Makefile 2005-04-04 23:17:28 UTC (rev 14495) +++ trunk/reactos/subsys/system/dhcp/Makefile 2005-04-04 23:45:33 UTC (rev 14496) @@ -0,0 +1,30 @@
+# + +PATH_TO_TOP = ../../.. + +TARGET_TYPE = program + +TARGET_APPTYPE = windows + +TARGET_NAME = dhcp + +TARGET_CFLAGS = -D__REACTOS__ -D_WIN32_WINNT=0x0501 -D__USE_W32API -Iinclude + +TARGET_OBJECTS = adapter.o alloc.o compat.o dhclient.o dispatch.o hash.o \ + options.o privsep.o socket.o tables.o timer.o util.o + +TARGET_SDKLIBS = iphlpapi.a ws2_32.a ntdll.a + +TARGET_RC_SRCS = dhcp.rc + +TARGET_RC_BINSRC = + +TARGET_RC_BINARIES = + +default: all +DEP_OBJECTS = $(TARGET_OBJECTS) +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk + +include $(TOOLS_PATH)/depend.mk _____
Added: trunk/reactos/subsys/system/dhcp/adapter.c --- trunk/reactos/subsys/system/dhcp/adapter.c 2005-04-04 23:17:28 UTC (rev 14495) +++ trunk/reactos/subsys/system/dhcp/adapter.c 2005-04-04 23:45:33 UTC (rev 14496) @@ -0,0 +1,162 @@
+#include "rosdhcp.h" + +static LIST_ENTRY AdapterList; +static WSADATA wsd; +extern struct interface_info *ifi; + +DWORD GetAddress( PDHCP_ADAPTER Adapter ) { + PMIB_IPADDRTABLE AddressTable = NULL; + ULONG i, Size = 0, NumAddressRows; + DWORD Error = GetIpAddrTable( AddressTable, &Size, FALSE ); + + while( Error == ERROR_INSUFFICIENT_BUFFER ) { + free( AddressTable ); + AddressTable = malloc( Size ); + if( AddressTable ) + Error = GetIpAddrTable( AddressTable, &Size, FALSE ); + } + if( Error != ERROR_SUCCESS ) { + free( AddressTable ); + return Error; + } + + NumAddressRows = Size / sizeof(MIB_IPADDRTABLE); + for( i = 0; i < AddressTable->dwNumEntries; i++ ) { + DH_DbgPrint(MID_TRACE, + ("Finding address for adapter %d: (%d -> %x)\n", + Adapter->IfMib.dwIndex, + AddressTable->table[i].dwIndex, + AddressTable->table[i].dwAddr)); + if( Adapter->IfMib.dwIndex == AddressTable->table[i].dwIndex ) { + memcpy( &Adapter->IfAddr, &AddressTable->table[i], + sizeof( MIB_IPADDRROW ) ); + } + } +} + +void AdapterInit() { + PMIB_IFTABLE Table = malloc(sizeof(MIB_IFTABLE)); + DWORD Error, Size, i; + PDHCP_ADAPTER Adapter = NULL; + + WSAStartup(0x0101,&wsd); + + InitializeListHead( &AdapterList ); + + DH_DbgPrint(MID_TRACE,("Getting Adapter List...\n")); + + while( (Error = GetIfTable(Table, &Size, 0 )) == + ERROR_INSUFFICIENT_BUFFER ) { + DH_DbgPrint(MID_TRACE,("Error %d, New Buffer Size: %d\n", Error, Size)); + free( Table ); + Table = malloc( Size ); + } + + if( Error != NO_ERROR ) goto term; + + DH_DbgPrint(MID_TRACE,("Got Adapter List (%d entries)\n", Table->dwNumEntries)); + + for( i = 0; i < Table->dwNumEntries; i++ ) { + DH_DbgPrint(MID_TRACE,("Getting adapter %d attributes\n", i)); + Adapter = calloc( sizeof( DHCP_ADAPTER ) + Table->table[i].dwMtu, 1 ); + + if( Adapter ) { + memcpy( &Adapter->IfMib, &Table->table[i], + sizeof(Adapter->IfMib) ); + GetAddress( Adapter ); + InsertTailList( &AdapterList, &Adapter->ListEntry ); + Adapter->DhclientInfo.next = ifi; + Adapter->DhclientInfo.client = &Adapter->DhclientState; + Adapter->DhclientInfo.rbuf = Adapter->recv_buf; + Adapter->DhclientInfo.rbuf_max = Table->table[i].dwMtu; + Adapter->DhclientInfo.rbuf_len = + Adapter->DhclientInfo.rbuf_offset = 0; + Adapter->DhclientInfo.rfdesc = + Adapter->DhclientInfo.wfdesc = + socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); + Adapter->ListenAddr.sin_family = AF_INET; + Adapter->ListenAddr.sin_port = htons(LOCAL_PORT); + Adapter->BindStatus = + (bind( Adapter->DhclientInfo.rfdesc, + (struct sockaddr *)&Adapter->ListenAddr, + sizeof(Adapter->ListenAddr) ) == 0) ? + 0 : WSAGetLastError(); + Adapter->DhclientState.config = &Adapter->DhclientConfig; + Adapter->DhclientConfig.initial_interval = DHCP_DISCOVER_INTERVAL; + Adapter->DhclientConfig.retry_interval = DHCP_DISCOVER_INTERVAL; + Adapter->DhclientConfig.select_interval = 1; + Adapter->DhclientConfig.reboot_timeout = DHCP_REBOOT_TIMEOUT; + Adapter->DhclientConfig.backoff_cutoff = DHCP_BACKOFF_MAX; + Adapter->DhclientState.interval = + Adapter->DhclientConfig.retry_interval; + strncpy(Adapter->DhclientInfo.name, Adapter->IfMib.bDescr, + sizeof(Adapter->DhclientInfo.name)); + DH_DbgPrint(MID_TRACE,("Adapter Name: [%s]\n", Adapter->DhclientInfo.name)); + ifi = &Adapter->DhclientInfo; + } + } + + DH_DbgPrint(MID_TRACE,("done with AdapterInit\n")); + +term: + if( Table ) free( Table ); +} + +void AdapterStop() { + PLIST_ENTRY ListEntry; + PDHCP_ADAPTER Adapter; + while( !IsListEmpty( &AdapterList ) ) { + ListEntry = (PLIST_ENTRY)RemoveHeadList( &AdapterList ); + Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry ); + free( Adapter ); + } + WSACleanup(); +} + +PDHCP_ADAPTER AdapterFindIndex( unsigned int indx ) { + PDHCP_ADAPTER Adapter; + PLIST_ENTRY ListEntry; + + for( ListEntry = AdapterList.Flink; + ListEntry != &AdapterList; + ListEntry = ListEntry->Flink ) { + Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry ); + if( Adapter->IfMib.dwIndex == indx ) return Adapter; + } + + return NULL; +} + +PDHCP_ADAPTER AdapterFindName( const WCHAR *name ) { + PDHCP_ADAPTER Adapter; + PLIST_ENTRY ListEntry; + + for( ListEntry = AdapterList.Flink; + ListEntry != &AdapterList; + ListEntry = ListEntry->Flink ) { + Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry ); + if( !wcsicmp( Adapter->IfMib.wszName, name ) ) return Adapter; + } + + return NULL; +} + +PDHCP_ADAPTER AdapterGetFirst() { + if( IsListEmpty( &AdapterList ) ) return NULL; else { + return CONTAINING_RECORD + ( AdapterList.Flink, DHCP_ADAPTER, ListEntry ); + } +} + +PDHCP_ADAPTER AdapterGetNext( PDHCP_ADAPTER This ) +{ + if( This->ListEntry.Flink == &AdapterList ) return NULL; + return CONTAINING_RECORD + ( This->ListEntry.Flink, DHCP_ADAPTER, ListEntry ); +} + +void if_register_send(struct interface_info *ip) { +} + +void if_register_receive(struct interface_info *ip) { +} _____
Added: trunk/reactos/subsys/system/dhcp/alloc.c --- trunk/reactos/subsys/system/dhcp/alloc.c 2005-04-04 23:17:28 UTC (rev 14495) +++ trunk/reactos/subsys/system/dhcp/alloc.c 2005-04-04 23:45:33 UTC (rev 14496) @@ -0,0 +1,79 @@
+/* $OpenBSD: alloc.c,v 1.9 2004/05/04 20:28:40 deraadt Exp $ */ + +/* Memory allocation... */ + +/* + * Copyright (c) 1995, 1996, 1998 The Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon mellon@fugue.com in cooperation with Vixie + * Enterprises. To learn more about the Internet Software Consortium, + * see ``http://www.vix.com/isc''. To learn more about Vixie + * Enterprises, see ``http://www.vix.com''. + */ + +#include "rosdhcp.h" +#include "dhcpd.h" + +struct string_list * +new_string_list(size_t size) +{ + struct string_list *rval; + + rval = calloc(1, sizeof(struct string_list) + size); + if (rval != NULL) + rval->string = ((char *)rval) + sizeof(struct string_list); + return (rval); +} + +struct hash_table * +new_hash_table(int count) +{ + struct hash_table *rval; + + rval = calloc(1, sizeof(struct hash_table) - + (DEFAULT_HASH_SIZE * sizeof(struct hash_bucket *)) + + (count * sizeof(struct hash_bucket *))); + if (rval == NULL) + return (NULL); + rval->hash_count = count; + return (rval); +} + +struct hash_bucket * +new_hash_bucket(void) +{ + struct hash_bucket *rval = calloc(1, sizeof(struct hash_bucket)); + + return (rval); +} + +void free_hash_bucket(struct hash_bucket *hb) { free(hb); } _____
Added: trunk/reactos/subsys/system/dhcp/compat.c --- trunk/reactos/subsys/system/dhcp/compat.c 2005-04-04 23:17:28 UTC (rev 14495) +++ trunk/reactos/subsys/system/dhcp/compat.c 2005-04-04 23:45:33 UTC (rev 14496) @@ -0,0 +1,40 @@
+#include "rosdhcp.h" +#include "dhcpd.h" +#include "stdint.h" + +size_t strlcpy(char *d, const char *s, size_t bufsize) +{ + size_t len = strlen(s); + size_t ret = len; + if (bufsize > 0) { + if (len >= bufsize) + len = bufsize-1; + memcpy(d, s, len); + d[len] = 0; + } + return ret; +} + +// not really random :( +u_int32_t arc4random() +{ + static int did_srand = 0; + u_int32_t ret; + + if (!did_srand) { + srand(0); + did_srand = 1; + } + + ret = rand() << 10 ^ rand(); + return ret; +} + +int inet_aton(const char *cp, struct in_addr *inp) +{ + inp->S_un.S_addr = inet_addr(cp); + if (INADDR_NONE == inp->S_un.S_addr) + return 0; + + return 1; +} _____
Added: trunk/reactos/subsys/system/dhcp/design.txt --- trunk/reactos/subsys/system/dhcp/design.txt 2005-04-04 23:17:28 UTC (rev 14495) +++ trunk/reactos/subsys/system/dhcp/design.txt 2005-04-04 23:45:33 UTC (rev 14496) @@ -0,0 +1,29 @@
+Ok I need these things: + +1) Adapter concept thingy + + Needs a name and index + Current IP address etc + interface_info + + Must be able to get one from an adapter index or name + Must query the ip address and such + Must be able to set the address + +2) System state doodad + + List of adapters + List of parameter changes + List of persistent stuff + + Must be able to initialize from the registry + (persistent stuff, some adapter info) + Save changes to persistent set + +3) Parameter change set + + TODO + +4) Persistent queries + + TODO \ No newline at end of file _____
Added: trunk/reactos/subsys/system/dhcp/dhclient.c --- trunk/reactos/subsys/system/dhcp/dhclient.c 2005-04-04 23:17:28 UTC (rev 14495) +++ trunk/reactos/subsys/system/dhcp/dhclient.c 2005-04-04 23:45:33 UTC (rev 14496) @@ -0,0 +1,2308 @@
+/* $OpenBSD: dhclient.c,v 1.62 2004/12/05 18:35:51 deraadt Exp $ */ + +/* + * Copyright 2004 Henning Brauer henning@openbsd.org + * Copyright (c) 1995, 1996, 1997, 1998, 1999 + * The Internet Software Consortium. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon mellon@fugue.com in cooperation with Vixie + * Enterprises. To learn more about the Internet Software Consortium, + * see ``http://www.vix.com/isc''. To learn more about Vixie + * Enterprises, see ``http://www.vix.com''. + * + * This client was substantially modified and enhanced by Elliot Poger + * for use on Linux while he was working on the MosquitoNet project at + * Stanford. + * + * The current version owes much to Elliot's Linux enhancements, but + * was substantially reorganized and partially rewritten by Ted Lemon + * so as to use the same networking framework that the Internet Software + * Consortium DHCP server uses. Much system-specific configuration code + * was moved into a shell script so that as support for more operating + * systems is added, it will not be necessary to port and maintain + * system-specific configuration code to these operating systems - instead, + * the shell script can invoke the native tools to accomplish the same + * purpose. + */ + +#include <winsock2.h> +#include "rosdhcp.h" +#include "dhcpd.h" +#include "privsep.h" + +#define PERIOD 0x2e +#define hyphenchar(c) ((c) == 0x2d) +#define bslashchar(c) ((c) == 0x5c) +#define periodchar(c) ((c) == PERIOD) +#define asterchar(c) ((c) == 0x2a) +#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \ + ((c) >= 0x61 && (c) <= 0x7a)) +#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) + +#define borderchar(c) (alphachar(c) || digitchar(c)) +#define middlechar(c) (borderchar(c) || hyphenchar(c)) +#define domainchar(c) ((c) > 0x20 && (c) < 0x7f) + +unsigned long debug_trace_level = DEBUG_ULTRA; +time_t cur_time; +time_t default_lease_time = 43200; /* 12 hours... */ + +char *path_dhclient_conf = _PATH_DHCLIENT_CONF; +char *path_dhclient_db = NULL; + +int log_perror = 1; +int privfd; +//int nullfd = -1; + +struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; +struct in_addr inaddr_any; +struct sockaddr_in sockaddr_broadcast; + +/* + * ASSERT_STATE() does nothing now; it used to be + * assert (state_is == state_shouldbe). + */ +#define ASSERT_STATE(state_is, state_shouldbe) {} + +#define TIME_MAX 2147483647 + +int log_priority; +int no_daemon; +int unknown_ok = 1; +int routefd; + +struct interface_info *ifi = NULL; + +void usage(void); +int check_option(struct client_lease *l, int option); +int ipv4addrs(char * buf); +int res_hnok(const char *dn); +char *option_as_string(unsigned int code, unsigned char *data, int len); +int fork_privchld(int, int); + +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) +#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) + +time_t scripttime; + +#if 0 + +int +findproto(char *cp, int n) +{ + struct sockaddr *sa; + int i; + + if (n == 0) + return -1; + for (i = 1; i; i <<= 1) { + if (i & n) { + sa = (struct sockaddr *)cp; + switch (i) { + case RTA_IFA: + case RTA_DST: + case RTA_GATEWAY: + case RTA_NETMASK: + if (sa->sa_family == AF_INET) + return AF_INET; + if (sa->sa_family == AF_INET6) + return AF_INET6; + break; + case RTA_IFP: + break; + } + ADVANCE(cp, sa); + } + } + return (-1); +} + + +struct sockaddr * +get_ifa(char *cp, int n) +{ + struct sockaddr *sa; + int i; + + if (n == 0) + return (NULL); + for (i = 1; i; i <<= 1) + if (i & n) { + sa = (struct sockaddr *)cp; + if (i == RTA_IFA) + return (sa); + ADVANCE(cp, sa); + } + + return (NULL); +} +struct iaddr defaddr = { 4 }; + +/* ARGSUSED */ +void +routehandler(struct protocol *p) +{ + char msg[2048]; + struct rt_msghdr *rtm; + struct if_msghdr *ifm; + struct ifa_msghdr *ifam; + struct if_announcemsghdr *ifan; + struct client_lease *l; + time_t t = time(NULL); + struct sockaddr *sa; + struct iaddr a; + ssize_t n; + + n = read(routefd, &msg, sizeof(msg)); + rtm = (struct rt_msghdr *)msg; + if (n < sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen || + rtm->rtm_version != RTM_VERSION) + return; + + switch (rtm->rtm_type) { + case RTM_NEWADDR: + ifam = (struct ifa_msghdr *)rtm; + if (ifam->ifam_index != ifi->index) + break; + if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET) + break; + if (ifi == NULL) + goto die; + sa = get_ifa((char *)(ifam + 1), ifam->ifam_addrs); + if (sa == NULL) + goto die; + + if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf)) + error("king bula sez: len mismatch"); + memcpy(a.iabuf, &((struct sockaddr_in *)sa)->sin_addr, a.len); + if (addr_eq(a, defaddr)) + break; + + for (l = ifi->client->active; l != NULL; l = l->next) + if (addr_eq(a, l->address)) + break; + + if (l != NULL) /* new addr is the one we set */ + break; + + goto die; + case RTM_DELADDR: + ifam = (struct ifa_msghdr *)rtm; + if (ifam->ifam_index != ifi->index) + break; + if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET) + break; + if (scripttime == 0 || t < scripttime + 10) + break; + goto die; + case RTM_IFINFO: + ifm = (struct if_msghdr *)rtm; + if (ifm->ifm_index != ifi->index) + break; + if ((rtm->rtm_flags & RTF_UP) == 0) + goto die; + break; + case RTM_IFANNOUNCE: + ifan = (struct if_announcemsghdr *)rtm; + if (ifan->ifan_what == IFAN_DEPARTURE && + ifan->ifan_index == ifi->index) + goto die; + break; + default: + break; + } + return; + +die: + script_init("FAIL", NULL); + if (ifi->client->alias) + script_write_params("alias_", ifi->client->alias); + script_go(); + exit(1); +} +#endif + +int +main(int argc, char *argv[]) +{ + extern char *__progname; + int ch, fd, quiet = 0, i = 0; + int pipe_fd[2]; + struct passwd *pw; + + AdapterInit(); + + tzset(); + time(&cur_time); + + memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast)); + sockaddr_broadcast.sin_family = AF_INET; + sockaddr_broadcast.sin_port = htons(REMOTE_PORT); + sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST; + inaddr_any.s_addr = INADDR_ANY; + + DH_DbgPrint(MID_TRACE,("DHCP Service Started\n")); + + read_client_conf(); + + if (!interface_link_status(ifi->name)) { + DH_DbgPrint(MID_TRACE,("%s: no link ", ifi->name)); + Sleep(1000); + while (!interface_link_status(ifi->name)) { + DH_DbgPrint(MID_TRACE,(".")); + if (++i > 10) { + DH_DbgPrint(MID_TRACE,("Giving up for now on adapter [%s]\n", ifi->name)); + } + Sleep(1000); + } + DH_DbgPrint(MID_TRACE,("Got link on [%s]\n", ifi->name)); + } + + DH_DbgPrint(MID_TRACE,("Discover Interfaces\n")); + + /* set up the interface */ + discover_interfaces(ifi); + + DH_DbgPrint + (MID_TRACE, + ("Setting init state and restarting interface %p\n",ifi)); + + ifi->client->state = S_INIT; + state_reboot(ifi); + + bootp_packet_handler = do_packet; + + DH_DbgPrint(MID_TRACE,("Going into dispatch()\n")); + + dispatch(); + + /* not reached */ + return (0); +} + +void +usage(void) +{ +// extern char *__progname; + +// fprintf(stderr, "usage: %s [-dqu] ", __progname); + fprintf(stderr, "usage: dhclient [-dqu] "); + fprintf(stderr, "[-c conffile] [-l leasefile] interface\n"); + exit(1); +} + +/* + * Individual States: + * + * Each routine is called from the dhclient_state_machine() in one of + * these conditions: + * -> entering INIT state + * -> recvpacket_flag == 0: timeout in this state + * -> otherwise: received a packet in this state + * + * Return conditions as handled by dhclient_state_machine(): + * Returns 1, sendpacket_flag = 1: send packet, reset timer. + * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone). + * Returns 0: finish the nap which was interrupted for no good reason. + * + * Several per-interface variables are used to keep track of the process: + * active_lease: the lease that is being used on the interface + * (null pointer if not configured yet). + * offered_leases: leases corresponding to DHCPOFFER messages that have + * been sent to us by DHCP servers. + * acked_leases: leases corresponding to DHCPACK messages that have been + * sent to us by DHCP servers. + * sendpacket: DHCP packet we're trying to send. + * destination: IP address to send sendpacket to + * In addition, there are several relevant per-lease variables. + * T1_expiry, T2_expiry, lease_expiry: lease milestones + * In the active lease, these control the process of renewing the lease; + * In leases on the acked_leases list, this simply determines when we + * can no longer legitimately use the lease. + */ + +void +state_reboot(void *ipp) +{ + struct interface_info *ip = ipp; + + /* If we don't remember an active lease, go straight to INIT. */ + if (!ip->client->active || ip->client->active->is_bootp) { + state_init(ip); + return; + } + + /* We are in the rebooting state. */ + ip->client->state = S_REBOOTING; + + /* make_request doesn't initialize xid because it normally comes + from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, + so pick an xid now. */ + ip->client->xid = arc4random(); + + /* Make a DHCPREQUEST packet, and set appropriate per-interface + flags. */ + make_request(ip, ip->client->active); + ip->client->destination = iaddr_broadcast; + ip->client->first_sending = cur_time; + ip->client->interval = ip->client->config->initial_interval; + + /* Zap the medium list... */ + ip->client->medium = NULL; + + /* Send out the first DHCPREQUEST packet. */ + send_request(ip); +} + +/* + * Called when a lease has completely expired and we've + * been unable to renew it. + */ +void +state_init(void *ipp) +{ + struct interface_info *ip = ipp; + + ASSERT_STATE(state, S_INIT); + + /* Make a DHCPDISCOVER packet, and set appropriate per-interface + flags. */ + make_discover(ip, ip->client->active); + ip->client->xid = ip->client->packet.xid; + ip->client->destination = iaddr_broadcast; + ip->client->state = S_SELECTING; + ip->client->first_sending = cur_time; + ip->client->interval = ip->client->config->initial_interval; + + /* Add an immediate timeout to cause the first DHCPDISCOVER packet + to go out. */ + send_discover(ip); +} + +/* + * state_selecting is called when one or more DHCPOFFER packets + * have been received and a configurable period of time has passed. + */ +void +state_selecting(void *ipp) +{ + struct interface_info *ip = ipp; + struct client_lease *lp, *next, *picked; + + ASSERT_STATE(state, S_SELECTING); + + /* Cancel state_selecting and send_discover timeouts, since either + one could have got us here. */ + cancel_timeout(state_selecting, ip); + cancel_timeout(send_discover, ip); + + /* We have received one or more DHCPOFFER packets. Currently, + the only criterion by which we judge leases is whether or + not we get a response when we arp for them. */ + picked = NULL; + for (lp = ip->client->offered_leases; lp; lp = next) { + next = lp->next; + + /* Check to see if we got an ARPREPLY for the address + in this particular lease. */ + if (!picked) { + script_init("ARPCHECK", lp->medium); + script_write_params("check_", lp); + + /* If the ARPCHECK code detects another + machine using the offered address, it exits + nonzero. We need to send a DHCPDECLINE and + toss the lease. */ + if (script_go()) { + make_decline(ip, lp); + send_decline(ip); + goto freeit; + } + picked = lp; + picked->next = NULL; + } else { +freeit: + free_client_lease(lp); + } + } + ip->client->offered_leases = NULL; + + /* If we just tossed all the leases we were offered, go back + to square one. */ + if (!picked) { + ip->client->state = S_INIT; + state_init(ip); + return; + } + + /* If it was a BOOTREPLY, we can just take the address right now. */ + if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) { + ip->client->new = picked; + + /* Make up some lease expiry times + XXX these should be configurable. */ + ip->client->new->expiry = cur_time + 12000; + ip->client->new->renewal += cur_time + 8000; + ip->client->new->rebind += cur_time + 10000; + + ip->client->state = S_REQUESTING; + + /* Bind to the address we received. */ + bind_lease(ip); + return; + } + + /* Go to the REQUESTING state. */ + ip->client->destination = iaddr_broadcast; + ip->client->state = S_REQUESTING; + ip->client->first_sending = cur_time; + ip->client->interval = ip->client->config->initial_interval; + + /* Make a DHCPREQUEST packet from the lease we picked. */ + make_request(ip, picked); + ip->client->xid = ip->client->packet.xid; + + /* Toss the lease we picked - we'll get it back in a DHCPACK. */ + free_client_lease(picked); + + /* Add an immediate timeout to send the first DHCPREQUEST packet. */ + send_request(ip); +} + +/* state_requesting is called when we receive a DHCPACK message after + having sent out one or more DHCPREQUEST packets. */ + +void +dhcpack(struct packet *packet) +{ + struct interface_info *ip = packet->interface; + struct client_lease *lease; + + /* If we're not receptive to an offer right now, or if the offer + has an unrecognizable transaction id, then just drop it. */ + if (packet->interface->client->xid != packet->raw->xid || + (packet->interface->hw_address.hlen != packet->raw->hlen) || + (memcmp(packet->interface->hw_address.haddr, + packet->raw->chaddr, packet->raw->hlen))) + return; + + if (ip->client->state != S_REBOOTING && + ip->client->state != S_REQUESTING && + ip->client->state != S_RENEWING && + ip->client->state != S_REBINDING) + return; + + note("DHCPACK from %s", piaddr(packet->client_addr)); + + lease = packet_to_lease(packet); + if (!lease) { + note("packet_to_lease failed."); + return; + } + + ip->client->new = lease; + + /* Stop resending DHCPREQUEST. */ + cancel_timeout(send_request, ip); + + /* Figure out the lease time. */ + if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data) + ip->client->new->expiry = getULong( + ip->client->new->options[DHO_DHCP_LEASE_TIME].data); + else + ip->client->new->expiry = default_lease_time; + /* A number that looks negative here is really just very large, + because the lease expiry offset is unsigned. */ + if (ip->client->new->expiry < 0) + ip->client->new->expiry = TIME_MAX; + /* XXX should be fixed by resetting the client state */ + if (ip->client->new->expiry < 60) + ip->client->new->expiry = 60; + + /* Take the server-provided renewal time if there is one; + otherwise figure it out according to the spec. */ + if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len) + ip->client->new->renewal = getULong( + ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data); + else + ip->client->new->renewal = ip->client->new->expiry / 2; + + /* Same deal with the rebind time. */ + if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len) + ip->client->new->rebind = getULong( + ip->client->new->options[DHO_DHCP_REBINDING_TIME].data); + else + ip->client->new->rebind = ip->client->new->renewal + + ip->client->new->renewal / 2 + ip->client->new->renewal / 4; + + ip->client->new->expiry += cur_time; + /* Lease lengths can never be negative. */ + if (ip->client->new->expiry < cur_time) + ip->client->new->expiry = TIME_MAX; + ip->client->new->renewal += cur_time; + if (ip->client->new->renewal < cur_time) + ip->client->new->renewal = TIME_MAX; + ip->client->new->rebind += cur_time; + if (ip->client->new->rebind < cur_time) + ip->client->new->rebind = TIME_MAX; + + bind_lease(ip); +} + +void +bind_lease(struct interface_info *ip) +{ + /* Remember the medium. */ + ip->client->new->medium = ip->client->medium; + + /* Write out the new lease. */ + write_client_lease(ip, ip->client->new, 0); + + /* Run the client script with the new parameters. */ + script_init((ip->client->state == S_REQUESTING ? "BOUND" : + (ip->client->state == S_RENEWING ? "RENEW" : + (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))), + ip->client->new->medium); + if (ip->client->active && ip->client->state != S_REBOOTING) + script_write_params("old_", ip->client->active); + script_write_params("new_", ip->client->new); + if (ip->client->alias) + script_write_params("alias_", ip->client->alias); + script_go(); + + /* Replace the old active lease with the new one. */ + if (ip->client->active) + free_client_lease(ip->client->active); + ip->client->active = ip->client->new; + ip->client->new = NULL; + + /* Set up a timeout to start the renewal process. */ + add_timeout(ip->client->active->renewal, state_bound, ip); + + note("bound to %s -- renewal in %d seconds.", + piaddr(ip->client->active->address), + ip->client->active->renewal - cur_time); + ip->client->state = S_BOUND; + reinitialize_interfaces(); +// go_daemon(); +} + +/* + * state_bound is called when we've successfully bound to a particular + * lease, but the renewal time on that lease has expired. We are + * expected to unicast a DHCPREQUEST to the server that gave us our + * original lease. + */ +void +state_bound(void *ipp) +{ + struct interface_info *ip = ipp; + [truncated at 1000 lines; 7424 more skipped]