Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3725 lines
116 KiB

/* 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());
}
PDhcpRequestParams = (DHCPREQUESTPARAMS)
GetProcAddress(HDhcpDll, "DhcpRequestParams");
if(NULL == PDhcpRequestParams)
{
return (GetLastError());
}
ClearTcpipInfo();
DwIpcpTraceId = TraceRegister("RASIPCP");
}
dwRefCount++;
}
else
{
dwRefCount--;
if (0 == dwRefCount)
{
HelperUninitialize();
// Ignore errors
HDhcpDll = NULL;
PDhcpRequestOptions = NULL;
PDhcpNotifyConfigChange2 = NULL;
PDhcpRequestParams = 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);
BOOL FClientMaySelectIpAddress = FALSE;
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)
{
FClientMaySelectIpAddress = TRUE;
}
RegCloseKey( hkey );
}
TraceIp("IPCP: Hard IP=%d",FClientMaySelectIpAddress);
pwb->IpAddressToHandout = ( FClientMaySelectIpAddress )
? 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;
DWORD dwIndex;
DWORD dwCurOffset;
DWORD dwDomainNameSize;
DWORD dwNumDNSAddresses = 0;
IPADDR* pnboDNSAddresses = NULL;
IPADDR nboWINSAddress1 = 0;
IPADDR nboWINSAddress2 = 0;
IPADDR nboSubnetMask = 0;
CHAR* szDomainName = NULL;
//
// Route Information obtained from DHCP option 133
//
PBYTE pbRouteInfo = NULL;
DWORD dwErr;
BOOL fFree = TRUE;
BOOL fSendMessage = FALSE;
int i;
DHCPCAPI_PARAMS DhcpRequestedOptions[6] =
{
{
0,
OPTION_DNS_NAME_SERVERS,
FALSE,
NULL,
0
},
{
0,
OPTION_NETBIOS_NAME_SERVERS,
FALSE,
NULL,
0
},
{
0,
OPTION_VENDOR_SPEC_INFO,
FALSE,
NULL,
0
},
{
0,
OPTION_SUBNET_MASK,
FALSE,
NULL,
0
},
{
0,
OPTION_VENDOR_ROUTE_PLUMB,
FALSE,
NULL,
0
},
{
0,
OPTION_DNS_DOMAIN_NAME,
FALSE,
NULL,
0
}
};
DHCPCAPI_PARAMS_ARRAY DhcpRequestedOptionsArray =
{
5,
DhcpRequestedOptions
};
DHCPCAPI_PARAMS_ARRAY DhcpSendOptionsArray =
{
0,
NULL
};
PBYTE pRequestBuffer = NULL;
DWORD dwBufferSize = 2048;
DHCPCAPI_PARAMS *pParam;
if(pIpcpDhcpInform->fUseDhcpInformDomainName)
{
DhcpRequestedOptionsArray.nParams = 6;
}
//
// Allocate a 2k buffer upfront and pass it to the
// api. Loop allocating if buffer is not big enough.
//
pRequestBuffer = LocalAlloc(LPTR, dwBufferSize);
if(NULL == pRequestBuffer)
{
TraceIp("DhcpInform:LocalAlloc=%d", GetLastError());
goto LDhcpInformEnd;
}
TraceIp("DhcpRequestParams(%ws)...", pIpcpDhcpInform->wszDevice);
do
{
dwErr = PDhcpRequestParams(
DHCPCAPI_REQUEST_SYNCHRONOUS,
NULL,
pIpcpDhcpInform->wszDevice,
NULL,
DhcpSendOptionsArray,
DhcpRequestedOptionsArray,
pRequestBuffer,
&dwBufferSize,
NULL);
if(ERROR_MORE_DATA == dwErr)
{
LocalFree(pRequestBuffer);
pRequestBuffer = LocalAlloc(LPTR, dwBufferSize);
if(NULL == pRequestBuffer)
{
dwErr = GetLastError();
}
}
} while(ERROR_MORE_DATA == dwErr);
TraceIp("DhcpRequestParams done(%d)", dwErr);
if(NO_ERROR != dwErr)
{
goto LDhcpInformEnd;
}
//
// DhcpRequestParams fills in all the available parameters
// and leaves the other parameters alone. Since the
// parameters are NULL initialized, its fine to quit the
// for loop when we get the first parameter with NULL data
// or 0 nBytesData. This is per DHCP dev - information is not
// correct in msdn.
//
for(dwIndex = 0;
dwIndex < DhcpRequestedOptionsArray.nParams;
dwIndex++)
{
pParam = &DhcpRequestedOptions[dwIndex];
switch(pParam->OptionId)
{
case OPTION_DNS_DOMAIN_NAME:
dwDomainNameSize = pParam->nBytesData;
if(0 == dwDomainNameSize)
{
goto LDhcpInformEnd;
}
if(NULL != szDomainName)
{
LocalFree(szDomainName);
}
szDomainName = LocalAlloc(LPTR, dwDomainNameSize + 1);
if(NULL == szDomainName)
{
fSendMessage = FALSE;
TraceIp("DhcpInform: LocalAlloc=%d", GetLastError());
goto LDhcpInformEnd;
}
CopyMemory(szDomainName, pParam->Data, pParam->nBytesData);
fSendMessage = TRUE;
TraceIp("DhcpInform: DOMAIN_NAME %s", szDomainName);
break;
case OPTION_DNS_NAME_SERVERS:
if( 0 == pParam->nBytesData)
{
goto LDhcpInformEnd;
}
if(0 != (pParam->nBytesData % 4))
{
TraceIp("Invalid DOMAIN_NAME_SERVERS size %d",
pParam->nBytesData);
fSendMessage = FALSE;
goto LDhcpInformEnd;
}
if(NULL != pnboDNSAddresses)
{
LocalFree(pnboDNSAddresses);
dwNumDNSAddresses = 0;
}
pnboDNSAddresses = LocalAlloc(LPTR,
sizeof(IPADDR)
* pParam->nBytesData / 4);
if(NULL == pnboDNSAddresses)
{
fSendMessage = FALSE;
TraceIp("DhcpInform: LocalAlloc=%d', GetLastError()");
goto LDhcpInformEnd;
}
for(dwCurOffset = 0;
dwCurOffset < pParam->nBytesData;
dwCurOffset += 4, dwNumDNSAddresses++)
{
pnboDNSAddresses[dwNumDNSAddresses] =
(pParam->Data[dwCurOffset])
+ (pParam->Data[dwCurOffset + 1] << 8)
+ (pParam->Data[dwCurOffset + 2] << 16)
+ (pParam->Data[dwCurOffset + 3] << 24);
TraceIp("DhcpInform: DOMAIN_NAME_SERVER 0x%x",
pnboDNSAddresses[dwNumDNSAddresses]);
fSendMessage = TRUE;
}
RTASSERT((pParam->nBytesData / 4) == dwNumDNSAddresses);
break;
case OPTION_NETBIOS_NAME_SERVERS:
if(0 == pParam->nBytesData)
{
goto LDhcpInformEnd;
}
if(0 != (pParam->nBytesData % 4))
{
fSendMessage = FALSE;
TraceIp("Invalid NETBIOS_NAME_SERVER size %d",
pParam->nBytesData);
goto LDhcpInformEnd;
}
dwCurOffset = 0;
for(i = 0; i < 2; i++)
{
IPADDR *paddr;
if(0 == i)
{
paddr = &nboWINSAddress1;
}
else
{
paddr = &nboWINSAddress2;
}
*paddr =
(pParam->Data[dwCurOffset])
+ (pParam->Data[dwCurOffset + 1] << 8)
+ (pParam->Data[dwCurOffset + 2] << 16)
+ (pParam->Data[dwCurOffset + 3] << 24);
TraceIp("DhcpInform: NETBIOS_NAME_SERVER 0x%x",
*paddr);
fSendMessage = TRUE;
dwCurOffset += 4;
if(dwCurOffset == pParam->nBytesData)
{
break;
}
}
break;
case OPTION_SUBNET_MASK:
if(0 == pParam->nBytesData)
{
goto LDhcpInformEnd;
}
if(0 != (pParam->nBytesData % 4))
{
fSendMessage = FALSE;
TraceIp("Invalid OPTION_SUBNET_MASK size %d",
pParam->nBytesData);
goto LDhcpInformEnd;
}
nboSubnetMask = pParam->Data[0]
+ (pParam->Data[1] << 8)
+ (pParam->Data[2] << 16)
+ (pParam->Data[3] << 24);
TraceIp("DhcpInform: OPTION_SUBNET_MASK 0x%x",
nboSubnetMask);
fSendMessage = TRUE;
break;
case OPTION_VENDOR_ROUTE_PLUMB:
if(0 == pParam->nBytesData)
{
goto LDhcpInformEnd;
}
//
// This option should be at least 5 bytes in length.
//
if(pParam->nBytesData < 5)
{
fSendMessage = FALSE;
TraceIp("Invalid OPTION_VENDOR_ROUTE_PLUMB size %d",
pParam->nBytesData);
goto LDhcpInformEnd;
}
TraceIp("DhcpInform: OPTION_VENDOR_ROUTE_PLUMB Code "
"Len 0x%x",
pParam->nBytesData);
pbRouteInfo = LocalAlloc(LPTR, pParam->nBytesData + sizeof(DWORD));
if(NULL == pbRouteInfo)
{
fSendMessage = FALSE;
TraceIp("DhcpInform: LocalAlloc=%d", GetLastError());
goto LDhcpInformEnd;
}
CopyMemory(pbRouteInfo + sizeof(DWORD),
pParam->Data, pParam->nBytesData);
*((DWORD *) pbRouteInfo) = pParam->nBytesData;
fSendMessage = TRUE;
break;
default:
break;
}
}
LDhcpInformEnd:
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;
}
if (fFree)
{
LocalFree(pIpcpDhcpInform->wszDevice);
LocalFree(pnboDNSAddresses);
LocalFree(szDomainName);
LocalFree(pbRouteInfo);
}
if(NULL != pRequestBuffer)
{
LocalFree(pRequestBuffer);
}
LocalFree(pIpcpDhcpInform);
}
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)];
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 | TRACE_USE_DATE,
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);
}