move dhcp client from /subsys/system to /services
authorGed Murphy <gedmurphy@reactos.org>
Wed, 19 Oct 2005 21:22:28 +0000 (21:22 +0000)
committerGed Murphy <gedmurphy@reactos.org>
Wed, 19 Oct 2005 21:22:28 +0000 (21:22 +0000)
svn path=/trunk/; revision=18607

37 files changed:
reactos/services/dhcp/adapter.c [new file with mode: 0644]
reactos/services/dhcp/alloc.c [new file with mode: 0644]
reactos/services/dhcp/api.c [new file with mode: 0644]
reactos/services/dhcp/compat.c [new file with mode: 0644]
reactos/services/dhcp/design.txt [new file with mode: 0644]
reactos/services/dhcp/dhclient.c [new file with mode: 0644]
reactos/services/dhcp/dhcp.rc [new file with mode: 0644]
reactos/services/dhcp/dhcp.xml [new file with mode: 0644]
reactos/services/dhcp/dhcpmain.c [new file with mode: 0644]
reactos/services/dhcp/dispatch.c [new file with mode: 0644]
reactos/services/dhcp/hash.c [new file with mode: 0644]
reactos/services/dhcp/include/cdefs.h [new file with mode: 0644]
reactos/services/dhcp/include/debug.h [new file with mode: 0644]
reactos/services/dhcp/include/dhcp.h [new file with mode: 0644]
reactos/services/dhcp/include/dhcpd.h [new file with mode: 0644]
reactos/services/dhcp/include/dhctoken.h [new file with mode: 0644]
reactos/services/dhcp/include/hash.h [new file with mode: 0644]
reactos/services/dhcp/include/inet.h [new file with mode: 0644]
reactos/services/dhcp/include/osdep.h [new file with mode: 0644]
reactos/services/dhcp/include/predec.h [new file with mode: 0644]
reactos/services/dhcp/include/privsep.h [new file with mode: 0644]
reactos/services/dhcp/include/rosdhcp.h [new file with mode: 0644]
reactos/services/dhcp/include/site.h [new file with mode: 0644]
reactos/services/dhcp/include/stdint.h [new file with mode: 0644]
reactos/services/dhcp/include/sysconf.h [new file with mode: 0644]
reactos/services/dhcp/include/tree.h [new file with mode: 0644]
reactos/services/dhcp/include/version.h [new file with mode: 0644]
reactos/services/dhcp/memory.c [new file with mode: 0644]
reactos/services/dhcp/options.c [new file with mode: 0644]
reactos/services/dhcp/pipe.c [new file with mode: 0644]
reactos/services/dhcp/privsep.c [new file with mode: 0644]
reactos/services/dhcp/socket.c [new file with mode: 0644]
reactos/services/dhcp/tables.c [new file with mode: 0644]
reactos/services/dhcp/timer.c [new file with mode: 0644]
reactos/services/dhcp/tree.c [new file with mode: 0644]
reactos/services/dhcp/util.c [new file with mode: 0644]
reactos/services/directory.xml

