mirror of https://github.com/tongzx/nt5src
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.
5793 lines
126 KiB
5793 lines
126 KiB
/*++
|
|
|
|
Copyright (C) 1992-98 Microsft Corporation. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
util.c
|
|
|
|
Abstract:
|
|
|
|
Utility functions used in rasmans.dll
|
|
|
|
Author:
|
|
|
|
Gurdeep Singh Pall (gurdeep) 06-Jun-1997
|
|
|
|
Revision History:
|
|
|
|
Miscellaneous Modifications - raos 31-Dec-1997
|
|
|
|
--*/
|
|
|
|
#define RASMXS_DYNAMIC_LINK
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntlsa.h>
|
|
#include <ntmsv1_0.h>
|
|
#include <llinfo.h>
|
|
#include <rasman.h>
|
|
#include <rasppp.h>
|
|
#include <lm.h>
|
|
#include <lmwksta.h>
|
|
#include <wanpub.h>
|
|
#include <raserror.h>
|
|
//
|
|
//Open this to plumb creds at winlogon time
|
|
//
|
|
#if 0
|
|
#include <wincrypt.h> // Required by sclogon.h
|
|
#include <sclogon.h> // For ScHelperGetCertFromLogonInfo
|
|
#endif
|
|
//#include <rasarp.h>
|
|
#include <media.h>
|
|
#include <mprlog.h>
|
|
#include <rtutils.h>
|
|
#include <device.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <rtutils.h>
|
|
#include "logtrdef.h"
|
|
#include "defs.h"
|
|
#include "structs.h"
|
|
#include "protos.h"
|
|
#include "globals.h"
|
|
#include "wincred.h"
|
|
#include "stdio.h"
|
|
#include "ntddip.h"
|
|
#include "iphlpapi.h"
|
|
#include "iprtrmib.h"
|
|
|
|
|
|
#include "eaptypeid.h" // for PPP_EAP_TLS
|
|
|
|
#if SENS_ENABLED
|
|
#include "sensapip.h"
|
|
#endif
|
|
|
|
#include "winsock2.h"
|
|
|
|
#define PASSWORDMAGIC 0xA5
|
|
|
|
//
|
|
// Following is copied from ..\..\ppp\eaptls\eaptls.h. Keep this in
|
|
// sync with the structure in eaptls.h. This is not good for maintenance
|
|
// TODO: copy the structure to a common header and include it both in
|
|
// rastls and rasman.
|
|
//
|
|
#define MAX_HASH_SIZE 20 // Certificate hash size
|
|
|
|
typedef struct _EAPTLS_HASH
|
|
{
|
|
DWORD cbHash; // Number of bytes in the hash
|
|
BYTE pbHash[MAX_HASH_SIZE]; // The hash of a certificate
|
|
|
|
} EAPTLS_HASH;
|
|
|
|
DWORD g_IphlpInitialized = FALSE;
|
|
|
|
typedef struct _RASMAN_EAPTLS_USER_PROPERTIES
|
|
{
|
|
DWORD reserved; // Must be 0 (compare with EAPLOGONINFO)
|
|
DWORD dwVersion;
|
|
DWORD dwSize; // Number of bytes in this structure
|
|
DWORD fFlags; // See EAPTLS_USER_FLAG_*
|
|
EAPTLS_HASH Hash; // Hash for the user certificate
|
|
WCHAR* pwszDiffUser; // The EAP Identity to send
|
|
DWORD dwPinOffset; // Offset in abData
|
|
WCHAR* pwszPin; // The smartcard PIN
|
|
USHORT usLength; // Part of UnicodeString
|
|
USHORT usMaximumLength; // Part of UnicodeString
|
|
UCHAR ucSeed; // To unlock the UnicodeString
|
|
WCHAR awszString[1]; // Storage for pwszDiffUser and pwszPin
|
|
|
|
} RASMAN_EAPTLS_USER_PROPERTIES;
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets information about the protocol change from ndiswan
|
|
|
|
Arguments:
|
|
|
|
pointer to a structure NDISWAN_GET_PROTOCOL_EVENT which
|
|
returns an array of PROTOCOL_EVENT structures.
|
|
|
|
Return Value:
|
|
|
|
return codes from IOCTL_NDISWAN_GET_PROTOCOL_EVENT.
|
|
E_INVALIDARG if pProtEvents is NULL.
|
|
|
|
--*/
|
|
|
|
DWORD
|
|
DwGetProtocolEvent(NDISWAN_GET_PROTOCOL_EVENT *pProtEvents)
|
|
{
|
|
DWORD retcode = SUCCESS;
|
|
|
|
DWORD dwbytes;
|
|
|
|
if(NULL == pProtEvents)
|
|
{
|
|
RasmanTrace(
|
|
"DwGetProtocolEvent: pProtEvents=NULL!");
|
|
|
|
retcode = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
|
|
ASSERT(INVALID_HANDLE_VALUE != RasHubHandle);
|
|
|
|
|
|
if(!DeviceIoControl(
|
|
RasHubHandle,
|
|
IOCTL_NDISWAN_GET_PROTOCOL_EVENT,
|
|
NULL,
|
|
0,
|
|
pProtEvents,
|
|
sizeof(NDISWAN_GET_PROTOCOL_EVENT),
|
|
&dwbytes,
|
|
NULL))
|
|
{
|
|
retcode = GetLastError();
|
|
|
|
RasmanTrace(
|
|
"DwGetProtocolEvent: Failed to get protocol"
|
|
" event. rc=0x%x",
|
|
retcode);
|
|
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
return retcode;
|
|
|
|
}
|
|
|
|
DWORD
|
|
GetBapPacket ( RasmanBapPacket **ppBapPacket )
|
|
{
|
|
DWORD retcode = SUCCESS;
|
|
RasmanBapPacket *pBapPacket = NULL;
|
|
|
|
if(NULL == BapBuffers)
|
|
{
|
|
HKEY hkey = NULL;
|
|
DWORD dwMaxBuffers = 10;
|
|
|
|
|
|
BapBuffers = (BapBuffersList *)
|
|
LocalAlloc(LPTR, sizeof(BapBuffersList));
|
|
|
|
if(NULL == BapBuffers)
|
|
{
|
|
retcode = GetLastError();
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Read from registry the max number of buffers we allow.
|
|
// default to 10.
|
|
//
|
|
if(NO_ERROR == RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
"System\\CurrentControlSet\\Services\\Rasman\\Parameters",
|
|
0,
|
|
KEY_READ,
|
|
&hkey))
|
|
{
|
|
DWORD cbData = sizeof(DWORD);
|
|
DWORD dwType;
|
|
|
|
if( (NO_ERROR == RegQueryValueEx(
|
|
hkey,
|
|
"MaxBapBuffers",
|
|
NULL,
|
|
&dwType,
|
|
(PBYTE) &dwMaxBuffers,
|
|
&cbData))
|
|
&& (REG_DWORD == dwType))
|
|
{
|
|
RasmanTrace(
|
|
"GetBapPacket: MaxBuffers = %d",
|
|
dwMaxBuffers);
|
|
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
BapBuffers->dwMaxBuffers = dwMaxBuffers;
|
|
}
|
|
|
|
if(BapBuffers->dwNumBuffers < BapBuffers->dwMaxBuffers)
|
|
{
|
|
pBapPacket = LocalAlloc(LPTR, sizeof(RasmanBapPacket));
|
|
|
|
if(NULL == pBapPacket)
|
|
{
|
|
retcode = GetLastError();
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Insert the new buffer in the buffers list
|
|
//
|
|
pBapPacket->RBP_Overlapped.RO_EventType = OVEVT_RASMAN_THRESHOLD;
|
|
pBapPacket->Next = BapBuffers->pPacketList;
|
|
BapBuffers->pPacketList = pBapPacket;
|
|
BapBuffers->dwNumBuffers += 1;
|
|
|
|
RasmanTrace(
|
|
"GetBapPacket: Max=%d, Num=%d",
|
|
BapBuffers->dwMaxBuffers,
|
|
BapBuffers->dwNumBuffers);
|
|
}
|
|
else
|
|
{
|
|
RasmanTrace(
|
|
"GetBapPacket: Not Allocating we have max BapBuffers");
|
|
}
|
|
|
|
done:
|
|
|
|
*ppBapPacket = pBapPacket;
|
|
|
|
return retcode;
|
|
}
|
|
|
|
|
|
DWORD
|
|
DwSetThresholdEvent(RasmanBapPacket *pBapPacket)
|
|
{
|
|
DWORD dwBytes;
|
|
DWORD retcode = SUCCESS;
|
|
|
|
RasmanTrace(
|
|
"DwSetThresholdEvent: pOverlapped=%p",
|
|
&pBapPacket->RBP_Overlapped);
|
|
|
|
//
|
|
// Set the threshold event
|
|
//
|
|
if (!DeviceIoControl(RasHubHandle,
|
|
IOCTL_NDISWAN_SET_THRESHOLD_EVENT,
|
|
( LPVOID ) &pBapPacket->RBP_ThresholdEvent,
|
|
sizeof ( NDISWAN_SET_THRESHOLD_EVENT ),
|
|
( LPVOID ) &pBapPacket->RBP_ThresholdEvent,
|
|
sizeof ( NDISWAN_SET_THRESHOLD_EVENT),
|
|
&dwBytes,
|
|
( LPOVERLAPPED ) &pBapPacket->RBP_Overlapped ))
|
|
{
|
|
retcode = GetLastError();
|
|
|
|
if (ERROR_IO_PENDING == retcode)
|
|
{
|
|
retcode = SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
RasmanTrace(
|
|
"DwSetThresholdEvent: Failed to Set Threshold Event. %d",
|
|
retcode );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RasmanTrace(
|
|
"DwSetThresholdEvent: completed sync!");
|
|
}
|
|
|
|
return retcode;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Pends an irp with ndiswan to signal in the case of
|
|
Protocols coming and going.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
return codes from IOCTL_NDISWAN_SET_PROTOCOL_EVENT.
|
|
|
|
--*/
|
|
|
|
DWORD
|
|
DwSetProtocolEvent()
|
|
{
|
|
DWORD retcode = SUCCESS;
|
|
|
|
//
|
|
// Check to see if ndiswan has started yet.
|
|
//
|
|
if(INVALID_HANDLE_VALUE == RasHubHandle)
|
|
{
|
|
if((DWORD) -1 != TraceHandle)
|
|
{
|
|
RasmanTrace(
|
|
"DwSetProtocolEvent: returning %d"
|
|
" since ndiswan isn't started yet",
|
|
ERROR_INVALID_HANDLE);
|
|
}
|
|
|
|
retcode = ERROR_INVALID_HANDLE;
|
|
goto done;
|
|
}
|
|
|
|
if((DWORD) -1 != TraceHandle)
|
|
{
|
|
RasmanTrace(
|
|
"DwSetProtocolEvent");
|
|
}
|
|
|
|
//
|
|
// Plumb the irp with ndiswan to notify on protocol
|
|
// events. Keep plumbing if the IOCTL is completed
|
|
// synchronously.
|
|
//
|
|
if (!DeviceIoControl(RasHubHandle,
|
|
IOCTL_NDISWAN_SET_PROTOCOL_EVENT,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
(LPOVERLAPPED) &RO_ProtocolEvent))
|
|
{
|
|
retcode = GetLastError();
|
|
|
|
if(ERROR_IO_PENDING == retcode)
|
|
{
|
|
retcode = SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
if((DWORD) -1 != TraceHandle)
|
|
{
|
|
RasmanTrace(
|
|
"_SET_PROTCOL_EVENT returned 0x%x",
|
|
retcode);
|
|
}
|
|
}
|
|
}
|
|
|
|
if((DWORD) -1 != TraceHandle)
|
|
{
|
|
RasmanTrace(
|
|
"DwSetProtocolEvent. rc=0x%x",
|
|
retcode);
|
|
}
|
|
|
|
if(ERROR_IO_PENDING == retcode)
|
|
{
|
|
retcode = SUCCESS;
|
|
}
|
|
|
|
done:
|
|
return retcode;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Pends an irp with ndiswan to signal in the case of
|
|
Hibernation.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
return codes from IOCTL_NDISWAN_SET_HIBERNATE_EVENT.
|
|
|
|
--*/
|
|
DWORD
|
|
DwSetHibernateEvent()
|
|
{
|
|
DWORD retcode = SUCCESS;
|
|
|
|
//
|
|
// Check to see if ndiswan has started yet.
|
|
//
|
|
if(INVALID_HANDLE_VALUE == RasHubHandle)
|
|
{
|
|
if((DWORD) -1 != TraceHandle)
|
|
{
|
|
RasmanTrace(
|
|
"DwSetProtocolEvent: returning %d"
|
|
" since ndiswan isn't started yet",
|
|
ERROR_INVALID_HANDLE);
|
|
}
|
|
|
|
retcode = ERROR_INVALID_HANDLE;
|
|
goto done;
|
|
}
|
|
|
|
if((DWORD) -1 != TraceHandle)
|
|
{
|
|
RasmanTrace(
|
|
"DwSetHibernateEvent");
|
|
}
|
|
|
|
//
|
|
// Plumb the irp with ndiswan to notify on Hibernate
|
|
// events.
|
|
//
|
|
if (!DeviceIoControl(RasHubHandle,
|
|
IOCTL_NDISWAN_SET_HIBERNATE_EVENT,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
(LPOVERLAPPED) &RO_HibernateEvent))
|
|
{
|
|
retcode = GetLastError();
|
|
|
|
if (ERROR_IO_PENDING == retcode)
|
|
{
|
|
retcode = SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
if((DWORD) -1 != TraceHandle)
|
|
{
|
|
RasmanTrace(
|
|
"DwSetHibernateEvent: Failed to Set "
|
|
"HibernateEvent Event. 0x%x",
|
|
retcode);
|
|
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
|
|
if((DWORD) -1 != TraceHandle)
|
|
{
|
|
RasmanTrace(
|
|
"DwSetHibernateEvent. rc=0x%x",
|
|
retcode);
|
|
}
|
|
|
|
done:
|
|
return retcode;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Makes the association between ndiswan and rasman's
|
|
completion port. Starts ndsiwan if required.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
return codes from DwStartNdiswan and CreateIoCompletion.
|
|
|
|
--*/
|
|
DWORD
|
|
DwStartAndAssociateNdiswan()
|
|
{
|
|
DWORD retcode = SUCCESS;
|
|
HANDLE hAssociatedPort;
|
|
|
|
ASSERT(INVALID_HANDLE_VALUE != hIoCompletionPort);
|
|
|
|
if(INVALID_HANDLE_VALUE == RasHubHandle)
|
|
{
|
|
retcode = DwStartNdiswan();
|
|
|
|
if(SUCCESS != retcode)
|
|
{
|
|
RasmanTrace(
|
|
"Failed to start ndiswan. 0x%x",
|
|
retcode);
|
|
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
ASSERT(INVALID_HANDLE_VALUE != RasHubHandle);
|
|
|
|
hAssociatedPort = CreateIoCompletionPort(
|
|
RasHubHandle,
|
|
hIoCompletionPort,
|
|
0,
|
|
0);
|
|
|
|
if(NULL == hAssociatedPort)
|
|
{
|
|
retcode = GetLastError();
|
|
|
|
RasmanTrace(
|
|
"Failed to make ndiswan association. 0x%x",
|
|
retcode);
|
|
|
|
goto done;
|
|
}
|
|
|
|
ASSERT(hAssociatedPort == hIoCompletionPort);
|
|
|
|
if(hAssociatedPort != hIoCompletionPort)
|
|
{
|
|
RasmanTrace(
|
|
"DwMakeNdiswanAssociation: hAssociatedport=0x%x"
|
|
" != hIoCompletionPort",
|
|
hAssociatedPort,
|
|
hIoCompletionPort);
|
|
}
|
|
|
|
//
|
|
// Set hibernate and protocol irps with ndiswan
|
|
//
|
|
retcode = DwSetEvents();
|
|
|
|
if(SUCCESS != retcode)
|
|
{
|
|
RasmanTrace(
|
|
"DwMakeNdiswanAssociation: failed to set ndis events. 0x%x",
|
|
retcode);
|
|
}
|
|
|
|
done:
|
|
|
|
RasmanTrace(
|
|
"DwStartAndAssociateNdiswan: 0x%x",
|
|
retcode);
|
|
|
|
return retcode;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If a listen is posted on a biplex port this function
|
|
is called to open it again - basically cancel the listen
|
|
and make the approp changes so that the listen can be
|
|
reposted when this port is closed.
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
Return Value:
|
|
|
|
SUCCESS.
|
|
|
|
--*/
|
|
DWORD
|
|
ReOpenBiplexPort (pPCB ppcb)
|
|
{
|
|
//
|
|
// The only information that is context dependent is the
|
|
// Notifier list AND the async op notifier. Back up both
|
|
// of these:
|
|
//
|
|
ppcb->PCB_BiplexNotifierList = ppcb->PCB_NotifierList ;
|
|
|
|
ppcb->PCB_NotifierList = NULL ;
|
|
|
|
ppcb->PCB_BiplexAsyncOpNotifier =
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier;
|
|
|
|
ppcb->PCB_BiplexOwnerPID = ppcb->PCB_OwnerPID ;
|
|
|
|
ppcb->PCB_BiplexUserStoredBlock =
|
|
ppcb->PCB_UserStoredBlock ;
|
|
|
|
ppcb->PCB_BiplexUserStoredBlockSize =
|
|
ppcb->PCB_UserStoredBlockSize ;
|
|
|
|
ppcb->PCB_UserStoredBlock = NULL ;
|
|
|
|
ppcb->PCB_UserStoredBlockSize = 0 ;
|
|
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier =
|
|
INVALID_HANDLE_VALUE ;
|
|
|
|
//
|
|
// Now Disconnect disconnect the port to cancel any
|
|
// existing states
|
|
//
|
|
DisconnectPort (ppcb,
|
|
INVALID_HANDLE_VALUE,
|
|
USER_REQUESTED) ;
|
|
|
|
return SUCCESS ;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
When the biplex port is closed - the previous listen
|
|
request is reposted.
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
Return Value:
|
|
|
|
SUCCESS.
|
|
|
|
--*/
|
|
VOID
|
|
RePostListenOnBiplexPort (pPCB ppcb)
|
|
{
|
|
|
|
DWORD retcode ;
|
|
DWORD opentry ;
|
|
|
|
//
|
|
// Close the port
|
|
//
|
|
PORTCLOSE (ppcb->PCB_Media, ppcb->PCB_PortIOHandle) ;
|
|
|
|
#define MAX_OPEN_TRIES 10
|
|
|
|
//
|
|
// In order to reset everything we close and open the
|
|
// port:
|
|
//
|
|
for (opentry=0; opentry < MAX_OPEN_TRIES; opentry++)
|
|
{
|
|
//
|
|
// Open followed by Close returns PortAlreadyOpen -
|
|
// hence the sleep.
|
|
//
|
|
Sleep (100L) ;
|
|
|
|
retcode = PORTOPEN (ppcb->PCB_Media,
|
|
ppcb->PCB_Name,
|
|
&ppcb->PCB_PortIOHandle,
|
|
hIoCompletionPort,
|
|
HandleToUlong(ppcb->PCB_PortHandle));
|
|
|
|
if (retcode==SUCCESS)
|
|
{
|
|
break ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the port does not open successfully again - we
|
|
// are in trouble with the port.
|
|
//
|
|
if (retcode != SUCCESS)
|
|
{
|
|
LPSTR temp = ppcb->PCB_Name ;
|
|
RouterLogErrorString (
|
|
hLogEvents,
|
|
ROUTERLOG_CANNOT_REOPEN_BIPLEX_PORT,
|
|
1, (LPSTR*)&temp,retcode, 1
|
|
) ;
|
|
}
|
|
|
|
//
|
|
// Open port first
|
|
//
|
|
ppcb->PCB_PortStatus = OPEN ;
|
|
|
|
SetPortConnState(__FILE__, __LINE__,
|
|
ppcb, DISCONNECTED);
|
|
|
|
ppcb->PCB_DisconnectReason = NOT_DISCONNECTED ;
|
|
|
|
ppcb->PCB_CurrentUsage |= CALL_IN ;
|
|
|
|
ppcb->PCB_CurrentUsage &= ~CALL_OUT;
|
|
|
|
ppcb->PCB_OpenedUsage &= ~CALL_OUT;
|
|
|
|
//
|
|
// First put the backed up notifier lists in place.
|
|
//
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier =
|
|
ppcb->PCB_BiplexAsyncOpNotifier ;
|
|
|
|
ppcb->PCB_NotifierList = ppcb->PCB_BiplexNotifierList ;
|
|
|
|
ppcb->PCB_OwnerPID = ppcb->PCB_BiplexOwnerPID ;
|
|
|
|
//
|
|
// there wasnt a listen pending - so just return.
|
|
//
|
|
if (ppcb->PCB_AsyncWorkerElement.WE_Notifier ==
|
|
INVALID_HANDLE_VALUE)
|
|
{
|
|
SignalPortDisconnect(ppcb, ERROR_PORT_DISCONNECTED);
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// Now we re-post a listen with the same async
|
|
// op notifier
|
|
//
|
|
retcode = ListenConnectRequest (
|
|
REQTYPE_DEVICELISTEN,
|
|
ppcb, ppcb->PCB_DeviceType,
|
|
ppcb->PCB_DeviceName, 0,
|
|
ppcb->PCB_BiplexAsyncOpNotifier
|
|
);
|
|
|
|
if (retcode != PENDING)
|
|
{
|
|
//
|
|
// Complete the async request if anything other
|
|
// than PENDING This allows the caller to dela
|
|
// with errors only in one place
|
|
//
|
|
CompleteListenRequest (ppcb, retcode) ;
|
|
}
|
|
|
|
RasmanTrace(
|
|
"Listen posted on port: %s, error code: %d",
|
|
ppcb->PCB_Name,
|
|
retcode);
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Loads the named device dll if it is not already
|
|
loaded and returns a pointer to the device control
|
|
block.
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
devicetype
|
|
|
|
Return Value:
|
|
|
|
Pointer to Device control block or NULL (if DLL could not
|
|
be loaded)
|
|
|
|
--*/
|
|
pDeviceCB
|
|
LoadDeviceDLL (pPCB ppcb, char *devicetype)
|
|
{
|
|
WORD i ;
|
|
|
|
char dllname [MAX_DEVICETYPE_NAME] ;
|
|
|
|
pDeviceCB pdcb = Dcb ;
|
|
|
|
DeviceDLLEntryPoints DDEntryPoints[MAX_DEVICEDLLENTRYPOINTS] =
|
|
{
|
|
DEVICEENUM_STR, DEVICEENUM_ID,
|
|
|
|
DEVICECONNECT_STR, DEVICECONNECT_ID,
|
|
|
|
DEVICELISTEN_STR, DEVICELISTEN_ID,
|
|
|
|
DEVICEGETINFO_STR, DEVICEGETINFO_ID,
|
|
|
|
DEVICESETINFO_STR, DEVICESETINFO_ID,
|
|
|
|
DEVICEDONE_STR, DEVICEDONE_ID,
|
|
|
|
DEVICEWORK_STR, DEVICEWORK_ID,
|
|
|
|
DEVICESETDEVCONFIG_STR, DEVICESETDEVCONFIG_ID,
|
|
|
|
DEVICEGETDEVCONFIG_STR, DEVICEGETDEVCONFIG_ID
|
|
} ;
|
|
|
|
//
|
|
// For optimization we have one DLL representing 3
|
|
// devices. In order to support this we map the 3
|
|
// device names to this one DLL name:
|
|
//
|
|
MapDeviceDLLName (ppcb, devicetype, dllname) ;
|
|
|
|
//
|
|
// Try to find the device first:
|
|
//
|
|
while (pdcb->DCB_Name[0] != '\0')
|
|
{
|
|
if (_stricmp (dllname, pdcb->DCB_Name) == 0)
|
|
{
|
|
return pdcb ;
|
|
}
|
|
|
|
pdcb++ ;
|
|
}
|
|
|
|
//
|
|
// Device DLL Not loaded, so load it.
|
|
//
|
|
if ((pdcb->DCB_DLLHandle =
|
|
LoadLibrary(dllname)) == NULL)
|
|
{
|
|
return NULL ;
|
|
}
|
|
|
|
//
|
|
// Get all the device DLL entry points:
|
|
//
|
|
for (i=0; i < MAX_DEVICEDLLENTRYPOINTS ; i++)
|
|
{
|
|
pdcb->DCB_AddrLookUp[i] = GetProcAddress(
|
|
pdcb->DCB_DLLHandle,
|
|
DDEntryPoints[i].name
|
|
);
|
|
}
|
|
|
|
//
|
|
// If all succeeded copy the device dll name and
|
|
// return pointer to the control block:
|
|
//
|
|
strcpy (pdcb->DCB_Name, dllname) ;
|
|
|
|
return pdcb ;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unloads all dynamically loaded device DLLs
|
|
|
|
Arguments:
|
|
|
|
void
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID
|
|
UnloadDeviceDLLs()
|
|
{
|
|
pDeviceCB pdcb;
|
|
|
|
for (pdcb = Dcb; *pdcb->DCB_Name != '\0'; pdcb++)
|
|
{
|
|
if (pdcb->DCB_DLLHandle != NULL)
|
|
{
|
|
FreeLibrary(pdcb->DCB_DLLHandle);
|
|
pdcb->DCB_DLLHandle = NULL;
|
|
}
|
|
*pdcb->DCB_Name = '\0';
|
|
}
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Used to map the device name to the corresponding DLL
|
|
name. If it is one of modem, pad or switch device we
|
|
map to rasmxs, Else, we map the device name itself.
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
devicetype
|
|
|
|
dllname
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID
|
|
MapDeviceDLLName (pPCB ppcb, char *devicetype, char *dllname)
|
|
{
|
|
if ( (0 ==
|
|
_stricmp (devicetype, DEVICE_MODEM)
|
|
&& (0 ==
|
|
_stricmp (ppcb->PCB_Media->MCB_Name, "RASTAPI"))))
|
|
{
|
|
//
|
|
// this is a unimodem modem
|
|
//
|
|
strcpy (dllname, "RASTAPI") ;
|
|
}
|
|
else if ( (0 == _stricmp (devicetype, DEVICE_MODEM))
|
|
|| (0 == _stricmp (devicetype, DEVICE_PAD))
|
|
|| (0 == _stricmp (devicetype, DEVICE_SWITCH)))
|
|
{
|
|
//
|
|
// rasmxs modem
|
|
//
|
|
strcpy (dllname, DEVICE_MODEMPADSWITCH);
|
|
}
|
|
else if (0 == _stricmp (devicetype, "RASETHER"))
|
|
{
|
|
strcpy (dllname, "RASETHER") ;
|
|
}
|
|
else if (0 == _stricmp (devicetype, "RASSNA"))
|
|
{
|
|
strcpy (dllname, "RASSNA") ;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// else all devices are supported bu rastapi dll
|
|
//
|
|
strcpy (dllname, "RASTAPI") ;
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees a allocated route. If it was also activated it is
|
|
"deactivated at this point"
|
|
|
|
Arguments:
|
|
|
|
pBundle
|
|
|
|
plist
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID
|
|
DeAllocateRoute (Bundle *pBundle, pList plist)
|
|
{
|
|
NDISWAN_UNROUTE rinfo ;
|
|
|
|
DWORD bytesrecvd ;
|
|
|
|
pProtInfo prot = (pProtInfo)plist->L_Element ;
|
|
|
|
if (plist->L_Activated)
|
|
{
|
|
|
|
#if DBG
|
|
ASSERT(INVALID_HANDLE_VALUE != RasHubHandle);
|
|
#endif
|
|
|
|
plist->L_Activated = FALSE ;
|
|
|
|
rinfo.hBundleHandle = pBundle->B_NdisHandle ;
|
|
|
|
rinfo.usProtocolType = (USHORT) prot->PI_Type;
|
|
|
|
//
|
|
// Un-route this by calling to the RASHUB.
|
|
//
|
|
DeviceIoControl (
|
|
RasHubHandle,
|
|
IOCTL_NDISWAN_UNROUTE,
|
|
(PBYTE) &rinfo,
|
|
sizeof(rinfo),
|
|
NULL,
|
|
0,
|
|
(LPDWORD) &bytesrecvd,
|
|
NULL
|
|
);
|
|
|
|
RasmanTrace(
|
|
|
|
"DeActivated Route , bundlehandle 0x%x,"
|
|
" prottype = %d",
|
|
rinfo.hBundleHandle,
|
|
rinfo.usProtocolType);
|
|
|
|
//
|
|
// Reset the window size we might have set.
|
|
// Don't care about the error.
|
|
//
|
|
(void)DwResetTcpWindowSize(prot->PI_AdapterName);
|
|
|
|
}
|
|
|
|
prot->PI_Allocated--;
|
|
|
|
if(ASYBEUI == prot->PI_Type)
|
|
{
|
|
g_cNbfAllocated -= 1;
|
|
|
|
RasmanTrace(
|
|
"DeAllocateRoute: cNbfAllocated = %d",
|
|
g_cNbfAllocated);
|
|
}
|
|
|
|
RasmanTrace(
|
|
|
|
"DeAllocateRoute: PI_Type=0x%x, PI_AdapterName=%s,"
|
|
" PI_Allocated=%d",
|
|
prot->PI_Type,
|
|
prot->PI_AdapterName,
|
|
prot->PI_Allocated);
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a list element pointing to the deviceCB.
|
|
This marks that the device has been used in
|
|
the connection on the port. This will be used
|
|
to clear up the data structures in the device dll.
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
device
|
|
|
|
Return Value:
|
|
|
|
LocalAlloc errors if memory allocation fails
|
|
|
|
--*/
|
|
DWORD
|
|
AddDeviceToDeviceList (pPCB ppcb, pDeviceCB device)
|
|
{
|
|
pList list ;
|
|
|
|
if (NULL == (list =
|
|
(pList) LocalAlloc(LPTR, sizeof (List))))
|
|
{
|
|
return GetLastError () ;
|
|
}
|
|
|
|
list->L_Element = (PVOID) device ;
|
|
|
|
list->L_Next = ppcb->PCB_DeviceList ;
|
|
|
|
ppcb->PCB_DeviceList = list ;
|
|
|
|
return SUCCESS ;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Runs thru the list of deviceCBs pointed to and calls
|
|
DeviceDone on all of them. The list elements are also
|
|
freed then.
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID
|
|
FreeDeviceList (pPCB ppcb)
|
|
{
|
|
pList list ;
|
|
pList next ;
|
|
|
|
for (list = ppcb->PCB_DeviceList; list; list = next)
|
|
{
|
|
DEVICEDONE(((pDeviceCB)list->L_Element),
|
|
ppcb->PCB_PortFileHandle);
|
|
|
|
next = list->L_Next ;
|
|
|
|
LocalFree (list) ;
|
|
}
|
|
|
|
ppcb->PCB_DeviceList = NULL ;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a notification to the specified notifier list.
|
|
|
|
Arguments:
|
|
|
|
pphlist
|
|
|
|
hEvent
|
|
|
|
dwfFlags
|
|
|
|
dwPid
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
DWORD
|
|
AddNotifierToList(
|
|
pHandleList *pphlist,
|
|
HANDLE hEvent,
|
|
DWORD dwfFlags,
|
|
DWORD dwPid
|
|
)
|
|
{
|
|
pHandleList hList;
|
|
|
|
//
|
|
// Silently ignore NULL events.
|
|
//
|
|
if (hEvent == NULL)
|
|
{
|
|
return SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Silently ignore out-of-memory errors.
|
|
//
|
|
hList = (pHandleList)LocalAlloc(LPTR,
|
|
sizeof (HandleList));
|
|
|
|
if (hList == NULL)
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
hList->H_Handle = hEvent;
|
|
hList->H_Flags = dwfFlags;
|
|
hList->H_Pid = dwPid;
|
|
hList->H_Next = *pphlist;
|
|
*pphlist = hList;
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a process information block to the global
|
|
list of client process information blocks.
|
|
|
|
Arguments:
|
|
|
|
dwPid
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID
|
|
AddProcessInfo( DWORD dwPid )
|
|
{
|
|
// HANDLE hProcess;
|
|
ClientProcessBlock *pCPB;
|
|
|
|
//
|
|
// Before we attempt adding this processinfo block
|
|
// make sure there isn't already a processblock
|
|
// with the same pid in our list - this is possible
|
|
// because some client process could have terminated
|
|
// abruptly and left behind a turd for us to cleanup.
|
|
//
|
|
(void) CleanUpProcess(dwPid);
|
|
|
|
#if 0
|
|
hProcess = OpenProcess( PROCESS_QUERY_INFORMATION,
|
|
FALSE,
|
|
dwPid
|
|
);
|
|
|
|
if (NULL == hProcess)
|
|
{
|
|
RasmanTrace(
|
|
"AddProcessInfo: Failed to OpenProcess %d. rc=%d",
|
|
dwPid,
|
|
GetLastError());
|
|
goto done;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Create a process block
|
|
//
|
|
pCPB = (ClientProcessBlock *)
|
|
LocalAlloc (LPTR, sizeof (ClientProcessBlock));
|
|
|
|
if (NULL == pCPB)
|
|
{
|
|
|
|
RasmanTrace (
|
|
"AddProcessInfo: Failed to allocate for process "
|
|
"%d. rc=%d",
|
|
dwPid,
|
|
GetLastError());
|
|
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Store the process handle and the pid in the
|
|
// process block
|
|
//
|
|
// pCPB->CPB_hProcess = hProcess;
|
|
pCPB->CPB_Pid = dwPid;
|
|
|
|
//
|
|
// Insert the entry in the global list
|
|
//
|
|
InsertTailList(&ClientProcessBlockList, &pCPB->CPB_ListEntry);
|
|
|
|
done:
|
|
return;
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find the process information block give the
|
|
pid of the prcess
|
|
|
|
Arguments:
|
|
|
|
dwPid
|
|
|
|
Return Value:
|
|
|
|
ClientProcessblock * if the process information
|
|
block is found. NULL otherwise
|
|
|
|
--*/
|
|
ClientProcessBlock *
|
|
FindProcess( DWORD dwPid )
|
|
{
|
|
PLIST_ENTRY pEntry;
|
|
ClientProcessBlock *pCPB;
|
|
|
|
for (pEntry = ClientProcessBlockList.Flink;
|
|
pEntry != &ClientProcessBlockList;
|
|
pEntry = pEntry->Flink)
|
|
{
|
|
pCPB = CONTAINING_RECORD(pEntry,
|
|
ClientProcessBlock,
|
|
CPB_ListEntry);
|
|
|
|
if (pCPB->CPB_Pid == dwPid)
|
|
{
|
|
return pCPB;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find out if the process represented by hProcess
|
|
is alive
|
|
|
|
Arguments:
|
|
|
|
hProcess
|
|
|
|
Return Value:
|
|
|
|
TRUE if the process is alive, FALSE otherwise
|
|
|
|
--*/
|
|
BOOL
|
|
fIsProcessAlive ( HANDLE hProcess )
|
|
{
|
|
DWORD dwExitCode;
|
|
BOOL fAlive = TRUE;
|
|
|
|
if(NULL == hProcess)
|
|
{
|
|
RasmanTrace(
|
|
"fIsProcessAlive: hProcess==NULL");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if(GetExitCodeProcess(hProcess, &dwExitCode))
|
|
{
|
|
if (STILL_ACTIVE != dwExitCode)
|
|
{
|
|
fAlive = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RasmanTrace(
|
|
"GetExitCodeProcess 0x%x failed. gle=0x%x",
|
|
hProcess,
|
|
GetLastError());
|
|
}
|
|
|
|
return fAlive;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleanup the resources held by the process with pid
|
|
dwPid
|
|
|
|
Arguments:
|
|
|
|
dwPid
|
|
|
|
Return Value:
|
|
|
|
TRUE if the process was cleaned up. FALSE otherwise
|
|
|
|
--*/
|
|
BOOL
|
|
CleanUpProcess( DWORD dwPid )
|
|
{
|
|
|
|
ClientProcessBlock * pCPB;
|
|
BOOL fResult = TRUE;
|
|
pHandleList pList = pConnectionNotifierList;
|
|
|
|
RasmanTrace( "Cleaning up process %d", dwPid);
|
|
|
|
pCPB = FindProcess (dwPid);
|
|
|
|
if (NULL == pCPB)
|
|
{
|
|
RasmanTrace(
|
|
"CleanUpProcess: Process %d not found!",
|
|
dwPid);
|
|
|
|
fResult = FALSE;
|
|
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Free up the notifier List owned by this process
|
|
// here
|
|
//
|
|
while (pList)
|
|
{
|
|
if (pList->H_Pid == dwPid)
|
|
{
|
|
|
|
RasmanTrace(
|
|
"Freeing handle for %d", dwPid);
|
|
|
|
try
|
|
{
|
|
FreeNotifierHandle( pList->H_Handle );
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
RasmanTrace(
|
|
"Exception while freeing handle 0x%x"
|
|
" exception=0x%x",
|
|
pList->H_Handle,
|
|
GetExceptionCode());
|
|
}
|
|
|
|
pList->H_Handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
pList = pList->H_Next;
|
|
}
|
|
|
|
#if 0
|
|
try
|
|
{
|
|
CloseHandle(pCPB->CPB_hProcess);
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
RasmanTrace(
|
|
"Exception while closing handle 0x%x"
|
|
" exception=0x%x",
|
|
pCPB->CPB_hProcess,
|
|
GetExceptionCode());
|
|
}
|
|
#endif
|
|
|
|
RemoveEntryList(&pCPB->CPB_ListEntry);
|
|
|
|
LocalFree (pCPB);
|
|
|
|
done:
|
|
return fResult;
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees a list of notifiers.
|
|
|
|
Arguments:
|
|
|
|
pHandleList
|
|
|
|
Return Value:
|
|
|
|
void
|
|
--*/
|
|
VOID
|
|
FreeNotifierList (pHandleList *orglist)
|
|
{
|
|
pHandleList hlist ;
|
|
pHandleList next ;
|
|
|
|
for (hlist = *orglist; hlist; hlist = next)
|
|
{
|
|
next = hlist->H_Next ;
|
|
FreeNotifierHandle (hlist->H_Handle) ;
|
|
LocalFree (hlist) ;
|
|
}
|
|
|
|
*orglist = NULL ;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a notifier to the head of. global
|
|
g_pPnPNotifierList
|
|
|
|
Arguments:
|
|
|
|
pNotifier
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID
|
|
AddPnPNotifierToList (pPnPNotifierList pNotifier)
|
|
{
|
|
|
|
pNotifier->PNPNotif_Next = g_pPnPNotifierList;
|
|
|
|
g_pPnPNotifierList = pNotifier;
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
RemovePnPNotifierFromList(PAPCFUNC pfn)
|
|
{
|
|
pPnPNotifierList *ppList = &g_pPnPNotifierList;
|
|
|
|
while(NULL != *ppList)
|
|
{
|
|
if((*ppList)->PNPNotif_uNotifier.pfnPnPNotifHandler == pfn)
|
|
{
|
|
pPnPNotifierList pNotifier = *ppList;
|
|
*ppList = (*ppList)->PNPNotif_Next;
|
|
LocalFree(pNotifier);
|
|
break;
|
|
}
|
|
|
|
ppList = &((*ppList)->PNPNotif_Next);
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees the global list of PnP notifiers
|
|
|
|
Arguments:
|
|
|
|
void
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID
|
|
FreePnPNotifierList ()
|
|
{
|
|
pPnPNotifierList pList = g_pPnPNotifierList;
|
|
pPnPNotifierList pTemp;
|
|
|
|
while ( pList )
|
|
{
|
|
pTemp = pList;
|
|
pList = pList->PNPNotif_Next;
|
|
|
|
LocalFree ( pTemp );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Runs thorugh a list of notifiers and calls the signalling
|
|
routine. Frees the global list of PnP notifiers
|
|
|
|
Arguments:
|
|
|
|
hlist
|
|
|
|
dwEvent
|
|
|
|
retcode
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID
|
|
SignalNotifiers (pHandleList hlist, DWORD dwEvent, DWORD retcode)
|
|
{
|
|
|
|
for (; hlist; hlist = hlist->H_Next)
|
|
{
|
|
if (hlist->H_Flags & dwEvent)
|
|
{
|
|
if( (INVALID_HANDLE_VALUE != hlist->H_Handle)
|
|
&& (NULL != hlist->H_Handle))
|
|
{
|
|
SetEvent (hlist->H_Handle);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Signals the port's notifier list and I/O completion
|
|
port of a disconnect event routine.
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
retcode
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID
|
|
SignalPortDisconnect(pPCB ppcb, DWORD retcode)
|
|
{
|
|
SignalNotifiers(ppcb->PCB_NotifierList,
|
|
NOTIF_DISCONNECT,
|
|
retcode);
|
|
|
|
if (ppcb->PCB_IoCompletionPort != INVALID_HANDLE_VALUE)
|
|
{
|
|
RasmanTrace(
|
|
"SignalPortDisconnect: pOverlapped=0x%x",
|
|
ppcb->PCB_OvDrop);
|
|
|
|
PostQueuedCompletionStatus(
|
|
ppcb->PCB_IoCompletionPort,
|
|
0,
|
|
0,
|
|
ppcb->PCB_OvDrop);
|
|
}
|
|
|
|
SendDisconnectNotificationToPPP ( ppcb );
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Disconnects the port in question. Since disconnection
|
|
is an async operation - if it completes synchronously,
|
|
then SUCCESS is returned and the app is signalled
|
|
asynchronously also.
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
handle
|
|
|
|
reason
|
|
|
|
Return Value:
|
|
|
|
Error codes returned by the Media DLL if failed.
|
|
SUCCESS otherwise
|
|
|
|
--*/
|
|
DWORD
|
|
DisconnectPort (pPCB ppcb,
|
|
HANDLE handle,
|
|
RASMAN_DISCONNECT_REASON reason)
|
|
{
|
|
pList list ;
|
|
|
|
pList temp ;
|
|
|
|
DWORD retcode ;
|
|
|
|
NDISWAN_UNROUTE rinfo ;
|
|
|
|
DWORD bytesrecvd ;
|
|
|
|
DWORD dwBundleCount = 0;
|
|
|
|
HBUNDLE hBundle = 0;
|
|
|
|
RasmanTrace(
|
|
"Disconnecting Port 0x%s, reason %d",
|
|
ppcb->PCB_Name,
|
|
reason);
|
|
|
|
if(ppcb->PCB_ConnState == LISTENING)
|
|
{
|
|
RasmanTrace(
|
|
"DisconnectPort: disconnecting port %d which is listening",
|
|
ppcb->PCB_PortHandle);
|
|
|
|
}
|
|
|
|
//
|
|
// Get the stats are store them - for displaying
|
|
// when we are not connected
|
|
//
|
|
if (ppcb->PCB_ConnState == CONNECTED)
|
|
{
|
|
DWORD stats[MAX_STATISTICS];
|
|
|
|
RasmanTrace(
|
|
"DisconnectPort: Saving Bundle stats for port %s",
|
|
ppcb->PCB_Name);
|
|
|
|
GetBundleStatisticsFromNdisWan (ppcb, stats) ;
|
|
|
|
//
|
|
// We save the bundle stats for the port so
|
|
// the server can report the correct bytes
|
|
// sent/received for the connection in its
|
|
// error log report.
|
|
//
|
|
memcpy(ppcb->PCB_Stats, stats, sizeof (WAN_STATS));
|
|
|
|
//
|
|
// If this is the last port and its going away
|
|
// then delete the credentials from credential
|
|
// manager
|
|
//
|
|
if( (NULL != ppcb->PCB_Connection)
|
|
&& (ppcb->PCB_Connection->CB_Signaled)
|
|
&& (1 == ppcb->PCB_Connection->CB_Ports)
|
|
&& (ppcb->PCB_Connection->CB_dwPid != GetCurrentProcessId()))
|
|
{
|
|
DWORD dwErr;
|
|
|
|
dwErr = DwDeleteCredentials(ppcb->PCB_Connection);
|
|
|
|
RasmanTrace(
|
|
"DisconnectPort: DwDeleteCreds returned 0x%x",
|
|
dwErr);
|
|
}
|
|
}
|
|
|
|
if(NULL != ppcb->PCB_Connection)
|
|
{
|
|
BOOL fQueued = FALSE;
|
|
|
|
if(ppcb->PCB_Connection->CB_Flags & CONNECTION_DEFERRED_CLOSE)
|
|
{
|
|
RasmanTrace("DisconnectPort: CONNECTION_DEFERRED_CLOSE");
|
|
}
|
|
else if(ppcb->PCB_Connection->CB_Flags & CONNECTION_DEFERRING_CLOSE)
|
|
{
|
|
//
|
|
// This port is in already disconnecting state
|
|
//
|
|
RasmanTrace("DisconnectPort: CONNECTION_DEFERRING_CLOSE");
|
|
FreeNotifierHandle(handle);
|
|
return ERROR_ALREADY_DISCONNECTING;
|
|
}
|
|
else
|
|
{
|
|
QueueCloseConnections(ppcb->PCB_Connection, handle, &fQueued);
|
|
if(fQueued)
|
|
{
|
|
RasmanTrace("DisconnectPort: Deferring Disconnect.");
|
|
return PENDING;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if UNMAP
|
|
UnmapEndPoint(ppcb);
|
|
#endif
|
|
|
|
//
|
|
// Set the port file handle back to the io handle since
|
|
// the io handle is the only valid handle after a
|
|
// disconnect.
|
|
//
|
|
ppcb->PCB_PortFileHandle = ppcb->PCB_PortIOHandle ;
|
|
|
|
//
|
|
// If there is a request pending and the state is
|
|
// not already disconnecting and this is a user
|
|
// requested operation - then complete the
|
|
// request.
|
|
//
|
|
if ( (reason == USER_REQUESTED)
|
|
&& (ppcb->PCB_ConnState != DISCONNECTING))
|
|
{
|
|
|
|
if (ppcb->PCB_ConnState == CONNECTED)
|
|
{
|
|
//
|
|
// In connected state the only thing pending is
|
|
// a read posted by rasman: if there is a read
|
|
// request pending - clean that.
|
|
//
|
|
if (ppcb->PCB_PendingReceive != NULL)
|
|
{
|
|
//
|
|
// Don't overwrite the real error if we
|
|
// have it stored.
|
|
//
|
|
if( (SUCCESS == ppcb->PCB_LastError)
|
|
|| (PENDING == ppcb->PCB_LastError))
|
|
{
|
|
ppcb->PCB_LastError = ERROR_PORT_DISCONNECTED ;
|
|
}
|
|
|
|
CompleteAsyncRequest (ppcb);
|
|
|
|
RasmanTrace(
|
|
"1. Notifying of disconnect on port %d",
|
|
ppcb->PCB_PortHandle);
|
|
|
|
FreeNotifierHandle(
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier
|
|
);
|
|
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier =
|
|
INVALID_HANDLE_VALUE;
|
|
|
|
if (ppcb->PCB_RasmanReceiveFlags
|
|
& RECEIVE_OUTOF_PROCESS)
|
|
{
|
|
//
|
|
// This means rasman allocated the buffer
|
|
// and so client is not going to free this
|
|
// memory.
|
|
//
|
|
LocalFree ( ppcb->PCB_PendingReceive );
|
|
|
|
ppcb->PCB_PendingReceive = NULL;
|
|
}
|
|
else
|
|
{
|
|
SendDisconnectNotificationToPPP ( ppcb );
|
|
}
|
|
|
|
ppcb->PCB_PendingReceive = NULL;
|
|
}
|
|
|
|
}
|
|
else if (ppcb->PCB_AsyncWorkerElement.WE_ReqType
|
|
!= REQTYPE_NONE)
|
|
{
|
|
//
|
|
// Not connected - some other operation may be
|
|
// pending - complete it.
|
|
//
|
|
if( (SUCCESS == ppcb->PCB_LastError)
|
|
|| (PENDING == ppcb->PCB_LastError))
|
|
{
|
|
ppcb->PCB_LastError = ERROR_PORT_DISCONNECTED ;
|
|
}
|
|
|
|
CompleteAsyncRequest (ppcb);
|
|
|
|
RasmanTrace(
|
|
"2. Notifying event on port %d",
|
|
ppcb->PCB_PortHandle);
|
|
|
|
FreeNotifierHandle(
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier
|
|
);
|
|
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier =
|
|
INVALID_HANDLE_VALUE ;
|
|
|
|
RemoveTimeoutElement(ppcb);
|
|
ppcb->PCB_AsyncWorkerElement.WE_TimeoutElement = NULL;
|
|
|
|
|
|
//SendDisconnectNotificationToPPP( ppcb );
|
|
}
|
|
}
|
|
else if(USER_REQUESTED != reason)
|
|
{
|
|
//
|
|
// if a receive is pending then free the notifier
|
|
// but do not notify since the cancelreceive is
|
|
// used by the client
|
|
//
|
|
RasmanTrace(
|
|
"10. Throwing away handle 0x%x!",
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier);
|
|
|
|
//
|
|
// Put in because on the server side the receive
|
|
// request handle is not
|
|
// being freed
|
|
//
|
|
FreeNotifierHandle(
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier
|
|
);
|
|
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier =
|
|
INVALID_HANDLE_VALUE ;
|
|
}
|
|
|
|
//
|
|
// Complete pending out-of-process receives if
|
|
// one is pending - there is no point in keeping
|
|
// this buffer around.
|
|
//
|
|
if(RECEIVE_WAITING & ppcb->PCB_RasmanReceiveFlags)
|
|
{
|
|
RasmanTrace(
|
|
|
|
"Completing pending OUT_OF_PROCESS receive on port %s",
|
|
ppcb->PCB_Name);
|
|
|
|
//
|
|
// remove the timeout element if there was one
|
|
//
|
|
//
|
|
if (ppcb->PCB_AsyncWorkerElement.WE_TimeoutElement != NULL)
|
|
{
|
|
RemoveTimeoutElement(ppcb);
|
|
ppcb->PCB_AsyncWorkerElement.WE_TimeoutElement = NULL;
|
|
}
|
|
|
|
ppcb->PCB_RasmanReceiveFlags = 0;
|
|
}
|
|
|
|
//
|
|
// If we are already disconnecting - then return
|
|
// PENDING. ** NOTE ** Since we only store one
|
|
// event - the event passed in this request is
|
|
// ignored.
|
|
//
|
|
if ( (INVALID_HANDLE_VALUE !=
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier)
|
|
&& (ppcb->PCB_ConnState == DISCONNECTING))
|
|
{
|
|
RasmanTrace(
|
|
"DisconnectPort: Throwing away notification "
|
|
"handle 0x%x on port %s",
|
|
handle, ppcb->PCB_Name);
|
|
|
|
RasmanTrace(
|
|
"DisconnectPort: Current handle=0x%x",
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier);
|
|
|
|
//
|
|
// since we are ignoring the notification handle
|
|
//
|
|
FreeNotifierHandle (handle);
|
|
return ERROR_ALREADY_DISCONNECTING ;
|
|
}
|
|
else if( (INVALID_HANDLE_VALUE != handle)
|
|
&& (DISCONNECTING == ppcb->PCB_ConnState))
|
|
{
|
|
RasmanTrace(
|
|
"Queueing event on a DISCONNECTING port %s",
|
|
ppcb->PCB_Name);
|
|
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier = handle;
|
|
|
|
return PENDING;
|
|
}
|
|
|
|
// If already disconnected - simply return success.
|
|
//
|
|
if (ppcb->PCB_ConnState == DISCONNECTED)
|
|
{
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier = handle ;
|
|
|
|
RasmanTrace(
|
|
"4. Notifying of disconnect on port %d",
|
|
ppcb->PCB_PortHandle);
|
|
|
|
CompleteDisconnectRequest (ppcb) ;
|
|
|
|
// SendDisconnectNotificationToPPP ( ppcb );
|
|
|
|
return SUCCESS ;
|
|
}
|
|
|
|
//
|
|
// If some other operation is pending we must remove
|
|
// it from the timeout queue before starting on
|
|
// disconnection:
|
|
//
|
|
if (NULL !=
|
|
ppcb->PCB_AsyncWorkerElement.WE_TimeoutElement)
|
|
{
|
|
RemoveTimeoutElement (ppcb) ;
|
|
|
|
ppcb->PCB_AsyncWorkerElement.WE_TimeoutElement = NULL ;
|
|
}
|
|
|
|
//
|
|
// Check to see if this port belongs to a
|
|
// connection where the process that has
|
|
// created it has terminated, or the port
|
|
// has not been disconnected due to user
|
|
// request. In this case, we automatically
|
|
// close the port so that if the RAS server
|
|
// is running, the listen will get reposted
|
|
// on the port.
|
|
//
|
|
if ( ppcb->PCB_Connection != NULL
|
|
&& reason != USER_REQUESTED)
|
|
{
|
|
RasmanTrace(
|
|
"%s, %d:Setting port %d for autoclosure...",
|
|
__FILE__, __LINE__,
|
|
ppcb->PCB_PortHandle);
|
|
|
|
ppcb->PCB_AutoClose = TRUE;
|
|
|
|
}
|
|
|
|
retcode =
|
|
PORTDISCONNECT(ppcb->PCB_Media, ppcb->PCB_PortIOHandle);
|
|
|
|
RasmanTrace(
|
|
"%s %d: Disconnected Port %d, reason %d. rc=0x%x",
|
|
__FILE__, __LINE__,
|
|
ppcb->PCB_PortHandle,
|
|
reason,
|
|
retcode);
|
|
|
|
//
|
|
// If this failed for any reason LOG IT.
|
|
//
|
|
if ( (retcode != SUCCESS)
|
|
&& (retcode != PENDING))
|
|
{
|
|
LPSTR temp = ppcb->PCB_Name ;
|
|
|
|
RasmanTrace(
|
|
"PortDisconnect failed on port %d. retcode = %d",
|
|
ppcb->PCB_PortHandle, retcode);
|
|
|
|
RouterLogErrorString (
|
|
hLogEvents,
|
|
ROUTERLOG_DISCONNECT_ERROR,
|
|
1,
|
|
(LPSTR*)&temp,
|
|
retcode,
|
|
1) ;
|
|
}
|
|
|
|
//
|
|
// Flush the queue of PPP events.
|
|
//
|
|
while (ppcb->PCB_PppQHead != NULL)
|
|
{
|
|
PPP_MESSAGE * pPppMsg = ppcb->PCB_PppQHead;
|
|
|
|
ppcb->PCB_PppQHead = ppcb->PCB_PppQHead->pNext;
|
|
|
|
LocalFree( pPppMsg );
|
|
}
|
|
|
|
ppcb->PCB_PppQTail = NULL;
|
|
|
|
//
|
|
// Close the PCB_PppEvent handle. It will
|
|
// get recreated the next time PppStart
|
|
// is called.
|
|
//
|
|
if (ppcb->PCB_PppEvent != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(ppcb->PCB_PppEvent);
|
|
ppcb->PCB_PppEvent = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
//
|
|
// Call the device dlls to clean up:
|
|
//
|
|
if ( (ppcb->PCB_ConnState==CONNECTING)
|
|
|| (ppcb->PCB_ConnState==LISTENING)
|
|
|| (ppcb->PCB_ConnState==LISTENCOMPLETED))
|
|
{
|
|
FreeDeviceList (ppcb) ;
|
|
}
|
|
|
|
//
|
|
// Unrouting works differently for Bundled and
|
|
// unbundled cases:
|
|
//
|
|
if (ppcb->PCB_Bundle == (Bundle *) NULL)
|
|
{
|
|
//
|
|
// Mark the allocated routes as deactivated.
|
|
//
|
|
for (list = ppcb->PCB_Bindings;
|
|
list;
|
|
list=list->L_Next)
|
|
{
|
|
if (list->L_Activated)
|
|
{
|
|
#if DBG
|
|
ASSERT(INVALID_HANDLE_VALUE != RasHubHandle);
|
|
#endif
|
|
rinfo.hBundleHandle = ppcb->PCB_BundleHandle ;
|
|
|
|
rinfo.usProtocolType =
|
|
(USHORT)((pProtInfo)(list->L_Element))->PI_Type;
|
|
|
|
//
|
|
// Un-route this by calling to the RASHUB.
|
|
//
|
|
DeviceIoControl (
|
|
RasHubHandle,
|
|
IOCTL_NDISWAN_UNROUTE,
|
|
(PBYTE) &rinfo,
|
|
sizeof(rinfo),
|
|
NULL,
|
|
0,
|
|
&bytesrecvd,
|
|
NULL
|
|
);
|
|
|
|
RasmanTrace(
|
|
"%s, %d: DeActivated Route for %s(0x%x) , "
|
|
"bundlehandle 0x%x, prottype = %d",
|
|
__FILE__, __LINE__,
|
|
ppcb->PCB_Name,
|
|
ppcb,
|
|
rinfo.hBundleHandle,
|
|
rinfo.usProtocolType);
|
|
|
|
list->L_Activated = FALSE ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BOOL fAsybeui = FALSE;
|
|
|
|
//
|
|
// If this is the last multilinked link -
|
|
// then revert back the binding list to
|
|
// this port.
|
|
//
|
|
dwBundleCount = --ppcb->PCB_Bundle->B_Count;
|
|
if (ppcb->PCB_Bundle->B_Count == 0)
|
|
{
|
|
//
|
|
// Mark the allocated routes as deactivated.
|
|
//
|
|
for (list = ppcb->PCB_Bundle->B_Bindings;
|
|
list;
|
|
list=list->L_Next)
|
|
{
|
|
if (list->L_Activated)
|
|
{
|
|
#if DBG
|
|
ASSERT(INVALID_HANDLE_VALUE != RasHubHandle);
|
|
#endif
|
|
rinfo.hBundleHandle = ppcb->PCB_BundleHandle;
|
|
|
|
rinfo.usProtocolType =
|
|
(USHORT)((pProtInfo)(list->L_Element))->PI_Type;
|
|
|
|
if(ASYBEUI == rinfo.usProtocolType)
|
|
{
|
|
fAsybeui = TRUE;
|
|
}
|
|
|
|
//
|
|
// Un-route this by calling to the RASHUB.
|
|
//
|
|
DeviceIoControl (
|
|
RasHubHandle,
|
|
IOCTL_NDISWAN_UNROUTE,
|
|
(PBYTE) &rinfo,
|
|
sizeof(rinfo),
|
|
NULL,
|
|
0,
|
|
&bytesrecvd,
|
|
NULL) ;
|
|
|
|
RasmanTrace(
|
|
"%s, %d: DeActivated Route for %s(0x%x),"
|
|
" bundlehandle 0x%x, prottype = %d",
|
|
__FILE__, __LINE__,
|
|
ppcb->PCB_Name,
|
|
ppcb,
|
|
rinfo.hBundleHandle,
|
|
rinfo.usProtocolType);
|
|
|
|
list->L_Activated = FALSE ;
|
|
}
|
|
}
|
|
|
|
if( fAsybeui
|
|
&& (NULL == ppcb->PCB_Connection)
|
|
&& !(ppcb->PCB_RasmanReceiveFlags & RECEIVE_PPPSTARTED))
|
|
{
|
|
ppcb->PCB_fAmb = TRUE;
|
|
|
|
//ppcb->PCB_Bundle->B_fAmb = TRUE;
|
|
|
|
//
|
|
// Don't NULL this out in the case where
|
|
// its netbeui. Otherwise this breaks
|
|
// callbacks on amb/netbeui. This will be
|
|
// NULL'd out in RasDeallocateRoute.
|
|
//
|
|
ppcb->PCB_Bindings =
|
|
ppcb->PCB_Bundle->B_Bindings;
|
|
|
|
RasmanTrace(
|
|
"Keeping bindings 0x%x on the "
|
|
"port for %s, bundle=0x%x",
|
|
ppcb->PCB_Bindings,
|
|
ppcb->PCB_Name,
|
|
ppcb->PCB_Bundle);
|
|
|
|
}
|
|
else
|
|
{
|
|
ppcb->PCB_Bindings = NULL;
|
|
}
|
|
|
|
if (ppcb->PCB_Bundle->B_Bindings != NULL)
|
|
{
|
|
//
|
|
// If the bundle has bindings, it will
|
|
// be deallocated via RasDeallocateRoute().
|
|
//
|
|
hBundle = ppcb->PCB_Bundle->B_Handle;
|
|
}
|
|
else
|
|
{
|
|
|
|
FreeBundle(ppcb->PCB_Bundle);
|
|
|
|
ppcb->PCB_Bundle = ( Bundle * ) NULL;
|
|
}
|
|
|
|
}
|
|
|
|
if (NULL == ppcb->PCB_Connection)
|
|
{
|
|
ppcb->PCB_Bundle = (Bundle *) NULL ;
|
|
}
|
|
}
|
|
|
|
ppcb->PCB_LinkHandle = INVALID_HANDLE_VALUE ;
|
|
ppcb->PCB_BundleHandle = INVALID_HANDLE_VALUE ;
|
|
|
|
//
|
|
// If there is any disconnect action to be
|
|
// performed - do it.
|
|
//
|
|
PerformDisconnectAction (ppcb, hBundle) ;
|
|
|
|
//
|
|
// If the disconnect occured due some failure
|
|
// (not user requested) then set the error code
|
|
// to say this
|
|
//
|
|
ppcb->PCB_DisconnectReason = reason ;
|
|
|
|
if ( SUCCESS != retcode
|
|
&& PENDING != retcode)
|
|
{
|
|
RasmanTrace(
|
|
"%s, %d: retcode = 0x%x, port = %d",
|
|
__FILE__, __LINE__,
|
|
retcode,
|
|
ppcb->PCB_PortHandle);
|
|
|
|
SetPortConnState(__FILE__, __LINE__,
|
|
ppcb,
|
|
DISCONNECTED);
|
|
}
|
|
else
|
|
{
|
|
SetPortConnState(__FILE__, __LINE__,
|
|
ppcb,
|
|
DISCONNECTING);
|
|
}
|
|
|
|
//
|
|
// Flush any pending receive buffers from this port
|
|
//
|
|
FlushPcbReceivePackets(ppcb);
|
|
|
|
//
|
|
// For all cases: whether rasman requested or user
|
|
// requested.
|
|
//
|
|
if ( retcode == SUCCESS )
|
|
{
|
|
SetPortConnState(__FILE__, __LINE__,
|
|
ppcb,
|
|
DISCONNECTED);
|
|
//
|
|
// Inform others the port has been disconnected.
|
|
//
|
|
RasmanTrace(
|
|
"5. Notifying of disconnect on port %d",
|
|
ppcb->PCB_PortHandle);
|
|
|
|
SignalPortDisconnect(ppcb, 0);
|
|
|
|
SignalNotifiers(pConnectionNotifierList,
|
|
NOTIF_DISCONNECT,
|
|
0);
|
|
|
|
//SendDisconnectNotificationToPPP ( ppcb );
|
|
}
|
|
|
|
//
|
|
// Set last error to the true retcode ONLY if this is a
|
|
// USER_REQUESTED operation. Else set it to
|
|
// ERROR_PORT_DISCONNECTED.
|
|
//
|
|
if (reason == USER_REQUESTED)
|
|
{
|
|
if ( (retcode == SUCCESS)
|
|
|| (retcode == PENDING))
|
|
{
|
|
|
|
if( (SUCCESS == ppcb->PCB_LastError)
|
|
|| (PENDING == ppcb->PCB_LastError))
|
|
{
|
|
//
|
|
// Set only for normal disconnect
|
|
//
|
|
ppcb->PCB_LastError = retcode ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ppcb->PCB_LastError = ERROR_PORT_DISCONNECTED ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the handle passed in is INVALID_HANDLE then this
|
|
// is not an operation requested asynchronously. So we
|
|
// do not need to marshall the asyncworkerlement for
|
|
// the port. We also do not need to keep the lasterror .
|
|
//
|
|
if (handle != INVALID_HANDLE_VALUE)
|
|
{
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier = handle ;
|
|
|
|
SetPortAsyncReqType(__FILE__, __LINE__,
|
|
ppcb,
|
|
REQTYPE_PORTDISCONNECT);
|
|
|
|
if (retcode == PENDING)
|
|
{
|
|
//
|
|
// This is added so that if some medias do not
|
|
// drop their connection within X amount of time
|
|
// - we force a disconnect.
|
|
//
|
|
|
|
//
|
|
// If some other operation is pending we must
|
|
// remove it from the timeout queue before
|
|
// starting on disconnection:
|
|
//
|
|
if (NULL !=
|
|
ppcb->PCB_AsyncWorkerElement.WE_TimeoutElement)
|
|
{
|
|
RemoveTimeoutElement (ppcb) ;
|
|
|
|
ppcb->PCB_AsyncWorkerElement.WE_TimeoutElement
|
|
= NULL;
|
|
}
|
|
|
|
ppcb->PCB_AsyncWorkerElement.WE_TimeoutElement =
|
|
AddTimeoutElement ((TIMERFUNC)DisconnectTimeout,
|
|
ppcb,
|
|
NULL,
|
|
DISCONNECT_TIMEOUT);
|
|
|
|
AdjustTimer();
|
|
|
|
return retcode ;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This means that the connection attempt completed
|
|
// synchronously: We must signal the event passed in
|
|
// : so that the calling program can treat this like
|
|
// a real async completion.
|
|
//
|
|
RasmanTrace(
|
|
"6. Notifying of disconnect on port %d",
|
|
ppcb->PCB_PortHandle);
|
|
|
|
CompleteDisconnectRequest (ppcb) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Make sure that the async worker element is set to
|
|
// REQTYPE_NONE
|
|
//
|
|
SetPortAsyncReqType(__FILE__, __LINE__,
|
|
ppcb,
|
|
REQTYPE_NONE);
|
|
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier =
|
|
INVALID_HANDLE_VALUE ;
|
|
|
|
if(SUCCESS == retcode)
|
|
{
|
|
ConnectionBlock *pConn = ppcb->PCB_Connection;
|
|
|
|
RasmanTrace(
|
|
"***** DisconnectReason=%d,"
|
|
"pConn=0x%x,cbports=%d,signaled=%d,hEvent=0x%x,"
|
|
"fRedial=%d",
|
|
ppcb->PCB_DisconnectReason,
|
|
pConn,
|
|
(pConn)?pConn->CB_Ports:0,
|
|
(pConn)?pConn->CB_Signaled:0,
|
|
ppcb->PCB_hEventClientDisconnect,
|
|
ppcb->PCB_fRedial);
|
|
|
|
|
|
if ( ( (ppcb->PCB_DisconnectReason != USER_REQUESTED)
|
|
|| (ppcb->PCB_fRedial))
|
|
&& (pConn != NULL)
|
|
&& (pConn->CB_Ports == 1)
|
|
&& (pConn->CB_Signaled)
|
|
&& ((INVALID_HANDLE_VALUE
|
|
== ppcb->PCB_hEventClientDisconnect)
|
|
|| (NULL == ppcb->PCB_hEventClientDisconnect)))
|
|
{
|
|
DWORD dwErr;
|
|
RasmanTrace(
|
|
"Calling DwQueueRedial");
|
|
|
|
dwErr = DwQueueRedial(pConn);
|
|
|
|
RasmanTrace(
|
|
"DwQueueRedial returned 0x%x",
|
|
dwErr);
|
|
|
|
}
|
|
else
|
|
{
|
|
if( (INVALID_HANDLE_VALUE != ppcb->PCB_hEventClientDisconnect)
|
|
|| (NULL != ppcb->PCB_hEventClientDisconnect))
|
|
{
|
|
RasmanTrace(
|
|
"Not queueing redial because its client initiated"
|
|
" disconnect on port %s",
|
|
ppcb->PCB_Name);
|
|
}
|
|
}
|
|
|
|
if (ppcb->PCB_AutoClose)
|
|
{
|
|
RasmanTrace(
|
|
|
|
"%s, %d: Autoclosing port %d", __FILE__,
|
|
__LINE__, ppcb->PCB_PortHandle);
|
|
|
|
(void)PortClose(ppcb, GetCurrentProcessId(),
|
|
TRUE, FALSE);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
RasmanTrace( "DisconnectPort Complete");
|
|
return retcode ;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the shared code between the Listen and Connect
|
|
requests. The corresponding device dll functions are
|
|
called. If these async operations complete synchronously
|
|
then we return SUCCESS but also comply to the async
|
|
protocol by clearing the events. Note that in case
|
|
of an error the state of the port is left at CONNECTING
|
|
or LISTENING, the calling app must call Disconnect()
|
|
to reset this.
|
|
|
|
Arguments:
|
|
|
|
reqtype
|
|
|
|
ppcb
|
|
|
|
devicetype
|
|
|
|
devicename
|
|
|
|
timeout
|
|
|
|
handle
|
|
|
|
Return Value:
|
|
|
|
Codes returned by the loader or the device dll.
|
|
|
|
--*/
|
|
DWORD
|
|
ListenConnectRequest (
|
|
WORD reqtype,
|
|
pPCB ppcb,
|
|
PCHAR devicetype,
|
|
PCHAR devicename,
|
|
DWORD timeout,
|
|
HANDLE handle
|
|
)
|
|
{
|
|
pDeviceCB device ;
|
|
DWORD retcode ;
|
|
|
|
//
|
|
// If some other operation is pending we must remove it
|
|
// from the timeout queue before starting on
|
|
// connect/listen:
|
|
//
|
|
if (ppcb->PCB_AsyncWorkerElement.WE_TimeoutElement != NULL)
|
|
{
|
|
RemoveTimeoutElement (ppcb) ;
|
|
ppcb->PCB_AsyncWorkerElement.WE_TimeoutElement = NULL ;
|
|
}
|
|
|
|
ppcb->PCB_AsyncWorkerElement.WE_Notifier = handle ;
|
|
|
|
//
|
|
// If this is the first device connecting or listening on
|
|
// this port then we need to call the media dll to do any
|
|
// initializations:
|
|
//
|
|
if ( (ppcb->PCB_ConnState!=CONNECTING)
|
|
|| (ppcb->PCB_ConnState!=LISTENING))
|
|
{
|
|
retcode = PORTINIT(ppcb->PCB_Media, ppcb->PCB_PortIOHandle) ;
|
|
|
|
if (retcode)
|
|
{
|
|
return retcode ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// First check if device dll is loaded. If not loaded -
|
|
// load it.
|
|
//
|
|
device = LoadDeviceDLL (ppcb, devicetype) ;
|
|
|
|
if (device == NULL)
|
|
{
|
|
return ERROR_DEVICE_DOES_NOT_EXIST ;
|
|
}
|
|
|
|
//
|
|
// We attach the device to the list of devices in the PCB
|
|
// that the app uses - this is used for cleanup of the
|
|
// device dll data structures after the connection is done.
|
|
//
|
|
if (SUCCESS !=
|
|
(retcode = AddDeviceToDeviceList (ppcb, device)))
|
|
{
|
|
return retcode ;
|
|
}
|
|
|
|
//
|
|
// If another async request is pending this will return
|
|
// with an error.
|
|
//
|
|
if (ppcb->PCB_AsyncWorkerElement.WE_ReqType != REQTYPE_NONE)
|
|
{
|
|
RasmanTrace(
|
|
"Returning ERROR_ASYNC_REQUEST_PENDING for "
|
|
"reqtype %d",
|
|
ppcb->PCB_AsyncWorkerElement.WE_ReqType);
|
|
|
|
return ERROR_ASYNC_REQUEST_PENDING ;
|
|
}
|
|
|
|
//
|
|
// The appropriate device dll call is made here:
|
|
//
|
|
if (reqtype == REQTYPE_DEVICECONNECT)
|
|
{
|
|
retcode = DEVICECONNECT (device,
|
|
ppcb->PCB_PortFileHandle,
|
|
devicetype,
|
|
devicename);
|
|
|
|
SetPortConnState(__FILE__, __LINE__,
|
|
ppcb, CONNECTING);
|
|
|
|
ppcb->PCB_CurrentUsage |= CALL_OUT ;
|
|
|
|
ppcb->PCB_CurrentUsage &= ~CALL_IN;
|
|
}
|
|
else
|
|
{
|
|
retcode = DEVICELISTEN (device,
|
|
ppcb->PCB_PortFileHandle,
|
|
devicetype,
|
|
devicename);
|
|
|
|
SetPortConnState(__FILE__, __LINE__,
|
|
ppcb, LISTENING);
|
|
|
|
ppcb->PCB_CurrentUsage |= CALL_IN ;
|
|
|
|
ppcb->PCB_CurrentUsage &= ~CALL_OUT;
|
|
}
|
|
|
|
//
|
|
// Set some of this information unconditionally
|
|
//
|
|
ppcb->PCB_LastError = retcode ;
|
|
|
|
//ppcb->PCB_AsyncWorkerElement.WE_Notifier = handle ;
|
|
|
|
strcpy (ppcb->PCB_DeviceTypeConnecting,
|
|
devicetype) ;
|
|
|
|
strcpy (ppcb->PCB_DeviceConnecting,
|
|
devicename) ;
|
|
|
|
switch (retcode)
|
|
{
|
|
case PENDING:
|
|
//
|
|
// The connection attempt was successfully initiated:
|
|
// make sure that the async operation struct in the
|
|
// PCB is initialised.
|
|
//
|
|
SetPortAsyncReqType(__FILE__, __LINE__,
|
|
ppcb,
|
|
reqtype);
|
|
|
|
//
|
|
// Add this async request to the timer queue if a
|
|
// timeout is specified:
|
|
//
|
|
if ((timeout != INFINITE) && (timeout != 0))
|
|
{
|
|
RasmanTrace(
|
|
"Adding timeout of %d for listen",
|
|
timeout );
|
|
|
|
ppcb->PCB_AsyncWorkerElement.WE_TimeoutElement =
|
|
AddTimeoutElement (
|
|
(TIMERFUNC)ListenConnectTimeout,
|
|
ppcb,
|
|
NULL,
|
|
timeout
|
|
);
|
|
|
|
AdjustTimer();
|
|
|
|
}
|
|
break ;
|
|
|
|
|
|
case SUCCESS:
|
|
|
|
//
|
|
// This means that the connection attempt completed
|
|
// synchronously: We must signal the event passed in:
|
|
// so that the calling program can treat this like a
|
|
// real async completion. This is done when this
|
|
// function returns.
|
|
//
|
|
|
|
default:
|
|
|
|
//
|
|
// Some error occured - simply pass the error back to
|
|
// the app. We do not set the state to DISCONNECT(ED/ING)
|
|
// because we want the app to recover any information
|
|
// about this before explicitly discnnecting.
|
|
//
|
|
|
|
break ;
|
|
}
|
|
|
|
return retcode ;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cancels receives if they are pending
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful , FALSE otherwise
|
|
|
|
--*/
|
|
BOOL
|
|
CancelPendingReceive (pPCB ppcb)
|
|
{
|
|
DWORD bytesrecvd ;
|
|
|
|
//
|
|
// If any reads are pending with the Hub cancel them:
|
|
//
|
|
if (ppcb->PCB_AsyncWorkerElement.WE_ReqType
|
|
== REQTYPE_PORTRECEIVEHUB)
|
|
{
|
|
//
|
|
// Nothing to be done. The actual receives to
|
|
// the hub are left intact
|
|
//
|
|
}
|
|
else if (ppcb->PCB_AsyncWorkerElement.WE_ReqType
|
|
== REQTYPE_PORTRECEIVE)
|
|
{
|
|
PORTCOMPLETERECEIVE(ppcb->PCB_Media,
|
|
ppcb->PCB_PortIOHandle,
|
|
&bytesrecvd) ;
|
|
}
|
|
else
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
ppcb->PCB_BytesReceived = 0 ;
|
|
ppcb->PCB_PendingReceive = NULL ;
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cancels receives if they are pending
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
Return Value:
|
|
|
|
TRUE if receive was pending and was cancelled
|
|
FALSE if no receive was pending
|
|
|
|
--*/
|
|
BOOL
|
|
CancelPendingReceiveBuffers (pPCB ppcb)
|
|
{
|
|
DWORD bytesrecvd ;
|
|
|
|
//
|
|
// If any reads are pending with the Hub cancel them:
|
|
//
|
|
if (ppcb->PCB_AsyncWorkerElement.WE_ReqType
|
|
== REQTYPE_PORTRECEIVEHUB)
|
|
{
|
|
|
|
#if DBG
|
|
ASSERT(INVALID_HANDLE_VALUE != RasHubHandle);
|
|
#endif
|
|
DeviceIoControl (
|
|
RasHubHandle,
|
|
IOCTL_NDISWAN_FLUSH_RECEIVE_PACKETS,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&bytesrecvd,
|
|
NULL
|
|
);
|
|
}
|
|
else if (ppcb->PCB_AsyncWorkerElement.WE_ReqType
|
|
== REQTYPE_PORTRECEIVE)
|
|
{
|
|
PORTCOMPLETERECEIVE(ppcb->PCB_Media,
|
|
ppcb->PCB_PortIOHandle,
|
|
&bytesrecvd) ;
|
|
}
|
|
else
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
ppcb->PCB_BytesReceived = 0 ;
|
|
ppcb->PCB_PendingReceive = NULL ;
|
|
|
|
//
|
|
// Flush any complete receives pending on this port
|
|
//
|
|
FlushPcbReceivePackets(ppcb);
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs the action requested at disconnect time.
|
|
If any errors occur - then the action is simply
|
|
not performed.
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
hBundle
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID
|
|
PerformDisconnectAction (pPCB ppcb, HBUNDLE hBundle)
|
|
{
|
|
//
|
|
// Anything to be done?
|
|
//
|
|
if (0 ==
|
|
ppcb->PCB_DisconnectAction.DA_IPAddress)
|
|
{
|
|
//
|
|
// no, return
|
|
//
|
|
return ;
|
|
}
|
|
|
|
RasHelperResetDefaultInterfaceNetEx(
|
|
ppcb->PCB_DisconnectAction.DA_IPAddress,
|
|
ppcb->PCB_DisconnectAction.DA_Device,
|
|
ppcb->PCB_DisconnectAction.DA_fPrioritize,
|
|
ppcb->PCB_DisconnectAction.DA_DNSAddress,
|
|
ppcb->PCB_DisconnectAction.DA_DNS2Address,
|
|
ppcb->PCB_DisconnectAction.DA_WINSAddress,
|
|
ppcb->PCB_DisconnectAction.DA_WINS2Address
|
|
) ;
|
|
|
|
RasmanTrace(
|
|
"PerformDisconnectAction: fPrioritize=%d",
|
|
ppcb->PCB_DisconnectAction.DA_fPrioritize);
|
|
|
|
ppcb->PCB_DisconnectAction.DA_IPAddress = 0 ;
|
|
ppcb->PCB_DisconnectAction.DA_fPrioritize = FALSE;
|
|
|
|
//
|
|
// Auto-unroute IP for SLIP connections.
|
|
//
|
|
if (hBundle)
|
|
{
|
|
DeAllocateRouteRequestCommon(hBundle, IP);
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates a new bundle block for a port
|
|
if it doesn't already have one. It is
|
|
assumed the port is locked on entry.
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
Return Value:
|
|
|
|
mem alloc errors
|
|
|
|
--*/
|
|
DWORD
|
|
AllocBundle(
|
|
pPCB ppcb
|
|
)
|
|
{
|
|
ULONG ulNextBundle;
|
|
|
|
if (ppcb->PCB_Bundle != NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Allocate a bundle block and a bundle
|
|
// block lock.
|
|
//
|
|
ppcb->PCB_Bundle = (Bundle *)
|
|
LocalAlloc (LPTR,
|
|
sizeof(Bundle));
|
|
|
|
if (ppcb->PCB_Bundle == NULL)
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
//
|
|
// Save the bundle context for later use.
|
|
//
|
|
ppcb->PCB_LastBundle = ppcb->PCB_Bundle;
|
|
|
|
//
|
|
// Increment Bundle count
|
|
//
|
|
ppcb->PCB_Bundle->B_Count++;
|
|
|
|
ulNextBundle = HandleToUlong(NextBundleHandle);
|
|
|
|
//
|
|
// Bundle IDs stay above 0xff000000 to keep this ID
|
|
// range separate from HPORTs.
|
|
//
|
|
if (ulNextBundle < 0xff000000)
|
|
{
|
|
NextBundleHandle = (HBUNDLE) UlongToPtr(0xff000000);
|
|
ulNextBundle = 0xff000000;
|
|
}
|
|
|
|
ulNextBundle += 1;
|
|
|
|
NextBundleHandle = (HBUNDLE) UlongToPtr(ulNextBundle);
|
|
|
|
ppcb->PCB_Bundle->B_NdisHandle = INVALID_HANDLE_VALUE;
|
|
ppcb->PCB_Bundle->B_Handle = NextBundleHandle;
|
|
ppcb->PCB_Bundle->B_Bindings = ppcb->PCB_Bindings;
|
|
ppcb->PCB_Bindings = NULL;
|
|
|
|
//
|
|
// Add it to the list.
|
|
//
|
|
InsertTailList(&BundleList, &ppcb->PCB_Bundle->B_ListEntry);
|
|
|
|
RasmanTrace(
|
|
"AllocBundle: pBundle=0x%x\n",
|
|
ppcb->PCB_Bundle);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find a bundle in the BundleList given its handle.
|
|
|
|
Arguments:
|
|
|
|
hBundle
|
|
|
|
Return Value:
|
|
|
|
Bundle *
|
|
|
|
--*/
|
|
Bundle *
|
|
FindBundle(
|
|
HBUNDLE hBundle
|
|
)
|
|
{
|
|
PLIST_ENTRY pEntry;
|
|
Bundle *pBundle;
|
|
|
|
if (!IsListEmpty(&BundleList))
|
|
{
|
|
for (pEntry = BundleList.Flink;
|
|
pEntry != &BundleList;
|
|
pEntry = pEntry->Flink)
|
|
{
|
|
pBundle = CONTAINING_RECORD(pEntry, Bundle, B_ListEntry);
|
|
|
|
if (pBundle->B_Handle == hBundle)
|
|
{
|
|
return pBundle;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
VOID
|
|
FreeBapPackets()
|
|
{
|
|
RasmanBapPacket *pPacket;
|
|
|
|
if(NULL == BapBuffers)
|
|
{
|
|
return;
|
|
}
|
|
|
|
while(NULL != BapBuffers->pPacketList)
|
|
{
|
|
pPacket = BapBuffers->pPacketList;
|
|
BapBuffers->pPacketList = pPacket->Next;
|
|
|
|
LocalFree(pPacket);
|
|
}
|
|
|
|
LocalFree(BapBuffers);
|
|
|
|
BapBuffers = NULL;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free the bundle block passed in
|
|
|
|
Arguments:
|
|
|
|
pBundle
|
|
|
|
Return Value:
|
|
|
|
void
|
|
--*/
|
|
VOID
|
|
FreeBundle(
|
|
Bundle *pBundle
|
|
)
|
|
{
|
|
RasmanTrace(
|
|
"FreeBundle: freeing pBundle=0x%x",
|
|
pBundle);
|
|
|
|
RemoveEntryList(&pBundle->B_ListEntry);
|
|
|
|
LocalFree(pBundle);
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy a string
|
|
|
|
Arguments:
|
|
|
|
lpsz
|
|
|
|
Return Value:
|
|
|
|
address of new string if allocation
|
|
of the string succeeded, NULL otherwise
|
|
|
|
--*/
|
|
PCHAR
|
|
CopyString(
|
|
PCHAR lpsz
|
|
)
|
|
{
|
|
DWORD dwcb;
|
|
PCHAR lpszNew;
|
|
|
|
if (lpsz == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
dwcb = strlen(lpsz);
|
|
|
|
lpszNew = LocalAlloc(LPTR, dwcb + 1);
|
|
|
|
if (lpszNew == NULL)
|
|
{
|
|
// Do we need to do something else here?
|
|
return NULL;
|
|
}
|
|
|
|
strcpy(lpszNew, lpsz);
|
|
|
|
return lpszNew;
|
|
}
|
|
|
|
BOOL
|
|
fIsValidConnection(ConnectionBlock *pConn)
|
|
{
|
|
PLIST_ENTRY pEntry;
|
|
BOOL fReturn = FALSE;
|
|
ConnectionBlock *pConnT;
|
|
|
|
for(pEntry = ConnectionBlockList.Flink;
|
|
pEntry != &ConnectionBlockList;
|
|
pEntry = pEntry->Flink)
|
|
{
|
|
pConnT =
|
|
CONTAINING_RECORD(pEntry, ConnectionBlock, CB_ListEntry);
|
|
|
|
if(pConnT == pConn)
|
|
{
|
|
fReturn = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Clean up and free a connection block.
|
|
|
|
Arguments:
|
|
|
|
pConn
|
|
|
|
Return Value:
|
|
|
|
void
|
|
--*/
|
|
VOID
|
|
FreeConnection(
|
|
ConnectionBlock *pConn
|
|
)
|
|
{
|
|
PLIST_ENTRY pEntry;
|
|
ConnectionBlock *pConnT;
|
|
DWORD dwError;
|
|
BOOL fAutoClose = pConn->CB_fAutoClose;
|
|
|
|
RasmanTrace(
|
|
"FreeConnection: pConn=0x%x, %d",
|
|
pConn,
|
|
fAutoClose);
|
|
|
|
#if 0
|
|
//
|
|
// Zip through all the connections and check to
|
|
// see if any connection is referring to this
|
|
// connection. Bring down that connection too
|
|
// if it is so. TODO: This could be optimized
|
|
// by keeping an array of hconns in the prereq
|
|
// entry - doing this for now as do not expect a
|
|
// lot of simultaneous outgoing connections to make
|
|
// a big performance gain
|
|
//
|
|
for (pEntry = ConnectionBlockList.Flink;
|
|
pEntry != &ConnectionBlockList;
|
|
pEntry = pEntry->Flink)
|
|
{
|
|
pConnT =
|
|
CONTAINING_RECORD(pEntry, ConnectionBlock, CB_ListEntry);
|
|
|
|
if(pConnT->CB_ReferredEntry == pConn->CB_Handle)
|
|
{
|
|
|
|
RasmanTrace(
|
|
"FreeConnection: Closing 0x%08x as the "
|
|
"connection it was referring to(0x%08x) "
|
|
"went down",
|
|
pConnT->CB_Handle,
|
|
pConn->CB_Handle);
|
|
|
|
//
|
|
// In this case make sure that the connection
|
|
// is blown away
|
|
//
|
|
pConnT->CB_RefCount = 1;
|
|
|
|
if(!fAutoClose)
|
|
{
|
|
RasmanTrace("Removing redial flag on %x",
|
|
pConnT->CB_Handle);
|
|
pConnT->CB_ConnectionParams.CP_ConnectionFlags &=
|
|
~(CONNECTION_REDIALONLINKFAILURE);
|
|
}
|
|
|
|
dwError = DwCloseConnection(pConnT->CB_Handle);
|
|
|
|
RasmanTrace(
|
|
"FreeConnection: DwCloseConnection returned %d",
|
|
dwError);
|
|
|
|
//
|
|
// Check to see if the connection is still valid
|
|
//
|
|
if(fIsValidConnection(pConnT))
|
|
{
|
|
RasmanTrace(
|
|
"pConn 0x%x still valid ",
|
|
pConnT);
|
|
//
|
|
// Null out the prereq connection. We don't want to
|
|
// try freeing this connection when freeconnection
|
|
// is called for pConnT
|
|
//
|
|
pConnT->CB_ReferredEntry = 0;
|
|
}
|
|
else
|
|
{
|
|
RasmanTrace(
|
|
"pConn 0x%x not valid anymore",
|
|
pConnT);
|
|
|
|
pEntry = ConnectionBlockList.Flink;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Allocate and q a request to de-reference a referredentry if
|
|
// one is present. Do this only if the vpn-connection is being
|
|
// remotely disconnected. Otherwise the client will disconnect
|
|
// the port.
|
|
//
|
|
if( (fAutoClose)
|
|
&& (NULL != pConn->CB_ReferredEntry))
|
|
{
|
|
RAS_OVERLAPPED *pOverlapped = NULL;
|
|
ConnectionBlock *pConnReferred =
|
|
FindConnection(pConn->CB_ReferredEntry);
|
|
|
|
if(NULL != pConnReferred)
|
|
{
|
|
//
|
|
// Don't do a redial if this is not a client
|
|
// disconnect. The Vpn connection will cause
|
|
// the inner connection to redial so no need
|
|
// to redial explicitly.
|
|
//
|
|
|
|
RasmanTrace(
|
|
"Removing redial flag on %x",
|
|
pConnReferred->CB_Handle);
|
|
|
|
pConnReferred->CB_ConnectionParams.CP_ConnectionFlags &=
|
|
~(CONNECTION_REDIALONLINKFAILURE);
|
|
}
|
|
|
|
pOverlapped = LocalAlloc(
|
|
LPTR,
|
|
sizeof(RAS_OVERLAPPED));
|
|
|
|
if(NULL != pOverlapped)
|
|
{
|
|
pOverlapped->RO_EventType =
|
|
OVEVT_RASMAN_DEFERRED_CLOSE_CONNECTION;
|
|
|
|
pOverlapped->RO_hInfo = pConn->CB_ReferredEntry;
|
|
|
|
if (!PostQueuedCompletionStatus(
|
|
hIoCompletionPort,
|
|
0,0,
|
|
(LPOVERLAPPED)
|
|
pOverlapped))
|
|
{
|
|
RasmanTrace(
|
|
"FreeConnection: failed to post completion"
|
|
" status. GLE=0%x", GetLastError());
|
|
|
|
LocalFree(pOverlapped);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RasmanTrace(
|
|
"FreeConnection: Failed to allocate overlapped"
|
|
" GLE=0x%x",
|
|
GetLastError());
|
|
}
|
|
}
|
|
|
|
CloseHandle(pConn->CB_Process);
|
|
|
|
FreeUserData(&pConn->CB_UserData);
|
|
|
|
FreeNotifierList(&pConn->CB_NotifierList);
|
|
|
|
if (pConn->CB_PortHandles != NULL)
|
|
{
|
|
LocalFree(pConn->CB_PortHandles);
|
|
}
|
|
|
|
RemoveEntryList(&pConn->CB_ListEntry);
|
|
|
|
LocalFree(pConn);
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieve a tagged user data object from a list.
|
|
|
|
Arguments:
|
|
|
|
pList
|
|
|
|
dwTag
|
|
|
|
Return Value:
|
|
|
|
UserData *
|
|
|
|
--*/
|
|
UserData *
|
|
GetUserData(
|
|
PLIST_ENTRY pList,
|
|
DWORD dwTag
|
|
)
|
|
{
|
|
PLIST_ENTRY pEntry;
|
|
UserData *pUserData;
|
|
|
|
//
|
|
// Enumerate the list looking for a tag match.
|
|
//
|
|
for (pEntry = pList->Flink;
|
|
pEntry != pList;
|
|
pEntry = pEntry->Flink)
|
|
{
|
|
pUserData =
|
|
CONTAINING_RECORD(pEntry, UserData, UD_ListEntry);
|
|
|
|
if (pUserData->UD_Tag == dwTag)
|
|
{
|
|
return pUserData;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Store a tagged user data object in a list.
|
|
|
|
Arguments:
|
|
|
|
pList
|
|
|
|
dwTag
|
|
|
|
pBuf
|
|
|
|
dwcbBuf
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID
|
|
SetUserData(
|
|
PLIST_ENTRY pList,
|
|
DWORD dwTag,
|
|
PBYTE pBuf,
|
|
DWORD dwcbBuf
|
|
)
|
|
{
|
|
UserData *pUserData;
|
|
|
|
//
|
|
// Check to see if the object already exists.
|
|
//
|
|
pUserData = GetUserData(pList, dwTag);
|
|
//
|
|
// If it does, delete it from the list.
|
|
//
|
|
if (pUserData != NULL)
|
|
{
|
|
RemoveEntryList(&pUserData->UD_ListEntry);
|
|
LocalFree(pUserData);
|
|
}
|
|
|
|
//
|
|
// Add the new value back to the list if
|
|
// necessary.
|
|
//
|
|
if (pBuf != NULL)
|
|
{
|
|
pUserData = LocalAlloc(
|
|
LPTR,
|
|
sizeof (UserData) + dwcbBuf);
|
|
if (pUserData == NULL)
|
|
{
|
|
RasmanTrace(
|
|
"SetUserData: LocalAlloc failed");
|
|
|
|
return;
|
|
}
|
|
pUserData->UD_Tag = dwTag;
|
|
|
|
pUserData->UD_Length = dwcbBuf;
|
|
|
|
memcpy(&pUserData->UD_Data, pBuf, dwcbBuf);
|
|
|
|
InsertTailList(pList, &pUserData->UD_ListEntry);
|
|
}
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free the user data list
|
|
|
|
Arguments:
|
|
|
|
pList
|
|
|
|
Return Value:
|
|
|
|
void
|
|
--*/
|
|
VOID
|
|
FreeUserData(
|
|
PLIST_ENTRY pList
|
|
)
|
|
{
|
|
PLIST_ENTRY pEntry;
|
|
UserData *pUserData;
|
|
|
|
//
|
|
// Enumerate the list freeing each object.
|
|
//
|
|
while (!IsListEmpty(pList))
|
|
{
|
|
pEntry = RemoveHeadList(pList);
|
|
|
|
pUserData =
|
|
CONTAINING_RECORD(pEntry, UserData, UD_ListEntry);
|
|
|
|
LocalFree(pUserData);
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Look up connection by id
|
|
|
|
Arguments:
|
|
|
|
hconn
|
|
|
|
Return Value:
|
|
|
|
A pointer to the connection if successful,
|
|
NULL otherwise.
|
|
|
|
--*/
|
|
ConnectionBlock *
|
|
FindConnection(
|
|
HCONN hconn
|
|
)
|
|
{
|
|
PLIST_ENTRY pEntry;
|
|
ConnectionBlock *pConn;
|
|
|
|
for (pEntry = ConnectionBlockList.Flink;
|
|
pEntry != &ConnectionBlockList;
|
|
pEntry = pEntry->Flink)
|
|
{
|
|
pConn =
|
|
CONTAINING_RECORD(pEntry, ConnectionBlock, CB_ListEntry);
|
|
|
|
if (pConn->CB_Handle == hconn)
|
|
{
|
|
return pConn;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free a connection block that has no connected ports.
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
pConn
|
|
|
|
fOwnerClose
|
|
|
|
Return Value:
|
|
|
|
void
|
|
--*/
|
|
VOID
|
|
RemoveConnectionPort(
|
|
pPCB ppcb,
|
|
ConnectionBlock *pConn,
|
|
BOOLEAN fOwnerClose
|
|
)
|
|
{
|
|
if (pConn == NULL)
|
|
{
|
|
RasmanTrace(
|
|
"RemoveConnectionPort:pConn==NULL");
|
|
return;
|
|
}
|
|
|
|
if(0 != pConn->CB_Ports)
|
|
{
|
|
pConn->CB_Ports--;
|
|
}
|
|
|
|
RasmanTrace(
|
|
|
|
"RemoveConnectionPort: port %d, fOwnerClose=%d, "
|
|
"pConn=0x%x, pConn->CB_Ports=%d\n",
|
|
ppcb->PCB_PortHandle,
|
|
fOwnerClose,
|
|
pConn,
|
|
pConn->CB_Ports);
|
|
|
|
if(NULL != pConn->CB_PortHandles)
|
|
{
|
|
//
|
|
// Remove the port from the connection.
|
|
//
|
|
pConn->CB_PortHandles[ppcb->PCB_SubEntry - 1] = NULL;
|
|
}
|
|
|
|
//
|
|
// If there are not any other ports
|
|
// in the connection, then signal that
|
|
// it's closed and free the connection
|
|
// only if one of the following conditions
|
|
// is true:
|
|
// 1. If the refcount on the connection is 0
|
|
// i.e every RasDial has been matched by
|
|
// a RasHangUp
|
|
// 2. if the last port in the connection was
|
|
// remotely disconnected.
|
|
//
|
|
if ( (0 == pConn->CB_Ports)
|
|
&& ( 0 == pConn->CB_RefCount
|
|
|| ppcb->PCB_AutoClose))
|
|
{
|
|
DWORD dwErr;
|
|
|
|
SignalNotifiers(pConn->CB_NotifierList,
|
|
NOTIF_DISCONNECT,
|
|
0);
|
|
|
|
SignalNotifiers(pConnectionNotifierList,
|
|
NOTIF_DISCONNECT,
|
|
0);
|
|
|
|
#if SENS_ENABLED
|
|
dwErr = SendSensNotification(
|
|
SENS_NOTIFY_RAS_DISCONNECT,
|
|
(HRASCONN) pConn->CB_Handle);
|
|
|
|
RasmanTrace(
|
|
|
|
"SendSensNotification(_RAS_DISCONNECT) for "
|
|
"0x%08x returns 0x%08x",
|
|
pConn->CB_Handle,
|
|
dwErr);
|
|
|
|
#endif
|
|
|
|
g_RasEvent.Type = ENTRY_DISCONNECTED;
|
|
|
|
dwErr = DwSendNotificationInternal(
|
|
pConn, &g_RasEvent);
|
|
|
|
RasmanTrace(
|
|
"DwSendNotificationInternal(ENTRY_DISCONNECTED) rc=0x%x",
|
|
dwErr);
|
|
|
|
RasmanTrace(
|
|
"RemoveConnectionPort: FreeConnection "
|
|
"hconn=0x%x, pconn=0x%x, AutoClose=%d",
|
|
pConn->CB_Handle,
|
|
pConn,
|
|
ppcb->PCB_AutoClose);
|
|
|
|
pConn->CB_fAutoClose = ppcb->PCB_AutoClose;
|
|
|
|
FreeConnection(pConn);
|
|
|
|
ppcb->PCB_Connection = NULL;
|
|
|
|
pConn = NULL;
|
|
|
|
}
|
|
else if ( 0 != pConn->CB_Ports
|
|
&& NULL != ppcb->PCB_Bundle
|
|
&& ppcb->PCB_Bundle->B_Count)
|
|
{
|
|
DWORD retcode;
|
|
|
|
RasmanTrace(
|
|
"RemoveConnectionPort: Notifying BANDWIDTHREMOVED"
|
|
" for port %s. Bundle 0x%x",
|
|
ppcb->PCB_Name,
|
|
ppcb->PCB_Bundle);
|
|
|
|
SignalNotifiers(
|
|
pConn->CB_NotifierList,
|
|
NOTIF_BANDWIDTHREMOVED,
|
|
0);
|
|
|
|
SignalNotifiers(
|
|
pConnectionNotifierList,
|
|
NOTIF_BANDWIDTHREMOVED,
|
|
0);
|
|
|
|
g_RasEvent.Type = ENTRY_BANDWIDTH_REMOVED;
|
|
|
|
retcode = DwSendNotificationInternal(pConn, &g_RasEvent);
|
|
|
|
RasmanTrace(
|
|
"DwSendNotificationInternal(ENTRY_BANDWIDTH_REMOVED)"
|
|
" rc=0x%08x",
|
|
retcode);
|
|
|
|
}
|
|
|
|
if( pConn
|
|
&& 0 == pConn->CB_Ports)
|
|
{
|
|
RasmanTrace(
|
|
"Connection not freed for 0x%x! "
|
|
"CB_Ports=%d, CB_Ref=%d",
|
|
pConn->CB_Handle,
|
|
pConn->CB_Ports,
|
|
pConn->CB_RefCount);
|
|
}
|
|
|
|
ppcb->PCB_Bundle = ( Bundle * ) NULL;
|
|
}
|
|
|
|
DWORD
|
|
DwProcessPppFailureMessage(pPCB ppcb)
|
|
{
|
|
DWORD dwErr = SUCCESS;
|
|
|
|
if(0 == (ppcb->PCB_RasmanReceiveFlags & RECEIVE_PPPSTARTED))
|
|
{
|
|
RasmanTrace(
|
|
"DwProcessPppFailureMessage: PPP called to "
|
|
"disconnect even though it hadn't started!! port %d",
|
|
ppcb->PCB_PortHandle);
|
|
|
|
goto done;
|
|
}
|
|
|
|
RasmanTrace(
|
|
"DwProcessPppFailureMessage: disconnecting %s,"
|
|
"hEventClientDisconnect=0x%x",
|
|
ppcb->PCB_Name,
|
|
ppcb->PCB_hEventClientDisconnect);
|
|
|
|
if( (INVALID_HANDLE_VALUE !=
|
|
ppcb->PCB_hEventClientDisconnect)
|
|
&& (NULL !=
|
|
ppcb->PCB_hEventClientDisconnect))
|
|
{
|
|
RasmanTrace(
|
|
"DwProcessPppFailureMessage: Not autoclosing %s",
|
|
ppcb->PCB_Name);
|
|
}
|
|
else
|
|
{
|
|
ppcb->PCB_AutoClose = TRUE;
|
|
}
|
|
|
|
ppcb->PCB_RasmanReceiveFlags |= RECEIVE_PPPSTOPPED;
|
|
|
|
dwErr = DisconnectPort(
|
|
ppcb,
|
|
ppcb->PCB_hEventClientDisconnect,
|
|
USER_REQUESTED);
|
|
|
|
ppcb->PCB_hEventClientDisconnect = INVALID_HANDLE_VALUE;
|
|
|
|
done:
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
VOID
|
|
ReverseString(
|
|
CHAR* psz )
|
|
|
|
/* Reverses order of characters in 'psz'.
|
|
*/
|
|
{
|
|
CHAR* pszBegin;
|
|
CHAR* pszEnd;
|
|
|
|
for (pszBegin = psz, pszEnd = psz + strlen( psz ) - 1;
|
|
pszBegin < pszEnd;
|
|
++pszBegin, --pszEnd)
|
|
{
|
|
CHAR ch = *pszBegin;
|
|
*pszBegin = *pszEnd;
|
|
*pszEnd = ch;
|
|
}
|
|
}
|
|
|
|
CHAR*
|
|
EncodePw(
|
|
IN OUT CHAR* pszPassword )
|
|
|
|
/* Obfuscate 'pszPassword' in place to foil memory scans for passwords.
|
|
**
|
|
** Returns the address of 'pszPassword'.
|
|
*/
|
|
{
|
|
if (pszPassword)
|
|
{
|
|
CHAR* psz;
|
|
|
|
ReverseString( pszPassword );
|
|
|
|
for (psz = pszPassword; *psz != '\0'; ++psz)
|
|
{
|
|
if (*psz != PASSWORDMAGIC)
|
|
*psz ^= PASSWORDMAGIC;
|
|
}
|
|
}
|
|
|
|
return pszPassword;
|
|
}
|
|
|
|
|
|
CHAR*
|
|
DecodePw(
|
|
IN OUT CHAR* pszPassword )
|
|
|
|
/* Un-obfuscate 'pszPassword' in place.
|
|
**
|
|
** Returns the address of 'pszPassword'.
|
|
*/
|
|
{
|
|
return EncodePw( pszPassword );
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Will receive the PPP_MESSAGE from RASPPP and tag
|
|
into the PCB structure for the appropriate port.
|
|
|
|
Arguments:
|
|
|
|
pPppMsg
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
DWORD
|
|
SendPPPMessageToRasman( PPP_MESSAGE * pPppMsg )
|
|
{
|
|
PPP_MESSAGE * pPppMessage = NULL;
|
|
DWORD dwErr = SUCCESS;
|
|
|
|
PCB *ppcb = GetPortByHandle(pPppMsg->hPort);
|
|
|
|
if (NULL == ppcb)
|
|
{
|
|
dwErr = ERROR_INVALID_HANDLE;
|
|
goto done;
|
|
}
|
|
|
|
RasmanTrace("sendpppmessagetorasman: msgid=%d",
|
|
pPppMsg->dwMsgId);
|
|
|
|
if (ppcb->PCB_ConnState != CONNECTED)
|
|
{
|
|
if( (ppcb->PCB_ConnState != LISTENING)
|
|
|| (PPPMSG_PppFailure == pPppMsg->dwMsgId))
|
|
{
|
|
RasmanTrace(
|
|
"SendPPPMessageToRasman: disconnecting port. state=%d",
|
|
ppcb->PCB_ConnState);
|
|
|
|
ppcb->PCB_fRedial = FALSE;
|
|
dwErr = DwProcessPppFailureMessage(ppcb);
|
|
}
|
|
else
|
|
{
|
|
RasmanTrace(
|
|
|
|
"SendPPPMessageToRasman: ignoring %d on port %d since ports"
|
|
" listening",
|
|
pPppMsg->dwMsgId,
|
|
ppcb->PCB_PortHandle);
|
|
}
|
|
|
|
goto done;
|
|
}
|
|
|
|
if (NULL ==
|
|
(pPppMessage = LocalAlloc(LPTR,
|
|
sizeof( PPP_MESSAGE))))
|
|
{
|
|
dwErr = GetLastError();
|
|
goto done;
|
|
}
|
|
|
|
*pPppMessage = *pPppMsg;
|
|
|
|
|
|
if(PPPMSG_InvokeEapUI == pPppMessage->dwMsgId)
|
|
{
|
|
RasmanTrace(
|
|
"SendPPPMessageToRasman: Queueing pppmessage "
|
|
"with ID=InvokeEapUI for port %s",
|
|
ppcb->PCB_Name);
|
|
}
|
|
|
|
if( (PPPMSG_PppFailure == pPppMessage->dwMsgId)
|
|
&& (ERROR_SUCCESS != pPppMessage->ExtraInfo.Failure.dwError))
|
|
{
|
|
RasmanTrace(
|
|
"Setting last error for port %s to ppp error 0x%x",
|
|
ppcb->PCB_Name,
|
|
pPppMessage->ExtraInfo.Failure.dwError);
|
|
|
|
ppcb->PCB_LastError = pPppMessage->ExtraInfo.Failure.dwError;
|
|
}
|
|
|
|
|
|
if(PPPMSG_SetCustomAuthData == pPppMessage->dwMsgId)
|
|
{
|
|
PPP_SET_CUSTOM_AUTH_DATA * pData =
|
|
&pPppMessage->ExtraInfo.SetCustomAuthData;
|
|
|
|
//
|
|
// Save the auth data that ppp sent to rasman in ppcb.
|
|
// Note that if this message is sent multiple times
|
|
// then the last writer wins - there is only one field
|
|
// in the phonebook to save this value. If memory alloc
|
|
// fails this will fail to save the information - which
|
|
// is not fatal - the worst case scenario is that rasdial
|
|
// will popup the ui to get the information again.
|
|
//
|
|
if( (0 != pData->dwSizeOfConnectionData)
|
|
&& (NULL != pData->pConnectionData))
|
|
{
|
|
SetUserData(
|
|
&ppcb->PCB_UserData,
|
|
PORT_CUSTOMAUTHDATA_INDEX,
|
|
(PBYTE) pData->pConnectionData,
|
|
pData->dwSizeOfConnectionData);
|
|
}
|
|
}
|
|
|
|
if(PPPMSG_ProjectionResult == pPppMessage->dwMsgId)
|
|
{
|
|
CHAR *pszReplyMessage =
|
|
pPppMessage->ExtraInfo.ProjectionResult.lcp.szReplyMessage;
|
|
|
|
//
|
|
// If we haven't saved already , save the reply
|
|
// message in the connection block.
|
|
//
|
|
if( (NULL != ppcb->PCB_Connection)
|
|
&& (NULL != pszReplyMessage))
|
|
{
|
|
|
|
if(NULL == GetUserData(
|
|
&ppcb->PCB_Connection->CB_UserData,
|
|
CONNECTION_PPPREPLYMESSAGE_INDEX))
|
|
{
|
|
//
|
|
// Allocate and store the message in the
|
|
// connection block
|
|
//
|
|
SetUserData(
|
|
&ppcb->PCB_Connection->CB_UserData,
|
|
CONNECTION_PPPREPLYMESSAGE_INDEX,
|
|
(PBYTE) pszReplyMessage,
|
|
strlen(pszReplyMessage) + 1);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if(PPPMSG_ChangePwRequest == pPppMessage->dwMsgId)
|
|
{
|
|
CHAR szPwd[PWLEN+1];
|
|
DWORD retcode;
|
|
|
|
//
|
|
// Retrieve the password from lsa, encode it
|
|
// and save it in the pcb. This will be used
|
|
// when PppChangePwd is called.
|
|
//
|
|
retcode = DwGetPassword(ppcb, szPwd, GetCurrentProcessId());
|
|
|
|
if(ERROR_SUCCESS == dwErr)
|
|
{
|
|
EncodePw(szPwd);
|
|
|
|
SetUserData(
|
|
&ppcb->PCB_UserData,
|
|
PORT_OLDPASSWORD_INDEX,
|
|
(PBYTE) szPwd,
|
|
sizeof(szPwd));
|
|
|
|
ZeroMemory(szPwd, sizeof(szPwd));
|
|
}
|
|
}
|
|
|
|
if(PPPMSG_Stopped == pPppMessage->dwMsgId)
|
|
{
|
|
RasmanTrace(
|
|
"PPPMSG_Stopped. dwError=0x%x",
|
|
pPppMessage->dwError);
|
|
|
|
if(ERROR_SUCCESS != pPppMessage->dwError)
|
|
{
|
|
RasmanTrace(
|
|
"setting error to %d",
|
|
pPppMessage->dwError);
|
|
ppcb->PCB_LastError = pPppMessage->dwError;
|
|
}
|
|
|
|
if(pPppMessage->ExtraInfo.Stopped.dwFlags &
|
|
PPP_FAILURE_REMOTE_DISCONNECT)
|
|
{
|
|
ppcb->PCB_fRedial = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ppcb->PCB_fRedial = FALSE;
|
|
}
|
|
|
|
dwErr = DwProcessPppFailureMessage(ppcb);
|
|
|
|
LocalFree(pPppMessage);
|
|
|
|
}
|
|
else
|
|
{
|
|
if (ppcb->PCB_PppQTail == NULL)
|
|
{
|
|
ppcb->PCB_PppQHead = pPppMessage;
|
|
}
|
|
else
|
|
{
|
|
ppcb->PCB_PppQTail->pNext = pPppMessage;
|
|
}
|
|
|
|
ppcb->PCB_PppQTail = pPppMessage;
|
|
ppcb->PCB_PppQTail->pNext = NULL;
|
|
|
|
SetPppEvent(ppcb);
|
|
}
|
|
|
|
done:
|
|
return dwErr;
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sets the pcb's ppp event and
|
|
posts a queued completion status packet,
|
|
if necessary.
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
Return Value:
|
|
|
|
void
|
|
--*/
|
|
VOID
|
|
SetPppEvent(
|
|
pPCB ppcb
|
|
)
|
|
{
|
|
SetEvent(ppcb->PCB_PppEvent);
|
|
|
|
if (ppcb->PCB_IoCompletionPort != INVALID_HANDLE_VALUE)
|
|
{
|
|
RasmanTrace(
|
|
|
|
"SetPppEvent: pOverlapped=0x%x",
|
|
ppcb->PCB_OvPpp);
|
|
|
|
PostQueuedCompletionStatus(
|
|
ppcb->PCB_IoCompletionPort,
|
|
0,
|
|
0,
|
|
ppcb->PCB_OvPpp);
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function flushes any receive packets that
|
|
are queue on a pcb.
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID
|
|
FlushPcbReceivePackets(
|
|
pPCB ppcb
|
|
)
|
|
{
|
|
RasmanPacket *Packet;
|
|
|
|
while (ppcb->PCB_RecvPackets != NULL)
|
|
{
|
|
|
|
GetRecvPacketFromPcb(ppcb, &Packet);
|
|
|
|
//PutRecvPacketOnFreeList(Packet);
|
|
//
|
|
// The packets on pcb are local alloc'd
|
|
// Local Free them
|
|
//
|
|
LocalFree( Packet );
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a wrapper to trace the port state
|
|
transitions.
|
|
|
|
Arguments:
|
|
|
|
pszFile
|
|
|
|
nLine
|
|
|
|
ppcb
|
|
|
|
state
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID
|
|
SetPortConnState(
|
|
PCHAR pszFile,
|
|
INT nLine,
|
|
pPCB ppcb,
|
|
RASMAN_STATE state
|
|
)
|
|
{
|
|
RasmanTrace(
|
|
"%s: %d: port %d state chg: prev=%d, new=%d",
|
|
pszFile,
|
|
nLine,
|
|
ppcb->PCB_PortHandle,
|
|
ppcb->PCB_ConnState,
|
|
state);
|
|
|
|
ppcb->PCB_ConnState = state;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a wrapper to trace the async worker
|
|
element type state transitions.
|
|
|
|
Arguments:
|
|
|
|
pszFile
|
|
|
|
nLine
|
|
|
|
ppcb
|
|
|
|
reqtype
|
|
|
|
Return Value:
|
|
|
|
void
|
|
--*/
|
|
VOID
|
|
SetPortAsyncReqType(
|
|
PCHAR pszFile,
|
|
INT nLine,
|
|
pPCB ppcb,
|
|
ReqTypes reqtype
|
|
)
|
|
{
|
|
RasmanTrace(
|
|
"%s: %d: port %d async reqtype chg: prev=%d, new=%d",
|
|
pszFile,
|
|
nLine,
|
|
ppcb->PCB_PortHandle,
|
|
ppcb->PCB_AsyncWorkerElement.WE_ReqType,
|
|
reqtype);
|
|
|
|
ppcb->PCB_AsyncWorkerElement.WE_ReqType = reqtype;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the I/O completion port associated with a port.
|
|
|
|
Arguments:
|
|
|
|
ppcb
|
|
|
|
hIoCompletionPort
|
|
|
|
lpDrop
|
|
|
|
lpStateChange
|
|
|
|
lpPpp
|
|
|
|
lpLast
|
|
|
|
fPost
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID
|
|
SetIoCompletionPortCommon(
|
|
pPCB ppcb,
|
|
HANDLE hIoCompletionPort,
|
|
LPOVERLAPPED lpDrop,
|
|
LPOVERLAPPED lpStateChange,
|
|
LPOVERLAPPED lpPpp,
|
|
LPOVERLAPPED lpLast,
|
|
BOOL fPost
|
|
)
|
|
{
|
|
if ( INVALID_HANDLE_VALUE != ppcb->PCB_IoCompletionPort
|
|
&& INVALID_HANDLE_VALUE == hIoCompletionPort)
|
|
{
|
|
//
|
|
// If we invalidate an I/O completion port, post one
|
|
// last message to inform rasapi32 that there will
|
|
// be no more events on this port.
|
|
//
|
|
if (fPost)
|
|
{
|
|
RasmanTrace(
|
|
|
|
"SetIoCompletionPortCommon: posting last event for port %d",
|
|
ppcb->PCB_PortHandle);
|
|
|
|
PostQueuedCompletionStatus(
|
|
ppcb->PCB_IoCompletionPort,
|
|
0,
|
|
0,
|
|
ppcb->PCB_OvLast);
|
|
}
|
|
|
|
CloseHandle(ppcb->PCB_IoCompletionPort);
|
|
ppcb->PCB_IoCompletionPort = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (hIoCompletionPort != INVALID_HANDLE_VALUE)
|
|
{
|
|
ppcb->PCB_IoCompletionPort = hIoCompletionPort;
|
|
ppcb->PCB_OvDrop = lpDrop;
|
|
ppcb->PCB_OvStateChange = lpStateChange;
|
|
ppcb->PCB_OvPpp = lpPpp;
|
|
ppcb->PCB_OvLast = lpLast;
|
|
}
|
|
else
|
|
{
|
|
ppcb->PCB_OvDrop = NULL;
|
|
ppcb->PCB_OvStateChange = NULL;
|
|
ppcb->PCB_OvPpp = NULL;
|
|
ppcb->PCB_OvLast = NULL;
|
|
}
|
|
}
|
|
|
|
#if SENS_ENABLED
|
|
|
|
DWORD
|
|
SendSensNotification(DWORD dwFlags, HRASCONN hRasConn)
|
|
{
|
|
SENS_NOTIFY_RAS sensNotification =
|
|
{
|
|
dwFlags,
|
|
(SENS_HRASCONN) (HandleToUlong(hRasConn))
|
|
};
|
|
|
|
return SensNotifyRasEvent(&sensNotification);
|
|
}
|
|
|
|
VOID
|
|
AdjustTimer(void)
|
|
{
|
|
|
|
if (!PostQueuedCompletionStatus(
|
|
hIoCompletionPort,
|
|
0,0,
|
|
(LPOVERLAPPED)
|
|
&RO_RasAdjustTimerEvent))
|
|
{
|
|
RasmanTrace(
|
|
|
|
"%s, %d: Failed to post "
|
|
"close event. GLE = %d",
|
|
__FILE__,
|
|
__LINE__,
|
|
GetLastError());
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if ENABLE_POWER
|
|
|
|
BOOL
|
|
fAnyConnectedPorts()
|
|
{
|
|
ULONG i;
|
|
pPCB ppcb;
|
|
BOOL fRet = FALSE;
|
|
|
|
for (i = 0; i < MaxPorts; i++)
|
|
{
|
|
ppcb = GetPortByHandle((HPORT) UlongToPtr(i));
|
|
|
|
if (ppcb != NULL)
|
|
{
|
|
if( (LISTENING != ppcb->PCB_ConnState)
|
|
&& (CLOSED != ppcb->PCB_PortStatus)
|
|
&& (REMOVED != ppcb->PCB_PortStatus)
|
|
&& (UNAVAILABLE != ppcb->PCB_PortStatus))
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
RasmanTrace(
|
|
"fAnyConnectedPorts: %d",
|
|
fRet);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
VOID
|
|
DropAllActiveConnections()
|
|
{
|
|
ULONG i;
|
|
pPCB ppcb;
|
|
|
|
RasmanTrace(
|
|
"Dropping All ActiveConnections as a result of"
|
|
" Hibernate Event");
|
|
|
|
for( i = 0; i < MaxPorts; i++)
|
|
{
|
|
ppcb = GetPortByHandle((HPORT) UlongToPtr(i));
|
|
|
|
if(ppcb != NULL)
|
|
{
|
|
if( (LISTENING != ppcb->PCB_ConnState)
|
|
&& (CLOSED != ppcb->PCB_PortStatus)
|
|
&& (REMOVED != ppcb->PCB_PortStatus)
|
|
&& (UNAVAILABLE != ppcb->PCB_PortStatus))
|
|
{
|
|
RasmanTrace(
|
|
"DropAllActiveConnections: Dropping connection"
|
|
" on port %s as a result of Hibernate Event",
|
|
ppcb->PCB_Name);
|
|
|
|
//
|
|
// Disconnect the port and autoclose the port
|
|
//
|
|
ppcb->PCB_AutoClose = TRUE;
|
|
|
|
DisconnectPort(ppcb,
|
|
INVALID_HANDLE_VALUE,
|
|
USER_REQUESTED);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
DWORD
|
|
DwSendNotificationInternal(ConnectionBlock *pConn, RASEVENT *pEvent)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
switch (pEvent->Type)
|
|
{
|
|
|
|
case ENTRY_CONNECTING:
|
|
case ENTRY_CONNECTED:
|
|
case ENTRY_DISCONNECTING:
|
|
case ENTRY_DISCONNECTED:
|
|
{
|
|
|
|
//
|
|
// Fill in RASENUMENTRYDETAILS structure with whatever
|
|
// information we have.
|
|
//
|
|
WCHAR *pwszPhonebook = NULL;
|
|
WCHAR *pwszPhoneEntry = NULL;
|
|
|
|
if(NULL == pConn)
|
|
{
|
|
RasmanTrace("DwSendNotificationInternal: NULL pConn");
|
|
dwErr = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
|
|
pEvent->Details.dwSize = sizeof(RASENUMENTRYDETAILS);
|
|
|
|
pwszPhonebook = StrdupAtoW(pConn->CB_ConnectionParams.CP_Phonebook);
|
|
pwszPhoneEntry = StrdupAtoW(pConn->CB_ConnectionParams.CP_PhoneEntry);
|
|
|
|
if(NULL != pwszPhonebook)
|
|
{
|
|
wcsncpy(pEvent->Details.szPhonebookPath,
|
|
pwszPhonebook,
|
|
MAX_PATH);
|
|
|
|
LocalFree(pwszPhonebook);
|
|
}
|
|
|
|
if(NULL != pwszPhoneEntry)
|
|
{
|
|
wcsncpy(pEvent->Details.szEntryName,
|
|
pwszPhoneEntry,
|
|
RASAPIP_MAX_ENTRY_NAME);
|
|
|
|
LocalFree(pwszPhoneEntry);
|
|
}
|
|
|
|
pEvent->Details.guidId = pConn->CB_GuidEntry;
|
|
|
|
break;
|
|
}
|
|
|
|
case ENTRY_BANDWIDTH_ADDED:
|
|
case ENTRY_BANDWIDTH_REMOVED:
|
|
{
|
|
if(NULL == pConn)
|
|
{
|
|
RasmanTrace("DwSendNotificationInternal: NULL pConn");
|
|
dwErr = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Fill in guidId field
|
|
//
|
|
pEvent->guidId = pConn->CB_GuidEntry;
|
|
break;
|
|
}
|
|
|
|
case SERVICE_EVENT:
|
|
case DEVICE_REMOVED:
|
|
case DEVICE_ADDED:
|
|
{
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwErr = DwSendNotification(pEvent);
|
|
|
|
done:
|
|
return dwErr;
|
|
}
|
|
|
|
DWORD
|
|
DwSendNotification(RASEVENT *pEvent)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
HINSTANCE hInst = NULL;
|
|
|
|
if(NULL != GetModuleHandle("netman.dll"))
|
|
{
|
|
RASEVENTNOTIFYPROC pfnNotify;
|
|
|
|
hInst = LoadLibrary("netman.dll");
|
|
|
|
if(NULL == hInst)
|
|
{
|
|
dwErr = GetLastError();
|
|
goto done;
|
|
}
|
|
|
|
pfnNotify = (RASEVENTNOTIFYPROC)
|
|
GetProcAddress(hInst, "RasEventNotify");
|
|
|
|
if(NULL == pfnNotify)
|
|
{
|
|
dwErr = GetLastError();
|
|
goto done;
|
|
}
|
|
|
|
pfnNotify(pEvent);
|
|
|
|
}
|
|
|
|
done:
|
|
if(NULL != hInst)
|
|
{
|
|
FreeLibrary(hInst);
|
|
}
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
DWORD
|
|
DwSaveIpSecInfo(pPCB ppcb)
|
|
{
|
|
DWORD retcode;
|
|
RAS_DEVICE_INFO *prdi;
|
|
RASTAPI_CONNECT_INFO *pConnectInfo = NULL;
|
|
DWORD dwSize = 0;
|
|
DWORD dwIpsecInformation = 0;
|
|
|
|
if(NULL == ppcb->PCB_Connection)
|
|
{
|
|
|
|
prdi = &ppcb->PCB_pDeviceInfo->rdiDeviceInfo;
|
|
|
|
//
|
|
// Get size of the connect information from TAPI
|
|
//
|
|
retcode = (DWORD)RastapiGetConnectInfo(
|
|
ppcb->PCB_PortIOHandle,
|
|
(RDT_Modem == RAS_DEVICE_TYPE(
|
|
prdi->eDeviceType))
|
|
? (PBYTE) prdi->szDeviceName
|
|
: (PBYTE) &prdi->guidDevice,
|
|
(RDT_Modem == RAS_DEVICE_TYPE(
|
|
prdi->eDeviceType)),
|
|
pConnectInfo,
|
|
&dwSize
|
|
);
|
|
|
|
if( (ERROR_BUFFER_TOO_SMALL != retcode)
|
|
&& (SUCCESS != retcode))
|
|
{
|
|
RasmanTrace(
|
|
|
|
"Failed to get size of connectinfo. rc=0%0x",
|
|
retcode);
|
|
|
|
goto done;
|
|
}
|
|
|
|
pConnectInfo = LocalAlloc(LPTR, dwSize);
|
|
|
|
if(NULL == pConnectInfo)
|
|
{
|
|
retcode = GetLastError();
|
|
|
|
RasmanTrace(
|
|
"DwSaveIpSecInformation: failed to allocate. rc=0%0x",
|
|
retcode);
|
|
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Get the connect information from TAPI
|
|
//
|
|
retcode = (DWORD)RastapiGetConnectInfo(
|
|
ppcb->PCB_PortIOHandle,
|
|
(RDT_Modem == RAS_DEVICE_TYPE(
|
|
prdi->eDeviceType))
|
|
? (PBYTE) prdi->szDeviceName
|
|
: (PBYTE) &prdi->guidDevice,
|
|
(RDT_Modem == RAS_DEVICE_TYPE(
|
|
prdi->eDeviceType)),
|
|
pConnectInfo,
|
|
&dwSize
|
|
);
|
|
|
|
if(SUCCESS != retcode)
|
|
{
|
|
|
|
RasmanTrace(
|
|
|
|
"Failed to get connectinfo. rc=0%0x",
|
|
retcode);
|
|
|
|
goto done;
|
|
}
|
|
|
|
|
|
if(0 != pConnectInfo->dwCallerIdSize)
|
|
{
|
|
CHAR *pszAddress;
|
|
|
|
//
|
|
// Extract the caller-id which should be the ip
|
|
// address of the the caller.
|
|
//
|
|
pszAddress = (CHAR *) (((PBYTE) pConnectInfo)
|
|
+ pConnectInfo->dwCallerIdOffset);
|
|
|
|
RasmanTrace(
|
|
|
|
"DwSaveIpSecInfo: pszAddress=%s",
|
|
pszAddress);
|
|
|
|
ppcb->PCB_ulDestAddr = inet_addr(pszAddress);
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get ipsecinformation from ipsec
|
|
//
|
|
retcode = DwGetIpSecInformation(ppcb, &dwIpsecInformation);
|
|
|
|
if(SUCCESS != retcode)
|
|
{
|
|
RasmanTrace(
|
|
"SaveIpsecInformation: failed to get ipsec info. 0x%x",
|
|
retcode);
|
|
|
|
}
|
|
|
|
|
|
done:
|
|
SetUserData(
|
|
&ppcb->PCB_UserData,
|
|
PORT_IPSEC_INFO_INDEX,
|
|
(PBYTE) &dwIpsecInformation,
|
|
sizeof(DWORD));
|
|
|
|
//
|
|
// Also stash the information away
|
|
// in the connection block so that
|
|
// client side apis work
|
|
//
|
|
if(NULL != ppcb->PCB_Connection)
|
|
{
|
|
SetUserData(
|
|
&ppcb->PCB_Connection->CB_UserData,
|
|
CONNECTION_IPSEC_INFO_INDEX,
|
|
(PBYTE) &dwIpsecInformation,
|
|
sizeof(DWORD));
|
|
}
|
|
|
|
if(NULL != pConnectInfo)
|
|
{
|
|
LocalFree(pConnectInfo);
|
|
}
|
|
|
|
return retcode;
|
|
}
|
|
|
|
BOOL
|
|
FRasmanAccessCheck()
|
|
{
|
|
SID_IDENTIFIER_AUTHORITY SidAuth = SECURITY_NT_AUTHORITY;
|
|
PSID psid;
|
|
BOOL fIsMember = FALSE;
|
|
RPC_STATUS rpcstatus;
|
|
HANDLE CurrentThreadToken = NULL;
|
|
BOOL fImpersonate = FALSE;
|
|
DWORD retcode = ERROR_SUCCESS;
|
|
SID sidLocalSystem = { 1, 1,
|
|
SECURITY_NT_AUTHORITY,
|
|
SECURITY_LOCAL_SYSTEM_RID };
|
|
|
|
rpcstatus = RpcImpersonateClient ( NULL );
|
|
|
|
if ( RPC_S_OK != rpcstatus )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
fImpersonate = TRUE;
|
|
|
|
retcode = NtOpenThreadToken(
|
|
NtCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&CurrentThreadToken
|
|
);
|
|
|
|
if(retcode != ERROR_SUCCESS)
|
|
{
|
|
RpcRevertToSelf();
|
|
goto done;
|
|
}
|
|
|
|
if (!CheckTokenMembership( CurrentThreadToken,
|
|
&sidLocalSystem, &fIsMember ))
|
|
{
|
|
fIsMember = FALSE;
|
|
}
|
|
|
|
if(fIsMember)
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
if (AllocateAndInitializeSid( &SidAuth, 2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0,
|
|
&psid ))
|
|
{
|
|
if (!CheckTokenMembership( CurrentThreadToken, psid, &fIsMember ))
|
|
{
|
|
RasmanTrace( "CheckTokenMemberShip for admins failed.");
|
|
fIsMember = FALSE;
|
|
}
|
|
|
|
FreeSid( psid );
|
|
}
|
|
|
|
done:
|
|
|
|
if(NULL != CurrentThreadToken)
|
|
{
|
|
NtClose(CurrentThreadToken);
|
|
}
|
|
|
|
if(fImpersonate)
|
|
{
|
|
RpcRevertToSelf();
|
|
}
|
|
|
|
return fIsMember;
|
|
}
|
|
|
|
VOID
|
|
RevealPassword(
|
|
IN UNICODE_STRING* pHiddenPassword
|
|
)
|
|
{
|
|
SECURITY_SEED_AND_LENGTH* SeedAndLength;
|
|
UCHAR Seed;
|
|
|
|
SeedAndLength = (SECURITY_SEED_AND_LENGTH*)&pHiddenPassword->Length;
|
|
Seed = SeedAndLength->Seed;
|
|
SeedAndLength->Seed = 0;
|
|
|
|
RtlRunDecodeUnicodeString(Seed, pHiddenPassword);
|
|
}
|
|
|
|
VOID
|
|
EncodePwd(RASMAN_CREDENTIALS *pCreds)
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
RtlInitUnicodeString(&UnicodeString, pCreds->wszPassword);
|
|
RtlRunEncodeUnicodeString(&pCreds->ucSeed, &UnicodeString);
|
|
pCreds->usLength = UnicodeString.Length;
|
|
pCreds->usMaximumLength = UnicodeString.MaximumLength;
|
|
}
|
|
|
|
VOID
|
|
DecodePwd(RASMAN_CREDENTIALS *pCreds)
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
UnicodeString.Length = pCreds->usLength;
|
|
UnicodeString.MaximumLength = pCreds->usMaximumLength;
|
|
UnicodeString.Buffer = pCreds->wszPassword;
|
|
RtlRunDecodeUnicodeString(pCreds->ucSeed, &UnicodeString);
|
|
}
|
|
|
|
VOID
|
|
EncodePin(
|
|
IN RASMAN_EAPTLS_USER_PROPERTIES* pUserProp
|
|
)
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
UCHAR ucSeed = 0;
|
|
|
|
RtlInitUnicodeString(&UnicodeString, pUserProp->pwszPin);
|
|
RtlRunEncodeUnicodeString(&ucSeed, &UnicodeString);
|
|
pUserProp->usLength = UnicodeString.Length;
|
|
pUserProp->usMaximumLength = UnicodeString.MaximumLength;
|
|
pUserProp->ucSeed = ucSeed;
|
|
}
|
|
|
|
|
|
VOID
|
|
DecodePin(
|
|
IN RASMAN_EAPTLS_USER_PROPERTIES* pUserProp
|
|
)
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
UnicodeString.Length = pUserProp->usLength;
|
|
UnicodeString.MaximumLength = pUserProp->usMaximumLength;
|
|
UnicodeString.Buffer = pUserProp->pwszPin;
|
|
RtlRunDecodeUnicodeString(pUserProp->ucSeed, &UnicodeString);
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
GetMarshalledCredFromHash(
|
|
PBYTE pbHash,
|
|
DWORD cbHash,
|
|
LPTSTR lpszMarshalledCred )
|
|
{
|
|
|
|
CERT_CREDENTIAL_INFO CertCredInfo;
|
|
LPTSTR lpszMarshalledCredLocal = NULL;
|
|
|
|
RasmanTrace("GetMarshalledCredFromHash");
|
|
|
|
CertCredInfo.cbSize = sizeof(CertCredInfo);
|
|
|
|
memcpy (CertCredInfo.rgbHashOfCert,
|
|
pbHash,
|
|
cbHash
|
|
);
|
|
if (CredMarshalCredential(CertCredential,
|
|
(PVOID) &CertCredInfo,
|
|
&lpszMarshalledCredLocal
|
|
)
|
|
)
|
|
{
|
|
//
|
|
// Got Marshalled Credential from the cert
|
|
// Set it in the username field
|
|
//
|
|
ASSERT( NULL != lpszMarshalledCredLocal );
|
|
lstrcpy ( lpszMarshalledCred, lpszMarshalledCredLocal );
|
|
CredFree ( lpszMarshalledCredLocal );
|
|
RasmanTrace("Got MarshalledCredFromHash");
|
|
|
|
}
|
|
else
|
|
{
|
|
RasmanTrace("CredMarshalCredential Failed with Error:0x%x",
|
|
GetLastError());
|
|
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SaveEapCredentials(pPCB ppcb, PBYTE buffer)
|
|
{
|
|
RASMAN_CREDENTIALS *pCreds;
|
|
|
|
if(NULL == ppcb->PCB_Connection)
|
|
{
|
|
RasmanTrace("Attempted to save creds for NULL connection!");
|
|
((REQTYPECAST *)buffer)->PortUserData.retcode = E_FAIL;
|
|
return;
|
|
}
|
|
|
|
pCreds = (RASMAN_CREDENTIALS *)
|
|
((REQTYPECAST *)buffer)->PortUserData.data;
|
|
|
|
//
|
|
// Store the user data object - make sure that the data is
|
|
// encrypted
|
|
//
|
|
#if 0
|
|
if(NO_ERROR == EncodeData(
|
|
(BYTE *) pCreds->wszPassword,
|
|
wcslen(pCreds->wszPassword) * sizeof(WCHAR),
|
|
&pblob))
|
|
{
|
|
pCreds->pbPasswordData = pblob->pbData;
|
|
pCreds->cbPasswordData = pblob->cbData;
|
|
LocalFree(pblob);
|
|
}
|
|
|
|
#endif
|
|
|
|
EncodePwd(pCreds);
|
|
|
|
SetUserData(
|
|
&ppcb->PCB_Connection->CB_UserData,
|
|
CONNECTION_CREDENTIALS_INDEX,
|
|
(BYTE *)pCreds,
|
|
sizeof(RASMAN_CREDENTIALS));
|
|
}
|
|
|
|
|
|
DWORD
|
|
DwCacheCredMgrCredentials(PPPE_MESSAGE *pMsg, pPCB ppcb)
|
|
{
|
|
RASMAN_CREDENTIALS *pCreds = NULL;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
CHAR *pszUser = NULL;
|
|
CHAR *pszDomain = NULL;
|
|
CHAR *pszPasswd = NULL;
|
|
UserData *pData = NULL;
|
|
RASMAN_EAPTLS_USER_PROPERTIES *pUserProps = NULL;
|
|
|
|
RasmanTrace("DwCacheCredentials");
|
|
|
|
//
|
|
// Store the credentials to be saved with credential manager.
|
|
// Encode password before we copy it to local memory.
|
|
//
|
|
pCreds = LocalAlloc(LPTR, sizeof(RASMAN_CREDENTIALS));
|
|
|
|
if(NULL == pCreds)
|
|
{
|
|
//
|
|
// This is not fatal. If we fail to save with Credmanager,
|
|
// the client might get a lot of challenges from credmgr
|
|
// which is not a fatal sideeffect.
|
|
//
|
|
RasmanTrace(
|
|
"PppStart: Failed to allocate. %d",
|
|
GetLastError());
|
|
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Fetch the stored credentials and initialize the
|
|
// credentials if the fetch succeeds
|
|
//
|
|
pData = GetUserData(
|
|
&(ppcb->PCB_Connection->CB_UserData),
|
|
CONNECTION_CREDENTIALS_INDEX);
|
|
|
|
if(NULL != pData)
|
|
{
|
|
RASMAN_CREDENTIALS *pSavedCreds =
|
|
(RASMAN_CREDENTIALS *) pData->UD_Data;
|
|
|
|
DecodePwd(pSavedCreds);
|
|
|
|
CopyMemory(pCreds, pSavedCreds, sizeof(RASMAN_CREDENTIALS));
|
|
|
|
//
|
|
// SavedCreds will be freed when SetUserData is called below
|
|
//
|
|
EncodePwd(pSavedCreds);
|
|
}
|
|
|
|
switch(pMsg->dwMsgId)
|
|
{
|
|
case PPPEMSG_Start:
|
|
{
|
|
pszUser = pMsg->ExtraInfo.Start.szUserName;
|
|
pszDomain = pMsg->ExtraInfo.Start.szDomain;
|
|
pszPasswd = pMsg->ExtraInfo.Start.szPassword;
|
|
|
|
if(pMsg->ExtraInfo.Start.fLogon)
|
|
{
|
|
pCreds->dwFlags |= RASCRED_LOGON;
|
|
}
|
|
|
|
if(NULL != pMsg->ExtraInfo.Start.pCustomAuthUserData)
|
|
{
|
|
pCreds->dwFlags |= RASCRED_EAP;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case PPPEMSG_ChangePw:
|
|
{
|
|
pszUser = pMsg->ExtraInfo.ChangePw.szUserName;
|
|
pszPasswd = pMsg->ExtraInfo.ChangePw.szNewPassword;
|
|
break;
|
|
}
|
|
|
|
case PPPEMSG_Retry:
|
|
{
|
|
pszUser = pMsg->ExtraInfo.Retry.szUserName;
|
|
pszDomain = pMsg->ExtraInfo.Retry.szDomain;
|
|
pszPasswd = pMsg->ExtraInfo.Retry.szPassword;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
dwErr = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
strcpy(pCreds->szUserName,
|
|
pszUser);
|
|
|
|
if(NULL != pszDomain)
|
|
{
|
|
strcpy(pCreds->szDomain,
|
|
pszDomain);
|
|
}
|
|
|
|
//
|
|
// Now do the dirty part of extracting the PIN if its
|
|
// EAP-TLS smartcard stuff. If its not tls, we don't
|
|
// know how to save the information in cred mgr. and
|
|
// we bail. This feature doesn't work for non-smart
|
|
// card eap at this point.
|
|
//
|
|
if(pCreds->dwFlags & RASCRED_EAP)
|
|
{
|
|
#if 0
|
|
|
|
RasmanTrace("DwCacheCredMgrCredentials: eap creds");
|
|
if(PPP_EAP_TLS != pMsg->ExtraInfo.Start.dwEapTypeId)
|
|
{
|
|
RasmanTrace("DwCacheCreMgrCredentials: Eap but not TLS");
|
|
dwErr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// It is tls. So Extract the PIN.
|
|
//
|
|
if(pCreds->dwFlags & RASCRED_LOGON)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
pUserProps = (RASMAN_EAPTLS_USER_PROPERTIES *)
|
|
LocalAlloc(LPTR,
|
|
(pMsg->ExtraInfo.Start.pCustomAuthUserData)->cbCustomAuthData );
|
|
if ( !pUserProps )
|
|
{
|
|
RasmanTrace(
|
|
"DwCacheCredMgrCredentials: Failed to allocate. %d",
|
|
GetLastError());
|
|
|
|
goto done;
|
|
}
|
|
|
|
CopyMemory
|
|
( pUserProps,
|
|
(pMsg->ExtraInfo.Start.pCustomAuthUserData)->abCustomAuthData,
|
|
(pMsg->ExtraInfo.Start.pCustomAuthUserData)->cbCustomAuthData
|
|
);
|
|
|
|
|
|
if ((pMsg->ExtraInfo.Start.pCustomAuthUserData)->cbCustomAuthData
|
|
< sizeof(RASMAN_EAPTLS_USER_PROPERTIES))
|
|
{
|
|
//
|
|
// nothing to plumb
|
|
//
|
|
pUserProps->dwVersion = 0;
|
|
pUserProps->dwSize =
|
|
(pMsg->ExtraInfo.Start.pCustomAuthUserData)->cbCustomAuthData;
|
|
|
|
pUserProps->pwszDiffUser = pUserProps->awszString;
|
|
pUserProps->dwPinOffset = 0;
|
|
pUserProps->pwszPin =
|
|
pUserProps->awszString + pUserProps->dwPinOffset;
|
|
}
|
|
else
|
|
{
|
|
pUserProps->dwSize =
|
|
(pMsg->ExtraInfo.Start.pCustomAuthUserData)->cbCustomAuthData;
|
|
pUserProps->pwszDiffUser = pUserProps->awszString;
|
|
pUserProps->pwszPin =
|
|
pUserProps->awszString + pUserProps->dwPinOffset;
|
|
|
|
//
|
|
// Decode Pin
|
|
//
|
|
DecodePin(pUserProps);
|
|
|
|
}
|
|
|
|
if (pUserProps->dwPinOffset )
|
|
{
|
|
wcscpy(pCreds->wszPassword,
|
|
pUserProps->awszString
|
|
+ pUserProps->dwPinOffset);
|
|
}
|
|
|
|
GetMarshalledCredFromHash(pUserProps->Hash.pbHash,
|
|
pUserProps->Hash.cbHash,
|
|
pCreds->szUserName );
|
|
|
|
//
|
|
// Encode Pin
|
|
//
|
|
EncodePin(pUserProps);
|
|
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
WCHAR *pwszPwd = StrdupAtoW(pszPasswd);
|
|
|
|
if(NULL == pwszPwd)
|
|
{
|
|
RasmanTrace("DwCacheCredMgrCredentials: failed to alloc pwd");
|
|
dwErr = E_OUTOFMEMORY;
|
|
goto done;
|
|
}
|
|
|
|
wcscpy(pCreds->wszPassword,
|
|
pwszPwd);
|
|
|
|
ZeroMemory(pwszPwd, (sizeof(WCHAR) * wcslen(pwszPwd)) + 1);
|
|
LocalFree(pwszPwd);
|
|
}
|
|
|
|
//
|
|
// Obfuscate the pwd
|
|
//
|
|
EncodePwd(pCreds);
|
|
|
|
SetUserData(&(ppcb->PCB_Connection->CB_UserData),
|
|
CONNECTION_CREDENTIALS_INDEX,
|
|
(PBYTE) pCreds,
|
|
sizeof(RASMAN_CREDENTIALS));
|
|
|
|
|
|
done:
|
|
|
|
if ( pUserProps )
|
|
{
|
|
LocalFree(pUserProps);
|
|
}
|
|
if(NULL != pCreds)
|
|
{
|
|
ZeroMemory(pCreds->wszPassword, sizeof(WCHAR) * (PWLEN + 1));
|
|
LocalFree(pCreds);
|
|
}
|
|
|
|
RasmanTrace("DwCacheCredMgrCredentials: 0x%x", dwErr);
|
|
return dwErr;
|
|
|
|
}
|
|
|
|
BOOL
|
|
fDomainNotPresent(CHAR *pszName)
|
|
{
|
|
while(*pszName != '\0')
|
|
{
|
|
if('\\' == *pszName)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pszName++;
|
|
}
|
|
|
|
return ('\0' == *pszName) ? TRUE : FALSE;
|
|
}
|
|
|
|
DWORD
|
|
DwSaveCredentials(ConnectionBlock *pConn)
|
|
{
|
|
RASMAN_CREDENTIALS *pCreds;
|
|
DWORD dwErr = SUCCESS;
|
|
CHAR szNameBuf[CRED_MAX_STRING_LENGTH];
|
|
CREDENTIAL stCredential;
|
|
BOOL bResult;
|
|
UserData *pData;
|
|
WCHAR *pwszPassword;
|
|
|
|
RasmanTrace("DwSaveCredentials");
|
|
|
|
// return dwErr;
|
|
|
|
if(NULL == pConn)
|
|
{
|
|
RasmanTrace("DwSaveCredentials: ERROR_NO_CONNECTION");
|
|
dwErr = ERROR_NO_CONNECTION;
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// This check is made for robustness. The caller of this
|
|
// function should actually be making the check.
|
|
//
|
|
if(0 == (pConn->CB_ConnectionParams.CP_ConnectionFlags
|
|
& CONNECTION_USERASCREDENTIALS))
|
|
{
|
|
RasmanTrace("DwSaveCredentials: not saving credentials");
|
|
goto done;
|
|
}
|
|
|
|
pData = GetUserData(
|
|
&pConn->CB_UserData,
|
|
CONNECTION_CREDENTIALS_INDEX);
|
|
|
|
if(NULL == pData)
|
|
{
|
|
RasmanTrace("DwSaveCredentials: Creds not found");
|
|
dwErr = ERROR_NOT_FOUND;
|
|
goto done;
|
|
}
|
|
|
|
pCreds = (RASMAN_CREDENTIALS *) pData->UD_Data;
|
|
|
|
//
|
|
// Save the credentials with cred mgr.
|
|
//
|
|
ZeroMemory(&stCredential, sizeof(CREDENTIAL));
|
|
|
|
stCredential.TargetName = CRED_SESSION_WILDCARD_NAME_A;
|
|
|
|
if(RASCRED_EAP & pCreds->dwFlags)
|
|
{
|
|
|
|
stCredential.Type = (DWORD) CRED_TYPE_DOMAIN_CERTIFICATE;
|
|
|
|
}
|
|
else
|
|
{
|
|
stCredential.Type = (DWORD) CRED_TYPE_DOMAIN_PASSWORD;
|
|
}
|
|
|
|
stCredential.Persist = CRED_PERSIST_SESSION;
|
|
|
|
//
|
|
// Check to see if domain name is passed in the username
|
|
// field (i.e the username is already in the form
|
|
// "domain\\user")
|
|
//
|
|
if( ('\0' != pCreds->szDomain[0])
|
|
&& (fDomainNotPresent(pCreds->szUserName)))
|
|
{
|
|
sprintf(szNameBuf,
|
|
"%s\\%s",
|
|
pCreds->szDomain,
|
|
pCreds->szUserName);
|
|
}
|
|
else
|
|
{
|
|
strcpy(szNameBuf, pCreds->szUserName);
|
|
}
|
|
|
|
stCredential.UserName = szNameBuf;
|
|
|
|
DecodePwd(pCreds);
|
|
|
|
stCredential.CredentialBlobSize = sizeof(WCHAR) * wcslen(pCreds->wszPassword);
|
|
stCredential.CredentialBlob = (unsigned char *) pCreds->wszPassword;
|
|
|
|
if(ERROR_SUCCESS == (dwErr = RasImpersonateUser(pConn->CB_Process)))
|
|
{
|
|
|
|
//
|
|
// Before writing the credentials, make sure there are no other wild card
|
|
// credentials present in the credential manager. There should be only one
|
|
// CRED_SESSION_WILDCARD_NAME credential at any time. Currently we only
|
|
// plumb _PASSWORD or _CERTIFICATE type of credentials. This will need to
|
|
// change if we backport any _GENERIC type.
|
|
//
|
|
(VOID) CredDelete(CRED_SESSION_WILDCARD_NAME_A,
|
|
CRED_TYPE_DOMAIN_CERTIFICATE,
|
|
0);
|
|
|
|
(VOID) CredDelete(CRED_SESSION_WILDCARD_NAME_A,
|
|
CRED_TYPE_DOMAIN_PASSWORD,
|
|
0);
|
|
|
|
if(!CredWrite(&stCredential, 0))
|
|
{
|
|
dwErr = GetLastError();
|
|
|
|
RasmanTrace(
|
|
"DwSaveCredentials: CredWrite failed to "
|
|
"save credentials in credmgr.0x%x", dwErr);
|
|
|
|
}
|
|
|
|
RasRevertToSelf();
|
|
}
|
|
else
|
|
{
|
|
RasmanTrace(
|
|
"DwSaveCredentials: failed to impersonate. 0x%x",
|
|
dwErr);
|
|
}
|
|
|
|
ZeroMemory(pCreds->wszPassword, sizeof(WCHAR) * (PWLEN + 1));
|
|
|
|
done:
|
|
|
|
RasmanTrace("DwSaveCredentials: 0x%x", dwErr);
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
DWORD
|
|
DwDeleteCredentials(ConnectionBlock *pConn)
|
|
{
|
|
DWORD dwErr = SUCCESS;
|
|
RASMAN_CREDENTIALS * pCreds = NULL;
|
|
UserData * pData = NULL;
|
|
RasmanTrace("DwDeleteCredentials");
|
|
|
|
// return dwErr;
|
|
|
|
if(NULL == pConn)
|
|
{
|
|
RasmanTrace("DwDeleteCredentials: ERROR_NO_CONNECTION");
|
|
dwErr = ERROR_NO_CONNECTION;
|
|
goto done;
|
|
}
|
|
|
|
if(0 == (pConn->CB_ConnectionParams.CP_ConnectionFlags
|
|
& CONNECTION_USERASCREDENTIALS))
|
|
{
|
|
RasmanTrace("DwDeleteCredentials: not deleting creds");
|
|
goto done;
|
|
}
|
|
|
|
pData = GetUserData(
|
|
&pConn->CB_UserData,
|
|
CONNECTION_CREDENTIALS_INDEX);
|
|
|
|
if(NULL == pData)
|
|
{
|
|
RasmanTrace("DwDeleteCredentials: not deleting creds");
|
|
dwErr = ERROR_NOT_FOUND;
|
|
goto done;
|
|
}
|
|
|
|
pCreds = (RASMAN_CREDENTIALS *) pData->UD_Data;
|
|
|
|
if(ERROR_SUCCESS == (dwErr = RasImpersonateUser(pConn->CB_Process)))
|
|
{
|
|
|
|
(VOID) CredDelete(CRED_SESSION_WILDCARD_NAME_A,
|
|
CRED_TYPE_DOMAIN_CERTIFICATE,
|
|
0);
|
|
|
|
(VOID) CredDelete(CRED_SESSION_WILDCARD_NAME_A,
|
|
CRED_TYPE_DOMAIN_PASSWORD,
|
|
0);
|
|
|
|
RasRevertToSelf();
|
|
}
|
|
else
|
|
{
|
|
RasmanTrace(
|
|
"DwDeleteCredentials: failed to impersonate. 0x%x",
|
|
dwErr);
|
|
}
|
|
|
|
done:
|
|
|
|
RasmanTrace("DwDeleteCredentials: 0x%x");
|
|
return dwErr;
|
|
}
|
|
|
|
DWORD
|
|
InitializeRasAudio()
|
|
{
|
|
DWORD retcode = SUCCESS;
|
|
CHAR *psz[2];
|
|
|
|
if(NULL != hinstRasAudio)
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
psz[0] = "initialize";
|
|
psz[1] = NULL;
|
|
|
|
hinstRasAudio = LoadLibrary("rasaudio.dll");
|
|
|
|
if(NULL == hinstRasAudio)
|
|
{
|
|
retcode = GetLastError();
|
|
RasmanTrace("InitializeRasAudio: failed to load rasaudio.dll"
|
|
" Error=%d", retcode);
|
|
goto done;
|
|
}
|
|
|
|
if( (NULL == (RasStartRasAudio =
|
|
GetProcAddress(hinstRasAudio,
|
|
"StartRasAudio")))
|
|
|| (NULL == (RasStopRasAudio =
|
|
GetProcAddress(hinstRasAudio,
|
|
"StopRasAudio"))))
|
|
{
|
|
retcode = GetLastError();
|
|
FreeLibrary(hinstRasAudio);
|
|
hinstRasAudio = NULL;
|
|
RasStartRasAudio = NULL;
|
|
|
|
RasmanTrace("EnableRasAudio: failed to "
|
|
"GetProcAddress. error=%d", retcode);
|
|
|
|
goto done;
|
|
}
|
|
|
|
retcode = (DWORD) RasStartRasAudio();
|
|
|
|
if(ERROR_SUCCESS != retcode)
|
|
{
|
|
psz[0] = "start";
|
|
}
|
|
|
|
done:
|
|
|
|
if(SUCCESS != retcode)
|
|
{
|
|
//
|
|
// Eventlog the failure
|
|
//
|
|
RouterLogErrorString (
|
|
hLogEvents,
|
|
ROUTERLOG_RASAUDIO_FAILURE,
|
|
2, psz, retcode, 2) ;
|
|
|
|
UninitializeRasAudio();
|
|
}
|
|
|
|
return retcode;
|
|
}
|
|
|
|
DWORD
|
|
UninitializeRasAudio()
|
|
{
|
|
DWORD retcode = SUCCESS;
|
|
|
|
if(NULL == hinstRasAudio)
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
retcode = (DWORD) RasStopRasAudio();
|
|
|
|
if(SUCCESS == retcode)
|
|
{
|
|
//
|
|
// Free the module
|
|
//
|
|
FreeLibrary(hinstRasAudio);
|
|
hinstRasAudio = NULL;
|
|
RasStartRasAudio = NULL;
|
|
RasStopRasAudio = NULL;
|
|
}
|
|
|
|
done:
|
|
|
|
if(SUCCESS != retcode)
|
|
{
|
|
CHAR *psz[2];
|
|
|
|
//
|
|
// Eventlog the failure
|
|
//
|
|
psz[0] = "stop";
|
|
psz[1] = NULL;
|
|
|
|
RouterLogErrorString (
|
|
hLogEvents,
|
|
ROUTERLOG_RASAUDIO_FAILURE,
|
|
2, psz, retcode, 2) ;
|
|
}
|
|
|
|
return retcode;
|
|
}
|
|
|
|
|
|
VOID
|
|
UninitializeIphlp()
|
|
{
|
|
if(g_IphlpInitialized)
|
|
{
|
|
ASSERT(NULL != hIphlp);
|
|
FreeLibrary(hIphlp);
|
|
}
|
|
|
|
hIphlp = NULL;
|
|
RasGetBestInterface = NULL;
|
|
RasGetIpAddrTable = NULL;
|
|
g_IphlpInitialized = FALSE;
|
|
}
|
|
|
|
DWORD
|
|
DwInitializeIphlp()
|
|
{
|
|
DWORD retcode = ERROR_SUCCESS;
|
|
|
|
if(g_IphlpInitialized)
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
if( (NULL == (hIphlp = LoadLibrary("iphlpapi.dll")))
|
|
|| (NULL == (RasGetBestInterface =
|
|
GetProcAddress(hIphlp,
|
|
"GetBestInterfaceFromStack")))
|
|
|| (NULL == (RasGetIpAddrTable =
|
|
GetProcAddress(hIphlp,
|
|
"GetIpAddrTable")))
|
|
|| (NULL == (RasAllocateAndGetInterfaceInfoFromStack =
|
|
GetProcAddress(hIphlp,
|
|
"NhpAllocateAndGetInterfaceInfoFromStack"))))
|
|
{
|
|
retcode = GetLastError();
|
|
goto done;
|
|
}
|
|
|
|
g_IphlpInitialized = TRUE;
|
|
|
|
done:
|
|
return retcode;
|
|
}
|
|
|
|
DWORD
|
|
DwCacheRefInterface(pPCB ppcb)
|
|
{
|
|
DWORD retcode = ERROR_SUCCESS;
|
|
DWORD dwIfIndex;
|
|
HANDLE hHeap = NULL;
|
|
IP_INTERFACE_NAME_INFO *pTable = NULL;
|
|
DWORD dw;
|
|
DWORD dwCount;
|
|
|
|
if( (NULL == ppcb->PCB_Connection)
|
|
|| (RDT_Tunnel_Pptp !=
|
|
RAS_DEVICE_TYPE(
|
|
ppcb->PCB_pDeviceInfo->rdiDeviceInfo.eDeviceType)))
|
|
{
|
|
RasmanTrace("DwCacheRefInterface: Invalid Parameter");
|
|
retcode = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
|
|
retcode = DwInitializeIphlp();
|
|
if(ERROR_SUCCESS != retcode)
|
|
{
|
|
RasmanTrace("DwCacheRefInterface: failed to init iphlp. 0x%x",
|
|
retcode);
|
|
goto done;
|
|
}
|
|
|
|
retcode = (DWORD)RasGetBestInterface(ppcb->PCB_ulDestAddr, &dwIfIndex);
|
|
if(ERROR_SUCCESS != retcode)
|
|
{
|
|
RasmanTrace("DwCacheRefInterface: GetBestInterface failed. 0x%x",
|
|
retcode);
|
|
goto done;
|
|
}
|
|
|
|
hHeap = GetProcessHeap();
|
|
|
|
retcode = (DWORD) RasAllocateAndGetInterfaceInfoFromStack(
|
|
&pTable, &dwCount, FALSE /* bOrder */,
|
|
hHeap, LPTR);
|
|
|
|
if(ERROR_SUCCESS != retcode)
|
|
{
|
|
RasmanTrace("DwCacheRefInterface: AllocAndGet.. failed. 0x%x",
|
|
retcode);
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Loop through and cache the interface guid
|
|
//
|
|
for(dw = 0; dw < dwCount; dw++)
|
|
{
|
|
if(dwIfIndex == pTable[dw].Index)
|
|
{
|
|
SetUserData(
|
|
&ppcb->PCB_Connection->CB_UserData,
|
|
CONNECTION_REFINTERFACEGUID_INDEX,
|
|
(PBYTE) &pTable[dw].InterfaceGuid,
|
|
sizeof(GUID));
|
|
|
|
SetUserData(
|
|
&ppcb->PCB_Connection->CB_UserData,
|
|
CONNECTION_REFDEVICEGUID_INDEX,
|
|
(PBYTE) &pTable[dw].DeviceGuid,
|
|
sizeof(GUID));
|
|
|
|
RasmanTrace(
|
|
"DwCacheRefInterface: setuserdata. Addr=0x%x, rc=0x%x",
|
|
ppcb->PCB_ulDestAddr, retcode);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(dw == dwCount)
|
|
{
|
|
RasmanTrace("DwCacheRefInterface: didn't find i/f index");
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
if(NULL != pTable)
|
|
{
|
|
HeapFree(hHeap, 0, pTable);
|
|
}
|
|
|
|
return retcode;
|
|
|
|
}
|
|
|
|
DWORD DwGetBestInterface(
|
|
DWORD DestAddress,
|
|
DWORD *pdwAddress,
|
|
DWORD *pdwMask)
|
|
{
|
|
DWORD retcode = ERROR_SUCCESS;
|
|
DWORD dwInterface;
|
|
DWORD dwSize = 0;
|
|
MIB_IPADDRTABLE *pAddressTable = NULL;
|
|
DWORD i;
|
|
|
|
ASSERT(NULL != pdwAddress);
|
|
ASSERT(NULL != pdwMask);
|
|
|
|
*pdwAddress = -1;
|
|
|
|
*pdwMask = -1;
|
|
|
|
retcode = DwInitializeIphlp();
|
|
|
|
if(ERROR_SUCCESS != retcode)
|
|
{
|
|
RasmanTrace(
|
|
"DwGetBestInteface: failed to init iphlp. 0x%x",
|
|
retcode);
|
|
|
|
goto done;
|
|
}
|
|
|
|
retcode = (DWORD) RasGetBestInterface(DestAddress, &dwInterface);
|
|
|
|
if(ERROR_SUCCESS != retcode)
|
|
{
|
|
RasmanTrace(
|
|
"DwGetBestInterface: GetBestInterface failed. 0x%x",
|
|
retcode);
|
|
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Get the interface to address mapping
|
|
//
|
|
retcode = (DWORD) RasGetIpAddrTable(
|
|
&pAddressTable,
|
|
&dwSize,
|
|
FALSE);
|
|
|
|
if(ERROR_INSUFFICIENT_BUFFER != retcode)
|
|
{
|
|
RasmanTrace(
|
|
"DwGetBestInterface: GetIpAddrTable returned 0x%x",
|
|
retcode);
|
|
|
|
goto done;
|
|
}
|
|
|
|
pAddressTable = (MIB_IPADDRTABLE *) LocalAlloc(LPTR, dwSize);
|
|
|
|
if(NULL == pAddressTable)
|
|
{
|
|
retcode = GetLastError();
|
|
RasmanTrace(
|
|
"DwGetBestInterface: failed to allocate table. 0x%x",
|
|
retcode);
|
|
|
|
goto done;
|
|
}
|
|
|
|
retcode = (DWORD) RasGetIpAddrTable(
|
|
pAddressTable,
|
|
&dwSize,
|
|
FALSE);
|
|
|
|
if(ERROR_SUCCESS != retcode)
|
|
{
|
|
RasmanTrace(
|
|
"DwGetBestInterface: failed to get ip addr table. 0x%x",
|
|
retcode);
|
|
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Loop through the address table and find the
|
|
// address with the index we are intersted in.
|
|
//
|
|
for(i = 0; i < pAddressTable->dwNumEntries; i++)
|
|
{
|
|
if(dwInterface == pAddressTable->table[i].dwIndex)
|
|
{
|
|
*pdwAddress = pAddressTable->table[i].dwAddr;
|
|
*pdwMask = pAddressTable->table[i].dwMask;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(i == pAddressTable->dwNumEntries)
|
|
{
|
|
retcode = ERROR_NOT_FOUND;
|
|
}
|
|
|
|
done:
|
|
|
|
if(NULL != pAddressTable)
|
|
{
|
|
LocalFree(pAddressTable);
|
|
}
|
|
|
|
RasmanTrace(
|
|
"DwGetBestInterface: done. rc=0x%x, address=0x%x, mask=0x%x",
|
|
retcode,
|
|
*pdwAddress,
|
|
*pdwMask);
|
|
|
|
return retcode;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
QueueCloseConnections(ConnectionBlock *pConn,
|
|
HANDLE hEvent,
|
|
BOOL *pfQueued)
|
|
{
|
|
DWORD retcode = ERROR_SUCCESS;
|
|
ConnectionBlock *pConnT;
|
|
PLIST_ENTRY pEntry;
|
|
DWORD dwCount = 0;
|
|
UserData *pData = NULL;
|
|
ConnectionBlock **phConn = NULL;
|
|
DWORD dwConn;
|
|
RAS_OVERLAPPED *pOverlapped = NULL;
|
|
|
|
ASSERT(pfQueued != NULL);
|
|
ASSERT(pConn != NULL);
|
|
|
|
*pfQueued = FALSE;
|
|
|
|
//
|
|
// Check to see if this is the last port
|
|
//
|
|
if(pConn->CB_Ports != 1)
|
|
{
|
|
RasmanTrace("QueueCloseConnections: cbports=%d",
|
|
pConn->CB_Ports);
|
|
goto done;
|
|
}
|
|
|
|
phConn = LocalAlloc(LPTR, 10 * sizeof(HCONN));
|
|
if(NULL == phConn)
|
|
{
|
|
RasmanTrace(
|
|
"QueueCloseConnections: failed to allocated");
|
|
goto done;
|
|
}
|
|
|
|
dwConn = 10;
|
|
|
|
for (pEntry = ConnectionBlockList.Flink;
|
|
pEntry != &ConnectionBlockList;
|
|
pEntry = pEntry->Flink)
|
|
|
|
{
|
|
pConnT =
|
|
CONTAINING_RECORD(pEntry, ConnectionBlock, CB_ListEntry);
|
|
|
|
//
|
|
// Get the interface guid
|
|
//
|
|
pData = GetUserData(&pConnT->CB_UserData,
|
|
CONNECTION_REFINTERFACEGUID_INDEX);
|
|
|
|
if(pData == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if(0 == memcmp(&pConn->CB_GuidEntry, pData->UD_Data, sizeof(GUID)))
|
|
{
|
|
phConn[dwCount] = pConnT;
|
|
dwCount += 1;
|
|
if(dwCount == dwConn)
|
|
{
|
|
ConnectionBlock **pTemp;
|
|
pTemp = LocalAlloc(LPTR, (dwCount + 10) * sizeof(HCONN));
|
|
if(NULL == pTemp)
|
|
{
|
|
goto done;
|
|
}
|
|
CopyMemory(pTemp, phConn, dwCount * sizeof(HCONN));
|
|
LocalFree(phConn);
|
|
phConn = pTemp;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(dwCount == 0)
|
|
{
|
|
RasmanTrace("QueueCloseConnections: no dependent connections");
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Now we have a list of connections which
|
|
// should be closed before pConn is closed.
|
|
// Queue requests to close these connections.
|
|
//
|
|
for(dwConn = 0; dwConn < dwCount; dwConn++)
|
|
{
|
|
pConnT = phConn[dwConn];
|
|
|
|
if(dwConn + 1 == dwCount)
|
|
{
|
|
pConnT->CB_ReferredEntry = pConn->CB_Handle;
|
|
}
|
|
|
|
pOverlapped = LocalAlloc(LPTR, sizeof(RAS_OVERLAPPED));
|
|
if(NULL == pOverlapped)
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
pOverlapped->RO_EventType = OVEVT_RASMAN_DEREFERENCE_CONNECTION;
|
|
pOverlapped->RO_hInfo = pConnT->CB_Handle;
|
|
RasmanTrace("Queueing DEREFERENCE for 0x%x",
|
|
pConnT->CB_Handle);
|
|
|
|
if (!PostQueuedCompletionStatus(
|
|
hIoCompletionPort,
|
|
0,0,
|
|
(LPOVERLAPPED)
|
|
pOverlapped))
|
|
{
|
|
RasmanTrace(
|
|
"QueueCloseConnections: failed to post completion"
|
|
" status. GLE=0%x", GetLastError());
|
|
|
|
LocalFree(pOverlapped);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
pConn->CB_Flags |= CONNECTION_DEFERRING_CLOSE;
|
|
*pfQueued = TRUE;
|
|
|
|
done:
|
|
|
|
if(phConn != NULL)
|
|
{
|
|
LocalFree(phConn);
|
|
}
|
|
}
|
|
|