[DHCPCSVC]
[reactos.git] / reactos / dll / win32 / dhcpcsvc / dhcp / adapter.c
index ea848bc..890972f 100644 (file)
@@ -145,10 +145,8 @@ cleanup:
 }
 
 BOOL PrepareAdapterForService( PDHCP_ADAPTER Adapter ) {
-    HKEY AdapterKey = NULL;
-    PCHAR IPAddress = NULL, Netmask = NULL, DefaultGateway = NULL;
-    NTSTATUS Status = STATUS_SUCCESS;
-    DWORD Error = ERROR_SUCCESS;
+    HKEY AdapterKey;
+    DWORD Error = ERROR_SUCCESS, DhcpEnabled, Length = sizeof(DWORD);
 
     Adapter->DhclientState.config = &Adapter->DhclientConfig;
     strncpy(Adapter->DhclientInfo.name, (char*)Adapter->IfMib.bDescr,
@@ -156,54 +154,32 @@ BOOL PrepareAdapterForService( PDHCP_ADAPTER Adapter ) {
 
     AdapterKey = FindAdapterKey( Adapter );
     if( AdapterKey )
-        IPAddress = RegReadString( AdapterKey, NULL, "IPAddress" );
+    {
+        Error = RegQueryValueEx(AdapterKey, "EnableDHCP", NULL, NULL, (LPBYTE)&DhcpEnabled, &Length);
 
-    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));
+        if (Error != ERROR_SUCCESS || Length != sizeof(DWORD))
+            DhcpEnabled = 1;
 
-        Adapter->DhclientState.state = S_STATIC;
+        CloseHandle(AdapterKey);
+    }
+    else
+    {
+        /* DHCP enabled by default */
+        DhcpEnabled = 1;
+    }           
 
-        Netmask = RegReadString( AdapterKey, NULL, "Subnetmask" );
-
-        Status = AddIPAddress( inet_addr( IPAddress ),
-                               inet_addr( Netmask ? Netmask : "255.255.255.0" ),
-                               Adapter->IfMib.dwIndex,
-                               &Adapter->NteContext,
-                               &Adapter->NteInstance );
-
-        DefaultGateway = RegReadString( AdapterKey, NULL, "DefaultGateway" );
-
-        if( DefaultGateway ) {
-            Adapter->RouterMib.dwForwardDest = 0;
-            Adapter->RouterMib.dwForwardMask = 0;
-            Adapter->RouterMib.dwForwardMetric1 = 1;
-            Adapter->RouterMib.dwForwardIfIndex = Adapter->IfMib.dwIndex;
-            Adapter->RouterMib.dwForwardNextHop = inet_addr(DefaultGateway);
-            Error = CreateIpForwardEntry( &Adapter->RouterMib );
-            if( Error )
-                warning("Failed to set default gateway %s: %ld\n",
-                        DefaultGateway, Error);
-        }
+    if( !DhcpEnabled ) {
+        /* Non-automatic case */
+        DbgPrint("DHCPCSVC: Adapter Name: [%s] (static)\n", Adapter->DhclientInfo.name);
 
-        if( DefaultGateway ) free( DefaultGateway );
-        if( Netmask ) free( Netmask );
+        Adapter->DhclientState.state = S_STATIC;
     } else {
         /* Automatic case */
-        DH_DbgPrint
-            (MID_TRACE,("Adapter Name: [%s] (Bind Status %x) (dynamic)\n",
-                        Adapter->DhclientInfo.name,
-                        Adapter->BindStatus));
+        DbgPrint("DHCPCSVC: Adapter Name: [%s] (dynamic)\n", Adapter->DhclientInfo.name);
 
        Adapter->DhclientInfo.client->state = S_INIT;
     }
 
-    if( IPAddress ) free( IPAddress );
-
     return TRUE;
 }
 
@@ -227,141 +203,203 @@ InterfaceConnected(MIB_IFROW IfEntry)
 /*
  * XXX Figure out the way to bind a specific adapter to a socket.
  */
