protocol.cxx
Upload User: caisha3
Upload Date: 2013-09-21
Package Size: 208739k
Code Size: 62k
Category:

Windows Develop

Development Platform:

Visual C++

  1. /*++
  2. Copyright (c) 1994  Microsoft Corporation
  3. Module Name:
  4.     protocol.cxx
  5. Abstract:
  6.     This module contains the server to client protocol for DHCP.
  7. Author:
  8.     Manny Weiser (mannyw)  21-Oct-1992
  9. Environment:
  10.     User Mode - Win32
  11. Revision History:
  12.     Madan Appiah (madana)  21-Oct-1993
  13.     Arthur Bierer (arthurbi) 15-July-1998
  14.         hacked up to use with Wininet's auto-proxy detection code
  15. --*/
  16. #include <wininetp.h>
  17. #include "aproxp.h"
  18. #include "apdetect.h"
  19. #ifndef VXD
  20. // ping routines.. ICMP
  21. #include <ipexport.h>
  22. //#include <icmpif.h>
  23. #include <icmpapi.h>
  24. #endif
  25. #ifdef NEWNT
  26. extern BOOL DhcpGlobalIsService;
  27. #endif // NEWNT
  28. DWORD                                             // Time in seconds
  29. DhcpCalculateWaitTime(                            // how much time to wait
  30.     IN      DWORD                  RoundNum,      // which round is this
  31.     OUT     DWORD                 *WaitMilliSecs  // if needed the # in milli seconds
  32. );
  33. POPTION
  34. FormatDhcpInform(
  35.     PDHCP_CONTEXT DhcpContext
  36. );
  37. DWORD
  38. SendDhcpInform(
  39.     PDHCP_CONTEXT DhcpContext,
  40.     PDWORD TransactionId
  41. );
  42. DWORD                                             // status
  43. SendInformAndGetReplies(                          // send an inform packet and collect replies
  44.     IN      PDHCP_CONTEXT          DhcpContext,   // the context to send out of
  45.     IN      DWORD                  nInformsToSend,// how many informs to send?
  46.     IN      DWORD                  MaxAcksToWait, // how many acks to wait for
  47.     OUT     DHCP_EXPECTED_OPTIONS *pExpectedOptions // list of things parsed out of request
  48. );
  49. VOID
  50. DhcpExtractFullOrLiteOptions(                     // Extract some important options alone or ALL
  51.     IN      PDHCP_CONTEXT          DhcpContext,
  52.     IN      LPBYTE                 OptStart,      // start of the options stuff
  53.     IN      DWORD                  MessageSize,   // # of bytes of options
  54.     IN      BOOL                   LiteOnly,      // next struc is EXPECTED_OPTIONS and not FULL_OPTIONS
  55.     OUT     LPVOID                 DhcpOptions,   // this is where the options would be stored
  56.     IN OUT  PLIST_ENTRY            RecdOptions,   // if !LiteOnly this gets filled with all incoming options
  57.     IN OUT  DWORD                 *LeaseExpiry,   // if !LiteOnly input expiry time, else output expiry time
  58.     IN      LPBYTE                 ClassName,     // if !LiteOnly this is used to add to the option above
  59.     IN      DWORD                  ClassLen       // if !LiteOnly this gives the # of bytes of classname
  60. );
  61. DWORD
  62. SendDhcpMessage(
  63.     PDHCP_CONTEXT DhcpContext,
  64.     DWORD MessageLength,
  65.     PDWORD TransactionId
  66.     );
  67. DWORD
  68. OpenDhcpSocket(
  69.     PDHCP_CONTEXT DhcpContext
  70.     );
  71. DWORD
  72. GetSpecifiedDhcpMessage(
  73.     PDHCP_CONTEXT DhcpContext,
  74.     PDWORD BufferLength,
  75.     DWORD TransactionId,
  76.     DWORD TimeToWait
  77.     );
  78. DWORD
  79. CloseDhcpSocket(
  80.     PDHCP_CONTEXT DhcpContext
  81.     );
  82. //
  83. // functions
  84. //
  85. DWORD                                             // Time in seconds
  86. DhcpCalculateWaitTime(                            // how much time to wait
  87.     IN      DWORD                  RoundNum,      // which round is this
  88.     OUT     DWORD                 *WaitMilliSecs  // if needed the # in milli seconds
  89. ) {
  90.     DWORD                          MilliSecs;
  91.     //DWORD                          WaitTimes[4] = { 4000, 8000, 16000, 32000 };
  92.     DWORD                          WaitTimes[4] = { 2000, 4000, 8000, 16000 };
  93.     if( WaitMilliSecs ) *WaitMilliSecs = 0;
  94.     if( RoundNum >= sizeof(WaitTimes)/sizeof(WaitTimes[0]) )
  95.         return 0;
  96.     MilliSecs = WaitTimes[RoundNum] - 1000 + ((rand()*((DWORD) 2000))/RAND_MAX);
  97.     if( WaitMilliSecs ) *WaitMilliSecs = MilliSecs;
  98.     return (MilliSecs + 501)/1000;
  99. }
  100. VOID        _inline
  101. ConcatOption(
  102.     IN OUT  LPBYTE                *Buf,           // input buffer to re-alloc
  103.     IN OUT  ULONG                 *BufSize,       // input buffer size
  104.     IN      BYTE UNALIGNED        *Data,          // data to append
  105.     IN      ULONG                  DataSize       // how many bytes to add?
  106. )
  107. {
  108.     LPBYTE                         NewBuf;
  109.     ULONG                          NewSize;
  110.     NewSize = (*BufSize) + DataSize;
  111.     NewBuf = (LPBYTE) DhcpAllocateMemory(NewSize);
  112.     if( NULL == NewBuf ) {                        // could not alloc memory?
  113.         return;                                   // can't do much
  114.     }
  115.     memcpy(NewBuf, *Buf, *BufSize);               // copy existing part
  116.     memcpy(NewBuf + *BufSize, Data, DataSize);    // copy new stuff
  117.     if( NULL != *Buf ) DhcpFreeMemory(*Buf);      // if we alloc'ed mem, free it now
  118.     *Buf = NewBuf;
  119.     *BufSize = NewSize;                           // fill in new values..
  120. }
  121. VOID
  122. DhcpExtractFullOrLiteOptions(                     // Extract some important options alone or ALL
  123.     IN      PDHCP_CONTEXT          DhcpContext,   // input context
  124.     IN      LPBYTE                 OptStart,      // start of the options stuff
  125.     IN      DWORD                  MessageSize,   // # of bytes of options
  126.     IN      BOOL                   LiteOnly,      // next struc is EXPECTED_OPTIONS and not FULL_OPTIONS
  127.     OUT     LPVOID                 DhcpOptions,   // this is where the options would be stored
  128.     IN OUT  PLIST_ENTRY            RecdOptions,   // if !LiteOnly this gets filled with all incoming options
  129.     IN OUT  DWORD                 *LeaseExpiry,   // if !LiteOnly input expiry time, else output expiry time
  130.     IN      LPBYTE                 ClassName,     // if !LiteOnly this is used to add to the option above
  131.     IN      DWORD                  ClassLen       // if !LiteOnly this gives the # of bytes of classname
  132. ) {
  133.     BYTE    UNALIGNED*             ThisOpt;
  134.     BYTE    UNALIGNED*             NextOpt;
  135.     BYTE    UNALIGNED*             EndOpt;
  136.     BYTE    UNALIGNED*             MagicCookie;
  137.     DWORD                          Error;
  138.     DWORD                          Size, ThisSize, UClassSize = 0;
  139.     LPBYTE                         UClass= NULL;  // concatenation of all OPTION_USER_CLASS options
  140.     PDHCP_EXPECTED_OPTIONS         ExpOptions;
  141.     PDHCP_FULL_OPTIONS             FullOptions;
  142.     BYTE                           ReqdCookie[] = {
  143.         (BYTE)DHCP_MAGIC_COOKIE_BYTE1,
  144.         (BYTE)DHCP_MAGIC_COOKIE_BYTE2,
  145.         (BYTE)DHCP_MAGIC_COOKIE_BYTE3,
  146.         (BYTE)DHCP_MAGIC_COOKIE_BYTE4
  147.     };
  148.     EndOpt = OptStart + MessageSize;              // all options should be < EndOpt;
  149.     ExpOptions = (PDHCP_EXPECTED_OPTIONS)DhcpOptions;
  150.     FullOptions = (PDHCP_FULL_OPTIONS)DhcpOptions;
  151.     RtlZeroMemory((LPBYTE)DhcpOptions, LiteOnly?sizeof(*ExpOptions):sizeof(*FullOptions));
  152.     // if(!LiteOnly) InitializeListHead(RecdOptions); -- clear off this list for getting ALL options
  153.     // dont clear off options... just accumulate over..
  154.     MagicCookie = OptStart;
  155.     if( 0 == MessageSize ) goto DropPkt;          // nothing to do in this case
  156.     if( 0 != memcmp(MagicCookie, ReqdCookie, sizeof(ReqdCookie)) )
  157.         goto DropPkt;                             // oops, cant handle this packet
  158.     NextOpt = &MagicCookie[sizeof(ReqdCookie)];
  159.     while( NextOpt < EndOpt && OPTION_END != *NextOpt ) {
  160.         if( OPTION_PAD == *NextOpt ) {            // handle pads right away
  161.             NextOpt++;
  162.             continue;
  163.         }
  164.         ThisOpt = NextOpt;                        // take a good look at this option
  165.         if( NextOpt + 2 >  EndOpt ) {             // goes over boundary?
  166.             break;
  167.         }
  168.         NextOpt += 2 + (unsigned)ThisOpt[1];      // Option[1] holds the size of this option
  169.         Size = ThisOpt[1];
  170.         if( NextOpt > EndOpt ) {                  // illegal option that goes over boundary!
  171.             break;                                // ignore the error, but dont take this option
  172.         }
  173.         if(!LiteOnly) do {                        // look for any OPTION_MSFT_CONTINUED ..
  174.             if( NextOpt >= EndOpt ) break;        // no more options
  175.             if( OPTION_MSFT_CONTINUED != NextOpt[0] ) break;
  176.             if( NextOpt + 1 + NextOpt[1] > EndOpt ) {
  177.                 NextOpt = NULL;                   // do this so that we know to quit at the end..
  178.                 break;
  179.             }
  180.             NextOpt++;                            // skip opt code
  181.             ThisSize = NextOpt[0];                // # of bytes to shift back..
  182.             memcpy(ThisOpt+2+Size, NextOpt+1,ThisSize);
  183.             NextOpt += ThisSize+1;
  184.             Size += ThisSize;
  185.         } while(1);                               // keep stringing up any "continued" options..
  186.         if( NULL == NextOpt ) {                   // err parsing OPTION_MSFT_CONTINUED ..
  187.             break;
  188.         }
  189.         if( LiteOnly ) {                          // handle the small subnet of options
  190.             switch( ThisOpt[0] ) {                // ThisOpt[0] is OptionId, ThisOpt[1] is size
  191.             case OPTION_MESSAGE_TYPE:
  192.                 if( ThisOpt[1] != 1 ) goto DropPkt;
  193.                 ExpOptions->MessageType = &ThisOpt[2];
  194.                 continue;
  195.             case OPTION_SUBNET_MASK:
  196.                 if( ThisOpt[1] != sizeof(DWORD) ) goto DropPkt;
  197.                 ExpOptions->SubnetMask = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
  198.                 continue;
  199.             case OPTION_LEASE_TIME:
  200.                 if( ThisOpt[1] != sizeof(DWORD) ) goto DropPkt;
  201.                 ExpOptions->LeaseTime = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
  202.                 continue;
  203.             case OPTION_SERVER_IDENTIFIER:
  204.                 if( ThisOpt[1] != sizeof(DWORD) ) goto DropPkt;
  205.                 ExpOptions->ServerIdentifier = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
  206.                 continue;
  207.             case OPTION_DOMAIN_NAME:
  208.                 if( ThisOpt[1] == 0 ) goto DropPkt;
  209.                 ExpOptions->DomainName = (BYTE UNALIGNED *)&ThisOpt[2];
  210.                 ExpOptions->DomainNameSize = ThisOpt[1];
  211.                 break;
  212.             case OPTION_WPAD_URL:
  213.                 if( ThisOpt[1] == 0 ) goto DropPkt;
  214.                 ExpOptions->WpadUrl = (BYTE UNALIGNED *)&ThisOpt[2];
  215.                 ExpOptions->WpadUrlSize = ThisOpt[1];
  216.                 break;
  217.             default:
  218.                 continue;
  219.             }
  220.         } else {                                  // Handle the full set of options
  221.             switch( ThisOpt[0] ) {
  222.             case OPTION_MESSAGE_TYPE:
  223.                 if( Size != 1 ) goto DropPkt;
  224.                 FullOptions->MessageType = &ThisOpt[2];
  225.                 break;
  226.             case OPTION_SUBNET_MASK:
  227.                 if( Size != sizeof(DWORD) ) goto DropPkt;
  228.                 FullOptions->SubnetMask = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
  229.                 break;
  230.             case OPTION_LEASE_TIME:
  231.                 if( Size != sizeof(DWORD) ) goto DropPkt;
  232.                 FullOptions->LeaseTime = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
  233.                 break;
  234.             case OPTION_SERVER_IDENTIFIER:
  235.                 if( Size != sizeof(DWORD) ) goto DropPkt;
  236.                 FullOptions->ServerIdentifier = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
  237.                 break;
  238.             case OPTION_RENEWAL_TIME:             // T1Time
  239.                 if( Size != sizeof(DWORD) ) goto DropPkt;
  240.                 FullOptions->T1Time = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
  241.                 break;
  242.             case OPTION_REBIND_TIME:              // T2Time
  243.                 if( Size != sizeof(DWORD) ) goto DropPkt;
  244.                 FullOptions->T2Time = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
  245.                 break;
  246.             case OPTION_ROUTER_ADDRESS:
  247.                 if( Size < sizeof(DWORD) || (Size % sizeof(DWORD) ) )
  248.                     goto DropPkt;                 // There can be many router addresses
  249.                 FullOptions->GatewayAddresses = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
  250.                 FullOptions->nGateways = Size / sizeof(DWORD);
  251.                 break;
  252.             case OPTION_STATIC_ROUTES:
  253.                 if( Size < 2*sizeof(DWORD) || (Size % (2*sizeof(DWORD))) )
  254.                     goto DropPkt;                 // the static routes come in pairs
  255.                 FullOptions->StaticRouteAddresses = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
  256.                 FullOptions->nStaticRoutes = Size/(2*sizeof(DWORD));
  257.                 break;
  258.             case OPTION_DYNDNS_BOTH:
  259.                 if( Size < 3 ) goto DropPkt;
  260.                 FullOptions->DnsFlags = (BYTE UNALIGNED *)&ThisOpt[2];
  261.                 FullOptions->DnsRcode1 = (BYTE UNALIGNED *)&ThisOpt[3];
  262.                 FullOptions->DnsRcode2 = (BYTE UNALIGNED *)&ThisOpt[3];
  263.                 break;
  264.             case OPTION_DOMAIN_NAME:
  265.                 if( Size == 0 ) goto DropPkt;
  266.                 FullOptions->DomainName = (BYTE UNALIGNED *)&ThisOpt[2];
  267.                 FullOptions->DomainNameSize = Size;
  268.                 break;
  269.             case OPTION_WPAD_URL:
  270.                 if( Size == 0 ) goto DropPkt;
  271.                 FullOptions->WpadUrl = (BYTE UNALIGNED *)&ThisOpt[2];
  272.                 FullOptions->WpadUrlSize = Size;
  273.                 break;
  274.             case OPTION_DOMAIN_NAME_SERVERS:
  275.                 if( Size < sizeof(DWORD) || (Size % sizeof(DWORD) ))
  276.                     goto DropPkt;
  277.                 FullOptions->DnsServerList = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
  278.                 FullOptions->nDnsServers = Size / sizeof(DWORD);
  279.                 break;
  280.             case OPTION_MESSAGE:
  281.                 if( Size == 0 ) break;      // ignore zero sized packets
  282.                 FullOptions->ServerMessage = &ThisOpt[2];
  283.                 FullOptions->ServerMessageLength = ThisOpt[1];
  284.                 break;
  285.             case OPTION_MCAST_LEASE_START:
  286.                 if ( Size != sizeof(DATE_TIME) ) goto DropPkt;
  287.                 FullOptions->MCastLeaseStartTime = (DWORD UNALIGNED *)&ThisOpt[2];
  288.                 break;
  289.             case OPTION_MCAST_TTL:
  290.                 if ( Size != 1 ) goto DropPkt;
  291.                 FullOptions->MCastTTL = (BYTE UNALIGNED *)&ThisOpt[2];
  292.                 break;
  293.             case OPTION_USER_CLASS:
  294.                 if( Size <= 6) goto DropPkt;
  295.                 ConcatOption(&UClass, &UClassSize, &ThisOpt[2], Size);
  296.                 continue;                         // don't add this option yet...
  297.             default:
  298.                 // unknowm message, nothing to do.. especially dont log this
  299.                 break;
  300.             }
  301.         } // if LiteOnly then else
  302.     } // while NextOpt < EndOpt
  303.     if( LiteOnly && LeaseExpiry ) {               // If asked to calculate lease expiration time..
  304.         DWORD    LeaseTime;
  305.         time_t   TimeNow, ExpirationTime;
  306.         // BBUGBUGBUG [arthurbi] broken intensionlly, dead code.
  307.         //if( ExpOptions->LeaseTime ) LeaseTime = _I_ntohl(*ExpOptions->LeaseTime);
  308.         if( ExpOptions->LeaseTime ) LeaseTime = 0;
  309.         else LeaseTime = DHCP_MINIMUM_LEASE;
  310.         ExpirationTime = (TimeNow = time(NULL)) + (time_t)LeaseTime;
  311.         if( ExpirationTime < TimeNow ) {
  312.             ExpirationTime = INFINIT_TIME;
  313.         }
  314.         *LeaseExpiry = (DWORD)ExpirationTime ;
  315.     }
  316.     if( !LiteOnly && NULL != UClass ) {           // we have a user class list to pass on..
  317.         DhcpAssert(UClassSize != 0 );             // we better have something here..
  318.         DhcpFreeMemory(UClass); UClass = NULL;
  319.     }
  320.     return;
  321.   DropPkt:
  322.     RtlZeroMemory(DhcpOptions, LiteOnly?sizeof(ExpOptions):sizeof(FullOptions));
  323.     if( LiteOnly && LeaseExpiry ) *LeaseExpiry = (DWORD) time(NULL) + DHCP_MINIMUM_LEASE;
  324.     //if(!LiteOnly) DhcpFreeAllOptions(RecdOptions);// ok undo the options that we just added
  325.     if(!LiteOnly && NULL != UClass ) DhcpFreeMemory(UClass);
  326. }
  327. POPTION                                           // ptr to add additional options
  328. FormatDhcpInform(                                 // format the packet for an INFORM
  329.     IN      PDHCP_CONTEXT          DhcpContext    // format for this context
  330. ) {
  331.     LPOPTION option;
  332.     LPBYTE OptionEnd;
  333.     BYTE value;
  334.     PDHCP_MESSAGE dhcpMessage;
  335.     dhcpMessage = DhcpContext->MessageBuffer;
  336.     RtlZeroMemory( dhcpMessage, DHCP_SEND_MESSAGE_SIZE );
  337.     //
  338.     // BUGBUG [arthurbi] - 
  339.     // For RAS client, use broadcast bit, otherwise the router will try
  340.     // to send as unicast to made-up RAS client hardware address, which
  341.     // will not work.  So will this work without it?
  342.     //
  343.     //
  344.     // Transaction ID is filled in during send
  345.     //
  346.     dhcpMessage->Operation             = BOOT_REQUEST;
  347.     dhcpMessage->HardwareAddressType   = DhcpContext->HardwareAddressType;
  348.     dhcpMessage->SecondsSinceBoot      = (WORD) DhcpContext->SecondsSinceBoot;
  349.     memcpy(dhcpMessage->HardwareAddress,DhcpContext->HardwareAddress,DhcpContext->HardwareAddressLength);
  350.     dhcpMessage->HardwareAddressLength = (BYTE)DhcpContext->HardwareAddressLength;
  351.     dhcpMessage->ClientIpAddress       = DhcpContext->IpAddress;
  352.     //dhcpMessage->Reserved = 0;
  353.     //dhcpMessage->Reserved = _I_htons(DHCP_BROADCAST);
  354.     //if ( IS_MDHCP_CTX(DhcpContext ) ) MDHCP_MESSAGE( dhcpMessage );
  355.     option = &dhcpMessage->Option;
  356.     OptionEnd = (LPBYTE)dhcpMessage + DHCP_SEND_MESSAGE_SIZE;
  357.     //
  358.     // always add magic cookie first
  359.     //
  360.     option = (LPOPTION) DhcpAppendMagicCookie( (LPBYTE) option, OptionEnd );
  361.     value = DHCP_INFORM_MESSAGE;
  362.     option = DhcpAppendOption(
  363.         option,
  364.         OPTION_MESSAGE_TYPE,
  365.         &value,
  366.         1,
  367.         OptionEnd
  368.     );
  369.     //
  370.     // BUGBUG [arthurbi], shouldn't we uncomment this?
  371.     //
  372.     // un comment later on
  373.     /*option = DhcpAppendClassIdOption(
  374.         DhcpContext,
  375.         (LPBYTE)option,
  376.         OptionEnd
  377.     );*/
  378.     return( option );
  379. }
  380. DWORD                                             // status
  381. SendDhcpInform(                                   // send an inform packet after filling required options
  382.     IN      PDHCP_CONTEXT          DhcpContext,   // sned out for this context
  383.     IN OUT  DWORD                 *pdwXid         // use this Xid (if zero fill something and return it)
  384. ) {
  385.     DWORD                          size;
  386.     DWORD                          Error;
  387.     POPTION                        option;
  388.     LPBYTE                         OptionEnd;
  389.     BYTE                           SentOpt[OPTION_END+1];
  390.     BYTE                           SentVOpt[OPTION_END+1];
  391.     BYTE                           VendorOpt[OPTION_END+1];
  392.     DWORD                          VendorOptSize;
  393.     RtlZeroMemory(SentOpt, sizeof(SentOpt));      // initialize boolean arrays
  394.     RtlZeroMemory(SentVOpt, sizeof(SentVOpt));    // so that no option is presumed sent
  395.     VendorOptSize = 0;                            // encapsulated vendor option is empty
  396.     option = FormatDhcpInform( DhcpContext );     // core format
  397.     OptionEnd = (LPBYTE)(DhcpContext->MessageBuffer) + DHCP_SEND_MESSAGE_SIZE;
  398.     if( DhcpContext->ClientIdentifier.fSpecified) // client id specified in registy
  399.         option = DhcpAppendClientIDOption(        // ==> use this client id as option
  400.             option,
  401.             DhcpContext->ClientIdentifier.bType,
  402.             DhcpContext->ClientIdentifier.pbID,
  403.             (BYTE)DhcpContext->ClientIdentifier.cbID,
  404.             OptionEnd
  405.         );
  406.     else                                          // client id was not specified
  407.         option = DhcpAppendClientIDOption(        // ==> use hw addr as client id
  408.             option,
  409.             DhcpContext->HardwareAddressType,
  410.             DhcpContext->HardwareAddress,
  411.             (BYTE)DhcpContext->HardwareAddressLength,
  412.             OptionEnd
  413.         );
  414.     {   // add hostname and comment options
  415.         char szHostName[255];
  416.         if ( _I_gethostname(szHostName, ARRAY_ELEMENTS(szHostName)) != SOCKET_ERROR  ) 
  417.         {
  418.             option = DhcpAppendOption(
  419.                 option,
  420.                 OPTION_HOST_NAME,
  421.                 (LPBYTE)szHostName,
  422.                 (BYTE)((strlen(szHostName) + 1) * sizeof(CHAR)),
  423.                 OptionEnd
  424.             );
  425.         }
  426.     }
  427.     if( NULL != DhcpGlobalClientClassInfo ) {     // if we have any info on client class..
  428.         option = DhcpAppendOption(
  429.             option,
  430.             OPTION_CLIENT_CLASS_INFO,
  431.             (LPBYTE)DhcpGlobalClientClassInfo,
  432.             strlen(DhcpGlobalClientClassInfo),
  433.             OptionEnd
  434.         );
  435.     }
  436.     SentOpt[OPTION_MESSAGE_TYPE] = TRUE;          // these must have been added by now
  437.     if(DhcpContext->ClassIdLength) SentOpt[OPTION_USER_CLASS] = TRUE;
  438.     SentOpt[OPTION_CLIENT_CLASS_INFO] = TRUE;
  439.     SentOpt[OPTION_CLIENT_ID] = TRUE;
  440.     SentOpt[OPTION_REQUESTED_ADDRESS] = TRUE;
  441.     SentOpt[OPTION_HOST_NAME] = TRUE;
  442.     option = DhcpAppendSendOptions(               // append all other options we need to send
  443.         DhcpContext,                              // for this context
  444.         &DhcpContext->SendOptionsList,            // this is the list of options to send out
  445.         DhcpContext->ClassId,                     // which class.
  446.         DhcpContext->ClassIdLength,               // how many bytes are there in the class id
  447.         (LPBYTE)option,                           // start of the buffer to add the options
  448.         (LPBYTE)OptionEnd,                        // end of the buffer up to which we can add options
  449.         SentOpt,                                  // this is the boolean array that marks what opt were sent
  450.         SentVOpt,                                 // this is for vendor spec options
  451.         VendorOpt,                                // this would contain some vendor specific options
  452.         &VendorOptSize                            // the # of bytes of vendor options added to VendorOpt param
  453.     );
  454.     if( !SentOpt[OPTION_VENDOR_SPEC_INFO] && VendorOptSize && VendorOptSize <= OPTION_END )
  455.         option = DhcpAppendOption(                // add vendor specific options if we havent already sent it
  456.             option,
  457.             OPTION_VENDOR_SPEC_INFO,
  458.             VendorOpt,
  459.             (BYTE)VendorOptSize,
  460.             OptionEnd
  461.         );
  462.     option = DhcpAppendOption( option, OPTION_END, NULL, 0, OptionEnd );
  463.     size = (DWORD)((PBYTE)option - (PBYTE)DhcpContext->MessageBuffer);
  464.     return  SendDhcpMessage(                      // finally send the message and return
  465.         DhcpContext,
  466.         size,
  467.         pdwXid
  468.     );
  469. }
  470. DWORD
  471. InitializeDhcpSocket(
  472.     SOCKET *Socket,
  473.     DHCP_IP_ADDRESS IpAddress
  474.     )
  475. /*++
  476. Routine Description:
  477.     This function initializes and binds a socket to the specified IP address.
  478. Arguments:
  479.     Socket - Returns a pointer to the initialized socket.
  480.     IpAddress - The IP address to bind the socket to.  It is legitimate
  481.         to bind a socket to 0.0.0.0 if the card has no current IP address.
  482. Return Value:
  483.     The status of the operation.
  484. --*/
  485. {
  486.     DWORD error;
  487.     DWORD closeError;
  488.     DWORD value;
  489.     struct sockaddr_in socketName;
  490.     DWORD i;
  491.     SOCKET sock;
  492.     //
  493.     // Sockets initialization
  494.     //
  495.     sock = _I_socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
  496.     if ( sock == INVALID_SOCKET ) {
  497.         error = _I_WSAGetLastError();
  498.         DhcpPrint(("socket failed, error = %ldn", error ));
  499.         return( error );
  500.     }
  501.     //
  502.     // Make the socket share-able
  503.     //
  504.     value = 1;
  505.     error = _I_setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char FAR *)&value, sizeof(value) );
  506.     if ( error != 0 ) {
  507.         error = _I_WSAGetLastError();
  508.         DhcpPrint(("setsockopt failed, err = %ldn", error ));
  509.         closeError = _I_closesocket( sock );
  510.         if ( closeError != 0 ) {
  511.             DhcpPrint(("closesocket failed, err = %dn", closeError ));
  512.         }
  513.         return( error );
  514.     }
  515.     error = _I_setsockopt( sock, SOL_SOCKET, SO_BROADCAST, (char FAR *)&value, sizeof(value) );
  516.     if ( error != 0 ) {
  517.         error = _I_WSAGetLastError();
  518.         DhcpPrint(("setsockopt failed, err = %ldn", error ));
  519.         closeError = _I_closesocket( sock );
  520.         if ( closeError != 0 ) {
  521.             DhcpPrint(("closesocket failed, err = %dn", closeError ));
  522.         }
  523.         return( error );
  524.     }
  525.     //
  526.     // If the IpAddress is zero, set the special socket option to make
  527.     // stack work with zero address.
  528.     //
  529.     if( IpAddress == 0 ) {
  530.         value = 1234;
  531.         error = _I_setsockopt( sock, SOL_SOCKET, 0x8000, (char FAR *)&value, sizeof(value) );
  532.         if ( error != 0 ) {
  533.             error = _I_WSAGetLastError();
  534.             DhcpPrint(("setsockopt failed, err = %ldn", error ));
  535.             closeError = _I_closesocket( sock );
  536.             if ( closeError != 0 ) {
  537.                 DhcpPrint(("closesocket failed, err = %dn", closeError ));
  538.             }
  539.             return( error );
  540.         }
  541.     }
  542.     socketName.sin_family = PF_INET;
  543.     socketName.sin_port = _I_htons( DHCP_CLIENT_PORT );
  544.     socketName.sin_addr.s_addr = IpAddress;
  545.     for ( i = 0; i < 8 ; i++ ) {
  546.         socketName.sin_zero[i] = 0;
  547.     }
  548.     //
  549.     // Bind this socket to the DHCP server port
  550.     //
  551.     error = _I_bind(
  552.                sock,
  553.                (struct sockaddr FAR *)&socketName,
  554.                sizeof( socketName )
  555.                );
  556.     if ( error != 0 ) {
  557.         error = _I_WSAGetLastError();
  558.         DhcpPrint(("bind failed (address 0x%lx), err = %ldn", IpAddress, error ));
  559.         closeError = _I_closesocket( sock );
  560.         if ( closeError != 0 ) {
  561.             DhcpPrint(("closesocket failed, err = %dn", closeError ));
  562.         }
  563.         return( error );
  564.     }
  565.     *Socket = sock;
  566.     return( NO_ERROR );
  567. }
  568. DWORD                                             // status
  569. SendInformAndGetReplies(                          // send an inform packet and collect replies
  570.     IN      PDHCP_CONTEXT          DhcpContext,   // the context to send out of
  571.     IN      DWORD                  nInformsToSend,// how many informs to send?
  572.     IN      DWORD                  MaxAcksToWait, // how many acks to wait for
  573.     OUT     DHCP_EXPECTED_OPTIONS *pExpectedOptions // list of things parsed out of request
  574. ) {
  575.     time_t                         StartTime;
  576.     time_t                         TimeNow;
  577.     DWORD                          TimeToWait;
  578.     DWORD                          Error;
  579.     DWORD                          Xid;
  580.     DWORD                          MessageSize;
  581.     DWORD                          RoundNum;
  582.     DWORD                          MessageCount;
  583.     DWORD                          LeaseExpirationTime;
  584.     DHCP_FULL_OPTIONS              FullOptions;
  585.     DhcpPrint(("SendInformAndGetReplies enteredn"));
  586.     if((Error = OpenDhcpSocket(DhcpContext)) != ERROR_SUCCESS) {
  587.         DhcpPrint(("Could not open socket for this interface! (%ld)n", Error));
  588.         return Error;
  589.     }
  590.     Xid                           = 0;            // Will be generated by first SendDhcpPacket
  591.     MessageCount                  = 0;            // total # of messages we have got
  592.     DhcpContext->SecondsSinceBoot = 0;            // start at zero..
  593.     for( RoundNum = 0; RoundNum < nInformsToSend;  RoundNum ++ ) {
  594.         Error = SendDhcpInform(DhcpContext, &Xid);
  595.         if( ERROR_SUCCESS != Error ) {
  596.             DhcpPrint(("SendDhcpInform: %ldn", Error));
  597.             goto Cleanup;
  598.         } else {
  599.             DhcpPrint(("Sent DhcpInformn"));
  600.         }
  601.         TimeToWait = DhcpCalculateWaitTime(RoundNum, NULL);
  602.         DhcpContext->SecondsSinceBoot += TimeToWait; // do this so that next time thru it can go thru relays..
  603.         StartTime  = time(NULL);
  604.         while ( TRUE ) {                          // wiat for the specified wait time
  605.             MessageSize =  DHCP_MESSAGE_SIZE;
  606.             DhcpPrint(("Waiting for ACK[Xid=%x]: %ld secondsn",Xid, TimeToWait));
  607.             Error = GetSpecifiedDhcpMessage(      // try to receive an ACK
  608.                 DhcpContext,
  609.                 &MessageSize,
  610.                 Xid,
  611.                 (DWORD)TimeToWait
  612.             );
  613.             if ( Error == ERROR_SEM_TIMEOUT ) break;
  614.             if( Error != ERROR_SUCCESS ) {
  615.                 DhcpPrint(("GetSpecifiedDhcpMessage: %ldn", Error));
  616.                 goto Cleanup;
  617.             }
  618.             DhcpExtractFullOrLiteOptions(         // Need to see if this is an ACK
  619.                 DhcpContext,
  620.                 (LPBYTE)&DhcpContext->MessageBuffer->Option,
  621.                 MessageSize - DHCP_MESSAGE_FIXED_PART_SIZE,
  622.                 TRUE,                             // do lite extract only
  623.                 pExpectedOptions,                 // check for only expected options
  624.                 NULL,                             // unused
  625.                 &LeaseExpirationTime,
  626.                 NULL,                             // unused
  627.                 0                                 // unused
  628.             );
  629.             if( NULL == pExpectedOptions->MessageType ) {
  630.                 DhcpPrint(("Received no message type!n"));
  631.             } else if( DHCP_ACK_MESSAGE != *(pExpectedOptions->MessageType) ) {
  632.                 DhcpPrint(("Received unexpected message type: %ldn", *(pExpectedOptions->MessageType)));
  633.             } else if( NULL == pExpectedOptions->ServerIdentifier ) {
  634.                 DhcpPrint(("Received no server identifier, dropping inform ACKn"));
  635.             } else {
  636.                 MessageCount ++;
  637.                 DhcpPrint(("Received %ld ACKS so farn", MessageCount));
  638.                 DhcpExtractFullOrLiteOptions(     // do FULL options..
  639.                     DhcpContext,
  640.                     (LPBYTE)&DhcpContext->MessageBuffer->Option,
  641.                     MessageSize - DHCP_MESSAGE_FIXED_PART_SIZE,
  642.                     FALSE,
  643.                     &FullOptions,
  644.                     &(DhcpContext->RecdOptionsList),
  645.                     &LeaseExpirationTime,
  646.                     DhcpContext->ClassId,
  647.                     DhcpContext->ClassIdLength
  648.                 );
  649.                 if( MessageCount >= MaxAcksToWait ) goto Cleanup;
  650.             } // if( it is an ACK and ServerId present )
  651.             TimeNow     = time(NULL);             // Reset the time values to reflect new time
  652.             if( TimeToWait < (DWORD) (TimeNow - StartTime) ) {
  653.                 break;                            // no more time left to wait..
  654.             }
  655.             TimeToWait -= (DWORD)(TimeNow - StartTime);  // recalculate time now
  656.             StartTime   = TimeNow;                // reset start time also
  657.         } // end of while ( TimeToWait > 0)
  658.     } // for (RoundNum = 0; RoundNum < nInformsToSend ; RoundNum ++ )
  659.   Cleanup:
  660.     CloseDhcpSocket(DhcpContext);
  661.     if( MessageCount ) Error = ERROR_SUCCESS;
  662.     DhcpPrint(("SendInformAndGetReplies: got %d ACKS (returning %ld)n", MessageCount,Error));
  663.     return Error;
  664. }
  665. //--------------------------------------------------------------------------------
  666. //  This function gets the options from the server using DHCP_INFORM message.
  667. //  It picks the first ACK and then processes it.
  668. //  It ignores any errors caused by TIME_OUTS as that only means there is no
  669. //  server, or the server does not have this functionality.  No point giving up
  670. //  because of that.
  671. //--------------------------------------------------------------------------------
  672. BOOL                                              // win32 status
  673. DhcpDoInform(                                     // send an inform packet if necessary
  674.     IN      CAdapterInterface *    pAdapterInterface,
  675.     IN      BOOL                   fBroadcast,    // Do we broadcast this inform, or unicast to server?
  676.     OUT     LPSTR                  lpszAutoProxyUrl,
  677.     IN      DWORD                  dwAutoProxyUrlLength
  678. ) {
  679.     DHCP_CONTEXT                   StackDhcpContext;   // input context to do inform on
  680.     PDHCP_CONTEXT                  DhcpContext = &StackDhcpContext;
  681.     DWORD                          Error;
  682.     DWORD                          LocalError;
  683.     BOOL                           WasPlumbedBefore;
  684.     time_t                         OldT2Time;
  685.     DHCP_EXPECTED_OPTIONS          ExpectedOptions;
  686.     *lpszAutoProxyUrl = '';
  687.            
  688.     if ( ! pAdapterInterface->IsDhcp() ) {
  689.         return FALSE;
  690.     }
  691.     if (! pAdapterInterface->CopyAdapterInfoToDhcpContext(DhcpContext) ) {
  692.         return FALSE;
  693.     }
  694.    
  695.     // mdhcp uses INADDR_ANY so it does not have to have an ipaddress.
  696.     if( 0 == DhcpContext->IpAddress && !IS_MDHCP_CTX( DhcpContext) ) {
  697.         DhcpPrint(("Cannot do DhcpInform on an adapter without ip address!n"));
  698.         return FALSE;
  699.     }
  700.     // Open the socket ahead... so that things work. Tricky, else does not work!!!
  701.     if((Error = OpenDhcpSocket(DhcpContext)) != ERROR_SUCCESS ) {
  702.         DhcpPrint(("Could not open socket (%ld)n", Error));
  703.         return FALSE;
  704.     }
  705.     // If you always need to broadcast this message, the KLUDGE is to
  706.     // set pContext->T2Time = 0; and pContext->fFlags &= ~DHCP_CONTEXT_FLAGS_PLUMBED
  707.     // and that should do the trick! Safe to change the struct as it was cloned.
  708.     OldT2Time = DhcpContext->T2Time;
  709.     WasPlumbedBefore = IS_ADDRESS_PLUMBED(DhcpContext);
  710.     if(fBroadcast) {
  711.         DhcpContext->T2Time = 0; // !!!! KLUDGE.. look at SendDhcpMessage to understand this ..
  712.         ADDRESS_UNPLUMBED(DhcpContext);
  713.         CONNECTION_BROADCAST(DhcpContext);
  714.     } else {
  715.         DhcpContext->T2Time = (-1);
  716.     }
  717.     memset((void *) &ExpectedOptions, 0, sizeof(DHCP_EXPECTED_OPTIONS));
  718.     Error = SendInformAndGetReplies(              // get replies on this
  719.         DhcpContext,                              // context to send on
  720.         2,                                        // send atmost 2 informs
  721.         1,                                        // wait for as many as 4 packets..
  722.         &ExpectedOptions
  723.     );
  724.     DhcpContext->LastInformSent = time(NULL);     // record when the last inform was sent
  725.     DhcpContext->T2Time = OldT2Time;
  726.     if( WasPlumbedBefore ) ADDRESS_PLUMBED(DhcpContext);
  727.     LocalError = CloseDhcpSocket(DhcpContext);
  728.     DhcpAssert(ERROR_SUCCESS == LocalError);
  729.     if( ERROR_SUCCESS != Error ) {
  730.         DhcpPrint(("DhcpDoInform:return [0x%lx]n", Error));
  731.     }
  732.     else
  733.     {
  734.         //
  735.         // Did we actually get a response with an URL that can be used ? 
  736.         //
  737.         if ( ExpectedOptions.WpadUrl && 
  738.              ExpectedOptions.WpadUrlSize > 0 &&
  739.              dwAutoProxyUrlLength > ExpectedOptions.WpadUrlSize )
  740.         {
  741.             memcpy(lpszAutoProxyUrl, ExpectedOptions.WpadUrl, ExpectedOptions.WpadUrlSize );
  742.             return TRUE;
  743.         }            
  744.     }
  745.     return FALSE;
  746. }
  747. DWORD
  748. SendDhcpMessage(
  749.     PDHCP_CONTEXT DhcpContext,
  750.     DWORD MessageLength,
  751.     PDWORD TransactionId
  752.     )
  753. /*++
  754. Routine Description:
  755.     This function sends a UDP message to the DHCP server specified
  756.     in the DhcpContext.
  757. Arguments:
  758.     DhcpContext - A pointer to a DHCP context block.
  759.     MessageLength - The length of the message to send.
  760.     TransactionID - The transaction ID for this message.  If 0, the
  761.         function generates a random ID, and returns it.
  762. Return Value:
  763.     The status of the operation.
  764. --*/
  765. {
  766.     DWORD error;
  767.     int i;
  768.     struct sockaddr_in socketName;
  769.     time_t TimeNow;
  770.     BOOL   LockedInterface = FALSE;
  771.     if ( *TransactionId == 0 ) {
  772.         *TransactionId = (rand() << 16) + rand();
  773.     }
  774.     DhcpContext->MessageBuffer->TransactionID = *TransactionId;
  775.     //
  776.     // Initialize the outgoing address.
  777.     //
  778.     socketName.sin_family = PF_INET;
  779.     socketName.sin_port = _I_htons( DHCP_SERVR_PORT );
  780.     if ( IS_MDHCP_CTX(DhcpContext) ) {
  781.         socketName.sin_addr.s_addr = DhcpContext->DhcpServerAddress;
  782.         if ( CLASSD_NET_ADDR( DhcpContext->DhcpServerAddress ) ) {
  783.             int   TTL = 16;
  784.             //
  785.             // Set TTL
  786.             // MBUG: we need to read this from the registry.
  787.             //
  788.             if (_I_setsockopt(
  789.                   DhcpContext->Socket,
  790.                   IPPROTO_IP,
  791.                   IP_MULTICAST_TTL,
  792.                   (char *)&TTL,
  793.                   sizeof((int)TTL)) == SOCKET_ERROR){
  794.                  error = _I_WSAGetLastError();
  795.                  DhcpPrint(("could not set MCast TTL %ldn",error ));
  796.                  return error;
  797.             }
  798.         }
  799.     } else if( IS_ADDRESS_PLUMBED(DhcpContext) &&
  800.                !IS_MEDIA_RECONNECTED(DhcpContext) &&    // media reconnect - braodcast
  801.                !IS_POWER_RESUMED(DhcpContext) ) {       // power resumed - broadcast
  802.         //
  803.         // If we are past T2, use the broadcast address; otherwise,
  804.         // direct this to the server.
  805.         //
  806.         TimeNow = time( NULL );
  807.         // BUGBUG why did we broadcast here before ?
  808.         if ( TimeNow > DhcpContext->T2Time && IS_CONNECTION_BROADCAST(DhcpContext)) {
  809.             socketName.sin_addr.s_addr = (DHCP_IP_ADDRESS)(INADDR_BROADCAST);
  810.         } else {
  811.             socketName.sin_addr.s_addr = DhcpContext->DhcpServerAddress;
  812.         }
  813.     }
  814.     else {
  815.         socketName.sin_addr.s_addr = (DHCP_IP_ADDRESS)(INADDR_BROADCAST);
  816.         INET_ASSERT(FALSE);
  817.     }
  818.     for ( i = 0; i < 8 ; i++ ) {
  819.         socketName.sin_zero[i] = 0;
  820.     }
  821.     if( socketName.sin_addr.s_addr ==
  822.             (DHCP_IP_ADDRESS)(INADDR_BROADCAST) ) {
  823.         DWORD Error = ERROR_SUCCESS;
  824.         DWORD InterfaceId;
  825.         //
  826.         // BUGBUG TODO [arthurbi] This code below is needed for 
  827.         //  Broadcasts to work.  We need to make some fancy driver
  828.         //  calls to work...
  829.         //
  830.         //
  831.         // if we broadcast a message, inform IP stack - the adapter we
  832.         // like to send this broadcast on, otherwise it will pick up the
  833.         // first uninitialized adapter.
  834.         //
  835. //        InterfaceId = DhcpContext->IpInterfaceContext;            
  836. //
  837. //        if( !IPSetInterface( InterfaceId ) ) {
  838. //            // DhcpAssert( FALSE );
  839. //            Error = ERROR_GEN_FAILURE;
  840. //        }
  841. //        InterfaceId = ((PLOCAL_CONTEXT_INFO)
  842. //            DhcpContext->LocalInformation)->IpInterfaceContext;
  843. //
  844. //        LOCK_INTERFACE();
  845. //        LockedInterface = TRUE;
  846. //        Error = IPSetInterface( InterfaceId );
  847.         // DhcpAssert( Error == ERROR_SUCCESS );
  848.         if( ERROR_SUCCESS != Error ) {
  849.             DhcpPrint(("IPSetInterface failed with %lx errorn", Error));
  850.             UNLOCK_INTERFACE();
  851.             return Error;
  852.         }
  853.     }
  854.     //
  855.     // send minimum DHCP_MIN_SEND_RECV_PK_SIZE (300) bytes, otherwise
  856.     // bootp relay agents don't like the packet.
  857.     //
  858.     MessageLength = (MessageLength > DHCP_MIN_SEND_RECV_PK_SIZE) ?
  859.                         MessageLength : DHCP_MIN_SEND_RECV_PK_SIZE;
  860.     error = _I_sendto(
  861.                 DhcpContext->Socket,
  862.                 (PCHAR)DhcpContext->MessageBuffer,
  863.                 MessageLength,
  864.                 0,
  865.                 (struct sockaddr *)&socketName,
  866.                 sizeof( struct sockaddr )
  867.                 );
  868. #ifndef VXD
  869.     if( LockedInterface ) { UNLOCK_INTERFACE(); }
  870. #endif  VXD
  871.     if ( error == SOCKET_ERROR ) {
  872.         error = _I_WSAGetLastError();
  873.         DhcpPrint(("Send failed, error = %ldn", error ));
  874.     } else {
  875.         IF_DEBUG( PROTOCOL ) {
  876.             DhcpPrint(("Sent message to %s: n", _I_inet_ntoa( socketName.sin_addr )));
  877.         }
  878.         DhcpDumpMessage( DEBUG_PROTOCOL_DUMP, DhcpContext->MessageBuffer );
  879.         error = NO_ERROR;
  880.     }
  881.     return( error );
  882. }
  883. DWORD
  884. OpenDhcpSocket(
  885.     PDHCP_CONTEXT DhcpContext
  886.     )
  887. {
  888.     DWORD Error;
  889.     PLOCAL_CONTEXT_INFO localInfo;
  890.     if ( DhcpContext->Socket != INVALID_SOCKET ) {
  891.         return ( ERROR_SUCCESS );
  892.     }
  893.     //
  894.     // create a socket for the dhcp protocol.  it's important to bind the
  895.     // socket to the correct ip address.  There are currently three cases:
  896.     //
  897.     // 1.  If the interface has been autoconfigured, it already has an address,
  898.     //     say, IP1.  If the client receives a unicast offer from a dhcp server
  899.     //     the offer will be addressed to IP2, which is the client's new dhcp
  900.     //     address.  If we bind the dhcp socket to IP1, the client won't be able
  901.     //     to receive unicast responses.  So, we bind the socket to 0.0.0.0.
  902.     //     This will allow the socket to receive a unicast datagram addressed to
  903.     //     any address.
  904.     //
  905.     // 2.  If the interface in not plumbed (i.e. doesn't have an address) bind
  906.     //     the socket to 0.0.0.0
  907.     //
  908.     // 3.  If the interface has been plumbed has in *not* autoconfigured, then
  909.     //     bind to the current address.
  910.     Error =  InitializeDhcpSocket(
  911.                  &DhcpContext->Socket,
  912.                  DhcpContext->IpAddress 
  913.                  );
  914.     if( Error != ERROR_SUCCESS ) {
  915.         DhcpContext->Socket = INVALID_SOCKET;
  916.         DhcpPrint((" Socket Open failed, %ldn", Error ));
  917.     }
  918.     return(Error);
  919. }
  920. DWORD
  921. CloseDhcpSocket(
  922.     PDHCP_CONTEXT DhcpContext
  923.     )
  924. {
  925.     DWORD Error = ERROR_SUCCESS;
  926.     if( DhcpContext->Socket != INVALID_SOCKET ) {
  927.         BOOL Bool;
  928.         Error = _I_closesocket( DhcpContext->Socket );
  929.         if( Error != ERROR_SUCCESS ) {
  930.             DhcpPrint((" Socket close failed, %ldn", Error ));
  931.         }
  932.         DhcpContext->Socket = INVALID_SOCKET;
  933.         //
  934.         // Reset the IP stack to send DHCP broadcast to first
  935.         // uninitialized stack.
  936.         //
  937.         //Bool = IPResetInterface();
  938.         //DhcpAssert( Bool == TRUE );
  939.     }
  940.     return( Error );
  941. }
  942. typedef     struct  /* anonymous */ {             // structure to hold waiting recvfroms
  943.     LIST_ENTRY                     RecvList;      // other elements in this list
  944.     PDHCP_CONTEXT                  Ctxt;          // which context is this wait for?
  945.     DWORD                          InBufLen;      // what was the buffer size to recv in?
  946.     PDWORD                         BufLen;        // how many bytes did we recvd?
  947.     DWORD                          Xid;           // what xid is this wait for?
  948.     time_t                         ExpTime;       // wait until what time?
  949.     HANDLE                         WaitEvent;     // event for waiting on..
  950.     BOOL                           Recd;          // was a packet received..?
  951. } RECV_CTXT, *PRECV_CTXT;                         // ctxt used to recv on..
  952. VOID
  953. InsertInPriorityList(                             // insert in priority list according to Secs
  954.     IN OUT  PRECV_CTXT             Ctxt,          // Secs field changed to hold offset
  955.     IN      PLIST_ENTRY            List,
  956.     OUT     PBOOL                  First          // adding in first location?
  957. )
  958. {
  959.     PRECV_CTXT                     ThisCtxt;
  960.     PLIST_ENTRY                    InitList;      // "List" param at function entry
  961.     if( IsListEmpty(List) ) {                     // no element in list? add this and quit
  962.         *First = TRUE;                            // adding at head
  963.     } else {
  964.         *First = FALSE;                           // adding at tail..
  965.     }
  966.     InsertTailList( List, &Ctxt->RecvList);       // insert element..
  967.     //LeaveCriticalSection( &DhcpGlobalRecvFromCritSect );
  968. }
  969. DWORD
  970. TryReceive(                                       // try to recv pkt on 0.0.0.0 socket
  971.     IN      SOCKET                 Socket,        // socket to recv on
  972.     IN      LPBYTE                 Buffer,        // buffer to fill
  973.     OUT     PDWORD                 BufLen,        // # of bytes filled in buffer
  974.     OUT     PDWORD                 Xid,           // Xid of recd pkt
  975.     IN      DWORD                  Secs           // # of secs to spend waiting?
  976. )
  977. {
  978.     DWORD                          Error;
  979.     struct timeval                 timeout;
  980.     fd_set                         SockSet;
  981.     struct sockaddr                SockName;
  982.     int                            SockNameSize;
  983.     FD_ZERO(&SockSet);
  984.     FD_SET(Socket,&SockSet);
  985.     SockNameSize = sizeof( SockName );
  986.     timeout.tv_sec = Secs;
  987.     timeout.tv_usec = 0;
  988.     DhcpPrint(("Select: waiting for: %ld secondsn", Secs));
  989.     Error = _I_select( 0, &SockSet, NULL, NULL, &timeout );
  990.     if( ERROR_SUCCESS == Error ) {            // timed out..
  991.         DhcpPrint(("Recv timed out..n"));
  992.         return ERROR_SEM_TIMEOUT;
  993.     }
  994.     Error = _I_recvfrom(Socket,(char *)Buffer,*BufLen, 0, &SockName, &SockNameSize);
  995.     if( SOCKET_ERROR == Error ) {
  996.         Error = _I_WSAGetLastError();
  997.         DhcpPrint(("Recv failed 0x%lxn",Error));
  998.     } else {
  999.         *BufLen = Error;
  1000.         Error = ERROR_SUCCESS;
  1001.         *Xid = ((PDHCP_MESSAGE)Buffer)->TransactionID;
  1002.         DhcpPrint(("Recd msg XID: 0x%lx [Mdhcp? %s]n", *Xid,
  1003.                    IS_MDHCP_MESSAGE(((PDHCP_MESSAGE)Buffer))?"yes":"no" ));
  1004.     }
  1005.     return Error;
  1006. }
  1007. VOID
  1008. DispatchPkt(                                      // find out any takers for Xid
  1009.     IN OUT  PRECV_CTXT             Ctxt,          // ctxt that has buffer and buflen
  1010.     IN      DWORD                  Xid            // recd Xid
  1011. )
  1012. {
  1013.     do {                                          // not a loop, just for ease of use
  1014.         LPBYTE                     Tmp;
  1015.         PLIST_ENTRY                Entry;
  1016.         PRECV_CTXT                 ThisCtxt;
  1017.         Entry = DhcpGlobalRecvFromList.Flink;
  1018.         while(Entry != &DhcpGlobalRecvFromList ) {
  1019.             ThisCtxt = CONTAINING_RECORD(Entry, RECV_CTXT, RecvList);
  1020.             Entry = Entry->Flink;
  1021.             if(Xid != ThisCtxt->Xid ) continue;   // mismatch.. nothing more todo
  1022.             // now check for same type of message and ctxt...
  1023.             if( (unsigned)IS_MDHCP_MESSAGE((Ctxt->Ctxt->MessageBuffer))
  1024.                 !=
  1025.                 IS_MDHCP_CTX( (ThisCtxt->Ctxt) )
  1026.             ) {
  1027.                 //
  1028.                 // The contexts dont match.. give up
  1029.                 //
  1030.                 continue;
  1031.             }
  1032.             //
  1033.             // check for same hardware address..
  1034.             //
  1035.             if( ThisCtxt->Ctxt->HardwareAddressLength != Ctxt->Ctxt->MessageBuffer->HardwareAddressLength ) {
  1036.                 continue;
  1037.             }
  1038.             if( 0 != memcmp(ThisCtxt->Ctxt->HardwareAddress,
  1039.                             Ctxt->Ctxt->MessageBuffer->HardwareAddress,
  1040.                             ThisCtxt->Ctxt->HardwareAddressLength
  1041.             ) ) {
  1042.                 continue;
  1043.             }
  1044.             // matched.. switch buffers to give this guy this due..
  1045.             DhcpDumpMessage(DEBUG_PROTOCOL_DUMP, (PDHCP_MESSAGE)(Ctxt->Ctxt->MessageBuffer) );
  1046.             *(ThisCtxt->BufLen) = *(Ctxt->BufLen);
  1047.             Tmp = (LPBYTE)(Ctxt->Ctxt)->MessageBuffer;
  1048.             (Ctxt->Ctxt)->MessageBuffer = (ThisCtxt->Ctxt)->MessageBuffer;
  1049.             (ThisCtxt->Ctxt)->MessageBuffer = (PDHCP_MESSAGE)Tmp;
  1050.             RemoveEntryList(&ThisCtxt->RecvList);
  1051.             InitializeListHead(&ThisCtxt->RecvList);
  1052.             DhcpAssert(FALSE == ThisCtxt->Recd);
  1053.             ThisCtxt->Recd = TRUE;
  1054.             if( 0 == SetEvent(ThisCtxt->WaitEvent) ) {
  1055.                 DhcpAssert(FALSE);
  1056.             }
  1057.             break;
  1058.         }
  1059.     } while (FALSE);
  1060.     //LeaveCriticalSection(&DhcpGlobalRecvFromCritSect);
  1061. }
  1062. DWORD
  1063. ProcessRecvFromSocket(                            // wait using select and process incoming pkts
  1064.     IN OUT  PRECV_CTXT             Ctxt           // ctxt to use
  1065. )
  1066. {
  1067.     time_t                         TimeNow;
  1068.     SOCKET                         Socket;
  1069.     LPBYTE                         Buffer;
  1070.     DWORD                          Xid;
  1071.     DWORD                          Error;
  1072.     PLIST_ENTRY                    Entry;
  1073.     Socket = (Ctxt->Ctxt)->Socket;
  1074.     TimeNow = time(NULL);
  1075.     Error = ERROR_SEM_TIMEOUT;
  1076.     while(TimeNow <= Ctxt->ExpTime ) {            // while required to wait
  1077.         Buffer = (LPBYTE)((Ctxt->Ctxt)->MessageBuffer);
  1078.         *(Ctxt->BufLen) = Ctxt->InBufLen;
  1079.         Error = TryReceive(Socket, Buffer, Ctxt->BufLen, &Xid, (DWORD)(Ctxt->ExpTime - TimeNow));
  1080.         if( ERROR_SUCCESS != Error ) {            // did not recv?
  1081.             if( WSAECONNRESET != Error ) break;   // ignore possibly spurious conn-resets..
  1082.             else {  TimeNow = time(NULL); continue; }
  1083.         }
  1084.         if( Xid == Ctxt->Xid ) break;             // this was destined for this ctxt only..
  1085.         DispatchPkt(Ctxt, Xid);
  1086.         TimeNow = time(NULL);
  1087.     }
  1088.     if( TimeNow > Ctxt->ExpTime ) {               // we timed out.
  1089.         Error = ERROR_SEM_TIMEOUT;
  1090.     }
  1091.     // now done.. so we must remove this ctxt from the list and signal first guy
  1092.     //EnterCriticalSection(&DhcpGlobalRecvFromCritSect);
  1093.     RemoveEntryList(&Ctxt->RecvList);
  1094.     CloseHandle(Ctxt->WaitEvent);
  1095.     if( !IsListEmpty(&DhcpGlobalRecvFromList)) {  // ok got an elt.. signal this.
  1096.         Entry = DhcpGlobalRecvFromList.Flink;
  1097.         Ctxt = CONTAINING_RECORD(Entry, RECV_CTXT, RecvList);
  1098.         if( 0 == SetEvent(Ctxt->WaitEvent) ) {
  1099.             DhcpAssert(FALSE);
  1100.         }
  1101.     }
  1102.     //LeaveCriticalSection(&DhcpGlobalRecvFromCritSect);
  1103.     return Error;
  1104. }
  1105. //================================================================================
  1106. //  get dhcp message with requested transaction id, but also make sure only one
  1107. //  socket is used at any given time (one socket bound to 0.0.0.0), and also
  1108. //  re-distribute message for some other thread if that is also required..
  1109. //================================================================================
  1110. DWORD
  1111. GetSpecifiedDhcpMessageEx(
  1112.     IN OUT  PDHCP_CONTEXT          DhcpContext,   // which context to recv for
  1113.     OUT     PDWORD                 BufferLength,  // how big a buffer was read?
  1114.     IN      DWORD                  Xid,           // which xid to look for?
  1115.     IN      DWORD                  TimeToWait     // how many seconds to sleep?
  1116. )
  1117. {
  1118.     RECV_CTXT                      Ctxt;          // element in list for this call to getspe..
  1119.     BOOL                           First;         // is this the first element in list?
  1120.     DWORD                          Result;
  1121.     Ctxt.Ctxt = DhcpContext;                      // fill in the context
  1122.     Ctxt.InBufLen = *BufferLength;
  1123.     Ctxt.BufLen = BufferLength;
  1124.     Ctxt.Xid = Xid;
  1125.     Ctxt.ExpTime = time(NULL) + TimeToWait;
  1126.     Ctxt.WaitEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  1127.     Ctxt.Recd = FALSE;
  1128.     if( NULL == Ctxt.WaitEvent ) {
  1129.         DhcpAssert(NULL != Ctxt.WaitEvent);
  1130.         return GetLastError();
  1131.     }
  1132.     First = FALSE;
  1133.     InsertInPriorityList(&Ctxt, &DhcpGlobalRecvFromList, &First);
  1134.     if( First ) {                                 // this *is* the first call to GetSpec..
  1135.         Result = ProcessRecvFromSocket(&Ctxt);
  1136.     } else {                                      // we wait for other calls to go thru..
  1137.         Result = WaitForSingleObject(Ctxt.WaitEvent, TimeToWait * 1000);
  1138.         //EnterCriticalSection(&DhcpGlobalRecvFromCritSect);
  1139.         if( Ctxt.Recd || WAIT_FAILED == Result || WAIT_TIMEOUT == Result ) {
  1140.             if( WAIT_FAILED == Result ) Result = GetLastError();
  1141.             else if (WAIT_TIMEOUT == Result ) Result = ERROR_SEM_TIMEOUT;
  1142.             else Result = ERROR_SUCCESS;
  1143.             RemoveEntryList(&Ctxt.RecvList);      // remove it from list
  1144.             //LeaveCriticalSection(&DhcpGlobalRecvFromCritSect);
  1145.             CloseHandle(Ctxt.WaitEvent);
  1146.             return Result;
  1147.         } else {
  1148.             DhcpAssert(WAIT_OBJECT_0 == Result && Ctxt.Recd == FALSE );
  1149.             // have not received a packet but have been woken up? must be first in line now..
  1150.             //LeaveCriticalSection(&DhcpGlobalRecvFromCritSect);
  1151.             Result = ProcessRecvFromSocket(&Ctxt);
  1152.         }
  1153.     }
  1154.     return Result;
  1155. }
  1156. #define RATIO 1
  1157. DWORD
  1158. GetSpecifiedDhcpMessage(
  1159.     PDHCP_CONTEXT DhcpContext,
  1160.     PDWORD BufferLength,
  1161.     DWORD TransactionId,
  1162.     DWORD TimeToWait
  1163.     )
  1164. /*++
  1165. Routine Description:
  1166.     This function waits TimeToWait seconds to receives the specified
  1167.     DHCP response.
  1168. Arguments:
  1169.     DhcpContext - A pointer to a DHCP context block.
  1170.     BufferLength - Returns the size of the input buffer.
  1171.     TransactionID - A filter.  Wait for a message with this TID.
  1172.     TimeToWait - Time, in milli seconds, to wait for the message.
  1173. Return Value:
  1174.     The status of the operation.  If the specified message has been
  1175.     been returned, the status is ERROR_TIMEOUT.
  1176. --*/
  1177. {
  1178.     struct sockaddr socketName;
  1179.     int socketNameSize = sizeof( socketName );
  1180.     struct timeval timeout;
  1181.     time_t startTime, now;
  1182.     DWORD error;
  1183.     DWORD actualTimeToWait;
  1184.     SOCKET clientSocket;
  1185.     fd_set readSocketSet;
  1186.     if( !IS_ADDRESS_PLUMBED(DhcpContext) ) {
  1187.         //
  1188.         // For RAS server Lease API this call won't happen as we don't have to do this nonsense
  1189.         //
  1190.         error = GetSpecifiedDhcpMessageEx(
  1191.             DhcpContext,
  1192.             BufferLength,
  1193.             TransactionId,
  1194.             TimeToWait
  1195.         );
  1196. if( ERROR_SUCCESS == error ) {
  1197.     // received a message frm the dhcp server..
  1198.             SERVER_REACHED(DhcpContext);
  1199. }
  1200. return error;
  1201.     }
  1202.     startTime = time( NULL );
  1203.     actualTimeToWait = TimeToWait;
  1204.     //
  1205.     // Setup the file descriptor set for select.
  1206.     //
  1207.     clientSocket = DhcpContext->Socket;
  1208.     FD_ZERO( &readSocketSet );
  1209.     FD_SET( clientSocket, &readSocketSet );
  1210.     while ( 1 ) {
  1211.         timeout.tv_sec  = actualTimeToWait / RATIO;
  1212.         timeout.tv_usec = actualTimeToWait % RATIO;
  1213.         DhcpPrint(("Select: waiting for: %ld secondsn", actualTimeToWait));
  1214.         error = _I_select( 0, &readSocketSet, NULL, NULL, &timeout );
  1215.         if ( error == 0 ) {
  1216.             //
  1217.             // Timeout before read data is available.
  1218.             //
  1219.             DhcpPrint(("Recv timed outn", 0 ));
  1220.             error = ERROR_SEM_TIMEOUT;
  1221.             break;
  1222.         }
  1223.         error = _I_recvfrom(
  1224.                     clientSocket,
  1225.                     (PCHAR)DhcpContext->MessageBuffer,
  1226.                     *BufferLength,
  1227.                     0,
  1228.                     &socketName,
  1229.                     &socketNameSize
  1230.                     );
  1231.         if ( error == SOCKET_ERROR ) {
  1232.             error = _I_WSAGetLastError();
  1233.             DhcpPrint(("Recv failed, error = %ldn", error ));
  1234.             if( WSAECONNRESET != error ) break;
  1235.             //
  1236.             // ignore connreset -- this could be caused by someone sending random ICMP port unreachable.
  1237.             //
  1238.         } else if (DhcpContext->MessageBuffer->TransactionID == TransactionId ) {
  1239.              
  1240.             DhcpPrint((  "Received Message, XID = %lx, MDhcp = %d.n",
  1241.                             TransactionId,
  1242.                             IS_MDHCP_MESSAGE( DhcpContext->MessageBuffer) ));
  1243.             if (((unsigned)IS_MDHCP_MESSAGE( DhcpContext->MessageBuffer) == IS_MDHCP_CTX( DhcpContext))) {
  1244.                 DhcpDumpMessage(DEBUG_PROTOCOL_DUMP, DhcpContext->MessageBuffer );
  1245.                 *BufferLength = error;
  1246.                 error = NO_ERROR;
  1247.                 if( DhcpContext->MessageBuffer->HardwareAddressLength == DhcpContext->HardwareAddressLength
  1248.                     && 0 == memcmp(DhcpContext->MessageBuffer->HardwareAddress,
  1249.                                    DhcpContext->HardwareAddress,
  1250.                                    DhcpContext->HardwareAddressLength
  1251.                     )) {
  1252.                     //
  1253.                     // Transction IDs match, same type (MDHCP/DHCP), Hardware addresses match!
  1254.                     //
  1255.                     break;
  1256.                 }
  1257.             }
  1258.         } else {            
  1259.             DhcpPrint(( "Received a buffer with unknown XID = %lxn",
  1260.                          DhcpContext->MessageBuffer->TransactionID ));
  1261.         }
  1262.         //
  1263.         // We received a message, but not the one we're interested in.
  1264.         // Reset the timeout to reflect elapsed time, and wait for
  1265.         // another message.
  1266.         //
  1267.         now = time( NULL );
  1268.         actualTimeToWait = (DWORD)(TimeToWait - RATIO * (now - startTime));
  1269.         if ( (LONG)actualTimeToWait < 0 ) {
  1270.             error = ERROR_SEM_TIMEOUT;
  1271.             break;
  1272.         }
  1273.     }
  1274.     if ( ERROR_SEM_TIMEOUT != error )
  1275.     {
  1276.         //
  1277.         // a message was received from a DHCP server.  disable IP autoconfiguration.
  1278.         //
  1279.         SERVER_REACHED(DhcpContext);
  1280.     }
  1281.     return( error );
  1282. }
  1283. DWORD 
  1284. QueryWellKnownDnsName(
  1285.     IN OUT LPSTR lpszAutoProxyUrl,
  1286.     IN     DWORD dwAutoProxyUrlLength
  1287.     )
  1288. /*++
  1289. Routine Description:
  1290.     This function walks a list of standard DNS names trying to find
  1291.      an entry for "wpad.some-domain-here.org"  If it does, it constructs
  1292.      an URL that is suitable for use in auto-proxy.
  1293. Arguments:
  1294.     lpszAutoProxyUrl - Url used to return a successful auto-proxy discover
  1295.     dwAutoProxyUrlLength - length of buffer passed in above
  1296. Return Value:
  1297.         
  1298.     ERROR_SUCCESS - if we found a URL/DNS name
  1299.     ERROR_NOT_FOUND - on error
  1300. revised: joshco 7-oct-1998
  1301.   if we dont get a valid domain back, be sure and try
  1302.   the netbios name ("wpad") no trailing dot.
  1303.   revised: joshco 7-oct-1998
  1304.    use the define PROXY_AUTO_DETECT_PATH instead
  1305.    of hardcoding "wpad.dat"
  1306.   
  1307. --*/
  1308. {
  1309. #define WORK_BUFFER_SIZE 356
  1310.     DEBUG_ENTER((DBG_SOCKETS,
  1311.                  Dword,
  1312.                  "QueryWellKnownDnsName",
  1313.                  "%x, %u",
  1314.                  lpszAutoProxyUrl,
  1315.                  dwAutoProxyUrlLength                 
  1316.                  ));
  1317.     char szHostDomain[WORK_BUFFER_SIZE];
  1318.     char * pszTemp = szHostDomain ;
  1319.     char *pszDot1 = NULL;
  1320.     char *pszDot2 = NULL;
  1321.     DWORD error = ERROR_NOT_FOUND;
  1322.     DWORD dwMinDomain = 2;  //  By default, assume domain is of the form: .domain-name.org
  1323.     lstrcpy(szHostDomain, "wpad.");
  1324.     pszTemp += (sizeof("wpad.") - 1);
  1325.     if ( SockGetSingleValue(CONFIG_DOMAIN,
  1326.                             (LPBYTE)pszTemp,
  1327.                             WORK_BUFFER_SIZE - sizeof("wpad.")
  1328.                             ) != ERROR_SUCCESS )
  1329.     {
  1330.         lstrcpy(szHostDomain, "wpad.");
  1331.         pszTemp = szHostDomain ;
  1332.         pszTemp += (sizeof("wpad.") - 1);
  1333.     }
  1334.     if ( (GetProxyDetectType() & PROXY_AUTO_DETECT_TYPE_NO_DOMAIN ) ||
  1335.          *pszTemp == '' ) 
  1336.     {
  1337.         // if the debug setting for no domain (netbios) or 
  1338.         // we didnt get back a valid domain, then just do the
  1339.         // netbios name.  
  1340.         // XXBUG sockgetsinglevalue returns true even if there is no domain
  1341.         INET_ASSERT(*(pszTemp  - 1 ) == '.');
  1342.         *(pszTemp - 1) = '';
  1343.     }
  1344.     // Now determine which form the domain name follows:
  1345.     //     domain-name.org
  1346.     //     domain-name.co.uk
  1347.     pszDot1 = &szHostDomain[lstrlen(szHostDomain)-1];
  1348.     while (pszDot1 >= szHostDomain && *pszDot1 != '.')
  1349.         pszDot1--;
  1350.     // Only check .?? endings
  1351.     if (pszDot1 >= szHostDomain && (pszDot1 + 3 == &szHostDomain[lstrlen(szHostDomain)]) )
  1352.     {
  1353.         pszDot2 = pszDot1 - 1;
  1354.         while (pszDot2 >= szHostDomain && *pszDot2 != '.')
  1355.            pszDot2--;
  1356.    
  1357.         if (pszDot2 >= szHostDomain && pszDot2 + 3 >= pszDot1)
  1358.         {
  1359.            // Domain ended in something of the form: .co.uk
  1360.            // This requires at least 3 pieces then to be considered a domain
  1361.            dwMinDomain = 3;
  1362.         }
  1363.         else if ((pszDot2 + 4) == pszDot1)
  1364.         {
  1365.             // Check domain endings of the form ending in .com.uk
  1366.             // These special 3-letter pieces also need 3 dots to be classified
  1367.             // as a domain.  Unfortunately, we can't leverage the equivalent
  1368.             // code used by cookies because there, the strings are reversed.
  1369.             static const char *s_pachSpecialDomains[] = {"COM", "EDU", "NET", "ORG", "GOV", "MIL", "INT" };
  1370.             for (int i=0; i < ARRAY_ELEMENTS(s_pachSpecialDomains); i++)
  1371.             {
  1372.                 if (StrCmpNIC(pszDot2+1, s_pachSpecialDomains[i], 3) == 0)
  1373.                 {
  1374.                     dwMinDomain = 3;
  1375.                     break;
  1376.                 }
  1377.             }
  1378.         }
  1379.     }
  1380.     while (TRUE)
  1381.     {
  1382.         PHOSTENT lpHostent = _I_gethostbyname(szHostDomain);
  1383.         if ( lpHostent != NULL )
  1384.         {
  1385.             //
  1386.             // Found a host, extract the IP address and form an URL to use.
  1387.             //
  1388.             char *pszAddressStr;
  1389.             LPBYTE * addressList;
  1390.             struct  in_addr sin_addr;
  1391.             DWORD dwIPAddressSize;
  1392.             addressList         = (LPBYTE *)lpHostent->h_addr_list;
  1393.             *(LPDWORD)&sin_addr = *(LPDWORD)addressList[0] ;
  1394.             pszAddressStr = _I_inet_ntoa (sin_addr);
  1395.             INET_ASSERT(pszAddressStr);
  1396.             dwIPAddressSize = lstrlen(pszAddressStr);
  1397.             if ( dwAutoProxyUrlLength < (dwIPAddressSize + 
  1398.               sizeof("http:///") + sizeof(PROXY_AUTO_DETECT_PATH) )  )
  1399.             {
  1400.                 error = ERROR_INSUFFICIENT_BUFFER;
  1401.                 goto quit;
  1402.             }
  1403.             wsprintf(lpszAutoProxyUrl, "http://%s/%s", pszAddressStr, PROXY_AUTO_DETECT_PATH );
  1404.             error = ERROR_SUCCESS;
  1405.             goto quit;
  1406.         }
  1407.         else
  1408.         {
  1409.             //
  1410.             // Did not find anything yet, reduce the domain level, 
  1411.             //  and if we're in the root domain stop and return error
  1412.             //
  1413.             DWORD dwPeriodCnt = 0, dwNewEndLength = 0;
  1414.             LPSTR lpszPeriod1 = NULL, lpszPeriod2 = NULL;
  1415.             for (pszTemp = szHostDomain; *pszTemp; pszTemp++ )
  1416.             {
  1417.                 if ( *pszTemp == '.' ) {
  1418.                     dwPeriodCnt ++;
  1419.                     if ( lpszPeriod1 == NULL ) {
  1420.                         lpszPeriod1 = pszTemp;
  1421.                     }
  1422.                     else if ( lpszPeriod2 == NULL ) {
  1423.                         lpszPeriod2 = pszTemp;
  1424.                     }
  1425.                 }
  1426.             }
  1427.             if ( dwPeriodCnt <= dwMinDomain) 
  1428.             {
  1429.                 error = ERROR_NOT_FOUND;
  1430.                 goto quit;
  1431.             }
  1432.             dwNewEndLength = lstrlen(lpszPeriod2);
  1433.             MoveMemory(lpszPeriod1, lpszPeriod2, dwNewEndLength);
  1434.             *(lpszPeriod1 + dwNewEndLength) = '';
  1435.         }
  1436.     }
  1437. quit:
  1438.     DEBUG_LEAVE(error);
  1439.     return error;    
  1440. }
  1441. //================================================================================
  1442. // End of file
  1443. //================================================================================