/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: lib/dhcpcapi/dhcpcapi.c * PURPOSE: Client API for DHCP * COPYRIGHT: Copyright 2005 Art Yerkes */ #include #include #define NDEBUG #include static WCHAR ServiceName[] = L"DHCP"; SERVICE_STATUS_HANDLE ServiceStatusHandle = 0; SERVICE_STATUS ServiceStatus; HANDLE hStopEvent = NULL; HANDLE hAdapterStateChangedEvent = NULL; static HANDLE PipeHandle = INVALID_HANDLE_VALUE; extern SOCKET DhcpSocket; DWORD APIENTRY DhcpCApiInitialize(LPDWORD Version) { DWORD PipeMode; /* Wait for the pipe to be available */ if (!WaitNamedPipeW(DHCP_PIPE_NAME, NMPWAIT_USE_DEFAULT_WAIT)) { /* No good, we failed */ return GetLastError(); } /* It's available, let's try to open it */ PipeHandle = CreateFileW(DHCP_PIPE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); /* Check if we succeeded in opening the pipe */ if (PipeHandle == INVALID_HANDLE_VALUE) { /* We didn't */ return GetLastError(); } /* Change the pipe into message mode */ PipeMode = PIPE_READMODE_MESSAGE; if (!SetNamedPipeHandleState(PipeHandle, &PipeMode, NULL, NULL)) { /* Mode change failed */ CloseHandle(PipeHandle); PipeHandle = INVALID_HANDLE_VALUE; return GetLastError(); } else { /* We're good to go */ *Version = 2; return NO_ERROR; } } VOID APIENTRY DhcpCApiCleanup(VOID) { CloseHandle(PipeHandle); PipeHandle = INVALID_HANDLE_VALUE; } DWORD APIENTRY DhcpQueryHWInfo(DWORD AdapterIndex, PDWORD MediaType, PDWORD Mtu, PDWORD Speed) { COMM_DHCP_REQ Req; COMM_DHCP_REPLY Reply; DWORD BytesRead; BOOL Result; ASSERT(PipeHandle != INVALID_HANDLE_VALUE); Req.Type = DhcpReqQueryHWInfo; Req.AdapterIndex = AdapterIndex; Result = TransactNamedPipe(PipeHandle, &Req, sizeof(Req), &Reply, sizeof(Reply), &BytesRead, NULL); if (!Result) { /* Pipe transaction failed */ return 0; } if (Reply.Reply == 0) return 0; *MediaType = Reply.QueryHWInfo.MediaType; *Mtu = Reply.QueryHWInfo.Mtu; *Speed = Reply.QueryHWInfo.Speed; return 1; } DWORD APIENTRY DhcpLeaseIpAddress(DWORD AdapterIndex) { COMM_DHCP_REQ Req; COMM_DHCP_REPLY Reply; DWORD BytesRead; BOOL Result; ASSERT(PipeHandle != INVALID_HANDLE_VALUE); Req.Type = DhcpReqLeaseIpAddress; Req.AdapterIndex = AdapterIndex; Result = TransactNamedPipe(PipeHandle, &Req, sizeof(Req), &Reply, sizeof(Reply), &BytesRead, NULL); if (!Result) { /* Pipe transaction failed */ return 0; } return Reply.Reply; } DWORD APIENTRY DhcpReleaseIpAddressLease(DWORD AdapterIndex) { COMM_DHCP_REQ Req; COMM_DHCP_REPLY Reply; DWORD BytesRead; BOOL Result; ASSERT(PipeHandle != INVALID_HANDLE_VALUE); Req.Type = DhcpReqReleaseIpAddress; Req.AdapterIndex = AdapterIndex; Result = TransactNamedPipe(PipeHandle, &Req, sizeof(Req), &Reply, sizeof(Reply), &BytesRead, NULL); if (!Result) { /* Pipe transaction failed */ return 0; } return Reply.Reply; } DWORD APIENTRY DhcpRenewIpAddressLease(DWORD AdapterIndex) { COMM_DHCP_REQ Req; COMM_DHCP_REPLY Reply; DWORD BytesRead; BOOL Result; ASSERT(PipeHandle != INVALID_HANDLE_VALUE); Req.Type = DhcpReqRenewIpAddress; Req.AdapterIndex = AdapterIndex; Result = TransactNamedPipe(PipeHandle, &Req, sizeof(Req), &Reply, sizeof(Reply), &BytesRead, NULL); if (!Result) { /* Pipe transaction failed */ return 0; } return Reply.Reply; } DWORD APIENTRY DhcpStaticRefreshParams(DWORD AdapterIndex, DWORD Address, DWORD Netmask) { COMM_DHCP_REQ Req; COMM_DHCP_REPLY Reply; DWORD BytesRead; BOOL Result; ASSERT(PipeHandle != INVALID_HANDLE_VALUE); Req.Type = DhcpReqStaticRefreshParams; Req.AdapterIndex = AdapterIndex; Req.Body.StaticRefreshParams.IPAddress = Address; Req.Body.StaticRefreshParams.Netmask = Netmask; Result = TransactNamedPipe(PipeHandle, &Req, sizeof(Req), &Reply, sizeof(Reply), &BytesRead, NULL); if (!Result) { /* Pipe transaction failed */ return 0; } return Reply.Reply; } /*! * Set new TCP/IP parameters and notify DHCP client service of this * * \param[in] ServerName * NULL for local machine * * \param[in] AdapterName * IPHLPAPI name of adapter to change * * \param[in] NewIpAddress * TRUE if IP address changes * * \param[in] IpAddress * New IP address (network byte order) * * \param[in] SubnetMask * New subnet mask (network byte order) * * \param[in] DhcpAction * 0 - don't modify * 1 - enable DHCP * 2 - disable DHCP * * \return non-zero on success * * \remarks Undocumented by Microsoft */ DWORD APIENTRY DhcpNotifyConfigChange(LPWSTR ServerName, LPWSTR AdapterName, BOOL NewIpAddress, DWORD IpIndex, DWORD IpAddress, DWORD SubnetMask, INT DhcpAction) { DPRINT1("DHCPCSVC: DhcpNotifyConfigChange not implemented yet\n"); return 0; } 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) { UNIMPLEMENTED; return 0; } /*! * Get DHCP info for an adapter * * \param[in] AdapterIndex * Index of the adapter (iphlpapi-style) for which info is * requested * * \param[out] DhcpEnabled * Returns whether DHCP is enabled for the adapter * * \param[out] DhcpServer * Returns DHCP server IP address (255.255.255.255 if no * server reached yet), in network byte order * * \param[out] LeaseObtained * Returns time at which the lease was obtained * * \param[out] LeaseExpires * Returns time at which the lease will expire * * \return non-zero on success * * \remarks This is a ReactOS-only routine */ DWORD APIENTRY DhcpRosGetAdapterInfo(DWORD AdapterIndex, PBOOL DhcpEnabled, PDWORD DhcpServer, time_t* LeaseObtained, time_t* LeaseExpires) { COMM_DHCP_REQ Req; COMM_DHCP_REPLY Reply; DWORD BytesRead; BOOL Result; ASSERT(PipeHandle != INVALID_HANDLE_VALUE); Req.Type = DhcpReqGetAdapterInfo; Req.AdapterIndex = AdapterIndex; Result = TransactNamedPipe(PipeHandle, &Req, sizeof(Req), &Reply, sizeof(Reply), &BytesRead, NULL); if (Result && Reply.Reply != 0) *DhcpEnabled = Reply.GetAdapterInfo.DhcpEnabled; else *DhcpEnabled = FALSE; if (*DhcpEnabled) { *DhcpServer = Reply.GetAdapterInfo.DhcpServer; *LeaseObtained = Reply.GetAdapterInfo.LeaseObtained; *LeaseExpires = Reply.GetAdapterInfo.LeaseExpires; } else { *DhcpServer = INADDR_NONE; *LeaseObtained = 0; *LeaseExpires = 0; } return Reply.Reply; } static VOID UpdateServiceStatus(DWORD dwState) { ServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; ServiceStatus.dwCurrentState = dwState; if (dwState == SERVICE_RUNNING) ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP; else ServiceStatus.dwControlsAccepted = 0; ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwServiceSpecificExitCode = 0; ServiceStatus.dwCheckPoint = 0; if (dwState == SERVICE_START_PENDING || dwState == SERVICE_STOP_PENDING) ServiceStatus.dwWaitHint = 1000; else ServiceStatus.dwWaitHint = 0; SetServiceStatus(ServiceStatusHandle, &ServiceStatus); } static DWORD WINAPI ServiceControlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext) { switch (dwControl) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: UpdateServiceStatus(SERVICE_STOP_PENDING); if (hStopEvent != NULL) SetEvent(hStopEvent); return ERROR_SUCCESS; case SERVICE_CONTROL_INTERROGATE: SetServiceStatus(ServiceStatusHandle, &ServiceStatus); return ERROR_SUCCESS; default: return ERROR_CALL_NOT_IMPLEMENTED; } } VOID WINAPI ServiceMain(DWORD argc, LPWSTR* argv) { HANDLE hPipeThread = INVALID_HANDLE_VALUE; HANDLE hDiscoveryThread = INVALID_HANDLE_VALUE; DWORD ret; ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName, ServiceControlHandler, NULL); if (!ServiceStatusHandle) { DPRINT1("DHCPCSVC: Unable to register service control handler (%lx)\n", GetLastError()); return; } UpdateServiceStatus(SERVICE_START_PENDING); /* Create the stop event */ hStopEvent = CreateEventW(NULL, TRUE, FALSE, NULL); if (hStopEvent == NULL) { UpdateServiceStatus(SERVICE_STOPPED); return; } hAdapterStateChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (hAdapterStateChangedEvent == NULL) { CloseHandle(hStopEvent); UpdateServiceStatus(SERVICE_STOPPED); return; } UpdateServiceStatus(SERVICE_START_PENDING); if (!init_client()) { DbgPrint("DHCPCSVC: init_client() failed!\n"); CloseHandle(hAdapterStateChangedEvent); CloseHandle(hStopEvent); UpdateServiceStatus(SERVICE_STOPPED); return; } UpdateServiceStatus(SERVICE_START_PENDING); hPipeThread = PipeInit(hStopEvent); if (hPipeThread == INVALID_HANDLE_VALUE) { DbgPrint("DHCPCSVC: PipeInit() failed!\n"); stop_client(); CloseHandle(hAdapterStateChangedEvent); CloseHandle(hStopEvent); UpdateServiceStatus(SERVICE_STOPPED); return; } hDiscoveryThread = StartAdapterDiscovery(hStopEvent); if (hDiscoveryThread == INVALID_HANDLE_VALUE) { DbgPrint("DHCPCSVC: StartAdapterDiscovery() failed!\n"); stop_client(); CloseHandle(hAdapterStateChangedEvent); CloseHandle(hStopEvent); UpdateServiceStatus(SERVICE_STOPPED); return; } DH_DbgPrint(MID_TRACE,("DHCP Service Started\n")); UpdateServiceStatus(SERVICE_RUNNING); DH_DbgPrint(MID_TRACE,("Going into dispatch()\n")); DH_DbgPrint(MID_TRACE,("DHCPCSVC: DHCP service is starting up\n")); dispatch(hStopEvent); DH_DbgPrint(MID_TRACE,("DHCPCSVC: DHCP service is shutting down\n")); stop_client(); DPRINT("Wait for pipe thread to close! %p\n", hPipeThread); if (hPipeThread != INVALID_HANDLE_VALUE) { DPRINT("Waiting for pipe thread\n"); ret = WaitForSingleObject(hPipeThread, 5000); DPRINT("Done %lx\n", ret); } DPRINT("Wait for discovery thread to close! %p\n", hDiscoveryThread); if (hDiscoveryThread != INVALID_HANDLE_VALUE) { DPRINT("Waiting for discovery thread\n"); ret = WaitForSingleObject(hDiscoveryThread, 5000); DPRINT("Done %lx\n", ret); } DPRINT("Closing events!\n"); CloseHandle(hAdapterStateChangedEvent); CloseHandle(hStopEvent); if (DhcpSocket != INVALID_SOCKET) closesocket(DhcpSocket); CloseHandle(hDiscoveryThread); CloseHandle(hPipeThread); DPRINT("Done!\n"); UpdateServiceStatus(SERVICE_STOPPED); } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hinstDLL); break; case DLL_PROCESS_DETACH: break; } return TRUE; } /* EOF */