-BOOLEAN AdapterDiscover() {
+DWORD WINAPI AdapterDiscoveryThread(LPVOID Context) {
     PMIB_IFTABLE Table = (PMIB_IFTABLE) malloc(sizeof(MIB_IFTABLE));
     DWORD Error, Size = sizeof(MIB_IFTABLE);
     PDHCP_ADAPTER Adapter = NULL;
+    HANDLE AdapterStateChangedEvent = (HANDLE)Context;
     struct interface_info *ifi = NULL;
-    int i;
-    BOOLEAN ret = TRUE;
+    int i, AdapterCount = 0, Broadcast;
 
-    DH_DbgPrint(MID_TRACE,("Getting Adapter List...\n"));
+    /* FIXME: Kill this thread when the service is stopped */
 
-    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 = (PMIB_IFTABLE) malloc( Size );
-    }
+    do {
+       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 = (PMIB_IFTABLE) malloc( Size );
+       }
+
+       if( Error != NO_ERROR )
+       {
+           /* HACK: We are waiting until TCP/IP starts */
+           Sleep(2000);
+           continue;
+       }
+
+       DH_DbgPrint(MID_TRACE,("Got Adapter List (%d entries)\n", Table->dwNumEntries));
+
+       for( i = Table->dwNumEntries - 1; i >= 0; i-- ) {
+            DH_DbgPrint(MID_TRACE,("Getting adapter %d attributes\n",
+                                   Table->table[i].dwIndex));
 
-    if( Error != NO_ERROR ) {
-        ret = FALSE;
-        goto term;
-    }
+            ApiLock();
 
-    DH_DbgPrint(MID_TRACE,("Got Adapter List (%d entries)\n", Table->dwNumEntries));
-
-    for( i = Table->dwNumEntries - 1; i >= 0; i-- ) {
-        DH_DbgPrint(MID_TRACE,("Getting adapter %d attributes\n",
-                               Table->table[i].dwIndex));
-
-        if ((Adapter = AdapterFindByHardwareAddress(Table->table[i].bPhysAddr, Table->table[i].dwPhysAddrLen)))
-        {
-            /* This is an existing adapter */
-            if (InterfaceConnected(Table->table[i])) {
-                /* We're still active so we stay in the list */
-                ifi = &Adapter->DhclientInfo;
-            } else {
-                /* We've lost our link so out we go */
-                RemoveEntryList(&Adapter->ListEntry);
-                free(Adapter);
-            }
+            if ((Adapter = AdapterFindByHardwareAddress(Table->table[i].bPhysAddr, Table->table[i].dwPhysAddrLen)))
+            {
+                /* This is an existing adapter */
+                if (InterfaceConnected(Table->table[i])) {
+                    /* We're still active so we stay in the list */
+                    ifi = &Adapter->DhclientInfo;
+                } else {
+                    /* We've lost our link so out we go */
+                    RemoveEntryList(&Adapter->ListEntry);
+                    free(Adapter);
+                }
 
-            continue;
-        }
+                ApiUnlock();
 
-        Adapter = (DHCP_ADAPTER*) calloc( sizeof( DHCP_ADAPTER ) + Table->table[i].dwMtu, 1 );
-
-        if( Adapter && Table->table[i].dwType == MIB_IF_TYPE_ETHERNET && InterfaceConnected(Table->table[i])) {
-            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;
-            /* I'm not sure where else to set this, but
-               some DHCP servers won't take a zero.
-               We checked the hardware type earlier in
-               the if statement. */
-            Adapter->DhclientInfo.hw_address.htype  =
-                HTYPE_ETHER;
-
-            if( DhcpSocket == INVALID_SOCKET ) {
-                DhcpSocket =
-                    Adapter->DhclientInfo.rfdesc =
-                    Adapter->DhclientInfo.wfdesc =
-                    socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
-
-                if (DhcpSocket != INVALID_SOCKET) {
-                    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();
+                continue;
+            }
+
+            ApiUnlock();
+
+            Adapter = (DHCP_ADAPTER*) calloc( sizeof( DHCP_ADAPTER ) + Table->table[i].dwMtu, 1 );
+
+            if( Adapter && Table->table[i].dwType == MIB_IF_TYPE_ETHERNET && InterfaceConnected(Table->table[i])) {
+                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;
+
+                /* I'm not sure where else to set this, but
+                   some DHCP servers won't take a zero.
+                   We checked the hardware type earlier in
+                   the if statement. */
+                Adapter->DhclientInfo.hw_address.htype = HTYPE_ETHER;
+
+                if( DhcpSocket == INVALID_SOCKET ) {
+                    DhcpSocket =
+                        Adapter->DhclientInfo.rfdesc =
+                        Adapter->DhclientInfo.wfdesc =
+                        socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
+
+                    if (DhcpSocket != INVALID_SOCKET) {
+                                               
+                                               /* Allow broadcast on this socket */
+                                               Broadcast = 1;
+                                               setsockopt(DhcpSocket,
+                                                                  SOL_SOCKET,
+                                                                  SO_BROADCAST,
+                                                                  (const char *)&Broadcast,
+                                                                  sizeof(Broadcast));
+                                               
+                        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 {
+                        error("socket() failed: %d\n", WSAGetLastError());
+                    }
                 } else {
-                    error("socket() failed: %d\n", WSAGetLastError());
+                    Adapter->DhclientInfo.rfdesc =
+                        Adapter->DhclientInfo.wfdesc = DhcpSocket;
                 }
-            } 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;
+                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;
+
+                    read_client_conf(&Adapter->DhclientInfo);
+
+                    if (Adapter->DhclientInfo.client->state == S_INIT)
+                    {
+                        add_protocol(Adapter->DhclientInfo.name,
+                                     Adapter->DhclientInfo.rfdesc,
+                                     got_one, &Adapter->DhclientInfo);
+
+                       state_init(&Adapter->DhclientInfo);
+                    }
+
+                    ApiLock();
+                    InsertTailList( &AdapterList, &Adapter->ListEntry );
+                    AdapterCount++;
+                    SetEvent(AdapterStateChangedEvent);
+                    ApiUnlock();
+                } 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));
+        }
+        Error = NotifyAddrChange(NULL, NULL);
+#if 0
+        if (Error != NO_ERROR)
+            break;
+#else
+        if (AdapterCount)
+            break;
+        else
+            Sleep(3000);
+#endif
+    } while (TRUE);
 
-            if( PrepareAdapterForService( Adapter ) ) {
-                Adapter->DhclientInfo.next = ifi;
-                ifi = &Adapter->DhclientInfo;
+    DbgPrint("DHCPCSVC: Adapter discovery thread is terminating! (Error: %d)\n", Error);
 
-                read_client_conf(&Adapter->DhclientInfo);
+    if( Table ) free( Table );
+    return Error;
+}
 
-                if (Adapter->DhclientInfo.client->state == S_INIT)
-                {
-                    add_protocol(Adapter->DhclientInfo.name,
-                                 Adapter->DhclientInfo.rfdesc,
-                                 got_one, &Adapter->DhclientInfo);
+HANDLE StartAdapterDiscovery(VOID) {
+    HANDLE /* ThreadHandle, */ EventHandle;
 
-                   state_init(&Adapter->DhclientInfo);
-                }
+    EventHandle = CreateEvent(NULL,
+                              FALSE,
+                              FALSE,
+                              NULL);
 
-                InsertTailList( &AdapterList, &Adapter->ListEntry );
-            } else { free( Adapter ); Adapter = 0; }
-        } else { free( Adapter ); Adapter = 0; }
+#if 0
+    ThreadHandle = CreateThread(NULL,
+                                0,
+                                AdapterDiscoveryThread,
+                                (LPVOID)EventHandle,
+                                0,
+                                NULL);
 
-        if( !Adapter )
-            DH_DbgPrint(MID_TRACE,("Adapter %d was rejected\n",
-                                   Table->table[i].dwIndex));
-    }
+    if (ThreadHandle == NULL)
+        return NULL;
 
-    DH_DbgPrint(MID_TRACE,("done with AdapterInit\n"));
+    CloseHandle(ThreadHandle);
+#else
+    AdapterDiscoveryThread((LPVOID)EventHandle);
+#endif
 
-term:
-    if( Table ) free( Table );
-    return ret;
+    return EventHandle;
 }
 
 void AdapterStop() {
     PLIST_ENTRY ListEntry;
     PDHCP_ADAPTER Adapter;
+    ApiLock();
     while( !IsListEmpty( &AdapterList ) ) {
         ListEntry = (PLIST_ENTRY)RemoveHeadList( &AdapterList );
         Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
         free( Adapter );
     }
+    ApiUnlock();
     WSACleanup();
 }