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