[DHCPSVC] Properly stub DhcpRequestParams()
[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
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 */