diff --git a/reactos/subsys/system/dhcp/Makefile b/reactos/subsys/system/dhcp/Makefile new file mode 100644 index 00000000000..34974ee379f --- /dev/null +++ b/reactos/subsys/system/dhcp/Makefile @@ -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 diff --git a/reactos/subsys/system/dhcp/adapter.c b/reactos/subsys/system/dhcp/adapter.c new file mode 100644 index 00000000000..b9c0b94f698 --- /dev/null +++ b/reactos/subsys/system/dhcp/adapter.c @@ -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) { +} diff --git a/reactos/subsys/system/dhcp/alloc.c b/reactos/subsys/system/dhcp/alloc.c new file mode 100644 index 00000000000..5894a96e6f3 --- /dev/null +++ b/reactos/subsys/system/dhcp/alloc.c @@ -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 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); } diff --git a/reactos/subsys/system/dhcp/compat.c b/reactos/subsys/system/dhcp/compat.c new file mode 100644 index 00000000000..34ed1d488cd --- /dev/null +++ b/reactos/subsys/system/dhcp/compat.c @@ -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; +} diff --git a/reactos/subsys/system/dhcp/design.txt b/reactos/subsys/system/dhcp/design.txt new file mode 100644 index 00000000000..5b3e17e01a2 --- /dev/null +++ b/reactos/subsys/system/dhcp/design.txt @@ -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 diff --git a/reactos/subsys/system/dhcp/dhclient.c b/reactos/subsys/system/dhcp/dhclient.c new file mode 100644 index 00000000000..9ead8b89419 --- /dev/null +++ b/reactos/subsys/system/dhcp/dhclient.c @@ -0,0 +1,2308 @@ +/* $OpenBSD: dhclient.c,v 1.62 2004/12/05 18:35:51 deraadt Exp $ */ + +/* + * Copyright 2004 Henning Brauer + * 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 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 +#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; + + ASSERT_STATE(state, S_BOUND); + + /* T1 has expired. */ + make_request(ip, ip->client->active); + ip->client->xid = ip->client->packet.xid; + + if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) { + memcpy(ip->client->destination.iabuf, ip->client->active-> + options[DHO_DHCP_SERVER_IDENTIFIER].data, 4); + ip->client->destination.len = 4; + } else + ip->client->destination = iaddr_broadcast; + + ip->client->first_sending = cur_time; + ip->client->interval = ip->client->config->initial_interval; + ip->client->state = S_RENEWING; + + /* Send the first packet immediately. */ + send_request(ip); +} + +void +bootp(struct packet *packet) +{ + struct iaddrlist *ap; + + if (packet->raw->op != BOOTREPLY) + return; + + /* If there's a reject list, make sure this packet's sender isn't + on it. */ + for (ap = packet->interface->client->config->reject_list; + ap; ap = ap->next) { + if (addr_eq(packet->client_addr, ap->addr)) { + note("BOOTREPLY from %s rejected.", piaddr(ap->addr)); + return; + } + } + dhcpoffer(packet); +} + +void +dhcp(struct packet *packet) +{ + struct iaddrlist *ap; + void (*handler)(struct packet *); + char *type; + + switch (packet->packet_type) { + case DHCPOFFER: + handler = dhcpoffer; + type = "DHCPOFFER"; + break; + case DHCPNAK: + handler = dhcpnak; + type = "DHCPNACK"; + break; + case DHCPACK: + handler = dhcpack; + type = "DHCPACK"; + break; + default: + return; + } + + /* If there's a reject list, make sure this packet's sender isn't + on it. */ + for (ap = packet->interface->client->config->reject_list; + ap; ap = ap->next) { + if (addr_eq(packet->client_addr, ap->addr)) { + note("%s from %s rejected.", type, piaddr(ap->addr)); + return; + } + } + (*handler)(packet); +} + +void +dhcpoffer(struct packet *packet) +{ + struct interface_info *ip = packet->interface; + struct client_lease *lease, *lp; + int i; + int arp_timeout_needed, stop_selecting; + char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ? + "DHCPOFFER" : "BOOTREPLY"; + + /* If we're not receptive to an offer right now, or if the offer + has an unrecognizable transaction id, then just drop it. */ + if (ip->client->state != S_SELECTING || + 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; + + note("%s from %s", name, piaddr(packet->client_addr)); + + + /* If this lease doesn't supply the minimum required parameters, + blow it off. */ + for (i = 0; ip->client->config->required_options[i]; i++) { + if (!packet->options[ip->client->config-> + required_options[i]].len) { + note("%s isn't satisfactory.", name); + return; + } + } + + /* If we've already seen this lease, don't record it again. */ + for (lease = ip->client->offered_leases; + lease; lease = lease->next) { + if (lease->address.len == sizeof(packet->raw->yiaddr) && + !memcmp(lease->address.iabuf, + &packet->raw->yiaddr, lease->address.len)) { + debug("%s already seen.", name); + return; + } + } + + lease = packet_to_lease(packet); + if (!lease) { + note("packet_to_lease failed."); + return; + } + + /* If this lease was acquired through a BOOTREPLY, record that + fact. */ + if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len) + lease->is_bootp = 1; + + /* Record the medium under which this lease was offered. */ + lease->medium = ip->client->medium; + + /* Send out an ARP Request for the offered IP address. */ + script_init("ARPSEND", lease->medium); + script_write_params("check_", lease); + /* If the script can't send an ARP request without waiting, + we'll be waiting when we do the ARPCHECK, so don't wait now. */ + if (script_go()) + arp_timeout_needed = 0; + else + arp_timeout_needed = 2; + + /* Figure out when we're supposed to stop selecting. */ + stop_selecting = + ip->client->first_sending + ip->client->config->select_interval; + + /* If this is the lease we asked for, put it at the head of the + list, and don't mess with the arp request timeout. */ + if (lease->address.len == ip->client->requested_address.len && + !memcmp(lease->address.iabuf, + ip->client->requested_address.iabuf, + ip->client->requested_address.len)) { + lease->next = ip->client->offered_leases; + ip->client->offered_leases = lease; + } else { + /* If we already have an offer, and arping for this + offer would take us past the selection timeout, + then don't extend the timeout - just hope for the + best. */ + if (ip->client->offered_leases && + (cur_time + arp_timeout_needed) > stop_selecting) + arp_timeout_needed = 0; + + /* Put the lease at the end of the list. */ + lease->next = NULL; + if (!ip->client->offered_leases) + ip->client->offered_leases = lease; + else { + for (lp = ip->client->offered_leases; lp->next; + lp = lp->next) + ; /* nothing */ + lp->next = lease; + } + } + + /* If we're supposed to stop selecting before we've had time + to wait for the ARPREPLY, add some delay to wait for + the ARPREPLY. */ + if (stop_selecting - cur_time < arp_timeout_needed) + stop_selecting = cur_time + arp_timeout_needed; + + /* If the selecting interval has expired, go immediately to + state_selecting(). Otherwise, time out into + state_selecting at the select interval. */ + if (stop_selecting <= 0) + state_selecting(ip); + else { + add_timeout(stop_selecting, state_selecting, ip); + cancel_timeout(send_discover, ip); + } +} + +/* Allocate a client_lease structure and initialize it from the parameters + in the specified packet. */ + +struct client_lease * +packet_to_lease(struct packet *packet) +{ + struct client_lease *lease; + int i; + + lease = malloc(sizeof(struct client_lease)); + + if (!lease) { + warning("dhcpoffer: no memory to record lease."); + return (NULL); + } + + memset(lease, 0, sizeof(*lease)); + + /* Copy the lease options. */ + for (i = 0; i < 256; i++) { + if (packet->options[i].len) { + lease->options[i].data = + malloc(packet->options[i].len + 1); + if (!lease->options[i].data) { + warning("dhcpoffer: no memory for option %d", i); + free_client_lease(lease); + return (NULL); + } else { + memcpy(lease->options[i].data, + packet->options[i].data, + packet->options[i].len); + lease->options[i].len = + packet->options[i].len; + lease->options[i].data[lease->options[i].len] = + 0; + } + if (!check_option(lease,i)) { + /* ignore a bogus lease offer */ + warning("Invalid lease option - ignoring offer"); + free_client_lease(lease); + return (NULL); + } + } + } + + lease->address.len = sizeof(packet->raw->yiaddr); + memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len); + + /* If the server name was filled out, copy it. */ + if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len || + !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) && + packet->raw->sname[0]) { + lease->server_name = malloc(DHCP_SNAME_LEN + 1); + if (!lease->server_name) { + warning("dhcpoffer: no memory for server name."); + free_client_lease(lease); + return (NULL); + } + memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN); + lease->server_name[DHCP_SNAME_LEN]='\0'; + if (!res_hnok(lease->server_name) ) { + warning("Bogus server name %s", lease->server_name ); + free_client_lease(lease); + return (NULL); + } + + } + + /* Ditto for the filename. */ + if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len || + !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) && + packet->raw->file[0]) { + /* Don't count on the NUL terminator. */ + lease->filename = malloc(DHCP_FILE_LEN + 1); + if (!lease->filename) { + warning("dhcpoffer: no memory for filename."); + free_client_lease(lease); + return (NULL); + } + memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN); + lease->filename[DHCP_FILE_LEN]='\0'; + } + return lease; +} + +void +dhcpnak(struct packet *packet) +{ + struct interface_info *ip = packet->interface; + + /* 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("DHCPNAK from %s", piaddr(packet->client_addr)); + + if (!ip->client->active) { + note("DHCPNAK with no active lease.\n"); + return; + } + + free_client_lease(ip->client->active); + ip->client->active = NULL; + + /* Stop sending DHCPREQUEST packets... */ + cancel_timeout(send_request, ip); + + ip->client->state = S_INIT; + state_init(ip); +} + +/* Send out a DHCPDISCOVER packet, and set a timeout to send out another + one after the right interval has expired. If we don't get an offer by + the time we reach the panic interval, call the panic function. */ + +void +send_discover(void *ipp) +{ + struct interface_info *ip = ipp; + int interval, increase = 1; + + DH_DbgPrint(MID_TRACE,("Doing discover on interface %p\n",ip)); + + /* Figure out how long it's been since we started transmitting. */ + interval = cur_time - ip->client->first_sending; + + /* If we're past the panic timeout, call the script and tell it + we haven't found anything for this interface yet. */ + if (interval > ip->client->config->timeout) { + state_panic(ip); + return; + } + + /* If we're selecting media, try the whole list before doing + the exponential backoff, but if we've already received an + offer, stop looping, because we obviously have it right. */ + if (!ip->client->offered_leases && + ip->client->config->media) { + int fail = 0; +again: + if (ip->client->medium) { + ip->client->medium = ip->client->medium->next; + increase = 0; + } + if (!ip->client->medium) { + if (fail) + error("No valid media types for %s!", ip->name); + ip->client->medium = ip->client->config->media; + increase = 1; + } + + note("Trying medium \"%s\" %d", ip->client->medium->string, + increase); + script_init("MEDIUM", ip->client->medium); + if (script_go()) + goto again; + } + + /* + * If we're supposed to increase the interval, do so. If it's + * currently zero (i.e., we haven't sent any packets yet), set + * it to one; otherwise, add to it a random number between zero + * and two times itself. On average, this means that it will + * double with every transmission. + */ + if (increase) { + if (!ip->client->interval) + ip->client->interval = + ip->client->config->initial_interval; + else { + ip->client->interval += (arc4random() >> 2) % + (2 * ip->client->interval); + } + + /* Don't backoff past cutoff. */ + if (ip->client->interval > + ip->client->config->backoff_cutoff) + ip->client->interval = + ((ip->client->config->backoff_cutoff / 2) + + ((arc4random() >> 2) % + ip->client->config->backoff_cutoff)); + } else if (!ip->client->interval) + ip->client->interval = + ip->client->config->initial_interval; + + /* If the backoff would take us to the panic timeout, just use that + as the interval. */ + if (cur_time + ip->client->interval > + ip->client->first_sending + ip->client->config->timeout) + ip->client->interval = + (ip->client->first_sending + + ip->client->config->timeout) - cur_time + 1; + + /* Record the number of seconds since we started sending. */ + if (interval < 65536) + ip->client->packet.secs = htons(interval); + else + ip->client->packet.secs = htons(65535); + ip->client->secs = ip->client->packet.secs; + + note("DHCPDISCOVER on %s to %s port %d interval %d", + ip->name, inet_ntoa(sockaddr_broadcast.sin_addr), + ntohs(sockaddr_broadcast.sin_port), ip->client->interval); + + /* Send out a packet. */ + (void)send_packet(ip, &ip->client->packet, ip->client->packet_length, + inaddr_any, &sockaddr_broadcast, NULL); + + DH_DbgPrint(MID_TRACE,("discover timeout: now %x -> then %x\n", + cur_time, cur_time + ip->client->interval)); + + add_timeout(cur_time + ip->client->interval, send_discover, ip); +} + +/* + * state_panic gets called if we haven't received any offers in a preset + * amount of time. When this happens, we try to use existing leases + * that haven't yet expired, and failing that, we call the client script + * and hope it can do something. + */ +void +state_panic(void *ipp) +{ + struct interface_info *ip = ipp; + struct client_lease *loop = ip->client->active; + struct client_lease *lp; + + note("No DHCPOFFERS received."); + + /* We may not have an active lease, but we may have some + predefined leases that we can try. */ + if (!ip->client->active && ip->client->leases) + goto activate_next; + + /* Run through the list of leases and see if one can be used. */ + while (ip->client->active) { + if (ip->client->active->expiry > cur_time) { + note("Trying recorded lease %s", + piaddr(ip->client->active->address)); + /* Run the client script with the existing + parameters. */ + script_init("TIMEOUT", + ip->client->active->medium); + script_write_params("new_", ip->client->active); + if (ip->client->alias) + script_write_params("alias_", + ip->client->alias); + + /* If the old lease is still good and doesn't + yet need renewal, go into BOUND state and + timeout at the renewal time. */ + if (!script_go()) { + if (cur_time < + ip->client->active->renewal) { + ip->client->state = S_BOUND; + note("bound: renewal in %d seconds.", + ip->client->active->renewal - + cur_time); + add_timeout( + ip->client->active->renewal, + state_bound, ip); + } else { + ip->client->state = S_BOUND; + note("bound: immediate renewal."); + state_bound(ip); + } + reinitialize_interfaces(); + //go_daemon(); + return; + } + } + + /* If there are no other leases, give up. */ + if (!ip->client->leases) { + ip->client->leases = ip->client->active; + ip->client->active = NULL; + break; + } + +activate_next: + /* Otherwise, put the active lease at the end of the + lease list, and try another lease.. */ + for (lp = ip->client->leases; lp->next; lp = lp->next) + ; + lp->next = ip->client->active; + if (lp->next) + lp->next->next = NULL; + ip->client->active = ip->client->leases; + ip->client->leases = ip->client->leases->next; + + /* If we already tried this lease, we've exhausted the + set of leases, so we might as well give up for + now. */ + if (ip->client->active == loop) + break; + else if (!loop) + loop = ip->client->active; + } + + /* No leases were available, or what was available didn't work, so + tell the shell script that we failed to allocate an address, + and try again later. */ + note("No working leases in persistent database - sleeping.\n"); + script_init("FAIL", NULL); + if (ip->client->alias) + script_write_params("alias_", ip->client->alias); + script_go(); + ip->client->state = S_INIT; + add_timeout(cur_time + ip->client->config->retry_interval, state_init, + ip); +// go_daemon(); +} + +void +send_request(void *ipp) +{ + struct interface_info *ip = ipp; + struct sockaddr_in destination; + struct in_addr from; + int interval; + + /* Figure out how long it's been since we started transmitting. */ + interval = cur_time - ip->client->first_sending; + + /* If we're in the INIT-REBOOT or REQUESTING state and we're + past the reboot timeout, go to INIT and see if we can + DISCOVER an address... */ + /* XXX In the INIT-REBOOT state, if we don't get an ACK, it + means either that we're on a network with no DHCP server, + or that our server is down. In the latter case, assuming + that there is a backup DHCP server, DHCPDISCOVER will get + us a new address, but we could also have successfully + reused our old address. In the former case, we're hosed + anyway. This is not a win-prone situation. */ + if ((ip->client->state == S_REBOOTING || + ip->client->state == S_REQUESTING) && + interval > ip->client->config->reboot_timeout) { +cancel: + ip->client->state = S_INIT; + cancel_timeout(send_request, ip); + state_init(ip); + return; + } + + /* If we're in the reboot state, make sure the media is set up + correctly. */ + if (ip->client->state == S_REBOOTING && + !ip->client->medium && + ip->client->active->medium ) { + script_init("MEDIUM", ip->client->active->medium); + + /* If the medium we chose won't fly, go to INIT state. */ + if (script_go()) + goto cancel; + + /* Record the medium. */ + ip->client->medium = ip->client->active->medium; + } + + /* If the lease has expired, relinquish the address and go back + to the INIT state. */ + if (ip->client->state != S_REQUESTING && + cur_time > ip->client->active->expiry) { + /* Run the client script with the new parameters. */ + script_init("EXPIRE", NULL); + script_write_params("old_", ip->client->active); + if (ip->client->alias) + script_write_params("alias_", ip->client->alias); + script_go(); + + /* Now do a preinit on the interface so that we can + discover a new address. */ + script_init("PREINIT", NULL); + if (ip->client->alias) + script_write_params("alias_", ip->client->alias); + script_go(); + + ip->client->state = S_INIT; + state_init(ip); + return; + } + + /* Do the exponential backoff... */ + if (!ip->client->interval) + ip->client->interval = ip->client->config->initial_interval; + else + ip->client->interval += ((arc4random() >> 2) % + (2 * ip->client->interval)); + + /* Don't backoff past cutoff. */ + if (ip->client->interval > + ip->client->config->backoff_cutoff) + ip->client->interval = + ((ip->client->config->backoff_cutoff / 2) + + ((arc4random() >> 2) % ip->client->interval)); + + /* If the backoff would take us to the expiry time, just set the + timeout to the expiry time. */ + if (ip->client->state != S_REQUESTING && + cur_time + ip->client->interval > + ip->client->active->expiry) + ip->client->interval = + ip->client->active->expiry - cur_time + 1; + + /* If the lease T2 time has elapsed, or if we're not yet bound, + broadcast the DHCPREQUEST rather than unicasting. */ + memset(&destination, 0, sizeof(destination)); + if (ip->client->state == S_REQUESTING || + ip->client->state == S_REBOOTING || + cur_time > ip->client->active->rebind) + destination.sin_addr.s_addr = INADDR_BROADCAST; + else + memcpy(&destination.sin_addr.s_addr, + ip->client->destination.iabuf, + sizeof(destination.sin_addr.s_addr)); + destination.sin_port = htons(REMOTE_PORT); + destination.sin_family = AF_INET; +// destination.sin_len = sizeof(destination); + + if (ip->client->state != S_REQUESTING) + memcpy(&from, ip->client->active->address.iabuf, + sizeof(from)); + else + from.s_addr = INADDR_ANY; + + /* Record the number of seconds since we started sending. */ + if (ip->client->state == S_REQUESTING) + ip->client->packet.secs = ip->client->secs; + else { + if (interval < 65536) + ip->client->packet.secs = htons(interval); + else + ip->client->packet.secs = htons(65535); + } + + note("DHCPREQUEST on %s to %s port %d", ip->name, + inet_ntoa(destination.sin_addr), ntohs(destination.sin_port)); + + /* Send out a packet. */ + (void) send_packet(ip, &ip->client->packet, ip->client->packet_length, + from, &destination, NULL); + + add_timeout(cur_time + ip->client->interval, send_request, ip); +} + +void +send_decline(void *ipp) +{ + struct interface_info *ip = ipp; + + note("DHCPDECLINE on %s to %s port %d", ip->name, + inet_ntoa(sockaddr_broadcast.sin_addr), + ntohs(sockaddr_broadcast.sin_port)); + + /* Send out a packet. */ + (void) send_packet(ip, &ip->client->packet, ip->client->packet_length, + inaddr_any, &sockaddr_broadcast, NULL); +} + +void +make_discover(struct interface_info *ip, struct client_lease *lease) +{ + unsigned char discover = DHCPDISCOVER; + struct tree_cache *options[256]; + struct tree_cache option_elements[256]; + int i; + + memset(option_elements, 0, sizeof(option_elements)); + memset(options, 0, sizeof(options)); + memset(&ip->client->packet, 0, sizeof(ip->client->packet)); + + /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */ + i = DHO_DHCP_MESSAGE_TYPE; + options[i] = &option_elements[i]; + options[i]->value = &discover; + options[i]->len = sizeof(discover); + options[i]->buf_size = sizeof(discover); + options[i]->timeout = 0xFFFFFFFF; + + /* Request the options we want */ + i = DHO_DHCP_PARAMETER_REQUEST_LIST; + options[i] = &option_elements[i]; + options[i]->value = ip->client->config->requested_options; + options[i]->len = ip->client->config->requested_option_count; + options[i]->buf_size = + ip->client->config->requested_option_count; + options[i]->timeout = 0xFFFFFFFF; + + /* If we had an address, try to get it again. */ + if (lease) { + ip->client->requested_address = lease->address; + i = DHO_DHCP_REQUESTED_ADDRESS; + options[i] = &option_elements[i]; + options[i]->value = lease->address.iabuf; + options[i]->len = lease->address.len; + options[i]->buf_size = lease->address.len; + options[i]->timeout = 0xFFFFFFFF; + } else + ip->client->requested_address.len = 0; + + /* Send any options requested in the config file. */ + for (i = 0; i < 256; i++) + if (!options[i] && + ip->client->config->send_options[i].data) { + options[i] = &option_elements[i]; + options[i]->value = + ip->client->config->send_options[i].data; + options[i]->len = + ip->client->config->send_options[i].len; + options[i]->buf_size = + ip->client->config->send_options[i].len; + options[i]->timeout = 0xFFFFFFFF; + } + + /* Set up the option buffer... */ + ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, + options, 0, 0, 0, NULL, 0); + if (ip->client->packet_length < BOOTP_MIN_LEN) + ip->client->packet_length = BOOTP_MIN_LEN; + + ip->client->packet.op = BOOTREQUEST; + ip->client->packet.htype = ip->hw_address.htype; + ip->client->packet.hlen = ip->hw_address.hlen; + ip->client->packet.hops = 0; + ip->client->packet.xid = arc4random(); + ip->client->packet.secs = 0; /* filled in by send_discover. */ + ip->client->packet.flags = 0; + + memset(&(ip->client->packet.ciaddr), + 0, sizeof(ip->client->packet.ciaddr)); + memset(&(ip->client->packet.yiaddr), + 0, sizeof(ip->client->packet.yiaddr)); + memset(&(ip->client->packet.siaddr), + 0, sizeof(ip->client->packet.siaddr)); + memset(&(ip->client->packet.giaddr), + 0, sizeof(ip->client->packet.giaddr)); + memcpy(ip->client->packet.chaddr, + ip->hw_address.haddr, ip->hw_address.hlen); +} + + +void +make_request(struct interface_info *ip, struct client_lease * lease) +{ + unsigned char request = DHCPREQUEST; + struct tree_cache *options[256]; + struct tree_cache option_elements[256]; + int i; + + memset(options, 0, sizeof(options)); + memset(&ip->client->packet, 0, sizeof(ip->client->packet)); + + /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */ + i = DHO_DHCP_MESSAGE_TYPE; + options[i] = &option_elements[i]; + options[i]->value = &request; + options[i]->len = sizeof(request); + options[i]->buf_size = sizeof(request); + options[i]->timeout = 0xFFFFFFFF; + + /* Request the options we want */ + i = DHO_DHCP_PARAMETER_REQUEST_LIST; + options[i] = &option_elements[i]; + options[i]->value = ip->client->config->requested_options; + options[i]->len = ip->client->config->requested_option_count; + options[i]->buf_size = + ip->client->config->requested_option_count; + options[i]->timeout = 0xFFFFFFFF; + + /* If we are requesting an address that hasn't yet been assigned + to us, use the DHCP Requested Address option. */ + if (ip->client->state == S_REQUESTING) { + /* Send back the server identifier... */ + i = DHO_DHCP_SERVER_IDENTIFIER; + options[i] = &option_elements[i]; + options[i]->value = lease->options[i].data; + options[i]->len = lease->options[i].len; + options[i]->buf_size = lease->options[i].len; + options[i]->timeout = 0xFFFFFFFF; + } + if (ip->client->state == S_REQUESTING || + ip->client->state == S_REBOOTING) { + ip->client->requested_address = lease->address; + i = DHO_DHCP_REQUESTED_ADDRESS; + options[i] = &option_elements[i]; + options[i]->value = lease->address.iabuf; + options[i]->len = lease->address.len; + options[i]->buf_size = lease->address.len; + options[i]->timeout = 0xFFFFFFFF; + } else + ip->client->requested_address.len = 0; + + /* Send any options requested in the config file. */ + for (i = 0; i < 256; i++) + if (!options[i] && + ip->client->config->send_options[i].data) { + options[i] = &option_elements[i]; + options[i]->value = + ip->client->config->send_options[i].data; + options[i]->len = + ip->client->config->send_options[i].len; + options[i]->buf_size = + ip->client->config->send_options[i].len; + options[i]->timeout = 0xFFFFFFFF; + } + + /* Set up the option buffer... */ + ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, + options, 0, 0, 0, NULL, 0); + if (ip->client->packet_length < BOOTP_MIN_LEN) + ip->client->packet_length = BOOTP_MIN_LEN; + + ip->client->packet.op = BOOTREQUEST; + ip->client->packet.htype = ip->hw_address.htype; + ip->client->packet.hlen = ip->hw_address.hlen; + ip->client->packet.hops = 0; + ip->client->packet.xid = ip->client->xid; + ip->client->packet.secs = 0; /* Filled in by send_request. */ + + /* If we own the address we're requesting, put it in ciaddr; + otherwise set ciaddr to zero. */ + if (ip->client->state == S_BOUND || + ip->client->state == S_RENEWING || + ip->client->state == S_REBINDING) { + memcpy(&ip->client->packet.ciaddr, + lease->address.iabuf, lease->address.len); + ip->client->packet.flags = 0; + } else { + memset(&ip->client->packet.ciaddr, 0, + sizeof(ip->client->packet.ciaddr)); + ip->client->packet.flags = 0; + } + + memset(&ip->client->packet.yiaddr, 0, + sizeof(ip->client->packet.yiaddr)); + memset(&ip->client->packet.siaddr, 0, + sizeof(ip->client->packet.siaddr)); + memset(&ip->client->packet.giaddr, 0, + sizeof(ip->client->packet.giaddr)); + memcpy(ip->client->packet.chaddr, + ip->hw_address.haddr, ip->hw_address.hlen); +} + +void +make_decline(struct interface_info *ip, struct client_lease *lease) +{ + struct tree_cache *options[256], message_type_tree; + struct tree_cache requested_address_tree; + struct tree_cache server_id_tree, client_id_tree; + unsigned char decline = DHCPDECLINE; + int i; + + memset(options, 0, sizeof(options)); + memset(&ip->client->packet, 0, sizeof(ip->client->packet)); + + /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */ + i = DHO_DHCP_MESSAGE_TYPE; + options[i] = &message_type_tree; + options[i]->value = &decline; + options[i]->len = sizeof(decline); + options[i]->buf_size = sizeof(decline); + options[i]->timeout = 0xFFFFFFFF; + + /* Send back the server identifier... */ + i = DHO_DHCP_SERVER_IDENTIFIER; + options[i] = &server_id_tree; + options[i]->value = lease->options[i].data; + options[i]->len = lease->options[i].len; + options[i]->buf_size = lease->options[i].len; + options[i]->timeout = 0xFFFFFFFF; + + /* Send back the address we're declining. */ + i = DHO_DHCP_REQUESTED_ADDRESS; + options[i] = &requested_address_tree; + options[i]->value = lease->address.iabuf; + options[i]->len = lease->address.len; + options[i]->buf_size = lease->address.len; + options[i]->timeout = 0xFFFFFFFF; + + /* Send the uid if the user supplied one. */ + i = DHO_DHCP_CLIENT_IDENTIFIER; + if (ip->client->config->send_options[i].len) { + options[i] = &client_id_tree; + options[i]->value = ip->client->config->send_options[i].data; + options[i]->len = ip->client->config->send_options[i].len; + options[i]->buf_size = ip->client->config->send_options[i].len; + options[i]->timeout = 0xFFFFFFFF; + } + + + /* Set up the option buffer... */ + ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, + options, 0, 0, 0, NULL, 0); + if (ip->client->packet_length < BOOTP_MIN_LEN) + ip->client->packet_length = BOOTP_MIN_LEN; + + ip->client->packet.op = BOOTREQUEST; + ip->client->packet.htype = ip->hw_address.htype; + ip->client->packet.hlen = ip->hw_address.hlen; + ip->client->packet.hops = 0; + ip->client->packet.xid = ip->client->xid; + ip->client->packet.secs = 0; /* Filled in by send_request. */ + ip->client->packet.flags = 0; + + /* ciaddr must always be zero. */ + memset(&ip->client->packet.ciaddr, 0, + sizeof(ip->client->packet.ciaddr)); + memset(&ip->client->packet.yiaddr, 0, + sizeof(ip->client->packet.yiaddr)); + memset(&ip->client->packet.siaddr, 0, + sizeof(ip->client->packet.siaddr)); + memset(&ip->client->packet.giaddr, 0, + sizeof(ip->client->packet.giaddr)); + memcpy(ip->client->packet.chaddr, + ip->hw_address.haddr, ip->hw_address.hlen); +} + +void +free_client_lease(struct client_lease *lease) +{ + int i; + + if (lease->server_name) + free(lease->server_name); + if (lease->filename) + free(lease->filename); + for (i = 0; i < 256; i++) { + if (lease->options[i].len) + free(lease->options[i].data); + } + free(lease); +} + +FILE *leaseFile; + +void +rewrite_client_leases(void) +{ + struct client_lease *lp; + + if (!leaseFile) { + leaseFile = fopen(path_dhclient_db, "w"); + if (!leaseFile) + error("can't create %s: %m", path_dhclient_db); + } else { + fflush(leaseFile); + rewind(leaseFile); + } + + for (lp = ifi->client->leases; lp; lp = lp->next) + write_client_lease(ifi, lp, 1); + if (ifi->client->active) + write_client_lease(ifi, ifi->client->active, 1); + + fflush(leaseFile); +// ftruncate(fileno(leaseFile), ftello(leaseFile)); +// fsync(fileno(leaseFile)); +} + +void +write_client_lease(struct interface_info *ip, struct client_lease *lease, + int rewrite) +{ + static int leases_written; + struct tm *t; + int i; + + if (!rewrite) { + if (leases_written++ > 20) { + rewrite_client_leases(); + leases_written = 0; + } + } + + /* If the lease came from the config file, we don't need to stash + a copy in the lease database. */ + if (lease->is_static) + return; + + if (!leaseFile) { /* XXX */ + leaseFile = fopen(path_dhclient_db, "w"); + if (!leaseFile) + error("can't create %s: %m", path_dhclient_db); + } + + fprintf(leaseFile, "lease {\n"); + if (lease->is_bootp) + fprintf(leaseFile, " bootp;\n"); + fprintf(leaseFile, " interface \"%s\";\n", ip->name); + fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address)); + if (lease->filename) + fprintf(leaseFile, " filename \"%s\";\n", lease->filename); + if (lease->server_name) + fprintf(leaseFile, " server-name \"%s\";\n", + lease->server_name); + if (lease->medium) + fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string); + for (i = 0; i < 256; i++) + if (lease->options[i].len) + fprintf(leaseFile, " option %s %s;\n", + dhcp_options[i].name, + pretty_print_option(i, lease->options[i].data, + lease->options[i].len, 1, 1)); + + t = gmtime(&lease->renewal); + fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n", + t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); + t = gmtime(&lease->rebind); + fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n", + t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); + t = gmtime(&lease->expiry); + fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n", + t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); + fprintf(leaseFile, "}\n"); + fflush(leaseFile); +} + +void +script_init(char *reason, struct string_list *medium) +{ + size_t len, mediumlen = 0; + struct imsg_hdr hdr; + struct buf *buf; + int errs; + + if (medium != NULL && medium->string != NULL) + mediumlen = strlen(medium->string); + + hdr.code = IMSG_SCRIPT_INIT; + hdr.len = sizeof(struct imsg_hdr) + + sizeof(size_t) + mediumlen + + sizeof(size_t) + strlen(reason); + + if ((buf = buf_open(hdr.len)) == NULL) + error("buf_open: %m"); + + errs = 0; + errs += buf_add(buf, &hdr, sizeof(hdr)); + errs += buf_add(buf, &mediumlen, sizeof(mediumlen)); + if (mediumlen > 0) + errs += buf_add(buf, medium->string, mediumlen); + len = strlen(reason); + errs += buf_add(buf, &len, sizeof(len)); + errs += buf_add(buf, reason, len); + + if (errs) + error("buf_add: %m"); + + if (buf_close(privfd, buf) == -1) + error("buf_close: %m"); +} + +void +priv_script_init(char *reason, char *medium) +{ + struct interface_info *ip = ifi; + + if (ip) { + // XXX Do we need to do anything? + } +} + +void +priv_script_write_params(char *prefix, struct client_lease *lease) +{ + struct interface_info *ip = ifi; + u_int8_t dbuf[1500]; + int i, len = 0; + char tbuf[128]; + +#if 0 + script_set_env(ip->client, prefix, "ip_address", + piaddr(lease->address)); +#endif + + if (lease->options[DHO_SUBNET_MASK].len && + (lease->options[DHO_SUBNET_MASK].len < + sizeof(lease->address.iabuf))) { + struct iaddr netmask, subnet, broadcast; + + memcpy(netmask.iabuf, lease->options[DHO_SUBNET_MASK].data, + lease->options[DHO_SUBNET_MASK].len); + netmask.len = lease->options[DHO_SUBNET_MASK].len; + + subnet = subnet_number(lease->address, netmask); + if (subnet.len) { +#if 0 + script_set_env(ip->client, prefix, "network_number", + piaddr(subnet)); +#endif + if (!lease->options[DHO_BROADCAST_ADDRESS].len) { + broadcast = broadcast_addr(subnet, netmask); + if (broadcast.len) +#if 0 + script_set_env(ip->client, prefix, + "broadcast_address", + piaddr(broadcast)); +#else + ; +#endif + } + } + } + +#if 0 + if (lease->filename) + script_set_env(ip->client, prefix, "filename", lease->filename); + if (lease->server_name) + script_set_env(ip->client, prefix, "server_name", + lease->server_name); +#endif + + for (i = 0; i < 256; i++) { + u_int8_t *dp = NULL; + + if (ip->client->config->defaults[i].len) { + if (lease->options[i].len) { + switch ( + ip->client->config->default_actions[i]) { + case ACTION_DEFAULT: + dp = lease->options[i].data; + len = lease->options[i].len; + break; + case ACTION_SUPERSEDE: +supersede: + dp = ip->client-> + config->defaults[i].data; + len = ip->client-> + config->defaults[i].len; + break; + case ACTION_PREPEND: + len = ip->client-> + config->defaults[i].len + + lease->options[i].len; + if (len > sizeof(dbuf)) { + warning("no space to %s %s", + "prepend option", + dhcp_options[i].name); + goto supersede; + } + dp = dbuf; + memcpy(dp, + ip->client-> + config->defaults[i].data, + ip->client-> + config->defaults[i].len); + memcpy(dp + ip->client-> + config->defaults[i].len, + lease->options[i].data, + lease->options[i].len); + dp[len] = '\0'; + break; + case ACTION_APPEND: + len = ip->client-> + config->defaults[i].len + + lease->options[i].len; + if (len > sizeof(dbuf)) { + warning("no space to %s %s", + "append option", + dhcp_options[i].name); + goto supersede; + } + dp = dbuf; + memcpy(dp, + lease->options[i].data, + lease->options[i].len); + memcpy(dp + lease->options[i].len, + ip->client-> + config->defaults[i].data, + ip->client-> + config->defaults[i].len); + dp[len] = '\0'; + } + } else { + dp = ip->client-> + config->defaults[i].data; + len = ip->client-> + config->defaults[i].len; + } + } else if (lease->options[i].len) { + len = lease->options[i].len; + dp = lease->options[i].data; + } else { + len = 0; + } +#if 0 + if (len) { + char name[256]; + + if (dhcp_option_ev_name(name, sizeof(name), + &dhcp_options[i])) + script_set_env(ip->client, prefix, name, + pretty_print_option(i, dp, len, 0, 0)); + } +#endif + } +#if 0 + snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry); + script_set_env(ip->client, prefix, "expiry", tbuf); +#endif +} + +void +script_write_params(char *prefix, struct client_lease *lease) +{ + size_t fn_len = 0, sn_len = 0, pr_len = 0; + struct imsg_hdr hdr; + struct buf *buf; + int errs, i; + + if (lease->filename != NULL) + fn_len = strlen(lease->filename); + if (lease->server_name != NULL) + sn_len = strlen(lease->server_name); + if (prefix != NULL) + pr_len = strlen(prefix); + + hdr.code = IMSG_SCRIPT_WRITE_PARAMS; + hdr.len = sizeof(hdr) + sizeof(struct client_lease) + + sizeof(size_t) + fn_len + sizeof(size_t) + sn_len + + sizeof(size_t) + pr_len; + + for (i = 0; i < 256; i++) + hdr.len += sizeof(int) + lease->options[i].len; + + scripttime = time(NULL); + + if ((buf = buf_open(hdr.len)) == NULL) + error("buf_open: %m"); + + errs = 0; + errs += buf_add(buf, &hdr, sizeof(hdr)); + errs += buf_add(buf, lease, sizeof(struct client_lease)); + errs += buf_add(buf, &fn_len, sizeof(fn_len)); + errs += buf_add(buf, lease->filename, fn_len); + errs += buf_add(buf, &sn_len, sizeof(sn_len)); + errs += buf_add(buf, lease->server_name, sn_len); + errs += buf_add(buf, &pr_len, sizeof(pr_len)); + errs += buf_add(buf, prefix, pr_len); + + for (i = 0; i < 256; i++) { + errs += buf_add(buf, &lease->options[i].len, + sizeof(lease->options[i].len)); + errs += buf_add(buf, lease->options[i].data, + lease->options[i].len); + } + + if (errs) + error("buf_add: %m"); + + if (buf_close(privfd, buf) == -1) + error("buf_close: %m"); +} + +int +script_go(void) +{ + struct imsg_hdr hdr; + struct buf *buf; + int ret; + + scripttime = time(NULL); + + hdr.code = IMSG_SCRIPT_GO; + hdr.len = sizeof(struct imsg_hdr); + + if ((buf = buf_open(hdr.len)) == NULL) + error("buf_open: %m"); + + if (buf_add(buf, &hdr, sizeof(hdr))) + error("buf_add: %m"); + + if (buf_close(privfd, buf) == -1) + error("buf_close: %m"); + + memset(&hdr, 0, sizeof(hdr)); + //bzero(&hdr, sizeof(hdr)); + buf_read(privfd, &hdr, sizeof(hdr)); + if (hdr.code != IMSG_SCRIPT_GO_RET) + error("unexpected msg type %u", hdr.code); + if (hdr.len != sizeof(hdr) + sizeof(int)) + error("received corrupted message"); + buf_read(privfd, &ret, sizeof(ret)); + + return (ret); +} + +#if 0 +int +priv_script_go(void) +{ + char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI"; + static char client_path[] = CLIENT_PATH; + struct interface_info *ip = ifi; + int pid, wpid, wstatus; + + scripttime = time(NULL); + + if (ip) { + scriptName = ip->client->config->script_name; + envp = ip->client->scriptEnv; + } else { + scriptName = top_level_config.script_name; + epp[0] = reason; + epp[1] = client_path; + epp[2] = NULL; + envp = epp; + } + + argv[0] = scriptName; + argv[1] = NULL; + + pid = fork(); + if (pid < 0) { + error("fork: %m"); + wstatus = 0; + } else if (pid) { + do { + wpid = wait(&wstatus); + } while (wpid != pid && wpid > 0); + if (wpid < 0) { + error("wait: %m"); + wstatus = 0; + } + } else { + execve(scriptName, argv, envp); + error("execve (%s, ...): %m", scriptName); + } + + if (ip) + script_flush_env(ip->client); + + return (wstatus & 0xff); +} +#endif + +#if 0 +void +script_set_env(struct client_state *client, const char *prefix, + const char *name, const char *value) +{ + int i, j, namelen; + + namelen = strlen(name); + + for (i = 0; client->scriptEnv[i]; i++) + if (strncmp(client->scriptEnv[i], name, namelen) == 0 && + client->scriptEnv[i][namelen] == '=') + break; + + if (client->scriptEnv[i]) + /* Reuse the slot. */ + free(client->scriptEnv[i]); + else { + /* New variable. Expand if necessary. */ + if (i >= client->scriptEnvsize - 1) { + char **newscriptEnv; + int newscriptEnvsize = client->scriptEnvsize + 50; + + newscriptEnv = realloc(client->scriptEnv, + newscriptEnvsize); + if (newscriptEnv == NULL) { + free(client->scriptEnv); + client->scriptEnv = NULL; + client->scriptEnvsize = 0; + error("script_set_env: no memory for variable"); + } + client->scriptEnv = newscriptEnv; + client->scriptEnvsize = newscriptEnvsize; + } + /* need to set the NULL pointer at end of array beyond + the new slot. */ + client->scriptEnv[i + 1] = NULL; + } + /* Allocate space and format the variable in the appropriate slot. */ + client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 + + strlen(value) + 1); + if (client->scriptEnv[i] == NULL) + error("script_set_env: no memory for variable assignment"); + + /* No `` or $() command substitution allowed in environment values! */ + for (j=0; j < strlen(value); j++) + switch (value[j]) { + case '`': + case '$': + error("illegal character (%c) in value '%s'", value[j], + value); + /* not reached */ + } + snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) + + 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value); +} + +void +script_flush_env(struct client_state *client) +{ + int i; + + for (i = 0; client->scriptEnv[i]; i++) { + free(client->scriptEnv[i]); + client->scriptEnv[i] = NULL; + } + client->scriptEnvsize = 0; +} +#endif + +int +dhcp_option_ev_name(char *buf, size_t buflen, struct dhcp_option *option) +{ + int i; + + for (i = 0; option->name[i]; i++) { + if (i + 1 == buflen) + return 0; + if (option->name[i] == '-') + buf[i] = '_'; + else + buf[i] = option->name[i]; + } + + buf[i] = 0; + return 1; +} + +#if 0 +void +go_daemon(void) +{ + static int state = 0; + + if (no_daemon || state) + return; + + state = 1; + + /* Stop logging to stderr... */ + log_perror = 0; + + if (daemon(1, 0) == -1) + error("daemon"); + + /* we are chrooted, daemon(3) fails to open /dev/null */ + if (nullfd != -1) { + dup2(nullfd, STDIN_FILENO); + dup2(nullfd, STDOUT_FILENO); + dup2(nullfd, STDERR_FILENO); + close(nullfd); + nullfd = -1; + } +} +#endif + +int +check_option(struct client_lease *l, int option) +{ + char *opbuf; + char *sbuf; + + /* we use this, since this is what gets passed to dhclient-script */ + + opbuf = pretty_print_option(option, l->options[option].data, + l->options[option].len, 0, 0); + + sbuf = option_as_string(option, l->options[option].data, + l->options[option].len); + + switch (option) { + case DHO_SUBNET_MASK: + case DHO_TIME_SERVERS: + case DHO_NAME_SERVERS: + case DHO_ROUTERS: + case DHO_DOMAIN_NAME_SERVERS: + case DHO_LOG_SERVERS: + case DHO_COOKIE_SERVERS: + case DHO_LPR_SERVERS: + case DHO_IMPRESS_SERVERS: + case DHO_RESOURCE_LOCATION_SERVERS: + case DHO_SWAP_SERVER: + case DHO_BROADCAST_ADDRESS: + case DHO_NIS_SERVERS: + case DHO_NTP_SERVERS: + case DHO_NETBIOS_NAME_SERVERS: + case DHO_NETBIOS_DD_SERVER: + case DHO_FONT_SERVERS: + case DHO_DHCP_SERVER_IDENTIFIER: + if (!ipv4addrs(opbuf)) { + warning("Invalid IP address in option: %s", opbuf); + return (0); + } + return (1) ; + case DHO_HOST_NAME: + case DHO_DOMAIN_NAME: + case DHO_NIS_DOMAIN: + if (!res_hnok(sbuf)) { + warning("Bogus Host Name option %d: %s (%s)", option, + sbuf, opbuf); + return (0); + } + return (1); + case DHO_PAD: + case DHO_TIME_OFFSET: + case DHO_BOOT_SIZE: + case DHO_MERIT_DUMP: + case DHO_ROOT_PATH: + case DHO_EXTENSIONS_PATH: + case DHO_IP_FORWARDING: + case DHO_NON_LOCAL_SOURCE_ROUTING: + case DHO_POLICY_FILTER: + case DHO_MAX_DGRAM_REASSEMBLY: + case DHO_DEFAULT_IP_TTL: + case DHO_PATH_MTU_AGING_TIMEOUT: + case DHO_PATH_MTU_PLATEAU_TABLE: + case DHO_INTERFACE_MTU: + case DHO_ALL_SUBNETS_LOCAL: + case DHO_PERFORM_MASK_DISCOVERY: + case DHO_MASK_SUPPLIER: + case DHO_ROUTER_DISCOVERY: + case DHO_ROUTER_SOLICITATION_ADDRESS: + case DHO_STATIC_ROUTES: + case DHO_TRAILER_ENCAPSULATION: + case DHO_ARP_CACHE_TIMEOUT: + case DHO_IEEE802_3_ENCAPSULATION: + case DHO_DEFAULT_TCP_TTL: + case DHO_TCP_KEEPALIVE_INTERVAL: + case DHO_TCP_KEEPALIVE_GARBAGE: + case DHO_VENDOR_ENCAPSULATED_OPTIONS: + case DHO_NETBIOS_NODE_TYPE: + case DHO_NETBIOS_SCOPE: + case DHO_X_DISPLAY_MANAGER: + case DHO_DHCP_REQUESTED_ADDRESS: + case DHO_DHCP_LEASE_TIME: + case DHO_DHCP_OPTION_OVERLOAD: + case DHO_DHCP_MESSAGE_TYPE: + case DHO_DHCP_PARAMETER_REQUEST_LIST: + case DHO_DHCP_MESSAGE: + case DHO_DHCP_MAX_MESSAGE_SIZE: + case DHO_DHCP_RENEWAL_TIME: + case DHO_DHCP_REBINDING_TIME: + case DHO_DHCP_CLASS_IDENTIFIER: + case DHO_DHCP_CLIENT_IDENTIFIER: + case DHO_DHCP_USER_CLASS_ID: + case DHO_END: + return (1); + default: + warning("unknown dhcp option value 0x%x", option); + return (unknown_ok); + } +} + +int +res_hnok(const char *dn) +{ + int pch = PERIOD, ch = *dn++; + + while (ch != '\0') { + int nch = *dn++; + + if (periodchar(ch)) { + ; + } else if (periodchar(pch)) { + if (!borderchar(ch)) + return (0); + } else if (periodchar(nch) || nch == '\0') { + if (!borderchar(ch)) + return (0); + } else { + if (!middlechar(ch)) + return (0); + } + pch = ch, ch = nch; + } + return (1); +} + +/* Does buf consist only of dotted decimal ipv4 addrs? + * return how many if so, + * otherwise, return 0 + */ +int +ipv4addrs(char * buf) +{ + struct in_addr jnk; + int count = 0; + + while (inet_aton(buf, &jnk) == 1){ + count++; + while (periodchar(*buf) || digitchar(*buf)) + buf++; + if (*buf == '\0') + return (count); + while (*buf == ' ') + buf++; + } + return (0); +} + + +char * +option_as_string(unsigned int code, unsigned char *data, int len) +{ + static char optbuf[32768]; /* XXX */ + char *op = optbuf; + int opleft = sizeof(optbuf); + unsigned char *dp = data; + + if (code > 255) + error("option_as_string: bad code %d", code); + + for (; dp < data + len; dp++) { + if (!isascii(*dp) || !isprint(*dp)) { + if (dp + 1 != data + len || *dp != 0) { + snprintf(op, opleft, "\\%03o", *dp); + op += 4; + opleft -= 4; + } + } else if (*dp == '"' || *dp == '\'' || *dp == '$' || + *dp == '`' || *dp == '\\') { + *op++ = '\\'; + *op++ = *dp; + opleft -= 2; + } else { + *op++ = *dp; + opleft--; + } + } + if (opleft < 1) + goto toobig; + *op = 0; + return optbuf; +toobig: + warning("dhcp option too large"); + return ""; +} + +#if 0 +int +fork_privchld(int fd, int fd2) +{ + struct pollfd pfd[1]; + int nfds; + + switch (fork()) { + case -1: + error("cannot fork"); + case 0: + break; + default: + return (0); + } + + setproctitle("%s [priv]", ifi->name); + + dup2(nullfd, STDIN_FILENO); + dup2(nullfd, STDOUT_FILENO); + dup2(nullfd, STDERR_FILENO); + close(nullfd); + close(fd2); + + for (;;) { + pfd[0].fd = fd; + pfd[0].events = POLLIN; + if ((nfds = poll(pfd, 1, INFTIM)) == -1) + if (errno != EINTR) + error("poll error"); + + if (nfds == 0 || !(pfd[0].revents & POLLIN)) + continue; + + dispatch_imsg(fd); + } +} +#endif diff --git a/reactos/subsys/system/dhcp/dhcp.rc b/reactos/subsys/system/dhcp/dhcp.rc new file mode 100644 index 00000000000..35e404f893e --- /dev/null +++ b/reactos/subsys/system/dhcp/dhcp.rc @@ -0,0 +1,6 @@ +/* $Id: regsvr32.rc 12852 2005-01-06 13:58:04Z mf $ */ + +#define REACTOS_STR_FILE_DESCRIPTION "DHCP Client Service" +#define REACTOS_STR_INTERNAL_NAME "dhcp\0" +#define REACTOS_STR_ORIGINAL_FILENAME "dhcp.exe\0" +#include diff --git a/reactos/subsys/system/dhcp/dhcpmain.c b/reactos/subsys/system/dhcp/dhcpmain.c new file mode 100644 index 00000000000..ea88fc8fe27 --- /dev/null +++ b/reactos/subsys/system/dhcp/dhcpmain.c @@ -0,0 +1,72 @@ +/* $Id:$ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Service + * FILE: subsys/system/dhcp + * PURPOSE: DHCP client service entry point + * PROGRAMMER: Art Yerkes (arty@users.sf.net) + * UPDATE HISTORY: + * Created 03/08/2005 + */ + +#include +#include "dhcpd.h" +#include "version.h" + +typedef struct _DHCP_API_REQUEST { + int type; + UINT flags; + LPDHCPAPI_CLASSID class_id; + DHCP_API_PARAMS_ARRAY vendor_params; + DHCP_API_PARAMS_ARRAY general_params; + LPWSTR request_id, adapter_name; +} DHCP_API_REQUEST; + +typedef struct _DHCP_MANAGED_ADAPTER { + LPWSTR adapter_name, hostname, dns_server; + UINT adapter_index; + struct sockaddr_in address, netmask; + struct interface_info *dhcp_info; +} DHCP_MANAGED_ADAPTER; + +#define DHCP_REQUESTPARAM WM_USER + 0 +#define DHCP_PARAMCHANGE WM_USER + 1 +#define DHCP_CANCELREQUEST WM_USER + 2 +#define DHCP_NOPARAMCHANGE WM_USER + 3 +#define DHCP_MANAGEADAPTER WM_USER + 4 +#define DHCP_UNMANAGEADAPTER WM_USER + 5 + +UINT DhcpEventTimer; +HANDLE DhcpServiceThread; +DWORD DhcpServiceThreadId; +LIST_ENTRY ManagedAdapters; + +LRESULT WINAPI ServiceThread( PVOID Data ) { + MSG msg; + + while( GetMessage( &msg, 0, 0, 0 ) ) { + switch( msg.message ) { + case DHCP_MANAGEADAPTER: + + break; + + case DHCP_UNMANAGEADAPTER: + break; + + case DHCP_REQUESTPARAM: + break; + + case DHCP_CANCELREQUEST: + break; + + case DHCP_PARAMCHANGE: + break; + + case DHCP_NOPARAMCHANGE: + break; + } + } +} + +int main( int argc, char **argv ) { +} diff --git a/reactos/subsys/system/dhcp/dispatch.c b/reactos/subsys/system/dhcp/dispatch.c new file mode 100644 index 00000000000..19f806a7b73 --- /dev/null +++ b/reactos/subsys/system/dhcp/dispatch.c @@ -0,0 +1,579 @@ +/* $OpenBSD: dispatch.c,v 1.31 2004/09/21 04:07:03 david Exp $ */ + +/* + * Copyright 2004 Henning Brauer + * 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 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" +//#include + +//#include +//#include +//#include + +struct protocol *protocols = NULL; +struct timeout *timeouts = NULL; +static struct timeout *free_timeouts = NULL; +static int interfaces_invalidated = FALSE; +void (*bootp_packet_handler)(struct interface_info *, + struct dhcp_packet *, int, unsigned int, + struct iaddr, struct hardware *); + +static int interface_status(struct interface_info *ifinfo); + +/* + * Use getifaddrs() to get a list of all the attached interfaces. For + * each interface that's of type INET and not the loopback interface, + * register that interface with the network I/O software, figure out + * what subnet it's on, and add it to the list of interfaces. + */ +#if 0 +void +discover_interfaces(struct interface_info *iface) +{ + struct ifaddrs *ifap, *ifa; + struct sockaddr_in foo; + struct ifreq *tif; + + if (getifaddrs(&ifap) != 0) + error("getifaddrs failed"); + + for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { + if ((ifa->ifa_flags & IFF_LOOPBACK) || + (ifa->ifa_flags & IFF_POINTOPOINT) || + (!(ifa->ifa_flags & IFF_UP))) + continue; + + + if (strcmp(iface->name, ifa->ifa_name)) + continue; + + /* + * If we have the capability, extract link information + * and record it in a linked list. + */ + if (ifa->ifa_addr->sa_family == AF_LINK) { + struct sockaddr_dl *foo = + (struct sockaddr_dl *)ifa->ifa_addr; + + iface->index = foo->sdl_index; + iface->hw_address.hlen = foo->sdl_alen; + iface->hw_address.htype = HTYPE_ETHER; /* XXX */ + memcpy(iface->hw_address.haddr, + LLADDR(foo), foo->sdl_alen); + } else if (ifa->ifa_addr->sa_family == AF_INET) { + struct iaddr addr; + + memcpy(&foo, ifa->ifa_addr, sizeof(foo)); + if (foo.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) + continue; + if (!iface->ifp) { + int len = IFNAMSIZ + ifa->ifa_addr->sa_len; + if ((tif = malloc(len)) == NULL) + error("no space to remember ifp"); + strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ); + memcpy(&tif->ifr_addr, ifa->ifa_addr, + ifa->ifa_addr->sa_len); + iface->ifp = tif; + iface->primary_address = foo.sin_addr; + } + addr.len = 4; + memcpy(addr.iabuf, &foo.sin_addr.s_addr, addr.len); + } + } + + if (!iface->ifp) + error("%s: not found", iface->name); + + /* Register the interface... */ + if_register_receive(iface); + if_register_send(iface); + add_protocol(iface->name, iface->rfdesc, got_one, iface); + freeifaddrs(ifap); +} +#else +void +discover_interfaces(struct interface_info *iface) +{ + NTSTATUS Status; + ULONG dim; + char TmpName [IFNAMSIZ]; + + PIP_ADAPTER_INFO pAdapterInfo; + PIP_ADAPTER_INFO pAdapter = NULL; + + pAdapterInfo = malloc(sizeof(IP_ADAPTER_INFO)); + dim = sizeof(IP_ADAPTER_INFO); + + if (GetAdaptersInfo( pAdapterInfo, &dim) != ERROR_SUCCESS) { + free(pAdapterInfo); + pAdapterInfo = (IP_ADAPTER_INFO *) malloc (dim); + } + + if ((Status = GetAdaptersInfo( pAdapterInfo, &dim)) != NO_ERROR) { + note("Error %x", Status); + free (pAdapterInfo); + return; + } + + for (pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next) { + /* we only do ethernet */ + note("found: %s %x\n", pAdapter->AdapterName, pAdapter->Address); + if (pAdapter->Type != MIB_IF_TYPE_ETHERNET) { + continue; + } + note ("found ethernet\n"); + + iface->hw_address.hlen = pAdapter->AddressLength; + iface->hw_address.htype = HTYPE_ETHER; + memcpy (&iface->hw_address.haddr[0], + pAdapter->Address, iface->hw_address.hlen); + + if (pAdapter->IpAddressList.IpAddress.String) + iface->primary_address.S_un.S_addr = inet_addr(pAdapter->IpAddressList.IpAddress.String); + + } + if (iface) { + if_register_receive(iface); + if_register_send(iface); + add_protocol(iface->name, iface->rfdesc, got_one, iface); + } + free (pAdapterInfo); +} +#endif + +void +reinitialize_interfaces(void) +{ + interfaces_invalidated = 1; +} + +/* + * Wait for packets to come in using poll(). When a packet comes in, + * call receive_packet to receive the packet and possibly strip hardware + * addressing information from it, and then call through the + * bootp_packet_handler hook to try to do something with it. + */ +void +dispatch(void) +{ + int count, i, to_msec, nfds = 0; + struct protocol *l; + fd_set fds; + time_t howlong; + struct timeval timeval; + + for (l = protocols; l; l = l->next) + nfds++; + + FD_ZERO(&fds); + +// fds = malloc(nfds * sizeof(struct pollfd)); +// if (fds == NULL) +// error("Can't allocate poll structures."); + + do { + DH_DbgPrint(MID_TRACE,("Cycling dispatch()\n")); + /* + * Call any expired timeouts, and then if there's still + * a timeout registered, time out the select call then. + */ + another: + if (timeouts) { + DH_DbgPrint(MID_TRACE,("Some timeouts are available\n")); + + struct timeout *t; + + if (timeouts->when <= cur_time) { + DH_DbgPrint(MID_TRACE,("Calling timeout %x %p %x\n", + timeouts->when, + timeouts->func, + timeouts->what)); + t = timeouts; + timeouts = timeouts->next; + (*(t->func))(t->what); + t->next = free_timeouts; + free_timeouts = t; + goto another; + } + + /* + * Figure timeout in milliseconds, and check for + * potential overflow, so we can cram into an + * int for poll, while not polling with a + * negative timeout and blocking indefinitely. + */ + howlong = timeouts->when - cur_time; + if (howlong > INT_MAX / 1000) + howlong = INT_MAX / 1000; + to_msec = howlong * 1000; + } else + to_msec = -1; + + /* Set up the descriptors to be polled. */ + for (i = 0, l = protocols; l; l = l->next) { + struct interface_info *ip = l->local; + + if (ip && (l->handler != got_one || !ip->dead)) { + DH_DbgPrint(MID_TRACE,("l->fd %d\n", l->fd)); + + FD_SET(l->fd, &fds); +// fds[i].fd = l->fd; +// fds[i].events = POLLIN; +// fds[i].revents = 0; + i++; + } + } + + if (i == 0) + error("No live interfaces to poll on - exiting."); + + /* Wait for a packet or a timeout... XXX */ + timeval.tv_sec = to_msec / 1000; + timeval.tv_usec = (to_msec % 1000) * 1000; + DH_DbgPrint(MID_TRACE,("select(%d,%d.%03d) =>\n", + nfds,timeval.tv_sec,timeval.tv_usec/1000)); + count = select(nfds, &fds, NULL, NULL, &timeval); + DH_DbgPrint(MID_TRACE,(" => %d\n", count)); + + /* Not likely to be transitory... */ + if (count == SOCKET_ERROR) { + if (errno == EAGAIN || errno == EINTR) { + time(&cur_time); + continue; + } else + error("poll: %m"); + } + + /* Get the current time... */ + time(&cur_time); + + i = 0; + for (l = protocols; l; l = l->next) { + struct interface_info *ip; + ip = l->local; + if (!FD_ISSET(l->fd, &fds)) { +//.revents & (POLLIN | POLLHUP))) { +// fds[i].revents = 0; + if (ip && (l->handler != got_one || + !ip->dead)) { + DH_DbgPrint(MID_TRACE,("Handling %x\n", l)); + (*(l->handler))(l); + if (interfaces_invalidated) + break; + } + i++; + } + interfaces_invalidated = 0; + } + DH_DbgPrint(MID_TRACE,("Done\n")); + } while (1); +} + +void +got_one(struct protocol *l) +{ + struct sockaddr_in from; + struct hardware hfrom; + struct iaddr ifrom; + ssize_t result; + union { + /* + * Packet input buffer. Must be as large as largest + * possible MTU. + */ + unsigned char packbuf[4095]; + struct dhcp_packet packet; + } u; + struct interface_info *ip = l->local; + + if ((result = receive_packet(ip, u.packbuf, sizeof(u), &from, + &hfrom)) == -1) { + warning("receive_packet failed on %s: %s", ip->name, + strerror(errno)); + ip->errors++; + if ((!interface_status(ip)) || + (ip->noifmedia && ip->errors > 20)) { + /* our interface has gone away. */ + warning("Interface %s no longer appears valid.", + ip->name); + ip->dead = 1; + interfaces_invalidated = 1; + close(l->fd); + remove_protocol(l); + free(ip); + } + return; + } + if (result == 0) + return; + + if (bootp_packet_handler) { + ifrom.len = 4; + memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len); + + (*bootp_packet_handler)(ip, &u.packet, result, + from.sin_port, ifrom, &hfrom); + } +} + +#if 0 +int +interface_status(struct interface_info *ifinfo) +{ + char *ifname = ifinfo->name; + int ifsock = ifinfo->rfdesc; + struct ifreq ifr; + struct ifmediareq ifmr; + + /* get interface flags */ + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) { + syslog(LOG_ERR, "ioctl(SIOCGIFFLAGS) on %s: %m", ifname); + goto inactive; + } + + /* + * if one of UP and RUNNING flags is dropped, + * the interface is not active. + */ + if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) + goto inactive; + + /* Next, check carrier on the interface, if possible */ + if (ifinfo->noifmedia) + goto active; + memset(&ifmr, 0, sizeof(ifmr)); + strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); + if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { + if (errno != EINVAL) { + syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m", + ifname); + + ifinfo->noifmedia = 1; + goto active; + } + /* + * EINVAL (or ENOTTY) simply means that the interface + * does not support the SIOCGIFMEDIA ioctl. We regard it alive. + */ + ifinfo->noifmedia = 1; + goto active; + } + if (ifmr.ifm_status & IFM_AVALID) { + switch (ifmr.ifm_active & IFM_NMASK) { + case IFM_ETHER: + if (ifmr.ifm_status & IFM_ACTIVE) + goto active; + else + goto inactive; + break; + default: + goto inactive; + } + } +inactive: + return (0); +active: + return (1); +} +#else +int +interface_status(struct interface_info *ifinfo) +{ + return (1); +} +#endif + +void +add_timeout(time_t when, void (*where)(void *), void *what) +{ + struct timeout *t, *q; + + DH_DbgPrint(MID_TRACE,("Adding timeout %x %p %x\n", when, where, what)); + /* See if this timeout supersedes an existing timeout. */ + t = NULL; + for (q = timeouts; q; q = q->next) { + if (q->func == where && q->what == what) { + if (t) + t->next = q->next; + else + timeouts = q->next; + break; + } + t = q; + } + + /* If we didn't supersede a timeout, allocate a timeout + structure now. */ + if (!q) { + if (free_timeouts) { + q = free_timeouts; + free_timeouts = q->next; + q->func = where; + q->what = what; + } else { + q = malloc(sizeof(struct timeout)); + if (!q) + error("Can't allocate timeout structure!"); + q->func = where; + q->what = what; + } + } + + q->when = when; + + /* Now sort this timeout into the timeout list. */ + + /* Beginning of list? */ + if (!timeouts || timeouts->when > q->when) { + q->next = timeouts; + timeouts = q; + return; + } + + /* Middle of list? */ + for (t = timeouts; t->next; t = t->next) { + if (t->next->when > q->when) { + q->next = t->next; + t->next = q; + return; + } + } + + /* End of list. */ + t->next = q; + q->next = NULL; +} + +void +cancel_timeout(void (*where)(void *), void *what) +{ + struct timeout *t, *q; + + /* Look for this timeout on the list, and unlink it if we find it. */ + t = NULL; + for (q = timeouts; q; q = q->next) { + if (q->func == where && q->what == what) { + if (t) + t->next = q->next; + else + timeouts = q->next; + break; + } + t = q; + } + + /* If we found the timeout, put it on the free list. */ + if (q) { + q->next = free_timeouts; + free_timeouts = q; + } +} + +/* Add a protocol to the list of protocols... */ +void +add_protocol(char *name, int fd, void (*handler)(struct protocol *), + void *local) +{ + struct protocol *p; + + p = malloc(sizeof(*p)); + if (!p) + error("can't allocate protocol struct for %s", name); + + p->fd = fd; + p->handler = handler; + p->local = local; + p->next = protocols; + protocols = p; +} + +void +remove_protocol(struct protocol *proto) +{ + struct protocol *p, *next, *prev; + + prev = NULL; + for (p = protocols; p; p = next) { + next = p->next; + if (p == proto) { + if (prev) + prev->next = p->next; + else + protocols = p->next; + free(p); + } + } +} + +int +interface_link_status(char *ifname) +{ +#if 0 + struct ifmediareq ifmr; + int sock; + + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + error("Can't create socket"); + + memset(&ifmr, 0, sizeof(ifmr)); + strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); + if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { + /* EINVAL -> link state unknown. treat as active */ + if (errno != EINVAL) + syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m", + ifname); + close(sock); + return (1); + } + close(sock); + + if (ifmr.ifm_status & IFM_AVALID) { + if ((ifmr.ifm_active & IFM_NMASK) == IFM_ETHER) { + if (ifmr.ifm_status & IFM_ACTIVE) + return (1); + else + return (0); + } + } +#endif + return (1); +} diff --git a/reactos/subsys/system/dhcp/hash.c b/reactos/subsys/system/dhcp/hash.c new file mode 100644 index 00000000000..c47c562879b --- /dev/null +++ b/reactos/subsys/system/dhcp/hash.c @@ -0,0 +1,164 @@ +/* hash.c + + Routines for manipulating hash tables... */ + +/* + * Copyright (c) 1995, 1996, 1997, 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 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: hash.c,v 1.9.2.3 1999/04/09 17:39:41 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "rosdhcp.h" + +static INLINE int do_hash PROTO ((unsigned char *, int, int)); + +struct hash_table *new_hash () +{ + struct hash_table *rv = new_hash_table (DEFAULT_HASH_SIZE); + if (!rv) + return rv; + memset (&rv -> buckets [0], 0, + DEFAULT_HASH_SIZE * sizeof (struct hash_bucket *)); + return rv; +} + +static INLINE int do_hash (name, len, size) + unsigned char *name; + int len; + int size; +{ + register int accum = 0; + register unsigned char *s = name; + int i = len; + while (i--) { + /* Add the character in... */ + accum += *s++; + /* Add carry back in... */ + while (accum > 255) { + accum = (accum & 255) + (accum >> 8); + } + } + return accum % size; +} + +void add_hash (table, name, len, pointer) + struct hash_table *table; + int len; + unsigned char *name; + unsigned char *pointer; +{ + int hashno; + struct hash_bucket *bp; + + if (!table) + return; + if (!len) + len = strlen ((char *)name); + + hashno = do_hash (name, len, table -> hash_count); + bp = new_hash_bucket (); + + if (!bp) { + warn ("Can't add %s to hash table.", name); + return; + } + bp -> name = name; + bp -> value = pointer; + bp -> next = table -> buckets [hashno]; + bp -> len = len; + table -> buckets [hashno] = bp; +} + +void delete_hash_entry (table, name, len) + struct hash_table *table; + int len; + unsigned char *name; +{ + int hashno; + struct hash_bucket *bp, *pbp = (struct hash_bucket *)0; + + if (!table) + return; + if (!len) + len = strlen ((char *)name); + + hashno = do_hash (name, len, table -> hash_count); + + /* Go through the list looking for an entry that matches; + if we find it, delete it. */ + for (bp = table -> buckets [hashno]; bp; bp = bp -> next) { + if ((!bp -> len && + !strcmp ((char *)bp -> name, (char *)name)) || + (bp -> len == len && + !memcmp (bp -> name, name, len))) { + if (pbp) { + pbp -> next = bp -> next; + } else { + table -> buckets [hashno] = bp -> next; + } + free_hash_bucket (bp, "delete_hash_entry"); + break; + } + pbp = bp; /* jwg, 9/6/96 - nice catch! */ + } +} + +unsigned char *hash_lookup (table, name, len) + struct hash_table *table; + unsigned char *name; + int len; +{ + int hashno; + struct hash_bucket *bp; + + if (!table) + return (unsigned char *)0; + + if (!len) + len = strlen ((char *)name); + + hashno = do_hash (name, len, table -> hash_count); + + for (bp = table -> buckets [hashno]; bp; bp = bp -> next) { + if (len == bp -> len && !memcmp (bp -> name, name, len)) + return bp -> value; + } + return (unsigned char *)0; +} diff --git a/reactos/subsys/system/dhcp/include/cdefs.h b/reactos/subsys/system/dhcp/include/cdefs.h new file mode 100644 index 00000000000..2bc67a5251a --- /dev/null +++ b/reactos/subsys/system/dhcp/include/cdefs.h @@ -0,0 +1,57 @@ +/* cdefs.h + + Standard C definitions... */ + +/* + * Copyright (c) 1996 The Internet Software Consortium. + * All Rights Reserved. + * Copyright (c) 1995 RadioMail Corporation. 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 RadioMail Corporation, 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 RADIOMAIL CORPORATION, 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 RADIOMAIL CORPORATION 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 was written for RadioMail Corporation by Ted Lemon + * under a contract with Vixie Enterprises. Further modifications have + * been made for the Internet Software Consortium under a contract + * with Vixie Laboratories. + */ + +#if (defined (__GNUC__) || defined (__STDC__)) && !defined (BROKEN_ANSI) +#define PROTO(x) x +#define KandR(x) +#define ANSI_DECL(x) x +#if defined (__GNUC__) +#define INLINE inline +#else +#define INLINE +#endif /* __GNUC__ */ +#else +#define PROTO(x) () +#define KandR(x) x +#define ANSI_DECL(x) +#define INLINE +#endif /* __GNUC__ || __STDC__ */ diff --git a/reactos/subsys/system/dhcp/include/debug.h b/reactos/subsys/system/dhcp/include/debug.h new file mode 100644 index 00000000000..2cac97489e0 --- /dev/null +++ b/reactos/subsys/system/dhcp/include/debug.h @@ -0,0 +1,84 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/debug.h + * PURPOSE: Debugging support macros + * DEFINES: DBG - Enable debug output + * NASSERT - Disable assertions + */ +#ifndef __DEBUG_H +#define __DEBUG_H + +#define NORMAL_MASK 0x000000FF +#define SPECIAL_MASK 0xFFFFFF00 +#define MIN_TRACE 0x00000001 +#define MID_TRACE 0x00000002 +#define MAX_TRACE 0x00000003 + +#define DEBUG_ADAPTER 0x00000100 +#define DEBUG_ULTRA 0xFFFFFFFF + +#ifdef DBG + +extern unsigned long debug_trace_level; + +#ifdef _MSC_VER + +#define DH_DbgPrint(_t_, _x_) \ + if (((debug_trace_level & NORMAL_MASK) >= _t_) || \ + ((debug_trace_level & _t_) > NORMAL_MASK)) { \ + DbgPrint("(%s:%d) ", __FILE__, __LINE__); \ + DbgPrint _x_ ; \ + } + +#else /* _MSC_VER */ + +#define DH_DbgPrint(_t_, _x_) \ + if (((debug_trace_level & NORMAL_MASK) >= _t_) || \ + ((debug_trace_level & _t_) > NORMAL_MASK)) { \ + DbgPrint("(%s:%d)(%s) ", __FILE__, __LINE__, __FUNCTION__); \ + DbgPrint _x_ ; \ + } + +#endif /* _MSC_VER */ + +#define ASSERT_IRQL(x) ASSERT(KeGetCurrentIrql() <= (x)) + +#else /* DBG */ + +#define DH_DbgPrint(_t_, _x_) + +#endif /* DBG */ + + +#define assert(x) ASSERT(x) +#define assert_irql(x) ASSERT_IRQL(x) + + +#ifdef _MSC_VER + +#define UNIMPLEMENTED \ + TI_DbgPrint(MIN_TRACE, ("The function at %s:%d is unimplemented, \ + but come back another day.\n", __FILE__, __LINE__)); + +#else /* _MSC_VER */ + +#define UNIMPLEMENTED \ + TI_DbgPrint(MIN_TRACE, ("(%s:%d)(%s) is unimplemented, \ + but come back another day.\n", __FILE__, __LINE__, __FUNCTION__)); + +#endif /* _MSC_VER */ + + +#define CHECKPOINT \ + do { TI_DbgPrint(DEBUG_CHECK, ("(%s:%d)\n", __FILE__, __LINE__)); } while(0); + +#define CP CHECKPOINT + +#define ASSERT_KM_POINTER(_x) \ + ASSERT(((PVOID)_x) != (PVOID)0xcccccccc); \ + ASSERT(((PVOID)_x) >= (PVOID)0x80000000); + +#endif /* __DEBUG_H */ + +/* EOF */ diff --git a/reactos/subsys/system/dhcp/include/dhcp.h b/reactos/subsys/system/dhcp/include/dhcp.h new file mode 100644 index 00000000000..8ac8ed3a9e6 --- /dev/null +++ b/reactos/subsys/system/dhcp/include/dhcp.h @@ -0,0 +1,169 @@ +/* $OpenBSD: dhcp.h,v 1.5 2004/05/04 15:49:49 deraadt Exp $ */ + +/* Protocol structures... */ + +/* + * Copyright (c) 1995, 1996 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 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''. + */ + +#define DHCP_UDP_OVERHEAD (14 + /* Ethernet header */ \ + 20 + /* IP header */ \ + 8) /* UDP header */ +#define DHCP_SNAME_LEN 64 +#define DHCP_FILE_LEN 128 +#define DHCP_FIXED_NON_UDP 236 +#define DHCP_FIXED_LEN (DHCP_FIXED_NON_UDP + DHCP_UDP_OVERHEAD) + /* Everything but options. */ +#define DHCP_MTU_MAX 1500 +#define DHCP_OPTION_LEN (DHCP_MTU_MAX - DHCP_FIXED_LEN) + +#define BOOTP_MIN_LEN 300 +#define DHCP_MIN_LEN 548 + +struct dhcp_packet { + u_int8_t op; /* Message opcode/type */ + u_int8_t htype; /* Hardware addr type (see net/if_types.h) */ + u_int8_t hlen; /* Hardware addr length */ + u_int8_t hops; /* Number of relay agent hops from client */ + u_int32_t xid; /* Transaction ID */ + u_int16_t secs; /* Seconds since client started looking */ + u_int16_t flags; /* Flag bits */ + struct in_addr ciaddr; /* Client IP address (if already in use) */ + struct in_addr yiaddr; /* Client IP address */ + struct in_addr siaddr; /* IP address of next server to talk to */ + struct in_addr giaddr; /* DHCP relay agent IP address */ + unsigned char chaddr[16]; /* Client hardware address */ + char sname[DHCP_SNAME_LEN]; /* Server name */ + char file[DHCP_FILE_LEN]; /* Boot filename */ + unsigned char options[DHCP_OPTION_LEN]; + /* Optional parameters + (actual length dependent on MTU). */ +}; + +/* BOOTP (rfc951) message types */ +#define BOOTREQUEST 1 +#define BOOTREPLY 2 + +/* Possible values for flags field... */ +#define BOOTP_BROADCAST 32768L + +/* Possible values for hardware type (htype) field... */ +#define HTYPE_ETHER 1 /* Ethernet */ +#define HTYPE_IEEE802 6 /* IEEE 802.2 Token Ring... */ +#define HTYPE_FDDI 8 /* FDDI... */ + +/* Magic cookie validating dhcp options field (and bootp vendor + extensions field). */ +#define DHCP_OPTIONS_COOKIE "\143\202\123\143" + + +/* DHCP Option codes: */ + +#define DHO_PAD 0 +#define DHO_SUBNET_MASK 1 +#define DHO_TIME_OFFSET 2 +#define DHO_ROUTERS 3 +#define DHO_TIME_SERVERS 4 +#define DHO_NAME_SERVERS 5 +#define DHO_DOMAIN_NAME_SERVERS 6 +#define DHO_LOG_SERVERS 7 +#define DHO_COOKIE_SERVERS 8 +#define DHO_LPR_SERVERS 9 +#define DHO_IMPRESS_SERVERS 10 +#define DHO_RESOURCE_LOCATION_SERVERS 11 +#define DHO_HOST_NAME 12 +#define DHO_BOOT_SIZE 13 +#define DHO_MERIT_DUMP 14 +#define DHO_DOMAIN_NAME 15 +#define DHO_SWAP_SERVER 16 +#define DHO_ROOT_PATH 17 +#define DHO_EXTENSIONS_PATH 18 +#define DHO_IP_FORWARDING 19 +#define DHO_NON_LOCAL_SOURCE_ROUTING 20 +#define DHO_POLICY_FILTER 21 +#define DHO_MAX_DGRAM_REASSEMBLY 22 +#define DHO_DEFAULT_IP_TTL 23 +#define DHO_PATH_MTU_AGING_TIMEOUT 24 +#define DHO_PATH_MTU_PLATEAU_TABLE 25 +#define DHO_INTERFACE_MTU 26 +#define DHO_ALL_SUBNETS_LOCAL 27 +#define DHO_BROADCAST_ADDRESS 28 +#define DHO_PERFORM_MASK_DISCOVERY 29 +#define DHO_MASK_SUPPLIER 30 +#define DHO_ROUTER_DISCOVERY 31 +#define DHO_ROUTER_SOLICITATION_ADDRESS 32 +#define DHO_STATIC_ROUTES 33 +#define DHO_TRAILER_ENCAPSULATION 34 +#define DHO_ARP_CACHE_TIMEOUT 35 +#define DHO_IEEE802_3_ENCAPSULATION 36 +#define DHO_DEFAULT_TCP_TTL 37 +#define DHO_TCP_KEEPALIVE_INTERVAL 38 +#define DHO_TCP_KEEPALIVE_GARBAGE 39 +#define DHO_NIS_DOMAIN 40 +#define DHO_NIS_SERVERS 41 +#define DHO_NTP_SERVERS 42 +#define DHO_VENDOR_ENCAPSULATED_OPTIONS 43 +#define DHO_NETBIOS_NAME_SERVERS 44 +#define DHO_NETBIOS_DD_SERVER 45 +#define DHO_NETBIOS_NODE_TYPE 46 +#define DHO_NETBIOS_SCOPE 47 +#define DHO_FONT_SERVERS 48 +#define DHO_X_DISPLAY_MANAGER 49 +#define DHO_DHCP_REQUESTED_ADDRESS 50 +#define DHO_DHCP_LEASE_TIME 51 +#define DHO_DHCP_OPTION_OVERLOAD 52 +#define DHO_DHCP_MESSAGE_TYPE 53 +#define DHO_DHCP_SERVER_IDENTIFIER 54 +#define DHO_DHCP_PARAMETER_REQUEST_LIST 55 +#define DHO_DHCP_MESSAGE 56 +#define DHO_DHCP_MAX_MESSAGE_SIZE 57 +#define DHO_DHCP_RENEWAL_TIME 58 +#define DHO_DHCP_REBINDING_TIME 59 +#define DHO_DHCP_CLASS_IDENTIFIER 60 +#define DHO_DHCP_CLIENT_IDENTIFIER 61 +#define DHO_DHCP_USER_CLASS_ID 77 +#define DHO_END 255 + +/* DHCP message types. */ +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 diff --git a/reactos/subsys/system/dhcp/include/dhcpd.h b/reactos/subsys/system/dhcp/include/dhcpd.h new file mode 100644 index 00000000000..7754d6d0aca --- /dev/null +++ b/reactos/subsys/system/dhcp/include/dhcpd.h @@ -0,0 +1,487 @@ +/* $OpenBSD: dhcpd.h,v 1.33 2004/05/06 22:29:15 deraadt Exp $ */ + +/* + * Copyright (c) 2004 Henning Brauer + * 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 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''. + */ + +#ifndef DHCPD_H +#define DHCPD_H + +#include +#include +#include "stdint.h" + +#define IFNAMSIZ MAX_INTERFACE_NAME_LEN + +#define ETH_ALEN 6 +#define ETHER_ADDR_LEN ETH_ALEN +struct ether_header +{ + u_int8_t ether_dhost[ETH_ALEN]; /* destination eth addr */ + u_int8_t ether_shost[ETH_ALEN]; /* source ether addr */ + u_int16_t ether_type; /* packet type ID field */ +} __attribute__ ((__packed__)); + +struct ip + { + unsigned int ip_hl:4; /* header length */ + unsigned int ip_v:4; /* version */ + u_int8_t ip_tos; /* type of service */ + u_short ip_len; /* total length */ + u_short ip_id; /* identification */ + u_short ip_off; /* fragment offset field */ +#define IP_RF 0x8000 /* reserved fragment flag */ +#define IP_DF 0x4000 /* dont fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + u_int8_t ip_ttl; /* time to live */ + u_int8_t ip_p; /* protocol */ + u_short ip_sum; /* checksum */ + struct in_addr ip_src, ip_dst; /* source and dest address */ + }; + +struct udphdr { + u_int16_t uh_sport; /* source port */ + u_int16_t uh_dport; /* destination port */ + u_int16_t uh_ulen; /* udp length */ + u_int16_t uh_sum; /* udp checksum */ +}; + +#define ETHERTYPE_IP 0x0800 +#define IPTOS_LOWDELAY 0x10 +#define ARPHRD_ETHER 1 + +// FIXME: I have no idea what this should be! +#define SIZE_T_MAX 1600 + +#define USE_SOCKET_RECEIVE +#define USE_SOCKET_SEND + +#include + +//#include +//#include +#include +#include +//#include +//#include + +//#include +//#include +//#include + +//#include +//#include + +#include +#include +#include +#include +//#include +//#include +#include +#include +#include +#include +#include +//#include +#include +#include + +#include "dhcp.h" +#include "tree.h" + +#define LOCAL_PORT 68 +#define REMOTE_PORT 67 + +struct option_data { + int len; + u_int8_t *data; +}; + +struct string_list { + struct string_list *next; + char *string; +}; + +struct iaddr { + int len; + unsigned char iabuf[16]; +}; + +struct iaddrlist { + struct iaddrlist *next; + struct iaddr addr; +}; + +struct packet { + struct dhcp_packet *raw; + int packet_length; + int packet_type; + int options_valid; + int client_port; + struct iaddr client_addr; + struct interface_info *interface; + struct hardware *haddr; + struct option_data options[256]; +}; + +struct hardware { + u_int8_t htype; + u_int8_t hlen; + u_int8_t haddr[16]; +}; + +struct client_lease { + struct client_lease *next; + time_t expiry, renewal, rebind; + struct iaddr address; + char *server_name; + char *filename; + struct string_list *medium; + unsigned int is_static : 1; + unsigned int is_bootp : 1; + struct option_data options[256]; +}; + +/* Possible states in which the client can be. */ +enum dhcp_state { + S_REBOOTING, + S_INIT, + S_SELECTING, + S_REQUESTING, + S_BOUND, + S_RENEWING, + S_REBINDING +}; + +struct client_config { + struct option_data defaults[256]; + enum { + ACTION_DEFAULT, + ACTION_SUPERSEDE, + ACTION_PREPEND, + ACTION_APPEND + } default_actions[256]; + + struct option_data send_options[256]; + u_int8_t required_options[256]; + u_int8_t requested_options[256]; + int requested_option_count; + time_t timeout; + time_t initial_interval; + time_t retry_interval; + time_t select_interval; + time_t reboot_timeout; + time_t backoff_cutoff; + struct string_list *media; + char *script_name; + enum { IGNORE, ACCEPT, PREFER } + bootp_policy; + struct string_list *medium; + struct iaddrlist *reject_list; +}; + +struct client_state { + struct client_lease *active; + struct client_lease *new; + struct client_lease *offered_leases; + struct client_lease *leases; + struct client_lease *alias; + enum dhcp_state state; + struct iaddr destination; + u_int32_t xid; + u_int16_t secs; + time_t first_sending; + time_t interval; + struct string_list *medium; + struct dhcp_packet packet; + int packet_length; + struct iaddr requested_address; + struct client_config *config; +}; + +struct interface_info { + struct interface_info *next; + struct hardware hw_address; + struct in_addr primary_address; + char name[IFNAMSIZ]; + int rfdesc; + int wfdesc; + unsigned char *rbuf; + size_t rbuf_max; + size_t rbuf_offset; + size_t rbuf_len; + struct client_state *client; + int noifmedia; + int errors; + int dead; + u_int16_t index; +}; + +struct timeout { + struct timeout *next; + time_t when; + void (*func)(void *); + void *what; +}; + +struct protocol { + struct protocol *next; + int fd; + void (*handler)(struct protocol *); + void *local; +}; + +#define DEFAULT_HASH_SIZE 97 + +struct hash_bucket { + struct hash_bucket *next; + unsigned char *name; + int len; + unsigned char *value; +}; + +struct hash_table { + int hash_count; + struct hash_bucket *buckets[DEFAULT_HASH_SIZE]; +}; + +/* Default path to dhcpd config file. */ +#define _PATH_DHCLIENT_CONF "/etc/dhclient.conf" +#define _PATH_DHCLIENT_DB "/var/db/dhclient.leases" +#define DHCPD_LOG_FACILITY LOG_DAEMON + +#define MAX_TIME 0x7fffffff +#define MIN_TIME 0 + +/* External definitions... */ + +/* options.c */ +int cons_options(struct packet *, struct dhcp_packet *, int, + struct tree_cache **, int, int, int, u_int8_t *, int); +char *pretty_print_option(unsigned int, + unsigned char *, int, int, int); +void do_packet(struct interface_info *, struct dhcp_packet *, + int, unsigned int, struct iaddr, struct hardware *); + +/* errwarn.c */ +extern int warnings_occurred; +void error(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +int warning(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +int note(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +int debug(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +int parse_warn(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); + +/* conflex.c */ +extern int lexline, lexchar; +extern char *token_line, *tlname; +extern char comments[4096]; +extern int comment_index; +extern int eol_token; +void new_parse(char *); +int next_token(char **, FILE *); +int peek_token(char **, FILE *); + +/* parse.c */ +void skip_to_semi(FILE *); +int parse_semi(FILE *); +char *parse_string(FILE *); +int parse_ip_addr(FILE *, struct iaddr *); +void parse_hardware_param(FILE *, struct hardware *); +void parse_lease_time(FILE *, time_t *); +unsigned char *parse_numeric_aggregate(FILE *, unsigned char *, int *, + int, int, int); +void convert_num(unsigned char *, char *, int, int); +time_t parse_date(FILE *); + +/* tree.c */ +pair cons(caddr_t, pair); + +/* alloc.c */ +struct string_list *new_string_list(size_t size); +struct hash_table *new_hash_table(int); +struct hash_bucket *new_hash_bucket(void); + +/* bpf.c */ +int if_register_bpf(struct interface_info *); +void if_register_send(struct interface_info *); +void if_register_receive(struct interface_info *); +ssize_t send_packet(struct interface_info *, struct dhcp_packet *, size_t, + struct in_addr, struct sockaddr_in *, struct hardware *); +ssize_t receive_packet(struct interface_info *, unsigned char *, size_t, + struct sockaddr_in *, struct hardware *); + +/* dispatch.c */ +extern void (*bootp_packet_handler)(struct interface_info *, + struct dhcp_packet *, int, unsigned int, struct iaddr, struct hardware *); +void discover_interfaces(struct interface_info *); +void reinitialize_interfaces(void); +void dispatch(void); +void got_one(struct protocol *); +void add_timeout(time_t, void (*)(void *), void *); +void cancel_timeout(void (*)(void *), void *); +void add_protocol(char *, int, void (*)(struct protocol *), void *); +void remove_protocol(struct protocol *); +int interface_link_status(char *); + +/* hash.c */ +struct hash_table *new_hash(void); +void add_hash(struct hash_table *, unsigned char *, int, unsigned char *); +unsigned char *hash_lookup(struct hash_table *, unsigned char *, int); + +/* tables.c */ +extern struct dhcp_option dhcp_options[256]; +extern unsigned char dhcp_option_default_priority_list[]; +extern int sizeof_dhcp_option_default_priority_list; +extern struct hash_table universe_hash; +extern struct universe dhcp_universe; +void initialize_universes(void); + +/* convert.c */ +u_int32_t getULong(unsigned char *); +int32_t getLong(unsigned char *); +u_int16_t getUShort(unsigned char *); +int16_t getShort(unsigned char *); +void putULong(unsigned char *, u_int32_t); +void putLong(unsigned char *, int32_t); +void putUShort(unsigned char *, unsigned int); +void putShort(unsigned char *, int); + +/* inet.c */ +struct iaddr subnet_number(struct iaddr, struct iaddr); +struct iaddr broadcast_addr(struct iaddr, struct iaddr); +int addr_eq(struct iaddr, struct iaddr); +char *piaddr(struct iaddr); + +/* dhclient.c */ +extern char *path_dhclient_conf; +extern char *path_dhclient_db; +extern time_t cur_time; +extern int log_priority; +extern int log_perror; + +extern struct client_config top_level_config; + +void dhcpoffer(struct packet *); +void dhcpack(struct packet *); +void dhcpnak(struct packet *); + +void send_discover(void *); +void send_request(void *); +void send_decline(void *); + +void state_reboot(void *); +void state_init(void *); +void state_selecting(void *); +void state_requesting(void *); +void state_bound(void *); +void state_panic(void *); + +void bind_lease(struct interface_info *); + +void make_discover(struct interface_info *, struct client_lease *); +void make_request(struct interface_info *, struct client_lease *); +void make_decline(struct interface_info *, struct client_lease *); + +void free_client_lease(struct client_lease *); +void rewrite_client_leases(void); +void write_client_lease(struct interface_info *, struct client_lease *, int); + +void priv_script_init(char *, char *); +void priv_script_write_params(char *, struct client_lease *); +int priv_script_go(void); + +void script_init(char *, struct string_list *); +void script_write_params(char *, struct client_lease *); +int script_go(void); +void client_envadd(struct client_state *, + const char *, const char *, const char *, ...); +void script_set_env(struct client_state *, const char *, const char *, + const char *); +void script_flush_env(struct client_state *); +int dhcp_option_ev_name(char *, size_t, struct dhcp_option *); + +struct client_lease *packet_to_lease(struct packet *); +void go_daemon(void); +void client_location_changed(void); + +void bootp(struct packet *); +void dhcp(struct packet *); + +/* packet.c */ +void assemble_hw_header(struct interface_info *, unsigned char *, + int *, struct hardware *); +void assemble_udp_ip_header(unsigned char *, int *, u_int32_t, u_int32_t, + unsigned int, unsigned char *, int); +ssize_t decode_hw_header(unsigned char *, int, struct hardware *); +ssize_t decode_udp_ip_header(unsigned char *, int, struct sockaddr_in *, + unsigned char *, int); + +/* ethernet.c */ +void assemble_ethernet_header(struct interface_info *, unsigned char *, + int *, struct hardware *); +ssize_t decode_ethernet_header(struct interface_info *, unsigned char *, + int, struct hardware *); + +/* clparse.c */ +int read_client_conf(void); +void read_client_leases(void); +void parse_client_statement(FILE *, struct interface_info *, + struct client_config *); +int parse_X(FILE *, u_int8_t *, int); +int parse_option_list(FILE *, u_int8_t *); +void parse_interface_declaration(FILE *, struct client_config *); +struct interface_info *interface_or_dummy(char *); +void make_client_state(struct interface_info *); +void make_client_config(struct interface_info *, struct client_config *); +void parse_client_lease_statement(FILE *, int); +void parse_client_lease_declaration(FILE *, struct client_lease *, + struct interface_info **); +struct dhcp_option *parse_option_decl(FILE *, struct option_data *); +void parse_string_list(FILE *, struct string_list **, int); +void parse_reject_statement(FILE *, struct client_config *); + +/* privsep.c */ +struct buf *buf_open(size_t); +int buf_add(struct buf *, void *, size_t); +int buf_close(int, struct buf *); +ssize_t buf_read(int, void *, size_t); +void dispatch_imsg(int); + +#endif/*DHCPD_H*/ diff --git a/reactos/subsys/system/dhcp/include/dhctoken.h b/reactos/subsys/system/dhcp/include/dhctoken.h new file mode 100644 index 00000000000..2aeb5303af1 --- /dev/null +++ b/reactos/subsys/system/dhcp/include/dhctoken.h @@ -0,0 +1,136 @@ +/* dhctoken.h + + Tokens for config file lexer and parser. */ + +/* + * 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 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''. + */ + +#define SEMI ';' +#define DOT '.' +#define COLON ':' +#define COMMA ',' +#define SLASH '/' +#define LBRACE '{' +#define RBRACE '}' + +#define FIRST_TOKEN HOST +#define HOST 256 +#define HARDWARE 257 +#define FILENAME 258 +#define FIXED_ADDR 259 +#define OPTION 260 +#define ETHERNET 261 +#define STRING 262 +#define NUMBER 263 +#define NUMBER_OR_NAME 264 +#define NAME 265 +#define TIMESTAMP 266 +#define STARTS 267 +#define ENDS 268 +#define UID 269 +#define CLASS 270 +#define LEASE 271 +#define RANGE 272 +#define PACKET 273 +#define CIADDR 274 +#define YIADDR 275 +#define SIADDR 276 +#define GIADDR 277 +#define SUBNET 278 +#define NETMASK 279 +#define DEFAULT_LEASE_TIME 280 +#define MAX_LEASE_TIME 281 +#define VENDOR_CLASS 282 +#define USER_CLASS 283 +#define SHARED_NETWORK 284 +#define SERVER_NAME 285 +#define DYNAMIC_BOOTP 286 +#define SERVER_IDENTIFIER 287 +#define DYNAMIC_BOOTP_LEASE_CUTOFF 288 +#define DYNAMIC_BOOTP_LEASE_LENGTH 289 +#define BOOT_UNKNOWN_CLIENTS 290 +#define NEXT_SERVER 291 +#define TOKEN_RING 292 +#define GROUP 293 +#define ONE_LEASE_PER_CLIENT 294 +#define GET_LEASE_HOSTNAMES 295 +#define USE_HOST_DECL_NAMES 296 +#define SEND 297 +#define CLIENT_IDENTIFIER 298 +#define REQUEST 299 +#define REQUIRE 300 +#define TIMEOUT 301 +#define RETRY 302 +#define SELECT_TIMEOUT 303 +#define SCRIPT 304 +#define INTERFACE 305 +#define RENEW 306 +#define REBIND 307 +#define EXPIRE 308 +#define UNKNOWN_CLIENTS 309 +#define ALLOW 310 +#define BOOTP 311 +#define DENY 312 +#define BOOTING 313 +#define DEFAULT 314 +#define MEDIA 315 +#define MEDIUM 316 +#define ALIAS 317 +#define REBOOT 318 +#define ABANDONED 319 +#define BACKOFF_CUTOFF 320 +#define INITIAL_INTERVAL 321 +#define NAMESERVER 322 +#define DOMAIN 323 +#define SEARCH 324 +#define SUPERSEDE 325 +#define APPEND 326 +#define PREPEND 327 +#define HOSTNAME 328 +#define CLIENT_HOSTNAME 329 +#define REJECT 330 +#define FDDI 331 +#define USE_LEASE_ADDR_FOR_DEFAULT_ROUTE 332 +#define AUTHORITATIVE 333 +#define TOKEN_NOT 334 +#define ALWAYS_REPLY_RFC1048 335 + +#define is_identifier(x) ((x) >= FIRST_TOKEN && \ + (x) != STRING && \ + (x) != NUMBER && \ + (x) != EOF) diff --git a/reactos/subsys/system/dhcp/include/hash.h b/reactos/subsys/system/dhcp/include/hash.h new file mode 100644 index 00000000000..1bebb3140f8 --- /dev/null +++ b/reactos/subsys/system/dhcp/include/hash.h @@ -0,0 +1,56 @@ +/* hash.h + + Definitions for hashing... */ + +/* + * Copyright (c) 1995, 1996 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 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''. + */ + +#define DEFAULT_HASH_SIZE 97 + +struct hash_bucket { + struct hash_bucket *next; + unsigned char *name; + int len; + unsigned char *value; +}; + +struct hash_table { + int hash_count; + struct hash_bucket *buckets [DEFAULT_HASH_SIZE]; +}; + diff --git a/reactos/subsys/system/dhcp/include/inet.h b/reactos/subsys/system/dhcp/include/inet.h new file mode 100644 index 00000000000..a45f92265de --- /dev/null +++ b/reactos/subsys/system/dhcp/include/inet.h @@ -0,0 +1,52 @@ +/* inet.h + + Portable definitions for internet addresses */ + +/* + * Copyright (c) 1996 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 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''. + */ + +/* An internet address of up to 128 bits. */ + +typedef struct _iaddr { + int len; + unsigned char iabuf [16]; +} iaddr; + +typedef struct _iaddrlist { + struct _iaddrlist *next; + iaddr addr; +} iaddrlist; diff --git a/reactos/subsys/system/dhcp/include/osdep.h b/reactos/subsys/system/dhcp/include/osdep.h new file mode 100644 index 00000000000..71a985980e1 --- /dev/null +++ b/reactos/subsys/system/dhcp/include/osdep.h @@ -0,0 +1,294 @@ +/* osdep.h + + Operating system dependencies... */ + +/* + * Copyright (c) 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 was written for the Internet Software Consortium by Ted Lemon + * under a contract with Vixie Laboratories. + */ + +#include "site.h" + +/* Porting:: + + If you add a new network API, you must add a check for it below: */ + +#if !defined (USE_SOCKETS) && \ + !defined (USE_SOCKET_SEND) && \ + !defined (USE_SOCKET_RECEIVE) && \ + !defined (USE_RAW_SOCKETS) && \ + !defined (USE_RAW_SEND) && \ + !defined (USE_SOCKET_RECEIVE) && \ + !defined (USE_BPF) && \ + !defined (USE_BPF_SEND) && \ + !defined (USE_BPF_RECEIVE) && \ + !defined (USE_LPF) && \ + !defined (USE_LPF_SEND) && \ + !defined (USE_LPF_RECEIVE) && \ + !defined (USE_NIT) && \ + !defined (USE_NIT_SEND) && \ + !defined (USE_NIT_RECEIVE) && \ + !defined (USR_DLPI_SEND) && \ + !defined (USE_DLPI_RECEIVE) +# define USE_DEFAULT_NETWORK +#endif + + +/* Porting:: + + If you add a new system configuration file, include it here: */ + +#if defined (sun) +# if defined (__svr4__) || defined (__SVR4) +# include "cf/sunos5-5.h" +# else +# include "cf/sunos4.h" +# endif +#endif + +#ifdef aix +# include "cf/aix.h" +#endif + +#ifdef bsdi +# include "cf/bsdos.h" +#endif + +#ifdef __NetBSD__ +# include "cf/netbsd.h" +#endif + +#ifdef __FreeBSD__ +# include "cf/freebsd.h" +#endif + +#if defined (__osf__) && defined (__alpha) +# include "cf/alphaosf.h" +#endif + +#ifdef ultrix +# include "cf/ultrix.h" +#endif + +#ifdef linux +# include "cf/linux.h" +#endif + +#ifdef SCO +# include "cf/sco.h" +#endif + +#if defined (hpux) || defined (__hpux) +# include "cf/hpux.h" +#endif + +#ifdef __QNX__ +# include "cf/qnx.h" +#endif + +#ifdef __CYGWIN32__ +# include "cf/cygwin32.h" +#endif + +#ifdef __APPLE__ +# include "cf/rhapsody.h" +#else +# if defined (NeXT) +# include "cf/nextstep.h" +# endif +#endif + +#if defined(IRIX) || defined(__sgi) +# include "cf/irix.h" +#endif + +#if !defined (TIME_MAX) +# define TIME_MAX 2147483647 +#endif + +/* Porting:: + + If you add a new network API, and have it set up so that it can be + used for sending or receiving, but doesn't have to be used for both, + then set up an ifdef like the ones below: */ + +#ifdef USE_SOCKETS +# define USE_SOCKET_SEND +# define USE_SOCKET_RECEIVE +#endif + +#ifdef USE_RAW_SOCKETS +# define USE_RAW_SEND +# define USE_SOCKET_RECEIVE +#endif + +#ifdef USE_BPF +# define USE_BPF_SEND +# define USE_BPF_RECEIVE +#endif + +#ifdef USE_LPF +# define USE_LPF_SEND +# define USE_LPF_RECEIVE +#endif + +#ifdef USE_NIT +# define USE_NIT_SEND +# define USE_NIT_RECEIVE +#endif + +#ifdef USE_DLPI +# define USE_DLPI_SEND +# define USE_DLPI_RECEIVE +#endif + +#ifdef USE_UPF +# define USE_UPF_SEND +# define USE_UPF_RECEIVE +#endif + +/* Porting:: + + If you add support for sending packets directly out an interface, + and your support does not do ARP or routing, you must use a fallback + mechanism to deal with packets that need to be sent to routers. + Currently, all low-level packet interfaces use BSD sockets as a + fallback. */ + +#if defined (USE_BPF_SEND) || defined (USE_NIT_SEND) || \ + defined (USE_DLPI_SEND) || defined (USE_UPF_SEND) || defined (USE_LPF_SEND) +# define USE_SOCKET_FALLBACK +# define USE_FALLBACK +#endif + +/* Porting:: + + If you add support for sending packets directly out an interface + and need to be able to assemble packets, add the USE_XXX_SEND + definition for your interface to the list tested below. */ + +#if defined (USE_RAW_SEND) || defined (USE_BPF_SEND) || \ + defined (USE_NIT_SEND) || defined (USE_UPF_SEND) || \ + defined (USE_DLPI_SEND) || defined (USE_LPF_SEND) +# define PACKET_ASSEMBLY +#endif + +/* Porting:: + + If you add support for receiving packets directly from an interface + and need to be able to decode raw packets, add the USE_XXX_RECEIVE + definition for your interface to the list tested below. */ + +#if defined (USE_RAW_RECEIVE) || defined (USE_BPF_SEND) || \ + defined (USE_NIT_RECEIVE) || defined (USE_UPF_RECEIVE) || \ + defined (USE_DLPI_RECEIVE) || \ + defined (USE_LPF_SEND) || \ + (defined (USE_SOCKET_SEND) && defined (SO_BINDTODEVICE)) +# define PACKET_DECODING +#endif + +/* If we don't have a DLPI packet filter, we have to filter in userland. + Probably not worth doing, actually. */ +#if defined (USE_DLPI_RECEIVE) && !defined (USE_DLPI_PFMOD) +# define USERLAND_FILTER +#endif + +/* jmp_buf is assumed to be a struct unless otherwise defined in the + system header. */ +#ifndef jbp_decl +# define jbp_decl(x) jmp_buf *x +#endif +#ifndef jref +# define jref(x) (&(x)) +#endif +#ifndef jdref +# define jdref(x) (*(x)) +#endif +#ifndef jrefproto +# define jrefproto jmp_buf * +#endif + +#ifndef BPF_FORMAT +# define BPF_FORMAT "/dev/bpf%d" +#endif + +#if defined (IFF_POINTOPOINT) && !defined (HAVE_IFF_POINTOPOINT) +# define HAVE_IFF_POINTOPOINT +#endif + +#if defined (AF_LINK) && !defined (HAVE_AF_LINK) +# define HAVE_AF_LINK +#endif + +#if defined (ARPHRD_TUNNEL) && !defined (HAVE_ARPHRD_TUNNEL) +# define HAVE_ARPHRD_TUNNEL +#endif + +#if defined (ARPHRD_LOOPBACK) && !defined (HAVE_ARPHRD_LOOPBACK) +# define HAVE_ARPHRD_LOOPBACK +#endif + +#if defined (ARPHRD_ROSE) && !defined (HAVE_ARPHRD_ROSE) +# define HAVE_ARPHRD_ROSE +#endif + +#if defined (ARPHRD_IEEE802) && !defined (HAVE_ARPHRD_IEEE802) +# define HAVE_ARPHRD_IEEE802 +#endif + +#if defined (ARPHRD_FDDI) && !defined (HAVE_ARPHRD_FDDI) +# define HAVE_ARPHRD_FDDI +#endif + +#if defined (ARPHRD_AX25) && !defined (HAVE_ARPHRD_AX25) +# define HAVE_ARPHRD_AX25 +#endif + +#if defined (ARPHRD_NETROM) && !defined (HAVE_ARPHRD_NETROM) +# define HAVE_ARPHRD_NETROM +#endif + +#if defined (ARPHRD_METRICOM) && !defined (HAVE_ARPHRD_METRICOM) +# define HAVE_ARPHRD_METRICOM +#endif + +#if defined (SO_BINDTODEVICE) && !defined (HAVE_SO_BINDTODEVICE) +# define HAVE_SO_BINDTODEVICE +#endif + +#if defined (SIOCGIFHWADDR) && !defined (HAVE_SIOCGIFHWADDR) +# define HAVE_SIOCGIFHWADDR +#endif + +#if defined (AF_LINK) && !defined (HAVE_AF_LINK) +# define HAVE_AF_LINK +#endif diff --git a/reactos/subsys/system/dhcp/include/predec.h b/reactos/subsys/system/dhcp/include/predec.h new file mode 100644 index 00000000000..7f2515beb33 --- /dev/null +++ b/reactos/subsys/system/dhcp/include/predec.h @@ -0,0 +1,7 @@ +#ifndef REACTOS_PREDEC_H +#define REACTOS_PREDEC_H + +struct iaddr; +struct interface_info; + +#endif diff --git a/reactos/subsys/system/dhcp/include/privsep.h b/reactos/subsys/system/dhcp/include/privsep.h new file mode 100644 index 00000000000..e1fc52d5b69 --- /dev/null +++ b/reactos/subsys/system/dhcp/include/privsep.h @@ -0,0 +1,47 @@ +/* $OpenBSD: privsep.h,v 1.2 2004/05/04 18:51:18 henning Exp $ */ + +/* + * Copyright (c) 2004 Henning Brauer + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +//#include +//#include + +struct buf { + u_char *buf; + size_t size; + size_t wpos; + size_t rpos; +}; + +enum imsg_code { + IMSG_NONE, + IMSG_SCRIPT_INIT, + IMSG_SCRIPT_WRITE_PARAMS, + IMSG_SCRIPT_GO, + IMSG_SCRIPT_GO_RET +}; + +struct imsg_hdr { + enum imsg_code code; + size_t len; +}; + +struct buf *buf_open(size_t); +int buf_add(struct buf *, void *, size_t); +int buf_close(int, struct buf *); +ssize_t buf_read(int sock, void *, size_t); diff --git a/reactos/subsys/system/dhcp/include/rosdhcp.h b/reactos/subsys/system/dhcp/include/rosdhcp.h new file mode 100644 index 00000000000..6c093ecbe3f --- /dev/null +++ b/reactos/subsys/system/dhcp/include/rosdhcp.h @@ -0,0 +1,55 @@ +#ifndef ROSDHCP_H +#define ROSDHCP_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "stdint.h" +#include "predec.h" +#include "debug.h" +#define IFNAMSIZ MAX_INTERFACE_NAME_LEN +#undef interface /* wine/objbase.h -- Grrr */ + +#undef IGNORE +#undef ACCEPT +#undef PREFER +#define DHCP_DISCOVER_INTERVAL 15 +#define DHCP_REBOOT_TIMEOUT 300 +#define DHCP_BACKOFF_MAX 300 +#define _PATH_DHCLIENT_PID "\\systemroot\\system32\\drivers\\etc\\dhclient.pid" + +typedef void *VOIDPTR; + +#define NTOS_MODE_USER +#include +typedef u_int32_t uintTIME; +#define TIME uintTIME +#include "dhcpd.h" + +#define INLINE inline +#define PROTO(x) x + +typedef void (*handler_t) PROTO ((struct packet *)); + +typedef struct _DHCP_ADAPTER { + LIST_ENTRY ListEntry; + MIB_IFROW IfMib; + MIB_IPADDRROW IfAddr; + SOCKADDR Address; + struct interface_info DhclientInfo; + struct client_state DhclientState; + struct client_config DhclientConfig; + struct sockaddr_in ListenAddr; + unsigned int BindStatus; + char recv_buf[1]; +} DHCP_ADAPTER, *PDHCP_ADAPTER; + +#define random rand +#define srandom srand + +#endif/*ROSDHCP_H*/ diff --git a/reactos/subsys/system/dhcp/include/site.h b/reactos/subsys/system/dhcp/include/site.h new file mode 100644 index 00000000000..30fdb703005 --- /dev/null +++ b/reactos/subsys/system/dhcp/include/site.h @@ -0,0 +1,100 @@ +/* Site-specific definitions. + + For supported systems, you shouldn't need to make any changes here. + However, you may want to, in order to deal with site-specific + differences. */ + +/* Add any site-specific definitions and inclusions here... */ + +/* #include */ +/* #define SITE_FOOBAR */ + +/* Define this if you don't want dhcpd to run as a daemon and do want + to see all its output printed to stdout instead of being logged via + syslog(). This also makes dhcpd use the dhcpd.conf in its working + directory and write the dhcpd.leases file there. */ + +/* #define DEBUG */ + +/* Define this to see what the parser is parsing. You probably don't + want to see this. */ + +/* #define DEBUG_TOKENS */ + +/* Define this to see dumps of incoming and outgoing packets. This + slows things down quite a bit... */ + +/* #define DEBUG_PACKET */ + +/* Define this if you want to see dumps of tree evaluations. The most + common reason for doing this is to watch what happens with DNS name + lookups. */ + +/* #define DEBUG_EVAL */ + +/* Define this if you want the dhcpd.pid file to go somewhere other than + the default (which varies from system to system, but is usually either + /etc or /var/run. */ + +/* #define _PATH_DHCPD_PID "/var/run/dhcpd.pid" */ + +/* Define this if you want the dhcpd.leases file (the dynamic lease database) + to go somewhere other than the default location, which is normally + /etc/dhcpd.leases. */ + +/* #define _PATH_DHCPD_DB "/etc/dhcpd.leases" */ + +/* Define this if you want the dhcpd.conf file to go somewhere other than + the default location. By default, it goes in /etc/dhcpd.conf. */ + +/* #define _PATH_DHCPD_CONF "/etc/dhcpd.conf" */ + +/* Network API definitions. You do not need to choose one of these - if + you don't choose, one will be chosen for you in your system's config + header. DON'T MESS WITH THIS UNLESS YOU KNOW WHAT YOU'RE DOING!!! */ + +/* Define this to use the standard BSD socket API. + + On many systems, the BSD socket API does not provide the ability to + send packets to the 255.255.255.255 broadcast address, which can + prevent some clients (e.g., Win95) from seeing replies. This is + not a problem on Solaris. + + In addition, the BSD socket API will not work when more than one + network interface is configured on the server. + + However, the BSD socket API is about as efficient as you can get, so if + the aforementioned problems do not matter to you, or if no other + API is supported for your system, you may want to go with it. */ + +/* #define USE_SOCKETS */ + +/* Define this to use the Sun Streams NIT API. + + The Sun Streams NIT API is only supported on SunOS 4.x releases. */ + +/* #define USE_NIT */ + +/* Define this to use the Berkeley Packet Filter API. + + The BPF API is available on all 4.4-BSD derivatives, including + NetBSD, FreeBSD and BSDI's BSD/OS. It's also available on + DEC Alpha OSF/1 in a compatibility mode supported by the Alpha OSF/1 + packetfilter interface. */ + +/* #define USE_BPF */ + +/* Define this to use the raw socket API. + + The raw socket API is provided on many BSD derivatives, and provides + a way to send out raw IP packets. It is only supported for sending + packets - packets must be received with the regular socket API. + This code is experimental - I've never gotten it to actually transmit + a packet to the 255.255.255.255 broadcast address - so use it at your + own risk. */ + +/* #define USE_RAW_SOCKETS */ + +/* Define this to change the logging facility used by dhcpd. */ + +/* #define DHCPD_LOG_FACILITY LOG_DAEMON */ diff --git a/reactos/subsys/system/dhcp/include/stdint.h b/reactos/subsys/system/dhcp/include/stdint.h new file mode 100644 index 00000000000..988c30359e9 --- /dev/null +++ b/reactos/subsys/system/dhcp/include/stdint.h @@ -0,0 +1,13 @@ +#ifndef REACTOS_STDINT_H +#define REACTOS_STDINT_H + +typedef signed char int8_t; +typedef unsigned char u_int8_t; +typedef short int16_t; +typedef unsigned short u_int16_t; +typedef int int32_t; +typedef unsigned int u_int32_t; + +typedef char *caddr_t; + +#endif diff --git a/reactos/subsys/system/dhcp/include/sysconf.h b/reactos/subsys/system/dhcp/include/sysconf.h new file mode 100644 index 00000000000..5feb4c75c70 --- /dev/null +++ b/reactos/subsys/system/dhcp/include/sysconf.h @@ -0,0 +1,52 @@ +/* systat.h + + Definitions for systat protocol... */ + +/* + * Copyright (c) 1997 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 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''. + */ + +#define SYSCONF_SOCKET "/var/run/sysconf" + +struct sysconf_header { + u_int32_t type; /* Type of status message... */ + u_int32_t length; /* Length of message. */ +}; + +/* Message types... */ +#define NETWORK_LOCATION_CHANGED 1 + diff --git a/reactos/subsys/system/dhcp/include/tree.h b/reactos/subsys/system/dhcp/include/tree.h new file mode 100644 index 00000000000..367ffa7d9a1 --- /dev/null +++ b/reactos/subsys/system/dhcp/include/tree.h @@ -0,0 +1,66 @@ +/* $OpenBSD: tree.h,v 1.5 2004/05/06 22:29:15 deraadt Exp $ */ + +/* Definitions for address trees... */ + +/* + * Copyright (c) 1995 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 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''. + */ + +/* A pair of pointers, suitable for making a linked list. */ +typedef struct _pair { + caddr_t car; + struct _pair *cdr; +} *pair; + +struct tree_cache { + unsigned char *value; + int len; + int buf_size; + time_t timeout; +}; + +struct universe { + char *name; + struct hash_table *hash; + struct dhcp_option *options[256]; +}; + +struct dhcp_option { + char *name; + char *format; + struct universe *universe; + unsigned char code; +}; diff --git a/reactos/subsys/system/dhcp/include/version.h b/reactos/subsys/system/dhcp/include/version.h new file mode 100644 index 00000000000..303fbfa332b --- /dev/null +++ b/reactos/subsys/system/dhcp/include/version.h @@ -0,0 +1,3 @@ +/* Current version of ISC DHCP Distribution. */ + +#define DHCP_VERSION "2.0pl5" diff --git a/reactos/subsys/system/dhcp/memory.c b/reactos/subsys/system/dhcp/memory.c new file mode 100644 index 00000000000..3673948dcba --- /dev/null +++ b/reactos/subsys/system/dhcp/memory.c @@ -0,0 +1,915 @@ +/* memory.c + + Memory-resident database... */ + +/* + * Copyright (c) 1995, 1996, 1997, 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 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: memory.c,v 1.35.2.4 1999/05/27 17:47:43 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "rosdhcp.h" +#include "dhcpd.h" + +struct subnet *subnets; +struct shared_network *shared_networks; +static struct hash_table *host_hw_addr_hash; +static struct hash_table *host_uid_hash; +static struct hash_table *lease_uid_hash; +static struct hash_table *lease_ip_addr_hash; +static struct hash_table *lease_hw_addr_hash; +struct lease *dangling_leases; + +static struct hash_table *vendor_class_hash; +static struct hash_table *user_class_hash; + +void enter_host (hd) + struct host_decl *hd; +{ + struct host_decl *hp = (struct host_decl *)0; + struct host_decl *np = (struct host_decl *)0; + + hd -> n_ipaddr = (struct host_decl *)0; + + if (hd -> interface.hlen) { + if (!host_hw_addr_hash) + host_hw_addr_hash = new_hash (); + else + hp = (struct host_decl *) + hash_lookup (host_hw_addr_hash, + hd -> interface.haddr, + hd -> interface.hlen); + + /* If there isn't already a host decl matching this + address, add it to the hash table. */ + if (!hp) + add_hash (host_hw_addr_hash, + hd -> interface.haddr, hd -> interface.hlen, + (unsigned char *)hd); + } + + /* If there was already a host declaration for this hardware + address, add this one to the end of the list. */ + + if (hp) { + for (np = hp; np -> n_ipaddr; np = np -> n_ipaddr) + ; + np -> n_ipaddr = hd; + } + + + if (hd -> group -> options [DHO_DHCP_CLIENT_IDENTIFIER]) { + if (!tree_evaluate (hd -> group -> options + [DHO_DHCP_CLIENT_IDENTIFIER])) + return; + + /* If there's no uid hash, make one; otherwise, see if + there's already an entry in the hash for this host. */ + if (!host_uid_hash) { + host_uid_hash = new_hash (); + hp = (struct host_decl *)0; + } else + hp = (struct host_decl *) hash_lookup + (host_uid_hash, + hd -> group -> options + [DHO_DHCP_CLIENT_IDENTIFIER] -> value, + hd -> group -> options + [DHO_DHCP_CLIENT_IDENTIFIER] -> len); + + /* If there's already a host declaration for this + client identifier, add this one to the end of the + list. Otherwise, add it to the hash table. */ + if (hp) { + /* Don't link it in twice... */ + if (!np) { + for (np = hp; np -> n_ipaddr; + np = np -> n_ipaddr) + ; + np -> n_ipaddr = hd; + } + } else { + add_hash (host_uid_hash, + hd -> group -> options + [DHO_DHCP_CLIENT_IDENTIFIER] -> value, + hd -> group -> options + [DHO_DHCP_CLIENT_IDENTIFIER] -> len, + (unsigned char *)hd); + } + } +} + +struct host_decl *find_hosts_by_haddr (htype, haddr, hlen) + int htype; + unsigned char *haddr; + int hlen; +{ + struct host_decl *foo; + + foo = (struct host_decl *)hash_lookup (host_hw_addr_hash, + haddr, hlen); + return foo; +} + +struct host_decl *find_hosts_by_uid (data, len) + unsigned char *data; + int len; +{ + struct host_decl *foo; + + foo = (struct host_decl *)hash_lookup (host_uid_hash, data, len); + return foo; +} + +/* More than one host_decl can be returned by find_hosts_by_haddr or + find_hosts_by_uid, and each host_decl can have multiple addresses. + Loop through the list of hosts, and then for each host, through the + list of addresses, looking for an address that's in the same shared + network as the one specified. Store the matching address through + the addr pointer, update the host pointer to point at the host_decl + that matched, and return the subnet that matched. */ + +subnet *find_host_for_network (struct host_decl **host, iaddr *addr, + shared_network *share) +{ + int i; + subnet *subnet; + iaddr ip_address; + struct host_decl *hp; + + for (hp = *host; hp; hp = hp -> n_ipaddr) { + if (!hp -> fixed_addr || !tree_evaluate (hp -> fixed_addr)) + continue; + for (i = 0; i < hp -> fixed_addr -> len; i += 4) { + ip_address.len = 4; + memcpy (ip_address.iabuf, + hp -> fixed_addr -> value + i, 4); + subnet = find_grouped_subnet (share, ip_address); + if (subnet) { + *addr = ip_address; + *host = hp; + return subnet; + } + } + } + return (struct _subnet *)0; +} + +void new_address_range (iaddr low, iaddr high, subnet *subnet, int dynamic) +{ + lease *address_range, *lp, *plp; + iaddr net; + int min, max, i; + char lowbuf [16], highbuf [16], netbuf [16]; + shared_network *share = subnet -> shared_network; + struct hostent *h; + struct in_addr ia; + + /* All subnets should have attached shared network structures. */ + if (!share) { + strcpy (netbuf, piaddr (subnet -> net)); + error ("No shared network for network %s (%s)", + netbuf, piaddr (subnet -> netmask)); + } + + /* Initialize the hash table if it hasn't been done yet. */ + if (!lease_uid_hash) + lease_uid_hash = new_hash (); + if (!lease_ip_addr_hash) + lease_ip_addr_hash = new_hash (); + if (!lease_hw_addr_hash) + lease_hw_addr_hash = new_hash (); + + /* Make sure that high and low addresses are in same subnet. */ + net = subnet_number (low, subnet -> netmask); + if (!addr_eq (net, subnet_number (high, subnet -> netmask))) { + strcpy (lowbuf, piaddr (low)); + strcpy (highbuf, piaddr (high)); + strcpy (netbuf, piaddr (subnet -> netmask)); + error ("Address range %s to %s, netmask %s spans %s!", + lowbuf, highbuf, netbuf, "multiple subnets"); + } + + /* Make sure that the addresses are on the correct subnet. */ + if (!addr_eq (net, subnet -> net)) { + strcpy (lowbuf, piaddr (low)); + strcpy (highbuf, piaddr (high)); + strcpy (netbuf, piaddr (subnet -> netmask)); + error ("Address range %s to %s not on net %s/%s!", + lowbuf, highbuf, piaddr (subnet -> net), netbuf); + } + + /* Get the high and low host addresses... */ + max = host_addr (high, subnet -> netmask); + min = host_addr (low, subnet -> netmask); + + /* Allow range to be specified high-to-low as well as low-to-high. */ + if (min > max) { + max = min; + min = host_addr (high, subnet -> netmask); + } + + /* Get a lease structure for each address in the range. */ + address_range = new_leases (max - min + 1, "new_address_range"); + if (!address_range) { + strcpy (lowbuf, piaddr (low)); + strcpy (highbuf, piaddr (high)); + error ("No memory for address range %s-%s.", lowbuf, highbuf); + } + memset (address_range, 0, (sizeof *address_range) * (max - min + 1)); + + /* Fill in the last lease if it hasn't been already... */ + if (!share -> last_lease) { + share -> last_lease = &address_range [0]; + } + + /* Fill out the lease structures with some minimal information. */ + for (i = 0; i < max - min + 1; i++) { + address_range [i].ip_addr = + ip_addr (subnet -> net, subnet -> netmask, i + min); + address_range [i].starts = + address_range [i].timestamp = MIN_TIME; + address_range [i].ends = MIN_TIME; + address_range [i].subnet = subnet; + address_range [i].shared_network = share; + address_range [i].flags = dynamic ? DYNAMIC_BOOTP_OK : 0; + + memcpy (&ia, address_range [i].ip_addr.iabuf, 4); + + if (subnet -> group -> get_lease_hostnames) { + h = gethostbyaddr ((char *)&ia, sizeof ia, AF_INET); + if (!h) + warn ("No hostname for %s", inet_ntoa (ia)); + else { + address_range [i].hostname = + malloc (strlen (h -> h_name) + 1); + if (!address_range [i].hostname) + error ("no memory for hostname %s.", + h -> h_name); + strcpy (address_range [i].hostname, + h -> h_name); + } + } + + /* Link this entry into the list. */ + address_range [i].next = share -> leases; + address_range [i].prev = (struct lease *)0; + share -> leases = &address_range [i]; + if (address_range [i].next) + address_range [i].next -> prev = share -> leases; + add_hash (lease_ip_addr_hash, + address_range [i].ip_addr.iabuf, + address_range [i].ip_addr.len, + (unsigned char *)&address_range [i]); + } + + /* Find out if any dangling leases are in range... */ + plp = (struct lease *)0; + for (lp = dangling_leases; lp; lp = lp -> next) { + iaddr lnet; + int lhost; + + lnet = subnet_number (lp -> ip_addr, subnet -> netmask); + lhost = host_addr (lp -> ip_addr, subnet -> netmask); + + /* If it's in range, fill in the real lease structure with + the dangling lease's values, and remove the lease from + the list of dangling leases. */ + if (addr_eq (lnet, subnet -> net) && + lhost >= i && lhost <= max) { + if (plp) { + plp -> next = lp -> next; + } else { + dangling_leases = lp -> next; + } + lp -> next = (struct lease *)0; + address_range [lhost - i].hostname = lp -> hostname; + address_range [lhost - i].client_hostname = + lp -> client_hostname; + supersede_lease (&address_range [lhost - i], lp, 0); + free_lease (lp, "new_address_range"); + } else + plp = lp; + } +} + +subnet *find_subnet (iaddr addr) +{ + subnet *rv; + + for (rv = subnets; rv; rv = rv -> next_subnet) { + if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) + return rv; + } + return (subnet *)0; +} + +subnet *find_grouped_subnet (shared_network *share, iaddr addr) +{ + subnet *rv; + + for (rv = share -> subnets; rv; rv = rv -> next_sibling) { + if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) + return rv; + } + return (subnet *)0; +} + +int subnet_inner_than (struct _subnet *subnet, struct _subnet *scan, int warnp) +{ + if (addr_eq (subnet_number (subnet -> net, scan -> netmask), + scan -> net) || + addr_eq (subnet_number (scan -> net, subnet -> netmask), + subnet -> net)) { + char n1buf [16]; + int i, j; + for (i = 0; i < 32; i++) + if (subnet -> netmask.iabuf [3 - (i >> 3)] + & (1 << (i & 7))) + break; + for (j = 0; j < 32; j++) + if (scan -> netmask.iabuf [3 - (j >> 3)] & + (1 << (j & 7))) + break; + strcpy (n1buf, piaddr (subnet -> net)); + if (warnp) + warn ("%ssubnet %s/%d conflicts with subnet %s/%d", + "Warning: ", n1buf, 32 - i, + piaddr (scan -> net), 32 - j); + if (i < j) + return 1; + } + return 0; +} + +/* Enter a new subnet into the subnet list. */ + +void enter_subnet (struct _subnet *subnet) +{ + struct _subnet *scan, *prev = (struct _subnet *)0; + + /* Check for duplicates... */ + for (scan = subnets; scan; scan = scan -> next_subnet) { + /* When we find a conflict, make sure that the + subnet with the narrowest subnet mask comes + first. */ + if (subnet_inner_than (subnet, scan, 1)) { + if (prev) { + prev -> next_subnet = subnet; + } else + subnets = subnet; + subnet -> next_subnet = scan; + return; + } + prev = scan; + } + + /* XXX use the BSD radix tree code instead of a linked list. */ + subnet -> next_subnet = subnets; + subnets = subnet; +} + +/* Enter a new shared network into the shared network list. */ + +void enter_shared_network (shared_network *share) +{ + /* XXX Sort the nets into a balanced tree to make searching quicker. */ + share -> next = shared_networks; + shared_networks = share; +} + +/* Enter a lease into the system. This is called by the parser each + time it reads in a new lease. If the subnet for that lease has + already been read in (usually the case), just update that lease; + otherwise, allocate temporary storage for the lease and keep it around + until we're done reading in the config file. */ + +void enter_lease (struct _lease *lease) +{ + struct _lease *comp = find_lease_by_ip_addr (lease -> ip_addr); + + /* If we don't have a place for this lease yet, save it for + later. */ + if (!comp) { + comp = new_lease ("enter_lease"); + if (!comp) { + error ("No memory for lease %s\n", + piaddr (lease -> ip_addr)); + } + *comp = *lease; + comp -> next = dangling_leases; + comp -> prev = (struct lease *)0; + dangling_leases = comp; + } else { + /* Record the hostname information in the lease. */ + comp -> hostname = lease -> hostname; + comp -> client_hostname = lease -> client_hostname; + supersede_lease (comp, lease, 0); + } +} + +/* Replace the data in an existing lease with the data in a new lease; + adjust hash tables to suit, and insertion sort the lease into the + list of leases by expiry time so that we can always find the oldest + lease. */ + +int supersede_lease (struct _lease *comp, struct _lease *lease, int commit) +{ + int enter_uid = 0; + int enter_hwaddr = 0; + struct _lease *lp; + + /* Static leases are not currently kept in the database... */ + if (lease -> flags & STATIC_LEASE) + return 1; + + /* If the existing lease hasn't expired and has a different + unique identifier or, if it doesn't have a unique + identifier, a different hardware address, then the two + leases are in conflict. If the existing lease has a uid + and the new one doesn't, but they both have the same + hardware address, and dynamic bootp is allowed on this + lease, then we allow that, in case a dynamic BOOTP lease is + requested *after* a DHCP lease has been assigned. */ + + if (!(lease -> flags & ABANDONED_LEASE) && + comp -> ends > cur_time && + (((comp -> uid && lease -> uid) && + (comp -> uid_len != lease -> uid_len || + memcmp (comp -> uid, lease -> uid, comp -> uid_len))) || + (!comp -> uid && + ((comp -> hardware_addr.htype != + lease -> hardware_addr.htype) || + (comp -> hardware_addr.hlen != + lease -> hardware_addr.hlen) || + memcmp (comp -> hardware_addr.haddr, + lease -> hardware_addr.haddr, + comp -> hardware_addr.hlen))))) { + warn ("Lease conflict at %s", + piaddr (comp -> ip_addr)); + return 0; + } else { + /* If there's a Unique ID, dissociate it from the hash + table and free it if necessary. */ + if (comp -> uid) { + uid_hash_delete (comp); + enter_uid = 1; + if (comp -> uid != &comp -> uid_buf [0]) { + free (comp -> uid); + comp -> uid_max = 0; + comp -> uid_len = 0; + } + comp -> uid = (unsigned char *)0; + } else + enter_uid = 1; + + if (comp -> hardware_addr.htype && + ((comp -> hardware_addr.hlen != + lease -> hardware_addr.hlen) || + (comp -> hardware_addr.htype != + lease -> hardware_addr.htype) || + memcmp (comp -> hardware_addr.haddr, + lease -> hardware_addr.haddr, + comp -> hardware_addr.hlen))) { + hw_hash_delete (comp); + enter_hwaddr = 1; + } else if (!comp -> hardware_addr.htype) + enter_hwaddr = 1; + + /* Copy the data files, but not the linkages. */ + comp -> starts = lease -> starts; + if (lease -> uid) { + if (lease -> uid_len < sizeof (lease -> uid_buf)) { + memcpy (comp -> uid_buf, + lease -> uid, lease -> uid_len); + comp -> uid = &comp -> uid_buf [0]; + comp -> uid_max = sizeof comp -> uid_buf; + } else if (lease -> uid != &lease -> uid_buf [0]) { + comp -> uid = lease -> uid; + comp -> uid_max = lease -> uid_max; + lease -> uid = (unsigned char *)0; + lease -> uid_max = 0; + } else { + error ("corrupt lease uid."); /* XXX */ + } + } else { + comp -> uid = (unsigned char *)0; + comp -> uid_max = 0; + } + comp -> uid_len = lease -> uid_len; + comp -> host = lease -> host; + comp -> hardware_addr = lease -> hardware_addr; + comp -> flags = ((lease -> flags & ~PERSISTENT_FLAGS) | + (comp -> flags & ~EPHEMERAL_FLAGS)); + + /* Record the lease in the uid hash if necessary. */ + if (enter_uid && lease -> uid) { + uid_hash_add (comp); + } + + /* Record it in the hardware address hash if necessary. */ + if (enter_hwaddr && lease -> hardware_addr.htype) { + hw_hash_add (comp); + } + + /* Remove the lease from its current place in the + timeout sequence. */ + if (comp -> prev) { + comp -> prev -> next = comp -> next; + } else { + comp -> shared_network -> leases = comp -> next; + } + if (comp -> next) { + comp -> next -> prev = comp -> prev; + } + if (comp -> shared_network -> last_lease == comp) { + comp -> shared_network -> last_lease = comp -> prev; + } + + /* Find the last insertion point... */ + if (comp == comp -> shared_network -> insertion_point || + !comp -> shared_network -> insertion_point) { + lp = comp -> shared_network -> leases; + } else { + lp = comp -> shared_network -> insertion_point; + } + + if (!lp) { + /* Nothing on the list yet? Just make comp the + head of the list. */ + comp -> shared_network -> leases = comp; + comp -> shared_network -> last_lease = comp; + } else if (lp -> ends > lease -> ends) { + /* Skip down the list until we run out of list + or find a place for comp. */ + while (lp -> next && lp -> ends > lease -> ends) { + lp = lp -> next; + } + if (lp -> ends > lease -> ends) { + /* If we ran out of list, put comp + at the end. */ + lp -> next = comp; + comp -> prev = lp; + comp -> next = (struct lease *)0; + comp -> shared_network -> last_lease = comp; + } else { + /* If we didn't, put it between lp and + the previous item on the list. */ + if ((comp -> prev = lp -> prev)) + comp -> prev -> next = comp; + comp -> next = lp; + lp -> prev = comp; + } + } else { + /* Skip up the list until we run out of list + or find a place for comp. */ + while (lp -> prev && lp -> ends < lease -> ends) { + lp = lp -> prev; + } + if (lp -> ends < lease -> ends) { + /* If we ran out of list, put comp + at the beginning. */ + lp -> prev = comp; + comp -> next = lp; + comp -> prev = (struct lease *)0; + comp -> shared_network -> leases = comp; + } else { + /* If we didn't, put it between lp and + the next item on the list. */ + if ((comp -> next = lp -> next)) + comp -> next -> prev = comp; + comp -> prev = lp; + lp -> next = comp; + } + } + comp -> shared_network -> insertion_point = comp; + comp -> ends = lease -> ends; + } + + /* Return zero if we didn't commit the lease to permanent storage; + nonzero if we did. */ + return commit && write_lease (comp) && commit_leases (); +} + +/* Release the specified lease and re-hash it as appropriate. */ + +void release_lease (struct _lease *lease) +{ + struct _lease lt; + + lt = *lease; + if (lt.ends > cur_time) { + lt.ends = cur_time; + supersede_lease (lease, <, 1); + } +} + +/* Abandon the specified lease (set its timeout to infinity and its + particulars to zero, and re-hash it as appropriate. */ + +void abandon_lease (struct _lease *lease, char *message) +{ + struct _lease lt; + + lease -> flags |= ABANDONED_LEASE; + lt = *lease; + lt.ends = cur_time; + warn ("Abandoning IP address %s: %s", + piaddr (lease -> ip_addr), message); + lt.hardware_addr.htype = 0; + lt.hardware_addr.hlen = 0; + lt.uid = (unsigned char *)0; + lt.uid_len = 0; + supersede_lease (lease, <, 1); +} + +/* Locate the lease associated with a given IP address... */ + +lease *find_lease_by_ip_addr (iaddr addr) +{ + lease *lease = (struct _lease *)hash_lookup (lease_ip_addr_hash, + addr.iabuf, + addr.len); + return lease; +} + +lease *find_lease_by_uid (unsigned char *uid, int len) +{ + lease *lease = (struct lease *)hash_lookup (lease_uid_hash, + uid, len); + return lease; +} + +lease *find_lease_by_hw_addr (unsigned char *hwaddr, int hwlen) +{ + struct _lease *lease = + (struct _lease *)hash_lookup (lease_hw_addr_hash, + hwaddr, hwlen); + return lease; +} + +/* Add the specified lease to the uid hash. */ + +void uid_hash_add (lease *lease) +{ + struct _lease *head = find_lease_by_uid (lease -> uid, lease -> uid_len); + struct _lease *scan; + +#ifdef DEBUG + if (lease -> n_uid) + abort (); +#endif + + /* If it's not in the hash, just add it. */ + if (!head) + add_hash (lease_uid_hash, lease -> uid, + lease -> uid_len, (unsigned char *)lease); + else { + /* Otherwise, attach it to the end of the list. */ + for (scan = head; scan -> n_uid; scan = scan -> n_uid) +#ifdef DEBUG + if (scan == lease) + abort () +#endif + ; + scan -> n_uid = lease; + } +} + +/* Delete the specified lease from the uid hash. */ + +void uid_hash_delete (lease *lease) +{ + struct _lease *head = + find_lease_by_uid (lease -> uid, lease -> uid_len); + struct _lease *scan; + + /* If it's not in the hash, we have no work to do. */ + if (!head) { + lease -> n_uid = (struct lease *)0; + return; + } + + /* If the lease we're freeing is at the head of the list, + remove the hash table entry and add a new one with the + next lease on the list (if there is one). */ + if (head == lease) { + delete_hash_entry (lease_uid_hash, + lease -> uid, lease -> uid_len); + if (lease -> n_uid) + add_hash (lease_uid_hash, + lease -> n_uid -> uid, + lease -> n_uid -> uid_len, + (unsigned char *)(lease -> n_uid)); + } else { + /* Otherwise, look for the lease in the list of leases + attached to the hash table entry, and remove it if + we find it. */ + for (scan = head; scan -> n_uid; scan = scan -> n_uid) { + if (scan -> n_uid == lease) { + scan -> n_uid = scan -> n_uid -> n_uid; + break; + } + } + } + lease -> n_uid = (struct lease *)0; +} + +/* Add the specified lease to the hardware address hash. */ + +void hw_hash_add (lease *lease) +{ + struct _lease *head = + find_lease_by_hw_addr (lease -> hardware_addr.haddr, + lease -> hardware_addr.hlen); + struct _lease *scan; + + /* If it's not in the hash, just add it. */ + if (!head) + add_hash (lease_hw_addr_hash, + lease -> hardware_addr.haddr, + lease -> hardware_addr.hlen, + (unsigned char *)lease); + else { + /* Otherwise, attach it to the end of the list. */ + for (scan = head; scan -> n_hw; scan = scan -> n_hw) + ; + scan -> n_hw = lease; + } +} + +/* Delete the specified lease from the hardware address hash. */ + +void hw_hash_delete (lease *lease) +{ + struct _lease *head = + find_lease_by_hw_addr (lease -> hardware_addr.haddr, + lease -> hardware_addr.hlen); + struct _lease *scan; + + /* If it's not in the hash, we have no work to do. */ + if (!head) { + lease -> n_hw = (struct lease *)0; + return; + } + + /* If the lease we're freeing is at the head of the list, + remove the hash table entry and add a new one with the + next lease on the list (if there is one). */ + if (head == lease) { + delete_hash_entry (lease_hw_addr_hash, + lease -> hardware_addr.haddr, + lease -> hardware_addr.hlen); + if (lease -> n_hw) + add_hash (lease_hw_addr_hash, + lease -> n_hw -> hardware_addr.haddr, + lease -> n_hw -> hardware_addr.hlen, + (unsigned char *)(lease -> n_hw)); + } else { + /* Otherwise, look for the lease in the list of leases + attached to the hash table entry, and remove it if + we find it. */ + for (scan = head; scan -> n_hw; scan = scan -> n_hw) { + if (scan -> n_hw == lease) { + scan -> n_hw = scan -> n_hw -> n_hw; + break; + } + } + } + lease -> n_hw = (struct lease *)0; +} + + +struct class *add_class (type, name) + int type; + char *name; +{ + struct class *class = new_class ("add_class"); + char *tname = (char *)malloc (strlen (name) + 1); + + if (!vendor_class_hash) + vendor_class_hash = new_hash (); + if (!user_class_hash) + user_class_hash = new_hash (); + + if (!tname || !class || !vendor_class_hash || !user_class_hash) + return (struct class *)0; + + memset (class, 0, sizeof *class); + strcpy (tname, name); + class -> name = tname; + + if (type) + add_hash (user_class_hash, + (unsigned char *)tname, strlen (tname), + (unsigned char *)class); + else + add_hash (vendor_class_hash, + (unsigned char *)tname, strlen (tname), + (unsigned char *)class); + return class; +} + +struct class *find_class (type, name, len) + int type; + unsigned char *name; + int len; +{ + struct class *class = + (struct class *)hash_lookup (type + ? user_class_hash + : vendor_class_hash, name, len); + return class; +} + +struct group *clone_group (group, caller) + struct group *group; + char *caller; +{ + struct group *g = new_group (caller); + if (!g) + error ("%s: can't allocate new group", caller); + *g = *group; + return g; +} + +/* Write all interesting leases to permanent storage. */ + +void write_leases () +{ + lease *l; + shared_network *s; + + for (s = shared_networks; s; s = (shared_network *)s -> next) { + for (l = s -> leases; l; l = l -> next) { + if (l -> hardware_addr.hlen || + l -> uid_len || + (l -> flags & ABANDONED_LEASE)) + if (!write_lease (l)) + error ("Can't rewrite lease database"); + } + } + if (!commit_leases ()) + error ("Can't commit leases to new database: %m"); +} + +void dump_subnets () +{ + struct _lease *l; + shared_network *s; + subnet *n; + + note ("Subnets:"); + for (n = subnets; n; n = n -> next_subnet) { + debug (" Subnet %s", piaddr (n -> net)); + debug (" netmask %s", + piaddr (n -> netmask)); + } + note ("Shared networks:"); + for (s = shared_networks; s; s = (shared_network *)s -> next) { + note (" %s", s -> name); + for (l = s -> leases; l; l = l -> next) { + print_lease (l); + } + if (s -> last_lease) { + debug (" Last Lease:"); + print_lease (s -> last_lease); + } + } +} diff --git a/reactos/subsys/system/dhcp/options.c b/reactos/subsys/system/dhcp/options.c new file mode 100644 index 00000000000..a037712982f --- /dev/null +++ b/reactos/subsys/system/dhcp/options.c @@ -0,0 +1,718 @@ +/* $OpenBSD: options.c,v 1.15 2004/12/26 03:17:07 deraadt Exp $ */ + +/* DHCP options parsing and reassembly. */ + +/* + * Copyright (c) 1995, 1996, 1997, 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 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 + +#define DHCP_OPTION_DATA +#include "rosdhcp.h" +#include "dhcpd.h" + +int bad_options = 0; +int bad_options_max = 5; + +void parse_options(struct packet *); +void parse_option_buffer(struct packet *, unsigned char *, int); +int store_options(unsigned char *, int, struct tree_cache **, + unsigned char *, int, int, int, int); + + +/* + * Parse all available options out of the specified packet. + */ +void +parse_options(struct packet *packet) +{ + /* Initially, zero all option pointers. */ + memset(packet->options, 0, sizeof(packet->options)); + + /* If we don't see the magic cookie, there's nothing to parse. */ + if (memcmp(packet->raw->options, DHCP_OPTIONS_COOKIE, 4)) { + packet->options_valid = 0; + return; + } + + /* + * Go through the options field, up to the end of the packet or + * the End field. + */ + parse_option_buffer(packet, &packet->raw->options[4], + packet->packet_length - DHCP_FIXED_NON_UDP - 4); + + /* + * If we parsed a DHCP Option Overload option, parse more + * options out of the buffer(s) containing them. + */ + if (packet->options_valid && + packet->options[DHO_DHCP_OPTION_OVERLOAD].data) { + if (packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1) + parse_option_buffer(packet, + (unsigned char *)packet->raw->file, + sizeof(packet->raw->file)); + if (packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2) + parse_option_buffer(packet, + (unsigned char *)packet->raw->sname, + sizeof(packet->raw->sname)); + } +} + +/* + * Parse options out of the specified buffer, storing addresses of + * option values in packet->options and setting packet->options_valid if + * no errors are encountered. + */ +void +parse_option_buffer(struct packet *packet, + unsigned char *buffer, int length) +{ + unsigned char *s, *t, *end = buffer + length; + int len, code; + + for (s = buffer; *s != DHO_END && s < end; ) { + code = s[0]; + + /* Pad options don't have a length - just skip them. */ + if (code == DHO_PAD) { + s++; + continue; + } + if (s + 2 > end) { + len = 65536; + goto bogus; + } + + /* + * All other fields (except end, see above) have a + * one-byte length. + */ + len = s[1]; + + /* + * If the length is outrageous, silently skip the rest, + * and mark the packet bad. Unfortunately some crappy + * dhcp servers always seem to give us garbage on the + * end of a packet. so rather than keep refusing, give + * up and try to take one after seeing a few without + * anything good. + */ + if (s + len + 2 > end) { + bogus: + bad_options++; + warning("option %s (%d) %s.", + dhcp_options[code].name, len, + "larger than buffer"); + if (bad_options == bad_options_max) { + packet->options_valid = 1; + bad_options = 0; + warning("Many bogus options seen in offers. " + "Taking this offer in spite of bogus " + "options - hope for the best!"); + } else { + warning("rejecting bogus offer."); + packet->options_valid = 0; + } + return; + } + /* + * If we haven't seen this option before, just make + * space for it and copy it there. + */ + if (!packet->options[code].data) { + if (!(t = calloc(1, len + 1))) + error("Can't allocate storage for option %s.", + dhcp_options[code].name); + /* + * Copy and NUL-terminate the option (in case + * it's an ASCII string. + */ + memcpy(t, &s[2], len); + t[len] = 0; + packet->options[code].len = len; + packet->options[code].data = t; + } else { + /* + * If it's a repeat, concatenate it to whatever + * we last saw. This is really only required + * for clients, but what the heck... + */ + t = calloc(1, len + packet->options[code].len + 1); + if (!t) + error("Can't expand storage for option %s.", + dhcp_options[code].name); + memcpy(t, packet->options[code].data, + packet->options[code].len); + memcpy(t + packet->options[code].len, + &s[2], len); + packet->options[code].len += len; + t[packet->options[code].len] = 0; + free(packet->options[code].data); + packet->options[code].data = t; + } + s += len + 2; + } + packet->options_valid = 1; +} + +/* + * cons options into a big buffer, and then split them out into the + * three separate buffers if needed. This allows us to cons up a set of + * vendor options using the same routine. + */ +int +cons_options(struct packet *inpacket, struct dhcp_packet *outpacket, + int mms, struct tree_cache **options, + int overload, /* Overload flags that may be set. */ + int terminate, int bootpp, u_int8_t *prl, int prl_len) +{ + unsigned char priority_list[300], buffer[4096]; + int priority_len, main_buffer_size, mainbufix, bufix; + int option_size, length; + + /* + * If the client has provided a maximum DHCP message size, use + * that; otherwise, if it's BOOTP, only 64 bytes; otherwise use + * up to the minimum IP MTU size (576 bytes). + * + * XXX if a BOOTP client specifies a max message size, we will + * honor it. + */ + if (!mms && + inpacket && + inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].data && + (inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].len >= + sizeof(u_int16_t))) + mms = getUShort( + inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].data); + + if (mms) + main_buffer_size = mms - DHCP_FIXED_LEN; + else if (bootpp) + main_buffer_size = 64; + else + main_buffer_size = 576 - DHCP_FIXED_LEN; + + if (main_buffer_size > sizeof(buffer)) + main_buffer_size = sizeof(buffer); + + /* Preload the option priority list with mandatory options. */ + priority_len = 0; + priority_list[priority_len++] = DHO_DHCP_MESSAGE_TYPE; + priority_list[priority_len++] = DHO_DHCP_SERVER_IDENTIFIER; + priority_list[priority_len++] = DHO_DHCP_LEASE_TIME; + priority_list[priority_len++] = DHO_DHCP_MESSAGE; + + /* + * If the client has provided a list of options that it wishes + * returned, use it to prioritize. Otherwise, prioritize based + * on the default priority list. + */ + if (inpacket && + inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].data) { + int prlen = + inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].len; + if (prlen + priority_len > sizeof(priority_list)) + prlen = sizeof(priority_list) - priority_len; + + memcpy(&priority_list[priority_len], + inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].data, + prlen); + priority_len += prlen; + prl = priority_list; + } else if (prl) { + if (prl_len + priority_len > sizeof(priority_list)) + prl_len = sizeof(priority_list) - priority_len; + + memcpy(&priority_list[priority_len], prl, prl_len); + priority_len += prl_len; + prl = priority_list; + } else { + memcpy(&priority_list[priority_len], + dhcp_option_default_priority_list, + sizeof_dhcp_option_default_priority_list); + priority_len += sizeof_dhcp_option_default_priority_list; + } + + /* Copy the options into the big buffer... */ + option_size = store_options( + buffer, + (main_buffer_size - 7 + ((overload & 1) ? DHCP_FILE_LEN : 0) + + ((overload & 2) ? DHCP_SNAME_LEN : 0)), + options, priority_list, priority_len, main_buffer_size, + (main_buffer_size + ((overload & 1) ? DHCP_FILE_LEN : 0)), + terminate); + + /* Put the cookie up front... */ + memcpy(outpacket->options, DHCP_OPTIONS_COOKIE, 4); + mainbufix = 4; + + /* + * If we're going to have to overload, store the overload option + * at the beginning. If we can, though, just store the whole + * thing in the packet's option buffer and leave it at that. + */ + if (option_size <= main_buffer_size - mainbufix) { + memcpy(&outpacket->options[mainbufix], + buffer, option_size); + mainbufix += option_size; + if (mainbufix < main_buffer_size) + outpacket->options[mainbufix++] = DHO_END; + length = DHCP_FIXED_NON_UDP + mainbufix; + } else { + outpacket->options[mainbufix++] = DHO_DHCP_OPTION_OVERLOAD; + outpacket->options[mainbufix++] = 1; + if (option_size > + main_buffer_size - mainbufix + DHCP_FILE_LEN) + outpacket->options[mainbufix++] = 3; + else + outpacket->options[mainbufix++] = 1; + + memcpy(&outpacket->options[mainbufix], + buffer, main_buffer_size - mainbufix); + bufix = main_buffer_size - mainbufix; + length = DHCP_FIXED_NON_UDP + mainbufix; + if (overload & 1) { + if (option_size - bufix <= DHCP_FILE_LEN) { + memcpy(outpacket->file, + &buffer[bufix], option_size - bufix); + mainbufix = option_size - bufix; + if (mainbufix < DHCP_FILE_LEN) + outpacket->file[mainbufix++] = (char)DHO_END; + while (mainbufix < DHCP_FILE_LEN) + outpacket->file[mainbufix++] = (char)DHO_PAD; + } else { + memcpy(outpacket->file, + &buffer[bufix], DHCP_FILE_LEN); + bufix += DHCP_FILE_LEN; + } + } + if ((overload & 2) && option_size < bufix) { + memcpy(outpacket->sname, + &buffer[bufix], option_size - bufix); + + mainbufix = option_size - bufix; + if (mainbufix < DHCP_SNAME_LEN) + outpacket->file[mainbufix++] = (char)DHO_END; + while (mainbufix < DHCP_SNAME_LEN) + outpacket->file[mainbufix++] = (char)DHO_PAD; + } + } + return (length); +} + +/* + * Store all the requested options into the requested buffer. + */ +int +store_options(unsigned char *buffer, int buflen, struct tree_cache **options, + unsigned char *priority_list, int priority_len, int first_cutoff, + int second_cutoff, int terminate) +{ + int bufix = 0, option_stored[256], i, ix, tto; + + /* Zero out the stored-lengths array. */ + memset(option_stored, 0, sizeof(option_stored)); + + /* + * Copy out the options in the order that they appear in the + * priority list... + */ + for (i = 0; i < priority_len; i++) { + /* Code for next option to try to store. */ + int code = priority_list[i]; + int optstart; + + /* + * Number of bytes left to store (some may already have + * been stored by a previous pass). + */ + int length; + + /* If no data is available for this option, skip it. */ + if (!options[code]) { + continue; + } + + /* + * The client could ask for things that are mandatory, + * in which case we should avoid storing them twice... + */ + if (option_stored[code]) + continue; + option_stored[code] = 1; + + /* We should now have a constant length for the option. */ + length = options[code]->len; + + /* Do we add a NUL? */ + if (terminate && dhcp_options[code].format[0] == 't') { + length++; + tto = 1; + } else + tto = 0; + + /* Try to store the option. */ + + /* + * If the option's length is more than 255, we must + * store it in multiple hunks. Store 255-byte hunks + * first. However, in any case, if the option data will + * cross a buffer boundary, split it across that + * boundary. + */ + ix = 0; + + optstart = bufix; + while (length) { + unsigned char incr = length > 255 ? 255 : length; + + /* + * If this hunk of the buffer will cross a + * boundary, only go up to the boundary in this + * pass. + */ + if (bufix < first_cutoff && + bufix + incr > first_cutoff) + incr = first_cutoff - bufix; + else if (bufix < second_cutoff && + bufix + incr > second_cutoff) + incr = second_cutoff - bufix; + + /* + * If this option is going to overflow the + * buffer, skip it. + */ + if (bufix + 2 + incr > buflen) { + bufix = optstart; + break; + } + + /* Everything looks good - copy it in! */ + buffer[bufix] = code; + buffer[bufix + 1] = incr; + if (tto && incr == length) { + memcpy(buffer + bufix + 2, + options[code]->value + ix, incr - 1); + buffer[bufix + 2 + incr - 1] = 0; + } else + memcpy(buffer + bufix + 2, + options[code]->value + ix, incr); + length -= incr; + ix += incr; + bufix += 2 + incr; + } + } + return (bufix); +} + +/* + * Format the specified option so that a human can easily read it. + */ +char * +pretty_print_option(unsigned int code, unsigned char *data, int len, + int emit_commas, int emit_quotes) +{ + static char optbuf[32768]; /* XXX */ + int hunksize = 0, numhunk = -1, numelem = 0; + char fmtbuf[32], *op = optbuf; + int i, j, k, opleft = sizeof(optbuf); + unsigned char *dp = data; + struct in_addr foo; + char comma; + + /* Code should be between 0 and 255. */ + if (code > 255) + error("pretty_print_option: bad code %d", code); + + if (emit_commas) + comma = ','; + else + comma = ' '; + + /* Figure out the size of the data. */ + for (i = 0; dhcp_options[code].format[i]; i++) { + if (!numhunk) { + warning("%s: Excess information in format string: %s", + dhcp_options[code].name, + &(dhcp_options[code].format[i])); + break; + } + numelem++; + fmtbuf[i] = dhcp_options[code].format[i]; + switch (dhcp_options[code].format[i]) { + case 'A': + --numelem; + fmtbuf[i] = 0; + numhunk = 0; + break; + case 'X': + for (k = 0; k < len; k++) + if (!isascii(data[k]) || + !isprint(data[k])) + break; + if (k == len) { + fmtbuf[i] = 't'; + numhunk = -2; + } else { + fmtbuf[i] = 'x'; + hunksize++; + comma = ':'; + numhunk = 0; + } + fmtbuf[i + 1] = 0; + break; + case 't': + fmtbuf[i] = 't'; + fmtbuf[i + 1] = 0; + numhunk = -2; + break; + case 'I': + case 'l': + case 'L': + hunksize += 4; + break; + case 's': + case 'S': + hunksize += 2; + break; + case 'b': + case 'B': + case 'f': + hunksize++; + break; + case 'e': + break; + default: + warning("%s: garbage in format string: %s", + dhcp_options[code].name, + &(dhcp_options[code].format[i])); + break; + } + } + + /* Check for too few bytes... */ + if (hunksize > len) { + warning("%s: expecting at least %d bytes; got %d", + dhcp_options[code].name, hunksize, len); + return (""); + } + /* Check for too many bytes... */ + if (numhunk == -1 && hunksize < len) + warning("%s: %d extra bytes", + dhcp_options[code].name, len - hunksize); + + /* If this is an array, compute its size. */ + if (!numhunk) + numhunk = len / hunksize; + /* See if we got an exact number of hunks. */ + if (numhunk > 0 && numhunk * hunksize < len) + warning("%s: %d extra bytes at end of array", + dhcp_options[code].name, len - numhunk * hunksize); + + /* A one-hunk array prints the same as a single hunk. */ + if (numhunk < 0) + numhunk = 1; + + /* Cycle through the array (or hunk) printing the data. */ + for (i = 0; i < numhunk; i++) { + for (j = 0; j < numelem; j++) { + int opcount; + switch (fmtbuf[j]) { + case 't': + if (emit_quotes) { + *op++ = '"'; + opleft--; + } + for (; dp < data + len; dp++) { + if (!isascii(*dp) || + !isprint(*dp)) { + if (dp + 1 != data + len || + *dp != 0) { + snprintf(op, opleft, + "\\%03o", *dp); + op += 4; + opleft -= 4; + } + } else if (*dp == '"' || + *dp == '\'' || + *dp == '$' || + *dp == '`' || + *dp == '\\') { + *op++ = '\\'; + *op++ = *dp; + opleft -= 2; + } else { + *op++ = *dp; + opleft--; + } + } + if (emit_quotes) { + *op++ = '"'; + opleft--; + } + + *op = 0; + break; + case 'I': + foo.s_addr = htonl(getULong(dp)); + opcount = strlcpy(op, inet_ntoa(foo), opleft); + if (opcount >= opleft) + goto toobig; + opleft -= opcount; + dp += 4; + break; + case 'l': + opcount = snprintf(op, opleft, "%ld", + (long)getLong(dp)); + if (opcount >= opleft || opcount == -1) + goto toobig; + opleft -= opcount; + dp += 4; + break; + case 'L': + opcount = snprintf(op, opleft, "%ld", + (unsigned long)getULong(dp)); + if (opcount >= opleft || opcount == -1) + goto toobig; + opleft -= opcount; + dp += 4; + break; + case 's': + opcount = snprintf(op, opleft, "%d", + getShort(dp)); + if (opcount >= opleft || opcount == -1) + goto toobig; + opleft -= opcount; + dp += 2; + break; + case 'S': + opcount = snprintf(op, opleft, "%d", + getUShort(dp)); + if (opcount >= opleft || opcount == -1) + goto toobig; + opleft -= opcount; + dp += 2; + break; + case 'b': + opcount = snprintf(op, opleft, "%d", + *(char *)dp++); + if (opcount >= opleft || opcount == -1) + goto toobig; + opleft -= opcount; + break; + case 'B': + opcount = snprintf(op, opleft, "%d", *dp++); + if (opcount >= opleft || opcount == -1) + goto toobig; + opleft -= opcount; + break; + case 'x': + opcount = snprintf(op, opleft, "%x", *dp++); + if (opcount >= opleft || opcount == -1) + goto toobig; + opleft -= opcount; + break; + case 'f': + opcount = strlcpy(op, + *dp++ ? "true" : "false", opleft); + if (opcount >= opleft) + goto toobig; + opleft -= opcount; + break; + default: + warning("Unexpected format code %c", fmtbuf[j]); + } + op += strlen(op); + opleft -= strlen(op); + if (opleft < 1) + goto toobig; + if (j + 1 < numelem && comma != ':') { + *op++ = ' '; + opleft--; + } + } + if (i + 1 < numhunk) { + *op++ = comma; + opleft--; + } + if (opleft < 1) + goto toobig; + + } + return (optbuf); + toobig: + warning("dhcp option too large"); + return (""); +} + +void +do_packet(struct interface_info *interface, struct dhcp_packet *packet, + int len, unsigned int from_port, struct iaddr from, struct hardware *hfrom) +{ + struct packet tp; + int i; + + if (packet->hlen > sizeof(packet->chaddr)) { + note("Discarding packet with invalid hlen."); + return; + } + + memset(&tp, 0, sizeof(tp)); + tp.raw = packet; + tp.packet_length = len; + tp.client_port = from_port; + tp.client_addr = from; + tp.interface = interface; + tp.haddr = hfrom; + + parse_options(&tp); + if (tp.options_valid && + tp.options[DHO_DHCP_MESSAGE_TYPE].data) + tp.packet_type = tp.options[DHO_DHCP_MESSAGE_TYPE].data[0]; + if (tp.packet_type) + dhcp(&tp); + else + bootp(&tp); + + /* Free the data associated with the options. */ + for (i = 0; i < 256; i++) + if (tp.options[i].len && tp.options[i].data) + free(tp.options[i].data); +} diff --git a/reactos/subsys/system/dhcp/privsep.c b/reactos/subsys/system/dhcp/privsep.c new file mode 100644 index 00000000000..9f36a942d4d --- /dev/null +++ b/reactos/subsys/system/dhcp/privsep.c @@ -0,0 +1,237 @@ +/* $OpenBSD: privsep.c,v 1.7 2004/05/10 18:34:42 deraadt Exp $ */ + +/* + * Copyright (c) 2004 Henning Brauer + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "rosdhcp.h" +#include "dhcpd.h" +#include "privsep.h" + +struct buf * +buf_open(size_t len) +{ + struct buf *buf; + + if ((buf = calloc(1, sizeof(struct buf))) == NULL) + return (NULL); + if ((buf->buf = malloc(len)) == NULL) { + free(buf); + return (NULL); + } + buf->size = len; + + return (buf); +} + +int +buf_add(struct buf *buf, void *data, size_t len) +{ + if (buf->wpos + len > buf->size) + return (-1); + + memcpy(buf->buf + buf->wpos, data, len); + buf->wpos += len; + return (0); +} + +int +buf_close(int sock, struct buf *buf) +{ + ssize_t n; + + do { + n = write(sock, buf->buf + buf->rpos, buf->size - buf->rpos); + if (n != -1) + buf->rpos += n; + if (n == 0) { /* connection closed */ + errno = 0; + return (-1); + } + } while (n == -1 && (errno == EAGAIN || errno == EINTR)); + + if (buf->rpos < buf->size) + error("short write: wanted %lu got %ld bytes", + (unsigned long)buf->size, (long)buf->rpos); + + free(buf->buf); + free(buf); + return (n); +} + +ssize_t +buf_read(int sock, void *buf, size_t nbytes) +{ + ssize_t n, r = 0; + char *p = buf; + + do { + n = read(sock, p, nbytes); + if (n == 0) + error("connection closed"); + if (n != -1) { + r += n; + p += n; + nbytes -= n; + } + } while (n == -1 && (errno == EINTR || errno == EAGAIN)); + + if (n == -1) + error("buf_read: %m"); + + if (r < nbytes) + error("short read: wanted %lu got %ld bytes", + (unsigned long)nbytes, (long)r); + + return (r); +} + +void +dispatch_imsg(int fd) +{ + struct imsg_hdr hdr; + char *medium, *reason, *filename, + *servername, *prefix; + size_t medium_len, reason_len, filename_len, + servername_len, prefix_len, totlen; + struct client_lease lease; + int ret, i, optlen; + struct buf *buf; + + buf_read(fd, &hdr, sizeof(hdr)); + + switch (hdr.code) { + case IMSG_SCRIPT_INIT: + if (hdr.len < sizeof(hdr) + sizeof(size_t)) + error("corrupted message received"); + buf_read(fd, &medium_len, sizeof(medium_len)); + if (hdr.len < medium_len + sizeof(size_t) + sizeof(hdr) + + sizeof(size_t) || medium_len == SIZE_T_MAX) + error("corrupted message received"); + if (medium_len > 0) { + if ((medium = calloc(1, medium_len + 1)) == NULL) + error("%m"); + buf_read(fd, medium, medium_len); + } else + medium = NULL; + + buf_read(fd, &reason_len, sizeof(reason_len)); + if (hdr.len < medium_len + reason_len + sizeof(hdr) || + reason_len == SIZE_T_MAX) + error("corrupted message received"); + if (reason_len > 0) { + if ((reason = calloc(1, reason_len + 1)) == NULL) + error("%m"); + buf_read(fd, reason, reason_len); + } else + reason = NULL; + +// priv_script_init(reason, medium); + free(reason); + free(medium); + break; + case IMSG_SCRIPT_WRITE_PARAMS: + //bzero(&lease, sizeof lease); + memset(&lease, 0, sizeof(lease)); + totlen = sizeof(hdr) + sizeof(lease) + sizeof(size_t); + if (hdr.len < totlen) + error("corrupted message received"); + buf_read(fd, &lease, sizeof(lease)); + + buf_read(fd, &filename_len, sizeof(filename_len)); + totlen += filename_len + sizeof(size_t); + if (hdr.len < totlen || filename_len == SIZE_T_MAX) + error("corrupted message received"); + if (filename_len > 0) { + if ((filename = calloc(1, filename_len + 1)) == NULL) + error("%m"); + buf_read(fd, filename, filename_len); + } else + filename = NULL; + + buf_read(fd, &servername_len, sizeof(servername_len)); + totlen += servername_len + sizeof(size_t); + if (hdr.len < totlen || servername_len == SIZE_T_MAX) + error("corrupted message received"); + if (servername_len > 0) { + if ((servername = + calloc(1, servername_len + 1)) == NULL) + error("%m"); + buf_read(fd, servername, servername_len); + } else + servername = NULL; + + buf_read(fd, &prefix_len, sizeof(prefix_len)); + totlen += prefix_len; + if (hdr.len < totlen || prefix_len == SIZE_T_MAX) + error("corrupted message received"); + if (prefix_len > 0) { + if ((prefix = calloc(1, prefix_len + 1)) == NULL) + error("%m"); + buf_read(fd, prefix, prefix_len); + } else + prefix = NULL; + + for (i = 0; i < 256; i++) { + totlen += sizeof(optlen); + if (hdr.len < totlen) + error("corrupted message received"); + buf_read(fd, &optlen, sizeof(optlen)); + lease.options[i].data = NULL; + lease.options[i].len = optlen; + if (optlen > 0) { + totlen += optlen; + if (hdr.len < totlen || optlen == SIZE_T_MAX) + error("corrupted message received"); + lease.options[i].data = + calloc(1, optlen + 1); + if (lease.options[i].data == NULL) + error("%m"); + buf_read(fd, lease.options[i].data, optlen); + } + } + lease.server_name = servername; + lease.filename = filename; + +// priv_script_write_params(prefix, &lease); + + free(servername); + free(filename); + free(prefix); + for (i = 0; i < 256; i++) + if (lease.options[i].len > 0) + free(lease.options[i].data); + break; + case IMSG_SCRIPT_GO: + if (hdr.len != sizeof(hdr)) + error("corrupted message received"); + +// ret = priv_script_go(); + + hdr.code = IMSG_SCRIPT_GO_RET; + hdr.len = sizeof(struct imsg_hdr) + sizeof(int); + if ((buf = buf_open(hdr.len)) == NULL) + error("buf_open: %m"); + if (buf_add(buf, &hdr, sizeof(hdr))) + error("buf_add: %m"); + if (buf_add(buf, &ret, sizeof(ret))) + error("buf_add: %m"); + if (buf_close(fd, buf) == -1) + error("buf_close: %m"); + break; + default: + error("received unknown message, code %d", hdr.code); + } +} diff --git a/reactos/subsys/system/dhcp/socket.c b/reactos/subsys/system/dhcp/socket.c new file mode 100644 index 00000000000..6af75e5121b --- /dev/null +++ b/reactos/subsys/system/dhcp/socket.c @@ -0,0 +1,24 @@ +#include "rosdhcp.h" + +SOCKET ServerSocket; + +void SocketInit() { + ServerSocket = socket( AF_INET, SOCK_DGRAM, 0 ); +} + +ssize_t send_packet( struct interface_info *ip, + struct dhcp_packet *p, + size_t size, + struct in_addr addr, + struct sockaddr_in *broadcast, + struct hardware *hardware ) { + return 0; +} + +ssize_t receive_packet(struct interface_info *ip, + unsigned char *packet_data, + size_t packet_len, + struct sockaddr_in *dest, + struct hardware *hardware ) { + return 0; +} diff --git a/reactos/subsys/system/dhcp/tables.c b/reactos/subsys/system/dhcp/tables.c new file mode 100644 index 00000000000..7eb9c766b6f --- /dev/null +++ b/reactos/subsys/system/dhcp/tables.c @@ -0,0 +1,692 @@ +/* tables.c + + Tables of information... */ + +/* + * Copyright (c) 1995, 1996 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 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: tables.c,v 1.13.2.4 1999/04/24 16:46:44 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "rosdhcp.h" + +/* DHCP Option names, formats and codes, from RFC1533. + + Format codes: + + e - end of data + I - IP address + l - 32-bit signed integer + L - 32-bit unsigned integer + s - 16-bit signed integer + S - 16-bit unsigned integer + b - 8-bit signed integer + B - 8-bit unsigned integer + t - ASCII text + f - flag (true or false) + A - array of whatever precedes (e.g., IA means array of IP addresses) +*/ + +struct universe dhcp_universe; +struct dhcp_option dhcp_options [256] = { + { "pad", "", &dhcp_universe, 0 }, + { "subnet-mask", "I", &dhcp_universe, 1 }, + { "time-offset", "l", &dhcp_universe, 2 }, + { "routers", "IA", &dhcp_universe, 3 }, + { "time-servers", "IA", &dhcp_universe, 4 }, + { "ien116-name-servers", "IA", &dhcp_universe, 5 }, + { "domain-name-servers", "IA", &dhcp_universe, 6 }, + { "log-servers", "IA", &dhcp_universe, 7 }, + { "cookie-servers", "IA", &dhcp_universe, 8 }, + { "lpr-servers", "IA", &dhcp_universe, 9 }, + { "impress-servers", "IA", &dhcp_universe, 10 }, + { "resource-location-servers", "IA", &dhcp_universe, 11 }, + { "host-name", "X", &dhcp_universe, 12 }, + { "boot-size", "S", &dhcp_universe, 13 }, + { "merit-dump", "t", &dhcp_universe, 14 }, + { "domain-name", "t", &dhcp_universe, 15 }, + { "swap-server", "I", &dhcp_universe, 16 }, + { "root-path", "t", &dhcp_universe, 17 }, + { "extensions-path", "t", &dhcp_universe, 18 }, + { "ip-forwarding", "f", &dhcp_universe, 19 }, + { "non-local-source-routing", "f", &dhcp_universe, 20 }, + { "policy-filter", "IIA", &dhcp_universe, 21 }, + { "max-dgram-reassembly", "S", &dhcp_universe, 22 }, + { "default-ip-ttl", "B", &dhcp_universe, 23 }, + { "path-mtu-aging-timeout", "L", &dhcp_universe, 24 }, + { "path-mtu-plateau-table", "SA", &dhcp_universe, 25 }, + { "interface-mtu", "S", &dhcp_universe, 26 }, + { "all-subnets-local", "f", &dhcp_universe, 27 }, + { "broadcast-address", "I", &dhcp_universe, 28 }, + { "perform-mask-discovery", "f", &dhcp_universe, 29 }, + { "mask-supplier", "f", &dhcp_universe, 30 }, + { "router-discovery", "f", &dhcp_universe, 31 }, + { "router-solicitation-address", "I", &dhcp_universe, 32 }, + { "static-routes", "IIA", &dhcp_universe, 33 }, + { "trailer-encapsulation", "f", &dhcp_universe, 34 }, + { "arp-cache-timeout", "L", &dhcp_universe, 35 }, + { "ieee802-3-encapsulation", "f", &dhcp_universe, 36 }, + { "default-tcp-ttl", "B", &dhcp_universe, 37 }, + { "tcp-keepalive-interval", "L", &dhcp_universe, 38 }, + { "tcp-keepalive-garbage", "f", &dhcp_universe, 39 }, + { "nis-domain", "t", &dhcp_universe, 40 }, + { "nis-servers", "IA", &dhcp_universe, 41 }, + { "ntp-servers", "IA", &dhcp_universe, 42 }, + { "vendor-encapsulated-options", "X", &dhcp_universe, 43 }, + { "netbios-name-servers", "IA", &dhcp_universe, 44 }, + { "netbios-dd-server", "IA", &dhcp_universe, 45 }, + { "netbios-node-type", "B", &dhcp_universe, 46 }, + { "netbios-scope", "t", &dhcp_universe, 47 }, + { "font-servers", "IA", &dhcp_universe, 48 }, + { "x-display-manager", "IA", &dhcp_universe, 49 }, + { "dhcp-requested-address", "I", &dhcp_universe, 50 }, + { "dhcp-lease-time", "L", &dhcp_universe, 51 }, + { "dhcp-option-overload", "B", &dhcp_universe, 52 }, + { "dhcp-message-type", "B", &dhcp_universe, 53 }, + { "dhcp-server-identifier", "I", &dhcp_universe, 54 }, + { "dhcp-parameter-request-list", "BA", &dhcp_universe, 55 }, + { "dhcp-message", "t", &dhcp_universe, 56 }, + { "dhcp-max-message-size", "S", &dhcp_universe, 57 }, + { "dhcp-renewal-time", "L", &dhcp_universe, 58 }, + { "dhcp-rebinding-time", "L", &dhcp_universe, 59 }, + { "dhcp-class-identifier", "t", &dhcp_universe, 60 }, + { "dhcp-client-identifier", "X", &dhcp_universe, 61 }, + { "option-62", "X", &dhcp_universe, 62 }, + { "option-63", "X", &dhcp_universe, 63 }, + { "nisplus-domain", "t", &dhcp_universe, 64 }, + { "nisplus-servers", "IA", &dhcp_universe, 65 }, + { "tftp-server-name", "t", &dhcp_universe, 66 }, + { "bootfile-name", "t", &dhcp_universe, 67 }, + { "mobile-ip-home-agent", "IA", &dhcp_universe, 68 }, + { "smtp-server", "IA", &dhcp_universe, 69 }, + { "pop-server", "IA", &dhcp_universe, 70 }, + { "nntp-server", "IA", &dhcp_universe, 71 }, + { "www-server", "IA", &dhcp_universe, 72 }, + { "finger-server", "IA", &dhcp_universe, 73 }, + { "irc-server", "IA", &dhcp_universe, 74 }, + { "streettalk-server", "IA", &dhcp_universe, 75 }, + { "streettalk-directory-assistance-server", "IA", &dhcp_universe, 76 }, + { "user-class", "t", &dhcp_universe, 77 }, + { "option-78", "X", &dhcp_universe, 78 }, + { "option-79", "X", &dhcp_universe, 79 }, + { "option-80", "X", &dhcp_universe, 80 }, + { "option-81", "X", &dhcp_universe, 81 }, + { "option-82", "X", &dhcp_universe, 82 }, + { "option-83", "X", &dhcp_universe, 83 }, + { "option-84", "X", &dhcp_universe, 84 }, + { "nds-servers", "IA", &dhcp_universe, 85 }, + { "nds-tree-name", "X", &dhcp_universe, 86 }, + { "nds-context", "X", &dhcp_universe, 87 }, + { "option-88", "X", &dhcp_universe, 88 }, + { "option-89", "X", &dhcp_universe, 89 }, + { "option-90", "X", &dhcp_universe, 90 }, + { "option-91", "X", &dhcp_universe, 91 }, + { "option-92", "X", &dhcp_universe, 92 }, + { "option-93", "X", &dhcp_universe, 93 }, + { "option-94", "X", &dhcp_universe, 94 }, + { "option-95", "X", &dhcp_universe, 95 }, + { "option-96", "X", &dhcp_universe, 96 }, + { "option-97", "X", &dhcp_universe, 97 }, + { "option-98", "X", &dhcp_universe, 98 }, + { "option-99", "X", &dhcp_universe, 99 }, + { "option-100", "X", &dhcp_universe, 100 }, + { "option-101", "X", &dhcp_universe, 101 }, + { "option-102", "X", &dhcp_universe, 102 }, + { "option-103", "X", &dhcp_universe, 103 }, + { "option-104", "X", &dhcp_universe, 104 }, + { "option-105", "X", &dhcp_universe, 105 }, + { "option-106", "X", &dhcp_universe, 106 }, + { "option-107", "X", &dhcp_universe, 107 }, + { "option-108", "X", &dhcp_universe, 108 }, + { "option-109", "X", &dhcp_universe, 109 }, + { "option-110", "X", &dhcp_universe, 110 }, + { "option-111", "X", &dhcp_universe, 111 }, + { "option-112", "X", &dhcp_universe, 112 }, + { "option-113", "X", &dhcp_universe, 113 }, + { "option-114", "X", &dhcp_universe, 114 }, + { "option-115", "X", &dhcp_universe, 115 }, + { "option-116", "X", &dhcp_universe, 116 }, + { "option-117", "X", &dhcp_universe, 117 }, + { "option-118", "X", &dhcp_universe, 118 }, + { "option-119", "X", &dhcp_universe, 119 }, + { "option-120", "X", &dhcp_universe, 120 }, + { "option-121", "X", &dhcp_universe, 121 }, + { "option-122", "X", &dhcp_universe, 122 }, + { "option-123", "X", &dhcp_universe, 123 }, + { "option-124", "X", &dhcp_universe, 124 }, + { "option-125", "X", &dhcp_universe, 125 }, + { "option-126", "X", &dhcp_universe, 126 }, + { "option-127", "X", &dhcp_universe, 127 }, + { "option-128", "X", &dhcp_universe, 128 }, + { "option-129", "X", &dhcp_universe, 129 }, + { "option-130", "X", &dhcp_universe, 130 }, + { "option-131", "X", &dhcp_universe, 131 }, + { "option-132", "X", &dhcp_universe, 132 }, + { "option-133", "X", &dhcp_universe, 133 }, + { "option-134", "X", &dhcp_universe, 134 }, + { "option-135", "X", &dhcp_universe, 135 }, + { "option-136", "X", &dhcp_universe, 136 }, + { "option-137", "X", &dhcp_universe, 137 }, + { "option-138", "X", &dhcp_universe, 138 }, + { "option-139", "X", &dhcp_universe, 139 }, + { "option-140", "X", &dhcp_universe, 140 }, + { "option-141", "X", &dhcp_universe, 141 }, + { "option-142", "X", &dhcp_universe, 142 }, + { "option-143", "X", &dhcp_universe, 143 }, + { "option-144", "X", &dhcp_universe, 144 }, + { "option-145", "X", &dhcp_universe, 145 }, + { "option-146", "X", &dhcp_universe, 146 }, + { "option-147", "X", &dhcp_universe, 147 }, + { "option-148", "X", &dhcp_universe, 148 }, + { "option-149", "X", &dhcp_universe, 149 }, + { "option-150", "X", &dhcp_universe, 150 }, + { "option-151", "X", &dhcp_universe, 151 }, + { "option-152", "X", &dhcp_universe, 152 }, + { "option-153", "X", &dhcp_universe, 153 }, + { "option-154", "X", &dhcp_universe, 154 }, + { "option-155", "X", &dhcp_universe, 155 }, + { "option-156", "X", &dhcp_universe, 156 }, + { "option-157", "X", &dhcp_universe, 157 }, + { "option-158", "X", &dhcp_universe, 158 }, + { "option-159", "X", &dhcp_universe, 159 }, + { "option-160", "X", &dhcp_universe, 160 }, + { "option-161", "X", &dhcp_universe, 161 }, + { "option-162", "X", &dhcp_universe, 162 }, + { "option-163", "X", &dhcp_universe, 163 }, + { "option-164", "X", &dhcp_universe, 164 }, + { "option-165", "X", &dhcp_universe, 165 }, + { "option-166", "X", &dhcp_universe, 166 }, + { "option-167", "X", &dhcp_universe, 167 }, + { "option-168", "X", &dhcp_universe, 168 }, + { "option-169", "X", &dhcp_universe, 169 }, + { "option-170", "X", &dhcp_universe, 170 }, + { "option-171", "X", &dhcp_universe, 171 }, + { "option-172", "X", &dhcp_universe, 172 }, + { "option-173", "X", &dhcp_universe, 173 }, + { "option-174", "X", &dhcp_universe, 174 }, + { "option-175", "X", &dhcp_universe, 175 }, + { "option-176", "X", &dhcp_universe, 176 }, + { "option-177", "X", &dhcp_universe, 177 }, + { "option-178", "X", &dhcp_universe, 178 }, + { "option-179", "X", &dhcp_universe, 179 }, + { "option-180", "X", &dhcp_universe, 180 }, + { "option-181", "X", &dhcp_universe, 181 }, + { "option-182", "X", &dhcp_universe, 182 }, + { "option-183", "X", &dhcp_universe, 183 }, + { "option-184", "X", &dhcp_universe, 184 }, + { "option-185", "X", &dhcp_universe, 185 }, + { "option-186", "X", &dhcp_universe, 186 }, + { "option-187", "X", &dhcp_universe, 187 }, + { "option-188", "X", &dhcp_universe, 188 }, + { "option-189", "X", &dhcp_universe, 189 }, + { "option-190", "X", &dhcp_universe, 190 }, + { "option-191", "X", &dhcp_universe, 191 }, + { "option-192", "X", &dhcp_universe, 192 }, + { "option-193", "X", &dhcp_universe, 193 }, + { "option-194", "X", &dhcp_universe, 194 }, + { "option-195", "X", &dhcp_universe, 195 }, + { "option-196", "X", &dhcp_universe, 196 }, + { "option-197", "X", &dhcp_universe, 197 }, + { "option-198", "X", &dhcp_universe, 198 }, + { "option-199", "X", &dhcp_universe, 199 }, + { "option-200", "X", &dhcp_universe, 200 }, + { "option-201", "X", &dhcp_universe, 201 }, + { "option-202", "X", &dhcp_universe, 202 }, + { "option-203", "X", &dhcp_universe, 203 }, + { "option-204", "X", &dhcp_universe, 204 }, + { "option-205", "X", &dhcp_universe, 205 }, + { "option-206", "X", &dhcp_universe, 206 }, + { "option-207", "X", &dhcp_universe, 207 }, + { "option-208", "X", &dhcp_universe, 208 }, + { "option-209", "X", &dhcp_universe, 209 }, + { "option-210", "X", &dhcp_universe, 210 }, + { "option-211", "X", &dhcp_universe, 211 }, + { "option-212", "X", &dhcp_universe, 212 }, + { "option-213", "X", &dhcp_universe, 213 }, + { "option-214", "X", &dhcp_universe, 214 }, + { "option-215", "X", &dhcp_universe, 215 }, + { "option-216", "X", &dhcp_universe, 216 }, + { "option-217", "X", &dhcp_universe, 217 }, + { "option-218", "X", &dhcp_universe, 218 }, + { "option-219", "X", &dhcp_universe, 219 }, + { "option-220", "X", &dhcp_universe, 220 }, + { "option-221", "X", &dhcp_universe, 221 }, + { "option-222", "X", &dhcp_universe, 222 }, + { "option-223", "X", &dhcp_universe, 223 }, + { "option-224", "X", &dhcp_universe, 224 }, + { "option-225", "X", &dhcp_universe, 225 }, + { "option-226", "X", &dhcp_universe, 226 }, + { "option-227", "X", &dhcp_universe, 227 }, + { "option-228", "X", &dhcp_universe, 228 }, + { "option-229", "X", &dhcp_universe, 229 }, + { "option-230", "X", &dhcp_universe, 230 }, + { "option-231", "X", &dhcp_universe, 231 }, + { "option-232", "X", &dhcp_universe, 232 }, + { "option-233", "X", &dhcp_universe, 233 }, + { "option-234", "X", &dhcp_universe, 234 }, + { "option-235", "X", &dhcp_universe, 235 }, + { "option-236", "X", &dhcp_universe, 236 }, + { "option-237", "X", &dhcp_universe, 237 }, + { "option-238", "X", &dhcp_universe, 238 }, + { "option-239", "X", &dhcp_universe, 239 }, + { "option-240", "X", &dhcp_universe, 240 }, + { "option-241", "X", &dhcp_universe, 241 }, + { "option-242", "X", &dhcp_universe, 242 }, + { "option-243", "X", &dhcp_universe, 243 }, + { "option-244", "X", &dhcp_universe, 244 }, + { "option-245", "X", &dhcp_universe, 245 }, + { "option-246", "X", &dhcp_universe, 246 }, + { "option-247", "X", &dhcp_universe, 247 }, + { "option-248", "X", &dhcp_universe, 248 }, + { "option-249", "X", &dhcp_universe, 249 }, + { "option-250", "X", &dhcp_universe, 250 }, + { "option-251", "X", &dhcp_universe, 251 }, + { "option-252", "X", &dhcp_universe, 252 }, + { "option-253", "X", &dhcp_universe, 253 }, + { "option-254", "X", &dhcp_universe, 254 }, + { "option-end", "e", &dhcp_universe, 255 }, +}; + +/* Default dhcp option priority list (this is ad hoc and should not be + mistaken for a carefully crafted and optimized list). */ +unsigned char dhcp_option_default_priority_list [] = { + DHO_DHCP_REQUESTED_ADDRESS, + DHO_DHCP_OPTION_OVERLOAD, + DHO_DHCP_MAX_MESSAGE_SIZE, + DHO_DHCP_RENEWAL_TIME, + DHO_DHCP_REBINDING_TIME, + DHO_DHCP_CLASS_IDENTIFIER, + DHO_DHCP_CLIENT_IDENTIFIER, + DHO_SUBNET_MASK, + DHO_TIME_OFFSET, + DHO_ROUTERS, + DHO_TIME_SERVERS, + DHO_NAME_SERVERS, + DHO_DOMAIN_NAME_SERVERS, + DHO_HOST_NAME, + DHO_LOG_SERVERS, + DHO_COOKIE_SERVERS, + DHO_LPR_SERVERS, + DHO_IMPRESS_SERVERS, + DHO_RESOURCE_LOCATION_SERVERS, + DHO_HOST_NAME, + DHO_BOOT_SIZE, + DHO_MERIT_DUMP, + DHO_DOMAIN_NAME, + DHO_SWAP_SERVER, + DHO_ROOT_PATH, + DHO_EXTENSIONS_PATH, + DHO_IP_FORWARDING, + DHO_NON_LOCAL_SOURCE_ROUTING, + DHO_POLICY_FILTER, + DHO_MAX_DGRAM_REASSEMBLY, + DHO_DEFAULT_IP_TTL, + DHO_PATH_MTU_AGING_TIMEOUT, + DHO_PATH_MTU_PLATEAU_TABLE, + DHO_INTERFACE_MTU, + DHO_ALL_SUBNETS_LOCAL, + DHO_BROADCAST_ADDRESS, + DHO_PERFORM_MASK_DISCOVERY, + DHO_MASK_SUPPLIER, + DHO_ROUTER_DISCOVERY, + DHO_ROUTER_SOLICITATION_ADDRESS, + DHO_STATIC_ROUTES, + DHO_TRAILER_ENCAPSULATION, + DHO_ARP_CACHE_TIMEOUT, + DHO_IEEE802_3_ENCAPSULATION, + DHO_DEFAULT_TCP_TTL, + DHO_TCP_KEEPALIVE_INTERVAL, + DHO_TCP_KEEPALIVE_GARBAGE, + DHO_NIS_DOMAIN, + DHO_NIS_SERVERS, + DHO_NTP_SERVERS, + DHO_VENDOR_ENCAPSULATED_OPTIONS, + DHO_NETBIOS_NAME_SERVERS, + DHO_NETBIOS_DD_SERVER, + DHO_NETBIOS_NODE_TYPE, + DHO_NETBIOS_SCOPE, + DHO_FONT_SERVERS, + DHO_X_DISPLAY_MANAGER, + DHO_DHCP_PARAMETER_REQUEST_LIST, + + /* Presently-undefined options... */ + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, + 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, +}; + +int sizeof_dhcp_option_default_priority_list = + sizeof dhcp_option_default_priority_list; + + +char *hardware_types [] = { + "unknown-0", + "ethernet", + "unknown-2", + "unknown-3", + "unknown-4", + "unknown-5", + "token-ring", + "unknown-7", + "fddi", + "unknown-9", + "unknown-10", + "unknown-11", + "unknown-12", + "unknown-13", + "unknown-14", + "unknown-15", + "unknown-16", + "unknown-17", + "unknown-18", + "unknown-19", + "unknown-20", + "unknown-21", + "unknown-22", + "unknown-23", + "unknown-24", + "unknown-25", + "unknown-26", + "unknown-27", + "unknown-28", + "unknown-29", + "unknown-30", + "unknown-31", + "unknown-32", + "unknown-33", + "unknown-34", + "unknown-35", + "unknown-36", + "unknown-37", + "unknown-38", + "unknown-39", + "unknown-40", + "unknown-41", + "unknown-42", + "unknown-43", + "unknown-44", + "unknown-45", + "unknown-46", + "unknown-47", + "unknown-48", + "unknown-49", + "unknown-50", + "unknown-51", + "unknown-52", + "unknown-53", + "unknown-54", + "unknown-55", + "unknown-56", + "unknown-57", + "unknown-58", + "unknown-59", + "unknown-60", + "unknown-61", + "unknown-62", + "unknown-63", + "unknown-64", + "unknown-65", + "unknown-66", + "unknown-67", + "unknown-68", + "unknown-69", + "unknown-70", + "unknown-71", + "unknown-72", + "unknown-73", + "unknown-74", + "unknown-75", + "unknown-76", + "unknown-77", + "unknown-78", + "unknown-79", + "unknown-80", + "unknown-81", + "unknown-82", + "unknown-83", + "unknown-84", + "unknown-85", + "unknown-86", + "unknown-87", + "unknown-88", + "unknown-89", + "unknown-90", + "unknown-91", + "unknown-92", + "unknown-93", + "unknown-94", + "unknown-95", + "unknown-96", + "unknown-97", + "unknown-98", + "unknown-99", + "unknown-100", + "unknown-101", + "unknown-102", + "unknown-103", + "unknown-104", + "unknown-105", + "unknown-106", + "unknown-107", + "unknown-108", + "unknown-109", + "unknown-110", + "unknown-111", + "unknown-112", + "unknown-113", + "unknown-114", + "unknown-115", + "unknown-116", + "unknown-117", + "unknown-118", + "unknown-119", + "unknown-120", + "unknown-121", + "unknown-122", + "unknown-123", + "unknown-124", + "unknown-125", + "unknown-126", + "unknown-127", + "unknown-128", + "unknown-129", + "unknown-130", + "unknown-131", + "unknown-132", + "unknown-133", + "unknown-134", + "unknown-135", + "unknown-136", + "unknown-137", + "unknown-138", + "unknown-139", + "unknown-140", + "unknown-141", + "unknown-142", + "unknown-143", + "unknown-144", + "unknown-145", + "unknown-146", + "unknown-147", + "unknown-148", + "unknown-149", + "unknown-150", + "unknown-151", + "unknown-152", + "unknown-153", + "unknown-154", + "unknown-155", + "unknown-156", + "unknown-157", + "unknown-158", + "unknown-159", + "unknown-160", + "unknown-161", + "unknown-162", + "unknown-163", + "unknown-164", + "unknown-165", + "unknown-166", + "unknown-167", + "unknown-168", + "unknown-169", + "unknown-170", + "unknown-171", + "unknown-172", + "unknown-173", + "unknown-174", + "unknown-175", + "unknown-176", + "unknown-177", + "unknown-178", + "unknown-179", + "unknown-180", + "unknown-181", + "unknown-182", + "unknown-183", + "unknown-184", + "unknown-185", + "unknown-186", + "unknown-187", + "unknown-188", + "unknown-189", + "unknown-190", + "unknown-191", + "unknown-192", + "unknown-193", + "unknown-194", + "unknown-195", + "unknown-196", + "unknown-197", + "unknown-198", + "unknown-199", + "unknown-200", + "unknown-201", + "unknown-202", + "unknown-203", + "unknown-204", + "unknown-205", + "unknown-206", + "unknown-207", + "unknown-208", + "unknown-209", + "unknown-210", + "unknown-211", + "unknown-212", + "unknown-213", + "unknown-214", + "unknown-215", + "unknown-216", + "unknown-217", + "unknown-218", + "unknown-219", + "unknown-220", + "unknown-221", + "unknown-222", + "unknown-223", + "unknown-224", + "unknown-225", + "unknown-226", + "unknown-227", + "unknown-228", + "unknown-229", + "unknown-230", + "unknown-231", + "unknown-232", + "unknown-233", + "unknown-234", + "unknown-235", + "unknown-236", + "unknown-237", + "unknown-238", + "unknown-239", + "unknown-240", + "unknown-241", + "unknown-242", + "unknown-243", + "unknown-244", + "unknown-245", + "unknown-246", + "unknown-247", + "unknown-248", + "unknown-249", + "unknown-250", + "unknown-251", + "unknown-252", + "unknown-253", + "unknown-254", + "unknown-255" }; + + + +struct hash_table universe_hash; + +void initialize_universes() +{ + int i; + + dhcp_universe.name = "dhcp"; + dhcp_universe.hash = new_hash (); + if (!dhcp_universe.hash) + error ("Can't allocate dhcp option hash table."); + for (i = 0; i < 256; i++) { + dhcp_universe.options [i] = &dhcp_options [i]; + add_hash (dhcp_universe.hash, + (unsigned char *)dhcp_options [i].name, 0, + (unsigned char *)&dhcp_options [i]); + } + universe_hash.hash_count = DEFAULT_HASH_SIZE; + add_hash (&universe_hash, + (unsigned char *)dhcp_universe.name, 0, + (unsigned char *)&dhcp_universe); +} diff --git a/reactos/subsys/system/dhcp/timer.c b/reactos/subsys/system/dhcp/timer.c new file mode 100644 index 00000000000..ccd817188ec --- /dev/null +++ b/reactos/subsys/system/dhcp/timer.c @@ -0,0 +1,2 @@ +#include "rosdhcp.h" + diff --git a/reactos/subsys/system/dhcp/tree.c b/reactos/subsys/system/dhcp/tree.c new file mode 100644 index 00000000000..9a49e5e3577 --- /dev/null +++ b/reactos/subsys/system/dhcp/tree.c @@ -0,0 +1,412 @@ +/* tree.c + + Routines for manipulating parse trees... */ + +/* + * Copyright (c) 1995, 1996, 1997 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 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: tree.c,v 1.10 1997/05/09 08:14:57 mellon Exp $ Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "rosdhcp.h" + +static TIME tree_evaluate_recurse PROTO ((int *, unsigned char **, int *, + struct tree *)); +static TIME do_host_lookup PROTO ((int *, unsigned char **, int *, + struct dns_host_entry *)); +static void do_data_copy PROTO ((int *, unsigned char **, int *, + unsigned char *, int)); + +pair cons (car, cdr) + caddr_t car; + pair cdr; +{ + pair foo = (pair)dmalloc (sizeof *foo, "cons"); + if (!foo) + error ("no memory for cons."); + foo -> car = car; + foo -> cdr = cdr; + return foo; +} + +struct tree_cache *tree_cache (tree) + struct tree *tree; +{ + struct tree_cache *tc; + + tc = new_tree_cache ("tree_cache"); + if (!tc) + return 0; + tc -> value = (unsigned char *)0; + tc -> len = tc -> buf_size = 0; + tc -> timeout = 0; + tc -> tree = tree; + return tc; +} + +struct tree *tree_host_lookup (name) + char *name; +{ + struct tree *nt; + nt = new_tree ("tree_host_lookup"); + if (!nt) + error ("No memory for host lookup tree node."); + nt -> op = TREE_HOST_LOOKUP; + nt -> data.host_lookup.host = enter_dns_host (name); + return nt; +} + +struct dns_host_entry *enter_dns_host (name) + char *name; +{ + struct dns_host_entry *dh; + + if (!(dh = (struct dns_host_entry *)dmalloc + (sizeof (struct dns_host_entry), "enter_dns_host")) + || !(dh -> hostname = dmalloc (strlen (name) + 1, + "enter_dns_host"))) + error ("Can't allocate space for new host."); + strcpy (dh -> hostname, name); + dh -> data = (unsigned char *)0; + dh -> data_len = 0; + dh -> buf_len = 0; + dh -> timeout = 0; + return dh; +} + +struct tree *tree_const (data, len) + unsigned char *data; + int len; +{ + struct tree *nt; + if (!(nt = new_tree ("tree_const")) + || !(nt -> data.const_val.data = + (unsigned char *)dmalloc (len, "tree_const"))) + error ("No memory for constant data tree node."); + nt -> op = TREE_CONST; + memcpy (nt -> data.const_val.data, data, len); + nt -> data.const_val.len = len; + return nt; +} + +struct tree *tree_concat (left, right) + struct tree *left, *right; +{ + struct tree *nt; + + /* If we're concatenating a null tree to a non-null tree, just + return the non-null tree; if both trees are null, return + a null tree. */ + if (!left) + return right; + if (!right) + return left; + + /* If both trees are constant, combine them. */ + if (left -> op == TREE_CONST && right -> op == TREE_CONST) { + unsigned char *buf = dmalloc (left -> data.const_val.len + + right -> data.const_val.len, + "tree_concat"); + if (!buf) + error ("No memory to concatenate constants."); + memcpy (buf, left -> data.const_val.data, + left -> data.const_val.len); + memcpy (buf + left -> data.const_val.len, + right -> data.const_val.data, + right -> data.const_val.len); + dfree (left -> data.const_val.data, "tree_concat"); + dfree (right -> data.const_val.data, "tree_concat"); + left -> data.const_val.data = buf; + left -> data.const_val.len += right -> data.const_val.len; + free_tree (right, "tree_concat"); + return left; + } + + /* Otherwise, allocate a new node to concatenate the two. */ + if (!(nt = new_tree ("tree_concat"))) + error ("No memory for data tree concatenation node."); + nt -> op = TREE_CONCAT; + nt -> data.concat.left = left; + nt -> data.concat.right = right; + return nt; +} + +struct tree *tree_limit (tree, limit) + struct tree *tree; + int limit; +{ + struct tree *rv; + + /* If the tree we're limiting is constant, limit it now. */ + if (tree -> op == TREE_CONST) { + if (tree -> data.const_val.len > limit) + tree -> data.const_val.len = limit; + return tree; + } + + /* Otherwise, put in a node which enforces the limit on evaluation. */ + rv = new_tree ("tree_limit"); + if (!rv) + return (struct tree *)0; + rv -> op = TREE_LIMIT; + rv -> data.limit.tree = tree; + rv -> data.limit.limit = limit; + return rv; +} + +int tree_evaluate (tree_cache) + struct tree_cache *tree_cache; +{ + unsigned char *bp = tree_cache -> value; + int bc = tree_cache -> buf_size; + int bufix = 0; + + /* If there's no tree associated with this cache, it evaluates + to a constant and that was detected at startup. */ + if (!tree_cache -> tree) + return 1; + + /* Try to evaluate the tree without allocating more memory... */ + tree_cache -> timeout = tree_evaluate_recurse (&bufix, &bp, &bc, + tree_cache -> tree); + + /* No additional allocation needed? */ + if (bufix <= bc) { + tree_cache -> len = bufix; + return 1; + } + + /* If we can't allocate more memory, return with what we + have (maybe nothing). */ + if (!(bp = (unsigned char *)dmalloc (bufix, "tree_evaluate"))) + return 0; + + /* Record the change in conditions... */ + bc = bufix; + bufix = 0; + + /* Note that the size of the result shouldn't change on the + second call to tree_evaluate_recurse, since we haven't + changed the ``current'' time. */ + tree_evaluate_recurse (&bufix, &bp, &bc, tree_cache -> tree); + + /* Free the old buffer if needed, then store the new buffer + location and size and return. */ + if (tree_cache -> value) + dfree (tree_cache -> value, "tree_evaluate"); + tree_cache -> value = bp; + tree_cache -> len = bufix; + tree_cache -> buf_size = bc; + return 1; +} + +static TIME tree_evaluate_recurse (bufix, bufp, bufcount, tree) + int *bufix; + unsigned char **bufp; + int *bufcount; + struct tree *tree; +{ + int limit; + TIME t1, t2; + + switch (tree -> op) { + case TREE_CONCAT: + t1 = tree_evaluate_recurse (bufix, bufp, bufcount, + tree -> data.concat.left); + t2 = tree_evaluate_recurse (bufix, bufp, bufcount, + tree -> data.concat.right); + if (t1 > t2) + return t2; + return t1; + + case TREE_HOST_LOOKUP: + return do_host_lookup (bufix, bufp, bufcount, + tree -> data.host_lookup.host); + + case TREE_CONST: + do_data_copy (bufix, bufp, bufcount, + tree -> data.const_val.data, + tree -> data.const_val.len); + t1 = MAX_TIME; + return t1; + + case TREE_LIMIT: + limit = *bufix + tree -> data.limit.limit; + t1 = tree_evaluate_recurse (bufix, bufp, bufcount, + tree -> data.limit.tree); + *bufix = limit; + return t1; + + default: + warn ("Bad node id in tree: %d."); + t1 = MAX_TIME; + return t1; + } +} + +static TIME do_host_lookup (bufix, bufp, bufcount, dns) + int *bufix; + unsigned char **bufp; + int *bufcount; + struct dns_host_entry *dns; +{ + struct hostent *h; + int i; + int new_len; + +#ifdef DEBUG_EVAL + debug ("time: now = %d dns = %d %d diff = %d", + cur_time, dns -> timeout, cur_time - dns -> timeout); +#endif + + /* If the record hasn't timed out, just copy the data and return. */ + if (cur_time <= dns -> timeout) { +#ifdef DEBUG_EVAL + debug ("easy copy: %x %d %x", + dns -> data, dns -> data_len, + dns -> data ? *(int *)(dns -> data) : 0); +#endif + do_data_copy (bufix, bufp, bufcount, + dns -> data, dns -> data_len); + return dns -> timeout; + } +#ifdef DEBUG_EVAL + debug ("Looking up %s", dns -> hostname); +#endif + + /* Otherwise, look it up... */ + h = gethostbyname (dns -> hostname); + if (!h) { +#ifndef NO_H_ERRNO + switch (h_errno) { + case HOST_NOT_FOUND: +#endif + warn ("%s: host unknown.", dns -> hostname); +#ifndef NO_H_ERRNO + break; + case TRY_AGAIN: + warn ("%s: temporary name server failure", + dns -> hostname); + break; + case NO_RECOVERY: + warn ("%s: name server failed", dns -> hostname); + break; + case NO_DATA: + warn ("%s: no A record associated with address", + dns -> hostname); + } +#endif /* !NO_H_ERRNO */ + + /* Okay to try again after a minute. */ + return cur_time + 60; + } + +#ifdef DEBUG_EVAL + debug ("Lookup succeeded; first address is %x", + h -> h_addr_list [0]); +#endif + + /* Count the number of addresses we got... */ + for (i = 0; h -> h_addr_list [i]; i++) + ; + + /* Do we need to allocate more memory? */ + new_len = i * h -> h_length; + if (dns -> buf_len < i) { + unsigned char *buf = + (unsigned char *)dmalloc (new_len, "do_host_lookup"); + /* If we didn't get more memory, use what we have. */ + if (!buf) { + new_len = dns -> buf_len; + if (!dns -> buf_len) { + dns -> timeout = cur_time + 60; + return dns -> timeout; + } + } else { + if (dns -> data) + dfree (dns -> data, "do_host_lookup"); + dns -> data = buf; + dns -> buf_len = new_len; + } + } + + /* Addresses are conveniently stored one to the buffer, so we + have to copy them out one at a time... :'( */ + for (i = 0; i < new_len / h -> h_length; i++) { + memcpy (dns -> data + h -> h_length * i, + h -> h_addr_list [i], h -> h_length); + } +#ifdef DEBUG_EVAL + debug ("dns -> data: %x h -> h_addr_list [0]: %x", + *(int *)(dns -> data), h -> h_addr_list [0]); +#endif + dns -> data_len = new_len; + + /* Set the timeout for an hour from now. + XXX This should really use the time on the DNS reply. */ + dns -> timeout = cur_time + 3600; + +#ifdef DEBUG_EVAL + debug ("hard copy: %x %d %x", + dns -> data, dns -> data_len, *(int *)(dns -> data)); +#endif + do_data_copy (bufix, bufp, bufcount, dns -> data, dns -> data_len); + return dns -> timeout; +} + +static void do_data_copy (bufix, bufp, bufcount, data, len) + int *bufix; + unsigned char **bufp; + int *bufcount; + unsigned char *data; + int len; +{ + int space = *bufcount - *bufix; + + /* If there's more space than we need, use only what we need. */ + if (space > len) + space = len; + + /* Copy as much data as will fit, then increment the buffer index + by the amount we actually had to copy, which could be more. */ + if (space > 0) + memcpy (*bufp + *bufix, data, space); + *bufix += len; +} diff --git a/reactos/subsys/system/dhcp/util.c b/reactos/subsys/system/dhcp/util.c new file mode 100644 index 00000000000..22d3948f920 --- /dev/null +++ b/reactos/subsys/system/dhcp/util.c @@ -0,0 +1,106 @@ +#include +#include "rosdhcp.h" + +char *piaddr( struct iaddr addr ) { + struct sockaddr_in *sa = (struct sockaddr_in *)addr.iabuf; + return inet_ntoa( sa->sin_addr ); +} + +int note( char *format, ... ) { + va_list arg_begin; + va_start( arg_begin, format ); + char buf[0x100]; + int ret; + + ret = vsnprintf( buf, sizeof(buf), format, arg_begin ); + + DbgPrint("NOTE: %s\n", buf); + + return ret; +} + +int debug( char *format, ... ) { + va_list arg_begin; + va_start( arg_begin, format ); + char buf[0x100]; + int ret; + + ret = vsnprintf( buf, sizeof(buf), format, arg_begin ); + + DbgPrint("DEBUG: %s\n", buf); + + return ret; +} + +int warn( char *format, ... ) { + va_list arg_begin; + va_start( arg_begin, format ); + char buf[0x100]; + int ret; + + ret = vsnprintf( buf, sizeof(buf), format, arg_begin ); + + DbgPrint("WARN: %s\n", buf); + + return ret; +} + +int warning( char *format, ... ) { + va_list arg_begin; + va_start( arg_begin, format ); + char buf[0x100]; + int ret; + + ret = vsnprintf( buf, sizeof(buf), format, arg_begin ); + + DbgPrint("WARNING: %s\n", buf); + + return ret; +} + +void error( char *format, ... ) { + va_list arg_begin; + va_start( arg_begin, format ); + char buf[0x100]; + + vsnprintf( buf, sizeof(buf), format, arg_begin ); + + DbgPrint("ERROR: %s\n", buf); +} + +int16_t getShort( unsigned char *data ) { + return 0; +} + +u_int16_t getUShort( unsigned char *data ) { + return 0; +} + +int32_t getLong( unsigned char *data ) { + return 0; +} + +u_int32_t getULong( unsigned char *data ) { + return 0; +} + +int addr_eq( struct iaddr a, struct iaddr b ) { + return a.len == b.len && !memcmp( a.iabuf, b.iabuf, a.len ); +} + +void *dmalloc( int size, char *name ) { return malloc( size ); } +void dfree( void *v, char *name ) { free( v ); } + +int read_client_conf(void) { + return 0; +} + +struct iaddr broadcast_addr( struct iaddr addr, struct iaddr mask ) { + struct iaddr bcast = { 0 }; + return bcast; +} + +struct iaddr subnet_number( struct iaddr addr, struct iaddr mask ) { + struct iaddr bcast = { 0 }; + return bcast; +}