xref: /reactos/base/services/dhcpcsvc/dhcpcsvc.c (revision 69bd857e)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            lib/dhcpcapi/dhcpcapi.c
5  * PURPOSE:         Client API for DHCP
6  * COPYRIGHT:       Copyright 2005 Art Yerkes <ayerkes@speakeasy.net>
7  */
8 
9 #include <rosdhcp.h>
10 #include <winsvc.h>
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 static WCHAR ServiceName[] = L"DHCP";
16 
17 SERVICE_STATUS_HANDLE ServiceStatusHandle = 0;
18 SERVICE_STATUS ServiceStatus;
19 HANDLE hStopEvent = NULL;
20 HANDLE hAdapterStateChangedEvent = NULL;
21 
22 static HANDLE PipeHandle = INVALID_HANDLE_VALUE;
23 extern SOCKET DhcpSocket;
24 
25 DWORD APIENTRY
DhcpCApiInitialize(LPDWORD Version)26 DhcpCApiInitialize(LPDWORD Version)
27 {
28     DWORD PipeMode;
29 
30     /* Wait for the pipe to be available */
31     if (!WaitNamedPipeW(DHCP_PIPE_NAME, NMPWAIT_USE_DEFAULT_WAIT))
32     {
33         /* No good, we failed */
34         return GetLastError();
35     }
36 
37     /* It's available, let's try to open it */
38     PipeHandle = CreateFileW(DHCP_PIPE_NAME,
39                              GENERIC_READ | GENERIC_WRITE,
40                              FILE_SHARE_READ | FILE_SHARE_WRITE,
41                              NULL,
42                              OPEN_EXISTING,
43                              0,
44                              NULL);
45 
46     /* Check if we succeeded in opening the pipe */
47     if (PipeHandle == INVALID_HANDLE_VALUE)
48     {
49         /* We didn't */
50         return GetLastError();
51     }
52 
53     /* Change the pipe into message mode */
54     PipeMode = PIPE_READMODE_MESSAGE;
55     if (!SetNamedPipeHandleState(PipeHandle, &PipeMode, NULL, NULL))
56     {
57         /* Mode change failed */
58         CloseHandle(PipeHandle);
59         PipeHandle = INVALID_HANDLE_VALUE;
60         return GetLastError();
61     }
62     else
63     {
64         /* We're good to go */
65         *Version = 2;
66         return NO_ERROR;
67     }
68 }
69 
70 VOID APIENTRY
DhcpCApiCleanup(VOID)71 DhcpCApiCleanup(VOID)
72 {
73     CloseHandle(PipeHandle);
74     PipeHandle = INVALID_HANDLE_VALUE;
75 }
76 
77 DWORD APIENTRY
DhcpQueryHWInfo(DWORD AdapterIndex,PDWORD MediaType,PDWORD Mtu,PDWORD Speed)78 DhcpQueryHWInfo(DWORD AdapterIndex,
79                 PDWORD MediaType,
80                 PDWORD Mtu,
81                 PDWORD Speed)
82 {
83     COMM_DHCP_REQ Req;
84     COMM_DHCP_REPLY Reply;
85     DWORD BytesRead;
86     BOOL Result;
87 
88     ASSERT(PipeHandle != INVALID_HANDLE_VALUE);
89 
90     Req.Type = DhcpReqQueryHWInfo;
91     Req.AdapterIndex = AdapterIndex;
92 
93     Result = TransactNamedPipe(PipeHandle,
94                                &Req, sizeof(Req),
95                                &Reply, sizeof(Reply),
96                                &BytesRead, NULL);
97     if (!Result)
98     {
99         /* Pipe transaction failed */
100         return 0;
101     }
102 
103     if (Reply.Reply == 0)
104         return 0;
105 
106     *MediaType = Reply.QueryHWInfo.MediaType;
107     *Mtu = Reply.QueryHWInfo.Mtu;
108     *Speed = Reply.QueryHWInfo.Speed;
109     return 1;
110 }
111 
112 DWORD APIENTRY
DhcpLeaseIpAddress(DWORD AdapterIndex)113 DhcpLeaseIpAddress(DWORD AdapterIndex)
114 {
115     COMM_DHCP_REQ Req;
116     COMM_DHCP_REPLY Reply;
117     DWORD BytesRead;
118     BOOL Result;
119 
120     ASSERT(PipeHandle != INVALID_HANDLE_VALUE);
121 
122     Req.Type = DhcpReqLeaseIpAddress;
123     Req.AdapterIndex = AdapterIndex;
124 
125     Result = TransactNamedPipe(PipeHandle,
126                                &Req, sizeof(Req),
127                                &Reply, sizeof(Reply),
128                                &BytesRead, NULL);
129     if (!Result)
130     {
131         /* Pipe transaction failed */
132         return 0;
133     }
134 
135     return Reply.Reply;
136 }
137 
138 DWORD APIENTRY
DhcpReleaseIpAddressLease(DWORD AdapterIndex)139 DhcpReleaseIpAddressLease(DWORD AdapterIndex)
140 {
141     COMM_DHCP_REQ Req;
142     COMM_DHCP_REPLY Reply;
143     DWORD BytesRead;
144     BOOL Result;
145 
146     ASSERT(PipeHandle != INVALID_HANDLE_VALUE);
147 
148     Req.Type = DhcpReqReleaseIpAddress;
149     Req.AdapterIndex = AdapterIndex;
150 
151     Result = TransactNamedPipe(PipeHandle,
152                                &Req, sizeof(Req),
153                                &Reply, sizeof(Reply),
154                                &BytesRead, NULL);
155     if (!Result)
156     {
157         /* Pipe transaction failed */
158         return 0;
159     }
160 
161     return Reply.Reply;
162 }
163 
164 DWORD APIENTRY
DhcpRenewIpAddressLease(DWORD AdapterIndex)165 DhcpRenewIpAddressLease(DWORD AdapterIndex)
166 {
167     COMM_DHCP_REQ Req;
168     COMM_DHCP_REPLY Reply;
169     DWORD BytesRead;
170     BOOL Result;
171 
172     ASSERT(PipeHandle != INVALID_HANDLE_VALUE);
173 
174     Req.Type = DhcpReqRenewIpAddress;
175     Req.AdapterIndex = AdapterIndex;
176 
177     Result = TransactNamedPipe(PipeHandle,
178                                &Req, sizeof(Req),
179                                &Reply, sizeof(Reply),
180                                &BytesRead, NULL);
181     if (!Result)
182     {
183         /* Pipe transaction failed */
184         return 0;
185     }
186 
187     return Reply.Reply;
188 }
189 
190 DWORD APIENTRY
DhcpStaticRefreshParams(DWORD AdapterIndex,DWORD Address,DWORD Netmask)191 DhcpStaticRefreshParams(DWORD AdapterIndex,
192                         DWORD Address,
193                         DWORD Netmask)
194 {
195     COMM_DHCP_REQ Req;
196     COMM_DHCP_REPLY Reply;
197     DWORD BytesRead;
198     BOOL Result;
199 
200     ASSERT(PipeHandle != INVALID_HANDLE_VALUE);
201 
202     Req.Type = DhcpReqStaticRefreshParams;
203     Req.AdapterIndex = AdapterIndex;
204     Req.Body.StaticRefreshParams.IPAddress = Address;
205     Req.Body.StaticRefreshParams.Netmask = Netmask;
206 
207     Result = TransactNamedPipe(PipeHandle,
208                                &Req, sizeof(Req),
209                                &Reply, sizeof(Reply),
210                                &BytesRead, NULL);
211     if (!Result)
212     {
213         /* Pipe transaction failed */
214         return 0;
215     }
216 
217     return Reply.Reply;
218 }
219 
220 /*!
221  * Set new TCP/IP parameters and notify DHCP client service of this
222  *
223  * \param[in] ServerName
224  *        NULL for local machine
225  *
226  * \param[in] AdapterName
227  *        IPHLPAPI name of adapter to change
228  *
229  * \param[in] NewIpAddress
230  *        TRUE if IP address changes
231  *
232  * \param[in] IpAddress
233  *        New IP address (network byte order)
234  *
235  * \param[in] SubnetMask
236  *        New subnet mask (network byte order)
237  *
238  * \param[in] DhcpAction
239  *        0 - don't modify
240  *        1 - enable DHCP
241  *        2 - disable DHCP
242  *
243  * \return non-zero on success
244  *
245  * \remarks Undocumented by Microsoft
246  */
247 DWORD APIENTRY
DhcpNotifyConfigChange(LPWSTR ServerName,LPWSTR AdapterName,BOOL NewIpAddress,DWORD IpIndex,DWORD IpAddress,DWORD SubnetMask,INT DhcpAction)248 DhcpNotifyConfigChange(LPWSTR ServerName,
249                        LPWSTR AdapterName,
250                        BOOL NewIpAddress,
251                        DWORD IpIndex,
252                        DWORD IpAddress,
253                        DWORD SubnetMask,
254                        INT DhcpAction)
255 {
256     DPRINT1("DHCPCSVC: DhcpNotifyConfigChange not implemented yet\n");
257     return 0;
258 }
259 
260 DWORD APIENTRY
DhcpRequestParams(DWORD Flags,PVOID Reserved,LPWSTR AdapterName,LPDHCPCAPI_CLASSID ClassId,DHCPCAPI_PARAMS_ARRAY SendParams,DHCPCAPI_PARAMS_ARRAY RecdParams,LPBYTE Buffer,LPDWORD pSize,LPWSTR RequestIdStr)261 DhcpRequestParams(DWORD Flags,
262                   PVOID Reserved,
263                   LPWSTR AdapterName,
264                   LPDHCPCAPI_CLASSID ClassId,
265                   DHCPCAPI_PARAMS_ARRAY SendParams,
266                   DHCPCAPI_PARAMS_ARRAY RecdParams,
267                   LPBYTE Buffer,
268                   LPDWORD pSize,
269                   LPWSTR RequestIdStr)
270 {
271     UNIMPLEMENTED;
272     return 0;
273 }
274 
275 /*!
276  * Get DHCP info for an adapter
277  *
278  * \param[in] AdapterIndex
279  *        Index of the adapter (iphlpapi-style) for which info is
280  *        requested
281  *
282  * \param[out] DhcpEnabled
283  *        Returns whether DHCP is enabled for the adapter
284  *
285  * \param[out] DhcpServer
286  *        Returns DHCP server IP address (255.255.255.255 if no
287  *        server reached yet), in network byte order
288  *
289  * \param[out] LeaseObtained
290  *        Returns time at which the lease was obtained
291  *
292  * \param[out] LeaseExpires
293  *        Returns time at which the lease will expire
294  *
295  * \return non-zero on success
296  *
297  * \remarks This is a ReactOS-only routine
298  */
299 DWORD APIENTRY
DhcpRosGetAdapterInfo(DWORD AdapterIndex,PBOOL DhcpEnabled,PDWORD DhcpServer,time_t * LeaseObtained,time_t * LeaseExpires)300 DhcpRosGetAdapterInfo(DWORD AdapterIndex,
301                       PBOOL DhcpEnabled,
302                       PDWORD DhcpServer,
303                       time_t* LeaseObtained,
304                       time_t* LeaseExpires)
305 {
306     COMM_DHCP_REQ Req;
307     COMM_DHCP_REPLY Reply;
308     DWORD BytesRead;
309     BOOL Result;
310 
311     ASSERT(PipeHandle != INVALID_HANDLE_VALUE);
312 
313     Req.Type = DhcpReqGetAdapterInfo;
314     Req.AdapterIndex = AdapterIndex;
315 
316     Result = TransactNamedPipe(PipeHandle,
317                                &Req, sizeof(Req),
318                                &Reply, sizeof(Reply),
319                                &BytesRead, NULL);
320 
321     if (Result && Reply.Reply != 0)
322         *DhcpEnabled = Reply.GetAdapterInfo.DhcpEnabled;
323     else
324         *DhcpEnabled = FALSE;
325 
326     if (*DhcpEnabled)
327     {
328         *DhcpServer = Reply.GetAdapterInfo.DhcpServer;
329         *LeaseObtained = Reply.GetAdapterInfo.LeaseObtained;
330         *LeaseExpires = Reply.GetAdapterInfo.LeaseExpires;
331     }
332     else
333     {
334         *DhcpServer = INADDR_NONE;
335         *LeaseObtained = 0;
336         *LeaseExpires = 0;
337     }
338 
339     return Reply.Reply;
340 }
341 
342 
343 static VOID
UpdateServiceStatus(DWORD dwState)344 UpdateServiceStatus(DWORD dwState)
345 {
346     ServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
347     ServiceStatus.dwCurrentState = dwState;
348 
349     if (dwState == SERVICE_RUNNING)
350         ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
351     else
352         ServiceStatus.dwControlsAccepted = 0;
353 
354     ServiceStatus.dwWin32ExitCode = 0;
355     ServiceStatus.dwServiceSpecificExitCode = 0;
356     ServiceStatus.dwCheckPoint = 0;
357 
358     if (dwState == SERVICE_START_PENDING ||
359         dwState == SERVICE_STOP_PENDING)
360         ServiceStatus.dwWaitHint = 1000;
361     else
362         ServiceStatus.dwWaitHint = 0;
363 
364     SetServiceStatus(ServiceStatusHandle,
365                      &ServiceStatus);
366 }
367 
368 static DWORD WINAPI
ServiceControlHandler(DWORD dwControl,DWORD dwEventType,LPVOID lpEventData,LPVOID lpContext)369 ServiceControlHandler(DWORD dwControl,
370                       DWORD dwEventType,
371                       LPVOID lpEventData,
372                       LPVOID lpContext)
373 {
374     switch (dwControl)
375     {
376         case SERVICE_CONTROL_STOP:
377         case SERVICE_CONTROL_SHUTDOWN:
378             UpdateServiceStatus(SERVICE_STOP_PENDING);
379             if (hStopEvent != NULL)
380                 SetEvent(hStopEvent);
381             return ERROR_SUCCESS;
382 
383         case SERVICE_CONTROL_INTERROGATE:
384             SetServiceStatus(ServiceStatusHandle,
385                              &ServiceStatus);
386             return ERROR_SUCCESS;
387 
388         default:
389             return ERROR_CALL_NOT_IMPLEMENTED;
390     }
391 }
392 
393 VOID WINAPI
ServiceMain(DWORD argc,LPWSTR * argv)394 ServiceMain(DWORD argc, LPWSTR* argv)
395 {
396     HANDLE hPipeThread = INVALID_HANDLE_VALUE;
397     HANDLE hDiscoveryThread = INVALID_HANDLE_VALUE;
398     DWORD ret;
399 
400     ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
401                                                         ServiceControlHandler,
402                                                         NULL);
403     if (!ServiceStatusHandle)
404     {
405         DPRINT1("DHCPCSVC: Unable to register service control handler (%lx)\n", GetLastError());
406         return;
407     }
408 
409     UpdateServiceStatus(SERVICE_START_PENDING);
410 
411     /* Create the stop event */
412     hStopEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
413     if (hStopEvent == NULL)
414     {
415         UpdateServiceStatus(SERVICE_STOPPED);
416         return;
417     }
418 
419     hAdapterStateChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
420     if (hAdapterStateChangedEvent == NULL)
421     {
422         CloseHandle(hStopEvent);
423         UpdateServiceStatus(SERVICE_STOPPED);
424         return;
425     }
426 
427     UpdateServiceStatus(SERVICE_START_PENDING);
428 
429     if (!init_client())
430     {
431         DbgPrint("DHCPCSVC: init_client() failed!\n");
432         CloseHandle(hAdapterStateChangedEvent);
433         CloseHandle(hStopEvent);
434         UpdateServiceStatus(SERVICE_STOPPED);
435         return;
436     }
437 
438     UpdateServiceStatus(SERVICE_START_PENDING);
439 
440     hPipeThread = PipeInit(hStopEvent);
441     if (hPipeThread == INVALID_HANDLE_VALUE)
442     {
443         DbgPrint("DHCPCSVC: PipeInit() failed!\n");
444         stop_client();
445         CloseHandle(hAdapterStateChangedEvent);
446         CloseHandle(hStopEvent);
447         UpdateServiceStatus(SERVICE_STOPPED);
448         return;
449     }
450 
451     hDiscoveryThread = StartAdapterDiscovery(hStopEvent);
452     if (hDiscoveryThread == INVALID_HANDLE_VALUE)
453     {
454         DbgPrint("DHCPCSVC: StartAdapterDiscovery() failed!\n");
455         stop_client();
456         CloseHandle(hAdapterStateChangedEvent);
457         CloseHandle(hStopEvent);
458         UpdateServiceStatus(SERVICE_STOPPED);
459         return;
460     }
461 
462     DH_DbgPrint(MID_TRACE,("DHCP Service Started\n"));
463 
464     UpdateServiceStatus(SERVICE_RUNNING);
465 
466     DH_DbgPrint(MID_TRACE,("Going into dispatch()\n"));
467     DH_DbgPrint(MID_TRACE,("DHCPCSVC: DHCP service is starting up\n"));
468 
469     dispatch(hStopEvent);
470 
471     DH_DbgPrint(MID_TRACE,("DHCPCSVC: DHCP service is shutting down\n"));
472 
473     stop_client();
474 
475     DPRINT("Wait for pipe thread to close! %p\n", hPipeThread);
476     if (hPipeThread != INVALID_HANDLE_VALUE)
477     {
478         DPRINT("Waiting for pipe thread\n");
479         ret = WaitForSingleObject(hPipeThread, 5000);
480         DPRINT("Done %lx\n", ret);
481     }
482 
483     DPRINT("Wait for discovery thread to close! %p\n", hDiscoveryThread);
484     if (hDiscoveryThread != INVALID_HANDLE_VALUE)
485     {
486         DPRINT("Waiting for discovery thread\n");
487         ret = WaitForSingleObject(hDiscoveryThread, 5000);
488         DPRINT("Done %lx\n", ret);
489     }
490 
491     DPRINT("Closing events!\n");
492     CloseHandle(hAdapterStateChangedEvent);
493     CloseHandle(hStopEvent);
494 
495     if (DhcpSocket != INVALID_SOCKET)
496         closesocket(DhcpSocket);
497 
498     CloseHandle(hDiscoveryThread);
499     CloseHandle(hPipeThread);
500 
501     DPRINT("Done!\n");
502 
503     UpdateServiceStatus(SERVICE_STOPPED);
504 }
505 
506 BOOL WINAPI
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)507 DllMain(HINSTANCE hinstDLL,
508         DWORD fdwReason,
509         LPVOID lpvReserved)
510 {
511     switch (fdwReason)
512     {
513         case DLL_PROCESS_ATTACH:
514             DisableThreadLibraryCalls(hinstDLL);
515             break;
516 
517         case DLL_PROCESS_DETACH:
518             break;
519     }
520 
521     return TRUE;
522 }
523 
524 /* EOF */
525