diff --git a/reactos/services/dhcp/adapter.c b/reactos/services/dhcp/adapter.c
new file mode 100644 (file)
index 0000000..58c5da3
--- /dev/null
@@ -0,0 +1,377 @@
+#include "rosdhcp.h"
+
+static SOCKET DhcpSocket = INVALID_SOCKET;
+static LIST_ENTRY AdapterList;
+static WSADATA wsd;
+extern struct interface_info *ifi;
+
+PCHAR *GetSubkeyNames( PCHAR MainKeyName, PCHAR Append ) {
+    int i = 0;
+    DWORD Error;
+    HKEY MainKey;
+    PCHAR *Out, OutKeyName;
+    DWORD CharTotal = 0, AppendLen = 1 + strlen(Append);
+    DWORD MaxSubKeyLen = 0, MaxSubKeys = 0;
+
+    Error = RegOpenKey( HKEY_LOCAL_MACHINE, MainKeyName, &MainKey );
+
+    if( Error ) return NULL;
+
+    Error = RegQueryInfoKey
+        ( MainKey,
+          NULL, NULL, NULL,
+          &MaxSubKeys, &MaxSubKeyLen,
+          NULL, NULL, NULL, NULL, NULL, NULL );
+
+    DH_DbgPrint(MID_TRACE,("MaxSubKeys: %d, MaxSubKeyLen %d\n",
+                           MaxSubKeys, MaxSubKeyLen));
+
+    CharTotal = (sizeof(PCHAR) + MaxSubKeyLen + AppendLen) * (MaxSubKeys + 1);
+
+    DH_DbgPrint(MID_TRACE,("AppendLen: %d, CharTotal: %d\n",
+                           AppendLen, CharTotal));
+
+    Out = malloc( CharTotal );
+    OutKeyName = ((PCHAR)&Out[MaxSubKeys+1]);
+
+    if( !Out ) { RegCloseKey( MainKey ); return NULL; }
+
+    i = 0;
+    do {
+        Out[i] = OutKeyName;
+        Error = RegEnumKey( MainKey, i, OutKeyName, MaxSubKeyLen );
+        if( !Error ) {
+            strcat( OutKeyName, Append );
+            DH_DbgPrint(MID_TRACE,("[%d]: %s\n", i, OutKeyName));
+            OutKeyName += strlen(OutKeyName) + 1;
+            i++;
+        } else Out[i] = 0;
+    } while( Error == ERROR_SUCCESS );
+
+    RegCloseKey( MainKey );
+
+    return Out;
+}
+
+PCHAR RegReadString( HKEY Root, PCHAR Subkey, PCHAR Value ) {
+    PCHAR SubOut = NULL;
+    DWORD SubOutLen = 0, Error = 0;
+    HKEY  ValueKey = NULL;
+
+    DH_DbgPrint(MID_TRACE,("Looking in %x:%s:%s\n", Root, Subkey, Value ));
+
+    if( Subkey && strlen(Subkey) ) {
+        if( RegOpenKey( Root, Subkey, &ValueKey ) != ERROR_SUCCESS )
+            goto regerror;
+    } else ValueKey = Root;
+
+    DH_DbgPrint(MID_TRACE,("Got Key %x\n", ValueKey));
+
+    if( (Error = RegQueryValueEx( ValueKey, Value, NULL, NULL,
+                                  (LPBYTE)SubOut, &SubOutLen )) != ERROR_SUCCESS )
+        goto regerror;
+
+    DH_DbgPrint(MID_TRACE,("Value %s has size %d\n", Value, SubOutLen));
+
+    if( !(SubOut = malloc(SubOutLen)) )
+        goto regerror;
+
+    if( (Error = RegQueryValueEx( ValueKey, Value, NULL, NULL,
+                                  (LPBYTE)SubOut, &SubOutLen )) != ERROR_SUCCESS )
+        goto regerror;
+
+    DH_DbgPrint(MID_TRACE,("Value %s is %s\n", Value, SubOut));
+
+    goto cleanup;
+
+regerror:
+    if( SubOut ) free( SubOut );
+cleanup:
+    if( ValueKey && ValueKey != Root ) {
+        DH_DbgPrint(MID_TRACE,("Closing key %x\n", ValueKey));
+        RegCloseKey( ValueKey );
+    }
+
+    DH_DbgPrint(MID_TRACE,("Returning %x with error %d\n", SubOut, Error));
+
+    return SubOut;
+}
+
+HKEY FindAdapterKey( PDHCP_ADAPTER Adapter ) {
+    int i = 0;
+    PCHAR EnumKeyName =
+        "SYSTEM\\CurrentControlSet\\Control\\Class\\"
+        "{4D36E972-E325-11CE-BFC1-08002BE10318}";
+    PCHAR TargetKeyNameStart =
+        "SYSTEM\\CurrentControlSet\\Services\\";
+    PCHAR TargetKeyNameEnd = "\\Parameters\\Tcpip";
+    PCHAR TargetKeyName = NULL;
+    PCHAR *EnumKeysLinkage = GetSubkeyNames( EnumKeyName, "\\Linkage" );
+    PCHAR *EnumKeysTop     = GetSubkeyNames( EnumKeyName, "" );
+    PCHAR RootDevice = NULL, DriverDesc = NULL;
+    HKEY EnumKey, OutKey = NULL;
+    DWORD Error = ERROR_SUCCESS;
+
+    if( !EnumKeysLinkage || !EnumKeysTop ) goto cleanup;
+
+    Error = RegOpenKey( HKEY_LOCAL_MACHINE, EnumKeyName, &EnumKey );
+
+    if( Error ) goto cleanup;
+
+    for( i = 0; EnumKeysLinkage[i]; i++ ) {
+        RootDevice = RegReadString
+            ( EnumKey, EnumKeysLinkage[i], "RootDevice" );
+        DriverDesc = RegReadString
+            ( EnumKey, EnumKeysTop[i], "DriverDesc" );
+
+        if( DriverDesc &&
+            !strcmp( DriverDesc, Adapter->DhclientInfo.name ) ) {
+            TargetKeyName =
+                malloc( strlen( TargetKeyNameStart ) +
+                        strlen( RootDevice ) +
+                        strlen( TargetKeyNameEnd ) + 1 );
+            if( !TargetKeyName ) goto cleanup;
+            sprintf( TargetKeyName, "%s%s%s",
+                     TargetKeyNameStart, RootDevice, TargetKeyNameEnd );
+            Error = RegOpenKey( HKEY_LOCAL_MACHINE, TargetKeyName, &OutKey );
+            break;
+        } else {
+            free( RootDevice ); RootDevice = 0;
+            free( DriverDesc ); DriverDesc = 0;
+        }
+    }
+
+cleanup:
+    if( RootDevice ) free( RootDevice );
+    if( DriverDesc ) free( DriverDesc );
+    if( EnumKeysLinkage ) free( EnumKeysLinkage );
+    if( EnumKeysTop ) free( EnumKeysTop );
+    if( TargetKeyName ) free( TargetKeyName );
+
+    return OutKey;
+}
+
+BOOL PrepareAdapterForService( PDHCP_ADAPTER Adapter ) {
+    HKEY AdapterKey = NULL;
+    PCHAR IPAddress = NULL, Netmask = NULL, DefaultGateway = NULL;
+    NTSTATUS Status = STATUS_SUCCESS;
+    DWORD Error = ERROR_SUCCESS;
+    MIB_IPFORWARDROW DefGatewayRow;
+
+    Adapter->DhclientState.config = &Adapter->DhclientConfig;
+    strncpy(Adapter->DhclientInfo.name, (char*)Adapter->IfMib.bDescr,
+            sizeof(Adapter->DhclientInfo.name));
+
+    AdapterKey = FindAdapterKey( Adapter );
+    if( AdapterKey )
+        IPAddress = RegReadString( AdapterKey, NULL, "IPAddress" );
+
+    if( IPAddress && strcmp( IPAddress, "0.0.0.0" ) ) {
+        /* Non-automatic case */
+        DH_DbgPrint
+            (MID_TRACE,("Adapter Name: [%s] (Bind Status %x) (static %s)\n",
+                        Adapter->DhclientInfo.name,
+                        Adapter->BindStatus,
+                        IPAddress));
+
+        Adapter->DhclientState.state = S_STATIC;
+
+        Netmask = RegReadString( AdapterKey, NULL, "Subnetmask" );
+        if( !Netmask ) Netmask = "255.255.255.0";
+
+        Status = AddIPAddress( inet_addr( IPAddress ),
+                               inet_addr( Netmask ),
+                               Adapter->IfMib.dwIndex,
+                               &Adapter->NteContext,
+                               &Adapter->NteInstance );
+
+        DefaultGateway = RegReadString( AdapterKey, NULL, "DefaultGateway" );
+
+        if( DefaultGateway ) {
+            DefGatewayRow.dwForwardDest = 0;
+            DefGatewayRow.dwForwardMask = 0;
+            DefGatewayRow.dwForwardMetric1 = 1;
+            DefGatewayRow.dwForwardNextHop = inet_addr(DefaultGateway);
+            Error = CreateIpForwardEntry( &DefGatewayRow );
+            if( Error )
+                warning("Failed to set default gateway %s: %ld\n",
+                        DefaultGateway, Error);
+        }
+
+        if( DefaultGateway ) free( DefaultGateway );
+        if( Netmask ) free( Netmask );
+    } else {
+        /* Automatic case */
+        DH_DbgPrint
+            (MID_TRACE,("Adapter Name: [%s] (Bind Status %x) (dynamic)\n",
+                        Adapter->DhclientInfo.name,
+                        Adapter->BindStatus));
+    }
+
+    if( IPAddress ) free( IPAddress );
+
+    return TRUE;
+}
+
+/*
+ * XXX Figure out the way to bind a specific adapter to a socket.
+ */
+
+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",
+                               Table->table[i].dwIndex));
+        Adapter = calloc( sizeof( DHCP_ADAPTER ) + Table->table[i].dwMtu, 1 );
+
+        if( Adapter && Table->table[i].dwType == MIB_IF_TYPE_ETHERNET ) {
+            memcpy( &Adapter->IfMib, &Table->table[i],
+                    sizeof(Adapter->IfMib) );
+            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;
+            memcpy(Adapter->DhclientInfo.hw_address.haddr,
+                   Adapter->IfMib.bPhysAddr,
+                   Adapter->IfMib.dwPhysAddrLen);
+            Adapter->DhclientInfo.hw_address.hlen  =
+                Adapter->IfMib.dwPhysAddrLen;
+
+            if( DhcpSocket == INVALID_SOCKET ) {
+                DhcpSocket =
+                    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();
+            } else {
+                Adapter->DhclientInfo.rfdesc =
+                    Adapter->DhclientInfo.wfdesc = DhcpSocket;
+            }
+
+            Adapter->DhclientConfig.timeout = DHCP_PANIC_TIMEOUT;
+            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;
+
+            if( PrepareAdapterForService( Adapter ) ) {
+                Adapter->DhclientInfo.next = ifi;
+                ifi = &Adapter->DhclientInfo;
+                InsertTailList( &AdapterList, &Adapter->ListEntry );
+            } else { free( Adapter ); Adapter = 0; }
+        } else { free( Adapter ); Adapter = 0; }
+
+        if( !Adapter )
+            DH_DbgPrint(MID_TRACE,("Adapter %d was rejected\n",
+                                   Table->table[i].dwIndex));
+    }
+
+    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 AdapterFindInfo( struct interface_info *ip ) {
+    PDHCP_ADAPTER Adapter;
+    PLIST_ENTRY ListEntry;
+
+    for( ListEntry = AdapterList.Flink;
+         ListEntry != &AdapterList;
+         ListEntry = ListEntry->Flink ) {
+        Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
+        if( ip == &Adapter->DhclientInfo ) 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/services/dhcp/alloc.c b/reactos/services/dhcp/alloc.c
new file mode 100644 (file)
index 0000000..5894a96
--- /dev/null
@@ -0,0 +1,79 @@
+/*     $OpenBSD: alloc.c,v 1.9 2004/05/04 20:28:40 deraadt Exp $       */
+
+/* Memory allocation... */
+
+/*
+ * Copyright (c) 1995, 1996, 1998 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include "rosdhcp.h"
+#include "dhcpd.h"
+
+struct string_list *
+new_string_list(size_t size)
+{
+       struct string_list *rval;
+
+       rval = calloc(1, sizeof(struct string_list) + size);
+       if (rval != NULL)
+               rval->string = ((char *)rval) + sizeof(struct string_list);
+       return (rval);
+}
+
+struct hash_table *
+new_hash_table(int count)
+{
+       struct hash_table *rval;
+
+       rval = calloc(1, sizeof(struct hash_table) -
+           (DEFAULT_HASH_SIZE * sizeof(struct hash_bucket *)) +
+           (count * sizeof(struct hash_bucket *)));
+       if (rval == NULL)
+               return (NULL);
+       rval->hash_count = count;
+       return (rval);
+}
+
+struct hash_bucket *
+new_hash_bucket(void)
+{
+       struct hash_bucket *rval = calloc(1, sizeof(struct hash_bucket));
+
+       return (rval);
+}
+
+void free_hash_bucket(struct hash_bucket *hb) { free(hb); }
diff --git a/reactos/services/dhcp/api.c b/reactos/services/dhcp/api.c
new file mode 100644 (file)
index 0000000..ca628bb
--- /dev/null
@@ -0,0 +1,142 @@
+/* $Id: $
+ *
+ * COPYRIGHT:        See COPYING in the top level directory
+ * PROJECT:          ReactOS kernel
+ * FILE:             subsys/system/dhcp/api.c
+ * PURPOSE:          DHCP client api handlers
+ * PROGRAMMER:       arty
+ */
+
+#include <winsock2.h>
+#include <iphlpapi.h>
+#include "rosdhcp.h"
+
+static CRITICAL_SECTION ApiCriticalSection;
+
+VOID ApiInit() {
+    InitializeCriticalSection( &ApiCriticalSection );
+}
+
+VOID ApiLock() {
+    EnterCriticalSection( &ApiCriticalSection );
+}
+
+VOID ApiUnlock() {
+    LeaveCriticalSection( &ApiCriticalSection );
+}
+
+/* This represents the service portion of the DHCP client API */
+
+DWORD DSLeaseIpAddress( PipeSendFunc Send, COMM_DHCP_REQ *Req ) {
+    COMM_DHCP_REPLY Reply;
+    PDHCP_ADAPTER Adapter;
+
+    ApiLock();
+
+    Adapter = AdapterFindIndex( Req->AdapterIndex );
+
+    Reply.Reply = Adapter ? 1 : 0;
+
+    if( Adapter ) {
+        add_protocol( Adapter->DhclientInfo.name,
+                      Adapter->DhclientInfo.rfdesc, got_one,
+                      &Adapter->DhclientInfo );
+       Adapter->DhclientInfo.client->state = S_INIT;
+       state_reboot(&Adapter->DhclientInfo);
+    }
+
+    ApiUnlock();
+
+    return Send( &Reply );
+}
+
+DWORD DSQueryHWInfo( PipeSendFunc Send, COMM_DHCP_REQ *Req ) {
+    COMM_DHCP_REPLY Reply;
+    PDHCP_ADAPTER Adapter;
+
+    ApiLock();
+
+    Adapter = AdapterFindIndex( Req->AdapterIndex );
+
+    Reply.QueryHWInfo.AdapterIndex = Req->AdapterIndex;
+    Reply.QueryHWInfo.MediaType = Adapter->IfMib.dwType;
+    Reply.QueryHWInfo.Mtu = Adapter->IfMib.dwMtu;
+    Reply.QueryHWInfo.Speed = Adapter->IfMib.dwSpeed;
+
+    ApiUnlock();
+
+    return Send( &Reply );
+}
+
+DWORD DSReleaseIpAddressLease( PipeSendFunc Send, COMM_DHCP_REQ *Req ) {
+    COMM_DHCP_REPLY Reply;
+    PDHCP_ADAPTER Adapter;
+
+    ApiLock();
+
+    Adapter = AdapterFindIndex( Req->AdapterIndex );
+
+    Reply.Reply = Adapter ? 1 : 0;
+
+    if( Adapter ) {
+        DeleteIPAddress( Adapter->NteContext );
+        remove_protocol( find_protocol_by_adapter( &Adapter->DhclientInfo ) );
+    }
+
+    ApiUnlock();
+
+    return Send( &Reply );
+}
+
+DWORD DSRenewIpAddressLease( PipeSendFunc Send, COMM_DHCP_REQ *Req ) {
+    COMM_DHCP_REPLY Reply;
+    PDHCP_ADAPTER Adapter;
+
+    ApiLock();
+
+    Adapter = AdapterFindIndex( Req->AdapterIndex );
+
+    Reply.Reply = Adapter ? 1 : 0;
+
+    if( !Adapter || Adapter->DhclientState.state != S_BOUND ) {
+        Reply.Reply = 0;
+        return Send( &Reply );
+    }
+
+    Adapter->DhclientState.state = S_BOUND;
+
+    send_discover( &Adapter->DhclientInfo );
+    state_bound( &Adapter->DhclientInfo );
+
+    ApiUnlock();
+
+    return Send( &Reply );
+}
+
+DWORD DSStaticRefreshParams( PipeSendFunc Send, COMM_DHCP_REQ *Req ) {
+    NTSTATUS Status;
+    COMM_DHCP_REPLY Reply;
+    PDHCP_ADAPTER Adapter;
+
+    ApiLock();
+
+    Adapter = AdapterFindIndex( Req->AdapterIndex );
+
+    Reply.Reply = Adapter ? 1 : 0;
+
+    if( Adapter ) {
+        DeleteIPAddress( Adapter->NteContext );
+        Adapter->DhclientState.state = S_STATIC;
+        remove_protocol( find_protocol_by_adapter( &Adapter->DhclientInfo ) );
+        Status = AddIPAddress( Req->Body.StaticRefreshParams.IPAddress,
+                               Req->Body.StaticRefreshParams.Netmask,
+                               Req->AdapterIndex,
+                               &Adapter->NteContext,
+                               &Adapter->NteInstance );
+        Reply.Reply = NT_SUCCESS(Status);
+    }
+
+    ApiUnlock();
+
+    return Send( &Reply );
+}
diff --git a/reactos/services/dhcp/compat.c b/reactos/services/dhcp/compat.c
new file mode 100644 (file)
index 0000000..34ed1d4
--- /dev/null
@@ -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/services/dhcp/design.txt b/reactos/services/dhcp/design.txt
new file mode 100644 (file)
index 0000000..17c9a29
--- /dev/null
@@ -0,0 +1,33 @@
+Acknowledgements:
+
+       Tinus provided the initial port of these dhclient file.
+
+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/services/dhcp/dhclient.c b/reactos/services/dhcp/dhclient.c
new file mode 100644 (file)
index 0000000..0734bf0
--- /dev/null
@@ -0,0 +1,2079 @@
+/*     $OpenBSD: dhclient.c,v 1.62 2004/12/05 18:35:51 deraadt Exp $   */
+
+/*
+ * Copyright 2004 Henning Brauer <henning@openbsd.org>
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999
+ * The Internet Software Consortium.    All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ *
+ * This client was substantially modified and enhanced by Elliot Poger
+ * for use on Linux while he was working on the MosquitoNet project at
+ * Stanford.
+ *
+ * The current version owes much to Elliot's Linux enhancements, but
+ * was substantially reorganized and partially rewritten by Ted Lemon
+ * so as to use the same networking framework that the Internet Software
+ * Consortium DHCP server uses.   Much system-specific configuration code
+ * was moved into a shell script so that as support for more operating
+ * systems is added, it will not be necessary to port and maintain
+ * system-specific configuration code to these operating systems - instead,
+ * the shell script can invoke the native tools to accomplish the same
+ * purpose.
+ */
+
+#include <winsock2.h>
+#include "rosdhcp.h"
+#include "dhcpd.h"
+#include "privsep.h"
+
+#define        PERIOD 0x2e
+#define        hyphenchar(c) ((c) == 0x2d)
+#define        bslashchar(c) ((c) == 0x5c)
+#define        periodchar(c) ((c) == PERIOD)
+#define        asterchar(c) ((c) == 0x2a)
+#define        alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
+           ((c) >= 0x61 && (c) <= 0x7a))
+#define        digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
+
+#define        borderchar(c) (alphachar(c) || digitchar(c))
+#define        middlechar(c) (borderchar(c) || hyphenchar(c))
+#define        domainchar(c) ((c) > 0x20 && (c) < 0x7f)
+
+unsigned long debug_trace_level = 0; /* 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;
+unsigned long old_default_route = 0;
+
+/*
+ * 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);
+int              check_arp( struct interface_info *ip, struct client_lease *lp );
+
+#define        ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+time_t scripttime;
+
+/* XXX Implement me */
+int check_arp( struct interface_info *ip, struct client_lease *lp ) {
+    return 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+    int i = 0;
+        ApiInit();
+        AdapterInit();
+        PipeInit();
+
+       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"));
+
+        /* If no adapters were found, just idle for now ... If any show up,
+         * then we'll start it later */
+        if( ifi ) {
+            /* set up the interface */
+            discover_interfaces(ifi);
+
+            DH_DbgPrint
+                (MID_TRACE,
+                 ("Setting init state and restarting interface %p\n",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) {
+                    if( !check_arp(ip,lp) ) 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 set_name_servers( struct client_lease *new_lease ) {
+    if( new_lease->options[DHO_DOMAIN_NAME_SERVERS].len ) {
+        HKEY RegKey;
+        struct iaddr nameserver;
+        char *nsbuf;
+        int i, addrs =
+            new_lease->options[DHO_DOMAIN_NAME_SERVERS].len / sizeof(ULONG);
+
+               /* XXX I'm setting addrs to 1 until we are ready up the chain */
+               addrs = 1;
+        nsbuf = malloc( addrs * sizeof(IP_ADDRESS_STRING) );
+        nsbuf[0] = 0;
+
+        if( nsbuf && !RegOpenKeyEx
+            ( HKEY_LOCAL_MACHINE,
+              "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
+              0, KEY_WRITE, &RegKey ) ) {
+            for( i = 0; i < addrs; i++ ) {
+                nameserver.len = sizeof(ULONG);
+                memcpy( nameserver.iabuf,
+                        new_lease->options[DHO_DOMAIN_NAME_SERVERS].data +
+                        (i * sizeof(ULONG)), sizeof(ULONG) );
+                strcat( nsbuf, piaddr(nameserver) );
+                if( i != addrs-1 ) strcat( nsbuf, "," );
+            }
+
+            DH_DbgPrint(MID_TRACE,("Setting Nameservers: %s\n", nsbuf));
+
+            /* XXX Fixme: I think this may be wrong and that we might have
+             * a problem somewhere else (in iphlpapi for example).
+             *
+             * Recheck the +1 below.
+             */
+            RegSetValueEx( RegKey, "NameServer", 0, REG_SZ,
+                           (LPBYTE)nsbuf, strlen(nsbuf) + 1 );
+
+            free( nsbuf );
+        }
+    }
+}
+
+void setup_adapter( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) {
+    struct iaddr netmask;
+
+    if( Adapter->NteContext )
+        DeleteIPAddress( Adapter->NteContext );
+
+    /* Set up our default router if we got one from the DHCP server */
+    if( new_lease->options[DHO_SUBNET_MASK].len ) {
+        NTSTATUS Status;
+
+        memcpy( netmask.iabuf,
+                new_lease->options[DHO_SUBNET_MASK].data,
+                new_lease->options[DHO_SUBNET_MASK].len );
+
+        Status = AddIPAddress
+            ( *((ULONG*)new_lease->address.iabuf),
+              *((ULONG*)netmask.iabuf),
+              Adapter->IfMib.dwIndex,
+              &Adapter->NteContext,
+              &Adapter->NteInstance );
+
+        if( !NT_SUCCESS(Status) )
+            warning("AddIPAddress: %lx\n", Status);
+    }
+
+    if( new_lease->options[DHO_ROUTERS].len ) {
+        MIB_IPFORWARDROW RouterMib;
+        NTSTATUS Status;
+
+        RouterMib.dwForwardDest = 0; /* Default route */
+        RouterMib.dwForwardMask = 0;
+        RouterMib.dwForwardMetric1 = 1;
+
+        if( old_default_route ) {
+            /* If we set a default route before, delete it before continuing */
+            RouterMib.dwForwardDest = old_default_route;
+            DeleteIpForwardEntry( &RouterMib );
+        }
+
+        RouterMib.dwForwardNextHop =
+            *((ULONG*)new_lease->options[DHO_ROUTERS].data);
+
+        Status = CreateIpForwardEntry( &RouterMib );
+
+        if( !NT_SUCCESS(Status) )
+            warning("CreateIpForwardEntry: %lx\n", Status);
+        else
+            old_default_route = RouterMib.dwForwardNextHop;
+    }
+}
+
+
+void
+bind_lease(struct interface_info *ip)
+{
+    PDHCP_ADAPTER Adapter;
+    struct client_lease *new_lease = ip->client->new;
+
+    /* Remember the medium. */
+    ip->client->new->medium = ip->client->medium;
+    ip->client->active = ip->client->new;
+    ip->client->new = NULL;
+
+    /* Set up a timeout to start the renewal process. */
+    /* Timeout of zero means no timeout (some implementations seem to use
+     * one day).
+     */
+    if( ip->client->active->renewal - cur_time )
+        add_timeout(ip->client->active->renewal, state_bound, ip);
+
+    note("bound to %s -- renewal in %ld seconds.",
+         piaddr(ip->client->active->address),
+         ip->client->active->renewal - cur_time);
+
+    ip->client->state = S_BOUND;
+
+    Adapter = AdapterFindInfo( ip );
+
+    if( Adapter )  setup_adapter( Adapter, new_lease );
+    else warning("Could not find adapter for info %p\n", ip);
+
+    set_name_servers( new_lease );
+
+    reinitialize_interfaces();
+}
+
+/*
+ * 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 = 0, 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. */
+        if( !check_arp( ip, lease ) ) {
+            note("Arp check failed\n");
+            return;
+        }
+
+       /* 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;
+
+               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);
+                /* XXX Support other media types eventually */
+       }
+
+       /*
+        * 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 %ld",
+           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 (cur_time <
+                            ip->client->active->renewal) {
+                            ip->client->state = S_BOUND;
+                            note("bound: renewal in %ld 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();
+                        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");
+       ip->client->state = S_INIT;
+       add_timeout(cur_time + ip->client->config->retry_interval, state_init,
+           ip);
+        /* XXX Take any failure actions necessary */
+}
+
+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) {
+               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. */
+                /* XXX Nothing for now */
+
+               /* 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) {
+            PDHCP_ADAPTER Adapter = AdapterFindInfo( ip );
+            /* Run the client script with the new parameters. */
+            /* No script actions necessary in the expiry case */
+            /* Now do a preinit on the interface so that we can
+               discover a new address. */
+
+            if( Adapter )
+                DeleteIPAddress( Adapter->NteContext );
+
+            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);
+}
+
+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;
+
+#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
+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(%d): %s", option, 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)
+{
+    char *tmp;
+    struct in_addr jnk;
+    int i = 0;
+
+    note("Input: %s\n", buf);
+
+    do {
+        tmp = strtok(buf, " ");
+        note("got %s\n", tmp);
+        if( tmp && inet_aton(tmp, &jnk) ) i++;
+        buf = NULL;
+    } while( tmp );
+
+    return (i);
+}
+
+
+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 "<error>";
+}
+
+#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/services/dhcp/dhcp.rc b/reactos/services/dhcp/dhcp.rc
new file mode 100644 (file)
index 0000000..35e404f
--- /dev/null
@@ -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 <reactos/version.rc>
diff --git a/reactos/services/dhcp/dhcp.xml b/reactos/services/dhcp/dhcp.xml
new file mode 100644 (file)
index 0000000..46efa47
--- /dev/null
@@ -0,0 +1,27 @@
+<module name="dhcp" type="win32gui" installbase="system32" installname="dhcp.exe" allowwarnings="true">
+       <include base="dhcp">.</include>
+       <include base="dhcp">include</include>
+       <define name="__USE_W32API" />
+       <define name="__REACTOS__" />
+       <define name="_WIN32_WINNT">0x0501</define>
+       <library>ntdll</library>
+       <library>kernel32</library>
+       <library>ws2_32</library>
+       <library>iphlpapi</library>
+    <pch>include/rosdhcp.h</pch>
+       <file>adapter.c</file>
+       <file>alloc.c</file>
+       <file>api.c</file>
+       <file>compat.c</file>
+       <file>dhclient.c</file>
+       <file>dispatch.c</file>
+       <file>hash.c</file>
+       <file>options.c</file>
+       <file>pipe.c</file>
+       <file>privsep.c</file>
+       <file>socket.c</file>
+       <file>tables.c</file>
+       <file>timer.c</file>
+       <file>util.c</file>
+       <file>dhcp.rc</file>
+</module>
diff --git a/reactos/services/dhcp/dhcpmain.c b/reactos/services/dhcp/dhcpmain.c
new file mode 100644 (file)
index 0000000..c1a1b30
--- /dev/null
@@ -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 <windows.h>
+#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/services/dhcp/dispatch.c b/reactos/services/dhcp/dispatch.c
new file mode 100644 (file)
index 0000000..5bf9410
--- /dev/null
@@ -0,0 +1,500 @@
+/*     $OpenBSD: dispatch.c,v 1.31 2004/09/21 04:07:03 david Exp $     */
+
+/*
+ * Copyright 2004 Henning Brauer <henning@openbsd.org>
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999
+ * The Internet Software Consortium.   All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include "rosdhcp.h"
+#include "dhcpd.h"
+//#include <sys/ioctl.h>
+
+//#include <net/if_media.h>
+//#include <ifaddrs.h>
+//#include <poll.h>
+
+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.
+ */
+void
+discover_interfaces(struct interface_info *iface)
+{
+    PDHCP_ADAPTER Adapter = AdapterFindInfo( iface );
+
+    if_register_receive(iface);
+    if_register_send(iface);
+
+    if( Adapter->DhclientState.state != S_STATIC ) {
+        add_protocol(iface->name, iface->rfdesc, got_one, iface);
+       iface->client->state = S_INIT;
+       state_reboot(iface);
+    }
+}
+
+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;
+
+    ApiLock();
+
+    for (l = protocols; l; l = l->next)
+        nfds++;
+
+    FD_ZERO(&fds);
+
+    do {
+        /*
+         * Call any expired timeouts, and then if there's still
+         * a timeout registered, time out the select call then.
+         */
+    another:
+        if (timeouts) {
+            struct timeout *t;
+
+            if (timeouts->when <= cur_time) {
+                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)) {
+                FD_SET(l->fd, &fds);
+                i++;
+            }
+        }
+
+        if (i == 0) {
+            /* No interfaces for now, set the select timeout reasonably so
+             * we can recover from that condition later. */
+            timeval.tv_sec = 5;
+            timeval.tv_usec = 0;
+        } else {
+            /* Wait for a packet or a timeout... XXX */
+            timeval.tv_sec = to_msec / 1000;
+            timeval.tv_usec = (to_msec % 1000) * 1000;
+        }
+
+        ApiUnlock();
+
+        count = select(nfds, &fds, NULL, NULL, &timeval);
+
+        DH_DbgPrint(MID_TRACE,("Select: %d\n", count));
+
+        /* Review poll output */
+        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,
+                     ("set(%d) -> %s\n",
+                      l->fd, FD_ISSET(l->fd, &fds) ? "true" : "false"));
+                i++;
+            }
+        }
+
+
+        ApiLock();
+
+        /* Not likely to be transitory... */
+        if (count == SOCKET_ERROR) {
+            if (errno == EAGAIN || errno == EINTR) {
+                time(&cur_time);
+                continue;
+            } else {
+                error("poll: %m");
+                break;
+            }
+        }
+
+        /* 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)) {
+                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;
+        }
+    } while (1);
+
+    ApiUnlock(); /* Not reached currently */
+}
+
+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);
+        }
+    }
+}
+
+struct protocol *
+find_protocol_by_adapter(struct interface_info *info)
+{
+    struct protocol *p;
+
+    for( p = protocols; p; p = p->next ) {
+        if( p->local == (void *)info ) return p;
+    }
+
+    return NULL;
+}
+
+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/services/dhcp/hash.c b/reactos/services/dhcp/hash.c
new file mode 100644 (file)
index 0000000..bd54ec3
--- /dev/null
@@ -0,0 +1,165 @@
+/* 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 <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#define lint
+#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/services/dhcp/include/cdefs.h b/reactos/services/dhcp/include/cdefs.h
new file mode 100644 (file)
index 0000000..2bc67a5
--- /dev/null
@@ -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/services/dhcp/include/debug.h b/reactos/services/dhcp/include/debug.h
new file mode 100644 (file)
index 0000000..5ee3e5e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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 */
+
+#else /* DBG */
+
+#define DH_DbgPrint(_t_, _x_)
+
+#endif /* DBG */
+
+#endif /* __DEBUG_H */
+
+/* EOF */
diff --git a/reactos/services/dhcp/include/dhcp.h b/reactos/services/dhcp/include/dhcp.h
new file mode 100644 (file)
index 0000000..8ac8ed3
--- /dev/null
@@ -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 <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#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/services/dhcp/include/dhcpd.h b/reactos/services/dhcp/include/dhcpd.h
new file mode 100644 (file)
index 0000000..1434021
--- /dev/null
@@ -0,0 +1,473 @@
+/*     $OpenBSD: dhcpd.h,v 1.33 2004/05/06 22:29:15 deraadt Exp $      */
+
+/*
+ * Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999
+ * The Internet Software Consortium.    All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#ifndef DHCPD_H
+#define DHCPD_H
+
+#include <winsock2.h>
+#include <iphlpapi.h>
+#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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#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,
+        S_STATIC
+};
+
+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 *);
+struct protocol *find_protocol_by_adapter( struct interface_info * );
+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/services/dhcp/include/dhctoken.h b/reactos/services/dhcp/include/dhctoken.h
new file mode 100644 (file)
index 0000000..2aeb530
--- /dev/null
@@ -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 <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#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/services/dhcp/include/hash.h b/reactos/services/dhcp/include/hash.h
new file mode 100644 (file)
index 0000000..1bebb31
--- /dev/null
@@ -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 <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#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/services/dhcp/include/inet.h b/reactos/services/dhcp/include/inet.h
new file mode 100644 (file)
index 0000000..a45f922
--- /dev/null
@@ -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 <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+/* 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/services/dhcp/include/osdep.h b/reactos/services/dhcp/include/osdep.h
new file mode 100644 (file)
index 0000000..71a9859
--- /dev/null
@@ -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/services/dhcp/include/predec.h b/reactos/services/dhcp/include/predec.h
new file mode 100644 (file)
index 0000000..7f2515b
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef REACTOS_PREDEC_H
+#define REACTOS_PREDEC_H
+
+struct iaddr;
+struct interface_info;
+
+#endif
diff --git a/reactos/services/dhcp/include/privsep.h b/reactos/services/dhcp/include/privsep.h
new file mode 100644 (file)
index 0000000..e1fc52d
--- /dev/null
@@ -0,0 +1,47 @@
+/*     $OpenBSD: privsep.h,v 1.2 2004/05/04 18:51:18 henning Exp $ */
+
+/*
+ * Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * 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 <sys/types.h>
+
+//#include <poll.h>
+//#include <pwd.h>
+
+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/services/dhcp/include/rosdhcp.h b/reactos/services/dhcp/include/rosdhcp.h
new file mode 100644 (file)
index 0000000..f27d046
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef ROSDHCP_H
+#define ROSDHCP_H
+
+#include <windows.h>
+#define NTOS_MODE_USER
+#include <ndk/ntndk.h>
+#include <iprtrmib.h>
+#include <iphlpapi.h>
+#include <winsock2.h>
+#include <dhcpcsdk.h>
+#include <stdio.h>
+#include <setjmp.h>
+#include "stdint.h"
+#include "predec.h"
+#include <dhcp/rosdhcp_public.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_PANIC_TIMEOUT DHCP_REBOOT_TIMEOUT * 3
+#define DHCP_BACKOFF_MAX 300
+#define _PATH_DHCLIENT_PID "\\systemroot\\system32\\drivers\\etc\\dhclient.pid"
+#define RRF_RT_REG_SZ 2
+typedef void *VOIDPTR;
+
+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;
+    ULONG NteContext,NteInstance;
+    struct interface_info DhclientInfo;
+    struct client_state DhclientState;
+    struct client_config DhclientConfig;
+    struct sockaddr_in ListenAddr;
+    unsigned int BindStatus;
+    unsigned char recv_buf[1];
+} DHCP_ADAPTER, *PDHCP_ADAPTER;
+
+typedef DWORD (*PipeSendFunc)( COMM_DHCP_REPLY *Reply );
+
+#define random rand
+#define srandom srand
+
+void AdapterInit(VOID);
+HANDLE PipeInit(VOID);
+extern PDHCP_ADAPTER AdapterFindIndex( unsigned int AdapterIndex );
+extern PDHCP_ADAPTER AdapterFindInfo( struct interface_info *info );
+extern VOID ApiInit();
+extern VOID ApiLock();
+extern VOID ApiUnlock();
+extern DWORD DSQueryHWInfo( PipeSendFunc Send, COMM_DHCP_REQ *Req );
+extern DWORD DSLeaseIpAddress( PipeSendFunc Send, COMM_DHCP_REQ *Req );
+extern DWORD DSRenewIpAddressLease( PipeSendFunc Send, COMM_DHCP_REQ *Req );
+extern DWORD DSReleaseIpAddressLease( PipeSendFunc Send, COMM_DHCP_REQ *Req );
+int warn( char *format, ... );
+#endif/*ROSDHCP_H*/
diff --git a/reactos/services/dhcp/include/site.h b/reactos/services/dhcp/include/site.h
new file mode 100644 (file)
index 0000000..30fdb70
--- /dev/null
@@ -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 <site-foo-bar.h> */
+/* #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/services/dhcp/include/stdint.h b/reactos/services/dhcp/include/stdint.h
new file mode 100644 (file)
index 0000000..988c303
--- /dev/null
@@ -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/services/dhcp/include/sysconf.h b/reactos/services/dhcp/include/sysconf.h
new file mode 100644 (file)
index 0000000..5feb4c7
--- /dev/null
@@ -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 <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#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/services/dhcp/include/tree.h b/reactos/services/dhcp/include/tree.h
new file mode 100644 (file)
index 0000000..367ffa7
--- /dev/null
@@ -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 <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+/* 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/services/dhcp/include/version.h b/reactos/services/dhcp/include/version.h
new file mode 100644 (file)
index 0000000..303fbfa
--- /dev/null
@@ -0,0 +1,3 @@
+/* Current version of ISC DHCP Distribution. */
+
+#define DHCP_VERSION   "2.0pl5"
diff --git a/reactos/services/dhcp/memory.c b/reactos/services/dhcp/memory.c
new file mode 100644 (file)
index 0000000..fc99fe5
--- /dev/null
@@ -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 <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#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, &lt, 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, &lt, 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/services/dhcp/options.c b/reactos/services/dhcp/options.c
new file mode 100644 (file)
index 0000000..a037712
--- /dev/null
@@ -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 <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include <ctype.h>
+
+#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 ("<error>");
+       }
+       /* 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 ("<error>");
+}
+
+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/services/dhcp/pipe.c b/reactos/services/dhcp/pipe.c
new file mode 100644 (file)
index 0000000..1b31f99
--- /dev/null
@@ -0,0 +1,92 @@
+/* $Id: $
+ *
+ * COPYRIGHT:        See COPYING in the top level directory
+ * PROJECT:          ReactOS kernel
+ * FILE:             subsys/system/dhcp/pipe.c
+ * PURPOSE:          DHCP client pipe
+ * PROGRAMMER:       arty
+ */
+
+#include <rosdhcp.h>
+
+static HANDLE CommPipe = INVALID_HANDLE_VALUE, CommThread;
+DWORD CommThrId;
+
+#define COMM_PIPE_OUTPUT_BUFFER sizeof(COMM_DHCP_REQ)
+#define COMM_PIPE_INPUT_BUFFER sizeof(COMM_DHCP_REPLY)
+#define COMM_PIPE_DEFAULT_TIMEOUT 1000
+
+DWORD PipeSend( COMM_DHCP_REPLY *Reply ) {
+    DWORD Written = 0;
+    BOOL Success =
+        WriteFile( CommPipe,
+                   Reply,
+                   sizeof(*Reply),
+                   &Written,
+                   NULL );
+    return Success ? Written : -1;
+}
+
+DWORD WINAPI PipeThreadProc( LPVOID Parameter ) {
+    DWORD BytesRead, BytesWritten;
+    COMM_DHCP_REQ Req;
+    BOOL Result;
+    BOOLEAN Connection;
+
+    while( (Connection = ConnectNamedPipe( CommPipe, NULL )) ) {
+        Result = ReadFile( CommPipe, &Req, sizeof(Req), &BytesRead, NULL );
+        if( Result ) {
+            switch( Req.Type ) {
+            case DhcpReqQueryHWInfo:
+                BytesWritten = DSQueryHWInfo( PipeSend, &Req );
+                break;
+
+            case DhcpReqLeaseIpAddress:
+                BytesWritten = DSLeaseIpAddress( PipeSend, &Req );
+                break;
+
+            case DhcpReqReleaseIpAddress:
+                BytesWritten = DSReleaseIpAddressLease( PipeSend, &Req );
+                break;
+
+            case DhcpReqRenewIpAddress:
+                BytesWritten = DSRenewIpAddressLease( PipeSend, &Req );
+                break;
+            }
+        }
+        CloseHandle( CommPipe );
+    }
+    
+    return TRUE;
+}
+
+HANDLE PipeInit() {
+    CommPipe = CreateNamedPipe
+        ( DHCP_PIPE_NAME,
+          PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE,
+          PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+          1,
+          COMM_PIPE_OUTPUT_BUFFER,
+          COMM_PIPE_INPUT_BUFFER,
+          COMM_PIPE_DEFAULT_TIMEOUT,
+          NULL );
+
+    if( CommPipe == INVALID_HANDLE_VALUE ) {
+        DbgPrint("DHCP: Could not create named pipe\n");
+        return CommPipe;
+    }
+
+    CommThread = CreateThread( NULL, 0, PipeThreadProc, NULL, 0, &CommThrId );
+
+    if( !CommThread ) {
+        CloseHandle( CommPipe );
+        CommPipe = INVALID_HANDLE_VALUE;
+    }
+
+    return CommPipe;
+}
+
+VOID PipeDestroy() {
+    CloseHandle( CommPipe );
+    CommPipe = INVALID_HANDLE_VALUE;
+}
diff --git a/reactos/services/dhcp/privsep.c b/reactos/services/dhcp/privsep.c
new file mode 100644 (file)
index 0000000..9f36a94
--- /dev/null
@@ -0,0 +1,237 @@
+/*     $OpenBSD: privsep.c,v 1.7 2004/05/10 18:34:42 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * 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/services/dhcp/socket.c b/reactos/services/dhcp/socket.c
new file mode 100644 (file)
index 0000000..849d049
--- /dev/null
@@ -0,0 +1,39 @@
+#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 ) {
+    int result =
+        sendto( ip->wfdesc, (char *)p, size, 0,
+                (struct sockaddr *)broadcast, sizeof(*broadcast) );
+
+    if (result < 0) {
+        note ("send_packet: %x", result);
+        if (result == WSAENETUNREACH)
+            note ("send_packet: please consult README file%s",
+                  " regarding broadcast address.");
+    }
+
+    return result;
+}
+
+ssize_t receive_packet(struct interface_info *ip,
+                       unsigned char *packet_data,
+                       size_t packet_len,
+                       struct sockaddr_in *dest,
+                       struct hardware *hardware ) {
+    int recv_addr_size = sizeof(*dest);
+    int result =
+        recvfrom (ip -> rfdesc, (char *)packet_data, packet_len, 0,
+                  (struct sockaddr *)dest, &recv_addr_size );
+    return result;
+}
diff --git a/reactos/services/dhcp/tables.c b/reactos/services/dhcp/tables.c
new file mode 100644 (file)
index 0000000..3de26b7
--- /dev/null
@@ -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 <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+#define lint
+#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",