3605 lines
110 KiB
C
3605 lines
110 KiB
C
/* Copyright (c) 1993, Microsoft Corporation, all rights reserved
|
|
**
|
|
** rasipcp.c
|
|
** Remote Access PPP Internet Protocol Control Protocol
|
|
** Core routines
|
|
**
|
|
** 11/05/93 Steve Cobb
|
|
*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
|
|
|
|
#include <lmcons.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <llinfo.h>
|
|
#include <rasman.h>
|
|
#include <ddwanarp.h>
|
|
#include <rtutils.h>
|
|
#include <dhcpcapi.h>
|
|
#include <devioctl.h>
|
|
#include <rasppp.h>
|
|
#include <uiip.h>
|
|
#include <pppcp.h>
|
|
#define INCL_HOSTWIRE
|
|
#define INCL_PARAMBUF
|
|
#define INCL_RASAUTHATTRIBUTES
|
|
#include <ppputil.h>
|
|
#include <raserror.h>
|
|
#include <mprlog.h>
|
|
#include <dnsapi.h>
|
|
#include "rassrvr.h"
|
|
#include "tcpreg.h"
|
|
#include "helper.h"
|
|
#include "rastcp.h"
|
|
#define RASIPCPGLOBALS
|
|
#include "rasipcp.h"
|
|
|
|
#define REGKEY_Ipcp \
|
|
"SYSTEM\\CurrentControlSet\\Services\\RasMan\\PPP\\ControlProtocols\\BuiltIn"
|
|
#define REGKEY_Params "SYSTEM\\CurrentControlSet\\Services\\RemoteAccess\\Parameters\\IP"
|
|
#define REGKEY_Linkage "SYSTEM\\CurrentControlSet\\Services\\RemoteAccess\\Linkage"
|
|
#define REGKEY_Disabled "SYSTEM\\CurrentControlSet\\Services\\RemoteAccess\\Linkage\\Disabled"
|
|
#define REGVAL_NsAddrs "RequestNameServerAddresses"
|
|
#define REGVAL_Unnumbered "Unnumbered"
|
|
#define REGVAL_VjComp "RequestVJCompression"
|
|
#define REGVAL_VjComp2 "AcceptVJCompression"
|
|
#define REGVAL_AllowVJOverVPN "AllowVJOverVPN"
|
|
#define REGVAL_HardIp "AllowClientIPAddresses"
|
|
#define REGVAL_RegisterRoutersWithWINS "RegisterRoutersWithWINSServers"
|
|
#define REGVAL_Bind "Bind"
|
|
#define ID_NetBTNdisWan "NetBT_NdisWan"
|
|
|
|
// DHCP Options. (from dhcp.h)
|
|
// dhcp.h lives in the sockets project. These are standard and
|
|
// cannot change, so its safe to put them here.
|
|
|
|
#define OPTION_SUBNET_MASK 1
|
|
#define OPTION_DNS_NAME_SERVERS 6
|
|
#define OPTION_NETBIOS_NAME_SERVERS 44
|
|
#define OPTION_DNS_DOMAIN_NAME 15
|
|
#define OPTION_VENDOR_SPEC_INFO 43
|
|
//Route Plumbing option
|
|
#define OPTION_VENDOR_ROUTE_PLUMB 249
|
|
|
|
|
|
#define CLASSA_ADDR(a) (( (*((unsigned char *)&(a))) & 0x80) == 0)
|
|
#define CLASSB_ADDR(a) (( (*((unsigned char *)&(a))) & 0xc0) == 0x80)
|
|
#define CLASSC_ADDR(a) (( (*((unsigned char *)&(a))) & 0xe0) == 0xc0)
|
|
#define CLASSE_ADDR(a) ((( (*((uchar *)&(a))) & 0xf0) == 0xf0) && \
|
|
((a) != 0xffffffff))
|
|
|
|
/* Gurdeepian dword byte-swapping macro.
|
|
**
|
|
** Note that in this module all IP addresses are stored in on the net form
|
|
** which is the opposite of Intel format.
|
|
*/
|
|
#define net_long(x) (((((unsigned long)(x))&0xffL)<<24) | \
|
|
((((unsigned long)(x))&0xff00L)<<8) | \
|
|
((((unsigned long)(x))&0xff0000L)>>8) | \
|
|
((((unsigned long)(x))&0xff000000L)>>24))
|
|
|
|
typedef struct _IPCP_DHCP_INFORM
|
|
{
|
|
WCHAR* wszDevice;
|
|
HCONN hConnection;
|
|
BOOL fUseDhcpInformDomainName;
|
|
|
|
} IPCP_DHCP_INFORM;
|
|
|
|
/*---------------------------------------------------------------------------
|
|
** External entry points
|
|
**---------------------------------------------------------------------------
|
|
*/
|
|
|
|
DWORD
|
|
IpcpInit(
|
|
IN BOOL fInitialize)
|
|
|
|
/* Called to initialize/uninitialize this CP. In the former case,
|
|
** fInitialize will be TRUE; in the latter case, it will be FALSE.
|
|
*/
|
|
{
|
|
static DWORD dwRefCount = 0;
|
|
DWORD dwErr;
|
|
|
|
if (fInitialize)
|
|
{
|
|
if (0 == dwRefCount)
|
|
{
|
|
if ((dwErr = HelperInitialize(&HDhcpDll)) != NO_ERROR)
|
|
{
|
|
return(dwErr);
|
|
}
|
|
|
|
PDhcpRequestOptions = (DHCPREQUESTOPTIONS)
|
|
GetProcAddress(HDhcpDll, "DhcpRequestOptions");
|
|
|
|
if (NULL == PDhcpRequestOptions)
|
|
{
|
|
return(GetLastError());
|
|
}
|
|
|
|
PDhcpNotifyConfigChange2 = (DHCPNOTIFYCONFIGCHANGEEX)
|
|
GetProcAddress(HDhcpDll, "DhcpNotifyConfigChangeEx");
|
|
|
|
if (NULL == PDhcpNotifyConfigChange2)
|
|
{
|
|
return(GetLastError());
|
|
}
|
|
|
|
ClearTcpipInfo();
|
|
|
|
DwIpcpTraceId = TraceRegister("RASIPCP");
|
|
}
|
|
|
|
dwRefCount++;
|
|
}
|
|
else
|
|
{
|
|
dwRefCount--;
|
|
|
|
if (0 == dwRefCount)
|
|
{
|
|
HelperUninitialize();
|
|
// Ignore errors
|
|
|
|
HDhcpDll = NULL;
|
|
PDhcpRequestOptions = NULL;
|
|
PDhcpNotifyConfigChange2 = NULL;
|
|
|
|
if (HRasArp != INVALID_HANDLE_VALUE)
|
|
CloseHandle( HRasArp );
|
|
|
|
HRasArp = INVALID_HANDLE_VALUE;
|
|
|
|
TraceDeregister(DwIpcpTraceId);
|
|
DwIpcpTraceId = INVALID_TRACEID;
|
|
}
|
|
}
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
DWORD
|
|
IpcpGetInfo(
|
|
IN DWORD dwProtocolId,
|
|
OUT PPPCP_INFO* pInfo )
|
|
|
|
/* IpcpGetInfo entry point called by the PPP engine by name. See RasCp
|
|
** interface documentation.
|
|
*/
|
|
{
|
|
ZeroMemory( pInfo, sizeof(*pInfo) );
|
|
|
|
pInfo->Protocol = (DWORD )PPP_IPCP_PROTOCOL;
|
|
lstrcpy(pInfo->SzProtocolName, "IPCP");
|
|
pInfo->Recognize = 7;
|
|
pInfo->RasCpInit = IpcpInit;
|
|
pInfo->RasCpBegin = IpcpBegin;
|
|
pInfo->RasCpReset = IpcpReset;
|
|
pInfo->RasCpEnd = IpcpEnd;
|
|
pInfo->RasCpThisLayerFinished = IpcpThisLayerFinished;
|
|
pInfo->RasCpThisLayerUp = IpcpThisLayerUp;
|
|
pInfo->RasCpPreDisconnectCleanup = IpcpPreDisconnectCleanup;
|
|
pInfo->RasCpMakeConfigRequest = IpcpMakeConfigRequest;
|
|
pInfo->RasCpMakeConfigResult = IpcpMakeConfigResult;
|
|
pInfo->RasCpConfigAckReceived = IpcpConfigAckReceived;
|
|
pInfo->RasCpConfigNakReceived = IpcpConfigNakReceived;
|
|
pInfo->RasCpConfigRejReceived = IpcpConfigRejReceived;
|
|
pInfo->RasCpGetNegotiatedInfo = IpcpGetNegotiatedInfo;
|
|
pInfo->RasCpProjectionNotification = IpcpProjectionNotification;
|
|
pInfo->RasCpChangeNotification = IpcpChangeNotification;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD
|
|
IpcpChangeNotification(
|
|
VOID )
|
|
{
|
|
HelperChangeNotification();
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
DWORD
|
|
IpcpBegin(
|
|
OUT VOID** ppWorkBuf,
|
|
IN VOID* pInfo )
|
|
|
|
/* RasCpBegin entry point called by the PPP engine thru the passed
|
|
** address. See RasCp interface documentation.
|
|
*/
|
|
{
|
|
DWORD dwErr;
|
|
PPPCP_INIT* pInit = (PPPCP_INIT* )pInfo;
|
|
IPCPWB* pwb;
|
|
RAS_AUTH_ATTRIBUTE * pAttribute;
|
|
BOOL fVPN = FALSE;
|
|
BOOL fVJAttributePresent = FALSE;
|
|
|
|
TraceIp("IPCP: IpcpBegin");
|
|
|
|
/* Allocate work buffer.
|
|
*/
|
|
if (!(pwb = (IPCPWB* )LocalAlloc( LPTR, sizeof(IPCPWB) )))
|
|
{
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
pwb->fServer = pInit->fServer;
|
|
pwb->hport = pInit->hPort;
|
|
pwb->hConnection = pInit->hConnection;
|
|
pwb->hIPInterface = pInit->hInterface;
|
|
pwb->IfType = pInit->IfType;
|
|
pwb->fDisableNetbt = pInit->fDisableNetbt;
|
|
|
|
if (0 == MultiByteToWideChar(
|
|
CP_ACP,
|
|
0,
|
|
pInit->pszUserName,
|
|
-1,
|
|
pwb->wszUserName,
|
|
UNLEN+1 ) )
|
|
{
|
|
dwErr = GetLastError();
|
|
TraceIp("MultiByteToWideChar(%s) failed: %d",
|
|
pInit->pszUserName, dwErr);
|
|
LocalFree( pwb );
|
|
return( dwErr );
|
|
}
|
|
|
|
if (0 == MultiByteToWideChar(
|
|
CP_ACP,
|
|
0,
|
|
pInit->pszPortName,
|
|
-1,
|
|
pwb->wszPortName,
|
|
MAX_PORT_NAME+1 ) )
|
|
{
|
|
dwErr = GetLastError();
|
|
TraceIp("MultiByteToWideChar(%s) failed: %d",
|
|
pInit->pszPortName, dwErr);
|
|
LocalFree( pwb );
|
|
return( dwErr );
|
|
}
|
|
|
|
if ( pwb->fServer )
|
|
{
|
|
HKEY hkey;
|
|
DWORD dwType;
|
|
DWORD dwValue;
|
|
DWORD cb = sizeof(DWORD);
|
|
|
|
if (RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_Params, &hkey ) == 0)
|
|
{
|
|
if (RegQueryValueEx(
|
|
hkey, REGVAL_HardIp, NULL, &dwType,
|
|
(LPBYTE )&dwValue, &cb ) == 0
|
|
&& dwType == REG_DWORD
|
|
&& cb == sizeof(DWORD)
|
|
&& dwValue)
|
|
{
|
|
FClientMaySelectAddress = TRUE;
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
}
|
|
|
|
TraceIp("IPCP: Hard IP=%d",FClientMaySelectAddress);
|
|
|
|
pwb->IpAddressToHandout = ( FClientMaySelectAddress )
|
|
? net_long( 0xFFFFFFFF )
|
|
: net_long( 0xFFFFFFFE );
|
|
//
|
|
// Is there an IP address parameter ?
|
|
//
|
|
|
|
pAttribute = RasAuthAttributeGet( raatFramedIPAddress,
|
|
pInit->pAttributes );
|
|
|
|
if ( pAttribute != NULL )
|
|
{
|
|
pwb->IpAddressToHandout = net_long( PtrToUlong(pAttribute->Value) );
|
|
|
|
TraceIp("IPCP: Using IP address attribute 0x%x",
|
|
pwb->IpAddressToHandout );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We are a router or client dialing out, let other side always choose
|
|
// their address
|
|
//
|
|
|
|
pwb->IpAddressToHandout = net_long( 0xFFFFFFFF );
|
|
}
|
|
|
|
pwb->fRegisterWithWINS = 1;
|
|
|
|
if ( pwb->IfType == ROUTER_IF_TYPE_FULL_ROUTER )
|
|
{
|
|
HKEY hkey;
|
|
DWORD dwType;
|
|
DWORD dwValue;
|
|
DWORD cb = sizeof(DWORD);
|
|
|
|
pwb->fRegisterWithWINS = 0;
|
|
|
|
if (RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_Ipcp, &hkey ) == 0)
|
|
{
|
|
if (RegQueryValueEx(
|
|
hkey, REGVAL_RegisterRoutersWithWINS, NULL,
|
|
&dwType, (LPBYTE )&dwValue, &cb ) == 0
|
|
&& dwType == REG_DWORD
|
|
&& cb == sizeof(DWORD)
|
|
&& dwValue != 0)
|
|
{
|
|
TraceIp("IPCP: Will register routers with WINS");
|
|
pwb->fRegisterWithWINS = 1;
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
}
|
|
}
|
|
|
|
/* Allocate a route between the MAC and the TCP/IP stack.
|
|
*/
|
|
if ((dwErr = RasAllocateRoute(
|
|
pwb->hport, IP, !pwb->fServer, &pwb->routeinfo )) != 0)
|
|
{
|
|
TraceIp("IPCP: RasAllocateRoute=%d",dwErr);
|
|
LocalFree( (HLOCAL )pwb );
|
|
return dwErr;
|
|
}
|
|
|
|
/* Lookup the compression capabilities.
|
|
*/
|
|
if ((dwErr = RasPortGetProtocolCompression(
|
|
pwb->hport, IP, &pwb->rpcSend, &pwb->rpcReceive )) != 0)
|
|
{
|
|
TraceIp("IPCP: RasPortGetProtocolCompression=%d",dwErr);
|
|
pwb->dwErrInBegin = dwErr;
|
|
*ppWorkBuf = pwb;
|
|
return 0;
|
|
}
|
|
|
|
if (0 == pwb->rpcSend.RP_ProtocolType.RP_IP.RP_IPCompressionProtocol)
|
|
{
|
|
HKEY hkey;
|
|
DWORD dwType;
|
|
DWORD dwValue;
|
|
DWORD cb = sizeof(DWORD);
|
|
|
|
fVPN = TRUE;
|
|
|
|
if (RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_Ipcp, &hkey ) == 0)
|
|
{
|
|
/* VJ header compression is a history based scheme and since
|
|
we can't reliably detect lost frames over vpn's we have
|
|
dropped support for vj over vpn's.
|
|
*/
|
|
|
|
if (RegQueryValueEx(
|
|
hkey, REGVAL_AllowVJOverVPN, NULL,
|
|
&dwType, (LPBYTE )&dwValue, &cb ) == 0
|
|
&& dwType == REG_DWORD
|
|
&& cb == sizeof(DWORD)
|
|
&& dwValue == 1)
|
|
{
|
|
TraceIp("IPCP: AllowVJOverVPN is TRUE");
|
|
pwb->rpcSend.RP_ProtocolType.RP_IP.RP_IPCompressionProtocol = 0x2D;
|
|
pwb->rpcReceive.RP_ProtocolType.RP_IP.RP_IPCompressionProtocol = 0x2D;
|
|
fVPN = FALSE;
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
}
|
|
}
|
|
|
|
if ( pwb->fServer )
|
|
{
|
|
HANDLE hAttribute;
|
|
|
|
pAttribute = RasAuthAttributeGetFirst(raatFramedCompression,
|
|
pInit->pAttributes, &hAttribute );
|
|
|
|
while (NULL != pAttribute)
|
|
{
|
|
switch (PtrToUlong(pAttribute->Value))
|
|
{
|
|
case 0:
|
|
|
|
/* Don't request or accept VJ compression.
|
|
*/
|
|
TraceIp("IPCP: VJ disabled by RADIUS");
|
|
pwb->fIpCompressionRejected = TRUE;
|
|
memset( &pwb->rpcSend, '\0', sizeof(pwb->rpcSend) );
|
|
|
|
fVJAttributePresent = TRUE;
|
|
break;
|
|
|
|
case 1:
|
|
|
|
TraceIp("IPCP: VJ required by RADIUS");
|
|
fVJAttributePresent = TRUE;
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
if (fVJAttributePresent)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pAttribute = RasAuthAttributeGetNext(&hAttribute,
|
|
raatFramedCompression);
|
|
}
|
|
}
|
|
|
|
if (fVJAttributePresent)
|
|
{
|
|
// Nothing
|
|
}
|
|
else if (fVPN)
|
|
{
|
|
TraceIp("IPCP: VJ disabled for VPN");
|
|
pwb->fIpCompressionRejected = TRUE;
|
|
memset( &pwb->rpcSend, '\0', sizeof(pwb->rpcSend) );
|
|
}
|
|
else
|
|
{
|
|
/* Look up "request VJ compresion" flag in registry.
|
|
*/
|
|
{
|
|
HKEY hkey;
|
|
DWORD dwType;
|
|
DWORD dwValue;
|
|
DWORD cb = sizeof(DWORD);
|
|
|
|
if (RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_Ipcp, &hkey ) == 0)
|
|
{
|
|
if (RegQueryValueEx(
|
|
hkey, REGVAL_VjComp, NULL,
|
|
&dwType, (LPBYTE )&dwValue, &cb ) == 0
|
|
&& dwType == REG_DWORD
|
|
&& cb == sizeof(DWORD)
|
|
&& dwValue == 0)
|
|
{
|
|
TraceIp("IPCP: VJ requests disabled");
|
|
pwb->fIpCompressionRejected = TRUE;
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
}
|
|
}
|
|
|
|
/* Look up "accept VJ compresion" flag in registry.
|
|
*/
|
|
{
|
|
HKEY hkey;
|
|
DWORD dwType;
|
|
DWORD dwValue;
|
|
DWORD cb = sizeof(DWORD);
|
|
|
|
if (RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_Ipcp, &hkey ) == 0)
|
|
{
|
|
if (RegQueryValueEx(
|
|
hkey, REGVAL_VjComp2, NULL,
|
|
&dwType, (LPBYTE )&dwValue, &cb ) == 0
|
|
&& dwType == REG_DWORD
|
|
&& cb == sizeof(DWORD)
|
|
&& dwValue == 0)
|
|
{
|
|
TraceIp("IPCP: VJ will not be accepted");
|
|
memset( &pwb->rpcSend, '\0', sizeof(pwb->rpcSend) );
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
}
|
|
}
|
|
}
|
|
|
|
TraceIp("IPCP: Compress capabilities: s=$%x,%d,%d r=$%x,%d,%d",
|
|
(int)Protocol(pwb->rpcSend),(int)MaxSlotId(pwb->rpcSend),
|
|
(int)CompSlotId(pwb->rpcSend),(int)Protocol(pwb->rpcReceive),
|
|
(int)MaxSlotId(pwb->rpcReceive),CompSlotId(pwb->rpcReceive));
|
|
|
|
//
|
|
// If we are receiving a call from a client or another router, or we
|
|
// are a router dialing out.
|
|
//
|
|
|
|
if ( ( pwb->fServer ) ||
|
|
( pwb->IfType == ROUTER_IF_TYPE_FULL_ROUTER ) )
|
|
{
|
|
/* Look up the DNS server, WINS server, and "this server" addresses.
|
|
** This is done once at the beginning since these addresses are the
|
|
** same for a given route regardless of the IP addresses.
|
|
*/
|
|
|
|
TraceIp("IPCP: Server address lookup...");
|
|
TraceIp("IPCP: RasSrvrQueryServerAddresses...");
|
|
|
|
dwErr = RasSrvrQueryServerAddresses( &(pwb->IpInfoRemote) );
|
|
|
|
TraceIp("IPCP: RasSrvrQueryServerAddresses done(%d)",dwErr);
|
|
|
|
if (dwErr != 0)
|
|
{
|
|
pwb->dwErrInBegin = dwErr;
|
|
*ppWorkBuf = pwb;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
TraceIp("IPCP:Dns=%08x,Wins=%08x,DnsB=%08x,WinsB=%08x,"
|
|
"Server=%08x,Mask=%08x",
|
|
pwb->IpInfoRemote.nboDNSAddress,
|
|
pwb->IpInfoRemote.nboWINSAddress,
|
|
pwb->IpInfoRemote.nboDNSAddressBackup,
|
|
pwb->IpInfoRemote.nboWINSAddressBackup,
|
|
pwb->IpInfoRemote.nboServerIpAddress,
|
|
pwb->IpInfoRemote.nboServerSubnetMask);
|
|
}
|
|
|
|
//
|
|
// If this is not a router interface, then we use the server address
|
|
// as a local address
|
|
//
|
|
|
|
if ( ( pwb->fServer ) && ( pwb->IfType != ROUTER_IF_TYPE_FULL_ROUTER ) )
|
|
{
|
|
/* Request server's own IP address. (RAS client's don't care what
|
|
** the server's address is, but some other vendors like
|
|
** MorningStar won't connect unless you tell them)
|
|
*/
|
|
|
|
pwb->IpAddressLocal = pwb->IpInfoRemote.nboServerIpAddress;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We are a client\router dialing out or a router dialing in,
|
|
//
|
|
|
|
if ( ( !pwb->fServer ) || ( pwb->IfType == ROUTER_IF_TYPE_FULL_ROUTER ) )
|
|
{
|
|
//
|
|
// See if registry indicates "no WINS/DNS requests" mode for clients
|
|
// dialing out.
|
|
//
|
|
|
|
HKEY hkey;
|
|
DWORD dwType;
|
|
DWORD dwValue;
|
|
DWORD cb = sizeof(DWORD);
|
|
|
|
if ( RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_Ipcp, &hkey ) == 0)
|
|
{
|
|
if ( RegQueryValueEx(
|
|
hkey, REGVAL_NsAddrs, NULL,
|
|
&dwType, (LPBYTE )&dwValue, &cb ) == 0
|
|
&& dwType == REG_DWORD
|
|
&& cb == sizeof(DWORD)
|
|
&& dwValue == 0)
|
|
{
|
|
TraceIp("IPCP: WINS/DNS requests disabled");
|
|
pwb->fIpaddrDnsRejected = TRUE;
|
|
pwb->fIpaddrWinsRejected = TRUE;
|
|
pwb->fIpaddrDnsBackupRejected = TRUE;
|
|
pwb->fIpaddrWinsBackupRejected = TRUE;
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
}
|
|
|
|
/* Read the parameters sent from the UI in the parameters buffer.
|
|
*/
|
|
pwb->fPrioritizeRemote = TRUE;
|
|
|
|
if (pInit->pszzParameters)
|
|
{
|
|
DWORD dwIpSource;
|
|
CHAR szIpAddress[ 16 ];
|
|
WCHAR wszIpAddress[ 16 ];
|
|
BOOL fVjCompression;
|
|
DWORD dwDnsFlags;
|
|
CHAR szDnsSuffix[DNS_SUFFIX_SIZE + 1];
|
|
|
|
TraceIp("IPCP: UI parameters...");
|
|
DUMPB(pInit->pszzParameters,PARAMETERBUFLEN);
|
|
|
|
FindFlagInParamBuf(
|
|
pInit->pszzParameters, PBUFKEY_IpPrioritizeRemote,
|
|
&pwb->fPrioritizeRemote );
|
|
|
|
pwb->fUnnumbered = FALSE;
|
|
|
|
if ( pwb->IfType == ROUTER_IF_TYPE_FULL_ROUTER )
|
|
{
|
|
if ( RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_Ipcp, &hkey ) == 0)
|
|
{
|
|
if ( RegQueryValueEx(
|
|
hkey, REGVAL_Unnumbered, NULL,
|
|
&dwType, (LPBYTE )&dwValue, &cb ) == 0
|
|
&& dwType == REG_DWORD
|
|
&& cb == sizeof(DWORD)
|
|
&& dwValue != 0)
|
|
{
|
|
TraceIp("Unnumbered");
|
|
pwb->fUnnumbered = TRUE;
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
}
|
|
}
|
|
|
|
{
|
|
if (FindLongInParamBuf(
|
|
pInit->pszzParameters, PBUFKEY_IpDnsFlags,
|
|
&dwDnsFlags ))
|
|
{
|
|
if (dwDnsFlags & 0x1)
|
|
{
|
|
pwb->fRegisterWithDNS = 1;
|
|
}
|
|
|
|
if ( (dwDnsFlags & 0x2)
|
|
|| (dwDnsFlags & 0x4) )
|
|
{
|
|
pwb->fRegisterAdapterDomainName = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
if (FindStringInParamBuf(
|
|
pInit->pszzParameters, PBUFKEY_IpDnsSuffix,
|
|
szDnsSuffix, DNS_SUFFIX_SIZE + 1 ))
|
|
{
|
|
strncpy(pwb->szDnsSuffix, szDnsSuffix, DNS_SUFFIX_SIZE);
|
|
}
|
|
}
|
|
|
|
{
|
|
fVjCompression = TRUE;
|
|
FindFlagInParamBuf(
|
|
pInit->pszzParameters, PBUFKEY_IpVjCompression,
|
|
&fVjCompression );
|
|
|
|
if (!fVjCompression)
|
|
{
|
|
/* Don't request or accept VJ compression.
|
|
*/
|
|
TraceIp("IPCP: VJ disabled");
|
|
pwb->fIpCompressionRejected = TRUE;
|
|
memset( &pwb->rpcSend, '\0', sizeof(pwb->rpcSend) );
|
|
}
|
|
}
|
|
|
|
if( !pwb->fIpCompressionRejected
|
|
&& !Protocol(pwb->rpcReceive))
|
|
{
|
|
pwb->fIpCompressionRejected = TRUE;
|
|
}
|
|
|
|
|
|
dwIpSource = PBUFVAL_ServerAssigned;
|
|
FindLongInParamBuf(
|
|
pInit->pszzParameters, PBUFKEY_IpAddressSource,
|
|
&dwIpSource );
|
|
|
|
if (dwIpSource == PBUFVAL_RequireSpecific)
|
|
{
|
|
if (FindStringInParamBuf(
|
|
pInit->pszzParameters, PBUFKEY_IpAddress,
|
|
szIpAddress, 16 ))
|
|
{
|
|
mbstowcs( wszIpAddress, szIpAddress, 16 );
|
|
pwb->IpAddressLocal
|
|
= IpAddressFromAbcdWsz( wszIpAddress );
|
|
}
|
|
}
|
|
|
|
dwIpSource = PBUFVAL_ServerAssigned;
|
|
FindLongInParamBuf(
|
|
pInit->pszzParameters, PBUFKEY_IpNameAddressSource,
|
|
&dwIpSource );
|
|
|
|
if (dwIpSource == PBUFVAL_RequireSpecific)
|
|
{
|
|
//
|
|
//check to see if DNS or WINS or both have been
|
|
//requested specific and set the flags accordingly
|
|
//so that we only request proper addresses
|
|
//from the server
|
|
//
|
|
|
|
if (FindStringInParamBuf(
|
|
pInit->pszzParameters, PBUFKEY_IpDnsAddress,
|
|
szIpAddress, 16 ))
|
|
{
|
|
mbstowcs( wszIpAddress, szIpAddress, 16 );
|
|
pwb->IpInfoLocal.nboDNSAddress
|
|
= IpAddressFromAbcdWsz( wszIpAddress );
|
|
}
|
|
|
|
if (FindStringInParamBuf(
|
|
pInit->pszzParameters, PBUFKEY_IpDns2Address,
|
|
szIpAddress, 16 ))
|
|
{
|
|
mbstowcs( wszIpAddress, szIpAddress, 16 );
|
|
pwb->IpInfoLocal.nboDNSAddressBackup
|
|
= IpAddressFromAbcdWsz( wszIpAddress );
|
|
}
|
|
|
|
if (FindStringInParamBuf(
|
|
pInit->pszzParameters, PBUFKEY_IpWinsAddress,
|
|
szIpAddress, 16 ))
|
|
{
|
|
mbstowcs( wszIpAddress, szIpAddress, 16 );
|
|
pwb->IpInfoLocal.nboWINSAddress
|
|
= IpAddressFromAbcdWsz( wszIpAddress );
|
|
}
|
|
|
|
if (FindStringInParamBuf(
|
|
pInit->pszzParameters, PBUFKEY_IpWins2Address,
|
|
szIpAddress, 16 ))
|
|
{
|
|
mbstowcs( wszIpAddress, szIpAddress, 16 );
|
|
pwb->IpInfoLocal.nboWINSAddressBackup
|
|
= IpAddressFromAbcdWsz( wszIpAddress );
|
|
}
|
|
if ( pwb->IpInfoLocal.nboDNSAddress ||
|
|
pwb->IpInfoLocal.nboDNSAddressBackup
|
|
)
|
|
{
|
|
//Specific DNS address has been passed in
|
|
pwb->fIpaddrDnsRejected = TRUE;
|
|
pwb->fIpaddrDnsBackupRejected = TRUE;
|
|
|
|
}
|
|
if ( pwb->IpInfoLocal.nboWINSAddress ||
|
|
pwb->IpInfoLocal.nboWINSAddressBackup
|
|
)
|
|
{
|
|
//Specific WINS address has been requested
|
|
pwb->fIpaddrWinsRejected = TRUE;
|
|
pwb->fIpaddrWinsBackupRejected = TRUE;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
TraceIp( "IPCP:a=%08x,f=%d",
|
|
pwb->IpAddressLocal,pwb->fPrioritizeRemote);
|
|
}
|
|
|
|
|
|
/* Register work buffer with engine.
|
|
*/
|
|
*ppWorkBuf = pwb;
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD
|
|
IpcpThisLayerFinished(
|
|
IN VOID* pWorkBuf )
|
|
|
|
/* RasCpThisLayerFinished entry point called by the PPP engine thru the
|
|
** passed address. See RasCp interface documentation.
|
|
*/
|
|
{
|
|
DWORD dwErr = 0;
|
|
IPCPWB* pwb = (IPCPWB* )pWorkBuf;
|
|
|
|
TraceIp("IPCP: IpcpThisLayerFinished...");
|
|
|
|
//
|
|
// If this is a server or a router dialing in or out then we release this
|
|
// address
|
|
//
|
|
|
|
if ( ( pwb->fServer ) ||
|
|
( pwb->IfType == ROUTER_IF_TYPE_FULL_ROUTER ))
|
|
{
|
|
if (pwb->IpAddressRemote != 0)
|
|
{
|
|
TraceIp("IPCP: RasSrvrReleaseAddress...");
|
|
RasSrvrReleaseAddress(pwb->IpAddressRemote,
|
|
pwb->wszUserName,
|
|
pwb->wszPortName,
|
|
( pwb->IfType == ROUTER_IF_TYPE_FULL_ROUTER ) ?
|
|
FALSE : TRUE);
|
|
TraceIp("IPCP: RasSrvrReleaseAddress done");
|
|
pwb->IpAddressRemote = 0;
|
|
}
|
|
|
|
//
|
|
// Set ConfigActive to false only for server
|
|
//
|
|
|
|
if ( ( pwb->fServer ) &&
|
|
( pwb->IfType != ROUTER_IF_TYPE_FULL_ROUTER ))
|
|
{
|
|
pwb->fRasConfigActive = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we are a client dialing out or a router dialing in or out then we
|
|
// notify DHCP of releasing this address.
|
|
//
|
|
|
|
if ( ( !pwb->fServer ) ||
|
|
( pwb->IfType == ROUTER_IF_TYPE_FULL_ROUTER ))
|
|
{
|
|
dwErr = DeActivateRasConfig( pwb );
|
|
|
|
if (dwErr == 0)
|
|
{
|
|
pwb->fRasConfigActive = FALSE;
|
|
}
|
|
}
|
|
|
|
if (pwb->fRouteActivated)
|
|
{
|
|
TraceIp("IPCP: RasDeAllocateRoute...");
|
|
RasDeAllocateRoute( pwb->hConnection, IP );
|
|
pwb->fRouteActivated = FALSE;
|
|
}
|
|
|
|
if ( pwb->pbDhcpRoutes )
|
|
{
|
|
//Parse the dhcp routes and remove the routes from stack
|
|
TraceIp("IPCP: RasDeAllocateDhcpRoute...");
|
|
RasTcpSetDhcpRoutes ( pwb->pbDhcpRoutes , pwb->IpAddressLocal, FALSE );
|
|
LocalFree (pwb->pbDhcpRoutes );
|
|
pwb->pbDhcpRoutes = NULL;
|
|
}
|
|
|
|
TraceIp("IPCP: IpcpThisLayerFinished done(%d)",dwErr);
|
|
return dwErr;
|
|
}
|
|
|
|
DWORD
|
|
IpcpEnd(
|
|
IN VOID* pWorkBuf )
|
|
|
|
/* RasCpEnd entry point called by the PPP engine thru the passed address.
|
|
** See RasCp interface documentation.
|
|
*/
|
|
{
|
|
DWORD dwErr = 0;
|
|
IPCPWB* pwb = (IPCPWB* )pWorkBuf;
|
|
|
|
TraceIp("IPCP: IpcpEnd...");
|
|
|
|
dwErr = IpcpThisLayerFinished( pWorkBuf );
|
|
|
|
LocalFree( (HLOCAL )pWorkBuf );
|
|
TraceIp("IPCP: IpcpEnd done(%d)",dwErr);
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
DWORD
|
|
IpcpReset(
|
|
IN VOID* pWorkBuf )
|
|
|
|
/* Called to reset negotiations. See RasCp interface documentation.
|
|
**
|
|
** Returns 0 if successful, otherwise a non-0 error code.
|
|
*/
|
|
{
|
|
/* RasPpp.dll requires this to exist even though it does nothing
|
|
** (complaints to Gibbs).
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD
|
|
IpcpThisLayerUp(
|
|
IN VOID* pWorkBuf )
|
|
|
|
/* Called when the CP is entering Open state. See RasCp interface
|
|
** documentation.
|
|
**
|
|
** Returns 0 if successful, otherwise a non-0 error code.
|
|
*/
|
|
{
|
|
IPCPWB* pwb = (IPCPWB* )pWorkBuf;
|
|
|
|
TraceIp("IPCP: IpcpThisLayerUp");
|
|
|
|
if (pwb->fRasConfigActive || pwb->fExpectingProjection)
|
|
{
|
|
TraceIp("IPCP: Link already up...ignored.");
|
|
return 0;
|
|
}
|
|
|
|
/* Can't route until we know the result of the projection. Shouldn't
|
|
** activate until just before we route or WANARP reports errors. See
|
|
** IpcpProjectionResult.
|
|
*/
|
|
pwb->fExpectingProjection = TRUE;
|
|
|
|
TraceIp("IPCP: IpcpThisLayerUp done");
|
|
return 0;
|
|
}
|
|
|
|
DWORD
|
|
IpcpPreDisconnectCleanup(
|
|
IN VOID* pWorkBuf )
|
|
{
|
|
IPCPWB* pwb = (IPCPWB* )pWorkBuf;
|
|
DWORD dwErr = NO_ERROR;
|
|
|
|
TraceIp("IPCP: IpcpPreDisconnectCleanup");
|
|
|
|
if ( ( pwb->fServer )
|
|
|| ( pwb->pwszDevice == NULL )
|
|
|| ( !pwb->fRegisterWithDNS ))
|
|
{
|
|
return( NO_ERROR );
|
|
}
|
|
|
|
if ( ( dwErr = ResetNetBTConfigInfo( pwb ) ) != NO_ERROR )
|
|
{
|
|
TraceIp("IPCP: ResetNetBTConfigInfo=%d",dwErr);
|
|
}
|
|
else
|
|
{
|
|
if ((dwErr = ReconfigureTcpip( pwb->pwszDevice, FALSE, 0, 0)) != 0)
|
|
{
|
|
TraceIp("IPCP: ReconfigureTcpip=%d", dwErr);
|
|
}
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
DWORD
|
|
IpcpMakeConfigRequest(
|
|
IN VOID* pWorkBuf,
|
|
OUT PPP_CONFIG* pSendBuf,
|
|
IN DWORD cbSendBuf )
|
|
|
|
/* Makes a configure-request packet in 'pSendBuf'. See RasCp interface
|
|
** documentation.
|
|
**
|
|
** Returns 0 if successful, otherwise a non-0 error code.
|
|
*/
|
|
{
|
|
IPCPWB* pwb = (IPCPWB* )pWorkBuf;
|
|
WORD cbPacket = PPP_CONFIG_HDR_LEN;
|
|
BYTE* pbThis = pSendBuf->Data;
|
|
|
|
TraceIp("IPCP: IpcpMakeConfigRequest");
|
|
RTASSERT(cbSendBuf>PPP_CONFIG_HDR_LEN+(IPADDRESSOPTIONLEN*3));
|
|
|
|
if (pwb->dwErrInBegin != 0)
|
|
{
|
|
TraceIp("IPCP: Deferred IpcpBegin error=%d",pwb->dwErrInBegin);
|
|
return pwb->dwErrInBegin;
|
|
}
|
|
|
|
if (++pwb->cRequestsWithoutResponse >= 5)
|
|
{
|
|
TraceIp("IPCP: Tossing MS options (request timeouts)");
|
|
pwb->fTryWithoutExtensions = TRUE;
|
|
pwb->fIpaddrDnsRejected = TRUE;
|
|
pwb->fIpaddrWinsRejected = TRUE;
|
|
pwb->fIpaddrDnsBackupRejected = TRUE;
|
|
pwb->fIpaddrWinsBackupRejected = TRUE;
|
|
}
|
|
|
|
if (!pwb->fIpCompressionRejected )
|
|
{
|
|
/* Request IP compression for both client and server.
|
|
*/
|
|
AddIpCompressionOption( pbThis, &pwb->rpcReceive );
|
|
cbPacket += IPCOMPRESSIONOPTIONLEN;
|
|
pbThis += IPCOMPRESSIONOPTIONLEN;
|
|
}
|
|
|
|
//
|
|
// We always negotiate this option, it will be 0 for clients and routers
|
|
// dialing out and routers dialing in, it will be the server's address
|
|
// for clients dialing in. We don't negotiate this option if we want
|
|
// unnumbered IPCP.
|
|
//
|
|
|
|
if (!pwb->fIpaddrRejected && !pwb->fUnnumbered)
|
|
{
|
|
AddIpAddressOption(
|
|
pbThis, OPTION_IpAddress, pwb->IpAddressLocal );
|
|
cbPacket += IPADDRESSOPTIONLEN;
|
|
pbThis += IPADDRESSOPTIONLEN;
|
|
}
|
|
|
|
//
|
|
// If we are client dialing out we need WINS and DNS addresses
|
|
//
|
|
|
|
if ( !pwb->fServer )
|
|
{
|
|
/* The client asks the server to provide a DNS address and WINS
|
|
** address (and depending on user's UI selections, an IP address) by
|
|
** sending 0's for these options.
|
|
*/
|
|
|
|
if (!pwb->fIpaddrDnsRejected)
|
|
{
|
|
AddIpAddressOption(
|
|
pbThis, OPTION_DnsIpAddress,
|
|
pwb->IpInfoLocal.nboDNSAddress );
|
|
cbPacket += IPADDRESSOPTIONLEN;
|
|
pbThis += IPADDRESSOPTIONLEN;
|
|
}
|
|
|
|
if (!pwb->fIpaddrWinsRejected)
|
|
{
|
|
AddIpAddressOption(
|
|
pbThis, OPTION_WinsIpAddress,
|
|
pwb->IpInfoLocal.nboWINSAddress );
|
|
cbPacket += IPADDRESSOPTIONLEN;
|
|
pbThis += IPADDRESSOPTIONLEN;
|
|
}
|
|
|
|
if (!pwb->fIpaddrDnsBackupRejected)
|
|
{
|
|
AddIpAddressOption(
|
|
pbThis, OPTION_DnsBackupIpAddress,
|
|
pwb->IpInfoLocal.nboDNSAddressBackup );
|
|
cbPacket += IPADDRESSOPTIONLEN;
|
|
pbThis += IPADDRESSOPTIONLEN;
|
|
}
|
|
|
|
if (!pwb->fIpaddrWinsBackupRejected)
|
|
{
|
|
AddIpAddressOption(
|
|
pbThis, OPTION_WinsBackupIpAddress,
|
|
pwb->IpInfoLocal.nboWINSAddressBackup );
|
|
cbPacket += IPADDRESSOPTIONLEN;
|
|
}
|
|
}
|
|
|
|
pSendBuf->Code = CONFIG_REQ;
|
|
HostToWireFormat16( cbPacket, pSendBuf->Length );
|
|
TraceIp("IPCP: ConfigRequest...");
|
|
DUMPB(pSendBuf,cbPacket);
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD
|
|
IpcpMakeConfigResult(
|
|
IN VOID* pWorkBuf,
|
|
IN PPP_CONFIG* pReceiveBuf,
|
|
OUT PPP_CONFIG* pSendBuf,
|
|
IN DWORD cbSendBuf,
|
|
IN BOOL fRejectNaks )
|
|
|
|
/* Makes a configure-ack, -nak, or -reject packet in 'pSendBuf'. See
|
|
** RasCp interface documentation.
|
|
**
|
|
** Implements the Stefanian rule, i.e. accept only configure requests that
|
|
** exactly match the previously acknowledged request after this layer up
|
|
** has been called. This is necessary because the RAS route cannot be
|
|
** deallocated when the port is open (NDISWAN driver limitation), so
|
|
** renegotiation with different parameters is not possible once the route
|
|
** has been activated.
|
|
**
|
|
** Returns 0 if successful, otherwise a non-0 error code.
|
|
*/
|
|
{
|
|
DWORD dwErr;
|
|
BOOL f;
|
|
IPCPWB* pwb = (IPCPWB* )pWorkBuf;
|
|
|
|
TraceIp("IPCP: IpcpMakeConfigResult for...");
|
|
DUMPB(pReceiveBuf,(pReceiveBuf)?WireToHostFormat16(pReceiveBuf->Length):0);
|
|
|
|
pwb->cRequestsWithoutResponse = 0;
|
|
|
|
/* Check if there's reason to reject the request and if so, do it.
|
|
*/
|
|
if ((dwErr = RejectCheck(
|
|
pwb, pReceiveBuf, pSendBuf, cbSendBuf, &f )) != 0)
|
|
{
|
|
TraceIp("IPCP: ConfigResult...");
|
|
DUMPB(pSendBuf,WireToHostFormat16(pSendBuf->Length));
|
|
return dwErr;
|
|
}
|
|
|
|
if (f)
|
|
return (pwb->fRasConfigActive) ? ERROR_PPP_NOT_CONVERGING : 0;
|
|
|
|
/* Check if there's reason to nak the request and if so, do it (or
|
|
** reject instead of nak if indicated by engine).
|
|
*/
|
|
if ((dwErr = NakCheck(
|
|
pwb, pReceiveBuf, pSendBuf, cbSendBuf, &f, fRejectNaks )) != 0)
|
|
{
|
|
TraceIp("IPCP: ConfigResult...");
|
|
DUMPB(pSendBuf,WireToHostFormat16(pSendBuf->Length));
|
|
return dwErr;
|
|
}
|
|
|
|
if (f)
|
|
return (pwb->fRasConfigActive) ? ERROR_PPP_NOT_CONVERGING : 0;
|
|
|
|
/* Acknowledge the request.
|
|
*/
|
|
{
|
|
WORD cbPacket = WireToHostFormat16( pReceiveBuf->Length );
|
|
CopyMemory( pSendBuf, pReceiveBuf, cbPacket );
|
|
pSendBuf->Code = CONFIG_ACK;
|
|
}
|
|
|
|
TraceIp("IPCP: ConfigResult...");
|
|
DUMPB(pSendBuf,WireToHostFormat16(pSendBuf->Length));
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD
|
|
IpcpConfigAckReceived(
|
|
IN VOID* pWorkBuf,
|
|
IN PPP_CONFIG* pReceiveBuf )
|
|
|
|
/* Examines received configure-ack in 'pReceiveBuf'. See RasCp interface
|
|
** documentation.
|
|
**
|
|
** Returns 0 if successful, otherwise a non-0 error code.
|
|
*/
|
|
{
|
|
DWORD dwErr = 0;
|
|
IPCPWB* pwb = (IPCPWB* )pWorkBuf;
|
|
|
|
WORD cbPacket = WireToHostFormat16( pReceiveBuf->Length );
|
|
WORD cbLeft = cbPacket - PPP_CONFIG_HDR_LEN;
|
|
|
|
PPP_OPTION UNALIGNED* pROption = (PPP_OPTION UNALIGNED* )pReceiveBuf->Data;
|
|
|
|
BOOL fIpCompressionOk = pwb->fIpCompressionRejected;
|
|
BOOL fIpaddrOk = pwb->fIpaddrRejected || pwb->fUnnumbered;
|
|
BOOL fIpaddrDnsOk = pwb->fIpaddrDnsRejected;
|
|
BOOL fIpaddrWinsOk = pwb->fIpaddrWinsRejected;
|
|
BOOL fIpaddrDnsBackupOk = pwb->fIpaddrDnsBackupRejected;
|
|
BOOL fIpaddrWinsBackupOk = pwb->fIpaddrWinsBackupRejected;
|
|
|
|
TraceIp("IPCP: IpcpConfigAckReceived...");
|
|
DUMPB(pReceiveBuf,cbPacket);
|
|
|
|
pwb->cRequestsWithoutResponse = 0;
|
|
|
|
while (cbLeft > 0)
|
|
{
|
|
if (cbLeft < pROption->Length)
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
|
|
if (pROption->Type == OPTION_IpCompression)
|
|
{
|
|
WORD wProtocol;
|
|
|
|
if (pROption->Length != IPCOMPRESSIONOPTIONLEN)
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
|
|
wProtocol = WireToHostFormat16U(pROption->Data );
|
|
if (wProtocol != Protocol(pwb->rpcReceive)
|
|
|| pROption->Data[ 2 ] != MaxSlotId(pwb->rpcReceive)
|
|
|| pROption->Data[ 3 ] != CompSlotId(pwb->rpcReceive))
|
|
{
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
}
|
|
|
|
fIpCompressionOk = TRUE;
|
|
}
|
|
else if (pROption->Type == OPTION_IpAddress)
|
|
{
|
|
IPADDR ipaddr;
|
|
|
|
if (pROption->Length != IPADDRESSOPTIONLEN)
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
|
|
CopyMemory( &ipaddr, pROption->Data, sizeof(IPADDR) );
|
|
|
|
if (ipaddr != 0 && ipaddr == pwb->IpAddressLocal )
|
|
fIpaddrOk = TRUE;
|
|
}
|
|
else if (!pwb->fServer)
|
|
{
|
|
//
|
|
// We are a client dialing out
|
|
//
|
|
|
|
switch (pROption->Type)
|
|
{
|
|
case OPTION_DnsIpAddress:
|
|
{
|
|
IPADDR ipaddr;
|
|
|
|
if (pROption->Length != IPADDRESSOPTIONLEN)
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
|
|
CopyMemory( &ipaddr, pROption->Data, sizeof(IPADDR) );
|
|
|
|
if (ipaddr == pwb->IpInfoLocal.nboDNSAddress)
|
|
fIpaddrDnsOk = TRUE;
|
|
break;
|
|
}
|
|
|
|
case OPTION_WinsIpAddress:
|
|
{
|
|
IPADDR ipaddr;
|
|
|
|
if (pROption->Length != IPADDRESSOPTIONLEN)
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
|
|
CopyMemory( &ipaddr, pROption->Data, sizeof(IPADDR) );
|
|
|
|
if (ipaddr == pwb->IpInfoLocal.nboWINSAddress)
|
|
fIpaddrWinsOk = TRUE;
|
|
break;
|
|
}
|
|
|
|
case OPTION_DnsBackupIpAddress:
|
|
{
|
|
IPADDR ipaddr;
|
|
|
|
if (pROption->Length != IPADDRESSOPTIONLEN)
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
|
|
CopyMemory( &ipaddr, pROption->Data, sizeof(IPADDR) );
|
|
|
|
if (ipaddr == pwb->IpInfoLocal.nboDNSAddressBackup)
|
|
{
|
|
fIpaddrDnsBackupOk = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case OPTION_WinsBackupIpAddress:
|
|
{
|
|
IPADDR ipaddr;
|
|
|
|
if (pROption->Length != IPADDRESSOPTIONLEN)
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
|
|
CopyMemory( &ipaddr, pROption->Data, sizeof(IPADDR) );
|
|
|
|
if (ipaddr == pwb->IpInfoLocal.nboWINSAddressBackup)
|
|
{
|
|
fIpaddrWinsBackupOk = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
TraceIp("IPCP: Unrecognized option ACKed?");
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceIp("IPCP: Unrecognized option ACKed?");
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
}
|
|
|
|
if (pROption->Length && pROption->Length < cbLeft)
|
|
cbLeft -= pROption->Length;
|
|
else
|
|
cbLeft = 0;
|
|
|
|
pROption = (PPP_OPTION* )((BYTE* )pROption + pROption->Length);
|
|
}
|
|
|
|
if ( !fIpCompressionOk
|
|
|| !fIpaddrOk
|
|
|| ( !pwb->fServer
|
|
&& ( !fIpaddrDnsOk
|
|
|| !fIpaddrWinsOk
|
|
|| !fIpaddrDnsBackupOk
|
|
|| !fIpaddrWinsBackupOk)))
|
|
{
|
|
dwErr = ERROR_PPP_INVALID_PACKET;
|
|
}
|
|
|
|
TraceIp("IPCP: IpcpConfigAckReceived done(%d)",dwErr);
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
DWORD
|
|
IpcpConfigNakReceived(
|
|
IN VOID* pWorkBuf,
|
|
IN PPP_CONFIG* pReceiveBuf )
|
|
|
|
/* Examines received configure-nak in 'pReceiveBuf'. See RasCp interface
|
|
** documentation.
|
|
**
|
|
** Returns 0 if successful, otherwise a non-0 error code.
|
|
*/
|
|
{
|
|
IPCPWB* pwb = (IPCPWB* )pWorkBuf;
|
|
PPP_OPTION* pROption = (PPP_OPTION* )pReceiveBuf->Data;
|
|
WORD cbPacket = WireToHostFormat16( pReceiveBuf->Length );
|
|
WORD cbLeft = cbPacket - PPP_CONFIG_HDR_LEN;
|
|
|
|
TraceIp("IPCP: IpcpConfigNakReceived");
|
|
TraceIp("IPCP: Nak received...");
|
|
DUMPB(pReceiveBuf,(pReceiveBuf)?WireToHostFormat16(pReceiveBuf->Length):0);
|
|
|
|
pwb->cRequestsWithoutResponse = 0;
|
|
|
|
while (cbLeft > 0)
|
|
{
|
|
if (cbLeft < pROption->Length)
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
|
|
if (pROption->Type == OPTION_IpCompression)
|
|
{
|
|
WORD wProtocol = WireToHostFormat16( pROption->Data );
|
|
|
|
if (wProtocol == COMPRESSION_VanJacobson)
|
|
{
|
|
/* He can send Van Jacobson but not with the slot parameters
|
|
** we suggested.
|
|
*/
|
|
if (pROption->Length != IPCOMPRESSIONOPTIONLEN)
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
|
|
if (pROption->Data[ 2 ] <= MaxSlotId(pwb->rpcReceive))
|
|
{
|
|
/* We can accept his suggested MaxSlotID when it is less
|
|
** than or the same as what we can do.
|
|
*/
|
|
MaxSlotId(pwb->rpcReceive) = pROption->Data[ 2 ];
|
|
}
|
|
|
|
if (CompSlotId(pwb->rpcReceive))
|
|
{
|
|
/* We can compress the slot-ID or not, so just accept
|
|
** whatever he wants to do.
|
|
*/
|
|
CompSlotId(pwb->rpcReceive) = pROption->Data[ 3 ];
|
|
}
|
|
}
|
|
}
|
|
else if ( ( !pwb->fServer ) ||
|
|
( pwb->IfType == ROUTER_IF_TYPE_FULL_ROUTER ) )
|
|
{
|
|
switch (pROption->Type)
|
|
{
|
|
case OPTION_IpAddress:
|
|
{
|
|
IPADDR ipaddr;
|
|
|
|
if (pROption->Length != IPADDRESSOPTIONLEN)
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
|
|
CopyMemory( &ipaddr, pROption->Data, sizeof(IPADDR) );
|
|
|
|
if (ipaddr == 0)
|
|
{
|
|
if (pwb->IpAddressLocal == 0)
|
|
{
|
|
/* Server naked us with zero when we asked it to
|
|
** assign us an address, meaning he doesn't know
|
|
** how to assign us an address but we can provide
|
|
** an alternate address if we want. Currently we
|
|
** don't support a backup address here.
|
|
*/
|
|
return ERROR_PPP_NO_ADDRESS_ASSIGNED;
|
|
}
|
|
else
|
|
{
|
|
/* Server naked us with zero when we asked for a
|
|
** specific address, meaning he doesn't know how
|
|
** to assign us an address but we can provide an
|
|
** alternate address if we want. Currently we
|
|
** don't support a backup address here.
|
|
*/
|
|
return ERROR_PPP_REQUIRED_ADDRESS_REJECTED;
|
|
}
|
|
}
|
|
|
|
if (pwb->IpAddressLocal != 0)
|
|
{
|
|
/* We asked for a specific address (per user's
|
|
** instructions) but server says we can't have it and
|
|
** is trying to give us another. No good, tell user
|
|
** we can't get the address he requires.
|
|
*/
|
|
return ERROR_PPP_REQUIRED_ADDRESS_REJECTED;
|
|
}
|
|
|
|
/* Accept the address suggested by server.
|
|
*/
|
|
pwb->IpAddressLocal = ipaddr;
|
|
break;
|
|
}
|
|
|
|
case OPTION_DnsIpAddress:
|
|
{
|
|
if (pROption->Length != IPADDRESSOPTIONLEN)
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
|
|
//
|
|
// Use this only if we asked for it
|
|
//
|
|
|
|
if ( !pwb->fIpaddrDnsRejected )
|
|
{
|
|
/* Accept the DNS address suggested by server.
|
|
*/
|
|
CopyMemory( &pwb->IpInfoLocal.nboDNSAddress,
|
|
pROption->Data, sizeof(IPADDR) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case OPTION_WinsIpAddress:
|
|
{
|
|
if (pROption->Length != IPADDRESSOPTIONLEN)
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
|
|
//
|
|
// Use this only if we asked for it
|
|
//
|
|
|
|
if ( !pwb->fIpaddrWinsRejected )
|
|
{
|
|
/* Accept the WINS address suggested by server.
|
|
*/
|
|
CopyMemory( &pwb->IpInfoLocal.nboWINSAddress,
|
|
pROption->Data, sizeof(IPADDR) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case OPTION_DnsBackupIpAddress:
|
|
{
|
|
if (pROption->Length != IPADDRESSOPTIONLEN)
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
|
|
//
|
|
// Use this only if we asked for it
|
|
//
|
|
|
|
if ( !pwb->fIpaddrDnsBackupRejected )
|
|
{
|
|
/* Accept the DNS backup address suggested by server.
|
|
*/
|
|
CopyMemory( &pwb->IpInfoLocal.nboDNSAddressBackup,
|
|
pROption->Data, sizeof(IPADDR) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case OPTION_WinsBackupIpAddress:
|
|
{
|
|
if (pROption->Length != IPADDRESSOPTIONLEN)
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
|
|
//
|
|
// Use this only if we asked for it
|
|
//
|
|
|
|
if ( !pwb->fIpaddrWinsBackupRejected )
|
|
{
|
|
/* Accept the WINS backup address suggested by server.
|
|
*/
|
|
CopyMemory( &pwb->IpInfoLocal.nboWINSAddressBackup,
|
|
pROption->Data, sizeof(IPADDR) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
TraceIp("IPCP: Unrequested option NAKed?");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pROption->Length && pROption->Length < cbLeft)
|
|
cbLeft -= pROption->Length;
|
|
else
|
|
cbLeft = 0;
|
|
|
|
pROption = (PPP_OPTION* )((BYTE* )pROption + pROption->Length);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD
|
|
IpcpConfigRejReceived(
|
|
IN VOID* pWorkBuf,
|
|
IN PPP_CONFIG* pReceiveBuf )
|
|
|
|
/* Examines received configure-reject in 'pReceiveBuf'. See RasCp
|
|
** interface documentation.
|
|
**
|
|
** Returns 0 if successful, otherwise a non-0 error code.
|
|
*/
|
|
{
|
|
IPCPWB* pwb = (IPCPWB* )pWorkBuf;
|
|
PPP_OPTION* pROption = (PPP_OPTION* )pReceiveBuf->Data;
|
|
WORD cbPacket = WireToHostFormat16( pReceiveBuf->Length );
|
|
WORD cbLeft = cbPacket - PPP_CONFIG_HDR_LEN;
|
|
|
|
TraceIp("IPCP: IpcpConfigRejReceived");
|
|
TraceIp("IPCP: Rej received...");
|
|
DUMPB(pReceiveBuf,(pReceiveBuf)?WireToHostFormat16(pReceiveBuf->Length):0);
|
|
|
|
pwb->cRequestsWithoutResponse = 0;
|
|
|
|
while (cbLeft > 0)
|
|
{
|
|
if (pROption->Type == OPTION_IpCompression)
|
|
{
|
|
TraceIp("IPCP: IP compression was rejected");
|
|
pwb->fIpCompressionRejected = TRUE;
|
|
Protocol(pwb->rpcReceive) = 0;
|
|
MaxSlotId(pwb->rpcReceive) = 0;
|
|
CompSlotId(pwb->rpcReceive) = 0;
|
|
}
|
|
else if ( ( pwb->fServer ) &&
|
|
( pwb->IfType != ROUTER_IF_TYPE_FULL_ROUTER ) )
|
|
{
|
|
switch (pROption->Type)
|
|
{
|
|
case OPTION_IpAddress:
|
|
{
|
|
/* He can't handle a server address option. No problem,
|
|
** it's informational only.
|
|
*/
|
|
TraceIp("IPCP: Server IP address was rejected");
|
|
pwb->fIpaddrRejected = TRUE;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
TraceIp("IPCP: Unrequested option rejected?");
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (pROption->Type)
|
|
{
|
|
case OPTION_IpAddress:
|
|
{
|
|
TraceIp("IPCP: IP was rejected");
|
|
|
|
if (pwb->IpAddressLocal != 0)
|
|
{
|
|
/* We accept rejection of the IP address if we know
|
|
** what address we want to use and use it anyway.
|
|
** Some router implementations require a
|
|
** certain IP address but can't handle this option to
|
|
** confirm that.
|
|
*/
|
|
pwb->fIpaddrRejected = TRUE;
|
|
break;
|
|
}
|
|
|
|
if ( pwb->IfType == ROUTER_IF_TYPE_FULL_ROUTER )
|
|
{
|
|
pwb->fUnnumbered = TRUE;
|
|
break;
|
|
}
|
|
else if (pwb->fTryWithoutExtensions)
|
|
{
|
|
/* He doesn't know how to give us an IP address, but
|
|
** we can't accept no for an answer. Have to bail.
|
|
*/
|
|
return ERROR_PPP_NO_ADDRESS_ASSIGNED;
|
|
}
|
|
else
|
|
{
|
|
/* When we request that server assign us an address,
|
|
** this is a required option. If it's rejected assume
|
|
** all the Microsoft extension options were rejected
|
|
** and try again. Other vendors will not test this
|
|
** case explicitly and may have bugs in their reject
|
|
** code.
|
|
*/
|
|
TraceIp("IPCP: Tossing MS options (no address)");
|
|
pwb->fTryWithoutExtensions = TRUE;
|
|
pwb->fIpaddrDnsRejected = TRUE;
|
|
pwb->fIpaddrWinsRejected = TRUE;
|
|
pwb->fIpaddrDnsBackupRejected = TRUE;
|
|
pwb->fIpaddrWinsBackupRejected = TRUE;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
case OPTION_DnsIpAddress:
|
|
{
|
|
/* He doesn't know how to give us a DNS address, but we
|
|
** can live with that.
|
|
*/
|
|
TraceIp("IPCP: DNS was rejected");
|
|
pwb->fIpaddrDnsRejected = TRUE;
|
|
break;
|
|
}
|
|
|
|
case OPTION_WinsIpAddress:
|
|
{
|
|
/* He doesn't know how to give us a WINS address, but we
|
|
** can live with that.
|
|
*/
|
|
TraceIp("IPCP: WINS was rejected");
|
|
pwb->fIpaddrWinsRejected = TRUE;
|
|
break;
|
|
}
|
|
|
|
case OPTION_DnsBackupIpAddress:
|
|
{
|
|
/* He doesn't know how to give us a backup DNS address,
|
|
** but we can live with that.
|
|
*/
|
|
TraceIp("IPCP: DNS backup was rejected");
|
|
pwb->fIpaddrDnsBackupRejected = TRUE;
|
|
break;
|
|
}
|
|
|
|
case OPTION_WinsBackupIpAddress:
|
|
{
|
|
/* He doesn't know how to give us a backup WINS address,
|
|
** but we can live with that.
|
|
*/
|
|
TraceIp("IPCP: WINS backup was rejected");
|
|
pwb->fIpaddrWinsBackupRejected = TRUE;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
TraceIp("IPCP: Unrequested option rejected?");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pROption->Length && pROption->Length <= cbLeft)
|
|
cbLeft -= pROption->Length;
|
|
else
|
|
{
|
|
if (pwb->fTryWithoutExtensions)
|
|
cbLeft = 0;
|
|
else
|
|
{
|
|
/* If an invalid packet is detected, assume all the Microsoft
|
|
** extension options were rejected and try again. Other
|
|
** vendors will not test this case explicitly and may have
|
|
** bugs in their reject code.
|
|
*/
|
|
TraceIp("IPCP: Tossing MS options (length)");
|
|
pwb->fTryWithoutExtensions = TRUE;
|
|
pwb->fIpaddrDnsRejected = TRUE;
|
|
pwb->fIpaddrWinsRejected = TRUE;
|
|
pwb->fIpaddrDnsBackupRejected = TRUE;
|
|
pwb->fIpaddrWinsBackupRejected = TRUE;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
pROption = (PPP_OPTION* )((BYTE* )pROption + pROption->Length);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD
|
|
IpcpGetNegotiatedInfo(
|
|
IN VOID* pWorkBuf,
|
|
OUT PPP_IPCP_RESULT * pIpCpResult
|
|
)
|
|
/* Returns the negotiated IP address in string form followed by the
|
|
** server's IP address, if known. The two addresses are null-terminated
|
|
** strings in back to back 15 + 1 character arrays.
|
|
**
|
|
** Returns 0 if successful, otherwise a non-0 error code. "No address
|
|
** active" is considered successful, and an empty address string is
|
|
** returned.
|
|
*/
|
|
{
|
|
IPCPWB* pwb = (IPCPWB* )pWorkBuf;
|
|
|
|
TraceIp("IPCP: IpcpGetNetworkAddress...");
|
|
|
|
if (pwb->fRasConfigActive || pwb->fExpectingProjection)
|
|
{
|
|
pIpCpResult->fSendVJHCompression = Protocol(pwb->rpcSend);
|
|
pIpCpResult->fReceiveVJHCompression = Protocol(pwb->rpcReceive);
|
|
|
|
pIpCpResult->dwLocalAddress = pwb->IpAddressLocal;
|
|
pIpCpResult->dwLocalWINSAddress = pwb->IpInfoLocal.nboWINSAddress;
|
|
pIpCpResult->dwLocalWINSBackupAddress
|
|
= pwb->IpInfoLocal.nboWINSAddressBackup;
|
|
pIpCpResult->dwLocalDNSAddress = pwb->IpInfoLocal.nboDNSAddress;
|
|
pIpCpResult->dwLocalDNSBackupAddress
|
|
= pwb->IpInfoLocal.nboDNSAddressBackup;
|
|
|
|
pIpCpResult->dwRemoteAddress = pwb->IpAddressRemote;
|
|
pIpCpResult->dwRemoteWINSAddress = pwb->IpInfoRemote.nboWINSAddress;
|
|
pIpCpResult->dwRemoteWINSBackupAddress
|
|
= pwb->IpInfoRemote.nboWINSAddressBackup;
|
|
pIpCpResult->dwRemoteDNSAddress = pwb->IpInfoRemote.nboDNSAddress;
|
|
pIpCpResult->dwRemoteDNSBackupAddress
|
|
= pwb->IpInfoRemote.nboDNSAddressBackup;
|
|
}
|
|
|
|
TraceIp("IPCP: IpcpGetNetworkAddress done");
|
|
return 0;
|
|
}
|
|
|
|
DWORD
|
|
IpcpDhcpInform(
|
|
IN IPCPWB* pwb,
|
|
IN PPP_DHCP_INFORM* pDhcpInform)
|
|
{
|
|
TCPIP_INFO* ptcpip = NULL;
|
|
IPADDR nboMask;
|
|
IPADDR nboIpAddr;
|
|
|
|
DWORD dwErr;
|
|
DWORD dwDomainNameSize;
|
|
size_t size;
|
|
DWORD dwIndex;
|
|
|
|
// Get current TCPIP setup info from registry.
|
|
|
|
TraceIp("IpcpDhcpInform:LoadTcpipInfo(Device=%ws)",pDhcpInform->wszDevice);
|
|
dwErr = LoadTcpipInfo( &ptcpip, pDhcpInform->wszDevice,
|
|
FALSE /* fAdapterOnly */ );
|
|
TraceIp("IpcpDhcpInform:LoadTcpipInfo done(%d)",dwErr);
|
|
|
|
if (dwErr != 0)
|
|
{
|
|
goto LDone;
|
|
}
|
|
|
|
TraceIp("IpcpDhcpInform: Old Dns=%ws",
|
|
ptcpip->wszDNSNameServers ? ptcpip->wszDNSNameServers : L"");
|
|
|
|
for (dwIndex = 0; dwIndex < pDhcpInform->dwNumDNSAddresses; dwIndex++)
|
|
{
|
|
dwErr = PrependDwIpAddress(
|
|
&ptcpip->wszDNSNameServers,
|
|
pDhcpInform->pdwDNSAddresses[dwIndex]);
|
|
|
|
if (dwErr)
|
|
{
|
|
TraceIp("IpcpDhcpInform: PrependDwIpAddress done(%d)",dwErr);
|
|
goto LDone;
|
|
}
|
|
}
|
|
|
|
TraceIp("IpcpDhcpInform: New Dns=%ws",
|
|
ptcpip->wszDNSNameServers ? ptcpip->wszDNSNameServers : L"");
|
|
|
|
if (pDhcpInform->dwWINSAddress1)
|
|
{
|
|
PrintMwsz("IpcpDhcpInform: Old Wins=", ptcpip->mwszNetBIOSNameServers);
|
|
|
|
if (pDhcpInform->dwWINSAddress2)
|
|
{
|
|
dwErr = PrependDwIpAddressToMwsz(
|
|
&ptcpip->mwszNetBIOSNameServers,
|
|
pDhcpInform->dwWINSAddress2);
|
|
|
|
if (dwErr)
|
|
{
|
|
TraceIp("IpcpDhcpInform: PrependDwIpAddress done(%d)",dwErr);
|
|
goto LDone;
|
|
}
|
|
}
|
|
|
|
dwErr = PrependDwIpAddressToMwsz(
|
|
&ptcpip->mwszNetBIOSNameServers,
|
|
pDhcpInform->dwWINSAddress1);
|
|
|
|
if (dwErr)
|
|
{
|
|
TraceIp("IpcpDhcpInform: PrependDwIpAddress done(%d)",dwErr);
|
|
goto LDone;
|
|
}
|
|
|
|
PrintMwsz("IpcpDhcpInform: New Wins=", ptcpip->mwszNetBIOSNameServers);
|
|
}
|
|
|
|
if (pDhcpInform->szDomainName)
|
|
{
|
|
dwDomainNameSize = strlen(pDhcpInform->szDomainName) + 1;
|
|
|
|
LocalFree(ptcpip->wszDNSDomainName);
|
|
|
|
ptcpip->wszDNSDomainName = LocalAlloc(LPTR, sizeof(WCHAR) * dwDomainNameSize);
|
|
|
|
if (NULL == ptcpip->wszDNSDomainName)
|
|
{
|
|
dwErr = GetLastError();
|
|
TraceIp("IpcpDhcpInform: LocalAlloc done(%d)", dwErr);
|
|
goto LDone;
|
|
}
|
|
|
|
if (0 == MultiByteToWideChar(
|
|
CP_ACP,
|
|
0,
|
|
pDhcpInform->szDomainName,
|
|
-1,
|
|
ptcpip->wszDNSDomainName,
|
|
dwDomainNameSize ) )
|
|
{
|
|
dwErr = GetLastError();
|
|
TraceIp("IpcpDhcpInform: Error %d converting domain name %s",
|
|
dwErr,
|
|
pDhcpInform->szDomainName);
|
|
goto LDone;
|
|
}
|
|
}
|
|
|
|
ptcpip->fDisableNetBIOSoverTcpip = pwb->fDisableNetbt;
|
|
|
|
// Set TCPIP setup info in registry and release the buffer.
|
|
|
|
TraceIp("IpcpDhcpInform: SaveTcpipInfo...");
|
|
dwErr = SaveTcpipInfo( ptcpip );
|
|
TraceIp("IpcpDhcpInform: SaveTcpipInfo done(%d)",dwErr);
|
|
|
|
if (dwErr != 0)
|
|
{
|
|
goto LDone;
|
|
}
|
|
|
|
dwErr = ReconfigureTcpip(pDhcpInform->wszDevice, FALSE, 0, 0);
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
TraceIp("IpcpDhcpInform: ReconfigureTcpip=%d",dwErr);
|
|
goto LDone;
|
|
}
|
|
|
|
|
|
nboIpAddr = pwb->IpAddressLocal;
|
|
|
|
if ( !pwb->fPrioritizeRemote )
|
|
{
|
|
// We have added this route only if there is
|
|
// no default route and so remove it if
|
|
// there is no default route
|
|
// Remove the old route with the guessed mask
|
|
|
|
|
|
nboMask = RasTcpDeriveMask(nboIpAddr);
|
|
|
|
if (nboMask != 0)
|
|
{
|
|
RasTcpSetRoute(
|
|
nboIpAddr & nboMask,
|
|
nboIpAddr,
|
|
nboMask,
|
|
nboIpAddr,
|
|
FALSE,
|
|
1,
|
|
TRUE);
|
|
}
|
|
}
|
|
|
|
// Add the new route with the precise mask
|
|
|
|
nboMask = pDhcpInform->dwSubnetMask;
|
|
|
|
if (nboMask != 0)
|
|
{
|
|
RasTcpSetRoute(
|
|
nboIpAddr & nboMask,
|
|
nboIpAddr,
|
|
nboMask,
|
|
nboIpAddr,
|
|
TRUE,
|
|
1,
|
|
TRUE);
|
|
}
|
|
|
|
pwb->dwNumDNSAddresses = pDhcpInform->dwNumDNSAddresses;
|
|
pwb->pdwDNSAddresses = pDhcpInform->pdwDNSAddresses;
|
|
|
|
if ( pDhcpInform->pbDhcpRoutes )
|
|
{
|
|
//Parse the dhcp routes and plumb ths stack
|
|
RasTcpSetDhcpRoutes ( pDhcpInform->pbDhcpRoutes, pwb->IpAddressLocal, TRUE );
|
|
pwb->pbDhcpRoutes = pDhcpInform->pbDhcpRoutes;
|
|
}
|
|
|
|
LDone:
|
|
|
|
FreeTcpipInfo(&ptcpip);
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
DWORD
|
|
ResetNetBTConfigInfo(
|
|
IN IPCPWB* pwb )
|
|
|
|
/*
|
|
** Will reset all the NetBT information in the registry to 0
|
|
*/
|
|
{
|
|
TCPIP_INFO* ptcpip = NULL;
|
|
DWORD dwErr;
|
|
|
|
/* Get current TCPIP setup info from registry.
|
|
*/
|
|
TraceIp("IPCP: LoadTcpipInfo...");
|
|
dwErr = LoadTcpipInfo( &ptcpip, pwb->pwszDevice, TRUE /* fAdapterOnly */ );
|
|
TraceIp("IPCP: LoadTcpipInfo done(%d)",dwErr);
|
|
|
|
if (dwErr)
|
|
{
|
|
goto LDone;
|
|
}
|
|
|
|
ptcpip->fChanged = TRUE ;
|
|
|
|
/* Set TCPIP setup info in registry and release the buffer.
|
|
*/
|
|
TraceIp("IPCP: SaveTcpipInfo...");
|
|
dwErr = SaveTcpipInfo( ptcpip );
|
|
TraceIp("IPCP: SaveTcpipInfo done(%d)",dwErr);
|
|
|
|
LDone:
|
|
|
|
FreeTcpipInfo( &ptcpip );
|
|
|
|
pwb->dwNumDNSAddresses = 0;
|
|
LocalFree(pwb->pdwDNSAddresses);
|
|
pwb->pdwDNSAddresses = NULL;
|
|
|
|
return( dwErr );
|
|
}
|
|
|
|
VOID
|
|
DhcpInform(
|
|
PVOID pContext
|
|
)
|
|
{
|
|
IPCP_DHCP_INFORM* pIpcpDhcpInform = (IPCP_DHCP_INFORM*)pContext;
|
|
PPPE_MESSAGE PppMessage;
|
|
//Changed vivekk
|
|
BYTE pbRequestedOptions[6];
|
|
BYTE* pbOptionList = NULL;
|
|
DWORD dwOptionListSize;
|
|
BYTE* pbReturnedOptions = NULL;
|
|
DWORD dwNumberOfAvailableOptions;
|
|
DWORD dwNumOptions;
|
|
|
|
DWORD dwIndex;
|
|
DWORD dwOffset;
|
|
DWORD dwNextOffset;
|
|
DWORD dwCurOffset;
|
|
DWORD dwDomainNameSize;
|
|
|
|
DWORD dwNumDNSAddresses = 0;
|
|
IPADDR* pnboDNSAddresses = NULL;
|
|
IPADDR nboWINSAddress1 = 0;
|
|
IPADDR nboWINSAddress2 = 0;
|
|
IPADDR nboSubnetMask = 0;
|
|
CHAR* szDomainName = NULL;
|
|
|
|
PBYTE pbRouteInfo = NULL; //Route information got from DHCP option 133
|
|
|
|
DWORD dwErr;
|
|
BOOL fFree = TRUE;
|
|
BOOL fSendMessage = FALSE;
|
|
int i;
|
|
|
|
pbRequestedOptions[0] = OPTION_DNS_NAME_SERVERS;
|
|
pbRequestedOptions[1] = OPTION_NETBIOS_NAME_SERVERS;
|
|
pbRequestedOptions[2] = OPTION_VENDOR_SPEC_INFO;
|
|
pbRequestedOptions[3] = OPTION_SUBNET_MASK;
|
|
pbRequestedOptions[4] = OPTION_VENDOR_ROUTE_PLUMB;
|
|
pbRequestedOptions[5] = OPTION_DNS_DOMAIN_NAME;
|
|
// There is a bug in DhcpRequestOptions, due to which, if we request
|
|
// OPTION_DNS_DOMAIN_NAME, it automatically gets written to the registry
|
|
|
|
if (pIpcpDhcpInform->fUseDhcpInformDomainName)
|
|
{
|
|
dwNumOptions = 6;
|
|
}
|
|
else
|
|
{
|
|
dwNumOptions = 5;
|
|
}
|
|
|
|
TraceIp("DhcpRequestOptions(%ws)...", pIpcpDhcpInform->wszDevice);
|
|
|
|
dwErr = PDhcpRequestOptions(
|
|
pIpcpDhcpInform->wszDevice,
|
|
pbRequestedOptions,
|
|
dwNumOptions,
|
|
&pbOptionList,
|
|
&dwOptionListSize,
|
|
&pbReturnedOptions,
|
|
&dwNumberOfAvailableOptions);
|
|
|
|
TraceIp("DhcpRequestOptions done(%d)", dwErr);
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
goto LDhcpInformEnd;
|
|
}
|
|
|
|
TraceIpDump(pbOptionList, dwOptionListSize);
|
|
|
|
for (dwIndex = 0, dwOffset = 0;
|
|
dwIndex < dwNumberOfAvailableOptions;
|
|
dwIndex++)
|
|
{
|
|
RTASSERT(dwOffset + 1 <= dwOptionListSize);
|
|
|
|
switch (pbReturnedOptions[dwIndex])
|
|
{
|
|
case OPTION_DNS_DOMAIN_NAME:
|
|
|
|
dwDomainNameSize = pbOptionList[dwOffset];
|
|
|
|
if (0 == dwDomainNameSize)
|
|
{
|
|
TraceIp("Invalid DOMAIN_NAME size %d", dwDomainNameSize);
|
|
goto LDhcpInformEnd;
|
|
}
|
|
|
|
if (NULL != szDomainName)
|
|
{
|
|
LocalFree(szDomainName);
|
|
}
|
|
|
|
szDomainName = LocalAlloc(LPTR, dwDomainNameSize + 1);
|
|
|
|
if (NULL == szDomainName)
|
|
{
|
|
TraceIp("DhcpInform: LocalAlloc=%d", GetLastError());
|
|
goto LDhcpInformEnd;
|
|
}
|
|
|
|
dwNextOffset = dwOffset + dwDomainNameSize + 1;
|
|
|
|
CopyMemory(szDomainName, pbOptionList + dwOffset + 1,
|
|
dwDomainNameSize);
|
|
|
|
fSendMessage = TRUE;
|
|
|
|
TraceIp("DhcpInform: DOMAIN_NAME %s", szDomainName);
|
|
|
|
dwOffset = dwNextOffset;
|
|
|
|
break;
|
|
|
|
case OPTION_DNS_NAME_SERVERS:
|
|
|
|
if (0 != (pbOptionList[dwOffset] % 4))
|
|
{
|
|
TraceIp("Invalid DOMAIN_NAME_SERVERS size %d",
|
|
pbOptionList[dwOffset]);
|
|
goto LDhcpInformEnd;
|
|
}
|
|
|
|
if (NULL != pnboDNSAddresses)
|
|
{
|
|
LocalFree(pnboDNSAddresses);
|
|
dwNumDNSAddresses = 0;
|
|
}
|
|
|
|
pnboDNSAddresses = LocalAlloc(LPTR,
|
|
sizeof(IPADDR) * pbOptionList[dwOffset] / 4);
|
|
|
|
if (NULL == pnboDNSAddresses)
|
|
{
|
|
TraceIp("DhcpInform: LocalAlloc=%d",GetLastError());
|
|
goto LDhcpInformEnd;
|
|
}
|
|
|
|
dwNextOffset = dwOffset + pbOptionList[dwOffset] + 1;
|
|
|
|
for (dwCurOffset = dwOffset + 1;
|
|
dwCurOffset < dwNextOffset;
|
|
dwCurOffset += 4, dwNumDNSAddresses++)
|
|
{
|
|
pnboDNSAddresses[dwNumDNSAddresses] =
|
|
(pbOptionList[dwCurOffset]) +
|
|
(pbOptionList[dwCurOffset + 1] << 8) +
|
|
(pbOptionList[dwCurOffset + 2] << 16) +
|
|
(pbOptionList[dwCurOffset + 3] << 24);
|
|
|
|
TraceIp("DhcpInform: DOMAIN_NAME_SERVER 0x%x",
|
|
pnboDNSAddresses[dwNumDNSAddresses]);
|
|
fSendMessage = TRUE;
|
|
}
|
|
|
|
RTASSERT((DWORD)(pbOptionList[dwOffset] / 4) == dwNumDNSAddresses);
|
|
|
|
dwOffset = dwNextOffset;
|
|
|
|
break;
|
|
|
|
case OPTION_NETBIOS_NAME_SERVERS:
|
|
|
|
if (0 != (pbOptionList[dwOffset] % 4))
|
|
{
|
|
TraceIp("Invalid NETBIOS_NAME_SERVER size %d",
|
|
pbOptionList[dwOffset]);
|
|
goto LDhcpInformEnd;
|
|
}
|
|
|
|
dwNextOffset = dwOffset + pbOptionList[dwOffset] + 1;
|
|
dwCurOffset = dwOffset + 1;
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
IPADDR* paddr;
|
|
|
|
if (0 == i)
|
|
{
|
|
paddr = &nboWINSAddress1;
|
|
}
|
|
else
|
|
{
|
|
paddr = &nboWINSAddress2;
|
|
}
|
|
|
|
*paddr =
|
|
(pbOptionList[dwCurOffset]) +
|
|
(pbOptionList[dwCurOffset + 1] << 8) +
|
|
(pbOptionList[dwCurOffset + 2] << 16) +
|
|
(pbOptionList[dwCurOffset + 3] << 24);
|
|
|
|
TraceIp("DhcpInform: NETBIOS_NAME_SERVER 0x%x",
|
|
*paddr);
|
|
|
|
fSendMessage = TRUE;
|
|
|
|
dwCurOffset += 4;
|
|
if (dwCurOffset == dwNextOffset)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwOffset = dwNextOffset;
|
|
|
|
break;
|
|
|
|
case OPTION_SUBNET_MASK:
|
|
|
|
if (0 != (pbOptionList[dwOffset] % 4))
|
|
{
|
|
TraceIp("Invalid OPTION_SUBNET_MASK size %d",
|
|
pbOptionList[dwOffset]);
|
|
goto LDhcpInformEnd;
|
|
}
|
|
|
|
dwNextOffset = dwOffset + pbOptionList[dwOffset] + 1;
|
|
|
|
nboSubnetMask = (pbOptionList[dwOffset + 1]) +
|
|
(pbOptionList[dwOffset + 2] << 8) +
|
|
(pbOptionList[dwOffset + 3] << 16) +
|
|
(pbOptionList[dwOffset + 4] << 24);
|
|
|
|
TraceIp("DhcpInform: OPTION_SUBNET_MASK 0x%x", nboSubnetMask);
|
|
|
|
fSendMessage = TRUE;
|
|
|
|
dwOffset = dwNextOffset;
|
|
|
|
break;
|
|
case OPTION_VENDOR_ROUTE_PLUMB:
|
|
TraceIp("DhcpInform: OPTION_VENDOR_ROUTE_PLUMB Code %x Len %x", pbOptionList[dwOffset], pbOptionList[dwOffset+1]);
|
|
//this should be a minimum of 5 bytes
|
|
dwNextOffset = dwOffset + pbOptionList[dwOffset] + 1;
|
|
if ( pbOptionList[dwOffset+1] < 5 )
|
|
{
|
|
TraceIp("Invalid OPTION_VENDOR_ROUTE_PLUMB size %d", pbOptionList[dwOffset+1]);
|
|
goto LDhcpInformEnd;
|
|
}
|
|
//now decode the
|
|
fSendMessage = TRUE;
|
|
pbRouteInfo = (PBYTE)LocalAlloc(LPTR, pbOptionList[dwOffset] + 1 );
|
|
if (NULL == pbRouteInfo)
|
|
{
|
|
TraceIp("DhcpInform: LocalAlloc=%d",GetLastError());
|
|
goto LDhcpInformEnd;
|
|
}
|
|
CopyMemory(pbRouteInfo, pbOptionList + dwOffset,
|
|
pbOptionList[dwOffset]+1);
|
|
fSendMessage= TRUE;
|
|
dwOffset = dwNextOffset;
|
|
break;
|
|
default:
|
|
|
|
dwOffset += pbOptionList[dwOffset] + 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (fSendMessage)
|
|
{
|
|
PppMessage.dwMsgId = PPPEMSG_DhcpInform;
|
|
PppMessage.hConnection = pIpcpDhcpInform->hConnection;
|
|
PppMessage.ExtraInfo.DhcpInform.wszDevice = pIpcpDhcpInform->wszDevice;
|
|
PppMessage.ExtraInfo.DhcpInform.dwNumDNSAddresses = dwNumDNSAddresses;
|
|
PppMessage.ExtraInfo.DhcpInform.pdwDNSAddresses = pnboDNSAddresses;
|
|
PppMessage.ExtraInfo.DhcpInform.dwWINSAddress1 = nboWINSAddress1;
|
|
PppMessage.ExtraInfo.DhcpInform.dwWINSAddress2 = nboWINSAddress2;
|
|
PppMessage.ExtraInfo.DhcpInform.dwSubnetMask = nboSubnetMask;
|
|
PppMessage.ExtraInfo.DhcpInform.szDomainName = szDomainName;
|
|
PppMessage.ExtraInfo.DhcpInform.pbDhcpRoutes = pbRouteInfo;
|
|
dwErr = SendPPPMessageToEngine(&PppMessage);
|
|
|
|
if (dwErr != NO_ERROR)
|
|
{
|
|
TraceIp("DhcpInform: SendPPPMessageToEngine=%d",dwErr);
|
|
goto LDhcpInformEnd;
|
|
}
|
|
|
|
fFree = FALSE;
|
|
}
|
|
|
|
LDhcpInformEnd:
|
|
|
|
if (fFree)
|
|
{
|
|
LocalFree(pIpcpDhcpInform->wszDevice);
|
|
LocalFree(pnboDNSAddresses);
|
|
LocalFree(szDomainName);
|
|
LocalFree(pbRouteInfo);
|
|
}
|
|
|
|
LocalFree(pIpcpDhcpInform);
|
|
LocalFree(pbOptionList);
|
|
LocalFree(pbReturnedOptions);
|
|
}
|
|
|
|
DWORD
|
|
IpcpProjectionNotification(
|
|
IN VOID* pWorkBuf,
|
|
IN VOID* pProjectionResult )
|
|
|
|
/* Called when projection result of all CPs is known.
|
|
**
|
|
** Returns 0 if successful, otherwise a non-0 error code.
|
|
*/
|
|
{
|
|
DWORD dwErr = 0;
|
|
IPCPWB* pwb = (IPCPWB* )pWorkBuf;
|
|
BOOL fSetDefaultRoute = FALSE;
|
|
|
|
TraceIp("IPCP: IpcpProjectionNotification");
|
|
|
|
if (pwb->fExpectingProjection)
|
|
{
|
|
CHAR szBuf[sizeof(PROTOCOL_CONFIG_INFO) + sizeof(IP_WAN_LINKUP_INFO)];
|
|
|
|
IPCPWB* pwb = (IPCPWB* )pWorkBuf;
|
|
PROTOCOL_CONFIG_INFO* pProtocol = (PROTOCOL_CONFIG_INFO* )szBuf;
|
|
IP_WAN_LINKUP_INFO UNALIGNED *pLinkUp = (PIP_WAN_LINKUP_INFO)pProtocol->P_Info;
|
|
PPP_PROJECTION_RESULT* p = (PPP_PROJECTION_RESULT* )pProjectionResult;
|
|
|
|
/* Activate the route between the TCP/IP stack and the RAS MAC.
|
|
*/
|
|
pProtocol->P_Length = sizeof(IP_WAN_LINKUP_INFO);
|
|
|
|
pLinkUp->duUsage = ( pwb->IfType == ROUTER_IF_TYPE_FULL_ROUTER )
|
|
? DU_ROUTER
|
|
: (pwb->fServer) ? DU_CALLIN : DU_CALLOUT;
|
|
|
|
pLinkUp->dwUserIfIndex = HandleToULong(pwb->hIPInterface);
|
|
pLinkUp->dwLocalMask = 0xFFFFFFFF;
|
|
pLinkUp->dwLocalAddr = pwb->IpAddressLocal;
|
|
pLinkUp->dwRemoteAddr = pwb->IpAddressRemote;
|
|
|
|
pLinkUp->fFilterNetBios =
|
|
(pwb->fServer && p->nbf.dwError == 0);
|
|
|
|
pLinkUp->fDefaultRoute = pwb->fPrioritizeRemote;
|
|
|
|
TraceIp("IPCP: RasActivateRoute(u=%x,a=%x,nf=%d)...",
|
|
pLinkUp->duUsage,pLinkUp->dwLocalAddr,
|
|
pLinkUp->fFilterNetBios);
|
|
|
|
TraceIp("IPCP: RasActivateRoute ICB# == %d",
|
|
pLinkUp->dwUserIfIndex);
|
|
|
|
dwErr = RasActivateRoute(pwb->hport,IP,&pwb->routeinfo,pProtocol);
|
|
|
|
TraceIp("IPCP: RasActivateRoute done(%d)",dwErr);
|
|
|
|
if ( dwErr == 0 )
|
|
{
|
|
pwb->fRouteActivated = TRUE;
|
|
|
|
/* Find the device name within the adapter name, e.g. ndiswan00.
|
|
** This is used to identify adapters in the TcpipInfo calls later.
|
|
*/
|
|
pwb->pwszDevice = wcschr(&pwb->routeinfo.RI_AdapterName[1], L'\\');
|
|
|
|
if ( !pwb->pwszDevice )
|
|
{
|
|
TraceIp("IPCP: No device?");
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
++pwb->pwszDevice;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we are a client or a router dialing in or out we need to plumb
|
|
// the registry.
|
|
//
|
|
|
|
if ( ( dwErr == 0 ) &&
|
|
((!pwb->fServer) || (pwb->IfType == ROUTER_IF_TYPE_FULL_ROUTER)))
|
|
{
|
|
do
|
|
{
|
|
|
|
TCPIP_INFO* ptcpip;
|
|
|
|
/* Get current TCPIP setup info from registry.
|
|
*/
|
|
TraceIp("IPCP:LoadTcpipInfo(Device=%ws)",pwb->pwszDevice);
|
|
dwErr = LoadTcpipInfo( &ptcpip, pwb->pwszDevice,
|
|
TRUE /* fAdapterOnly */ );
|
|
TraceIp("IPCP: LoadTcpipInfo done(%d)",dwErr);
|
|
|
|
if (dwErr != 0)
|
|
break;
|
|
|
|
//
|
|
// We first save the IP address and call
|
|
// DhcpNotifyConfigChange, then set WINS/DNS and call
|
|
// DhcpNotifyConfigChange to work around Windows 2000 bug
|
|
// 381884.
|
|
//
|
|
|
|
AbcdWszFromIpAddress(pwb->IpAddressLocal, ptcpip->wszIPAddress);
|
|
AbcdWszFromIpAddress(pLinkUp->dwLocalMask, ptcpip->wszSubnetMask);
|
|
|
|
ptcpip->fDisableNetBIOSoverTcpip = pwb->fDisableNetbt;
|
|
|
|
ptcpip->fChanged = TRUE ;
|
|
|
|
TraceIp("IPCP: SaveTcpipInfo...");
|
|
|
|
dwErr = SaveTcpipInfo( ptcpip );
|
|
|
|
TraceIp("IPCP: SaveTcpipInfo done(%d)",dwErr);
|
|
|
|
if (dwErr)
|
|
{
|
|
ResetNetBTConfigInfo( pwb );
|
|
FreeTcpipInfo( &ptcpip );
|
|
break;
|
|
}
|
|
|
|
#if 0
|
|
if (!pwb->fUnnumbered)
|
|
{
|
|
/* Tell TCPIP components to reconfigure themselves.
|
|
*/
|
|
if ((dwErr = ReconfigureTcpip(pwb->pwszDevice,
|
|
TRUE,
|
|
pwb->IpAddressLocal,
|
|
pLinkUp->dwLocalMask)) != NO_ERROR)
|
|
{
|
|
TraceIp("IPCP: ReconfigureTcpip=%d",dwErr);
|
|
ResetNetBTConfigInfo( pwb );
|
|
FreeTcpipInfo( &ptcpip );
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/* Make the LAN the default interface in multi-homed case.
|
|
*/
|
|
if(pLinkUp->duUsage != DU_ROUTER)
|
|
{
|
|
|
|
BOOL fAddRoute = TRUE;
|
|
RASMAN_INFO *pInfo = LocalAlloc(LPTR, sizeof(RASMAN_INFO));
|
|
|
|
if(NULL != pInfo)
|
|
{
|
|
dwErr = RasGetInfo(NULL, pwb->hport, pInfo);
|
|
if(ERROR_SUCCESS != dwErr)
|
|
{
|
|
TraceIp("IPCP: HelperSetDefaultInterfaceNet, RasGetInfo "
|
|
"failed 0x%x", dwErr);
|
|
}
|
|
|
|
if(RAS_DEVICE_CLASS(pInfo->RI_rdtDeviceType)
|
|
== RDT_Tunnel)
|
|
{
|
|
fAddRoute = FALSE;
|
|
}
|
|
|
|
LocalFree(pInfo);
|
|
}
|
|
|
|
//
|
|
// Do the change metric and add subnet route stuff
|
|
// for non router cases only
|
|
//
|
|
|
|
TraceIp("IPCP: HelperSetDefaultInterfaceNet(a=%08x,f=%d)",
|
|
pwb->IpAddressLocal,pwb->fPrioritizeRemote);
|
|
|
|
dwErr = HelperSetDefaultInterfaceNet(
|
|
pwb->IpAddressLocal,
|
|
(fAddRoute) ?
|
|
pwb->IpAddressRemote :
|
|
0,
|
|
pwb->fPrioritizeRemote,
|
|
pwb->pwszDevice);
|
|
|
|
TraceIp("IPCP: HelperSetDefaultInterfaceNet done(%d)",
|
|
dwErr);
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
// ResetNetBTConfigInfo( pwb );
|
|
// FreeTcpipInfo( &ptcpip );
|
|
break;
|
|
}
|
|
|
|
fSetDefaultRoute = TRUE;
|
|
}
|
|
|
|
|
|
#if 0
|
|
|
|
/* Get current TCPIP setup info from registry.
|
|
*/
|
|
TraceIp("IPCP:LoadTcpipInfo(Device=%ws)",pwb->pwszDevice);
|
|
dwErr = LoadTcpipInfo( &ptcpip, pwb->pwszDevice,
|
|
TRUE /* fAdapterOnly */ );
|
|
TraceIp("IPCP: LoadTcpipInfo done(%d)",dwErr);
|
|
|
|
if (dwErr != 0)
|
|
break;
|
|
|
|
AbcdWszFromIpAddress(pwb->IpAddressLocal, ptcpip->wszIPAddress);
|
|
AbcdWszFromIpAddress(pLinkUp->dwLocalMask, ptcpip->wszSubnetMask);
|
|
|
|
#endif
|
|
|
|
ptcpip->fChanged = FALSE ;
|
|
|
|
/* Add the negotiated DNS and backup DNS server (if any)
|
|
** at the head of the list of DNS servers. (Backup is
|
|
** done first so the the non-backup will wind up first)
|
|
*/
|
|
if (pwb->IpInfoLocal.nboDNSAddressBackup)
|
|
{
|
|
dwErr = PrependDwIpAddress(
|
|
&ptcpip->wszDNSNameServers,
|
|
pwb->IpInfoLocal.nboDNSAddressBackup );
|
|
|
|
if (dwErr)
|
|
{
|
|
FreeTcpipInfo( &ptcpip );
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pwb->IpInfoLocal.nboDNSAddress)
|
|
{
|
|
dwErr = PrependDwIpAddress(
|
|
&ptcpip->wszDNSNameServers,
|
|
pwb->IpInfoLocal.nboDNSAddress );
|
|
|
|
if (dwErr)
|
|
{
|
|
FreeTcpipInfo( &ptcpip );
|
|
break;
|
|
}
|
|
}
|
|
|
|
TraceIp("IPCP: New Dns=%ws",
|
|
ptcpip->wszDNSNameServers ? ptcpip->wszDNSNameServers : L"");
|
|
|
|
if (!pwb->fRegisterWithWINS)
|
|
{
|
|
// Ignore the WINS server addresses. If we save them, then
|
|
// registration will happen automatically.
|
|
}
|
|
else
|
|
{
|
|
/* Set the WINS and backup WINS server addresses to
|
|
** the negotiated addresses (if any).
|
|
*/
|
|
|
|
if (pwb->IpInfoLocal.nboWINSAddressBackup)
|
|
{
|
|
dwErr = PrependDwIpAddressToMwsz(
|
|
&ptcpip->mwszNetBIOSNameServers,
|
|
pwb->IpInfoLocal.nboWINSAddressBackup );
|
|
|
|
if (dwErr)
|
|
{
|
|
FreeTcpipInfo( &ptcpip );
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pwb->IpInfoLocal.nboWINSAddress)
|
|
{
|
|
dwErr = PrependDwIpAddressToMwsz(
|
|
&ptcpip->mwszNetBIOSNameServers,
|
|
pwb->IpInfoLocal.nboWINSAddress );
|
|
|
|
if (dwErr)
|
|
{
|
|
FreeTcpipInfo( &ptcpip );
|
|
break;
|
|
}
|
|
}
|
|
|
|
PrintMwsz("IPCP: New Wins=",
|
|
ptcpip->mwszNetBIOSNameServers);
|
|
}
|
|
|
|
// The DNS API's are called in rasSrvrInitAdapterName also.
|
|
|
|
if (pwb->fRegisterWithDNS)
|
|
{
|
|
DnsEnableDynamicRegistration(pwb->pwszDevice);
|
|
TraceIp("DnsEnableDynamicRegistration");
|
|
}
|
|
else
|
|
{
|
|
DnsDisableDynamicRegistration(pwb->pwszDevice);
|
|
TraceIp("DnsDisableDynamicRegistration");
|
|
}
|
|
|
|
if (pwb->fRegisterAdapterDomainName)
|
|
{
|
|
DnsEnableAdapterDomainNameRegistration(pwb->pwszDevice);
|
|
TraceIp("DnsEnableAdapterDomainNameRegistration");
|
|
}
|
|
else
|
|
{
|
|
DnsDisableAdapterDomainNameRegistration(pwb->pwszDevice);
|
|
TraceIp("DnsDisableAdapterDomainNameRegistration");
|
|
}
|
|
|
|
if (pwb->szDnsSuffix[0] != 0)
|
|
{
|
|
DWORD dwDomainNameSize;
|
|
|
|
dwDomainNameSize = strlen(pwb->szDnsSuffix) + 1;
|
|
|
|
ptcpip->wszDNSDomainName = LocalAlloc(LPTR, sizeof(WCHAR) * dwDomainNameSize);
|
|
|
|
if (NULL != ptcpip->wszDNSDomainName)
|
|
{
|
|
MultiByteToWideChar(
|
|
CP_ACP,
|
|
0,
|
|
pwb->szDnsSuffix,
|
|
-1,
|
|
ptcpip->wszDNSDomainName,
|
|
dwDomainNameSize );
|
|
}
|
|
}
|
|
|
|
TraceIp("IPCP: SaveTcpipInfo...");
|
|
|
|
dwErr = SaveTcpipInfo( ptcpip );
|
|
|
|
TraceIp("IPCP: SaveTcpipInfo done(%d)",dwErr);
|
|
|
|
FreeTcpipInfo( &ptcpip );
|
|
|
|
if (dwErr != 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (!pwb->fUnnumbered)
|
|
{
|
|
/* Tell TCPIP components to reconfigure themselves.
|
|
*/
|
|
if ((dwErr = ReconfigureTcpip(pwb->pwszDevice,
|
|
TRUE,
|
|
pwb->IpAddressLocal,
|
|
pLinkUp->dwLocalMask)) != NO_ERROR)
|
|
{
|
|
TraceIp("IPCP: ReconfigureTcpip=%d",dwErr);
|
|
// This will fail if the dhcp client is not running.
|
|
// dwErr = NO_ERROR;
|
|
ResetNetBTConfigInfo( pwb );
|
|
break;
|
|
}
|
|
}
|
|
/* Adjust the metric for Multicast class D Addresses */
|
|
if ( (!pwb->fServer)
|
|
)
|
|
{
|
|
dwErr = RasTcpAdjustMulticastRouteMetric ( pwb->IpAddressLocal, TRUE );
|
|
if ( NO_ERROR != dwErr )
|
|
{
|
|
TraceIp("IPCP: =RasTcpAdjustMulticastRouteMetric%d",dwErr);
|
|
dwErr = NO_ERROR;
|
|
}
|
|
|
|
|
|
}
|
|
/* Do DHCPINFORM only for clients */
|
|
|
|
while ((!pwb->fServer) &&
|
|
(pwb->IfType != ROUTER_IF_TYPE_FULL_ROUTER))
|
|
{
|
|
IPCP_DHCP_INFORM* pIpcpDhcpInform = NULL;
|
|
BOOL fErr = TRUE;
|
|
|
|
pIpcpDhcpInform = LocalAlloc(LPTR, sizeof(IPCP_DHCP_INFORM));
|
|
|
|
if (NULL == pIpcpDhcpInform)
|
|
{
|
|
TraceIp("IPCP: LocalAlloc 1 =%d",GetLastError());
|
|
goto LWhileEnd;
|
|
}
|
|
|
|
pIpcpDhcpInform->fUseDhcpInformDomainName =
|
|
(pwb->szDnsSuffix[0] == 0);
|
|
|
|
pIpcpDhcpInform->wszDevice = LocalAlloc(LPTR,
|
|
sizeof(WCHAR) * (wcslen(pwb->pwszDevice) + 1));
|
|
|
|
if (NULL == pIpcpDhcpInform->wszDevice)
|
|
{
|
|
TraceIp("IPCP: LocalAlloc 2 =%d",GetLastError());
|
|
goto LWhileEnd;
|
|
}
|
|
|
|
wcscpy(pIpcpDhcpInform->wszDevice, pwb->pwszDevice);
|
|
pIpcpDhcpInform->hConnection = pwb->hConnection;
|
|
|
|
dwErr = RtlQueueWorkItem(DhcpInform, pIpcpDhcpInform,
|
|
WT_EXECUTELONGFUNCTION);
|
|
|
|
if (dwErr != STATUS_SUCCESS)
|
|
{
|
|
TraceIp("IPCP: RtlQueueWorkItem=%d",dwErr);
|
|
goto LWhileEnd;
|
|
}
|
|
|
|
fErr = FALSE;
|
|
|
|
LWhileEnd:
|
|
if (fErr)
|
|
{
|
|
if (pIpcpDhcpInform)
|
|
{
|
|
LocalFree(pIpcpDhcpInform->wszDevice);
|
|
}
|
|
|
|
LocalFree(pIpcpDhcpInform);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
while (FALSE);
|
|
}
|
|
|
|
if (dwErr == 0)
|
|
{
|
|
pwb->fRasConfigActive = TRUE;
|
|
|
|
/* Tell MAC about any negotiated compression parameters.
|
|
*/
|
|
if (pwb->fIpCompressionRejected)
|
|
{
|
|
Protocol(pwb->rpcReceive) = NO_PROTOCOL_COMPRESSION;
|
|
MaxSlotId(pwb->rpcReceive) = 0;
|
|
CompSlotId(pwb->rpcReceive) = 0;
|
|
}
|
|
|
|
if (!pwb->fSendCompression)
|
|
{
|
|
Protocol(pwb->rpcSend) = NO_PROTOCOL_COMPRESSION;
|
|
MaxSlotId(pwb->rpcSend) = 0;
|
|
CompSlotId(pwb->rpcSend) = 0;
|
|
}
|
|
|
|
//if (Protocol(pwb->rpcSend) != 0 || Protocol(pwb->rpcReceive) != 0)
|
|
{
|
|
TraceIp("IPCP:RasPortSetProtocolCompression(s=%d,%d r=%d,%d)",
|
|
(int)MaxSlotId(pwb->rpcSend),(int)CompSlotId(pwb->rpcSend),
|
|
(int)MaxSlotId(pwb->rpcReceive),
|
|
(int)CompSlotId(pwb->rpcReceive));
|
|
dwErr = RasPortSetProtocolCompression(
|
|
pwb->hport, IP, &pwb->rpcSend, &pwb->rpcReceive );
|
|
TraceIp("IPCP: RasPortSetProtocolCompression done(%d)",dwErr);
|
|
}
|
|
|
|
if ( ( ( pwb->fServer ) ||
|
|
( pwb->IfType == ROUTER_IF_TYPE_FULL_ROUTER ) )
|
|
&& ( pwb->IpAddressRemote != 0 ))
|
|
{
|
|
WCHAR* pwsz[5];
|
|
WCHAR wszIPAddress[MAXIPSTRLEN + 1];
|
|
WCHAR wszSubnet[MAXIPSTRLEN + 1];
|
|
WCHAR wszMask[MAXIPSTRLEN + 1];
|
|
|
|
/* Register addresses in server's routing tables.
|
|
*/
|
|
|
|
TraceIp("IPCP: RasSrvrActivateIp...");
|
|
dwErr = RasSrvrActivateIp( pwb->IpAddressRemote,
|
|
pLinkUp->duUsage );
|
|
TraceIp("IPCP: RasSrvrActivateIp done(%d)",dwErr);
|
|
}
|
|
|
|
if ( pwb->IfType == ROUTER_IF_TYPE_FULL_ROUTER )
|
|
{
|
|
WCHAR* pwsz[2];
|
|
|
|
if ( pwb->IpAddressRemote == 0 )
|
|
{
|
|
pwsz[0] = pwb->wszPortName;
|
|
pwsz[1] = pwb->wszUserName;
|
|
|
|
LogEventW(EVENTLOG_WARNING_TYPE,
|
|
ROUTERLOG_REMOTE_UNNUMBERED_IPCP, 2,
|
|
pwsz);
|
|
}
|
|
|
|
if ( pwb->IpAddressLocal == 0 )
|
|
{
|
|
pwsz[0] = pwb->wszPortName;
|
|
pwsz[1] = pwb->wszUserName;
|
|
|
|
LogEventW(EVENTLOG_WARNING_TYPE,
|
|
ROUTERLOG_LOCAL_UNNUMBERED_IPCP, 2,
|
|
pwsz);
|
|
}
|
|
}
|
|
}
|
|
|
|
pwb->fExpectingProjection = FALSE;
|
|
|
|
if (dwErr != NO_ERROR)
|
|
{
|
|
if(pwb->fRouteActivated)
|
|
{
|
|
TraceIp("IPCP: RasDeAllocateRoute...");
|
|
RasDeAllocateRoute( pwb->hConnection, IP );
|
|
pwb->fRouteActivated = FALSE;
|
|
}
|
|
|
|
if(fSetDefaultRoute)
|
|
{
|
|
HelperResetDefaultInterfaceNet(
|
|
pwb->IpAddressLocal,
|
|
pwb->fPrioritizeRemote);
|
|
}
|
|
}
|
|
}
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
** Internal routines (alphabetically)
|
|
**---------------------------------------------------------------------------
|
|
*/
|
|
|
|
|
|
VOID
|
|
AddIpAddressOption(
|
|
OUT BYTE UNALIGNED* pbBuf,
|
|
IN BYTE bOption,
|
|
IN IPADDR ipaddr )
|
|
|
|
/* Write an IP address 'ipaddr' configuration option of type 'bOption' at
|
|
** location 'pbBuf'.
|
|
*/
|
|
{
|
|
*pbBuf++ = bOption;
|
|
*pbBuf++ = IPADDRESSOPTIONLEN;
|
|
*((IPADDR UNALIGNED* )pbBuf) = ipaddr;
|
|
}
|
|
|
|
|
|
VOID
|
|
AddIpCompressionOption(
|
|
OUT BYTE UNALIGNED* pbBuf,
|
|
IN RAS_PROTOCOLCOMPRESSION* prpc )
|
|
|
|
/* Write an IP compression protocol configuration as described in '*prpc'
|
|
** at location 'pbBuf'.
|
|
*/
|
|
{
|
|
*pbBuf++ = OPTION_IpCompression;
|
|
*pbBuf++ = IPCOMPRESSIONOPTIONLEN;
|
|
HostToWireFormat16U( Protocol(*prpc), pbBuf );
|
|
pbBuf += 2;
|
|
*pbBuf++ = MaxSlotId(*prpc);
|
|
*pbBuf = CompSlotId(*prpc);
|
|
}
|
|
|
|
/*
|
|
|
|
Notes:
|
|
DeActivates the active RAS configuration, if any.
|
|
|
|
*/
|
|
|
|
DWORD
|
|
DeActivateRasConfig(
|
|
IN IPCPWB* pwb
|
|
)
|
|
{
|
|
DWORD dwErr = NO_ERROR;
|
|
|
|
if (!pwb->fRasConfigActive)
|
|
{
|
|
goto LDone;
|
|
}
|
|
|
|
TraceIp("DeActivateRasConfig");
|
|
|
|
dwErr = ResetNetBTConfigInfo(pwb);
|
|
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
goto LDone;
|
|
}
|
|
/* Adjust the metric for Multicast class D Addresses */
|
|
if ( (!pwb->fServer)
|
|
)
|
|
{
|
|
RasTcpAdjustMulticastRouteMetric ( pwb->IpAddressLocal, FALSE );
|
|
//The route will be automatically removed when the interface disapperars
|
|
}
|
|
|
|
dwErr = ReconfigureTcpip(pwb->pwszDevice, TRUE, 0, 0);
|
|
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
// Ignore errors. You may get a 15 here.
|
|
dwErr = NO_ERROR;
|
|
}
|
|
|
|
if (pwb->IfType != ROUTER_IF_TYPE_FULL_ROUTER)
|
|
{
|
|
TraceIp("HelperResetDefaultInterfaceNet(0x%x, %sPrioritizeRemote)",
|
|
pwb->IpAddressLocal,
|
|
pwb->fPrioritizeRemote ? "" : "!");
|
|
|
|
dwErr = HelperResetDefaultInterfaceNet(
|
|
pwb->IpAddressLocal, pwb->fPrioritizeRemote);
|
|
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
TraceIp("HelperResetDefaultInterfaceNet failed and returned %d",
|
|
dwErr);
|
|
}
|
|
}
|
|
|
|
LDone:
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
DWORD
|
|
NakCheck(
|
|
IN IPCPWB* pwb,
|
|
IN PPP_CONFIG* pReceiveBuf,
|
|
OUT PPP_CONFIG* pSendBuf,
|
|
IN DWORD cbSendBuf,
|
|
OUT BOOL* pfNak,
|
|
IN BOOL fRejectNaks )
|
|
|
|
/* Check to see if received packet 'pReceiveBuf' should be Naked and if
|
|
** so, build a Nak packet with suggested values in 'pSendBuf'. If
|
|
** 'fRejectNaks' is set the original options are placed in a Reject packet
|
|
** instead. '*pfNak' is set true if either a Nak or Rej packet was
|
|
** created.
|
|
**
|
|
** Note: This routine assumes that corrupt packets have already been
|
|
** weeded out.
|
|
**
|
|
** Returns 0 if successful, otherwise a non-0 error code.
|
|
*/
|
|
{
|
|
PPP_OPTION UNALIGNED* pROption = (PPP_OPTION UNALIGNED* )pReceiveBuf->Data;
|
|
PPP_OPTION UNALIGNED* pSOption = (PPP_OPTION UNALIGNED* )pSendBuf->Data;
|
|
|
|
/* (server only) The address the client requests, then if NAKed, the non-0
|
|
** address we NAK with. If this is 0 after the packet has been processed,
|
|
** the IP-Address option was not negotiated.
|
|
*/
|
|
IPADDR ipaddrClient = 0;
|
|
|
|
DWORD dwErr = 0;
|
|
WORD cbPacket = WireToHostFormat16( pReceiveBuf->Length );
|
|
WORD cbLeft = cbPacket - PPP_CONFIG_HDR_LEN;
|
|
|
|
TraceIp("IPCP: NakCheck");
|
|
|
|
*pfNak = FALSE;
|
|
|
|
while (cbLeft > 0)
|
|
{
|
|
RTASSERT(cbLeft>=pROption->Length);
|
|
|
|
if (pROption->Type == OPTION_IpCompression)
|
|
{
|
|
BOOL fNakCompression = FALSE;
|
|
|
|
if (WireToHostFormat16U(pROption->Data )
|
|
== COMPRESSION_VanJacobson)
|
|
{
|
|
RTASSERT((pROption->Length==IPCOMPRESSIONOPTIONLEN));
|
|
|
|
/* He wants to receive Van Jacobson. We know we can do it or
|
|
** it would have already been rejected, but make sure we can
|
|
** handle his slot parameters.
|
|
*/
|
|
if (pROption->Data[ 2 ] <= MaxSlotId(pwb->rpcSend))
|
|
{
|
|
/* We can accept his suggested MaxSlotID when it is less
|
|
** than or the same as what we can send.
|
|
*/
|
|
MaxSlotId(pwb->rpcSend) = pROption->Data[ 2 ];
|
|
}
|
|
else
|
|
fNakCompression = TRUE;
|
|
|
|
if (CompSlotId(pwb->rpcSend))
|
|
{
|
|
/* We can compress the slot-ID or not, so just accept
|
|
** whatever he wants us to send.
|
|
*/
|
|
CompSlotId(pwb->rpcSend) = pROption->Data[ 3 ];
|
|
}
|
|
else if (pROption->Data[ 3 ])
|
|
fNakCompression = TRUE;
|
|
}
|
|
else
|
|
fNakCompression = TRUE;
|
|
|
|
if (fNakCompression)
|
|
{
|
|
TraceIp("IPCP: Naking IP compression");
|
|
*pfNak = TRUE;
|
|
|
|
if (fRejectNaks)
|
|
{
|
|
CopyMemory(
|
|
(VOID* )pSOption, (VOID* )pROption, pROption->Length );
|
|
}
|
|
else
|
|
{
|
|
pSOption->Type = OPTION_IpCompression;
|
|
pSOption->Length = IPCOMPRESSIONOPTIONLEN;
|
|
HostToWireFormat16U(
|
|
(WORD )COMPRESSION_VanJacobson,
|
|
pSOption->Data );
|
|
|
|
pSOption->Data[ 2 ] = MaxSlotId(pwb->rpcSend);
|
|
pSOption->Data[ 3 ] = CompSlotId(pwb->rpcSend);
|
|
|
|
pSOption =
|
|
(PPP_OPTION UNALIGNED* )((BYTE* )pSOption +
|
|
pSOption->Length);
|
|
}
|
|
|
|
pwb->fSendCompression = FALSE;
|
|
}
|
|
else
|
|
{
|
|
pwb->fSendCompression = TRUE;
|
|
}
|
|
}
|
|
else if ((pwb->fServer) || (pwb->IfType == ROUTER_IF_TYPE_FULL_ROUTER))
|
|
{
|
|
switch (pROption->Type)
|
|
{
|
|
case OPTION_IpAddress:
|
|
{
|
|
RTASSERT(pROption->Length==IPADDRESSOPTIONLEN);
|
|
CopyMemory( &ipaddrClient, pROption->Data, sizeof(IPADDR) );
|
|
|
|
if (pwb->IpAddressRemote != 0)
|
|
{
|
|
if ( ipaddrClient == pwb->IpAddressRemote )
|
|
{
|
|
//
|
|
// If we have already allocated what the user
|
|
// wants, we are done with this option.
|
|
//
|
|
|
|
break;
|
|
}
|
|
else if ( ipaddrClient == 0 )
|
|
{
|
|
ipaddrClient = pwb->IpAddressRemote;
|
|
|
|
*pfNak = TRUE;
|
|
CopyMemory(
|
|
(VOID* )pSOption, (VOID* )pROption,
|
|
pROption->Length );
|
|
|
|
if (!fRejectNaks)
|
|
{
|
|
TraceIp("IPCP: Naking IP");
|
|
|
|
CopyMemory( pSOption->Data,
|
|
&pwb->IpAddressRemote,
|
|
sizeof(IPADDR) );
|
|
}
|
|
|
|
pSOption =
|
|
(PPP_OPTION UNALIGNED* )((BYTE* )pSOption +
|
|
pROption->Length);
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
TraceIp("IPCP: RasSrvrReleaseAddress...");
|
|
RasSrvrReleaseAddress(
|
|
pwb->IpAddressRemote,
|
|
pwb->wszUserName,
|
|
pwb->wszPortName,
|
|
FALSE );
|
|
TraceIp("IPCP: RasSrvrReleaseAddress done");
|
|
|
|
pwb->IpAddressRemote = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If client is requesting an IP address, check to see
|
|
// if we are allowed to give it to him.
|
|
//
|
|
|
|
if ( ( ipaddrClient != 0 ) &&
|
|
( pwb->IfType != ROUTER_IF_TYPE_FULL_ROUTER ) &&
|
|
( pwb->IpAddressToHandout == net_long( 0xFFFFFFFE ) ) )
|
|
{
|
|
TraceIp("IPCP: Clients not allowed to request IPaddr");
|
|
|
|
ipaddrClient = 0;
|
|
}
|
|
|
|
TraceIp("IPCP: RasSrvrAcquireAddress(%08x)...",
|
|
ipaddrClient);
|
|
dwErr = RasSrvrAcquireAddress(
|
|
pwb->hport,
|
|
((pwb->IpAddressToHandout != net_long(0xFFFFFFFF))&&
|
|
(pwb->IpAddressToHandout != net_long(0xFFFFFFFE)))
|
|
? pwb->IpAddressToHandout
|
|
: ipaddrClient,
|
|
&(pwb->IpAddressRemote),
|
|
pwb->wszUserName,
|
|
pwb->wszPortName );
|
|
TraceIp("IPCP: RasSrvrAcquireAddress done(%d)",
|
|
dwErr);
|
|
|
|
if (dwErr != 0)
|
|
{
|
|
return dwErr;
|
|
}
|
|
|
|
if (ipaddrClient != 0)
|
|
{
|
|
TraceIp("IPCP: Hard IP requested");
|
|
|
|
if ( ipaddrClient == pwb->IpAddressRemote )
|
|
{
|
|
/* Good. Client's asking for the address we
|
|
** want to give him.
|
|
*/
|
|
TraceIp("IPCP: Accepting IP");
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Otherwise we could not give the user the
|
|
// address he/she requested. Nak with this address.
|
|
//
|
|
|
|
TraceIp("IPCP: 3rd party DLL changed IP");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceIp("IPCP: Server IP requested");
|
|
}
|
|
|
|
ipaddrClient = pwb->IpAddressRemote;
|
|
|
|
*pfNak = TRUE;
|
|
CopyMemory(
|
|
(VOID* )pSOption, (VOID* )pROption,
|
|
pROption->Length );
|
|
|
|
if (!fRejectNaks)
|
|
{
|
|
TraceIp("IPCP: Naking IP");
|
|
|
|
CopyMemory( pSOption->Data,
|
|
&pwb->IpAddressRemote,
|
|
sizeof(IPADDR) );
|
|
}
|
|
|
|
pSOption =
|
|
(PPP_OPTION UNALIGNED* )((BYTE* )pSOption +
|
|
pROption->Length);
|
|
|
|
break;
|
|
}
|
|
|
|
case OPTION_DnsIpAddress:
|
|
case OPTION_WinsIpAddress:
|
|
case OPTION_DnsBackupIpAddress:
|
|
case OPTION_WinsBackupIpAddress:
|
|
{
|
|
if (NakCheckNameServerOption(
|
|
pwb, fRejectNaks, pROption, &pSOption ))
|
|
{
|
|
*pfNak = TRUE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
TraceIp("IPCP: Unknown option?");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pROption->Length && pROption->Length < cbLeft)
|
|
cbLeft -= pROption->Length;
|
|
else
|
|
cbLeft = 0;
|
|
|
|
pROption =
|
|
(PPP_OPTION UNALIGNED* )((BYTE* )pROption + pROption->Length);
|
|
}
|
|
|
|
if ( pwb->fServer
|
|
&& ( pwb->IfType != ROUTER_IF_TYPE_FULL_ROUTER )
|
|
&& ipaddrClient == 0 )
|
|
{
|
|
/* ipaddrClient is 0 iff there is no OPTION_IpAddress */
|
|
TraceIp("IPCP: No IP option");
|
|
|
|
/* If client doesn't provide or asked to be assigned an IP address,
|
|
** suggest one so he'll tell us what he wants.
|
|
*/
|
|
if ( pwb->IpAddressRemote == 0 )
|
|
{
|
|
TraceIp("IPCP: RasSrvrAcquireAddress(0)...");
|
|
dwErr = RasSrvrAcquireAddress(
|
|
pwb->hport,
|
|
0,
|
|
&(pwb->IpAddressRemote),
|
|
pwb->wszUserName,
|
|
pwb->wszPortName );
|
|
TraceIp("IPCP: RasSrvrAcquireAddress done(%d)",dwErr);
|
|
|
|
if (dwErr != 0)
|
|
return dwErr;
|
|
}
|
|
|
|
/* Time to reject instead of nak and client is still not requesting an
|
|
** IP address. We simply allocate an IP address and ACK this request
|
|
*/
|
|
if ( !fRejectNaks )
|
|
{
|
|
AddIpAddressOption(
|
|
(BYTE UNALIGNED* )pSOption, OPTION_IpAddress,
|
|
pwb->IpAddressRemote );
|
|
|
|
pSOption =
|
|
(PPP_OPTION UNALIGNED* )((BYTE* )pSOption + IPADDRESSOPTIONLEN);
|
|
|
|
*pfNak = TRUE;
|
|
}
|
|
}
|
|
|
|
if (*pfNak)
|
|
{
|
|
pSendBuf->Code = (fRejectNaks) ? CONFIG_REJ : CONFIG_NAK;
|
|
|
|
HostToWireFormat16(
|
|
(WORD )((BYTE* )pSOption - (BYTE* )pSendBuf), pSendBuf->Length );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
BOOL
|
|
NakCheckNameServerOption(
|
|
IN IPCPWB* pwb,
|
|
IN BOOL fRejectNaks,
|
|
IN PPP_OPTION UNALIGNED* pROption,
|
|
OUT PPP_OPTION UNALIGNED** ppSOption )
|
|
|
|
/* Check a name server option for possible naking. 'pwb' the work buffer
|
|
** stored for us by the engine. 'fRejectNaks' is set the original options
|
|
** are placed in a Reject packet instead. 'pROption' is the address of
|
|
** the received option. '*ppSOption' is the address of the option to be
|
|
** sent, if there's a problem.
|
|
**
|
|
** Returns true if the name server address option should be naked or
|
|
** rejected, false if it's OK.
|
|
*/
|
|
{
|
|
IPADDR ipaddr;
|
|
IPADDR* pipaddrWant;
|
|
|
|
switch (pROption->Type)
|
|
{
|
|
case OPTION_DnsIpAddress:
|
|
pipaddrWant = &pwb->IpInfoRemote.nboDNSAddress;
|
|
break;
|
|
|
|
case OPTION_WinsIpAddress:
|
|
pipaddrWant = &pwb->IpInfoRemote.nboWINSAddress;
|
|
break;
|
|
|
|
case OPTION_DnsBackupIpAddress:
|
|
pipaddrWant = &pwb->IpInfoRemote.nboDNSAddressBackup;
|
|
break;
|
|
|
|
case OPTION_WinsBackupIpAddress:
|
|
pipaddrWant = &pwb->IpInfoRemote.nboWINSAddressBackup;
|
|
break;
|
|
|
|
default:
|
|
RTASSERT((!"Bogus option"));
|
|
return FALSE;
|
|
}
|
|
|
|
RTASSERT(pROption->Length==IPADDRESSOPTIONLEN);
|
|
CopyMemory( &ipaddr, pROption->Data, sizeof(IPADDR) );
|
|
|
|
if (ipaddr == *pipaddrWant)
|
|
{
|
|
/* Good. Client's asking for the address we want to give him.
|
|
*/
|
|
return FALSE;
|
|
}
|
|
|
|
/* Not our expected address value, so Nak it.
|
|
*/
|
|
TraceIp("IPCP: Naking $%x",(int)pROption->Type);
|
|
|
|
CopyMemory( (VOID* )*ppSOption, (VOID* )pROption, pROption->Length );
|
|
|
|
if (!fRejectNaks)
|
|
CopyMemory( (*ppSOption)->Data, pipaddrWant, sizeof(IPADDR) );
|
|
|
|
*ppSOption =
|
|
(PPP_OPTION UNALIGNED* )((BYTE* )*ppSOption + pROption->Length);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
RejectCheck(
|
|
IN IPCPWB* pwb,
|
|
IN PPP_CONFIG* pReceiveBuf,
|
|
OUT PPP_CONFIG* pSendBuf,
|
|
IN DWORD cbSendBuf,
|
|
OUT BOOL* pfReject )
|
|
|
|
/* Check received packet 'pReceiveBuf' options to see if any should be
|
|
** rejected and if so, build a Rej packet in 'pSendBuf'. '*pfReject' is
|
|
** set true if a Rej packet was created.
|
|
**
|
|
** Returns 0 if successful, otherwise a non-0 error code.
|
|
*/
|
|
{
|
|
PPP_OPTION UNALIGNED* pROption = (PPP_OPTION UNALIGNED* )pReceiveBuf->Data;
|
|
PPP_OPTION UNALIGNED* pSOption = (PPP_OPTION UNALIGNED* )pSendBuf->Data;
|
|
|
|
WORD cbPacket = WireToHostFormat16( pReceiveBuf->Length );
|
|
WORD cbLeft = cbPacket - PPP_CONFIG_HDR_LEN;
|
|
|
|
TraceIp("IPCP: RejectCheck");
|
|
|
|
*pfReject = FALSE;
|
|
|
|
while (cbLeft > 0)
|
|
{
|
|
if (cbLeft < pROption->Length)
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
|
|
if (pROption->Type == OPTION_IpCompression)
|
|
{
|
|
WORD wProtocol =
|
|
WireToHostFormat16U(pROption->Data );
|
|
|
|
if (wProtocol != COMPRESSION_VanJacobson
|
|
|| pROption->Length != IPCOMPRESSIONOPTIONLEN
|
|
|| Protocol(pwb->rpcSend) == 0)
|
|
{
|
|
TraceIp("IPCP: Rejecting IP compression");
|
|
|
|
*pfReject = TRUE;
|
|
CopyMemory(
|
|
(VOID* )pSOption, (VOID* )pROption, pROption->Length );
|
|
|
|
pSOption = (PPP_OPTION UNALIGNED* )((BYTE* )pSOption +
|
|
pROption->Length);
|
|
}
|
|
}
|
|
else if (pwb->fServer)
|
|
{
|
|
//
|
|
// This is a client/router dialing in
|
|
//
|
|
|
|
switch (pROption->Type)
|
|
{
|
|
case OPTION_IpAddress:
|
|
case OPTION_DnsIpAddress:
|
|
case OPTION_WinsIpAddress:
|
|
case OPTION_DnsBackupIpAddress:
|
|
case OPTION_WinsBackupIpAddress:
|
|
{
|
|
IPADDR ipaddr;
|
|
BOOL fBadLength = (pROption->Length != IPADDRESSOPTIONLEN);
|
|
|
|
if (!fBadLength)
|
|
CopyMemory( &ipaddr, pROption->Data, sizeof(IPADDR) );
|
|
|
|
if (fBadLength
|
|
|| (!ipaddr
|
|
&& ((pROption->Type == OPTION_DnsIpAddress
|
|
&& !pwb->IpInfoRemote.nboDNSAddress)
|
|
|| (pROption->Type == OPTION_WinsIpAddress
|
|
&& !pwb->IpInfoRemote.nboWINSAddress)
|
|
|| (pROption->Type == OPTION_DnsBackupIpAddress
|
|
&& !pwb->IpInfoRemote.nboDNSAddressBackup)
|
|
|| (pROption->Type == OPTION_WinsBackupIpAddress
|
|
&& !pwb->IpInfoRemote.nboWINSAddressBackup))))
|
|
{
|
|
/* messed up IP address option, reject it.
|
|
*/
|
|
TraceIp("IPCP: Rejecting $%x",(int )pROption->Type);
|
|
|
|
*pfReject = TRUE;
|
|
CopyMemory(
|
|
(VOID* )pSOption, (VOID* )pROption,
|
|
pROption->Length );
|
|
|
|
pSOption = (PPP_OPTION UNALIGNED* )((BYTE* )pSOption +
|
|
pROption->Length);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
/* Unknown option, reject it.
|
|
*/
|
|
TraceIp("IPCP: Rejecting $%x",(int )pROption->Type);
|
|
|
|
*pfReject = TRUE;
|
|
CopyMemory(
|
|
(VOID* )pSOption, (VOID* )pROption, pROption->Length );
|
|
pSOption =
|
|
(PPP_OPTION UNALIGNED* )((BYTE* )pSOption +
|
|
pROption->Length);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is a client/router dialing out
|
|
//
|
|
|
|
IPADDR ipaddr;
|
|
BOOL fBad = (pROption->Type != OPTION_IpAddress
|
|
|| pROption->Length != IPADDRESSOPTIONLEN);
|
|
|
|
if (!fBad)
|
|
CopyMemory( &ipaddr, pROption->Data, sizeof(IPADDR) );
|
|
|
|
if ( fBad
|
|
|| ( !ipaddr
|
|
&& (pwb->IfType != ROUTER_IF_TYPE_FULL_ROUTER)))
|
|
{
|
|
/* Client rejects everything except a non-zero IP address
|
|
** which is accepted because some peers (such as Shiva) can't
|
|
** handle rejection of this option.
|
|
*/
|
|
TraceIp("IPCP: Rejecting %d",(int )pROption->Type);
|
|
|
|
*pfReject = TRUE;
|
|
CopyMemory(
|
|
(VOID* )pSOption, (VOID* )pROption, pROption->Length );
|
|
pSOption = (PPP_OPTION UNALIGNED* )((BYTE* )pSOption +
|
|
pROption->Length);
|
|
}
|
|
else
|
|
{
|
|
/* Store the server's IP address as some applications may be
|
|
** able to make use of it (e.g. Compaq does), though they are
|
|
** not guaranteed to receive it from all IPCP implementations.
|
|
*/
|
|
if (pwb->IfType != ROUTER_IF_TYPE_FULL_ROUTER)
|
|
{
|
|
pwb->IpAddressRemote = ipaddr;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pROption->Length && pROption->Length < cbLeft)
|
|
cbLeft -= pROption->Length;
|
|
else
|
|
cbLeft = 0;
|
|
|
|
pROption =
|
|
(PPP_OPTION UNALIGNED* )((BYTE* )pROption +
|
|
pROption->Length);
|
|
}
|
|
|
|
if (*pfReject)
|
|
{
|
|
pSendBuf->Code = CONFIG_REJ;
|
|
|
|
HostToWireFormat16(
|
|
(WORD )((BYTE* )pSOption - (BYTE* )pSendBuf), pSendBuf->Length );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ReconfigureTcpip(
|
|
IN WCHAR* pwszDevice,
|
|
IN BOOL fNewIpAddress,
|
|
IN IPADDR ipaddr,
|
|
IN IPADDR ipMask
|
|
)
|
|
|
|
/* Reconfigure running TCP/IP components.
|
|
**
|
|
** Returns 0 if successful, otherwise a non-0 error code.
|
|
*/
|
|
{
|
|
DWORD dwErr;
|
|
|
|
TraceIp("IPCP: ReconfigureTcpip(%08x, %08x)",
|
|
ipaddr, ipMask);
|
|
|
|
dwErr = PDhcpNotifyConfigChange2(NULL, pwszDevice, fNewIpAddress, 0,
|
|
ipaddr, ipMask, IgnoreFlag,
|
|
NOTIFY_FLG_DO_DNS);
|
|
|
|
TraceIp("IPCP: ReconfigureTcpip done(%d)",dwErr);
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
VOID
|
|
TraceIp(
|
|
CHAR * Format,
|
|
...
|
|
)
|
|
{
|
|
va_list arglist;
|
|
|
|
va_start(arglist, Format);
|
|
|
|
TraceVprintfEx( DwIpcpTraceId,
|
|
PPPIPCP_TRACE | TRACE_USE_MASK | TRACE_USE_MSEC,
|
|
Format,
|
|
arglist);
|
|
|
|
va_end(arglist);
|
|
}
|
|
|
|
VOID
|
|
TraceIpDump(
|
|
LPVOID lpData,
|
|
DWORD dwByteCount
|
|
)
|
|
{
|
|
TraceDumpEx( DwIpcpTraceId,
|
|
PPPIPCP_TRACE | TRACE_USE_MASK | TRACE_USE_MSEC,
|
|
lpData, dwByteCount, 1, FALSE, NULL );
|
|
}
|
|
|
|
VOID
|
|
PrintMwsz(
|
|
CHAR* sz,
|
|
WCHAR* mwsz
|
|
)
|
|
{
|
|
WCHAR* wsz;
|
|
DWORD dwLength;
|
|
|
|
if (NULL == mwsz)
|
|
{
|
|
TraceIp("%s", sz);
|
|
return;
|
|
}
|
|
|
|
dwLength = MwszLength(mwsz);
|
|
|
|
wsz = LocalAlloc(LPTR, dwLength * sizeof(WCHAR));
|
|
|
|
if (NULL == wsz)
|
|
{
|
|
TraceIp("LocalAlloc failed and returned %d", GetLastError());
|
|
return;
|
|
}
|
|
|
|
CopyMemory(wsz, mwsz, dwLength * sizeof(WCHAR));
|
|
|
|
dwLength -= 2;
|
|
|
|
while (dwLength != 0)
|
|
{
|
|
dwLength--;
|
|
|
|
if (0 == wsz[dwLength])
|
|
{
|
|
wsz[dwLength] = L' ';
|
|
}
|
|
}
|
|
|
|
TraceIp("%s %ws", sz, wsz);
|
|
|
|
LocalFree(wsz);
|
|
}
|