..back /*****************************************************************************/ /** Microsoft Windows **/ /** Copyright (c) 1997-2000 Microsoft Corporation. All rights reserved. **/ /*****************************************************************************/ /* dhcp.c DESCRIPTION: */ #include "dhcpp.h" #include "dhcp.h" #include "protocol.h" #include "netui.h" BOOL v_fWorkerThread; DhcpInfo *v_pWaitingList; DhcpInfo *v_pEstablishedList; DhcpInfo *v_pCurrent; DhcpInfo *v_pDelete; DEFINE_LOCK_STRUCTURE(v_GlobalListLock) #define DEFAULT_MAX_RETRIES 2 #define DEFAULT_RETRY_DIALOGUE 2 #define DEFAULT_INIT_DELAY 10000 // 10 secs // local externs extern void ProcessT1(DhcpInfo *pDhcp); extern void ProcessT2(DhcpInfo *pDhcp); void mul64_32_64(const FILETIME *lpnum1, DWORD num2, LPFILETIME lpres) { __int64 num1; num1 = (__int64)lpnum1->dwLowDateTime * (__int64)num2; num1 += ((__int64)lpnum1->dwHighDateTime * (__int64)num2)<<32; lpres->dwHighDateTime = (DWORD)(num1>>32); lpres->dwLowDateTime = (DWORD)(num1&0xffffffff); } void add64_32_64(const FILETIME *lpnum1, DWORD num2, LPFILETIME lpres) { DWORD bottom = lpnum1->dwLowDateTime + num2; lpres->dwHighDateTime = lpnum1->dwHighDateTime + (bottom < lpnum1->dwLowDateTime ? 1 : 0); lpres->dwLowDateTime = bottom; } #ifdef THUMB #pragma optimize("",off) #endif void add64_64_64(const FILETIME *lpnum1, LPFILETIME lpnum2, LPFILETIME lpres) { __int64 num1, num2; num1 = (((__int64)lpnum1->dwHighDateTime)<<32)+(__int64)lpnum1->dwLowDateTime; num2 = (((__int64)lpnum2->dwHighDateTime)<<32)+(__int64)lpnum2->dwLowDateTime; num1 += num2; lpres->dwHighDateTime = (DWORD)(num1>>32); lpres->dwLowDateTime = (DWORD)(num1&0xffffffff); } void sub64_64_64(const FILETIME *lpnum1, LPFILETIME lpnum2, LPFILETIME lpres) { __int64 num1, num2; num1 = (((__int64)lpnum1->dwHighDateTime)<<32)+(__int64)lpnum1->dwLowDateTime; num2 = (((__int64)lpnum2->dwHighDateTime)<<32)+(__int64)lpnum2->dwLowDateTime; num1 -= num2; lpres->dwHighDateTime = (DWORD)(num1>>32); lpres->dwLowDateTime = (DWORD)(num1&0xffffffff); } #ifdef THUMB #pragma optimize("",on) #endif // Unsigned divide // Divides a 64 bit number by a *31* bit number. Doesn't work for 32 bit divisors! void div64_32_64(const FILETIME *lpdividend, DWORD divisor, LPFILETIME lpresult) { DWORD bitmask; DWORD top; FILETIME wholetop = *lpdividend; top = 0; lpresult->dwHighDateTime = 0; for (bitmask = 0x80000000; bitmask; bitmask >>= 1) { top = (top<<1) + ((wholetop.dwHighDateTime&bitmask) ? 1 : 0); if (top >= divisor) { top -= divisor; lpresult->dwHighDateTime |= bitmask; } } lpresult->dwLowDateTime = 0; for (bitmask = 0x80000000; bitmask; bitmask >>= 1) { top = (top<<1) + ((wholetop.dwLowDateTime&bitmask) ? 1 : 0); if (top >= divisor) { top -= divisor; lpresult->dwLowDateTime |= bitmask; } } } // Len, SubnetMask(1), DomainName(15), Router(3), NB Name Server(44), // NB Node Type(46), NBT Scope (47), DomainServer(6) unsigned char v_aDftReqOptions[] = {7, 0x01, 0x03, 0x06, 0x0f, 0x2c, 0x2e, 0x2f, 0x0}; unsigned int v_cXid; int v_fXidInit; unsigned int GetXid(char *pMacAddr) { unsigned int i; if (! v_fXidInit) { memcpy(&i, pMacAddr + 2, 4); v_cXid ^= i; v_fXidInit++; } // CTEGetLock(&v_MiscLock, 0); if (i = v_cXid++) ; else // if it is 0, we increment again! i = v_cXid++; // CTEFreeLock(&v_MiscLock, 0); return i; } // GetXid() DhcpInfo *NewDhcpInfo(int cName) { DhcpInfo *pDhcp; pDhcp = LocalAlloc(LPTR, sizeof(*pDhcp) + cName); if (NULL != pDhcp) { pDhcp->ARPEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // manual reset if (NULL == pDhcp->ARPEvent) { DEBUGMSG(ZONE_WARN, (L"DHCP:NewDhcpInfo - CreateEvent failed!\n")); LocalFree(pDhcp); return NULL; } CTEInitLock(&pDhcp->Lock); // technically speaking should be net_long(INADDR_BROADCAST); pDhcp->DhcpServer = INADDR_BROADCAST; pDhcp->Flags = AUTO_IP_ENABLED_FL; pDhcp->AutoInterval = DHPC_IPAUTOCONFIG_DEFAULT_INTERVAL; pDhcp->AutoMask = DHCP_IPAUTOCONFIGURATION_DEFAULT_MASK; pDhcp->AutoSubnet = DHCP_IPAUTOCONFIGURATION_DEFAULT_SUBNET; } DEBUGMSG(ZONE_WARN, (TEXT("*NewDhcpInfo: %X\n"), pDhcp)); return pDhcp; } // NewDhcpInfo() void FreeDhcpInfo(DhcpInfo *pDhcp) { DEBUGMSG(ZONE_WARN, (TEXT("*FreeDhcpInfo: %X\n"), pDhcp)); CTEStopFTimer(&pDhcp->Timer); CTEDeleteLock(&pDhcp->Lock); if (pDhcp->pSendOptions) { LocalFree(pDhcp->pSendOptions); } if (pDhcp->ARPEvent) { CloseHandle(pDhcp->ARPEvent); } LocalFree(pDhcp); } // FreeDhcpInfo() // assumes pDhcp->Lock is NOT held // it gets the v_GlobalListLock, tries to find a double-ptr to the dhcp // and gets its lock // always returns with v_GlobalListLock held DhcpInfo **_FindDhcp(DhcpInfo *pDhcp, PTSTR pName) { DhcpInfo **ppTemp; CTEGetLock(&v_GlobalListLock, 0); ppTemp = &v_pEstablishedList; for ( ; *ppTemp; ppTemp = &(*ppTemp)->pNext) { if (pDhcp) { if (*ppTemp == pDhcp) break; } else if (0 == _tcscmp((*ppTemp)->Name, pName)) break; } // for() if (*ppTemp) CTEGetLock(&(*ppTemp)->Lock, 0); return ppTemp; } // _FindDhcp() BOOL StringToAddr(TCHAR *AddressString, DWORD *AddressValue) { TCHAR *pStr = AddressString; PUCHAR AddressPtr = (PUCHAR)AddressValue; int i; int Value; // Parse the four pieces of the address. for (i=0; *pStr && (i < 4); i++) { Value = 0; while (*pStr && TEXT('.') != *pStr) { if ((*pStr < TEXT('0')) || (*pStr > TEXT('9'))) { DEBUGMSG (ZONE_INIT, (TEXT("Unable to convert %s to address\r\n"), AddressString)); return FALSE; } Value *= 10; Value += *pStr - TEXT('0'); pStr++; } if (Value > 255) { DEBUGMSG (ZONE_INIT, (TEXT("Unable to convert %s to address\r\n"), AddressString)); return FALSE; } AddressPtr[i] = Value; if (TEXT('.') == *pStr) { pStr++; } } // Did we get all of the pieces? if (i != 4) { DEBUGMSG (ZONE_INIT, (TEXT("Unable to convert %s to address\r\n"), AddressString)); return FALSE; } DEBUGMSG (ZONE_INIT, (TEXT("Converted %s to address %X\r\n"), AddressString, *AddressValue)); return TRUE; } // StringToAddr() LPTSTR AddrToString(DWORD Addr, TCHAR *pString) { TCHAR Buffer[16], *p; int i; unsigned char *aAddr; DEBUGMSG(ZONE_WARN, (TEXT("+AddrToString: %X\r\n"), Addr)); p = Buffer; Addr = net_long(Addr); // put it in the desired format aAddr = (unsigned char *)&Addr; for (i = 0; i < 4; i++) { do { *p++ = aAddr[i] % 10 + TEXT('0'); } while (aAddr[i] /= 10); *p++ = TEXT('.'); } *(--p) = '\0'; // get rid of last '.' & end str for (i = 0; i <= 16 && p > Buffer; i++) { pString[i] = *(--p); } pString[i] = TEXT('\0'); DEBUGMSG(ZONE_WARN, (TEXT("-AddrToString: %s\r\n"), pString)); return pString; } // AddrToString() // our list is typically < 10 elts so this n^2 algo shld work void InsSort(int cBuf, uchar *pBuf) { uchar c, *p, *pBig, *pEnd = pBuf + cBuf; while ((pBig = pBuf) < pEnd) { for (p = pBuf; p < pEnd; p++) { if (*p > *pBig) pBig = p; } if (pBig < --pEnd) { c = *pBig; *pBig = *pEnd; *pEnd = c; } } } // InsSort // returns 0, if not valid # int Convert(TCHAR *szName, DWORD cName, uchar *pc) { uchar c = 0; for ( ; cName-- > 0 && *szName != TEXT('\0'); szName++) { if (*szName < TEXT('0') || *szName > TEXT('9')) return 0; c *= 10; c += *szName - TEXT('0'); } *pc = c; return 1; } STATUS GetReqOptions(HKEY hRoot, DhcpInfo *pDhcp) { HKEY hKey; LONG hRes; TCHAR szName[4]; DWORD i, j, cName, cBuf, Type; uchar *p, aBuf[OPTIONS_LEN], aPrevReqOptions[MAX_DHCP_REQ_OPTIONS+1]; pDhcp->Flags &= ~(OPTION_CHANGE_FL | USER_OPTIONS_FL); p = aBuf + 1; hRes = RegOpenKeyEx(hRoot, TEXT("DhcpOptions"), 0, 0, &hKey); if (ERROR_SUCCESS == hRes) { cName = sizeof(szName); hRes = RegQueryValueEx(hKey, NULL, NULL, NULL, NULL, &cName); if (ERROR_SUCCESS == hRes && cName) { pDhcp->Flags |= USER_OPTIONS_FL; // RegDeleteValue(hKey, NULL); i = 0; while (i < MAX_DHCP_REQ_OPTIONS) { cName = sizeof(szName)/sizeof(szName[0]); hRes = RegEnumValue(hKey, i++, szName, &cName, NULL, NULL, NULL, NULL); if (ERROR_SUCCESS == hRes) { if (Convert(szName, 4, p)) p++; } else break; } // while() aBuf[0] = (uchar)(p - aBuf - 1); InsSort(aBuf[0], &aBuf[1]); memcpy(pDhcp->ReqOptions, aBuf, aBuf[0] + 1); } else { memcpy(pDhcp->ReqOptions, v_aDftReqOptions, v_aDftReqOptions[0] + 1); } RegCloseKey (hKey); } else { memcpy(pDhcp->ReqOptions, v_aDftReqOptions, v_aDftReqOptions[0] + 1); } // RFC 2131 requires that if a client requests parameters in a DISCOVER, the // list must be included in subsequent REQUEST messages. So, if our option // list changes, set a flag which will drop us back to INIT state. cBuf = sizeof(aPrevReqOptions); if (GetRegBinaryValue(hRoot,TEXT("PrevReqOptions"),aPrevReqOptions,&cBuf)) { ASSERT(cBuf == (DWORD)(aPrevReqOptions[0] + 1)); if (memcmp(aPrevReqOptions,pDhcp->ReqOptions,cBuf)) { DEBUGMSG(ZONE_WARN,(TEXT("\tGetReqOptions, detected ReqOptions change\r\n"))); pDhcp->Flags |= OPTION_CHANGE_FL; } } hRes = RegOpenKeyEx(hRoot, TEXT("DhcpSendOptions"), 0, 0, &hKey); if (ERROR_SUCCESS == hRes) { cName = sizeof(szName); hRes = RegQueryValueEx(hKey, NULL, NULL, NULL, NULL, &cName); if (ERROR_SUCCESS == hRes && cName) { pDhcp->Flags |= SEND_OPTIONS_FL; // RegDeleteValue(hKey, NULL); i = j = 0; while (j < OPTIONS_LEN - MAX_DHCP_REQ_OPTIONS - 4 - 3 - 9 - 6) { cName = sizeof(szName)/sizeof(szName[0]); cBuf = OPTIONS_LEN - j - 22; hRes = RegEnumValue(hKey, i++, szName, &cName, NULL, &Type, &aBuf[j], &cBuf); if (ERROR_SUCCESS == hRes && REG_BINARY == Type) { j += cBuf; } else if (ERROR_NO_MORE_ITEMS == hRes) break; } // while() if (j > 0) { if (p = LocalAlloc(LPTR, j)) { if (pDhcp->pSendOptions) LocalFree(pDhcp->pSendOptions); pDhcp->pSendOptions = p; memcpy(p, aBuf, j); pDhcp->cSendOptions = j; } } else { ASSERT(j == 0); // note cSendOptions only valid when pSendOptions != NULL LocalFree(pDhcp->pSendOptions); pDhcp->pSendOptions = NULL; } } RegCloseKey (hKey); } return ERROR_SUCCESS; } // GetReqOptions // Read IP address strings from the registry and convert them to DWORDs BOOL GetRegIPAddr(HKEY hKey, LPTSTR lpVal, LPDWORD lpdwIPAddrs, DWORD dwNumIPAddrs) { TCHAR Buffer[MAX_REG_STR]; LPTSTR lpBuf = Buffer; Buffer[0] = TEXT('\0'); // GetRegMultiSZValue works on REG_SZ strings as well as REG_MULTI_SZ if (!GetRegMultiSZValue(hKey, lpVal, lpBuf, sizeof(Buffer))) { return FALSE; } while (dwNumIPAddrs) { if (TEXT('0') == *lpBuf) { *lpdwIPAddrs = 0; } else { StringToAddr(lpBuf, lpdwIPAddrs); lpBuf += _tcslen(lpBuf) + 1; } lpdwIPAddrs++; dwNumIPAddrs--; } return TRUE; } // GetRegIPAddr HKEY OpenDHCPKey( DhcpInfo * pDhcp ) { TCHAR Buffer[MAX_REG_STR]; HKEY hKey; LONG hRes; _tcscpy (Buffer, COMM_REG_KEY); _tcscat (Buffer, pDhcp->Name); _tcscat (Buffer, TEXT("\\Parms\\TcpIp")); hRes = RegOpenKeyEx (HKEY_LOCAL_MACHINE, Buffer, 0, 0, &hKey); if (hRes) { return NULL; } return hKey; } STATUS GetDhcpConfig(DhcpInfo *pDhcp) { HKEY hKey; BOOL fStatus; uint fDhcpEnabled; int i; DEBUGMSG (ZONE_INIT, (TEXT("+GetDhcpConfig:\r\n"))); // Open the Registry Key. hKey = OpenDHCPKey(pDhcp); if (hKey) { fStatus = GetRegDWORDValue(hKey, TEXT("EnableDHCP"), &fDhcpEnabled); if (fStatus && fDhcpEnabled) pDhcp->Flags |= DHCP_ENABLED_FL; fStatus = GetRegIPAddr(hKey, TEXT("DhcpIPAddress"), &pDhcp->IPAddr, 1); if (fStatus && pDhcp->IPAddr) { fStatus = GetRegIPAddr(hKey, TEXT("DhcpSubnetMask"), &pDhcp->SubnetMask, 1); if (fStatus && pDhcp->SubnetMask) { // Get the DhcpServer GetRegIPAddr(hKey, TEXT("DhcpServer"), &pDhcp->DhcpServer, 1); // Get the DhcpDftGateway GetRegIPAddr(hKey, TEXT("DhcpDefaultGateway"), &pDhcp->Gateway, 1); GetRegIPAddr(hKey, TEXT("DhcpDNS"), pDhcp->DNS, 2); GetRegIPAddr(hKey, TEXT("DhcpWINS"), pDhcp->WinsServer, 2); // Get Lease Info GetRegDWORDValue(hKey, TEXT("LeaseObtainedLow"), &pDhcp->LeaseObtained.dwLowDateTime); GetRegDWORDValue(hKey, TEXT("LeaseObtainedHigh"), &pDhcp->LeaseObtained.dwHighDateTime); GetRegDWORDValue(hKey, TEXT("Lease"), &pDhcp->Lease); // Get T1 & T2 GetRegDWORDValue(hKey, TEXT("T1"), &pDhcp->T1); GetRegDWORDValue(hKey, TEXT("T2"), &pDhcp->T2); } } pDhcp->cMaxRetry = DEFAULT_MAX_RETRIES; pDhcp->InitDelay = DEFAULT_INIT_DELAY; pDhcp->cRetryDialogue = DEFAULT_RETRY_DIALOGUE; // Get MaxRetries, InitDelayInterval GetRegDWORDValue(hKey, TEXT("DhcpMaxRetry"), &pDhcp->cMaxRetry); GetRegDWORDValue(hKey, TEXT("DhcpInitDelayInterval"), &pDhcp->InitDelay); GetRegDWORDValue(hKey, TEXT("DhcpRetryDialogue"), &pDhcp->cRetryDialogue); i = 0; GetRegDWORDValue(hKey, TEXT("DhcpNoMacCompare"), &i); if (i) pDhcp->Flags |= NO_MAC_COMPARE_FL; else pDhcp->Flags &= ~NO_MAC_COMPARE_FL; GetReqOptions(hKey, pDhcp); // Get auto IP config state if (GetRegDWORDValue(hKey, TEXT("AutoCfg"), (LPDWORD)&i)) { // auto IP config is enabled by default if (!i) { pDhcp->Flags &= ~AUTO_IP_ENABLED_FL; // user wants it disabled } } if (pDhcp->Flags & AUTO_IP_ENABLED_FL) { GetRegDWORDValue(hKey, TEXT("AutoSeed"), &pDhcp->AutoSeed); GetRegIPAddr(hKey, TEXT("AutoIP"), &pDhcp->AutoIPAddr, 1); GetRegIPAddr(hKey, TEXT("AutoSubnet"), &pDhcp->AutoSubnet, 1); GetRegIPAddr(hKey, TEXT("AutoMask"), &pDhcp->AutoMask, 1); GetRegDWORDValue(hKey, TEXT("AutoInterval"), &pDhcp->AutoInterval); } RegCloseKey(hKey); } // if (hKey) DEBUGMSG (ZONE_INIT, (TEXT("-GetDhcpConfig:\r\n"))); return DHCP_SUCCESS; } // GetDhcpConfig() STATUS SetDhcpConfig(DhcpInfo *pDhcp) { TCHAR Buffer[MAX_REG_STR]; HKEY hKey; LONG hRes; BOOL fStatus; int i; DEBUGMSG (ZONE_INIT, (TEXT("+SetDhcpConfig:\r\n"))); // Open the Registry Key. hKey = OpenDHCPKey(pDhcp); if (hKey) { SetRegDWORDValue(hKey, TEXT("EnableDHCP"), (pDhcp->Flags & DHCP_ENABLED_FL) ? 1 : 0); AddrToString(pDhcp->IPAddr, Buffer); fStatus = SetRegSZValue(hKey, TEXT("DhcpIPAddress"), Buffer); DEBUGMSG (ZONE_WARN, (TEXT("\tSetDhcpConfig: set IPAddr %X\r\n"), pDhcp->IPAddr)); if (fStatus) { AddrToString(pDhcp->SubnetMask, Buffer); SetRegSZValue(hKey, TEXT("DhcpSubnetMask"), Buffer); AddrToString(pDhcp->DhcpServer, Buffer); SetRegSZValue(hKey, TEXT("DhcpServer"), Buffer); AddrToString(pDhcp->Gateway, Buffer); SetRegSZValue(hKey, TEXT("DhcpDefaultGateway"), Buffer); Buffer[0] = Buffer[1] = TEXT('\0'); i = 0; if (pDhcp->DNS[0]) { AddrToString(pDhcp->DNS[0], Buffer); i = _tcslen(Buffer) + 1; if (pDhcp->DNS[1]) { AddrToString(pDhcp->DNS[1], &Buffer[i]); i += _tcslen(&Buffer[i]) + 1; } Buffer[i] = TEXT('\0'); } // we want: dns1\0dns2\0\0 SetRegMultiSZValue(hKey, TEXT("DhcpDNS"), Buffer); Buffer[0] = Buffer[1] = TEXT('\0'); i = 0; if (pDhcp->WinsServer[0]) { AddrToString(pDhcp->WinsServer[0], Buffer); i = _tcslen(Buffer) + 1; if (pDhcp->WinsServer[1]) { AddrToString(pDhcp->WinsServer[1], &Buffer[i]); i += _tcslen(&Buffer[i]) + 1; } Buffer[i] = TEXT('\0'); } // we want: wins1\0wins2\0\0 SetRegMultiSZValue(hKey, TEXT("DhcpWINS"), Buffer); // Set Lease Times SetRegDWORDValue(hKey, TEXT("LeaseObtainedLow"), pDhcp->LeaseObtained.dwLowDateTime); SetRegDWORDValue(hKey, TEXT("LeaseObtainedHigh"), pDhcp->LeaseObtained.dwHighDateTime); DEBUGMSG (ZONE_WARN, (TEXT("\tSetDhcpConfig: set LeaseObtained %x %x\r\n"), pDhcp->LeaseObtained.dwHighDateTime, pDhcp->LeaseObtained.dwLowDateTime)); SetRegDWORDValue(hKey, TEXT("Lease"), pDhcp->Lease); // Set T1 & T2 SetRegDWORDValue(hKey, TEXT("T1"), pDhcp->T1); SetRegDWORDValue(hKey, TEXT("T2"), pDhcp->T2); DEBUGMSG (ZONE_WARN, (TEXT("\tSetDhcpConfig: T1 %x T2 %x Lease %x\r\n"), pDhcp->T1, pDhcp->T2, pDhcp->Lease)); // Store the list of params requested from server so we can tell // if it has changed after a reboot. SetRegBinaryValue(hKey,TEXT("PrevReqOptions"),pDhcp->ReqOptions,pDhcp->ReqOptions[0]+1); } // Save auto IP config state if (pDhcp->Flags & AUTO_IP_ENABLED_FL) { SetRegDWORDValue(hKey, TEXT("AutoSeed"), pDhcp->AutoSeed); AddrToString(pDhcp->AutoIPAddr, Buffer); SetRegSZValue(hKey, TEXT("AutoIP"), Buffer); AddrToString(pDhcp->AutoSubnet, Buffer); SetRegSZValue(hKey, TEXT("AutoSubnet"), Buffer); AddrToString(pDhcp->AutoMask, Buffer); SetRegSZValue(hKey, TEXT("AutoMask"), Buffer); SetRegDWORDValue(hKey, TEXT("AutoInterval"), pDhcp->AutoInterval); } else { SetRegDWORDValue(hKey, TEXT("AutoCfg"), 0); } RegCloseKey (hKey); } // if (hKey) if (pDhcp->aDomainName[0]) { _tcscpy (Buffer, COMM_REG_KEY); _tcscat (Buffer, TEXT("TcpIp\\Parms")); hRes = RegOpenKeyEx (HKEY_LOCAL_MACHINE, Buffer, 0, 0, &hKey); if (ERROR_SUCCESS == hRes) { if (-1 != mbstowcs(Buffer, &pDhcp->aDomainName[1], pDhcp->aDomainName[0])) { Buffer[pDhcp->aDomainName[0]]= (L'\0'); SetRegSZValue(hKey, TEXT("DNSDomain"), Buffer); } RegCloseKey(hKey); } } DEBUGMSG (ZONE_INIT, (TEXT("-SetDhcpConfig:\r\n"))); return DHCP_SUCCESS; } // SetDhcpConfig() // assumes caller owns pDhcp->Lock void TakeNetDown(DhcpInfo *pDhcp, BOOL fDiscardIPAddr, BOOL fRemoveAfdInterface) { HKEY hKey; RETAILMSG(1, (TEXT("*TakeNetDown: pDhcp 0x%x IP %X!\r\n"), pDhcp, pDhcp->IPAddr)); pDhcp->ARPResult = ERROR_UNEXP_NET_ERR; SetEvent(pDhcp->ARPEvent); // wake up any waiting threads (*pfnIPSetNTEAddr)((ushort)pDhcp->NteContext, NULL, 0, 0, 0); if (fRemoveAfdInterface) { CallAfd(AddInterface)(pDhcp->Name, pDhcp->Nte, pDhcp->NteContext, ADD_INTF_DELETE_FL, pDhcp->IPAddr, pDhcp->SubnetMask, 0, NULL, 0, NULL); } if (fDiscardIPAddr) { pDhcp->IPAddr = 0; // Delete the IPAddr. hKey = OpenDHCPKey(pDhcp); if (hKey) { RegDeleteValue(hKey, TEXT("DhcpIPAddress")); RegCloseKey (hKey); } } } // TakeNetDown() // assumes caller has v_GlobalListLock void PutInWorkerQ(DhcpInfo *pDhcp) { HANDLE hWorkerThrd; DWORD ThreadId; pDhcp->pNext = v_pWaitingList; v_pWaitingList = pDhcp; // if there is already a worker thread we're done if (! v_fWorkerThread) { v_fWorkerThread = TRUE; hWorkerThrd = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)DhcpWorkerThread, NULL, 0, &ThreadId); if (hWorkerThrd) { CloseHandle(hWorkerThrd); } else { RETAILMSG(1, (TEXT("!RequestDHCPAddr: can't create worker thread\r\n"))); } } } // PutInWorkerQ // // Close the Dhcp interface's socket if open and set it to NULL // (Afd doesn't check the socket parameter, so we have to) // void CloseDhcpSocket( DhcpInfo *pDhcp ) { if (pDhcp->Socket) { CallSock(Close) (pDhcp->Socket); pDhcp->Socket = NULL; } } // called when our lease has expired! void ProcessExpire(DhcpInfo *pDhcp) { DhcpInfo **ppDhcp; DEBUGMSG(ZONE_TIMER|ZONE_WARN, (TEXT("+ProcessExpire: pDhcp 0x%X\r\n"), pDhcp)); if (*(ppDhcp = _FindDhcp(pDhcp, NULL))) { RETAILMSG(1, (TEXT("!Lease Time Expired, bringing net down %x\r\n"), pDhcp)); *ppDhcp = pDhcp->pNext; // take the interface down! pDhcp->SFlags |= DHCPSTATE_LEASE_EXPIRE; TakeNetDown(pDhcp, TRUE, TRUE); ClearDHCPNTE(pDhcp); CloseDhcpSocket(pDhcp); PutInWorkerQ(pDhcp); CTEFreeLock(&v_GlobalListLock, 0); CTEFreeLock(&pDhcp->Lock, 0); } else CTEFreeLock(&v_GlobalListLock, 0); DEBUGMSG(ZONE_TIMER, (TEXT("-ProcessExpire: pDhcp 0x%X\r\n"), pDhcp)); } // ProcessExpire() void CalcMidwayTime(DhcpInfo *pDhcp, int End, CTEEventRtn Rtn1, CTEEventRtn Rtn2) { FILETIME CurTime, EndTime, TempTime; // calc Expire time, if > 1 min restart T1 timer EndTime.dwLowDateTime = End; EndTime.dwHighDateTime = 0; mul64_32_64(&EndTime, TEN_M, &EndTime); add64_64_64(&pDhcp->LeaseObtained, &EndTime, &EndTime); GetCurrentFT(&CurTime); if (CompareFileTime(&CurTime, &EndTime) >= 0) { DEBUGMSG(ZONE_TIMER, (TEXT("*CalcMidwayTime: late already! start 2nd timer %x %x\r\n"), EndTime.dwHighDateTime, EndTime.dwLowDateTime)); // start next timer CTEStartFTimer(&pDhcp->Timer, EndTime, (CTEEventRtn)Rtn2, pDhcp); } else { sub64_64_64(&EndTime, &CurTime, &TempTime); DEBUGMSG(ZONE_TIMER, (TEXT("*CalcMidwayTime: CurTime %x %x Endtime %x %x dt %x %x\r\n"), CurTime.dwHighDateTime, CurTime.dwLowDateTime, EndTime.dwHighDateTime, EndTime.dwLowDateTime, TempTime.dwHighDateTime, TempTime.dwLowDateTime)); // if more than 1 min remain, restart timer // otherwise start the next timer if (TempTime.dwHighDateTime > 0 || (TempTime.dwHighDateTime == 0 && TempTime.dwLowDateTime >= (60 * TEN_M))) { div64_32_64(&TempTime, 2, &TempTime); add64_64_64(&CurTime, &TempTime, &TempTime); DEBUGMSG(ZONE_TIMER, (TEXT("*CalcMidwayTime: starting timer for %x %x\r\n"), TempTime.dwHighDateTime, TempTime.dwLowDateTime)); // restart the timer CTEStartFTimer(&pDhcp->Timer, TempTime, (CTEEventRtn)Rtn1, pDhcp); } else { DEBUGMSG(ZONE_TIMER, (TEXT("*CalcMidwayTime: starting 2nd timer for %x %x\r\n"), EndTime.dwHighDateTime, EndTime.dwLowDateTime)); // start next timer CTEStartFTimer(&pDhcp->Timer, EndTime, (CTEEventRtn)Rtn2, pDhcp); } } } // CalcMidwayTime() void CalcT1Time(DhcpInfo *pDhcp) { FILETIME Ft; Ft.dwLowDateTime = pDhcp->T1; Ft.dwHighDateTime = 0; mul64_32_64(&Ft, TEN_M, &Ft); add64_64_64(&pDhcp->LeaseObtained, &Ft, &Ft); // Start T1 timer DEBUGMSG(ZONE_TIMER, (TEXT("*CalcT1Time: init LO %x %x , T1 %x %x\r\n"), pDhcp->LeaseObtained.dwHighDateTime, pDhcp->LeaseObtained.dwLowDateTime, Ft.dwHighDateTime, Ft.dwLowDateTime)); CTEStartFTimer(&pDhcp->Timer, Ft, (CTEEventRtn)ProcessT1, pDhcp); } // CalcT1Time() STATUS DhcpInitSock(DhcpInfo *pInfo, int SrcIP) { SOCKADDR_IN SockAddr; STATUS Status = DHCP_SUCCESS; LPSOCK_INFO Sock; DEBUGMSG(ZONE_INIT, (TEXT("+DhcpInitSock: pInfo 0x%X\r\n"), pInfo)); memset ((char *)&SockAddr, 0, sizeof(SockAddr)); SockAddr.sin_family = AF_INET; SockAddr.sin_port = net_short(DHCP_CLIENT_PORT); SockAddr.sin_addr.S_un.S_addr = SrcIP; // net_long(0); // set flag that this is an internal socket Sock = (LPSOCK_INFO) CallAfd(Socket) (0x80000000 | AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (Sock) { int i = 1; if (SOCKET_ERROR == CallSock(SetOption)(Sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i), NULL) || SOCKET_ERROR == CallSock(SetOption)(Sock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i), NULL) || SOCKET_ERROR == CallSock(Bind)(Sock, (SOCKADDR *)&SockAddr, sizeof(SockAddr), (struct CRITICAL_SECTION *)0xffffffff)) { Status = GetLastError(); DEBUGMSG(ZONE_WARN | ZONE_ERROR, (TEXT("\t!DhcpInitSock: failure %d\r\n"), Status)); CallSock(Close) (Sock); } } else // if (Sock) Status = GetLastError(); if (DHCP_SUCCESS == Status) pInfo->Socket = Sock; DEBUGMSG(ZONE_INIT, (TEXT("-DhcpInitSock: pInfo 0x%X/0x%X Ret: %d\r\n"), pInfo, pInfo->Socket, Status)); return Status; } // InitSocket() // // Function to call ARP's SetDHCPNTE - caller must have pDhcp->Lock // BOOL SetDHCPNTE( DhcpInfo * pDhcp ) { BOOL RetStatus = FALSE; if (0 == (pDhcp->SFlags & DHCPSTATE_DHCPNTE_SET)) { RetStatus = (*pfnSetDHCPNTE)(pDhcp->NteContext, NULL, NULL, NULL); if (RetStatus) pDhcp->SFlags |= DHCPSTATE_DHCPNTE_SET; } return RetStatus; } BOOL ClearDHCPNTE( DhcpInfo * pDhcp ) { BOOL RetStatus = FALSE; if (pDhcp->SFlags & DHCPSTATE_DHCPNTE_SET) { // even if this fails we're going to assume that we no longer have // the dhcpnte set pDhcp->SFlags &= ~DHCPSTATE_DHCPNTE_SET; RetStatus = (*pfnSetDHCPNTE)(0x1fff, NULL, NULL, NULL); } return RetStatus; } void ProcessT2(DhcpInfo *pDhcp) { STATUS Status = DHCP_SUCCESS; DhcpPkt Pkt; int cPkt; FILETIME CurTime; int fStatus; DhcpInfo **ppDhcp; DEBUGMSG(ZONE_TIMER, (TEXT("+ProcessT2: pDhcp 0x%X\r\n"), pDhcp)); if (*_FindDhcp(pDhcp, NULL)) { CTEFreeLock(&v_GlobalListLock, 0); pDhcp->SFlags |= DHCPSTATE_T2_EXPIRE; if (DHCP_SUCCESS == (Status = DhcpInitSock(pDhcp, pDhcp->IPAddr))) { BuildDhcpPkt(pDhcp, &Pkt, DHCPREQUEST, (NEW_PKT_FL), pDhcp->ReqOptions, &cPkt); fStatus = SetDHCPNTE(pDhcp); GetCurrentFT(&CurTime); DEBUGMSG(ZONE_TIMER, (TEXT("\tProcess T2: CurTime: %x %x\r\n"), CurTime.dwHighDateTime, CurTime.dwLowDateTime)); if (fStatus) Status = SendDhcpPkt(pDhcp, &Pkt, cPkt, DHCPACK, (ONCE_FL | BCAST_FL)); else Status = DHCP_NOCARD; if (Status == DHCP_SUCCESS) { pDhcp->SFlags &= ~(DHCPSTATE_T2_EXPIRE | DHCPSTATE_T1_EXPIRE); memcpy(&pDhcp->LeaseObtained, &CurTime, sizeof(CurTime)); SetDhcpConfig(pDhcp); CalcT1Time(pDhcp); } else if (Status == DHCP_NACK) { DEBUGMSG(ZONE_WARN, (TEXT("\t!ProcessT2: Take Net Down\r\n"))); TakeNetDown(pDhcp, TRUE, TRUE); ClearDHCPNTE(pDhcp); pDhcp->SFlags &= ~(DHCPSTATE_T2_EXPIRE | DHCPSTATE_T1_EXPIRE); CloseDhcpSocket(pDhcp); CTEFreeLock(&pDhcp->Lock, 0); if (*(ppDhcp = _FindDhcp(pDhcp, NULL))) { *ppDhcp = pDhcp->pNext; // CallNetMsgBox(NULL, NMB_FL_EXCLAIM | NMB_FL_OK | NMB_FL_TOPMOST, // NETUI_GETNETSTR_LEASE_EXPIRED); PutInWorkerQ(pDhcp); CTEFreeLock(&pDhcp->Lock, 0); } CTEFreeLock(&v_GlobalListLock, 0); return; } else { CalcMidwayTime(pDhcp, pDhcp->Lease, (CTEEventRtn)ProcessT2, (CTEEventRtn)ProcessExpire); } if (fStatus) ClearDHCPNTE(pDhcp); CloseDhcpSocket(pDhcp); } else { // (DHCP_SUCCESS == DhcpInitSock()) DEBUGMSG(ZONE_WARN, (TEXT("\t!ProcessT2: DhcpInitSock failed %d!!\r\n"), Status)); CalcMidwayTime(pDhcp, pDhcp->Lease, (CTEEventRtn)ProcessT2, (CTEEventRtn)ProcessExpire); } CTEFreeLock(&pDhcp->Lock, 0); } else // if (*_FindDhcp()) CTEFreeLock(&v_GlobalListLock, 0); DEBUGMSG(ZONE_TIMER, (TEXT("-ProcessT2: pDhcp 0x%X\r\n"), pDhcp)); } // ProcessT2() void ProcessT1(DhcpInfo *pDhcp) { STATUS Status = DHCP_SUCCESS; DhcpPkt Pkt; int cPkt; FILETIME CurTime; int fStatus; DhcpInfo **ppDhcp; DEBUGMSG(ZONE_TIMER, (TEXT("+ProcessT1: pDhcp 0x%X\r\n"), pDhcp)); if (*_FindDhcp(pDhcp, NULL)) { CTEFreeLock(&v_GlobalListLock, 0); pDhcp->SFlags |= DHCPSTATE_T1_EXPIRE; if (DHCP_SUCCESS == (Status = DhcpInitSock(pDhcp, pDhcp->IPAddr))) { BuildDhcpPkt(pDhcp, &Pkt, DHCPREQUEST, (NEW_PKT_FL), pDhcp->ReqOptions, &cPkt); fStatus = SetDHCPNTE(pDhcp); GetCurrentFT(&CurTime); DEBUGMSG(ZONE_TIMER, (TEXT("\tProcess T1: CurTime: %x %x\r\n"), CurTime.dwHighDateTime, CurTime.dwLowDateTime)); if (fStatus) Status = SendDhcpPkt(pDhcp, &Pkt, cPkt, DHCPACK, ONCE_FL); else Status = DHCP_NOCARD; if (Status == DHCP_SUCCESS) { pDhcp->SFlags &= ~(DHCPSTATE_T1_EXPIRE); memcpy(&pDhcp->LeaseObtained, &CurTime, sizeof(CurTime)); SetDhcpConfig(pDhcp); CalcT1Time(pDhcp); } else if (Status == DHCP_NACK) { // Take Net Down !!! DEBUGMSG(ZONE_WARN, (TEXT("\t!ProcessT1: Take Net Down\r\n"))); TakeNetDown(pDhcp, TRUE, TRUE); ClearDHCPNTE(pDhcp); pDhcp->SFlags &= ~(DHCPSTATE_T1_EXPIRE); CloseDhcpSocket(pDhcp); CTEFreeLock(&pDhcp->Lock, 0); if (*(ppDhcp = _FindDhcp(pDhcp, NULL))) { *ppDhcp = pDhcp->pNext; // CallNetMsgBox(NULL, NMB_FL_EXCLAIM | NMB_FL_OK | NMB_FL_TOPMOST, // NETUI_GETNETSTR_LEASE_EXPIRED); PutInWorkerQ(pDhcp); CTEFreeLock(&pDhcp->Lock, 0); } CTEFreeLock(&v_GlobalListLock, 0); return; } else { CalcMidwayTime(pDhcp, pDhcp->T2, (CTEEventRtn)ProcessT1, (CTEEventRtn)ProcessT2); } if (fStatus) ClearDHCPNTE(pDhcp); CloseDhcpSocket(pDhcp); } else { // if (DHCP_SUCCESS == DhcpInitSock) DEBUGMSG(ZONE_WARN, (TEXT("\t!ProcessT1: DhcpInitSock failed %d!!\r\n"), Status)); CalcMidwayTime(pDhcp, pDhcp->T2, (CTEEventRtn)ProcessT1, (CTEEventRtn)ProcessT2); } CTEFreeLock(&pDhcp->Lock, 0); } else // if (FindDhcp()) CTEFreeLock(&v_GlobalListLock, 0); DEBUGMSG(ZONE_TIMER, (TEXT("-ProcessT1: pDhcp 0x%X\r\n"), pDhcp)); } // ProcessT1() #ifdef UNDER_CE // Handles by which to notify applications of changes to IP data structures. HANDLE g_hAddrChangeEvent; void NotifyXxxChange(HANDLE hEvent) // // Pulse the event to let applications know a change has occurred // { if (hEvent) { PulseEvent(hEvent); } } #endif //UNDER_CE // // PutNetUp - Cause TCP/IP to use DHCP negotiated IP address for this net. // The TCP/IP stack will call our ARPResult function if there is an IP address conflict. // ARPResult sets the ARPEvent to indicate it was called. // // Return: DHCP_* error code from comm\inc\dhcp.h // STATUS PutNetUp(DhcpInfo *pDhcp) { int i, j; pDhcp->ARPResult = ERROR_SUCCESS; // assume no IP address collision ResetEvent(pDhcp->ARPEvent); i = (*pfnIPSetNTEAddr)((ushort)pDhcp->NteContext, NULL, pDhcp->IPAddr, pDhcp->SubnetMask, pDhcp->Gateway); if (i == IP_PENDING) WaitForSingleObject(pDhcp->ARPEvent, ARP_RESPONSE_WAIT); else if (i != IP_SUCCESS) { DEBUGMSG(ZONE_WARN, (L"DHCP:PutNetUp - IPSetNTEAddr failed!\n")); return (i == IP_DUPLICATE_ADDRESS) ? DHCP_COLLISION : DHCP_FAILURE; } if (ERROR_SUCCESS == pDhcp->ARPResult) { // no IP address collision, proceed i = j = 0; if (pDhcp->DNS[0]) { i++; if (pDhcp->DNS[1]) { i++; } } if (pDhcp->WinsServer[0]) { j++; if (pDhcp->WinsServer[1]) { j++; } } CallAfd(AddInterface)(pDhcp->Name, pDhcp->Nte, pDhcp->NteContext, 0, pDhcp->IPAddr, pDhcp->SubnetMask, i, pDhcp->DNS, j, pDhcp->WinsServer); NotifyXxxChange(g_hAddrChangeEvent); return DHCP_SUCCESS; } else { DEBUGMSG(ZONE_WARN, (L"DHCP:PutNetUp - ARPResult == %d, assuming IP addr collision\n", pDhcp->ARPResult)); return DHCP_COLLISION; } } // PutNetUp() STATUS DhcpSendDown(DhcpInfo *pDhcp, DhcpPkt *pPkt, int cPkt, int DestIP); void DhcpDecline(DhcpInfo * pDhcp, DhcpPkt *pPkt) { int cPkt; BuildDhcpPkt(pDhcp, pPkt, DHCPDECLINE, RIP_PKT_FL|NEW_PKT_FL, NULL, &cPkt); DhcpSendDown(pDhcp, pPkt, cPkt, INADDR_BROADCAST); // AFD info not added at this point TakeNetDown(pDhcp, TRUE, FALSE); } BOOL CanUseCachedLease(DhcpInfo * pDhcp) { FILETIME BeginTime, EndTime; // we only try to use our old lease if we're not in T2 stage! EndTime.dwHighDateTime = 0; EndTime.dwLowDateTime = pDhcp->T2; mul64_32_64(&EndTime, TEN_M, &EndTime); add64_64_64(&pDhcp->LeaseObtained, &EndTime, &EndTime); GetCurrentFT(&BeginTime); if (CompareFileTime(&EndTime, &BeginTime) >= 0) { return TRUE; } return FALSE; } // CanUseCachedLease STATUS GetParams(DhcpInfo *pDhcp) { STATUS Status = DHCP_SUCCESS; DhcpPkt Pkt; int cPkt, fDiscover, Flags, fDone; FILETIME BeginTime; uint cRetry, cDelay; DEBUGMSG(ZONE_INIT, (TEXT("+GetParams: pDhcp 0x%X/0x%X\n"), pDhcp, pDhcp->Socket)); cRetry = fDone = 0; pDhcp->SFlags &= ~(DHCPSTATE_T1_EXPIRE | DHCPSTATE_T2_EXPIRE | DHCPSTATE_LEASE_EXPIRE | DHCPSTATE_SAW_DHCP_SRV); GetDhcpConfig(pDhcp); if (pDhcp->Flags & DHCP_ENABLED_FL) { // If the IP address is currently auto cfg and the user has requested "ipconfig /renew" // then stop the 5 minute discover timer and force a discover to happen if (pDhcp->SFlags & DHCPSTATE_AUTO_CFG_IP) { CTEStopFTimer(&pDhcp->Timer); pDhcp->SFlags &= ~DHCPSTATE_AUTO_CFG_IP; pDhcp->IPAddr = 0; // force a discover } for ( ; ! fDone && cRetry <= pDhcp->cMaxRetry; cRetry++) { cDelay = (GetTickCount() % pDhcp->InitDelay); Sleep(cDelay); if (SetDHCPNTE(pDhcp)) { Status = DHCP_SUCCESS; GetCurrentFT(&BeginTime); fDiscover = (!pDhcp->IPAddr) || (pDhcp->Flags & OPTION_CHANGE_FL); if (fDiscover) { // if no prev IP or lease exp. or option change pDhcp->IPAddr = 0; pDhcp->Flags &= ~OPTION_CHANGE_FL; BuildDhcpPkt(pDhcp, &Pkt, DHCPDISCOVER, (NEW_PKT_FL), pDhcp->ReqOptions, &cPkt); Status = SendDhcpPkt(pDhcp, &Pkt, cPkt, DHCPOFFER, BCAST_FL | DFT_LOOP_FL); } if (DHCP_SUCCESS == Status) { Flags = RIP_PKT_FL; // request IP addr must be filled in if (fDiscover) Flags |= SID_PKT_FL; else { Flags |= NEW_PKT_FL; } BuildDhcpPkt(pDhcp, &Pkt, DHCPREQUEST, Flags, pDhcp->ReqOptions, &cPkt); Status = SendDhcpPkt(pDhcp, &Pkt, cPkt, DHCPACK, BCAST_FL | DFT_LOOP_FL); } ClearDHCPNTE(pDhcp); if ((pDhcp->Flags & AUTO_IP_ENABLED_FL) && (!(pDhcp->SFlags & DHCPSTATE_SAW_DHCP_SRV))) { // No response from a DHCP server, so try AutoIP. DEBUGMSG(ZONE_AUTOIP, (TEXT("DHCP:GetParams - No response from DHCP server, trying AutoIP\n"))); Status = AutoIP(pDhcp); } if (DHCP_SUCCESS == Status) { memcpy(&pDhcp->LeaseObtained, &BeginTime, sizeof(BeginTime)); SetDhcpConfig(pDhcp); fDone = TRUE; // We need to PutNetUp() here only when we've negotiated a lease with a DHCP server. // If we didn't auto configure and didn't see a DHCP server, then AutoIP() was able to // ping the default gateway so it decided to use the cached lease already. if ((!(pDhcp->SFlags & DHCPSTATE_AUTO_CFG_IP)) && (pDhcp->SFlags & DHCPSTATE_SAW_DHCP_SRV)) { Status = PutNetUp(pDhcp); switch (Status) { case DHCP_SUCCESS: CalcT1Time(pDhcp); break; case DHCP_COLLISION: DhcpDecline(pDhcp, &Pkt); // fall through default: fDone = FALSE; break; } } } else if (DHCP_NACK == Status) { pDhcp->IPAddr = 0; } else if (!fDiscover) { // didn't get a NAK see if we can use our old lease if (pDhcp->IPAddr) { if (CanUseCachedLease(pDhcp)) { DEBUGMSG(ZONE_WARN, (TEXT("\tGetParams: using cached DHCP lease\r\n"))); CallNetMsgBox(NULL, NMB_FL_OK, NETUI_GETNETSTR_CACHED_LEASE); Status = PutNetUp(pDhcp); switch (Status) { case DHCP_SUCCESS: // even if we're already in T1 stage this should work // it just sets up a timer to call ProcessT1 right away // ProcessT1 should then do the right thing CalcT1Time(pDhcp); fDone = TRUE; break; case DHCP_COLLISION: DhcpDecline(pDhcp, &Pkt); // fall through default: fDone = FALSE; break; } } else { // we're in T2 stage don't use old addr. pDhcp->IPAddr = 0; } } } else { // else if (!fDiscover) DEBUGMSG(ZONE_WARN, (TEXT("\tGetParams: failed badly!\n"))); // shall we try again? pDhcp->IPAddr = 0; } } else { // if (SetDHCPNTE) DEBUGMSG(ZONE_WARN, (TEXT("DHCP: GetParams: adapter disappeared\r\n"))); Status = DHCP_NOCARD; } if (! fDone && ((pDhcp->SFlags & DHCPSTATE_DIALOGUE_BOX) == 0) && DHCP_NOCARD != Status && (cRetry == pDhcp->cRetryDialogue || cRetry == pDhcp->cMaxRetry)) { pDhcp->SFlags |= DHCPSTATE_DIALOGUE_BOX; CallNetMsgBox(NULL, NMB_FL_EXCLAIM | NMB_FL_OK | NMB_FL_TOPMOST, NETUI_GETNETSTR_NO_IPADDR); } } // for(...) if (fDone) { pDhcp->SFlags &= ~DHCPSTATE_DIALOGUE_BOX; } } // if (pDhcp->Flags & DHCP_ENABLED_FL) DEBUGMSG(ZONE_INIT, (TEXT("-GetParams: pDhcp 0x%X Ret: %d\n"), pDhcp, Status)); return Status; } // GetParams() STATUS DelDHCPInterface(PTSTR pAdapter, void *Nte, unsigned Context) { STATUS Status; DhcpInfo **ppDhcp, *pDhcp; ppDhcp = _FindDhcp(NULL, pAdapter); if (pDhcp = *ppDhcp) { *ppDhcp = pDhcp->pNext; CTEFreeLock(&v_GlobalListLock, 0); TakeNetDown(pDhcp, FALSE, TRUE); // we probably don't need to clear, but since we now have a flag // to not clear if we don't have it set it should be safer ClearDHCPNTE(pDhcp); CloseDhcpSocket(pDhcp); CTEFreeLock(&pDhcp->Lock, 0); FreeDhcpInfo(pDhcp); } else { // let's check the worker Q ppDhcp = &v_pWaitingList; while (pDhcp = *ppDhcp) { if (0 == _tcscmp(pDhcp->Name, pAdapter)) { *ppDhcp = pDhcp->pNext; FreeDhcpInfo(pDhcp); break; } ppDhcp = &(pDhcp->pNext); } if (pDhcp) { Status = DHCP_SUCCESS; } else if (v_pCurrent && (0 == _tcscmp(v_pCurrent->Name, pAdapter))) { ASSERT(NULL == v_pDelete); v_pDelete = v_pCurrent; Status = DHCP_SUCCESS; } else { DEBUGMSG(ZONE_ERROR, (TEXT("DHCP: DelDHCPInterface: couldn't find Interface %s\r\n"), pAdapter)); Status = DHCP_NOINTERFACE; } CTEFreeLock(&v_GlobalListLock, 0); } return Status; } // DelDHCPInterface() STATUS RenewDHCPAddr(PTSTR pAdapter, void *Nte, unsigned Context, char *pAddr, unsigned cAddr) { STATUS Status = DHCP_SUCCESS; DhcpInfo **ppDhcp, *pDhcp; int fNewSock = 0; DhcpPkt Pkt; int cPkt; FILETIME CurTime; int fStatus, fLockFreed = 0; ppDhcp = _FindDhcp(NULL, pAdapter); if (pDhcp = *ppDhcp) { CTEFreeLock(&v_GlobalListLock, 0); ASSERT(pDhcp->Nte == Nte); ASSERT(pDhcp->NteContext == Context); if (pDhcp->SFlags & DHCPSTATE_LEASE_EXPIRE) { ASSERT(0); // if this is the case, we shouldn't be on the established list! Status = DHCP_FAILURE; } else if (pDhcp->SFlags & DHCPSTATE_AUTO_CFG_IP) { fLockFreed = TRUE; TakeNetDown(pDhcp, FALSE, TRUE); CTEFreeLock(&pDhcp->Lock, 0); Status = RequestDHCPAddr(pAdapter, Nte, Context, pAddr, cAddr); } else { if (! pDhcp->Socket) { fNewSock++; Status = DhcpInitSock(pDhcp, pDhcp->IPAddr); } if (DHCP_SUCCESS == Status) { BuildDhcpPkt(pDhcp, &Pkt, DHCPREQUEST, (NEW_PKT_FL), pDhcp->ReqOptions, &cPkt); fStatus = TRUE; // SetDHCPNTE(pDhcp); GetCurrentFT(&CurTime); if (fStatus) Status = SendDhcpPkt(pDhcp, &Pkt, cPkt, DHCPACK, 3); else Status = DHCP_NOCARD; if (Status == DHCP_SUCCESS) { CTEStopFTimer(&pDhcp->Timer); memcpy(&pDhcp->LeaseObtained, &CurTime, sizeof(CurTime)); SetDhcpConfig(pDhcp); // this should set the FTimer based on the new settings. CalcT1Time(pDhcp); } else if (Status == DHCP_NACK) { // Take Net Down !!! DEBUGMSG(ZONE_WARN, (TEXT("\t!ProcessT1: Take Net Down\r\n"))); CTEStopFTimer(&pDhcp->Timer); TakeNetDown(pDhcp, TRUE, TRUE); ClearDHCPNTE(pDhcp); CloseDhcpSocket(pDhcp); CTEFreeLock(&pDhcp->Lock, 0); if (*(ppDhcp = _FindDhcp(pDhcp, NULL))) { *ppDhcp = pDhcp->pNext; // CallNetMsgBox(NULL, NMB_FL_EXCLAIM | NMB_FL_OK | NMB_FL_TOPMOST, // NETUI_GETNETSTR_LEASE_EXPIRED); PutInWorkerQ(pDhcp); CTEFreeLock(&pDhcp->Lock, 0); } CTEFreeLock(&v_GlobalListLock, 0); // Status should be DHCP_NACK goto Exit; } // Status == DHCP_NACK if (fNewSock) CloseDhcpSocket(pDhcp); } // DHCP_SUCCESS == Status } // else DHCPSTATE_LEASE_EXPIRE if (! fLockFreed) CTEFreeLock(&pDhcp->Lock, 0); } else { // if (_FindDhcp(... // let's check the worker Q pDhcp = v_pWaitingList; while (pDhcp) { if (0 == _tcscmp(pDhcp->Name, pAdapter)) { break; } pDhcp = pDhcp->pNext; } if (! pDhcp) { if (v_pCurrent && (0 == _tcscmp(v_pCurrent->Name, pAdapter))) pDhcp = v_pCurrent; } CTEFreeLock(&v_GlobalListLock, 0); if (pDhcp) { // this means he is either on the waiting list or our current one // so there is nothing more to do; return success. Status = DHCP_SUCCESS; } else { Status = RequestDHCPAddr(pAdapter, Nte, Context, pAddr, cAddr); } } Exit: return Status; } // RenewDHCPAddr() STATUS RequestDHCPAddr(PTSTR pAdapter, void *Nte, unsigned Context, char *pAddr, unsigned cAddr) { DhcpInfo **ppDhcp, *pDhcp; int cLen; STATUS Status = DHCP_SUCCESS; DEBUGMSG(ZONE_WARN, (TEXT("+RequestDHCPAddr: %s Context %d\r\n"), pAdapter, Context)); ppDhcp = _FindDhcp(NULL, pAdapter); if (pDhcp = *ppDhcp) { DEBUGMSG(ZONE_WARN, (TEXT("!RequestDHCPAddr: found previous pDhcp %X w. IP %X\r\n"), pDhcp, pDhcp->IPAddr)); // we already have an object for this adapter // take out of established list *ppDhcp = pDhcp->pNext; pDhcp->Nte = Nte; pDhcp->NteContext = Context; if (pAddr) memcpy(pDhcp->PhysAddr, pAddr, cAddr); CTEFreeLock(&pDhcp->Lock, 0); } else { cLen = (_tcslen(pAdapter) + 1) << 1; if (pDhcp = NewDhcpInfo(cLen)) { _tcscpy(pDhcp->Name, pAdapter); pDhcp->Nte = Nte; pDhcp->NteContext = Context; if (pAddr) memcpy(pDhcp->PhysAddr, pAddr, cAddr); } } if (pDhcp) { PutInWorkerQ(pDhcp); } else Status = DHCP_NOMEM; CTEFreeLock(&v_GlobalListLock, 0); ASSERT(v_GlobalListLock.OwnerThread != (HANDLE)GetCurrentThreadId()); DEBUGMSG(ZONE_WARN, (TEXT("-RequestDHCPAddr: Context %d\r\n"), Context)); return Status; } // RequestDHCPAddr() STATUS ReleaseDHCPAddr(PTSTR pAdapter) { DhcpInfo **ppDhcp, *pDhcp; int cPkt; STATUS Status; DhcpPkt Pkt; DEBUGMSG(ZONE_WARN, (TEXT("+ReleaseDHCPAddr: %s \n"), pAdapter)); // Find the object to release Status = DHCP_NOINTERFACE; ppDhcp = _FindDhcp(NULL, pAdapter); if (pDhcp = *ppDhcp) { // Don't want T1 or T2 timer to fire while we are in the middle // of releasing... // CTEStopFTimer(&pDhcp->Timer); // this won't happen...ie: if it fires, it won't find us on the list // Open the socket if (DHCP_SUCCESS == (Status = DhcpInitSock(pDhcp, pDhcp->IPAddr))) { // Build and transmit the Dhcp Release packet BuildDhcpPkt(pDhcp, &Pkt, DHCPRELEASE, NEW_PKT_FL, NULL, &cPkt); // // Note that there is no ACK packet for a DHCPRELEASE, so there is // no way to know for certain if a release is successful. // Status = DhcpSendDown(pDhcp, &Pkt, cPkt, pDhcp->DhcpServer); // Inform TCP/IP that the IP address is no longer valid, // Remove pDhcp from the global list *ppDhcp = pDhcp->pNext; CTEFreeLock(&v_GlobalListLock, 0); TakeNetDown(pDhcp, TRUE, TRUE); // we didn't set it, but in case someone else had... ClearDHCPNTE(pDhcp); CloseDhcpSocket(pDhcp); CTEFreeLock(&pDhcp->Lock, 0); FreeDhcpInfo(pDhcp); } else { CTEFreeLock(&v_GlobalListLock, 0); CTEFreeLock(&pDhcp->Lock, 0); } } else { CTEFreeLock(&v_GlobalListLock, 0); } return Status; } // ReleaseDHCPAddr() void DhcpWorkerThread() { DhcpInfo *pInfo; STATUS Status; DWORD Size; CTEGetLock(&v_GlobalListLock, 0); while (pInfo = v_pWaitingList) { // take him off the list v_pWaitingList = pInfo->pNext; v_pCurrent = pInfo; pInfo->pNext = NULL; CTEFreeLock(&v_GlobalListLock, 0); // now try to get an address for him if (DHCP_SUCCESS == (Status = DhcpInitSock(pInfo, 0))) { CTEGetLock(&pInfo->Lock, 0); if (! pInfo->Nte) { Size = ETH_ADDR_LEN; (*pfnSetDHCPNTE)(pInfo->NteContext, &pInfo->Nte, pInfo->PhysAddr, &Size); } Status = GetParams(pInfo); CloseDhcpSocket(pInfo); CTEFreeLock(&pInfo->Lock, 0); CTEGetLock(&v_GlobalListLock, 0); if (v_pDelete == v_pCurrent) { if (DHCP_SUCCESS == Status) { TakeNetDown(pInfo, FALSE, TRUE); // we really shouldn't need to clear him, but to be safer ClearDHCPNTE(pInfo); Status = DHCP_FAILURE; } v_pDelete = NULL; } ASSERT(NULL == v_pDelete); v_pCurrent = NULL; if (DHCP_SUCCESS == Status) { DEBUGMSG(ZONE_INIT, (TEXT("Put Adapter in Established list\r\n"))); // cool put him on the established list pInfo->pNext = v_pEstablishedList; v_pEstablishedList = pInfo; } else { DEBUGMSG(ZONE_WARN, (TEXT("\tDhcpWorkerThread: couldn't get Addr for pInfo 0x%X, Context 0x%X\r\n"), pInfo, pInfo->NteContext)); FreeDhcpInfo(pInfo); } } else { CTEGetLock(&v_GlobalListLock, 0); if (v_pDelete == v_pCurrent) { v_pDelete = NULL; } ASSERT(NULL == v_pDelete); v_pCurrent = NULL; // releaes global list lock since callnetmsgbox blocks our thread CTEFreeLock(&v_GlobalListLock, 0); FreeDhcpInfo(pInfo); CallNetMsgBox(NULL, NMB_FL_EXCLAIM | NMB_FL_OK | NMB_FL_TOPMOST, NETUI_GETNETSTR_NO_IPADDR); CTEGetLock(&v_GlobalListLock, 0); } // we should have the Global Lock before going back up DEBUGMSG(ZONE_WARN, (TEXT("\tDhcpWorkerThread: loop 1: WaitList is 0x%X\r\n"), v_pWaitingList)); } v_pCurrent = NULL; v_fWorkerThread = FALSE; DEBUGMSG(ZONE_WARN, (TEXT("-DhcpWorkerThread: WaitList is 0x%X\r\n"), v_pWaitingList)); ASSERT(v_GlobalListLock.OwnerThread == (HANDLE)GetCurrentThreadId()); CTEFreeLock(&v_GlobalListLock, 0); ASSERT(v_GlobalListLock.OwnerThread != (HANDLE)GetCurrentThreadId()); } // DhcpWorkerThread() STATUS DhcpNotify(uint Code, PTSTR pAdapter, void *Nte, unsigned Context, char *pAddr, unsigned cAddr) { STATUS Status; switch(Code) { case DHCP_NOTIFY_DEL_INTERFACE: Status = DelDHCPInterface(pAdapter, Nte, Context); break; case DHCP_REQUEST_ADDRESS: Status = RequestDHCPAddr(pAdapter, Nte, Context, pAddr, cAddr); break; case DHCP_REQUEST_RELEASE: Status = ReleaseDHCPAddr(pAdapter); break; case DHCP_REQUEST_RENEW: Status = RenewDHCPAddr(pAdapter, Nte, Context, pAddr, cAddr); break; // the following are unhandled cases no one should be calling them case DHCP_NOTIFY_ADD_INTERFACE: default: ASSERT(0); Status = DHCP_FAILURE; break; } ASSERT(v_GlobalListLock.OwnerThread != (HANDLE)GetCurrentThreadId()); return Status; } // DhcpNotify()


Legal Declaration: it is for studying wince(MicroSoft Windows CE) only! : http://www.vxworks6.com