819af629a793f6cdd34d0c604a6f0483a82cd181
[reactos.git] / base / services / dhcpcsvc / dhcpcsvc.c
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
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
71 DhcpCApiCleanup(VOID)
72 {
73 CloseHandle(PipeHandle);
74 PipeHandle = INVALID_HANDLE_VALUE;
75 }
76
77 DWORD APIENTRY
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
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
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
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
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
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
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
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
344 UpdateServiceStatus(DWORD dwState)
345 {
346 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_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
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
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
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 */