4891 lines
138 KiB
C
4891 lines
138 KiB
C
/*
|
|
|
|
Copyright (c) 1997, Microsoft Corporation, all rights reserved
|
|
|
|
Description:
|
|
Remote Access PPP Bandwidth Allocation Protocol routines. Based on
|
|
RFC 2125.
|
|
|
|
History:
|
|
Mar 27, 1997: Vijay Baliga created original version.
|
|
|
|
Overview:
|
|
When NdisWan tells us that a link has to be added or dropped,
|
|
BapEventAddLink or BapEventDropLink gets called. They call FFillBapCb to
|
|
fill in the BAPCB structure of the bundle. The BAPCB structure is mostly
|
|
used for holding values of the various BAP Datagram Options. FFillBapCb
|
|
calls FGetAvailableLink[ClientOrRouter | NonRouterServer] to see if links
|
|
are available, and if so, to choose one. If FFillBapCb returns FALSE, then
|
|
we cannot satisfy NdisWan's request. Otherwise, we call
|
|
FSendInitialBapRequest to send the request to the peer.
|
|
|
|
When we get a packet from the peer, BapEventReceive gets called. It calls
|
|
the various BapEventRecv* functions, eg BapEventRecvCallOrCallbackReq,
|
|
BapEventRecvDropResp, etc. We respond by calling FSendBapResponse.
|
|
|
|
Before we send a Callback-Request, or ACK a Call-Request, we call
|
|
FListenForCall if we are a non-router client. Routers and servers are
|
|
always listening anyway, so we don't explicitly start listening.
|
|
|
|
If our Call-Request is ACK'ed or we ACK a Callback-Request, we call FCall
|
|
to add another link to the multilink bundle. Clients and routers call
|
|
RasDial. Non-router servers send messages to Ddm.
|
|
|
|
The bundles are always in one of several BAP_STATEs, eg BAP_STATE_INITIAL
|
|
(the rest state), BAP_STATE_CALLING, etc. Call-Requests and
|
|
Callback-Requests are NAK'ed unless the state is INITIAL, SENT_CALL_REQ, or
|
|
SENT_CALLBACK_REQ (the latter two to resolve race conditions).
|
|
Drop-Requests are NAK'ed unless the state is INITIAL or SEND_DROP_REQ (the
|
|
latter to resolve race conditions).
|
|
|
|
Note on Dropping Links:
|
|
We want to forcibly drop links when the utilization falls below a cutoff.
|
|
The server wants to do this to prevent users from hogging ports. The client
|
|
wants to do this to save money on calls.
|
|
|
|
Before sending a BAP_PACKET_DROP_REQ, we note down the number of active
|
|
links (in BapCb.dwLinCount) and set fForceDropOnNak to TRUE. If the packet
|
|
times out or we get any response other than ACK, we summarily drop the link
|
|
by calling FsmClose if the number of active links has not decreased and
|
|
fForceDropOnNak is still TRUE.
|
|
|
|
fForceDropOnNak is set to FALSE if there is a race condition and we are not
|
|
the favored peer. We then mark the link for dropping and insert an item in
|
|
the timer queue. After BAP_TIMEOUT_FAV_PEER sec, if the peer has still not
|
|
dropped the link, and we have at least two active links, we summarily drop
|
|
the link by calling FsmClose.
|
|
|
|
Note on the "previously known number" for calculating Phone-Deltas:
|
|
|
|
1) Client sending its numbers to the server (425 882 5759 and 425 882 5760)
|
|
Client sends 011 91 425 882 5759. Server dials it.
|
|
Client sends 011 91 425 882 5760. Server applies delta to above number.
|
|
|
|
2) Server sending its numbers to the client. Client called 882 5759 first.
|
|
(425 882 5759, 425 882 5660, 425 882 5758, 425 882 6666)
|
|
Server sends 660. Client applies delta to first number.
|
|
Server sends 758 (not just 8). Client applies delta to first number.
|
|
Server sends 6666. Client applies delta to first number.
|
|
|
|
This works irrespective of whether the 3rd party client applies delta to
|
|
the first number or the last number.
|
|
|
|
If the client gets 011 91 425 882 5660, it must just dial the last 7
|
|
digits, since it dialed only 7 digits the first time.
|
|
|
|
*/
|
|
|
|
#include <nt.h> // Required by windows.h
|
|
#include <ntrtl.h> // Required by windows.h
|
|
#include <nturtl.h> // Required by windows.h
|
|
#include <windows.h> // Win32 base API's
|
|
|
|
#include <raserror.h> // For ERROR_BUFFER_TOO_SMALL, etc
|
|
#include <mprerror.h> // For ERROR_BAP_DISCONNECTED, etc
|
|
#include <mprlog.h> // For ROUTERLOG_BAP_DISCONNECTED, etc
|
|
#include <rasman.h> // Required by pppcp.h
|
|
#include <pppcp.h> // For PPP_CONFIG_HDR_LEN, PPP_BACP_PROTOCOL, etc
|
|
|
|
#include <ppp.h> // For PCB, PPP_PACKET, etc. Reqd by bap.h
|
|
#include <rtutils.h> // For RTASSERT (PPP_ASSERT)
|
|
#include <util.h> // For GetCpIndexFromProtocol(), etc
|
|
#include <timer.h> // For InsertInTimerQ(), RemoveFromTimerQ()
|
|
#include <smevents.h> // For FsmClose()
|
|
#include <worker.h> // For ProcessCallResult()
|
|
#include <bap.h>
|
|
#include <rasbacp.h> // For BACPCB
|
|
|
|
#define BAP_KEY_CLIENT_CALLBACK "Software\\Microsoft\\RAS Phonebook\\Callback"
|
|
#define BAP_KEY_SERVER_CALLBACK "Software\\Microsoft\\Router Phonebook\\Callback"
|
|
#define BAP_VAL_NUMBER "Number"
|
|
|
|
/*
|
|
|
|
Description:
|
|
g_dwMandatoryOptions[BAP_PACKET_foo] contains the mandatory options for BAP
|
|
Datagram BAP_PACKET_foo.
|
|
|
|
*/
|
|
|
|
static DWORD g_dwMandatoryOptions[] =
|
|
{
|
|
0,
|
|
BAP_N_LINK_TYPE,
|
|
0,
|
|
BAP_N_LINK_TYPE | BAP_N_PHONE_DELTA,
|
|
0,
|
|
BAP_N_LINK_DISC,
|
|
0,
|
|
BAP_N_CALL_STATUS,
|
|
0
|
|
};
|
|
|
|
/*
|
|
|
|
Returns:
|
|
void
|
|
|
|
Description:
|
|
Used for printing BAP trace statements.
|
|
|
|
*/
|
|
|
|
VOID
|
|
BapTrace(
|
|
IN CHAR* Format,
|
|
...
|
|
)
|
|
{
|
|
va_list arglist;
|
|
|
|
va_start(arglist, Format);
|
|
|
|
TraceVprintfEx(DwBapTraceId,
|
|
0x00010000 | TRACE_USE_MASK | TRACE_USE_MSEC,
|
|
Format,
|
|
arglist);
|
|
|
|
va_end(arglist);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Calls RasPortEnum() and returns an array of RASMAN_PORT's in *ppRasmanPort
|
|
and the number of elements in the array in *pdwNumPorts. If this function
|
|
fails, *ppRasmanPort will be NULL and *pdwNumPorts will be 0. If this
|
|
function succeeds, the caller must call LOCAL_FREE(*ppRasmanPort);
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FEnumPorts(
|
|
OUT RASMAN_PORT** ppRasmanPort,
|
|
OUT DWORD* pdwNumPorts
|
|
)
|
|
{
|
|
DWORD dwErr;
|
|
DWORD dwSize;
|
|
DWORD dwNumEntries;
|
|
BOOL fRet = FALSE;
|
|
|
|
PPP_ASSERT(NULL != ppRasmanPort);
|
|
PPP_ASSERT(NULL != pdwNumPorts);
|
|
|
|
*ppRasmanPort = NULL;
|
|
|
|
dwSize = 0;
|
|
dwErr = RasPortEnum(NULL, NULL /* buffer */, &dwSize, &dwNumEntries);
|
|
PPP_ASSERT(ERROR_BUFFER_TOO_SMALL == dwErr);
|
|
|
|
*ppRasmanPort = (RASMAN_PORT*) LOCAL_ALLOC(LPTR, dwSize);
|
|
if (NULL == *ppRasmanPort)
|
|
{
|
|
BapTrace("FEnumPorts: Out of memory.");
|
|
goto LDone;
|
|
}
|
|
|
|
dwErr = RasPortEnum(NULL, (BYTE*)*ppRasmanPort, &dwSize, &dwNumEntries);
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("FEnumPorts: RasPortEnum returned error %d", dwErr);
|
|
goto LDone;
|
|
}
|
|
|
|
fRet = TRUE;
|
|
|
|
LDone:
|
|
|
|
if (!fRet)
|
|
{
|
|
if (NULL != *ppRasmanPort)
|
|
{
|
|
LOCAL_FREE(*ppRasmanPort);
|
|
}
|
|
|
|
*ppRasmanPort = NULL;
|
|
*pdwNumPorts = 0;
|
|
}
|
|
|
|
*pdwNumPorts = dwNumEntries;
|
|
return(fRet);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: ASCII digits
|
|
FALSE: not ASCII digits
|
|
|
|
Description:
|
|
Looks at dwLength bytes in *pByte. Returns TRUE iff all of them are ASCII
|
|
digits.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FAsciiDigits(
|
|
IN BYTE* pByte,
|
|
IN DWORD dwLength
|
|
)
|
|
{
|
|
PPP_ASSERT(NULL != pByte);
|
|
|
|
while (dwLength--)
|
|
{
|
|
if (!isdigit(pByte[dwLength]))
|
|
{
|
|
if (FDoBapOnVpn && '.' == pByte[dwLength])
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Given a pointer to a RASMAN_PORT, this function returns the link type (in
|
|
*pdwLinkType) and link speed in kbps (in *pdwLinkSpeed) for the associated
|
|
port. The link type is the same as the Link Type in the Link-Type BAP
|
|
option: 1 for ISDN, 2 for X.25, and 4 for modem. If this function fails,
|
|
*pdwLinkType and *pdwLinkSpeed will be set to 0.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FGetLinkTypeAndSpeedFromRasmanPort(
|
|
IN RASMAN_PORT* pRasmanPort,
|
|
OUT DWORD* pdwLinkType,
|
|
OUT DWORD* pdwLinkSpeed
|
|
)
|
|
{
|
|
BOOL fRet = TRUE;
|
|
|
|
PPP_ASSERT(NULL != pRasmanPort);
|
|
PPP_ASSERT(NULL != pdwLinkType);
|
|
PPP_ASSERT(NULL != pdwLinkSpeed);
|
|
|
|
if (!lstrcmpi(pRasmanPort->P_DeviceType, RASDT_Isdn))
|
|
{
|
|
*pdwLinkType = 1;
|
|
*pdwLinkSpeed = 64;
|
|
}
|
|
else if (!lstrcmpi(pRasmanPort->P_DeviceType, RASDT_X25))
|
|
{
|
|
*pdwLinkType = 2;
|
|
*pdwLinkSpeed = 56;
|
|
}
|
|
else if (!lstrcmpi(pRasmanPort->P_DeviceType, RASDT_Modem))
|
|
{
|
|
*pdwLinkType = 4;
|
|
*pdwLinkSpeed = 56;
|
|
}
|
|
else if (FDoBapOnVpn && !lstrcmpi(pRasmanPort->P_DeviceType, RASDT_Vpn))
|
|
{
|
|
*pdwLinkType = 32;
|
|
*pdwLinkSpeed = 10000;
|
|
}
|
|
else
|
|
{
|
|
// BapTrace("Unknown LinkType %s", pRasmanPort->P_DeviceType);
|
|
*pdwLinkType = 0;
|
|
*pdwLinkSpeed = 0;
|
|
fRet = FALSE;
|
|
}
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Given an hPort, this function tries to find out the phone number that the
|
|
peer can dial to connect to the device that the port belongs to. The phone
|
|
number (only ASCII digits, and with at most RAS_MaxCallbackNumber chars) is
|
|
returned in szOurPhoneNumber.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FGetOurPhoneNumberFromHPort(
|
|
IN HPORT hPort,
|
|
OUT CHAR* szOurPhoneNumber
|
|
)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
RAS_CONNECT_INFO* pRasConnectInfo = NULL;
|
|
DWORD dwSize;
|
|
DWORD dwErr;
|
|
|
|
ZeroMemory(szOurPhoneNumber, (RAS_MaxCallbackNumber + 1) * sizeof(CHAR));
|
|
|
|
dwSize = 0;
|
|
dwErr = RasGetConnectInfo(hPort, &dwSize, NULL);
|
|
if (ERROR_BUFFER_TOO_SMALL != dwErr)
|
|
{
|
|
BapTrace("RasGetConnectInfo failed and returned 0x%x", dwErr);
|
|
goto LDone;
|
|
}
|
|
|
|
pRasConnectInfo = (RAS_CONNECT_INFO*) LOCAL_ALLOC(LPTR, dwSize);
|
|
if (NULL == pRasConnectInfo)
|
|
{
|
|
BapTrace("FGetOurPhoneNumbersFromHPort: Out of memory.");
|
|
goto LDone;
|
|
}
|
|
|
|
dwErr = RasGetConnectInfo(hPort, &dwSize, pRasConnectInfo);
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("RasGetConnectInfo failed and returned 0x%x", dwErr);
|
|
goto LDone;
|
|
}
|
|
|
|
if ( (0 < pRasConnectInfo->dwCalledIdSize)
|
|
&& (0 != pRasConnectInfo->pszCalledId[0]))
|
|
{
|
|
strncpy(szOurPhoneNumber, pRasConnectInfo->pszCalledId,
|
|
RAS_MaxCallbackNumber);
|
|
}
|
|
else if ( (0 < pRasConnectInfo->dwAltCalledIdSize)
|
|
&& (0 != pRasConnectInfo->pszAltCalledId[0]))
|
|
{
|
|
strncpy(szOurPhoneNumber, pRasConnectInfo->pszAltCalledId,
|
|
RAS_MaxCallbackNumber);
|
|
}
|
|
|
|
fRet = TRUE;
|
|
|
|
LDone:
|
|
|
|
if (NULL != pRasConnectInfo)
|
|
{
|
|
LOCAL_FREE(pRasConnectInfo);
|
|
}
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Given a port name, szPortName, this function tries to find out the phone
|
|
number that the peer has to dial to connect to the port. The phone number
|
|
is returned in szOurPhoneNumber, whose size must be at least
|
|
RAS_MaxCallbackNumber + 1. If we are the server or the router,
|
|
fRouterPhoneBook must be TRUE and szTextualSid is ignored. Otherwise,
|
|
fRouterPhoneBook must be FALSE and szTextualSid must contain the
|
|
textual sid of the logged on user.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FGetOurPhoneNumberFromPortName(
|
|
IN CHAR* szPortName,
|
|
OUT CHAR* szOurPhoneNumber,
|
|
IN BOOL fRouterPhoneBook,
|
|
IN CHAR* szTextualSid
|
|
)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
HKEY hKeyCallback;
|
|
BOOL fCloseHKeyCallback = FALSE;
|
|
|
|
HKEY hKey;
|
|
DWORD dwIndex;
|
|
DWORD dwSize;
|
|
FILETIME FileTime;
|
|
CHAR szCallbackNumber[RAS_MaxCallbackNumber + 1];
|
|
DWORD dwErr;
|
|
|
|
// The size has been obtained from DeviceAndPortFromPsz in noui.c:
|
|
CHAR szDeviceAndPort[RAS_MaxDeviceName + 2 + MAX_PORT_NAME + 1 + 1];
|
|
CHAR* pchStart;
|
|
CHAR* pchEnd;
|
|
CHAR* szCallback;
|
|
|
|
PPP_ASSERT(NULL != szPortName);
|
|
PPP_ASSERT(NULL != szOurPhoneNumber);
|
|
|
|
if (fRouterPhoneBook)
|
|
{
|
|
szCallback = BAP_KEY_SERVER_CALLBACK;
|
|
}
|
|
else
|
|
{
|
|
szCallback = BAP_KEY_CLIENT_CALLBACK;
|
|
}
|
|
|
|
fCloseHKeyCallback = FALSE;
|
|
if (fRouterPhoneBook)
|
|
{
|
|
dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szCallback, 0, KEY_READ,
|
|
&hKeyCallback);
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("RegOpenKeyEx on %s returned error %d", szCallback, dwErr);
|
|
goto LDone;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (NULL == szTextualSid)
|
|
{
|
|
BapTrace("Textual Sid is not known");
|
|
goto LDone;
|
|
}
|
|
|
|
dwErr = RegOpenKeyEx(HKEY_USERS, szTextualSid, 0, KEY_READ, &hKey);
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("RegOpenKeyEx on %s returned error %d", szTextualSid,
|
|
dwErr);
|
|
goto LDone;
|
|
}
|
|
|
|
dwErr = RegOpenKeyEx(hKey, szCallback, 0, KEY_READ, &hKeyCallback);
|
|
RegCloseKey(hKey);
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("RegOpenKeyEx on %s returned error %d", szCallback, dwErr);
|
|
goto LDone;
|
|
}
|
|
}
|
|
fCloseHKeyCallback = TRUE;
|
|
|
|
dwIndex = 0;
|
|
while (TRUE)
|
|
{
|
|
dwSize = sizeof(szDeviceAndPort);
|
|
dwErr = RegEnumKeyEx(hKeyCallback, dwIndex++,
|
|
szDeviceAndPort, &dwSize,
|
|
NULL, NULL, NULL, &FileTime);
|
|
|
|
if (ERROR_NO_MORE_ITEMS == dwErr)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (ERROR_MORE_DATA == dwErr)
|
|
{
|
|
BapTrace("The buffer is too small for key %d in %s",
|
|
dwIndex, szCallback);
|
|
continue;
|
|
}
|
|
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("RegEnumKeyEx on %s returned error %d",
|
|
szCallback, dwErr);
|
|
break;
|
|
}
|
|
|
|
pchEnd = szDeviceAndPort + strlen(szDeviceAndPort) - 1;
|
|
pchStart = pchEnd;
|
|
while (szDeviceAndPort < pchStart)
|
|
{
|
|
if ('(' == *pchStart)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
pchStart -= 1;
|
|
}
|
|
}
|
|
|
|
if ( (szDeviceAndPort < pchStart) && (pchStart < pchEnd)
|
|
&& ('(' == *pchStart) && (')' == *pchEnd))
|
|
{
|
|
*pchEnd = 0;
|
|
pchStart += 1;
|
|
}
|
|
else
|
|
{
|
|
BapTrace("Invalid DeviceAndPort %s in key %s",
|
|
szDeviceAndPort, szCallback);
|
|
continue;
|
|
}
|
|
|
|
if (!lstrcmpi(pchStart, szPortName))
|
|
{
|
|
*pchEnd = ')';
|
|
dwErr = RegOpenKeyEx(hKeyCallback, szDeviceAndPort, 0, KEY_READ,
|
|
&hKey);
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("RegOpenKeyEx on %s returned error %d", szDeviceAndPort,
|
|
dwErr);
|
|
break;
|
|
}
|
|
|
|
dwSize = RAS_MaxCallbackNumber + 1;
|
|
dwErr = RegQueryValueEx(hKey, BAP_VAL_NUMBER, NULL, NULL,
|
|
szCallbackNumber, &dwSize);
|
|
RegCloseKey(hKey);
|
|
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("RegQueryValueEx on %s\\%s failed. Error: %d",
|
|
szDeviceAndPort, BAP_VAL_NUMBER, dwErr);
|
|
break;
|
|
}
|
|
|
|
RemoveNonNumerals(szCallbackNumber);
|
|
|
|
if (szCallbackNumber[0])
|
|
{
|
|
lstrcpy(szOurPhoneNumber, szCallbackNumber);
|
|
fRet = TRUE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
LDone:
|
|
|
|
if (fCloseHKeyCallback)
|
|
{
|
|
RegCloseKey(hKeyCallback);
|
|
}
|
|
|
|
if (!fRet)
|
|
{
|
|
BapTrace("No callback number for port %s", szPortName);
|
|
}
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Writes a Phone-Delta in pbPhoneDelta using szOurPhoneNumber as the phone
|
|
number to send to the peer and szBasePhoneNumber as the "previously known
|
|
number". If the lengths of the szOurPhoneNumber and szBasePhoneNumber are
|
|
different, or if szBasePhoneNumber is NULL, it writes the entire
|
|
PhoneNumber into pbPhoneDelta. Otherwise, the unique portion of
|
|
szBasePhoneNumber is overwritten with X's so that the unique portion will
|
|
never decrease.
|
|
|
|
*pdwNumBytes contains the number of bytes the function can write in
|
|
pbPhoneDelta. On exit, it is decremented by the number of bytes actually
|
|
written.
|
|
|
|
NOTE: NOTE: NOTE: NOTE: NOTE:
|
|
|
|
If the function returns FALSE, nothing will be written in pbPhoneDelta and
|
|
*pdwNumBytes will be left unchanged.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FWritePhoneDelta(
|
|
IN CHAR* szOurPhoneNumber,
|
|
IN CHAR* szBasePhoneNumber,
|
|
OUT BYTE* pbPhoneDelta,
|
|
IN OUT DWORD* pdwNumBytes)
|
|
{
|
|
DWORD dwNumCharsPhoneNumber;
|
|
DWORD dwNumCharsBase = 0;
|
|
DWORD dwDeltaIndex;
|
|
DWORD dwTemp;
|
|
DWORD dwNumCharsUnique;
|
|
BOOL fRet = FALSE;
|
|
|
|
PPP_ASSERT(NULL != szOurPhoneNumber);
|
|
PPP_ASSERT(NULL != pbPhoneDelta);
|
|
PPP_ASSERT(NULL != pdwNumBytes);
|
|
|
|
dwNumCharsPhoneNumber = lstrlen(szOurPhoneNumber);
|
|
if (0 == dwNumCharsPhoneNumber)
|
|
{
|
|
BapTrace("szOurPhoneNumbers is an empty string");
|
|
goto LDone;
|
|
}
|
|
|
|
if (NULL != szBasePhoneNumber)
|
|
{
|
|
dwNumCharsBase = lstrlen(szBasePhoneNumber);
|
|
}
|
|
|
|
dwDeltaIndex = 0;
|
|
|
|
if ((NULL != szBasePhoneNumber) &&
|
|
(dwNumCharsPhoneNumber == dwNumCharsBase))
|
|
{
|
|
// Find the substring of szOurPhoneNumber that differs from
|
|
// szBasePhoneNumber.
|
|
|
|
while ((0 != szOurPhoneNumber[dwDeltaIndex]) &&
|
|
(szOurPhoneNumber[dwDeltaIndex] ==
|
|
szBasePhoneNumber[dwDeltaIndex]))
|
|
{
|
|
dwDeltaIndex++;
|
|
}
|
|
|
|
for (dwTemp = dwDeltaIndex; 0 != szBasePhoneNumber[dwTemp];
|
|
dwTemp++)
|
|
{
|
|
// We want to make sure that the Unique portion will increase
|
|
// each time, ie if we sent 3 unique digits last time, this time
|
|
// we should send atleast 3. This is because we don't know
|
|
// whether the peer will apply the phone delta to the first
|
|
// number received or the latest one.
|
|
|
|
szBasePhoneNumber[dwTemp] = 'X';
|
|
}
|
|
}
|
|
|
|
// The unique part of szOurPhoneNumber begins at
|
|
// szOurPhoneNumber[dwDeltaIndex].
|
|
|
|
dwNumCharsUnique = dwNumCharsPhoneNumber - dwDeltaIndex;
|
|
|
|
if (0 == dwNumCharsUnique)
|
|
{
|
|
// Other implementations may not be able to handle 0 Unique-Digits
|
|
dwNumCharsUnique = 1;
|
|
dwDeltaIndex -= 1;
|
|
}
|
|
|
|
#if 0
|
|
// Do not remove this code. It shows how we would have handled 0
|
|
// Unique-Digits.
|
|
if (0 == dwNumCharsUnique)
|
|
{
|
|
// szOurPhoneNumber and szBasePhoneNumber are the same.
|
|
|
|
if (1 > *pdwNumBytes)
|
|
{
|
|
BapTrace("No space in pbPhoneDelta");
|
|
return(FALSE);
|
|
}
|
|
|
|
// See BAPCB comments for an explanation of the 0xFF weirdness.
|
|
pbPhoneDelta[0] = 0xFF;
|
|
*pdwNumBytes -= 1;
|
|
|
|
return(TRUE);
|
|
}
|
|
#endif
|
|
|
|
RTASSERT(FAsciiDigits(szOurPhoneNumber + dwDeltaIndex,
|
|
dwNumCharsUnique));
|
|
|
|
// Our phone numbers should have no more than RAS_MaxPhoneNumber (128)
|
|
// digits.
|
|
PPP_ASSERT(0xFF >= dwNumCharsUnique);
|
|
|
|
if (dwNumCharsUnique + 4 > *pdwNumBytes)
|
|
{
|
|
BapTrace("Not enough space in pbPhoneDelta. Delta: %s. "
|
|
"Bytes available: %d",
|
|
szOurPhoneNumber + dwDeltaIndex, *pdwNumBytes);
|
|
|
|
goto LDone;
|
|
}
|
|
|
|
// We have a phone delta
|
|
fRet = TRUE;
|
|
|
|
// See the format for writing Phone-Deltas in the BAPCB documentation.
|
|
pbPhoneDelta[0] = (BYTE) dwNumCharsUnique;
|
|
pbPhoneDelta[1] = 0;
|
|
lstrcpy(pbPhoneDelta + 2, szOurPhoneNumber + dwDeltaIndex);
|
|
pbPhoneDelta[dwNumCharsUnique + 2] = 0;
|
|
pbPhoneDelta[dwNumCharsUnique + 3] = 0;
|
|
|
|
*pdwNumBytes -= dwNumCharsUnique + 4;
|
|
|
|
LDone:
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Reads the Phone-Delta in pbPhoneDelta into szPeerPhoneNumber using
|
|
szBasePhoneNumber as the "previously known number".
|
|
|
|
If szBasePhoneNumber is NULL, it writes only the Phone-Delta into
|
|
szPeerPhoneNumber.
|
|
|
|
If the Phone-Delta is larger than the szBasePhoneNumber, it writes only the
|
|
last strlen(szBasePhoneNumber) number of digits into szPeerPhoneNumber. If
|
|
szBasePhoneNumber is 882 5759, and the delta is 425 713 5748, we should
|
|
dial 713 5748, not the whole number.
|
|
|
|
If szBasePhoneNumber is not NULL and contains an empty string,
|
|
szPeerPhoneNumber is written to it.
|
|
|
|
It returns the number of bytes read from pbPhoneDelta in *pdwBytesRead.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FReadPhoneDelta(
|
|
OUT CHAR* szPeerPhoneNumber,
|
|
IN CHAR* szBasePhoneNumber,
|
|
IN BYTE* pbPhoneDelta,
|
|
OUT DWORD* pdwBytesRead)
|
|
{
|
|
DWORD dwNumCharsPhoneNumber;
|
|
DWORD dwNumCharsBase = 0;
|
|
DWORD dwNumCharsDelta;
|
|
DWORD dwDeltaIndex;
|
|
DWORD dwNumCharsUnique;
|
|
|
|
PPP_ASSERT(NULL != szPeerPhoneNumber);
|
|
PPP_ASSERT(NULL != pbPhoneDelta);
|
|
|
|
if (NULL != szBasePhoneNumber)
|
|
{
|
|
dwNumCharsBase = lstrlen(szBasePhoneNumber);
|
|
}
|
|
|
|
dwNumCharsDelta = pbPhoneDelta[0];
|
|
|
|
// FReadOptions() makes sure that the bytes in the Subscriber-Number are all
|
|
// ASCII digits.
|
|
|
|
if (0xFF == dwNumCharsDelta)
|
|
{
|
|
// Unique-Digits is 0. See BAPCB comments.
|
|
|
|
if (NULL != szBasePhoneNumber)
|
|
{
|
|
lstrcpy(szPeerPhoneNumber, szBasePhoneNumber);
|
|
*pdwBytesRead = 1;
|
|
return(TRUE);
|
|
}
|
|
else
|
|
{
|
|
BapTrace("Unique-Digits is 0, but there is no "
|
|
"\"previously known number\"");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else if (0 == dwNumCharsBase)
|
|
{
|
|
// Note that pbPhoneDelta contains only the unique digits part of the
|
|
// Subscriber-Number Sub-Option. The leading non unique digits sent by
|
|
// the peer are ignored. See the BAPCB comments.
|
|
|
|
lstrcpy(szPeerPhoneNumber, pbPhoneDelta + 2);
|
|
}
|
|
else
|
|
{
|
|
// If szBasePhoneNumber were NULL, we would have
|
|
// (0 == dwNumCharsBase) above
|
|
|
|
PPP_ASSERT(NULL != szBasePhoneNumber);
|
|
|
|
if (dwNumCharsDelta > dwNumCharsBase)
|
|
{
|
|
// If szBasePhoneNumber is 882 5759, and the peer sent us
|
|
// 425 713 5748, we should dial 713 5748, not the whole number.
|
|
lstrcpy(szPeerPhoneNumber,
|
|
pbPhoneDelta + 2 + dwNumCharsDelta - dwNumCharsBase);
|
|
}
|
|
else
|
|
{
|
|
lstrcpy(szPeerPhoneNumber, szBasePhoneNumber);
|
|
lstrcpy(szPeerPhoneNumber + dwNumCharsBase - dwNumCharsDelta,
|
|
pbPhoneDelta + 2);
|
|
}
|
|
}
|
|
|
|
if ( (NULL != szBasePhoneNumber)
|
|
&& (0 == szBasePhoneNumber[0]))
|
|
{
|
|
lstrcpy(szBasePhoneNumber, szPeerPhoneNumber);
|
|
}
|
|
|
|
*pdwBytesRead = 2 + lstrlen(pbPhoneDelta + 2) + 1;
|
|
*pdwBytesRead += lstrlen(pbPhoneDelta + *pdwBytesRead) + 1;
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
This function must only be called by clients or routers.
|
|
|
|
It tries to find a free link in the entry szEntryName in the phone book
|
|
szPhonebookPath. fCallOut is TRUE iff we will dial out on the link. fRouter
|
|
is TRUE iff we are a router. szTextualSid contains the textual sid of the
|
|
logged on user. It is required iff pbPhoneDelta is not NULL and fRouter is
|
|
FALSE.
|
|
|
|
If *pdwLinkType is 0, it doesn't care about the link type and sets
|
|
*pdwLinkType and *pdwLinkSpeed (link speed in kbps). Otherwise, the type of
|
|
the free link must match *pdwLinkType. The link type is the same as the
|
|
Link Type in the Link-Type BAP option: 1 for ISDN, 2 for X.25, and 4 for
|
|
modem.
|
|
|
|
If szPeerPhoneNumber is not NULL, it fills it up with the peer's phone
|
|
number (the number that we will have to dial). If pbPhoneDelta is not NULL,
|
|
it fills it up with one (!fRouter) or more (fRouter) Phone-Deltas (the
|
|
numbers that the peer will have to dial). Each Phone-Delta is calculated
|
|
with szBasePhoneNumber as the "previously known number". szBasePhoneNumber
|
|
MUST be NULL if we are not the server. A non-router client does not want
|
|
to do multiple RasPortListen()'s, and hence will send only one Phone-Delta.
|
|
|
|
If pdwSubEntryIndex is not NULL, the 1-based index of the subentry in
|
|
szEntryName that corresponds to the free link is put in *pdwSubEntryIndex.
|
|
If szPortName is not NULL, it fills it up with the name of the port
|
|
corresponding to the free link. szPortName is needed to do a
|
|
RasPortListen().
|
|
|
|
Sanity check: If *pdwLinkType is 0 (any link will do), pbPhoneDelta must be
|
|
NULL. Ie if we are NAK'ing a request, we mustn't send any Phone-Delta.
|
|
|
|
NOTE: NOTE: NOTE: NOTE: NOTE:
|
|
|
|
This function is very similar to FGetAvailableLinkNonRouterServer(). If you
|
|
change one, you probably need to change the other too.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FGetAvailableLinkClientOrRouter(
|
|
IN PCB* pPcbLocal,
|
|
IN CHAR* szPhonebookPath,
|
|
IN CHAR* szEntryName,
|
|
IN BOOL fCallOut,
|
|
IN BOOL fRouter,
|
|
IN CHAR* szTextualSid,
|
|
IN OUT DWORD* pdwLinkType,
|
|
IN OUT DWORD* pdwLinkSpeed,
|
|
OUT CHAR* szPeerPhoneNumber,
|
|
OUT DWORD* pdwSubEntryIndex,
|
|
OUT BYTE* pbPhoneDelta,
|
|
OUT CHAR* szPortName,
|
|
IN CHAR* szBasePhoneNumber
|
|
)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
DWORD dwErr;
|
|
|
|
RASMAN_PORT* pRasmanPort = NULL;
|
|
DWORD dwNumPorts;
|
|
|
|
RASENTRY* pRasEntry = NULL;
|
|
DWORD dwBufferSize;
|
|
|
|
DWORD dwSubEntryIndex;
|
|
RASSUBENTRY* pRasSubEntry = NULL;
|
|
|
|
DWORD dwPcbIndex;
|
|
|
|
DWORD dwPortIndex;
|
|
RASMAN_INFO RasmanInfo;
|
|
|
|
DWORD dwLinkType;
|
|
DWORD dwLinkSpeed;
|
|
CHAR szOurPhoneNumber[RAS_MaxCallbackNumber + 2]; // MULTI_SZ
|
|
DWORD dwNumChars;
|
|
BOOL fPortAvailable;
|
|
RASMAN_USAGE RasmanUsage;
|
|
BOOL fExitOuterFor;
|
|
|
|
PPP_ASSERT(NULL != szPhonebookPath);
|
|
PPP_ASSERT(NULL != szEntryName);
|
|
PPP_ASSERT(NULL != pdwLinkType);
|
|
PPP_ASSERT(NULL != pdwLinkSpeed);
|
|
|
|
// We do this in order to keep szOurPhoneNumber a MULTI_SZ
|
|
ZeroMemory(szOurPhoneNumber, RAS_MaxCallbackNumber + 2);
|
|
|
|
// We don't care about the link type. Any link will do.
|
|
if (0 == *pdwLinkType)
|
|
{
|
|
// Set *pdwLinkSpeed, in case we return an error.
|
|
*pdwLinkSpeed = 0;
|
|
}
|
|
|
|
if (!FEnumPorts(&pRasmanPort, &dwNumPorts))
|
|
{
|
|
goto LDone;
|
|
}
|
|
|
|
if (NULL != pbPhoneDelta)
|
|
{
|
|
// FWritePhoneDelta will write Phone-Delta's into pbPhoneDelta. We want
|
|
// the very next byte to be 0. (See BAPCB documentation).
|
|
ZeroMemory(pbPhoneDelta, BAP_PHONE_DELTA_SIZE + 1);
|
|
|
|
// The size (in bytes) of pbPhoneDelta available. Note that the last
|
|
// byte is reserved for the terminating 0, which is why we do not set
|
|
// dwNumChars to BAP_PHONE_DELTA_SIZE + 1;
|
|
dwNumChars = BAP_PHONE_DELTA_SIZE;
|
|
}
|
|
|
|
dwBufferSize = 0;
|
|
dwErr = RasGetEntryProperties(szPhonebookPath, szEntryName, NULL,
|
|
&dwBufferSize, NULL, NULL);
|
|
|
|
if (ERROR_BUFFER_TOO_SMALL != dwErr)
|
|
{
|
|
BapTrace("RasGetEntryProperties(%s, %s) returned error %d",
|
|
szPhonebookPath, szEntryName, dwErr);
|
|
goto LDone;
|
|
}
|
|
|
|
pRasEntry = LOCAL_ALLOC(LPTR, dwBufferSize);
|
|
if (NULL == pRasEntry)
|
|
{
|
|
BapTrace("FGetAvailableLinkClientOrRouter: Out of memory.");
|
|
goto LDone;
|
|
}
|
|
|
|
pRasEntry->dwSize = sizeof(RASENTRY);
|
|
dwErr = RasGetEntryProperties(szPhonebookPath, szEntryName, pRasEntry,
|
|
&dwBufferSize, NULL, NULL);
|
|
|
|
if (0 != dwErr)
|
|
{
|
|
BapTrace("RasGetEntryProperties(%s, %s) returned error %d",
|
|
szPhonebookPath, szEntryName, dwErr);
|
|
goto LDone;
|
|
}
|
|
|
|
fExitOuterFor = FALSE;
|
|
|
|
for (dwSubEntryIndex = 1;
|
|
dwSubEntryIndex <= pRasEntry->dwSubEntries;
|
|
dwSubEntryIndex++)
|
|
{
|
|
pRasSubEntry = NULL;
|
|
|
|
for (dwPcbIndex = 0;
|
|
dwPcbIndex < pPcbLocal->pBcb->dwPpcbArraySize;
|
|
dwPcbIndex++)
|
|
{
|
|
if ( (NULL != pPcbLocal->pBcb->ppPcb[dwPcbIndex])
|
|
&& (dwSubEntryIndex ==
|
|
pPcbLocal->pBcb->ppPcb[dwPcbIndex]->dwSubEntryIndex))
|
|
{
|
|
// This sub entry is already connected
|
|
goto LOuterForEnd;
|
|
}
|
|
}
|
|
|
|
dwBufferSize = 0;
|
|
dwErr = RasGetSubEntryProperties(szPhonebookPath, szEntryName,
|
|
dwSubEntryIndex, NULL, &dwBufferSize, NULL, NULL);
|
|
|
|
if (ERROR_BUFFER_TOO_SMALL != dwErr)
|
|
{
|
|
BapTrace("RasGetSubEntryProperties(%s, %s, %d) returned error %d",
|
|
szPhonebookPath, szEntryName, dwSubEntryIndex, dwErr);
|
|
goto LOuterForEnd;
|
|
}
|
|
|
|
pRasSubEntry = LOCAL_ALLOC(LPTR, dwBufferSize);
|
|
if (NULL == pRasSubEntry)
|
|
{
|
|
BapTrace("FGetAvailableLinkClientOrRouter: Out of memory.");
|
|
goto LOuterForEnd;
|
|
}
|
|
|
|
pRasSubEntry->dwSize = sizeof(RASSUBENTRY);
|
|
dwErr = RasGetSubEntryProperties(szPhonebookPath, szEntryName,
|
|
dwSubEntryIndex, pRasSubEntry, &dwBufferSize, NULL, NULL);
|
|
|
|
if (0 != dwErr)
|
|
{
|
|
BapTrace("RasGetSubEntryProperties(%s, %s, %d) returned error %d",
|
|
szPhonebookPath, szEntryName, dwSubEntryIndex, dwErr);
|
|
goto LOuterForEnd;
|
|
}
|
|
|
|
for (dwPortIndex = 0;
|
|
dwPortIndex < dwNumPorts;
|
|
dwPortIndex++)
|
|
{
|
|
// For each sub entry, find the port that corresponds to it. See if
|
|
// it is available.
|
|
|
|
if (lstrcmpi(pRasmanPort[dwPortIndex].P_DeviceName,
|
|
pRasSubEntry->szDeviceName))
|
|
{
|
|
// This is not the port we want
|
|
continue;
|
|
}
|
|
|
|
RasmanUsage = pRasmanPort[dwPortIndex].P_ConfiguredUsage;
|
|
|
|
if (fRouter)
|
|
{
|
|
// Make sure that the port is a router port.
|
|
|
|
if (!(RasmanUsage & CALL_ROUTER))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If fCallOut is TRUE, make sure that we can call out on this
|
|
// port.
|
|
|
|
if (fCallOut && !(RasmanUsage & CALL_OUT))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
dwErr = RasGetInfo(NULL, pRasmanPort[dwPortIndex].P_Handle,
|
|
&RasmanInfo);
|
|
|
|
fPortAvailable = FALSE;
|
|
|
|
if (ERROR_PORT_NOT_OPEN == dwErr)
|
|
{
|
|
/*
|
|
|
|
If fCallOut is TRUE, we will call RasDial().
|
|
ERROR_PORT_NOT_OPEN is good. Otherwise, if we are not the
|
|
router, we will call RasPortOpen() and RasPortListen(), so it
|
|
is fine. The port is unacceptable *iff* a router wants to
|
|
listen on it.
|
|
|
|
*/
|
|
|
|
fPortAvailable = fCallOut || !fRouter;
|
|
}
|
|
else if ((LISTENING == RasmanInfo.RI_ConnState) &&
|
|
((RasmanUsage & CALL_ROUTER) ||
|
|
(RasmanUsage & CALL_IN)))
|
|
{
|
|
/*
|
|
|
|
We can use the port if the server or the router is doing a
|
|
listen. We cannot use the port if it is in the LISTENING state
|
|
because a client called RasDial() on it and is expecting a
|
|
callback. If neither CALL_ROUTER nor CALL_IN is true, we know
|
|
that it is a client doing a listen. Otherwise, we don't know,
|
|
but we will assume that it is available and handle errors
|
|
later.
|
|
|
|
*/
|
|
|
|
fPortAvailable = TRUE;
|
|
}
|
|
|
|
if (!fPortAvailable)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!FGetLinkTypeAndSpeedFromRasmanPort(
|
|
pRasmanPort + dwPortIndex, &dwLinkType, &dwLinkSpeed))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (0 == *pdwLinkType)
|
|
{
|
|
*pdwLinkType = dwLinkType;
|
|
*pdwLinkSpeed = dwLinkSpeed;
|
|
}
|
|
else if (dwLinkType != *pdwLinkType)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (szPortName)
|
|
{
|
|
lstrcpy(szPortName, pRasmanPort[dwPortIndex].P_PortName);
|
|
}
|
|
|
|
if (pbPhoneDelta)
|
|
{
|
|
// If our phone number is requested and we cannot supply it, we
|
|
// must return FALSE.
|
|
|
|
if (!FGetOurPhoneNumberFromPortName(
|
|
pRasmanPort[dwPortIndex].P_PortName,
|
|
szOurPhoneNumber, fRouter, szTextualSid))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!FWritePhoneDelta(szOurPhoneNumber, szBasePhoneNumber,
|
|
pbPhoneDelta + BAP_PHONE_DELTA_SIZE - dwNumChars,
|
|
&dwNumChars))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (szPeerPhoneNumber)
|
|
{
|
|
lstrcpy(szPeerPhoneNumber, pRasSubEntry->szLocalPhoneNumber);
|
|
}
|
|
|
|
if (pdwSubEntryIndex)
|
|
{
|
|
*pdwSubEntryIndex = dwSubEntryIndex;
|
|
}
|
|
|
|
BapTrace("FGetAvailableLinkClientOrRouter: Portname is %s",
|
|
pRasmanPort[dwPortIndex].P_PortName);
|
|
fRet = TRUE;
|
|
|
|
if (!pbPhoneDelta || !fRouter)
|
|
{
|
|
// We don't want to collect all our Phone-Deltas.
|
|
fExitOuterFor = TRUE;
|
|
goto LOuterForEnd;
|
|
}
|
|
}
|
|
|
|
LOuterForEnd:
|
|
|
|
if (NULL != pRasSubEntry)
|
|
{
|
|
LOCAL_FREE(pRasSubEntry);
|
|
}
|
|
|
|
if (fExitOuterFor)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
LDone:
|
|
|
|
if (NULL != pRasmanPort)
|
|
{
|
|
LOCAL_FREE(pRasmanPort);
|
|
}
|
|
|
|
if (NULL != pRasEntry)
|
|
{
|
|
LOCAL_FREE(pRasEntry);
|
|
}
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
This function must only be called by servers that are not routers.
|
|
|
|
It tries to find a free link that the server can use. fCallOut is TRUE iff
|
|
we will dial out on the link. If *pdwLinkType is 0, it doesn't care about
|
|
the link type and sets *pdwLinkType and *pdwLinkSpeed (link speed in kbps).
|
|
Otherwise, the type of the free link must match *pdwLinkType. The link type
|
|
is the same as the Link Type in the Link-Type BAP option: 1 for ISDN, 2 for
|
|
X.25, and 4 for modem.
|
|
|
|
If fCallOut is TRUE, the handle of the port that the server will call out
|
|
on will be put in *phPort.
|
|
|
|
If pbPhoneDelta is not NULL, it fills it up with our Phone-Deltas (the
|
|
numbers that the peer can dial). Each Phone-Delta is calculated with
|
|
szBasePhoneNumber as the "previously known number". szBasePhoneNumber can
|
|
be NULL.
|
|
|
|
Sanity check: If *pdwLinkType is 0 (any link will do), pbPhoneDelta must be
|
|
NULL. Ie if we are NAK'ing a request, we mustn't send any Phone-Delta.
|
|
|
|
NOTE: NOTE: NOTE: NOTE: NOTE:
|
|
|
|
This function is very similar to FGetAvailableLinkClientOrRouter(). If you
|
|
change one, you probably need to change the other too.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FGetAvailableLinkNonRouterServer(
|
|
IN BOOL fCallOut,
|
|
IN OUT DWORD* pdwLinkType,
|
|
IN OUT DWORD* pdwLinkSpeed,
|
|
OUT HPORT* phPort,
|
|
OUT BYTE* pbPhoneDelta,
|
|
IN CHAR* szBasePhoneNumber
|
|
)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
DWORD dwErr;
|
|
|
|
RASMAN_PORT* pRasmanPort = NULL;
|
|
DWORD dwNumPorts;
|
|
|
|
DWORD dwPortIndex;
|
|
RASMAN_INFO RasmanInfo;
|
|
|
|
DWORD dwLinkType;
|
|
DWORD dwLinkSpeed;
|
|
CHAR szOurPhoneNumber[RAS_MaxCallbackNumber + 1];
|
|
DWORD dwNumChars;
|
|
BOOL fPortAvailable;
|
|
RASMAN_USAGE RasmanUsage;
|
|
|
|
PPP_ASSERT(NULL != pdwLinkType);
|
|
PPP_ASSERT(NULL != pdwLinkSpeed);
|
|
|
|
// We don't care about the link type. Any link will do.
|
|
if (0 == *pdwLinkType)
|
|
{
|
|
// Set *pdwLinkSpeed, in case we return an error.
|
|
|
|
// We shouldn't be sending a Phone-Delta if we are NAK'ing a
|
|
// Call-Request or Callback-Request and sending a Link-Type
|
|
PPP_ASSERT(NULL == pbPhoneDelta);
|
|
|
|
*pdwLinkSpeed = 0;
|
|
}
|
|
|
|
if (!FEnumPorts(&pRasmanPort, &dwNumPorts))
|
|
{
|
|
goto LDone;
|
|
}
|
|
|
|
if (NULL != pbPhoneDelta)
|
|
{
|
|
// FWritePhoneDelta will write Phone-Delta's into pbPhoneDelta. We want
|
|
// the very next byte to be 0. (See BAPCB documentation).
|
|
ZeroMemory(pbPhoneDelta, BAP_PHONE_DELTA_SIZE + 1);
|
|
|
|
// The size (in bytes) of pbPhoneDelta available. Note that the last
|
|
// byte is reserved for the terminating 0, which is why we do not set
|
|
// dwNumChars to BAP_PHONE_DELTA_SIZE + 1;
|
|
dwNumChars = BAP_PHONE_DELTA_SIZE;
|
|
}
|
|
|
|
for (dwPortIndex = 0; dwPortIndex < dwNumPorts; dwPortIndex++)
|
|
{
|
|
RasmanUsage = pRasmanPort[dwPortIndex].P_ConfiguredUsage;
|
|
|
|
// If fCallOut is TRUE, make sure that we can call out on this
|
|
// port. Else, make sure that we can accept calls on this port.
|
|
|
|
if ((fCallOut && !(RasmanUsage & CALL_OUT)) ||
|
|
(!fCallOut && !(RasmanUsage & CALL_IN)))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
dwErr = RasGetInfo(NULL, pRasmanPort[dwPortIndex].P_Handle, &RasmanInfo);
|
|
|
|
fPortAvailable = FALSE;
|
|
|
|
if (ERROR_PORT_NOT_OPEN == dwErr)
|
|
{
|
|
/*
|
|
|
|
If fCallOut is TRUE, we will open the port and call out, so
|
|
ERROR_PORT_NOT_OPEN is fine. Otherwise, the port is unacceptable.
|
|
|
|
*/
|
|
|
|
fPortAvailable = fCallOut;
|
|
}
|
|
else if ( NO_ERROR != dwErr)
|
|
{
|
|
continue;
|
|
}
|
|
else if ((LISTENING == RasmanInfo.RI_ConnState) &&
|
|
((RasmanUsage & CALL_ROUTER) ||
|
|
(RasmanUsage & CALL_IN)))
|
|
{
|
|
/*
|
|
|
|
We can use the port if the server or the router is doing a listen.
|
|
We cannot use the port if it is in the LISTENING state because
|
|
a client called RasDial() on it and is expecting a callback. If
|
|
neither CALL_ROUTER nor CALL_IN is true, we know that it is a
|
|
client doing a listen. Otherwise, we don't know, but we will
|
|
assume that it is available and handle errors later.
|
|
|
|
*/
|
|
|
|
fPortAvailable = TRUE;
|
|
}
|
|
|
|
if (!fPortAvailable)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!FGetLinkTypeAndSpeedFromRasmanPort(
|
|
pRasmanPort + dwPortIndex, &dwLinkType, &dwLinkSpeed))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (0 == *pdwLinkType)
|
|
{
|
|
*pdwLinkType = dwLinkType;
|
|
*pdwLinkSpeed = dwLinkSpeed;
|
|
}
|
|
else if (dwLinkType != *pdwLinkType)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (phPort)
|
|
{
|
|
*phPort = pRasmanPort[dwPortIndex].P_Handle;
|
|
}
|
|
|
|
if (pbPhoneDelta)
|
|
{
|
|
// If our phone number is requested and we cannot supply it, we
|
|
// must return FALSE.
|
|
|
|
if (!FGetOurPhoneNumberFromHPort(
|
|
pRasmanPort[dwPortIndex].P_Handle,
|
|
szOurPhoneNumber))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!FWritePhoneDelta(szOurPhoneNumber, szBasePhoneNumber,
|
|
pbPhoneDelta + BAP_PHONE_DELTA_SIZE - dwNumChars,
|
|
&dwNumChars))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
BapTrace("FGetAvailableLinkNonRouterServer: Portname is %s",
|
|
pRasmanPort[dwPortIndex].P_PortName);
|
|
fRet = TRUE;
|
|
|
|
if (!pbPhoneDelta)
|
|
{
|
|
// We don't want to collect all our Phone-Deltas.
|
|
break;
|
|
}
|
|
}
|
|
|
|
LDone:
|
|
|
|
if (NULL != pRasmanPort)
|
|
{
|
|
LOCAL_FREE(pRasmanPort);
|
|
}
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
If fServer is TRUE, it calls FGetAvailableLinkNonRouterServer() with the
|
|
appropriate arguments. Otherwise it calls FGetAvailableLinkClientOrRouter().
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FGetAvailableLink(
|
|
IN PCB* pPcbLocal,
|
|
IN BOOL fServer,
|
|
IN BOOL fRouter,
|
|
IN BOOL fCallOut,
|
|
IN CHAR* szPhonebookPath,
|
|
IN CHAR* szEntryName,
|
|
IN CHAR* szTextualSid,
|
|
IN OUT DWORD* pdwLinkType,
|
|
IN OUT DWORD* pdwLinkSpeed,
|
|
OUT CHAR* szPeerPhoneNumber,
|
|
OUT DWORD* pdwSubEntryIndex,
|
|
OUT HPORT* phPort,
|
|
OUT BYTE* pbPhoneDelta,
|
|
OUT CHAR* szPortName,
|
|
IN CHAR* szBasePhoneNumber
|
|
)
|
|
{
|
|
if (fServer && !fRouter)
|
|
{
|
|
return(FGetAvailableLinkNonRouterServer(
|
|
fCallOut,
|
|
pdwLinkType,
|
|
pdwLinkSpeed,
|
|
phPort,
|
|
pbPhoneDelta,
|
|
szBasePhoneNumber));
|
|
}
|
|
else
|
|
{
|
|
return(FGetAvailableLinkClientOrRouter(
|
|
pPcbLocal,
|
|
szPhonebookPath,
|
|
szEntryName,
|
|
fCallOut,
|
|
fRouter,
|
|
szTextualSid,
|
|
pdwLinkType,
|
|
pdwLinkSpeed,
|
|
szPeerPhoneNumber,
|
|
pdwSubEntryIndex,
|
|
pbPhoneDelta,
|
|
szPortName,
|
|
szBasePhoneNumber));
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
VOID
|
|
|
|
Description:
|
|
The PPP thread mustn't call RasDial. Otherwise, a deadlock will occur in
|
|
the following case. The user tries to hang up a connectoid from the UI.
|
|
RasHangUp acquires csStopLock, calls StopPPP, and waits for StopPPP to
|
|
return. Meanwhile, if the PPP thread calls RasDial, it will wait for
|
|
csStopLock.
|
|
|
|
*/
|
|
|
|
VOID
|
|
RasDialThreadFunc(
|
|
IN VOID* pVoid
|
|
)
|
|
{
|
|
RASDIAL_ARGS* pRasDialArgs = pVoid;
|
|
RASDIALPARAMS* pRasDialParams;
|
|
HRASCONN hRasConn = NULL;
|
|
HRASCONN hRasConnSubEntry = NULL;
|
|
PCB_WORK_ITEM* pWorkItem;
|
|
DWORD dwErr;
|
|
|
|
PPP_ASSERT(NULL != pRasDialArgs);
|
|
|
|
pRasDialParams = &(pRasDialArgs->RasDialParams);
|
|
|
|
BapTrace("Dialing %s using %s(%d)...",
|
|
pRasDialParams->szPhoneNumber,
|
|
pRasDialParams->szEntryName,
|
|
pRasDialParams->dwSubEntry);
|
|
|
|
DecodePw(pRasDialArgs->chSeed, pRasDialArgs->RasDialParams.szPassword);
|
|
|
|
dwErr = RasDial(
|
|
&(pRasDialArgs->RasDialExtensions),
|
|
pRasDialArgs->szPhonebookPath,
|
|
&(pRasDialArgs->RasDialParams),
|
|
2 /* dwNotifierType */,
|
|
NULL,
|
|
&hRasConn);
|
|
|
|
EncodePw(pRasDialArgs->chSeed, pRasDialArgs->RasDialParams.szPassword);
|
|
|
|
BapTrace(" ");
|
|
BapTrace("RasDial returned %d on HCONN 0x%x",
|
|
dwErr, pRasDialArgs->RasDialParams.dwCallbackId);
|
|
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
goto LDone;
|
|
}
|
|
|
|
// By this time, PPP has been negotiated on the new link and the new link
|
|
// has been bundled or not (if the user disconnected the connection). If it
|
|
// has not been bundled, then pRasDialArgs->hRasConn is invalid and
|
|
// RasGetSubEntryHandle will fail.
|
|
|
|
if (pRasDialArgs->fServerRouter)
|
|
{
|
|
hRasConnSubEntry = hRasConn;
|
|
}
|
|
else
|
|
{
|
|
dwErr = RasGetSubEntryHandle(pRasDialArgs->hRasConn,
|
|
pRasDialParams->dwSubEntry, &hRasConnSubEntry);
|
|
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("RasGetSubEntryHandle failed and returned %d", dwErr);
|
|
goto LDone;
|
|
}
|
|
}
|
|
|
|
LDone:
|
|
|
|
pWorkItem = (PCB_WORK_ITEM*) LOCAL_ALLOC(LPTR, sizeof(PCB_WORK_ITEM));
|
|
|
|
if (pWorkItem == NULL)
|
|
{
|
|
dwErr = GetLastError();
|
|
BapTrace("Couldn't allocate memory for ProcessCallResult");
|
|
}
|
|
else
|
|
{
|
|
// Inform the worker thread that we know the result of the
|
|
// call attempt.
|
|
pWorkItem->Process = ProcessCallResult;
|
|
pWorkItem->hConnection = (HCONN)
|
|
(pRasDialArgs->RasDialParams.dwCallbackId);
|
|
pWorkItem->PppMsg.BapCallResult.dwResult = dwErr;
|
|
pWorkItem->PppMsg.BapCallResult.hRasConn = hRasConnSubEntry;
|
|
InsertWorkItemInQ(pWorkItem);
|
|
}
|
|
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
if (NULL != hRasConnSubEntry)
|
|
{
|
|
// Perhaps we couldn't alloc a PCB_WORK_ITEM.
|
|
dwErr = RasHangUp(hRasConnSubEntry);
|
|
}
|
|
|
|
if (NULL != hRasConn)
|
|
{
|
|
dwErr = RasHangUp(hRasConn);
|
|
}
|
|
|
|
if (0 != dwErr)
|
|
{
|
|
BapTrace("RasHangup failed and returned %d", dwErr);
|
|
}
|
|
}
|
|
|
|
if (NULL != pRasDialArgs->pbEapInfo)
|
|
{
|
|
LOCAL_FREE(pRasDialArgs->pbEapInfo);
|
|
}
|
|
LOCAL_FREE(pRasDialArgs->szPhonebookPath);
|
|
LOCAL_FREE(pRasDialArgs);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Places a call to the peer. pBcbLocal represents the bundle that wants to
|
|
call.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FCall(
|
|
IN BCB* pBcbLocal
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
DWORD dwErr;
|
|
BAPCB* pBapCbLocal;
|
|
PPP_MESSAGE PppMsg;
|
|
BOOL fRouter;
|
|
BOOL fServer;
|
|
BOOL fClientOrRouter;
|
|
DWORD dwBytesRead;
|
|
PCB* pPcbLocal;
|
|
BOOL fRet = FALSE;
|
|
RASMAN_INFO RasmanInfo;
|
|
RASDIAL_ARGS* pRasDialArgs = NULL;
|
|
RASDIALPARAMS* pRasDialParams;
|
|
RASDIALEXTENSIONS* pRasDialExtensions;
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
|
|
pBapCbLocal = &(pBcbLocal->BapCb);
|
|
|
|
pRasDialArgs = LOCAL_ALLOC(LPTR, sizeof(RASDIAL_ARGS));
|
|
if (NULL == pRasDialArgs)
|
|
{
|
|
BapTrace("Out of memory. Can't call on HCONN 0x%x",
|
|
pBcbLocal->hConnection);
|
|
goto LDone;
|
|
}
|
|
pRasDialArgs->chSeed = pBcbLocal->chSeed;
|
|
pRasDialParams = &(pRasDialArgs->RasDialParams);
|
|
pRasDialExtensions = &(pRasDialArgs->RasDialExtensions);
|
|
|
|
fServer = (pBcbLocal->fFlags & BCBFLAG_IS_SERVER) != 0;
|
|
fRouter =
|
|
(ROUTER_IF_TYPE_FULL_ROUTER == pBcbLocal->InterfaceInfo.IfType);
|
|
fClientOrRouter = !fServer || fRouter;
|
|
|
|
ZeroMemory(&PppMsg, sizeof(PppMsg));
|
|
|
|
if (!pBapCbLocal->fPeerSuppliedPhoneNumber)
|
|
{
|
|
PPP_ASSERT(fClientOrRouter);
|
|
pRasDialParams->szPhoneNumber[0] = 0;
|
|
}
|
|
else
|
|
{
|
|
PPP_ASSERT(NULL != pBapCbLocal->pbPhoneDeltaRemote);
|
|
|
|
if (!FReadPhoneDelta(
|
|
fClientOrRouter ?
|
|
pRasDialParams->szPhoneNumber :
|
|
PppMsg.ExtraInfo.BapCallbackRequest.szCallbackNumber,
|
|
fServer ? pBapCbLocal->szClientPhoneNumber :
|
|
pBapCbLocal->szServerPhoneNumber,
|
|
pBapCbLocal->pbPhoneDeltaRemote +
|
|
pBapCbLocal->dwPhoneDeltaRemoteOffset,
|
|
&dwBytesRead))
|
|
{
|
|
goto LDone;
|
|
}
|
|
else
|
|
{
|
|
pBapCbLocal->dwPhoneDeltaRemoteOffset += dwBytesRead;
|
|
}
|
|
}
|
|
|
|
pPcbLocal = GetPCBPointerFromBCB(pBcbLocal);
|
|
if (NULL == pPcbLocal)
|
|
{
|
|
BapTrace("FCall: No links in HCONN 0x%x!", pBcbLocal->hConnection);
|
|
goto LDone;
|
|
}
|
|
|
|
if (!fClientOrRouter)
|
|
{
|
|
// Non-router server
|
|
// Don't call RasDial. Instead ask Ddm to call
|
|
|
|
PppMsg.hPort = pBapCbLocal->hPort;
|
|
PppMsg.dwMsgId = PPPDDMMSG_BapCallbackRequest;
|
|
|
|
PppMsg.ExtraInfo.BapCallbackRequest.hConnection =
|
|
pBcbLocal->hConnection;
|
|
|
|
PppConfigInfo.SendPPPMessageToDdm(&PppMsg);
|
|
|
|
BapTrace("Dialing %s on port %d...",
|
|
PppMsg.ExtraInfo.BapCallbackRequest.szCallbackNumber,
|
|
pBapCbLocal->hPort);
|
|
}
|
|
else
|
|
{
|
|
dwErr = RasGetInfo(NULL, pPcbLocal->hPort, &RasmanInfo);
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("RasGetInfo failed on hPort %d. Error: %d",
|
|
pPcbLocal->hPort, dwErr);
|
|
goto LDone;
|
|
}
|
|
|
|
pRasDialArgs->hRasConn = RasmanInfo.RI_ConnectionHandle;
|
|
|
|
pRasDialExtensions->dwSize = sizeof(RASDIALEXTENSIONS);
|
|
|
|
if (fRouter)
|
|
{
|
|
pRasDialArgs->fServerRouter = fServer;
|
|
pRasDialExtensions->dwfOptions = RDEOPT_Router;
|
|
CopyMemory(&(pRasDialArgs->InterfaceInfo),
|
|
&(pBcbLocal->InterfaceInfo), sizeof(PPP_INTERFACE_INFO));
|
|
pRasDialExtensions->reserved
|
|
= (ULONG_PTR)&(pRasDialArgs->InterfaceInfo);
|
|
}
|
|
|
|
if ( (NULL != pBcbLocal->pCustomAuthUserData)
|
|
&& (0 != pBcbLocal->pCustomAuthUserData->cbCustomAuthData))
|
|
{
|
|
pRasDialArgs->pbEapInfo = LOCAL_ALLOC(LPTR,
|
|
pBcbLocal->pCustomAuthUserData->cbCustomAuthData);
|
|
if (NULL == pRasDialArgs->pbEapInfo)
|
|
{
|
|
BapTrace("Out of memory. Can't call on HCONN 0x%x",
|
|
pBcbLocal->hConnection);
|
|
goto LDone;
|
|
}
|
|
CopyMemory(pRasDialArgs->pbEapInfo,
|
|
pBcbLocal->pCustomAuthUserData->abCustomAuthData,
|
|
pBcbLocal->pCustomAuthUserData->cbCustomAuthData);
|
|
|
|
pRasDialExtensions->RasEapInfo.dwSizeofEapInfo =
|
|
pBcbLocal->pCustomAuthUserData->cbCustomAuthData;
|
|
pRasDialExtensions->RasEapInfo.pbEapInfo =
|
|
pRasDialArgs->pbEapInfo;
|
|
|
|
if (pBcbLocal->fFlags & BCBFLAG_LOGON_USER_DATA)
|
|
{
|
|
pRasDialExtensions->dwfOptions = RDEOPT_NoUser;
|
|
}
|
|
}
|
|
|
|
pRasDialParams->dwSize = sizeof(RASDIALPARAMS);
|
|
lstrcpy(pRasDialParams->szEntryName, pBcbLocal->szEntryName);
|
|
lstrcpy(pRasDialParams->szUserName, pBcbLocal->szLocalUserName);
|
|
lstrcpy(pRasDialParams->szPassword, pBcbLocal->szPassword);
|
|
lstrcpy(pRasDialParams->szDomain, pBcbLocal->szLocalDomain);
|
|
pRasDialParams->dwCallbackId = HandleToUlong(pBcbLocal->hConnection);
|
|
pRasDialParams->dwSubEntry = pBapCbLocal->dwSubEntryIndex;
|
|
|
|
pRasDialArgs->szPhonebookPath =
|
|
LOCAL_ALLOC(LPTR, strlen(pBcbLocal->szPhonebookPath) + 1);
|
|
if (NULL == pRasDialArgs->szPhonebookPath)
|
|
{
|
|
BapTrace("Out of memory. Can't call on HCONN 0x%x",
|
|
pBcbLocal->hConnection);
|
|
goto LDone;
|
|
}
|
|
lstrcpy(pRasDialArgs->szPhonebookPath, pBcbLocal->szPhonebookPath);
|
|
|
|
Status = RtlQueueWorkItem( RasDialThreadFunc, pRasDialArgs,
|
|
WT_EXECUTEDEFAULT);
|
|
|
|
if (STATUS_SUCCESS != Status)
|
|
{
|
|
BapTrace("RtlQueueWorkItem failed and returned %d", Status);
|
|
goto LDone;
|
|
}
|
|
|
|
pRasDialArgs = NULL; // This will be freed by RasDialThreadFunc
|
|
}
|
|
|
|
fRet = TRUE;
|
|
|
|
LDone:
|
|
|
|
if (NULL != pRasDialArgs)
|
|
{
|
|
if (NULL != pRasDialArgs->szPhonebookPath)
|
|
{
|
|
LOCAL_FREE(pRasDialArgs->szPhonebookPath);
|
|
}
|
|
|
|
if (NULL != pRasDialArgs->pbEapInfo)
|
|
{
|
|
LOCAL_FREE(pRasDialArgs->pbEapInfo);
|
|
}
|
|
|
|
LOCAL_FREE(pRasDialArgs);
|
|
}
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
pBcbLocal represents the bundle that wants to call. pBapCbRemote is filled
|
|
with the options sent by the peer. This function allocates
|
|
pbPhoneDeltaRemote and sets dwPhoneDeltaRemoteOffset and
|
|
fPeerSuppliedPhoneNumber in pBapCbLocal before calling FCall to do the
|
|
actual work.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FCallInitial(
|
|
IN BCB* pBcbLocal,
|
|
IN BAPCB* pBapCbRemote
|
|
)
|
|
{
|
|
BAPCB* pBapCbLocal;
|
|
BOOL fCall;
|
|
BOOL fRet;
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
PPP_ASSERT(NULL != pBapCbRemote);
|
|
|
|
pBapCbLocal = &(pBcbLocal->BapCb);
|
|
|
|
// If the peer is responding to our Call-Request and we had sent the
|
|
// No-Phone-Number-Needed option, we don't need any phone number. In all
|
|
// other cases, the peer must have supplied a phone number.
|
|
|
|
fCall = (BAP_PACKET_CALL_RESP == pBapCbRemote->dwType);
|
|
pBapCbLocal->fPeerSuppliedPhoneNumber =
|
|
!(fCall && (pBapCbLocal->dwOptions & BAP_N_NO_PH_NEEDED));
|
|
|
|
// pbPhoneDeltaRemote is initially NULL and we always set it to NULL after
|
|
// we deallocate it.
|
|
PPP_ASSERT(NULL == pBapCbLocal->pbPhoneDeltaRemote);
|
|
|
|
if (pBapCbLocal->fPeerSuppliedPhoneNumber)
|
|
{
|
|
pBapCbLocal->pbPhoneDeltaRemote =
|
|
LOCAL_ALLOC(LPTR, BAP_PHONE_DELTA_SIZE + 1);
|
|
|
|
if (NULL == pBapCbLocal->pbPhoneDeltaRemote)
|
|
{
|
|
BapTrace("Out of memory");
|
|
fRet = FALSE;
|
|
goto LDone;
|
|
}
|
|
|
|
if (NULL != pBapCbLocal->pbPhoneDeltaRemote)
|
|
{
|
|
CopyMemory(pBapCbLocal->pbPhoneDeltaRemote,
|
|
pBapCbRemote->pbPhoneDelta,
|
|
BAP_PHONE_DELTA_SIZE + 1);
|
|
pBapCbLocal->dwPhoneDeltaRemoteOffset = 0;
|
|
|
|
// FReadOptions() makes sure that there is at least one Phone-Delta
|
|
PPP_ASSERT(0 != pBapCbLocal->pbPhoneDeltaRemote[0]);
|
|
}
|
|
}
|
|
|
|
fRet = FCall(pBcbLocal);
|
|
|
|
if (!fRet)
|
|
{
|
|
if (NULL != pBapCbLocal->pbPhoneDeltaRemote)
|
|
{
|
|
LOCAL_FREE(pBapCbLocal->pbPhoneDeltaRemote);
|
|
}
|
|
pBapCbLocal->pbPhoneDeltaRemote = NULL;
|
|
}
|
|
else
|
|
{
|
|
// BapEventCallResult will get called at some point, and we will free
|
|
// pBapCbLocal->pbPhoneDeltaRemote.
|
|
}
|
|
|
|
LDone:
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Listens for incoming calls on the port named szPortName. dwSubEntryIndex is
|
|
the index of the phonebook sub entry that corresponds to that port.
|
|
pPcbLocal is any PCB in the bbundle that wants to do the listen. This
|
|
function should be called by non-router clients only.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FListenForCall(
|
|
IN CHAR* szPortName,
|
|
IN DWORD dwSubEntryIndex,
|
|
IN PCB* pPcbLocal
|
|
)
|
|
{
|
|
DWORD dwErr;
|
|
HPORT hPort;
|
|
BOOL fCloseHPort = FALSE;
|
|
PCB* pPcbOther;
|
|
PCB* pPcbNew = NULL;
|
|
DWORD dwIndex;
|
|
RASMAN_INFO RasmanInfo;
|
|
BOOL fRet = FALSE;
|
|
HCONN hConnection;
|
|
|
|
PPP_ASSERT(NULL != szPortName);
|
|
PPP_ASSERT(NULL != pPcbLocal);
|
|
|
|
hConnection = pPcbLocal->pBcb->hConnection;
|
|
|
|
dwErr = RasGetInfo(NULL, pPcbLocal->hPort, &RasmanInfo);
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("RasGetInfo failed on hPort %d. Error: %d",
|
|
pPcbLocal->hPort, dwErr);
|
|
goto LDone;
|
|
}
|
|
|
|
pPcbNew = (PCB *)LOCAL_ALLOC(LPTR, sizeof(PCB));
|
|
if (NULL == pPcbNew)
|
|
{
|
|
BapTrace("Out of memory. Can't accept a call on HCONN 0x%x",
|
|
hConnection);
|
|
goto LDone;
|
|
}
|
|
|
|
dwErr = AllocateAndInitBcb(pPcbNew);
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("Out of memory. Can't accept a call on HCONN 0x%x",
|
|
hConnection);
|
|
goto LDone;
|
|
}
|
|
|
|
dwErr = RasPortOpen(szPortName, &hPort, NULL /* notifier */);
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("RasPortOpen failed on HCONN 0x%x. Error: %d",
|
|
hConnection, dwErr);
|
|
goto LDone;
|
|
}
|
|
fCloseHPort = TRUE;
|
|
|
|
pPcbOther = GetPCBPointerFromhPort(hPort);
|
|
|
|
if (NULL != pPcbOther)
|
|
{
|
|
BapTrace("hPort %d not cleaned up yet", hPort);
|
|
goto LDone;
|
|
}
|
|
|
|
dwErr = RasAddConnectionPort(RasmanInfo.RI_ConnectionHandle, hPort,
|
|
dwSubEntryIndex);
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("RasAddConnectionPort failed with hPort %d and HRASCONN 0x%x. "
|
|
"Error: %d",
|
|
hPort, RasmanInfo.RI_ConnectionHandle, dwErr);
|
|
goto LDone;
|
|
}
|
|
|
|
dwIndex = HashPortToBucket(hPort);
|
|
|
|
dwErr = RasPortListen(hPort, PppConfigInfo.dwBapListenTimeoutSeconds,
|
|
INVALID_HANDLE_VALUE);
|
|
if (NO_ERROR != dwErr && PENDING != dwErr)
|
|
{
|
|
BapTrace("RasPortListen failed on HCONN 0x%x. Error: %d",
|
|
hConnection, dwErr);
|
|
goto LDone;
|
|
}
|
|
|
|
BapTrace("RasPortListen called on hPort %d for HCONN 0x%x",
|
|
hPort, hConnection);
|
|
|
|
pPcbNew->hPort = hPort;
|
|
pPcbNew->hConnection = hConnection;
|
|
pPcbNew->fFlags = PCBFLAG_PORT_IN_LISTENING_STATE;
|
|
lstrcpy(pPcbNew->szPortName, szPortName);
|
|
|
|
// Insert NewPcb into PCB hash table
|
|
PppLog(2, "Inserting port in bucket # %d", dwIndex);
|
|
pPcbNew->pNext = PcbTable.PcbBuckets[dwIndex].pPorts;
|
|
PcbTable.PcbBuckets[dwIndex].pPorts = pPcbNew;
|
|
|
|
fRet = TRUE;
|
|
|
|
pPcbLocal->pBcb->fFlags |= BCBFLAG_LISTENING;
|
|
|
|
LDone:
|
|
|
|
if (!fRet)
|
|
{
|
|
if (NULL != pPcbNew)
|
|
{
|
|
DeallocateAndRemoveBcbFromTable(pPcbNew->pBcb);
|
|
LOCAL_FREE(pPcbNew);
|
|
}
|
|
|
|
if (fCloseHPort)
|
|
{
|
|
RasPortClose(hPort);
|
|
}
|
|
}
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: We are willing to add a link to the bundle
|
|
FALSE: No more links in the bundle right now
|
|
|
|
Description:
|
|
Considers the bandwidth utilization on the bundle represented by pBcbLocal
|
|
and says whether the BAP policy allows us to add another link.
|
|
|
|
When the server receives a call[back] request, it will ACK if the
|
|
utilization is more than the lower threshold for the sample period and the
|
|
user's max link limit has not been reached. Otherwise, it will NAK.
|
|
|
|
When a client receives a call[back] request, it will ACK if the utilization
|
|
is more than the upper threshold for the sample period. Otherwise, it will
|
|
NAK.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FOkToAddLink(
|
|
IN BCB * pBcbLocal
|
|
)
|
|
{
|
|
PCB* pPcbLocal;
|
|
RAS_GET_BANDWIDTH_UTILIZATION Util;
|
|
DWORD dwLowThreshold;
|
|
DWORD dwHighThreshold;
|
|
DWORD dwUpPeriod;
|
|
DWORD dwDownPeriod;
|
|
DWORD dwErr;
|
|
|
|
return(TRUE);
|
|
#if 0
|
|
pPcbLocal = GetPCBPointerFromBCB(pBcbLocal);
|
|
if (NULL == pPcbLocal)
|
|
{
|
|
BapTrace("FOkToAddLink: No links in HCONN 0x%x!",
|
|
pBcbLocal->hConnection);
|
|
return(FALSE);
|
|
}
|
|
|
|
dwErr = RasGetBandwidthUtilization(pPcbLocal->hPort, &Util);
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("RasGetBandwidthUtilization failed and returned %d", dwErr);
|
|
return(FALSE);
|
|
}
|
|
|
|
dwDownPeriod = pBcbLocal->BapParams.dwHangUpExtraSampleSeconds;
|
|
dwUpPeriod = pBcbLocal->BapParams.dwDialExtraSampleSeconds;
|
|
|
|
BapTrace("Utilization: "
|
|
"%d sec: (Xmit: %d%%, Recv: %d%%), "
|
|
"%d sec: (Xmit: %d%%, Recv: %d%%)",
|
|
dwUpPeriod, Util.ulUpperXmitUtil, Util.ulUpperRecvUtil,
|
|
dwDownPeriod, Util.ulLowerXmitUtil, Util.ulLowerRecvUtil);
|
|
|
|
dwLowThreshold = pBcbLocal->BapParams.dwHangUpExtraPercent;
|
|
dwHighThreshold = pBcbLocal->BapParams.dwDialExtraPercent;
|
|
|
|
if (pBcbLocal->fFlags & BCBFLAG_IS_SERVER)
|
|
{
|
|
if ( (Util.ulLowerXmitUtil > dwLowThreshold)
|
|
|| (Util.ulLowerRecvUtil > dwLowThreshold))
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( (Util.ulUpperXmitUtil > dwHighThreshold)
|
|
|| (Util.ulUpperRecvUtil > dwHighThreshold))
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
return(FALSE);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: We are willing to drop a link from the bundle
|
|
FALSE: We need all the links in the bundle
|
|
|
|
Description:
|
|
Considers the bandwidth utilization on the bundle represented by pBcbLocal
|
|
and says whether the BAP policy allows us to drop a link.
|
|
|
|
When the server receives a drop request, it will always ACK.
|
|
|
|
When a client receives a drop request, it will ACK if the utilization is
|
|
less than the lower threshold for the sample period. Otherwise, it will NAK.
|
|
*/
|
|
|
|
BOOL
|
|
FOkToDropLink(
|
|
IN BCB * pBcbLocal,
|
|
IN BAPCB * pBapCbRemote
|
|
)
|
|
{
|
|
PCB* pPcbLocal;
|
|
RAS_GET_BANDWIDTH_UTILIZATION Util;
|
|
DWORD dwLowThreshold;
|
|
DWORD dwUpPeriod;
|
|
DWORD dwDownPeriod;
|
|
DWORD dwErr;
|
|
|
|
if (pBcbLocal->fFlags & BCBFLAG_IS_SERVER)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
pPcbLocal = GetPCBPointerFromBCB(pBcbLocal);
|
|
if (NULL == pPcbLocal)
|
|
{
|
|
BapTrace("FOkToAddLink: No links in HCONN 0x%x!",
|
|
pBcbLocal->hConnection);
|
|
return(FALSE);
|
|
}
|
|
|
|
dwErr = RasGetBandwidthUtilization(pPcbLocal->hPort, &Util);
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("RasGetBandwidthUtilization failed and returned %d", dwErr);
|
|
return(FALSE);
|
|
}
|
|
|
|
dwDownPeriod = pBcbLocal->BapParams.dwHangUpExtraSampleSeconds;
|
|
dwUpPeriod = pBcbLocal->BapParams.dwDialExtraSampleSeconds;
|
|
|
|
BapTrace("Utilization: "
|
|
"%d sec: (Xmit: %d%%, Recv: %d%%), "
|
|
"%d sec: (Xmit: %d%%, Recv: %d%%)",
|
|
dwUpPeriod, Util.ulUpperXmitUtil, Util.ulUpperRecvUtil,
|
|
dwDownPeriod, Util.ulLowerXmitUtil, Util.ulLowerRecvUtil);
|
|
|
|
dwLowThreshold = pBcbLocal->BapParams.dwHangUpExtraPercent;
|
|
|
|
if ( (Util.ulLowerXmitUtil < dwLowThreshold)
|
|
&& (Util.ulLowerRecvUtil < dwLowThreshold))
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Upper limit reached
|
|
FALSE: Upper limit not reached
|
|
|
|
Description:
|
|
Returns TRUE iff we can add another link to the multilink bundle
|
|
represented by pBclLocal. This function is used to Full-Nak a
|
|
Call[back]-Request.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FUpperLimitReached(
|
|
IN BCB * pBcbLocal
|
|
)
|
|
{
|
|
if (NumLinksInBundle(pBcbLocal) >= pBcbLocal->dwMaxLinksAllowed)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Fills in some of the fields of pBcbLocal->BapCb (our BapCb) by considering
|
|
pBapCbRemote (the BapCb sent by the peer). dwPacketType is the type of
|
|
packet that we want to send.
|
|
|
|
For all packet types:
|
|
dwType = dwPacketType
|
|
dwOptions = the options (see BAP_N_*), whose values have been set
|
|
|
|
BAP_PACKET_CALL_REQ:
|
|
dwLinkType, dwLinkSpeed
|
|
|
|
BAP_PACKET_CALL_RESP:
|
|
dwLink-Type+, pbPhoneDelta+
|
|
|
|
BAP_PACKET_CALLBACK_REQ:
|
|
dwLinkType, dwLinkSpeed, pbPhoneDelta
|
|
|
|
BAP_PACKET_CALLBACK_RESP:
|
|
dwLink-Type+
|
|
|
|
BAP_PACKET_DROP_REQ:
|
|
dwLinkDiscriminator
|
|
|
|
+ indicates that the field may not be filled in.
|
|
*/
|
|
|
|
BOOL
|
|
FFillBapCb(
|
|
IN DWORD dwPacketType,
|
|
OUT BCB* pBcbLocal,
|
|
IN BAPCB* pBapCbRemote
|
|
)
|
|
{
|
|
DWORD dwOptions = 0;
|
|
BOOL fResult = TRUE;
|
|
BOOL fServer;
|
|
BOOL fRouter;
|
|
PCB* pPcbLocal;
|
|
LCPCB* pLcpCb;
|
|
BAPCB* pBapCbLocal;
|
|
BOOL fCall;
|
|
BOOL fGetOurPhoneNumber;
|
|
DWORD dwLength;
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
pBapCbLocal = &(pBcbLocal->BapCb);
|
|
PPP_ASSERT(BAP_STATE_INITIAL == pBapCbLocal->BapState);
|
|
|
|
if (((BAP_PACKET_CALL_REQ == dwPacketType) &&
|
|
(pBcbLocal->fFlags & BCBFLAG_PEER_CANT_ACCEPT_CALLS)) ||
|
|
((BAP_PACKET_CALLBACK_REQ == dwPacketType) &&
|
|
(pBcbLocal->fFlags & BCBFLAG_PEER_CANT_CALL)))
|
|
{
|
|
BapTrace("FFillBapCb: Peer rejects %s",
|
|
BAP_PACKET_CALL_REQ == dwPacketType ? "Call-Requests" :
|
|
"Callback-Requests");
|
|
fResult = FALSE;
|
|
goto LDone;
|
|
}
|
|
|
|
pPcbLocal = GetPCBPointerFromBCB(pBcbLocal);
|
|
if (NULL == pPcbLocal)
|
|
{
|
|
BapTrace("FFillBapCb: No links in HCONN 0x%x!", pBcbLocal->hConnection);
|
|
fResult = FALSE;
|
|
goto LDone;
|
|
}
|
|
|
|
fServer = (pBcbLocal->fFlags & BCBFLAG_IS_SERVER) != 0;
|
|
fRouter =
|
|
(ROUTER_IF_TYPE_FULL_ROUTER == pBcbLocal->InterfaceInfo.IfType);
|
|
|
|
if (dwPacketType == BAP_PACKET_CALL_REQ ||
|
|
dwPacketType == BAP_PACKET_CALLBACK_REQ ||
|
|
dwPacketType == BAP_PACKET_CALL_RESP ||
|
|
dwPacketType == BAP_PACKET_CALLBACK_RESP)
|
|
{
|
|
if (FUpperLimitReached(pBcbLocal))
|
|
{
|
|
BapTrace("FFillBapCb: Link limit reached on HCONN 0x%x: %d",
|
|
pBcbLocal->hConnection,
|
|
pBcbLocal->dwMaxLinksAllowed);
|
|
fResult = FALSE;
|
|
goto LDone;
|
|
}
|
|
}
|
|
|
|
switch(dwPacketType)
|
|
{
|
|
case BAP_PACKET_CALL_REQ:
|
|
case BAP_PACKET_CALLBACK_REQ:
|
|
|
|
PPP_ASSERT(!fServer);
|
|
|
|
fCall = (BAP_PACKET_CALL_REQ == dwPacketType);
|
|
|
|
if (pBapCbRemote != NULL)
|
|
{
|
|
// The peer NAK'ed our Call-Request or Callback-Request and
|
|
// specified a different link type in the NAK.
|
|
|
|
pBapCbLocal->dwLinkType = pBapCbRemote->dwLinkType;
|
|
pBapCbLocal->dwLinkSpeed = pBapCbRemote->dwLinkSpeed;
|
|
}
|
|
else
|
|
{
|
|
// We don't have any link type preference
|
|
|
|
pBapCbLocal->dwLinkType = 0;
|
|
}
|
|
|
|
if (!FGetAvailableLinkClientOrRouter(
|
|
pPcbLocal,
|
|
pBcbLocal->szPhonebookPath,
|
|
pBcbLocal->szEntryName,
|
|
fCall,
|
|
fRouter,
|
|
pBcbLocal->szTextualSid,
|
|
&(pBapCbLocal->dwLinkType),
|
|
&(pBapCbLocal->dwLinkSpeed),
|
|
fCall ? pBapCbLocal->szPeerPhoneNumber : NULL,
|
|
&(pBapCbLocal->dwSubEntryIndex),
|
|
fCall ? NULL : pBapCbLocal->pbPhoneDelta,
|
|
fCall ? NULL : pBapCbLocal->szPortName,
|
|
NULL /* szBasePhoneNumber */))
|
|
{
|
|
BapTrace("FFillBapCb: Requested link type not available");
|
|
fResult = FALSE;
|
|
goto LDone;
|
|
}
|
|
|
|
dwOptions = BAP_N_LINK_TYPE;
|
|
|
|
if (fCall)
|
|
{
|
|
if (pBapCbLocal->szPeerPhoneNumber[0])
|
|
{
|
|
dwOptions |= BAP_N_NO_PH_NEEDED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If we ask for our phone number, FGetAvailableLinkClientOrRouter()
|
|
// must provide it or return FALSE
|
|
PPP_ASSERT(pBapCbLocal->pbPhoneDelta[0]);
|
|
|
|
dwOptions |= BAP_N_PHONE_DELTA;
|
|
}
|
|
|
|
break;
|
|
|
|
case BAP_PACKET_CALL_RESP:
|
|
case BAP_PACKET_CALLBACK_RESP:
|
|
|
|
PPP_ASSERT(NULL != pBapCbRemote);
|
|
|
|
fCall = (BAP_PACKET_CALL_RESP == dwPacketType);
|
|
|
|
// We need to send our phone number to the peer if we are responding to
|
|
// a Call-Request and the peer has not sent the No-Phone-Number-Needed
|
|
// option.
|
|
fGetOurPhoneNumber = fCall &&
|
|
!(pBapCbRemote->dwOptions & BAP_N_NO_PH_NEEDED);
|
|
|
|
// Case nRS: fServer && !fRouter (Non-Router Servers)
|
|
// Case CR: !fServer || fRouter (Clients and Routers)
|
|
// Case SR: fServer || fRouter (Servers and Routers)
|
|
|
|
if (FGetAvailableLink(
|
|
pPcbLocal,
|
|
fServer,
|
|
fRouter,
|
|
!fCall,
|
|
pBcbLocal->szPhonebookPath, // Meaningless in Case nRS
|
|
pBcbLocal->szEntryName, // Meaningless in Case nRS
|
|
pBcbLocal->szTextualSid, // Meaningless in Case SR
|
|
&(pBapCbRemote->dwLinkType),
|
|
&(pBapCbRemote->dwLinkSpeed),
|
|
pBapCbLocal->szPeerPhoneNumber, // Meaningless in Case nRS
|
|
&(pBapCbLocal->dwSubEntryIndex),// Meaningless in Case nRS
|
|
&(pBapCbLocal->hPort), // Meaningless in Case CR
|
|
fGetOurPhoneNumber ? pBapCbLocal->pbPhoneDelta : NULL,
|
|
|
|
// Meaningless in Case SR
|
|
fCall ? pBapCbLocal->szPortName : NULL,
|
|
|
|
fGetOurPhoneNumber && fServer ?
|
|
pBapCbLocal->szServerPhoneNumber : NULL))
|
|
{
|
|
if (fGetOurPhoneNumber)
|
|
{
|
|
// If we ask for our phone number, FGetAvailableLink()
|
|
// must provide it or return FALSE
|
|
PPP_ASSERT(pBapCbLocal->pbPhoneDelta[0]);
|
|
|
|
dwOptions = BAP_N_PHONE_DELTA;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We don't have the link type requested. Fill BapCb with
|
|
// details of a link type that we do have.
|
|
|
|
BapTrace("FFillBapCb: Requested link type not available. "
|
|
"Let us tell the peer what we have.");
|
|
|
|
fResult = FALSE;
|
|
|
|
// If fGetOurPhoneNumber, assume that the peer doesn't have any
|
|
// phone number. So send him a new link type only if we have its
|
|
// phone number.
|
|
|
|
// We don't have any link type preference
|
|
pBapCbLocal->dwLinkType = 0;
|
|
|
|
if (FGetAvailableLink(
|
|
pPcbLocal,
|
|
fServer,
|
|
fRouter,
|
|
!fCall,
|
|
pBcbLocal->szPhonebookPath, // Meaningless in Case nRS
|
|
pBcbLocal->szEntryName, // Meaningless in Case nRS
|
|
pBcbLocal->szTextualSid, // Meaningless in Case SR
|
|
&(pBapCbLocal->dwLinkType),
|
|
&(pBapCbLocal->dwLinkSpeed),
|
|
NULL /* szPeerPhoneNumber */,
|
|
NULL /* pdwSubEntryIndex */,
|
|
NULL /* phPort */,
|
|
NULL /* pbPhoneDelta */,
|
|
NULL /* szPortName */,
|
|
NULL /* szBasePhoneNumber */))
|
|
{
|
|
dwOptions = BAP_N_LINK_TYPE;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case BAP_PACKET_DROP_REQ:
|
|
|
|
if (NumLinksInBundle(pBcbLocal) <= 1)
|
|
{
|
|
BapTrace("FFillBapCb: Only one link in the bundle");
|
|
fResult = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// This will cause the link represented by pPcbLocal to get dropped.
|
|
// This link happens to have the highest dwSubEntryIndex, so we are
|
|
// happy.
|
|
|
|
pLcpCb = (LCPCB*)(pPcbLocal->LcpCb.pWorkBuf);
|
|
PPP_ASSERT(pLcpCb->Remote.Work.dwLinkDiscriminator <= 0xFFFF);
|
|
pBapCbLocal->dwLinkDiscriminator =
|
|
pLcpCb->Remote.Work.dwLinkDiscriminator;
|
|
dwOptions = BAP_N_LINK_DISC;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
LDone:
|
|
|
|
pBapCbLocal->dwType = dwPacketType;
|
|
pBapCbLocal->dwOptions = dwOptions;
|
|
return(fResult);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
void
|
|
|
|
Description:
|
|
This function asks NdisWan to inform us if the bandwidth utilization for
|
|
the bundle represented by pBcb goes out of the desired range for a given
|
|
amount of time.
|
|
|
|
*/
|
|
|
|
VOID
|
|
BapSetPolicy(
|
|
IN BCB * pBcb
|
|
)
|
|
{
|
|
DWORD dwLowThreshold;
|
|
DWORD dwHighThreshold;
|
|
DWORD dwLowSamplePeriod;
|
|
DWORD dwHighSamplePeriod;
|
|
DWORD dwErr;
|
|
|
|
PPP_ASSERT(NULL != pBcb);
|
|
|
|
dwLowThreshold = pBcb->BapParams.dwHangUpExtraPercent;
|
|
dwLowSamplePeriod = pBcb->BapParams.dwHangUpExtraSampleSeconds;
|
|
dwHighThreshold = pBcb->BapParams.dwDialExtraPercent;
|
|
dwHighSamplePeriod = pBcb->BapParams.dwDialExtraSampleSeconds;
|
|
|
|
dwErr = RasSetBapPolicy(pBcb->hConnection,
|
|
dwLowThreshold, dwLowSamplePeriod,
|
|
dwHighThreshold, dwHighSamplePeriod);
|
|
|
|
if (NO_ERROR != dwErr)
|
|
{
|
|
BapTrace("RasPppSetBapPolicy returned error %d", dwErr);
|
|
return;
|
|
}
|
|
|
|
BapTrace("BapSetPolicy on HCONN 0x%x: Low: %d%% for %d sec; "
|
|
"High: %d%% for %d sec",
|
|
pBcb->hConnection,
|
|
dwLowThreshold, dwLowSamplePeriod,
|
|
dwHighThreshold, dwHighSamplePeriod);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
void
|
|
|
|
Description:
|
|
Increments dwId in pBcb->BapCb.
|
|
|
|
*/
|
|
|
|
VOID
|
|
IncrementId(
|
|
IN BCB* pBcb
|
|
)
|
|
{
|
|
DWORD* pdwLastId;
|
|
BYTE bId;
|
|
|
|
pdwLastId = &(pBcb->BapCb.dwId);
|
|
bId = (BYTE)(*pdwLastId);
|
|
|
|
// 0 -> FF -> 0 -> ...
|
|
bId++;
|
|
*pdwLastId = bId;
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
void
|
|
|
|
Description:
|
|
Used for displaying BAP packets. fReceived is TRUE iff the packet was
|
|
received from the peer. hPort represents the port on which the packet was
|
|
sent/received. pBcb represents the bundle that owns this packet. pPacket
|
|
points to the packet that was sent/received and cbPacket is the number of
|
|
bytes in the packet.
|
|
|
|
*/
|
|
|
|
VOID
|
|
LogBapPacket(
|
|
IN BOOL fReceived,
|
|
IN HPORT hPort,
|
|
IN BCB* pBcb,
|
|
IN PPP_PACKET* pPacket,
|
|
IN DWORD cbPacket
|
|
)
|
|
{
|
|
BAP_RESPONSE* pBapResponse;
|
|
DWORD dwType;
|
|
|
|
static CHAR* szBapResponseName[] =
|
|
{
|
|
"ACK",
|
|
"NAK",
|
|
"REJ",
|
|
"FULL-NAK"
|
|
};
|
|
|
|
PPP_ASSERT(NULL != pBcb);
|
|
PPP_ASSERT(NULL != pPacket);
|
|
|
|
pBapResponse = (BAP_RESPONSE *)(pPacket->Information);
|
|
dwType = pBapResponse->Type;
|
|
|
|
BapTrace(" ");
|
|
|
|
BapTrace("Number of links in HCONN 0x%x: %d", pBcb->hConnection,
|
|
NumLinksInBundle(pBcb));
|
|
BapTrace("%sBAP packet %s:",
|
|
fReceived ? ">" : "<", fReceived ? "received" : "sent");
|
|
BapTrace("%sType: %s, Length: %d, Id: 0x%x, HCONN: 0x%x, hPort: %d%s",
|
|
fReceived ? ">" : "<",
|
|
dwType <= BAP_PACKET_LIMIT ?
|
|
SzBapPacketName[dwType] : "UNKNOWN",
|
|
cbPacket, pBapResponse->Id,
|
|
pBcb->hConnection, hPort,
|
|
hPort == (HPORT) -1 ? " (not known)" : "");
|
|
|
|
TraceDumpExA(DwBapTraceId,
|
|
0x00010000 | TRACE_USE_MASK | TRACE_USE_MSEC,
|
|
(CHAR*)pPacket,
|
|
cbPacket,
|
|
1,
|
|
FALSE,
|
|
fReceived ? ">" : "<");
|
|
|
|
if (((dwType == BAP_PACKET_CALL_RESP) ||
|
|
(dwType == BAP_PACKET_CALLBACK_RESP) ||
|
|
(dwType == BAP_PACKET_DROP_RESP)) &&
|
|
pBapResponse->ResponseCode <= BAP_RESPONSE_FULL_NAK)
|
|
{
|
|
BapTrace("%sResponse Code: %s", fReceived ? ">" : "<",
|
|
szBapResponseName[pBapResponse->ResponseCode]);
|
|
}
|
|
|
|
BapTrace(" ");
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Favored-Peer
|
|
FALSE: not Favored-Peer
|
|
|
|
Description:
|
|
Returns TRUE iff the peer represented by pBcb is the favored peer.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FFavoredPeer(
|
|
IN BCB* pBcb
|
|
)
|
|
{
|
|
DWORD dwCpIndex;
|
|
CPCB* pCpCb;
|
|
BACPCB* pBacpCb;
|
|
PCB* pPcb;
|
|
|
|
dwCpIndex = GetCpIndexFromProtocol(PPP_BACP_PROTOCOL);
|
|
PPP_ASSERT((DWORD)-1 != dwCpIndex);
|
|
PPP_ASSERT(NULL != pBcb);
|
|
|
|
pPcb = GetPCBPointerFromBCB(pBcb);
|
|
|
|
if (NULL == pPcb)
|
|
{
|
|
BapTrace("FFavoredPeer: No links in HCONN 0x%x!", pBcb->hConnection);
|
|
return(TRUE);
|
|
}
|
|
|
|
if (dwCpIndex != (DWORD)-1)
|
|
{
|
|
pCpCb = GetPointerToCPCB(pPcb, dwCpIndex);
|
|
PPP_ASSERT(NULL != pCpCb);
|
|
|
|
if (NULL != pCpCb)
|
|
{
|
|
pBacpCb = (BACPCB *)(pCpCb->pWorkBuf);
|
|
|
|
/*
|
|
|
|
The favored peer is the peer that transmits the lowest Magic-Number
|
|
in its Favored-Peer Configuration Option.
|
|
|
|
*/
|
|
|
|
return(pBacpCb->dwLocalMagicNumber < pBacpCb->dwRemoteMagicNumber);
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Looks in the bundle represented by pBcb, for a link whose Link
|
|
Discriminator = dwLinkDiscriminator. If fRemote, the remote Link
|
|
Discriminator is used. Else the local one is used. Returns the pPcb of the
|
|
link in ppPcb.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FGetPcbOfLink(
|
|
IN BCB* pBcb,
|
|
IN DWORD dwLinkDiscriminator,
|
|
IN BOOL fRemote,
|
|
OUT PCB** ppPcb
|
|
)
|
|
{
|
|
DWORD dwForIndex;
|
|
LCPCB* pLcpCb;
|
|
|
|
PPP_ASSERT(NULL != pBcb);
|
|
PPP_ASSERT(0xFFFF >= dwLinkDiscriminator);
|
|
PPP_ASSERT(NULL != ppPcb);
|
|
|
|
for (dwForIndex = 0; dwForIndex < pBcb->dwPpcbArraySize; dwForIndex++)
|
|
{
|
|
// Look at all the ports in the bundle for the port with the right Link
|
|
// Discriminator.
|
|
|
|
*ppPcb = pBcb->ppPcb[dwForIndex];
|
|
|
|
if (*ppPcb != NULL)
|
|
{
|
|
pLcpCb = (LCPCB*)((*ppPcb)->LcpCb.pWorkBuf);
|
|
PPP_ASSERT(NULL != pLcpCb);
|
|
|
|
if (fRemote)
|
|
{
|
|
PPP_ASSERT(pLcpCb->Remote.Work.dwLinkDiscriminator <= 0xFFFF);
|
|
if (pLcpCb->Remote.Work.dwLinkDiscriminator ==
|
|
dwLinkDiscriminator)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PPP_ASSERT(pLcpCb->Local.Work.dwLinkDiscriminator <= 0xFFFF);
|
|
if (pLcpCb->Local.Work.dwLinkDiscriminator ==
|
|
dwLinkDiscriminator)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BapTrace("FGetPcbOfLink: There is no link in HCONN 0x%x, whose remote "
|
|
"Link Disc is %d",
|
|
pBcb->hConnection, dwLinkDiscriminator);
|
|
|
|
*ppPcb = NULL;
|
|
return(FALSE);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Scans the BAP Datagram Options in the PPP packet pPacket. dwPacketType is
|
|
the BAP Datagram Type (see BAP_PACKET_*). dwLength is the BAP Datagram
|
|
Length. pBapCbRemote (including dwType and dwOptions) is filled up using
|
|
these options.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FReadOptions(
|
|
IN PPP_PACKET* pPacket,
|
|
IN DWORD dwPacketType,
|
|
IN DWORD dwLength,
|
|
OUT BAPCB* pBapCbRemote
|
|
)
|
|
{
|
|
PPP_OPTION* pOption;
|
|
BYTE* pbData;
|
|
DWORD dwIndex = 0;
|
|
DWORD dwUniqueDigits;
|
|
DWORD dwSubscribNumLength;
|
|
BYTE* pbNumberOption;
|
|
BYTE* pbSubAddrOption;
|
|
DWORD dwPhoneDeltaLength;
|
|
|
|
PPP_ASSERT(NULL != pPacket);
|
|
PPP_ASSERT(NULL != pBapCbRemote);
|
|
|
|
if (dwPacketType > BAP_PACKET_LIMIT)
|
|
{
|
|
BapTrace("Unknown BAP Datagram Type: %d", dwPacketType);
|
|
return(FALSE);
|
|
}
|
|
|
|
if (dwPacketType == BAP_PACKET_CALL_RESP ||
|
|
dwPacketType == BAP_PACKET_CALLBACK_RESP ||
|
|
dwPacketType == BAP_PACKET_DROP_RESP ||
|
|
dwPacketType == BAP_PACKET_STAT_RESP)
|
|
{
|
|
if (BAP_RESPONSE_HDR_LEN > dwLength)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
pOption = (PPP_OPTION *)(pPacket->Information + BAP_RESPONSE_HDR_LEN);
|
|
dwLength -= BAP_RESPONSE_HDR_LEN;
|
|
}
|
|
else
|
|
{
|
|
if (PPP_CONFIG_HDR_LEN > dwLength)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
pOption = (PPP_OPTION *)(pPacket->Information + PPP_CONFIG_HDR_LEN);
|
|
dwLength -= PPP_CONFIG_HDR_LEN;
|
|
}
|
|
|
|
ZeroMemory(pBapCbRemote, sizeof(BAPCB));
|
|
pBapCbRemote->dwType = dwPacketType;
|
|
|
|
while(dwLength > 0)
|
|
{
|
|
if (0 == pOption->Length || dwLength < pOption->Length)
|
|
{
|
|
BapTrace("FReadOptions: Invalid BAP Datagram Length");
|
|
return(FALSE);
|
|
}
|
|
|
|
dwLength -= pOption->Length;
|
|
|
|
if (pOption->Type <= BAP_OPTION_LIMIT)
|
|
{
|
|
pBapCbRemote->dwOptions |= (1 << pOption->Type);
|
|
}
|
|
|
|
switch(pOption->Type)
|
|
{
|
|
case BAP_OPTION_LINK_TYPE:
|
|
|
|
if (pOption->Length != PPP_OPTION_HDR_LEN + 3)
|
|
{
|
|
BapTrace("FReadOptions: Invalid length for Link-Type: %d",
|
|
pOption->Length);
|
|
return(FALSE);
|
|
}
|
|
|
|
pBapCbRemote->dwLinkSpeed = WireToHostFormat16(pOption->Data);
|
|
pBapCbRemote->dwLinkType = pOption->Data[2];
|
|
|
|
if (0 == pBapCbRemote->dwLinkType)
|
|
{
|
|
// In FGetAvailableLink(), we interpret Link Type 0 to
|
|
// mean "any link"
|
|
|
|
BapTrace("FReadOptions: Invalid Link-Type: 0");
|
|
return(FALSE);
|
|
}
|
|
|
|
break;
|
|
|
|
case BAP_OPTION_PHONE_DELTA:
|
|
|
|
/*
|
|
|
|
An implementation MAY include more than one Phone-Delta option in a
|
|
response.
|
|
|
|
dwIndex is the index into pBapCbRemote->pbPhoneDelta where we should
|
|
start writing.
|
|
|
|
If the only Sub-Options are Unique-Digits and Subscriber-Number,
|
|
the number of bytes we want to store is pOption->Length - 3.
|
|
|
|
Eg, if we get
|
|
02 11 (01 3 4) (02 6 9 9 9 9)
|
|
we store
|
|
4 0 9 9 9 9 0 0, ie 11 - 3 = 8 bytes
|
|
|
|
If Phone-Number-Sub-Address is also present, we will need
|
|
pOption->Length - 5 bytes in pBapCbRemote->pbPhoneDelta.
|
|
|
|
Eg, if we get
|
|
02 15 (01 3 4) (02 6 9 9 9 9) (03 4 9 9)
|
|
we store
|
|
4 0 9 9 9 9 0 9 9 0, ie 15 - 5 = 10 bytes
|
|
|
|
pbPhoneDelta has BAP_PHONE_DELTA_SIZE + 1 bytes, and we put the
|
|
terminating 0 byte after we have read all the Options.
|
|
|
|
*/
|
|
|
|
if (dwIndex + pOption->Length - 3 <= BAP_PHONE_DELTA_SIZE)
|
|
{
|
|
// Read the Phone-Delta option
|
|
|
|
pbData = pOption->Data;
|
|
dwPhoneDeltaLength = pOption->Length - PPP_OPTION_HDR_LEN;
|
|
|
|
dwUniqueDigits = 0;
|
|
pbNumberOption = pbSubAddrOption = NULL;
|
|
|
|
while(dwPhoneDeltaLength > 0)
|
|
{
|
|
/*
|
|
|
|
Read the Sub-Options.
|
|
|
|
If there are multiple Sub-Options of the same type (which
|
|
shouldn't really happen), we remember only the last
|
|
Sub-Option of each type.
|
|
|
|
*/
|
|
|
|
// pbData[1] contains Sub-Option Length
|
|
|
|
if (2 > pbData[1] || dwPhoneDeltaLength < pbData[1])
|
|
{
|
|
BapTrace("FReadOptions: Invalid BAP Datagram "
|
|
"Sub-Option Length");
|
|
return(FALSE);
|
|
}
|
|
|
|
dwPhoneDeltaLength -= pbData[1];
|
|
|
|
// pbData[0] contains Sub-Option Type
|
|
|
|
switch(pbData[0])
|
|
{
|
|
case BAP_SUB_OPTION_UNIQUE_DIGITS:
|
|
|
|
if (pbData[1] != 3)
|
|
{
|
|
BapTrace("FReadOptions: Invalid length for "
|
|
"Unique-Digits: %d",
|
|
pbData[1]);
|
|
return(FALSE);
|
|
}
|
|
|
|
dwUniqueDigits = pbData[2];
|
|
break;
|
|
|
|
case BAP_SUB_OPTION_SUBSCRIB_NUM:
|
|
|
|
dwSubscribNumLength = pbData[1] - 2;
|
|
|
|
if (dwSubscribNumLength > MAX_PHONE_NUMBER_LEN)
|
|
{
|
|
BapTrace("FReadOptions: Subscriber-Number too "
|
|
"long: %d",
|
|
pbData[1] - 2);
|
|
return(FALSE);
|
|
}
|
|
|
|
pbNumberOption = pbData;
|
|
|
|
if (!FAsciiDigits(pbNumberOption + 2,
|
|
dwSubscribNumLength))
|
|
{
|
|
BapTrace("FReadOptions: Subscriber-Number contains "
|
|
"bytes other than ASCII digits");
|
|
return(FALSE);
|
|
}
|
|
|
|
break;
|
|
|
|
case BAP_SUB_OPTION_SUB_ADDR:
|
|
|
|
if (pbData[1] - 2 > MAX_PHONE_NUMBER_LEN)
|
|
{
|
|
BapTrace("FReadOptions: Phone-Number-Sub-Address "
|
|
"too long: %d",
|
|
pbData[1] - 2);
|
|
return(FALSE);
|
|
}
|
|
|
|
pbSubAddrOption = pbData;
|
|
|
|
if (!FAsciiDigits(pbSubAddrOption + 2,
|
|
pbSubAddrOption[1] - 2))
|
|
{
|
|
BapTrace("FReadOptions: Phone-Number-Sub-Address "
|
|
"contains bytes other than ASCII digits");
|
|
return(FALSE);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
BapTrace("FReadOptions: Unknown Phone-Delta Sub-Option "
|
|
"Type %d",
|
|
pbData[0]);
|
|
break;
|
|
}
|
|
|
|
pbData += pbData[1];
|
|
}
|
|
|
|
if (pbNumberOption == NULL ||
|
|
dwUniqueDigits > dwSubscribNumLength)
|
|
{
|
|
BapTrace("FReadOptions: Invalid Unique-Digits or "
|
|
"Subscriber-Number in Phone-Delta");
|
|
return(FALSE);
|
|
}
|
|
|
|
if (0 == dwUniqueDigits)
|
|
{
|
|
// We cannot write 0 0 0. See BAPCB comments
|
|
pBapCbRemote->pbPhoneDelta[dwIndex++] = 0xFF;
|
|
}
|
|
else
|
|
{
|
|
pBapCbRemote->pbPhoneDelta[dwIndex++] = (BYTE)dwUniqueDigits;
|
|
pBapCbRemote->pbPhoneDelta[dwIndex++] = 0;
|
|
|
|
CopyMemory(pBapCbRemote->pbPhoneDelta + dwIndex,
|
|
pbNumberOption + 2 + dwSubscribNumLength - dwUniqueDigits,
|
|
dwSubscribNumLength);
|
|
dwIndex += pbNumberOption[1] - 2;
|
|
pBapCbRemote->pbPhoneDelta[dwIndex++] = 0;
|
|
|
|
if (pbSubAddrOption != NULL)
|
|
{
|
|
CopyMemory(pBapCbRemote->pbPhoneDelta + dwIndex,
|
|
pbSubAddrOption + 2, pbSubAddrOption[1] - 2);
|
|
dwIndex += pbSubAddrOption[1] - 2;
|
|
}
|
|
pBapCbRemote->pbPhoneDelta[dwIndex++] = 0;
|
|
}
|
|
}
|
|
else if (dwIndex == 0)
|
|
{
|
|
// We were unable to read any Phone-Deltas
|
|
BapTrace("FReadOptions: Couldn't read any Phone-Delta");
|
|
return(FALSE);
|
|
}
|
|
|
|
break;
|
|
|
|
case BAP_OPTION_NO_PH_NEEDED:
|
|
|
|
if (pOption->Length != PPP_OPTION_HDR_LEN)
|
|
{
|
|
BapTrace("FReadOptions: Invalid length for "
|
|
"No-Phone-Number-Needed: %d",
|
|
pOption->Length);
|
|
return(FALSE);
|
|
}
|
|
|
|
// In pBapCbRemote->dwOptions, we remember that we have seen this
|
|
// option. We don't need to do anything else.
|
|
|
|
break;
|
|
|
|
case BAP_OPTION_REASON:
|
|
|
|
break;
|
|
|
|
case BAP_OPTION_LINK_DISC:
|
|
|
|
if (pOption->Length != PPP_OPTION_HDR_LEN + 2)
|
|
{
|
|
BapTrace("FReadOptions: Invalid length for "
|
|
"Link-Discriminator: %d",
|
|
pOption->Length);
|
|
return(FALSE);
|
|
}
|
|
|
|
pBapCbRemote->dwLinkDiscriminator
|
|
= WireToHostFormat16(pOption->Data);
|
|
|
|
break;
|
|
|
|
case BAP_OPTION_CALL_STATUS:
|
|
|
|
if (pOption->Length != PPP_OPTION_HDR_LEN + 2)
|
|
{
|
|
BapTrace("FReadOptions: Invalid length for Call-Status: %d",
|
|
pOption->Length);
|
|
return(FALSE);
|
|
}
|
|
|
|
pBapCbRemote->dwStatus = pOption->Data[0];
|
|
pBapCbRemote->dwAction = pOption->Data[1];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// Perhaps this is a new option that we don't recognize
|
|
BapTrace("FReadOptions: Unknown BAP Datagram Option: 0x%x",
|
|
pOption->Type);
|
|
break;
|
|
}
|
|
|
|
pOption = (PPP_OPTION *)((BYTE*)pOption + pOption->Length);
|
|
}
|
|
|
|
// The terminating 0 byte in pbPhoneDelta.
|
|
PPP_ASSERT(dwIndex <= BAP_PHONE_DELTA_SIZE + 1);
|
|
pBapCbRemote->pbPhoneDelta[dwIndex++] = 0;
|
|
|
|
if (g_dwMandatoryOptions[dwPacketType] & ~pBapCbRemote->dwOptions)
|
|
{
|
|
BapTrace("FReadOptions: Missing options: Scanned options: 0x%x, "
|
|
"Mandatory options: 0x%x",
|
|
pBapCbRemote->dwOptions, g_dwMandatoryOptions[dwPacketType]);
|
|
|
|
return(FALSE);
|
|
}
|
|
else
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Writes one (or more in the case of Phone-Delta) BAP Datagram Option of type
|
|
dwOptionType (see BAP_OPTION_*) into **ppOption, by looking at the fields
|
|
in pBapCbLocal. *ppOption is updated to point to the place where the next
|
|
option should go. *pcbOption contains the number of free bytes in
|
|
*ppOption. It is decreased by the number of free bytes used up. *ppOption
|
|
and *pcbOption are not modified if the function returns FALSE.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FMakeBapOption(
|
|
IN BAPCB* pBapCbLocal,
|
|
IN DWORD dwOptionType,
|
|
IN PPP_OPTION** ppOption,
|
|
IN OUT DWORD* pcbOption
|
|
)
|
|
{
|
|
DWORD dwLength;
|
|
DWORD dwNumberOptionSize;
|
|
DWORD dwSubAddrOptionSize;
|
|
BYTE* pbData;
|
|
DWORD dwIndex;
|
|
DWORD dwTempIndex;
|
|
DWORD dwSubAddrIndex;
|
|
DWORD fAtLeastOnePhoneDelta = FALSE;
|
|
PPP_OPTION* pOption;
|
|
|
|
PPP_ASSERT(NULL != pBapCbLocal);
|
|
PPP_ASSERT(NULL != ppOption);
|
|
PPP_ASSERT(NULL != pcbOption);
|
|
|
|
pOption = *ppOption;
|
|
|
|
PPP_ASSERT(NULL != pOption);
|
|
|
|
switch(dwOptionType)
|
|
{
|
|
case BAP_OPTION_LINK_TYPE:
|
|
|
|
dwLength = PPP_OPTION_HDR_LEN + 3;
|
|
if (*pcbOption < dwLength)
|
|
{
|
|
BapTrace("FMakeBapOption: Buffer too small for Link-Type. "
|
|
"Size: %d, Reqd: %d",
|
|
*pcbOption, dwLength);
|
|
return(FALSE);
|
|
}
|
|
|
|
pOption->Length = (BYTE)dwLength;
|
|
PPP_ASSERT(pBapCbLocal->dwLinkSpeed <= 0xFFFF);
|
|
HostToWireFormat16((WORD)(pBapCbLocal->dwLinkSpeed), pOption->Data);
|
|
PPP_ASSERT(pBapCbLocal->dwLinkType <= 0xFF);
|
|
pOption->Data[2] = (BYTE)(pBapCbLocal->dwLinkType);
|
|
|
|
break;
|
|
|
|
case BAP_OPTION_PHONE_DELTA:
|
|
|
|
dwIndex = 0;
|
|
|
|
while (pBapCbLocal->pbPhoneDelta[dwIndex])
|
|
{
|
|
if (0xFF == pBapCbLocal->pbPhoneDelta[dwIndex])
|
|
{
|
|
// Unique-Digits is 0. See BAPCB comments
|
|
|
|
dwNumberOptionSize = 2;
|
|
dwSubAddrOptionSize = 0;
|
|
dwTempIndex = dwIndex + 1;
|
|
}
|
|
else
|
|
{
|
|
// Write as many Phone-Delta options as possible
|
|
|
|
dwTempIndex = dwIndex + 2;
|
|
|
|
dwNumberOptionSize = 0;
|
|
while (pBapCbLocal->pbPhoneDelta[dwTempIndex++])
|
|
{
|
|
dwNumberOptionSize++;
|
|
}
|
|
PPP_ASSERT(dwNumberOptionSize <= MAX_PHONE_NUMBER_LEN);
|
|
// Increase by 2 to accommodate Sub-Option Type and Sub-Option
|
|
// Len
|
|
dwNumberOptionSize += 2;
|
|
|
|
dwSubAddrIndex = dwTempIndex;
|
|
|
|
dwSubAddrOptionSize = 0;
|
|
while (pBapCbLocal->pbPhoneDelta[dwTempIndex++])
|
|
{
|
|
dwSubAddrOptionSize++;
|
|
}
|
|
PPP_ASSERT(dwSubAddrOptionSize <= MAX_PHONE_NUMBER_LEN);
|
|
|
|
if (0 != dwSubAddrOptionSize)
|
|
{
|
|
// Increase by 2 to accommodate Sub-Option Type and
|
|
// Sub-Option Len
|
|
dwSubAddrOptionSize += 2;
|
|
}
|
|
}
|
|
|
|
dwLength = PPP_OPTION_HDR_LEN + 3 /* for Unique-Digits */ +
|
|
dwNumberOptionSize + dwSubAddrOptionSize;
|
|
|
|
if (*pcbOption < dwLength || 0xFF < dwLength)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pOption->Type = (BYTE)dwOptionType;
|
|
pOption->Length = (BYTE)dwLength;
|
|
pbData = pOption->Data;
|
|
|
|
pbData[0] = BAP_SUB_OPTION_UNIQUE_DIGITS;
|
|
pbData[1] = 3;
|
|
pbData[2] = pBapCbLocal->pbPhoneDelta[dwIndex];
|
|
if (0xFF == pbData[2])
|
|
{
|
|
// Unique-Digits is 0. See BAPCB comments
|
|
pbData[2] = 0;
|
|
}
|
|
pbData += 3;
|
|
|
|
pbData[0] = BAP_SUB_OPTION_SUBSCRIB_NUM;
|
|
PPP_ASSERT(dwNumberOptionSize <= 0xFF);
|
|
pbData[1] = (BYTE)dwNumberOptionSize;
|
|
CopyMemory(pbData + 2, pBapCbLocal->pbPhoneDelta + dwIndex + 2,
|
|
dwNumberOptionSize - 2);
|
|
pbData += dwNumberOptionSize;
|
|
|
|
if (0 != dwSubAddrOptionSize)
|
|
{
|
|
pbData[0] = BAP_SUB_OPTION_SUB_ADDR;
|
|
PPP_ASSERT(dwSubAddrOptionSize <= 0xFF);
|
|
pbData[1] = (BYTE)dwSubAddrOptionSize;
|
|
CopyMemory(pbData + 2,
|
|
pBapCbLocal->pbPhoneDelta + dwSubAddrIndex,
|
|
dwSubAddrOptionSize - 2);
|
|
}
|
|
|
|
*pcbOption -= dwLength;
|
|
pOption = (PPP_OPTION *)((BYTE *)pOption + dwLength);
|
|
dwIndex = dwTempIndex;
|
|
fAtLeastOnePhoneDelta = TRUE;
|
|
}
|
|
|
|
if (!fAtLeastOnePhoneDelta)
|
|
{
|
|
BapTrace("FMakeBapOption: Buffer too small for Phone-Delta. "
|
|
"Size: %d, Reqd: %d",
|
|
*pcbOption, dwLength);
|
|
return(FALSE);
|
|
}
|
|
else
|
|
{
|
|
// We need to return from here. We don't want to set pOption->Type.
|
|
*ppOption = pOption;
|
|
return(TRUE);
|
|
}
|
|
|
|
break;
|
|
|
|
case BAP_OPTION_NO_PH_NEEDED:
|
|
|
|
dwLength = PPP_OPTION_HDR_LEN;
|
|
if (*pcbOption < dwLength)
|
|
{
|
|
BapTrace("FMakeBapOption: Buffer too small for "
|
|
"No-Phone-Number-Needed. Size: %d, Reqd: %d",
|
|
*pcbOption, dwLength);
|
|
return(FALSE);
|
|
}
|
|
|
|
pOption->Length = (BYTE)dwLength;
|
|
break;
|
|
|
|
case BAP_OPTION_REASON:
|
|
|
|
dwLength = PPP_OPTION_HDR_LEN;
|
|
break;
|
|
|
|
case BAP_OPTION_LINK_DISC:
|
|
|
|
dwLength = PPP_OPTION_HDR_LEN + 2;
|
|
if (*pcbOption < dwLength)
|
|
{
|
|
BapTrace("FMakeBapOption: Buffer too small for Link-Discriminator. "
|
|
"Size: %d, Reqd: %d",
|
|
*pcbOption, dwLength);
|
|
return(FALSE);
|
|
}
|
|
|
|
pOption->Length = (BYTE)dwLength;
|
|
PPP_ASSERT(pBapCbLocal->dwLinkDiscriminator <= 0xFFFF);
|
|
HostToWireFormat16((WORD)(pBapCbLocal->dwLinkDiscriminator),
|
|
pOption->Data);
|
|
|
|
break;
|
|
|
|
case BAP_OPTION_CALL_STATUS:
|
|
|
|
dwLength = PPP_OPTION_HDR_LEN + 2;
|
|
if (*pcbOption < dwLength)
|
|
{
|
|
BapTrace("FMakeBapOption: Buffer too small for Call-Status. "
|
|
"Size: %d, Reqd: %d",
|
|
*pcbOption, dwLength);
|
|
return(FALSE);
|
|
}
|
|
|
|
pOption->Length = (BYTE)dwLength;
|
|
PPP_ASSERT(pBapCbLocal->dwStatus <= 0xFF);
|
|
pOption->Data[0] = (BYTE)(pBapCbLocal->dwStatus);
|
|
PPP_ASSERT(pBapCbLocal->dwAction <= 0xFF);
|
|
pOption->Data[1] = (BYTE)(pBapCbLocal->dwAction);
|
|
|
|
break;
|
|
|
|
default:
|
|
BapTrace("FMakeBapOption: Unknown BAP Datagram Option: %d. Ignoring.",
|
|
dwOptionType);
|
|
return(FALSE);
|
|
}
|
|
|
|
*ppOption = (PPP_OPTION *)((BYTE *)pOption + dwLength);
|
|
*pcbOption -= dwLength;
|
|
pOption->Type = (BYTE)dwOptionType;
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Writes BAP Datagram Options specified by dwOptions (see BAP_N_*) into
|
|
pbData, by consulting pBapCbLocal. *pcbOptions contains the number of free
|
|
bytes in pbData. It is decreased by the number of free bytes used up.
|
|
*pcbOptions may be modified even if the function returns FALSE.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FBuildBapOptionList(
|
|
IN BAPCB* pBapCbLocal,
|
|
IN DWORD dwOptions,
|
|
IN BYTE* pbData,
|
|
IN OUT DWORD* pcbOptions
|
|
)
|
|
{
|
|
DWORD dwOptionType;
|
|
PPP_OPTION* pOption;
|
|
|
|
PPP_ASSERT(NULL != pBapCbLocal);
|
|
PPP_ASSERT(NULL != pbData);
|
|
PPP_ASSERT(NULL != pcbOptions);
|
|
|
|
pOption = (PPP_OPTION *) pbData;
|
|
|
|
for (dwOptionType = 1; dwOptionType <= BAP_OPTION_LIMIT;
|
|
dwOptionType++)
|
|
{
|
|
if (dwOptions & (1 << dwOptionType))
|
|
{
|
|
if (!FMakeBapOption(pBapCbLocal, dwOptionType, &pOption,
|
|
pcbOptions))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Sends the BAP packet in pPcb->pSendBuf. dwId is the Identifier and dwLength
|
|
is the length of the BAP Datagram. We also add a timeout element so that we
|
|
can retransmit the datagram if it doesn't reach the peer. fInsertInTimerQ
|
|
is TRUE if an element has to be inserted in the timer queue.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FSendBapPacket(
|
|
IN PCB* pPcb,
|
|
IN DWORD dwId,
|
|
IN DWORD dwLength,
|
|
IN BOOL fInsertInTimerQ
|
|
)
|
|
{
|
|
DWORD dwErr;
|
|
LCPCB* pLcpCb;
|
|
|
|
PPP_ASSERT(NULL != pPcb);
|
|
PPP_ASSERT(0xFF >= dwId);
|
|
|
|
pLcpCb = (LCPCB *)(LCPCB*)(pPcb->LcpCb.pWorkBuf);
|
|
PPP_ASSERT(NULL != pLcpCb);
|
|
|
|
if (dwLength > LCP_DEFAULT_MRU && dwLength > pLcpCb->Remote.Work.MRU)
|
|
{
|
|
BapTrace("FSendBapPacket: BAP packet too long. Length = %d. MRU = %d",
|
|
dwLength, pLcpCb->Remote.Work.MRU);
|
|
return(FALSE);
|
|
}
|
|
|
|
dwLength += PPP_PACKET_HDR_LEN;
|
|
PPP_ASSERT(dwLength <= 0xFFFF);
|
|
LogBapPacket(FALSE /* fReceived */, pPcb->hPort, pPcb->pBcb, pPcb->pSendBuf,
|
|
dwLength);
|
|
|
|
if ((dwErr = PortSendOrDisconnect(pPcb, dwLength)) != NO_ERROR)
|
|
{
|
|
BapTrace("FSendBapPacket: PortSendOrDisconnect failed and returned %d",
|
|
dwErr);
|
|
return(FALSE);
|
|
}
|
|
|
|
if (fInsertInTimerQ)
|
|
{
|
|
InsertInTimerQ(pPcb->pBcb->dwBundleId, pPcb->pBcb->hConnection, dwId,
|
|
PPP_BAP_PROTOCOL, FALSE /* fAuthenticator */, TIMER_EVENT_TIMEOUT,
|
|
pPcb->RestartTimer);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Builds a BAP Request or Indication Datagram using the options specified by
|
|
pBcbLocal->BapCb.dwOptions and the values in pBcbLocal->BapCb and sends it.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FSendBapRequest(
|
|
IN BCB* pBcbLocal
|
|
)
|
|
{
|
|
DWORD dwLength;
|
|
BAPCB* pBapCbLocal;
|
|
PPP_CONFIG* pSendConfig;
|
|
PCB* pPcb;
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
|
|
pBapCbLocal = &(pBcbLocal->BapCb);
|
|
pPcb = GetPCBPointerFromBCB(pBcbLocal);
|
|
|
|
if (NULL == pPcb)
|
|
{
|
|
BapTrace("FSendBapRequest: No links in HCONN 0x%x!",
|
|
pBcbLocal->hConnection);
|
|
return(FALSE);
|
|
}
|
|
|
|
pSendConfig = (PPP_CONFIG *)(pPcb->pSendBuf->Information);
|
|
|
|
// Remaining free space in buffer, ie size of pSendConfig->Data
|
|
dwLength = LCP_DEFAULT_MRU - PPP_PACKET_HDR_LEN - PPP_CONFIG_HDR_LEN;
|
|
|
|
if (!FBuildBapOptionList(pBapCbLocal, pBapCbLocal->dwOptions,
|
|
pSendConfig->Data, &dwLength))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
dwLength = LCP_DEFAULT_MRU - PPP_PACKET_HDR_LEN - dwLength;
|
|
|
|
HostToWireFormat16(PPP_BAP_PROTOCOL, pPcb->pSendBuf->Protocol);
|
|
|
|
PPP_ASSERT(pBapCbLocal->dwType <= 0xFF);
|
|
pSendConfig->Code = (BYTE)(pBapCbLocal->dwType);
|
|
PPP_ASSERT(pBapCbLocal->dwId <= 0xFF);
|
|
pSendConfig->Id = (BYTE)(pBapCbLocal->dwId);
|
|
PPP_ASSERT(dwLength <= 0xFFFF);
|
|
HostToWireFormat16((WORD)dwLength, pSendConfig->Length);
|
|
|
|
return(FSendBapPacket(pPcb, pBapCbLocal->dwId, dwLength,
|
|
TRUE /* fInsertInTimerQ */));
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Same as FSendBapRequest, except that pBcbLocal->BapCb.dwRetryCount is
|
|
initialized. FSendInitialBapRequest should be used to send the first BAP
|
|
Request or Indication Datagram and FSendBapRequest should be used to send
|
|
the subsequent datagrams after timeouts.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FSendInitialBapRequest(
|
|
IN BCB* pBcbLocal
|
|
)
|
|
{
|
|
BAPCB* pBapCbLocal;
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
pBapCbLocal = &(pBcbLocal->BapCb);
|
|
|
|
pBapCbLocal->dwRetryCount = PppConfigInfo.MaxConfigure;
|
|
if (BAP_PACKET_STATUS_IND == pBapCbLocal->dwType)
|
|
{
|
|
/*
|
|
|
|
Call-Status-Indication packets MUST use the same Identifier as was used
|
|
by the original Call-Request or Callback-Request that was used to
|
|
initiate the call.
|
|
|
|
*/
|
|
|
|
pBapCbLocal->dwId = pBapCbLocal->dwStatusIndicationId;
|
|
}
|
|
else
|
|
{
|
|
IncrementId(pBcbLocal);
|
|
}
|
|
|
|
return(FSendBapRequest(pBcbLocal));
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
TRUE: Success
|
|
FALSE: Failure
|
|
|
|
Description:
|
|
Builds a BAP Response Datagram using the options specified by dwOptions and
|
|
the values in pBcbLocal->BapCb and sends it. The BAP Datagram Type,
|
|
Identifier, and Response Code are specified in dwType, dwId, and
|
|
dwResponseCode.
|
|
|
|
We cannot use dwOptions and dwType from pBcbLocal->BapCb because we
|
|
sometimes call FSendBapResponse without calling FFillBapCb first. We may be
|
|
in a BAP_STATE_SENT_* at this point, and we don't want to modify
|
|
pBcbLocal->BapCb.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
FSendBapResponse(
|
|
IN BCB* pBcbLocal,
|
|
IN DWORD dwOptions,
|
|
IN DWORD dwType,
|
|
IN DWORD dwId,
|
|
IN DWORD dwResponseCode
|
|
)
|
|
{
|
|
DWORD dwLength;
|
|
BAPCB* pBapCbLocal;
|
|
BAP_RESPONSE* pBapResponse;
|
|
PCB* pPcb;
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
|
|
pBapCbLocal = &(pBcbLocal->BapCb);
|
|
pPcb = GetPCBPointerFromBCB(pBcbLocal);
|
|
|
|
if (NULL == pPcb)
|
|
{
|
|
BapTrace("FSendBapResponse: No links in HCONN 0x%x!",
|
|
pBcbLocal->hConnection);
|
|
return(FALSE);
|
|
}
|
|
|
|
pBapResponse = (BAP_RESPONSE *)(pPcb->pSendBuf->Information);
|
|
|
|
// Remaining free space in buffer, ie size of pBapResponse->Data
|
|
dwLength = LCP_DEFAULT_MRU - PPP_PACKET_HDR_LEN - BAP_RESPONSE_HDR_LEN;
|
|
|
|
if (!FBuildBapOptionList(pBapCbLocal, dwOptions, pBapResponse->Data,
|
|
&dwLength))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
dwLength = LCP_DEFAULT_MRU - PPP_PACKET_HDR_LEN - dwLength;
|
|
|
|
HostToWireFormat16(PPP_BAP_PROTOCOL, pPcb->pSendBuf->Protocol);
|
|
|
|
PPP_ASSERT(dwType <= 0xFF);
|
|
pBapResponse->Type = (BYTE) dwType;
|
|
PPP_ASSERT(dwId <= 0xFF);
|
|
pBapResponse->Id = (BYTE) dwId;
|
|
PPP_ASSERT(dwLength <= 0xFFFF);
|
|
HostToWireFormat16((WORD)dwLength, pBapResponse->Length);
|
|
PPP_ASSERT(dwResponseCode <= 0xFF);
|
|
pBapResponse->ResponseCode = (BYTE) dwResponseCode;
|
|
|
|
return(FSendBapPacket(pPcb, dwId, dwLength, FALSE /* fInsertInTimerQ */));
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
void
|
|
|
|
Description:
|
|
Called when NDISWAN determines that a link has to be added to the bundle
|
|
represented pBcbLocal
|
|
|
|
*/
|
|
|
|
VOID
|
|
BapEventAddLink(
|
|
IN BCB* pBcbLocal
|
|
)
|
|
{
|
|
BAP_STATE* pBapState;
|
|
PCB* pPcbLocal;
|
|
BAPCB* pBapCbLocal;
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
pBapState = &(pBcbLocal->BapCb.BapState);
|
|
PPP_ASSERT(BAP_STATE_LIMIT >= *pBapState);
|
|
|
|
if (!(pBcbLocal->fFlags & BCBFLAG_CAN_DO_BAP))
|
|
{
|
|
BapTrace("BapEventAddLink called on HCONN 0x%x without BACP",
|
|
pBcbLocal->hConnection);
|
|
return;
|
|
}
|
|
|
|
BapTrace(" ");
|
|
BapTrace("BapEventAddLink on HCONN 0x%x", pBcbLocal->hConnection);
|
|
|
|
if (pBcbLocal->fFlags & BCBFLAG_LISTENING)
|
|
{
|
|
BapTrace("Still listening; must ignore BapEventAddLink");
|
|
return;
|
|
}
|
|
|
|
switch(*pBapState)
|
|
{
|
|
case BAP_STATE_INITIAL:
|
|
|
|
if (pBcbLocal->fFlags & BCBFLAG_CAN_ACCEPT_CALLS)
|
|
{
|
|
// If we can accept calls, we prefer to be called (to save us the
|
|
// cost of calling).
|
|
|
|
if (FFillBapCb(BAP_PACKET_CALLBACK_REQ, pBcbLocal,
|
|
NULL /* pBapCbRemote */))
|
|
{
|
|
pPcbLocal = GetPCBPointerFromBCB(pBcbLocal);
|
|
pBapCbLocal = &(pBcbLocal->BapCb);
|
|
|
|
if (NULL == pPcbLocal)
|
|
{
|
|
BapTrace("BapEventRecvCallOrCallbackReq: No links in "
|
|
"HCONN 0x%x!",
|
|
pBcbLocal->hConnection);
|
|
return;
|
|
}
|
|
|
|
if ((pBcbLocal->fFlags & BCBFLAG_IS_SERVER) ||
|
|
(ROUTER_IF_TYPE_FULL_ROUTER ==
|
|
pPcbLocal->pBcb->InterfaceInfo.IfType) ||
|
|
FListenForCall(pBapCbLocal->szPortName,
|
|
pBapCbLocal->dwSubEntryIndex, pPcbLocal))
|
|
{
|
|
// Servers and routers are already listening. We have to
|
|
// call FListenForCall() only for non-router clients.
|
|
|
|
// We do a listen first and then send the Callback-Request
|
|
// because the peer may send an ACK and call back
|
|
// immediately before we have a chance to do a listen.
|
|
|
|
if (FSendInitialBapRequest(pBcbLocal))
|
|
{
|
|
*pBapState = BAP_STATE_SENT_CALLBACK_REQ;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// FListenForCall may have failed because we chose an
|
|
// inappropriate port. Sending a Call-Request will not work
|
|
// because, most probably, we will select the same port.
|
|
return;
|
|
}
|
|
}
|
|
|
|
// We cannot accept calls, so we will call.
|
|
|
|
if ((pBcbLocal->fFlags & BCBFLAG_CAN_CALL) &&
|
|
FFillBapCb(BAP_PACKET_CALL_REQ, pBcbLocal,
|
|
NULL /* pBapCbRemote */))
|
|
{
|
|
if (FSendInitialBapRequest(pBcbLocal))
|
|
{
|
|
*pBapState = BAP_STATE_SENT_CALL_REQ;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BapTrace("BapEventAddLink ignored on HCONN 0x%x from state %s.",
|
|
pBcbLocal->hConnection, SzBapStateName[*pBapState]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
void
|
|
|
|
Description:
|
|
Called when NDISWAN determines that a link has to be dropped from the
|
|
bundle represented by pBcbLocal
|
|
|
|
*/
|
|
|
|
VOID
|
|
BapEventDropLink(
|
|
IN BCB* pBcbLocal
|
|
)
|
|
{
|
|
BAP_STATE* pBapState;
|
|
BAPCB* pBapCbLocal;
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
|
|
pBapCbLocal = &(pBcbLocal->BapCb);
|
|
pBapState = &(pBapCbLocal->BapState);
|
|
|
|
PPP_ASSERT(BAP_STATE_LIMIT >= *pBapState);
|
|
|
|
if (!(pBcbLocal->fFlags & BCBFLAG_CAN_DO_BAP))
|
|
{
|
|
BapTrace("BapEventAddLink called on HCONN 0x%x without BACP",
|
|
pBcbLocal->hConnection);
|
|
return;
|
|
}
|
|
|
|
BapTrace(" ");
|
|
BapTrace("BapEventDropLink on HCONN 0x%x", pBcbLocal->hConnection);
|
|
|
|
switch(*pBapState)
|
|
{
|
|
case BAP_STATE_INITIAL:
|
|
|
|
if (FFillBapCb(BAP_PACKET_DROP_REQ, pBcbLocal,
|
|
NULL /* pBapCbRemote */))
|
|
{
|
|
// See note "Dropping Links" at the top of the file
|
|
pBapCbLocal->dwLinkCount = NumLinksInBundle(pBcbLocal);
|
|
pBapCbLocal->fForceDropOnNak = TRUE;
|
|
|
|
if (FSendInitialBapRequest(pBcbLocal))
|
|
{
|
|
*pBapState = BAP_STATE_SENT_DROP_REQ;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case BAP_STATE_SENT_CALL_REQ:
|
|
case BAP_STATE_SENT_CALLBACK_REQ:
|
|
|
|
// We wanted to add a link, but we have now changed our minds.
|
|
*pBapState = BAP_STATE_INITIAL;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
|
|
// Do not retransmit the request.
|
|
RemoveFromTimerQ(pBcbLocal->dwBundleId, pBapCbLocal->dwId,
|
|
PPP_BAP_PROTOCOL, FALSE /* fAuthenticator */, TIMER_EVENT_TIMEOUT);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BapTrace("BapEventDropLink ignored on HCONN 0x%x from state %s.",
|
|
pBcbLocal->hConnection, SzBapStateName[*pBapState]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
void
|
|
|
|
Description:
|
|
Called when a Call-Request or Callback-Request BAP Datagram is received.
|
|
fCall is TRUE if it is a Call-Request. pBcbLocal represents the bundle that
|
|
receives the Request. The BAP Datagram Options sent by the peer are in
|
|
*pBapCbRemote. The Identifier of the BAP Datagram sent by the peer is in
|
|
dwId.
|
|
|
|
*/
|
|
|
|
VOID
|
|
BapEventRecvCallOrCallbackReq(
|
|
IN BOOL fCall,
|
|
IN BCB* pBcbLocal,
|
|
IN BAPCB* pBapCbRemote,
|
|
IN DWORD dwId
|
|
)
|
|
{
|
|
BAPCB* pBapCbLocal;
|
|
DWORD dwOptions = 0;
|
|
DWORD dwResponseCode;
|
|
DWORD dwPacketType = fCall ? BAP_PACKET_CALL_RESP :
|
|
BAP_PACKET_CALLBACK_RESP;
|
|
BAP_STATE* pBapState;
|
|
CHAR* szRequest = fCall ? "Call-Request" : "Callback-Request";
|
|
PCB* pPcbLocal;
|
|
BOOL fServer;
|
|
BAP_CALL_RESULT BapCallResult;
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
PPP_ASSERT(NULL != pBapCbRemote);
|
|
PPP_ASSERT(0xFF >= dwId);
|
|
|
|
pBapCbLocal = &(pBcbLocal->BapCb);
|
|
pBapState = &(pBapCbLocal->BapState);
|
|
|
|
PPP_ASSERT(BAP_STATE_LIMIT >= *pBapState);
|
|
|
|
BapTrace("BapEventRecvCallOrCallbackReq on HCONN 0x%x",
|
|
pBcbLocal->hConnection);
|
|
|
|
if ((!fCall && !(pBcbLocal->fFlags & BCBFLAG_CAN_CALL)) ||
|
|
(fCall && !(pBcbLocal->fFlags & BCBFLAG_CAN_ACCEPT_CALLS)))
|
|
{
|
|
BapTrace("Rejecting %s on HCONN 0x%x", szRequest,
|
|
pBcbLocal->hConnection);
|
|
dwResponseCode = BAP_RESPONSE_REJ;
|
|
}
|
|
else if (FUpperLimitReached(pBcbLocal))
|
|
{
|
|
BapTrace("Full-Nak'ing %s on HCONN 0x%x: upper limit reached",
|
|
szRequest, pBcbLocal->hConnection);
|
|
dwResponseCode = BAP_RESPONSE_FULL_NAK;
|
|
}
|
|
else
|
|
{
|
|
switch (*pBapState)
|
|
{
|
|
case BAP_STATE_SENT_DROP_REQ:
|
|
case BAP_STATE_SENT_STATUS_IND:
|
|
case BAP_STATE_CALLING:
|
|
case BAP_STATE_LISTENING:
|
|
|
|
BapTrace("Nak'ing %s on HCONN 0x%x from state %s",
|
|
szRequest, pBcbLocal->hConnection, SzBapStateName[*pBapState]);
|
|
dwResponseCode = BAP_RESPONSE_NAK;
|
|
break;
|
|
|
|
case BAP_STATE_INITIAL:
|
|
case BAP_STATE_SENT_CALL_REQ:
|
|
case BAP_STATE_SENT_CALLBACK_REQ:
|
|
|
|
if ((*pBapState != BAP_STATE_INITIAL && FFavoredPeer(pBcbLocal)) ||
|
|
(*pBapState == BAP_STATE_INITIAL && !FOkToAddLink(pBcbLocal)))
|
|
{
|
|
// If a race condition occurs and we are the favored peer, then
|
|
// NAK. If our algo does not allow us to add a link (based on
|
|
// the bandwidth utilization), then NAK.
|
|
BapTrace("Nak'ing %s on HCONN 0x%x from state %s%s",
|
|
szRequest,
|
|
pBcbLocal->hConnection,
|
|
SzBapStateName[*pBapState],
|
|
*pBapState != BAP_STATE_INITIAL ?
|
|
": we are the favored peer" : "");
|
|
dwResponseCode = BAP_RESPONSE_NAK;
|
|
}
|
|
else
|
|
{
|
|
// State is Initial and it is OK to add a link or
|
|
// State is Sent-Call[back]_Req and we are not the favored peer
|
|
// (so we should drop our request and agree to the peer's
|
|
// request).
|
|
|
|
if (*pBapState != BAP_STATE_INITIAL)
|
|
{
|
|
*pBapState = BAP_STATE_INITIAL;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x: we are not "
|
|
"the favored peer",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
|
|
// Do not retransmit the request.
|
|
RemoveFromTimerQ(pBcbLocal->dwBundleId, pBapCbLocal->dwId,
|
|
PPP_BAP_PROTOCOL, FALSE /* fAuthenticator */,
|
|
TIMER_EVENT_TIMEOUT);
|
|
}
|
|
|
|
if (FFillBapCb(dwPacketType, pBcbLocal, pBapCbRemote))
|
|
{
|
|
BapTrace("Ack'ing %s on HCONN 0x%x",
|
|
szRequest, pBcbLocal->hConnection);
|
|
dwOptions = pBapCbLocal->dwOptions;
|
|
dwResponseCode = BAP_RESPONSE_ACK;
|
|
}
|
|
else if (pBapCbLocal->dwOptions & BAP_N_LINK_TYPE)
|
|
{
|
|
// We don't have the link type requested
|
|
|
|
BapTrace("Nak'ing %s on HCONN 0x%x: link type not available",
|
|
szRequest, pBcbLocal->hConnection);
|
|
dwOptions = pBapCbLocal->dwOptions;
|
|
dwResponseCode = BAP_RESPONSE_NAK;
|
|
}
|
|
else
|
|
{
|
|
// We don't know our own phone number or no link is
|
|
// available
|
|
|
|
BapTrace("Full-Nak'ing %s on HCONN 0x%x: no link available",
|
|
szRequest, pBcbLocal->hConnection);
|
|
dwResponseCode = BAP_RESPONSE_FULL_NAK;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
PPP_ASSERT(FALSE);
|
|
BapTrace("In weird state: %d", *pBapState);
|
|
return;
|
|
}
|
|
}
|
|
|
|
pPcbLocal = GetPCBPointerFromBCB(pBcbLocal);
|
|
|
|
if (NULL == pPcbLocal)
|
|
{
|
|
BapTrace("BapEventRecvCallOrCallbackReq: No links in HCONN 0x%x!",
|
|
pBcbLocal->hConnection);
|
|
return;
|
|
}
|
|
|
|
fServer = (pBcbLocal->fFlags & BCBFLAG_IS_SERVER) != 0;
|
|
|
|
if (BAP_RESPONSE_ACK == dwResponseCode &&
|
|
fCall && !fServer &&
|
|
(ROUTER_IF_TYPE_FULL_ROUTER != pBcbLocal->InterfaceInfo.IfType))
|
|
{
|
|
// If we received a Call-Request and agreed to accept the call, we
|
|
// have to start listening if we are a non-router client. Servers
|
|
// and routers are always listening, so we do nothing.
|
|
|
|
// We do a listen first and then send the ACK to the Call-Request
|
|
// because the peer may start dialing as soon as it gets the ACK.
|
|
|
|
if (FListenForCall(pBapCbLocal->szPortName,
|
|
pBapCbLocal->dwSubEntryIndex, pPcbLocal))
|
|
{
|
|
*pBapState = BAP_STATE_LISTENING;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
}
|
|
else
|
|
{
|
|
BapTrace("Nak'ing %s on HCONN 0x%x",
|
|
szRequest, pBcbLocal->hConnection);
|
|
|
|
dwOptions = 0;
|
|
dwResponseCode = BAP_RESPONSE_NAK;
|
|
}
|
|
}
|
|
|
|
if (FSendBapResponse(pBcbLocal, dwOptions, dwPacketType, dwId,
|
|
dwResponseCode))
|
|
{
|
|
if (!fCall && (BAP_RESPONSE_ACK == dwResponseCode))
|
|
{
|
|
// We received a Callback-Request and we agreed to call.
|
|
if (FCallInitial(pBcbLocal, pBapCbRemote))
|
|
{
|
|
pBapCbLocal->dwStatusIndicationId = dwId;
|
|
*pBapState = BAP_STATE_CALLING;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
}
|
|
else
|
|
{
|
|
BapCallResult.dwResult = ERROR_INVALID_FUNCTION;
|
|
BapCallResult.hRasConn = (HRASCONN)-1;
|
|
BapEventCallResult(pBcbLocal, &BapCallResult);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
void
|
|
|
|
Description:
|
|
Called when a Link-Drop-Query-Request BAP Datagram is received. pBcbLocal
|
|
represents the bundle that receives the Request. The BAP Datagram Options
|
|
sent by the peer are in *pBapCbRemote. The Identifier of the BAP Datagram
|
|
sent by the peer is in dwId.
|
|
|
|
*/
|
|
|
|
VOID
|
|
BapEventRecvDropReq(
|
|
IN BCB* pBcbLocal,
|
|
IN BAPCB* pBapCbRemote,
|
|
IN DWORD dwId
|
|
)
|
|
{
|
|
BAPCB* pBapCbLocal;
|
|
BAP_STATE* pBapState;
|
|
DWORD dwResponseCode;
|
|
PCB* pPcbDrop;
|
|
CHAR* psz[2];
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
PPP_ASSERT(NULL != pBapCbRemote);
|
|
PPP_ASSERT(0xFF >= dwId);
|
|
|
|
pBapCbLocal = &(pBcbLocal->BapCb);
|
|
pBapState = &(pBapCbLocal->BapState);
|
|
|
|
PPP_ASSERT(BAP_STATE_LIMIT >= *pBapState);
|
|
|
|
BapTrace("BapEventRecvDropReq on HCONN 0x%x", pBcbLocal->hConnection);
|
|
|
|
if (!(pBcbLocal->fFlags & BCBFLAG_IS_SERVER))
|
|
{
|
|
psz[0] = pBcbLocal->szEntryName;
|
|
psz[1] = pBcbLocal->szLocalUserName;
|
|
PppLogInformation(ROUTERLOG_BAP_WILL_DISCONNECT, 2, psz);
|
|
}
|
|
|
|
if (NumLinksInBundle(pBcbLocal) == 1)
|
|
{
|
|
// Do not agree to drop the last link
|
|
BapTrace("Full-Nak'ing Link-Drop-Query-Request on HCONN 0x%x: last link",
|
|
pBcbLocal->hConnection);
|
|
dwResponseCode = BAP_RESPONSE_FULL_NAK;
|
|
}
|
|
else
|
|
{
|
|
switch(*pBapState)
|
|
{
|
|
case BAP_STATE_SENT_CALL_REQ:
|
|
case BAP_STATE_SENT_CALLBACK_REQ:
|
|
case BAP_STATE_SENT_STATUS_IND:
|
|
case BAP_STATE_CALLING:
|
|
case BAP_STATE_LISTENING:
|
|
|
|
BapTrace("Nak'ing Link-Drop-Query-Request on HCONN 0x%x from "
|
|
"state %s",
|
|
pBcbLocal->hConnection, SzBapStateName[*pBapState]);
|
|
dwResponseCode = BAP_RESPONSE_NAK;
|
|
break;
|
|
|
|
case BAP_STATE_INITIAL:
|
|
case BAP_STATE_SENT_DROP_REQ:
|
|
|
|
if (!FGetPcbOfLink(pBcbLocal, pBapCbRemote->dwLinkDiscriminator,
|
|
FALSE /* fRemote */, &pPcbDrop) ||
|
|
(*pBapState != BAP_STATE_INITIAL && FFavoredPeer(pBcbLocal)) ||
|
|
(*pBapState == BAP_STATE_INITIAL &&
|
|
!FOkToDropLink(pBcbLocal, pBapCbRemote)))
|
|
{
|
|
// The link discriminator sent by the peer is wrong. Or
|
|
// There is a race condition and we are the favored peer. Or
|
|
// Our algo does not allow us to drop a link (based on the
|
|
// bandwidth utilization).
|
|
BapTrace("Nak'ing Link-Drop-Query-Request on HCONN 0x%x from "
|
|
"state %s%s",
|
|
pBcbLocal->hConnection,
|
|
SzBapStateName[*pBapState],
|
|
*pBapState != BAP_STATE_INITIAL ?
|
|
": we are the favored peer" : "");
|
|
dwResponseCode = BAP_RESPONSE_NAK;
|
|
}
|
|
else
|
|
{
|
|
// State is Initial and it is OK to drop a link or
|
|
// State is Sent-Drop_Req and we are not the favored peer
|
|
// (so we should drop our request and agree to the peer's
|
|
// request).
|
|
|
|
if (*pBapState != BAP_STATE_INITIAL)
|
|
{
|
|
*pBapState = BAP_STATE_INITIAL;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x: we are not "
|
|
"the favored peer",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
|
|
// We will get a NAK from the peer. That is OK. He will be
|
|
// dropping a link. We don't have to drop any link.
|
|
pBapCbLocal->fForceDropOnNak = FALSE;
|
|
|
|
// Do not retransmit the request.
|
|
RemoveFromTimerQ(pBcbLocal->dwBundleId, pBapCbLocal->dwId,
|
|
PPP_BAP_PROTOCOL, FALSE /* fAuthenticator */,
|
|
TIMER_EVENT_TIMEOUT);
|
|
|
|
// Make sure that the peer will indeed drop this link.
|
|
InsertInTimerQ(pPcbDrop->dwPortId, pPcbDrop->hPort,
|
|
0 /* Id */, 0 /* Protocol */,
|
|
FALSE /* fAuthenticator */,
|
|
TIMER_EVENT_FAV_PEER_TIMEOUT,
|
|
BAP_TIMEOUT_FAV_PEER);
|
|
}
|
|
|
|
BapTrace("Ack'ing Link-Drop-Query-Request on HCONN 0x%x",
|
|
pBcbLocal->hConnection);
|
|
dwResponseCode = BAP_RESPONSE_ACK;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
PPP_ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
FSendBapResponse(pBcbLocal, 0 /* dwOptions */, BAP_PACKET_DROP_RESP,
|
|
dwId, dwResponseCode);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
void
|
|
|
|
Description:
|
|
Called when a Call-Status-Indication BAP Datagram is received. pBcbLocal
|
|
represents the bundle that receives the Indication. The BAP Datagram
|
|
Options sent by the peer are in *pBapCbRemote. The Identifier of the BAP
|
|
Datagram sent by the peer is in dwId.
|
|
|
|
*/
|
|
|
|
VOID
|
|
BapEventRecvStatusInd(
|
|
IN BCB* pBcbLocal,
|
|
IN BAPCB* pBapCbRemote,
|
|
IN DWORD dwId
|
|
)
|
|
{
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
PPP_ASSERT(NULL != pBapCbRemote);
|
|
PPP_ASSERT(0xFF >= dwId);
|
|
|
|
BapTrace("BapEventRecvStatusInd on HCONN 0x%x", pBcbLocal->hConnection);
|
|
|
|
FSendBapResponse(pBcbLocal, 0 /* dwOptions */, BAP_PACKET_STAT_RESP,
|
|
dwId, BAP_RESPONSE_ACK);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
void
|
|
|
|
Description:
|
|
Called when a Call-Response or Callback-Response BAP Datagram is received.
|
|
fCall is TRUE iff it is a Call-Response. pBcbLocal represents the bundle
|
|
that receives the Request. The BAP Datagram Options sent by the peer are in
|
|
*pBapCbRemote. The Identifier and Response Code of the BAP Datagram sent by
|
|
the peer are in dwId and dwResponseCode.
|
|
|
|
*/
|
|
|
|
VOID
|
|
BapEventRecvCallOrCallbackResp(
|
|
IN BOOL fCall,
|
|
IN BCB* pBcbLocal,
|
|
IN BAPCB* pBapCbRemote,
|
|
IN DWORD dwId,
|
|
IN DWORD dwResponseCode
|
|
)
|
|
{
|
|
BAPCB* pBapCbLocal;
|
|
BAP_STATE* pBapState;
|
|
BAP_CALL_RESULT BapCallResult;
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
PPP_ASSERT(NULL != pBapCbRemote);
|
|
PPP_ASSERT(0xFF >= dwId);
|
|
|
|
pBapCbLocal = &(pBcbLocal->BapCb);
|
|
pBapState = &(pBapCbLocal->BapState);
|
|
|
|
PPP_ASSERT(BAP_STATE_LIMIT >= *pBapState);
|
|
|
|
BapTrace("BapEventRecvCallOrCallbackResp on HCONN 0x%x",
|
|
pBcbLocal->hConnection);
|
|
|
|
if ((fCall && (*pBapState != BAP_STATE_SENT_CALL_REQ)) ||
|
|
(!fCall && (*pBapState != BAP_STATE_SENT_CALLBACK_REQ)) ||
|
|
dwId != pBapCbLocal->dwId)
|
|
{
|
|
BapTrace("Discarding unexpected Call[back]-Response (ID = %d) on "
|
|
"HCONN 0x%x",
|
|
dwId, pBcbLocal->hConnection);
|
|
return;
|
|
}
|
|
|
|
*pBapState = BAP_STATE_INITIAL;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
|
|
// Do not retransmit the request.
|
|
RemoveFromTimerQ(pBcbLocal->dwBundleId, dwId, PPP_BAP_PROTOCOL,
|
|
FALSE /* fAuthenticator */, TIMER_EVENT_TIMEOUT);
|
|
|
|
switch(dwResponseCode)
|
|
{
|
|
case BAP_RESPONSE_ACK:
|
|
|
|
if (fCall)
|
|
{
|
|
if (FCallInitial(pBcbLocal, pBapCbRemote))
|
|
{
|
|
pBapCbLocal->dwStatusIndicationId = dwId;
|
|
*pBapState = BAP_STATE_CALLING;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
}
|
|
else
|
|
{
|
|
BapCallResult.dwResult = ERROR_INVALID_FUNCTION;
|
|
BapCallResult.hRasConn = (HRASCONN)-1;
|
|
BapEventCallResult(pBcbLocal, &BapCallResult);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case BAP_RESPONSE_NAK:
|
|
|
|
if (pBapCbRemote->dwOptions & BAP_N_LINK_TYPE)
|
|
{
|
|
// The peer wants to use a different link type
|
|
|
|
if (FFillBapCb(
|
|
fCall ? BAP_PACKET_CALL_REQ : BAP_PACKET_CALLBACK_REQ,
|
|
pBcbLocal, pBapCbRemote))
|
|
{
|
|
if (FSendInitialBapRequest(pBcbLocal))
|
|
{
|
|
*pBapState = fCall ?
|
|
BAP_STATE_SENT_CALL_REQ : BAP_STATE_SENT_CALLBACK_REQ;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BapTrace("We don't have the reqd link type: %d on HCONN 0x%x",
|
|
pBapCbRemote->dwLinkType, pBcbLocal->hConnection);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The original Request MAY be retried after a little while.
|
|
// So we will not do anything here.
|
|
}
|
|
|
|
break;
|
|
|
|
case BAP_RESPONSE_REJ:
|
|
|
|
// We always try to send a Callback-Request first. If the peer rejects
|
|
// it, we can try to send a Call-Request. If the peer rejects a
|
|
// Call-Request, there is nothing that we can do.
|
|
|
|
pBcbLocal->fFlags |= (fCall ? BCBFLAG_PEER_CANT_ACCEPT_CALLS :
|
|
BCBFLAG_PEER_CANT_CALL);
|
|
|
|
if (pBcbLocal->fFlags & BCBFLAG_LISTENING)
|
|
{
|
|
BapTrace("Still listening; will not send Call-Request");
|
|
break;
|
|
}
|
|
|
|
if (!fCall && (pBcbLocal->fFlags & BCBFLAG_CAN_CALL))
|
|
{
|
|
if (FFillBapCb(BAP_PACKET_CALL_REQ, pBcbLocal,
|
|
NULL /* pBapCbRemote */))
|
|
{
|
|
if (FSendInitialBapRequest(pBcbLocal))
|
|
{
|
|
*pBapState = BAP_STATE_SENT_CALL_REQ;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case BAP_RESPONSE_FULL_NAK:
|
|
|
|
// Do not try to add links till the total bandwidth of the bundle
|
|
// has changed. However, we don't know the total bw. So we will not
|
|
// do anything here. After all, this is not a MUST.
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BapTrace("Unknown Response Code %d received on HCONN 0x%x",
|
|
dwResponseCode, pBcbLocal->hConnection);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
void
|
|
|
|
Description:
|
|
Called when a Link-Drop-Query-Response BAP Datagram is received. pBcbLocal
|
|
represents the bundle that receives the Response. The Identifier and
|
|
Response Code of the BAP Datagram sent by the peer are in dwId and
|
|
dwResponseCode.
|
|
|
|
*/
|
|
|
|
VOID
|
|
BapEventRecvDropResp(
|
|
IN BCB* pBcbLocal,
|
|
IN DWORD dwId,
|
|
IN DWORD dwResponseCode
|
|
)
|
|
{
|
|
BAPCB* pBapCbLocal;
|
|
BAP_STATE* pBapState;
|
|
PCB* pPcbDrop;
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
PPP_ASSERT(0xFF >= dwId);
|
|
|
|
pBapCbLocal = &(pBcbLocal->BapCb);
|
|
pBapState = &(pBapCbLocal->BapState);
|
|
|
|
PPP_ASSERT(BAP_STATE_LIMIT >= *pBapState);
|
|
|
|
BapTrace("BapEventRecvDropResp on HCONN 0x%x", pBcbLocal->hConnection);
|
|
|
|
if ((*pBapState != BAP_STATE_SENT_DROP_REQ) ||
|
|
dwId != pBapCbLocal->dwId)
|
|
{
|
|
BapTrace("Discarding unexpected Link-Drop-Query-Response (ID = %d) on "
|
|
"HCONN 0x%x",
|
|
dwId, pBcbLocal->hConnection);
|
|
return;
|
|
}
|
|
|
|
*pBapState = BAP_STATE_INITIAL;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
|
|
// Do not retransmit the request.
|
|
RemoveFromTimerQ(pBcbLocal->dwBundleId, dwId, PPP_BAP_PROTOCOL,
|
|
FALSE /* fAuthenticator */, TIMER_EVENT_TIMEOUT);
|
|
|
|
switch(dwResponseCode)
|
|
{
|
|
default:
|
|
|
|
BapTrace("Unknown Response Code %d received on HCONN 0x%x",
|
|
dwResponseCode, pBcbLocal->hConnection);
|
|
|
|
// Fall through (perhaps we need to drop a link)
|
|
|
|
case BAP_RESPONSE_NAK:
|
|
case BAP_RESPONSE_REJ:
|
|
case BAP_RESPONSE_FULL_NAK:
|
|
|
|
if ( (NumLinksInBundle(pBcbLocal) < pBapCbLocal->dwLinkCount)
|
|
|| !pBapCbLocal->fForceDropOnNak)
|
|
{
|
|
// Do not forcibly drop a link.
|
|
break;
|
|
}
|
|
|
|
// Fall through (to forcibly drop a link)
|
|
|
|
case BAP_RESPONSE_ACK:
|
|
|
|
if (FGetPcbOfLink(pBcbLocal, pBapCbLocal->dwLinkDiscriminator,
|
|
TRUE /* fRemote */, &pPcbDrop))
|
|
{
|
|
CHAR* psz[3];
|
|
|
|
if (!(pBcbLocal->fFlags & BCBFLAG_IS_SERVER))
|
|
{
|
|
psz[0] = pPcbDrop->pBcb->szEntryName;
|
|
psz[1] = pPcbDrop->pBcb->szLocalUserName;
|
|
psz[2] = pPcbDrop->szPortName;
|
|
PppLogInformation(ROUTERLOG_BAP_DISCONNECTED, 3, psz);
|
|
}
|
|
|
|
BapTrace("Dropping link with hPort %d from HCONN 0x%x",
|
|
pPcbDrop->hPort, pBcbLocal->hConnection);
|
|
pPcbDrop->LcpCb.dwError = ERROR_BAP_DISCONNECTED;
|
|
FsmClose(pPcbDrop, LCP_INDEX);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
void
|
|
|
|
Description:
|
|
Called when a Call-Status-Response BAP Datagram is received. pBcbLocal
|
|
represents the bundle that receives the Response. The Identifier and
|
|
Response Code of the BAP Datagram sent by the peer are in dwId and
|
|
dwResponseCode.
|
|
|
|
*/
|
|
|
|
VOID
|
|
BapEventRecvStatusResp(
|
|
IN BCB* pBcbLocal,
|
|
IN DWORD dwId,
|
|
IN DWORD dwResponseCode
|
|
)
|
|
{
|
|
BAPCB* pBapCbLocal;
|
|
BAP_STATE* pBapState;
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
PPP_ASSERT(0xFF >= dwId);
|
|
|
|
pBapCbLocal = &(pBcbLocal->BapCb);
|
|
pBapState = &(pBapCbLocal->BapState);
|
|
|
|
PPP_ASSERT(BAP_STATE_LIMIT >= *pBapState);
|
|
|
|
BapTrace("BapEventRecvStatusResp on HCONN 0x%x", pBcbLocal->hConnection);
|
|
|
|
if ((*pBapState != BAP_STATE_SENT_STATUS_IND) ||
|
|
dwId != pBapCbLocal->dwId)
|
|
{
|
|
BapTrace("Discarding unexpected Call-Status-Response (ID = %d) on "
|
|
"HCONN 0x%x",
|
|
dwId, pBcbLocal->hConnection);
|
|
return;
|
|
}
|
|
|
|
// Do not retransmit the indication.
|
|
RemoveFromTimerQ(pBcbLocal->dwBundleId, dwId, PPP_BAP_PROTOCOL,
|
|
FALSE /* fAuthenticator */, TIMER_EVENT_TIMEOUT);
|
|
|
|
if (pBapCbLocal->dwAction && FCall(pBcbLocal))
|
|
{
|
|
*pBapState = BAP_STATE_CALLING;
|
|
|
|
// BapEventRecvStatusResp or BapEventTimeout will get called at some
|
|
// point, and we will free pBapCbLocal->pbPhoneDeltaRemote.
|
|
}
|
|
else
|
|
{
|
|
*pBapState = BAP_STATE_INITIAL;
|
|
if (NULL != pBapCbLocal->pbPhoneDeltaRemote)
|
|
{
|
|
LOCAL_FREE(pBapCbLocal->pbPhoneDeltaRemote);
|
|
}
|
|
pBapCbLocal->pbPhoneDeltaRemote = NULL;
|
|
}
|
|
|
|
BapTrace("BAP state change to %s on HCONN 0x%x",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
void
|
|
|
|
Description:
|
|
Called when a BAP Datagram is received. pBcbLocal represents the bundle
|
|
that receives the Datagram. pPacket is the PPP packet which contains the
|
|
Datagram. dwPacketLength is the number of bytes in the PPP packet.
|
|
|
|
*/
|
|
|
|
VOID
|
|
BapEventReceive(
|
|
IN BCB* pBcbLocal,
|
|
IN PPP_PACKET* pPacket,
|
|
IN DWORD dwPacketLength
|
|
)
|
|
{
|
|
PPP_CONFIG* pConfig;
|
|
BAP_RESPONSE* pResponse;
|
|
DWORD dwLength;
|
|
DWORD dwType;
|
|
DWORD dwId;
|
|
BAPCB BapCbRemote;
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
PPP_ASSERT(NULL != pPacket);
|
|
|
|
// We don't know whether we have received a request or a response. Let us
|
|
// grab pointers to both the request part and the response part.
|
|
pConfig = (PPP_CONFIG *)(pPacket->Information);
|
|
pResponse = (BAP_RESPONSE *)(pPacket->Information);
|
|
|
|
// The Length, Type, and Id are always found in the same place, both for
|
|
// requests and responses. So let us get those values, assuming that we have
|
|
// received a request.
|
|
dwLength = WireToHostFormat16(pConfig->Length);
|
|
dwType = pConfig->Code;
|
|
dwId = pConfig->Id;
|
|
|
|
LogBapPacket(TRUE /* fReceived */, (HPORT)-1 /* hPort */,
|
|
pBcbLocal, pPacket, dwPacketLength);
|
|
|
|
if ((dwLength > dwPacketLength - PPP_PACKET_HDR_LEN) ||
|
|
(dwLength < PPP_CONFIG_HDR_LEN) ||
|
|
(dwType > BAP_PACKET_LIMIT) ||
|
|
!FReadOptions(pPacket, dwType, dwLength, &BapCbRemote))
|
|
{
|
|
BapTrace("Silently discarding badly formed BAP packet");
|
|
return;
|
|
}
|
|
|
|
switch(dwType)
|
|
{
|
|
case BAP_PACKET_CALL_REQ:
|
|
|
|
BapEventRecvCallOrCallbackReq(
|
|
TRUE /* fCall */,
|
|
pBcbLocal,
|
|
&BapCbRemote,
|
|
dwId);
|
|
return;
|
|
|
|
case BAP_PACKET_CALL_RESP:
|
|
|
|
BapEventRecvCallOrCallbackResp(
|
|
TRUE /* fCall */,
|
|
pBcbLocal,
|
|
&BapCbRemote,
|
|
dwId,
|
|
pResponse->ResponseCode);
|
|
return;
|
|
|
|
case BAP_PACKET_CALLBACK_REQ:
|
|
|
|
BapEventRecvCallOrCallbackReq(
|
|
FALSE /* fCall */,
|
|
pBcbLocal,
|
|
&BapCbRemote,
|
|
dwId);
|
|
return;
|
|
|
|
case BAP_PACKET_CALLBACK_RESP:
|
|
|
|
BapEventRecvCallOrCallbackResp(
|
|
FALSE /* fCall */,
|
|
pBcbLocal,
|
|
&BapCbRemote,
|
|
dwId,
|
|
pResponse->ResponseCode);
|
|
return;
|
|
|
|
case BAP_PACKET_DROP_REQ:
|
|
|
|
BapEventRecvDropReq(
|
|
pBcbLocal,
|
|
&BapCbRemote,
|
|
dwId);
|
|
return;
|
|
|
|
case BAP_PACKET_DROP_RESP:
|
|
|
|
BapEventRecvDropResp(
|
|
pBcbLocal,
|
|
dwId,
|
|
pResponse->ResponseCode);
|
|
return;
|
|
|
|
case BAP_PACKET_STATUS_IND:
|
|
|
|
BapEventRecvStatusInd(
|
|
pBcbLocal,
|
|
&BapCbRemote,
|
|
dwId);
|
|
return;
|
|
|
|
case BAP_PACKET_STAT_RESP:
|
|
|
|
BapEventRecvStatusResp(
|
|
pBcbLocal,
|
|
dwId,
|
|
pResponse->ResponseCode);
|
|
return;
|
|
|
|
default:
|
|
|
|
// The check above should have caught this case.
|
|
PPP_ASSERT(FALSE);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
void
|
|
|
|
Description:
|
|
Called when a BAP Request or Indication packet times out while waiting for
|
|
a Response. pBcbLocal represents the bundle that the packet was sent on.
|
|
The Identifier of the BAP Datagram is in dwId.
|
|
|
|
*/
|
|
|
|
VOID
|
|
BapEventTimeout(
|
|
IN BCB* pBcbLocal,
|
|
IN DWORD dwId
|
|
)
|
|
{
|
|
BAPCB* pBapCbLocal;
|
|
BAP_STATE* pBapState;
|
|
PCB* pPcbDrop;
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
|
|
pBapCbLocal = &(pBcbLocal->BapCb);
|
|
pBapState = &(pBapCbLocal->BapState);
|
|
|
|
PPP_ASSERT(BAP_STATE_LIMIT >= *pBapState);
|
|
|
|
if (dwId != pBapCbLocal->dwId ||
|
|
*pBapState == BAP_STATE_INITIAL ||
|
|
*pBapState == BAP_STATE_CALLING)
|
|
{
|
|
BapTrace("Illegal timeout occurred. Id: %d, BapCb's Id: %d, "
|
|
"BAP state: %s",
|
|
dwId, pBapCbLocal->dwId, SzBapStateName[*pBapState]);
|
|
return;
|
|
}
|
|
|
|
BapTrace("BAP packet (Type: %s, ID: %d) sent on HCONN 0x%x timed out.",
|
|
pBapCbLocal->dwType <= BAP_PACKET_LIMIT ?
|
|
SzBapPacketName[pBapCbLocal->dwType] : "UNKNOWN",
|
|
dwId, pBcbLocal->hConnection);
|
|
|
|
if (pBapCbLocal->dwRetryCount > 0)
|
|
{
|
|
// Send the packet once again
|
|
(pBapCbLocal->dwRetryCount)--;
|
|
FSendBapRequest(pBcbLocal);
|
|
|
|
// BapEventRecvStatusResp or BapEventTimeout will get called at some
|
|
// point, and we will free pBapCbLocal->pbPhoneDeltaRemote.
|
|
}
|
|
else
|
|
{
|
|
// We have sent the packet too many times. Discard it now.
|
|
BapTrace("Request retry exceeded.");
|
|
|
|
if (*pBapState == BAP_STATE_SENT_DROP_REQ)
|
|
{
|
|
// The peer did not respond to our Link-Drop-Query-Request. Perhaps
|
|
// we need to forcibly drop the link.
|
|
|
|
if (NumLinksInBundle(pBcbLocal) >= pBapCbLocal->dwLinkCount &&
|
|
pBapCbLocal->fForceDropOnNak)
|
|
{
|
|
if (FGetPcbOfLink(pBcbLocal, pBapCbLocal->dwLinkDiscriminator,
|
|
TRUE /*fRemote */, &pPcbDrop))
|
|
{
|
|
CHAR* psz[3];
|
|
|
|
if (!(pBcbLocal->fFlags & BCBFLAG_IS_SERVER))
|
|
{
|
|
psz[0] = pPcbDrop->pBcb->szEntryName;
|
|
psz[1] = pPcbDrop->pBcb->szLocalUserName;
|
|
psz[2] = pPcbDrop->szPortName;
|
|
PppLogInformation(ROUTERLOG_BAP_DISCONNECTED, 3, psz);
|
|
}
|
|
|
|
BapTrace("Dropping link with hPort %d from HCONN 0x%x",
|
|
pPcbDrop->hPort, pBcbLocal->hConnection);
|
|
pPcbDrop->LcpCb.dwError = ERROR_BAP_DISCONNECTED;
|
|
FsmClose(pPcbDrop, LCP_INDEX);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NULL != pBapCbLocal->pbPhoneDeltaRemote)
|
|
{
|
|
LOCAL_FREE(pBapCbLocal->pbPhoneDeltaRemote);
|
|
}
|
|
pBapCbLocal->pbPhoneDeltaRemote = NULL;
|
|
|
|
*pBapState = BAP_STATE_INITIAL;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
Returns:
|
|
void
|
|
|
|
Description:
|
|
Called when we know the result of a call attempt. pBcbLocal represents the
|
|
bundle that called out. *pBapCallResult contains information about the call
|
|
attempt.
|
|
|
|
*/
|
|
|
|
VOID
|
|
BapEventCallResult(
|
|
IN BCB* pBcbLocal,
|
|
IN BAP_CALL_RESULT* pBapCallResult
|
|
)
|
|
{
|
|
BAPCB* pBapCbLocal;
|
|
BAP_STATE* pBapState;
|
|
DWORD dwResult;
|
|
HPORT hPort;
|
|
PCB* pPcbNew;
|
|
PPP_MESSAGE PppMsg;
|
|
BOOL fWillCallAgain;
|
|
|
|
PPP_ASSERT(NULL != pBcbLocal);
|
|
PPP_ASSERT(NULL != pBapCallResult);
|
|
|
|
pBapCbLocal = &(pBcbLocal->BapCb);
|
|
pBapState = &(pBapCbLocal->BapState);
|
|
dwResult = pBapCallResult->dwResult;
|
|
|
|
// If we have to use pbPhoneDeltaRemote, it had better not be NULL
|
|
PPP_ASSERT(!pBapCbLocal->fPeerSuppliedPhoneNumber ||
|
|
(NULL != pBapCbLocal->pbPhoneDeltaRemote));
|
|
|
|
PPP_ASSERT(BAP_STATE_LIMIT >= *pBapState);
|
|
|
|
// The call failed, but we have other numbers to try
|
|
fWillCallAgain = (0 != dwResult) &&
|
|
pBapCbLocal->fPeerSuppliedPhoneNumber &&
|
|
(NULL != pBapCbLocal->pbPhoneDeltaRemote) &&
|
|
(0 !=
|
|
pBapCbLocal->pbPhoneDeltaRemote[pBapCbLocal->dwPhoneDeltaRemoteOffset]);
|
|
|
|
BapTrace("BapEventCallResult (%s) on HCONN 0x%x",
|
|
dwResult ? "failure" : "success",
|
|
pBcbLocal->hConnection);
|
|
*pBapState = BAP_STATE_INITIAL;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x",
|
|
SzBapStateName[*pBapState],
|
|
pBcbLocal->hConnection);
|
|
|
|
pBapCbLocal->dwType = BAP_PACKET_STATUS_IND;
|
|
pBapCbLocal->dwOptions = BAP_N_CALL_STATUS;
|
|
pBapCbLocal->dwStatus = dwResult ? 255 : 0;
|
|
pBapCbLocal->dwAction = fWillCallAgain;
|
|
|
|
if (FSendInitialBapRequest(pBcbLocal))
|
|
{
|
|
*pBapState = BAP_STATE_SENT_STATUS_IND;
|
|
BapTrace("BAP state change to %s on HCONN 0x%x",
|
|
SzBapStateName[*pBapState], pBcbLocal->hConnection);
|
|
|
|
// BapEventRecvStatusResp or BapEventTimeout will get called at some
|
|
// point, and we will free pBapCbLocal->pbPhoneDeltaRemote.
|
|
}
|
|
else
|
|
{
|
|
if (NULL != pBapCbLocal->pbPhoneDeltaRemote)
|
|
{
|
|
LOCAL_FREE(pBapCbLocal->pbPhoneDeltaRemote);
|
|
}
|
|
pBapCbLocal->pbPhoneDeltaRemote = NULL;
|
|
}
|
|
|
|
if (0 == dwResult)
|
|
{
|
|
if ((HRASCONN)-1 != pBapCallResult->hRasConn)
|
|
{
|
|
CHAR* psz[3];
|
|
|
|
// hRasConn will be -1 if we are here because of a message from Ddm,
|
|
// not RasDial().
|
|
hPort = RasGetHport(pBapCallResult->hRasConn);
|
|
pPcbNew = GetPCBPointerFromhPort(hPort);
|
|
if (NULL == pPcbNew)
|
|
{
|
|
BapTrace("BapEventCallResult: No PCB for new port %d in "
|
|
"HCONN 0x%x!",
|
|
hPort, pBcbLocal->hConnection);
|
|
return;
|
|
}
|
|
|
|
psz[0] = pPcbNew->pBcb->szLocalUserName;
|
|
psz[1] = pPcbNew->pBcb->szEntryName;
|
|
psz[2] = pPcbNew->szPortName;
|
|
PppLogInformation(ROUTERLOG_BAP_CLIENT_CONNECTED, 3, psz);
|
|
|
|
if ((ROUTER_IF_TYPE_FULL_ROUTER ==
|
|
pPcbNew->pBcb->InterfaceInfo.IfType))
|
|
{
|
|
// Inform Ddm that a new link is up. This allows MprAdmin, for
|
|
// example, to display Active Connections correctly.
|
|
ZeroMemory(&PppMsg, sizeof(PppMsg));
|
|
PppMsg.hPort = hPort;
|
|
PppMsg.dwMsgId = PPPDDMMSG_NewBapLinkUp;
|
|
|
|
PppMsg.ExtraInfo.BapNewLinkUp.hRasConn =
|
|
pBapCallResult->hRasConn;
|
|
|
|
PppConfigInfo.SendPPPMessageToDdm(&PppMsg);
|
|
}
|
|
}
|
|
}
|
|
}
|