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