You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1085 lines
30 KiB
1085 lines
30 KiB
/********************************************************************/
|
|
/** Copyright(c) 1998 Microsoft Corporation. **/
|
|
/********************************************************************/
|
|
|
|
//***
|
|
//
|
|
// Filename: rasatcp.c
|
|
|
|
//
|
|
// Description: Contains routines that implement the ATCP functionality.
|
|
//
|
|
// History: Feb 26, 1998 Shirish Koti Created original version.
|
|
//
|
|
//***
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
|
|
#include <lmcons.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <llinfo.h>
|
|
#include <rasman.h>
|
|
#include <rtutils.h>
|
|
#include <devioctl.h>
|
|
#include <rasppp.h>
|
|
#include <pppcp.h>
|
|
#define INCL_HOSTWIRE
|
|
#include <ppputil.h>
|
|
#include <raserror.h>
|
|
|
|
#include <arapio.h>
|
|
#include "rasatcp.h"
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
HANDLE AtcpHandle=NULL;
|
|
CRITICAL_SECTION AtcpCritSect;
|
|
BOOLEAN fCritSectInitialized = FALSE;
|
|
NET_ADDR AtcpServerAddress;
|
|
NET_ADDR AtcpDefaultRouter;
|
|
DWORD AtcpNumConnections=0;
|
|
UCHAR AtcpServerName[NAMESTR_LEN];
|
|
UCHAR AtcpZoneName[ZONESTR_LEN];
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: atcpStartup
|
|
// This routine does init time setup
|
|
//
|
|
// Return: result of operation
|
|
//
|
|
//***$
|
|
|
|
DWORD
|
|
atcpStartup(
|
|
IN VOID
|
|
)
|
|
{
|
|
DWORD dwRetCode=NO_ERROR;
|
|
DWORD dwSrvNameLen=MAX_COMPUTERNAME_LENGTH+1;
|
|
|
|
|
|
// get the server name
|
|
if (!GetComputerName((LPTSTR)&AtcpServerName[1],&dwSrvNameLen))
|
|
{
|
|
dwRetCode = GetLastError();
|
|
ATCP_DBGPRINT(("atcpStartup: GetComputerName failed %ld\n",dwRetCode));
|
|
return(dwRetCode);
|
|
}
|
|
|
|
// store it in Pascal string format
|
|
AtcpServerName[0] = (BYTE)dwSrvNameLen;
|
|
|
|
InitializeCriticalSection( &AtcpCritSect );
|
|
fCritSectInitialized = TRUE;
|
|
|
|
return(dwRetCode);
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: atcpShutdown
|
|
// This routine does de-init time work
|
|
//
|
|
// Return: result of operation
|
|
//
|
|
//***$
|
|
|
|
DWORD
|
|
atcpShutdown(
|
|
IN VOID
|
|
)
|
|
{
|
|
DWORD dwRetCode=NO_ERROR;
|
|
|
|
if (fCritSectInitialized)
|
|
{
|
|
fCritSectInitialized = FALSE;
|
|
DeleteCriticalSection( &AtcpCritSect );
|
|
}
|
|
|
|
return(dwRetCode);
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: atcpOpenHandle
|
|
// Opens the RAS device exported by the appletalk stack
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Return: None
|
|
//
|
|
// Globals: AtcpHandle, if successful
|
|
//
|
|
//***$
|
|
|
|
VOID
|
|
atcpOpenHandle(
|
|
IN VOID
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING DeviceName;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
HANDLE hLocalHandle;
|
|
|
|
|
|
if (AtcpHandle)
|
|
{
|
|
ATCP_DBGPRINT(("atcpOpenHandle: handle %lx already open!\n",AtcpHandle));
|
|
return;
|
|
}
|
|
|
|
RtlInitUnicodeString( &DeviceName, ARAP_DEVICE_NAME );
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&DeviceName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
status = NtCreateFile(
|
|
&hLocalHandle,
|
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
|
|
&ObjectAttributes,
|
|
&IoStatus,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN_IF,
|
|
0,
|
|
NULL,
|
|
0 );
|
|
|
|
|
|
if ( NT_SUCCESS(status) )
|
|
{
|
|
AtcpHandle = hLocalHandle;
|
|
ATCP_DBGPRINT(("atcpOpenHandle: NtCreateFile succeeded\n",status));
|
|
}
|
|
else
|
|
{
|
|
ATCP_DBGPRINT(("atcpOpenHandle: NtCreateFile failed %lx\n",status));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: atcpCloseHandle
|
|
// Closes the RAS device (opened in atcpOpenHandle)
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Return: None
|
|
//
|
|
// Globals: AtalkHandle
|
|
//
|
|
//***$
|
|
|
|
VOID
|
|
atcpCloseHandle(
|
|
IN VOID
|
|
)
|
|
{
|
|
NTSTATUS status=STATUS_SUCCESS;
|
|
|
|
|
|
if (!AtcpHandle)
|
|
{
|
|
ATCP_DBGPRINT(("atcpCloseHandle: handle already closed!\n"));
|
|
return;
|
|
}
|
|
|
|
status = NtClose( AtcpHandle );
|
|
|
|
AtcpHandle = NULL;
|
|
|
|
if ( !NT_SUCCESS( status ) )
|
|
{
|
|
ATCP_DBGPRINT(("atcpCloseHandle: NtClose failed %lx\n",status));
|
|
ATCP_ASSERT(0);
|
|
}
|
|
else
|
|
{
|
|
ATCP_DBGPRINT(("atcpCloseHandle: NtClose succeeded\n",status));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: atcpAtkSetup
|
|
// This is the entry point into the stack to tell the stack to
|
|
// set up a context for this connection, to get a network address
|
|
// for the dial-in client, server's zone name, and router address
|
|
//
|
|
// Parameters: pAtcpConn - connection context
|
|
//
|
|
// Return: status returned by NtDeviceIoControlFile
|
|
//
|
|
//***$
|
|
|
|
DWORD
|
|
atcpAtkSetup(
|
|
IN PATCPCONN pAtcpConn,
|
|
IN ULONG IoControlCode
|
|
)
|
|
{
|
|
|
|
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK iosb;
|
|
HANDLE Event;
|
|
BYTE Buffer[sizeof(ARAP_SEND_RECV_INFO) + sizeof(ATCPINFO)];
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo;
|
|
PATCPINFO pAtcpInfo;
|
|
PATCP_SUPPRESS_INFO pSupprInfo;
|
|
DWORD dwRetCode=NO_ERROR;
|
|
|
|
|
|
RtlZeroMemory((PBYTE)Buffer, sizeof(Buffer));
|
|
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)Buffer;
|
|
pSndRcvInfo->StatusCode = (DWORD)-1;
|
|
pSndRcvInfo->pDllContext = (PVOID)pAtcpConn;
|
|
pSndRcvInfo->IoctlCode = IoControlCode;
|
|
pSndRcvInfo->ClientAddr = pAtcpConn->ClientAddr;
|
|
|
|
if (IoControlCode == IOCTL_ATCP_SETUP_CONNECTION)
|
|
{
|
|
pSndRcvInfo->DataLen = sizeof(ATCPINFO);
|
|
}
|
|
else if (IoControlCode == IOCTL_ATCP_SUPPRESS_BCAST)
|
|
{
|
|
// if we don't need to suppress broadcasts, done here
|
|
if ((!pAtcpConn->SuppressRtmp) && (!pAtcpConn->SuppressAllBcast))
|
|
{
|
|
return(NO_ERROR);
|
|
}
|
|
pSndRcvInfo->DataLen = sizeof(ATCP_SUPPRESS_INFO);
|
|
|
|
pSupprInfo = (PATCP_SUPPRESS_INFO)&pSndRcvInfo->Data[0];
|
|
pSupprInfo->SuppressRtmp = pAtcpConn->SuppressRtmp;
|
|
pSupprInfo->SuppressAllBcast = pAtcpConn->SuppressAllBcast;
|
|
}
|
|
else
|
|
{
|
|
pSndRcvInfo->DataLen = 0;
|
|
}
|
|
|
|
Event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (Event == NULL)
|
|
{
|
|
ATCP_DBGPRINT(("atcpAtkSetup: CreateEvent failed (%ld)\n",GetLastError()));
|
|
return(ARAPERR_OUT_OF_RESOURCES);
|
|
}
|
|
|
|
status = NtDeviceIoControlFile(
|
|
AtcpHandle,
|
|
Event, // Event
|
|
NULL, // ApcRoutine
|
|
NULL, // ApcContext
|
|
&iosb, // IoStatusBlock
|
|
IoControlCode, // IoControlCode
|
|
Buffer, // InputBuffer
|
|
sizeof(Buffer), // InputBufferSize
|
|
Buffer, // OutputBuffer
|
|
sizeof(Buffer)); // OutputBufferSize
|
|
|
|
|
|
if (status == STATUS_PENDING)
|
|
{
|
|
status = NtWaitForSingleObject(
|
|
Event, // Handle
|
|
TRUE, // Alertable
|
|
NULL); // Timeout
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
status = iosb.Status;
|
|
}
|
|
}
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
ATCP_DBGPRINT(("atcpAtkSetup: NtDeviceIoControlFile failure (%lx)\n",
|
|
status));
|
|
dwRetCode = ARAPERR_IOCTL_FAILURE;
|
|
}
|
|
|
|
CloseHandle(Event);
|
|
|
|
dwRetCode = pSndRcvInfo->StatusCode;
|
|
|
|
if (dwRetCode != NO_ERROR)
|
|
{
|
|
ATCP_DBGPRINT(("atcpAtkSetup: ioctl %lx failed %ld\n",
|
|
IoControlCode,dwRetCode));
|
|
return(dwRetCode);
|
|
}
|
|
|
|
//
|
|
// for SETUP ioctl, we have some info from stack we need to copy
|
|
//
|
|
if (IoControlCode == IOCTL_ATCP_SETUP_CONNECTION)
|
|
{
|
|
pAtcpInfo = (PATCPINFO)&pSndRcvInfo->Data[0];
|
|
|
|
// get the client's address out
|
|
EnterCriticalSection(&pAtcpConn->CritSect);
|
|
|
|
pAtcpConn->AtalkContext = pSndRcvInfo->AtalkContext;
|
|
pAtcpConn->ClientAddr = pSndRcvInfo->ClientAddr;
|
|
|
|
LeaveCriticalSection(&pAtcpConn->CritSect);
|
|
|
|
//
|
|
// get the default router's address and the zone name
|
|
//
|
|
EnterCriticalSection( &AtcpCritSect );
|
|
|
|
AtcpServerAddress = pAtcpInfo->ServerAddr;
|
|
AtcpDefaultRouter = pAtcpInfo->DefaultRouterAddr;
|
|
|
|
ATCP_ASSERT(pAtcpInfo->ServerZoneName[0] < ZONESTR_LEN);
|
|
|
|
CopyMemory(&AtcpZoneName[1],
|
|
&pAtcpInfo->ServerZoneName[1],
|
|
pAtcpInfo->ServerZoneName[0]);
|
|
|
|
AtcpZoneName[0] = pAtcpInfo->ServerZoneName[0];
|
|
|
|
// got one more connection!
|
|
AtcpNumConnections++;
|
|
|
|
LeaveCriticalSection( &AtcpCritSect );
|
|
}
|
|
|
|
return(dwRetCode);
|
|
}
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: atcpAllocConnection
|
|
// This routine allocates an ATCP connection block, initializes
|
|
// it with info provided by PPP engine.
|
|
//
|
|
// Parameters: pInfo - PPPCP_INIT info
|
|
//
|
|
// Return: pointer to ATCP connection if successful, NULL otherwise
|
|
//
|
|
//***$
|
|
|
|
PATCPCONN
|
|
atcpAllocConnection(
|
|
IN PPPCP_INIT *pPppInit
|
|
)
|
|
{
|
|
PATCPCONN pAtcpConn=NULL;
|
|
|
|
|
|
pAtcpConn = (PATCPCONN)LocalAlloc(LPTR, sizeof(ATCPCONN));
|
|
|
|
if (pAtcpConn == NULL)
|
|
{
|
|
ATCP_DBGPRINT(("atcpAllocConnection: malloc failed\n"));
|
|
return(NULL);
|
|
}
|
|
|
|
memset( pAtcpConn, 0, sizeof(ATCPCONN) );
|
|
|
|
pAtcpConn->Signature = ATCP_SIGNATURE;
|
|
|
|
// by default, broadcasts are not suppressed
|
|
pAtcpConn->SuppressRtmp = FALSE;
|
|
pAtcpConn->SuppressAllBcast = FALSE;
|
|
|
|
pAtcpConn->fLineUpDone = FALSE;
|
|
|
|
InitializeCriticalSection( &pAtcpConn->CritSect );
|
|
pAtcpConn->fCritSectInitialized = TRUE;
|
|
|
|
pAtcpConn->hPort = pPppInit->hPort;
|
|
pAtcpConn->hConnection = pPppInit->hConnection;
|
|
|
|
return(pAtcpConn);
|
|
}
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: atcpParseRequest
|
|
// This routine parses the incoming ATCP packet and prepares a
|
|
// response as appropriate (Rej, Nak or Ack)
|
|
//
|
|
// AppleTalk-Address
|
|
// 1 6 0 AT-NET(2) AT-Node (1)
|
|
// Routing-Protocol
|
|
// 2 4 0 0 (Routing protocol - last 2 bytes - can be 0, 1, 2, 3:
|
|
// we only support 0)
|
|
// Suppress-Broadcasts
|
|
// 3 2 (to suppress all broadcasts)
|
|
// 3 3 1 (to suppress RTMP bcasts. We don't support other types)
|
|
// AT-Compression-Protocol
|
|
// 4 4 Undefined!
|
|
// Server-information
|
|
// 6 Len .....
|
|
// Zone-Information
|
|
// 7 Len ZoneName
|
|
// Default-Router-Address
|
|
// 8 6 0 AT-NET(2) AT-Node (1)
|
|
//
|
|
//
|
|
// Parameters: pAtcpConn - the connection
|
|
// pReceiveBuf - PPP_CONFIG info: the request
|
|
// pSendBuf - PPP_CONFIG info: our response
|
|
// cbSendBuf - how big is the Data buffer for our response (for Rej)
|
|
// ParseResult - array where we mark off options we saw
|
|
// pfRejectingSomething - pointer to TRUE if Rejecting something
|
|
//
|
|
// Return: result of the operation
|
|
//
|
|
//***$
|
|
|
|
DWORD
|
|
atcpParseRequest(
|
|
IN PATCPCONN pAtcpConn,
|
|
IN PPP_CONFIG *pReceiveBuf,
|
|
OUT PPP_CONFIG *pSendBuf,
|
|
IN DWORD cbSendBuf,
|
|
OUT BYTE ParseResult[ATCP_OPT_MAX_VAL+1],
|
|
OUT BOOL *pfRejectingSomething
|
|
)
|
|
{
|
|
PPP_OPTION UNALIGNED *pRequest;
|
|
PPP_OPTION UNALIGNED *pReject;
|
|
DWORD BytesLeftInSendBuf;
|
|
PBYTE pOptData;
|
|
USHORT OptDataLen;
|
|
USHORT PktLen;
|
|
USHORT RequestLen;
|
|
USHORT UnParsedBytes;
|
|
NET_ADDR ClientAddr;
|
|
DWORD i;
|
|
|
|
|
|
*pfRejectingSomething = FALSE;
|
|
|
|
pRequest = (PPP_OPTION UNALIGNED* )pReceiveBuf->Data;
|
|
pReject = (PPP_OPTION UNALIGNED* )pSendBuf->Data;
|
|
|
|
BytesLeftInSendBuf = cbSendBuf;
|
|
|
|
PktLen = WireToHostFormat16( pReceiveBuf->Length );
|
|
UnParsedBytes = PktLen - PPP_CONFIG_HDR_LEN;
|
|
|
|
if (pRequest->Type > ATCP_OPT_MAX_VAL)
|
|
{
|
|
ATCP_DBGPRINT(("atcpParseRequest: invalid type %d\n",
|
|
pRequest->Type));
|
|
return(ERROR_PPP_INVALID_PACKET);
|
|
}
|
|
|
|
// initialize for now to "nothing requested"
|
|
for (i=0; i<ATCP_OPT_MAX_VAL; i++)
|
|
{
|
|
ParseResult[i] = ATCP_NOT_REQUESTED;
|
|
}
|
|
|
|
//
|
|
// we loop until we have parsed all the bytes
|
|
//
|
|
while (UnParsedBytes > 0)
|
|
{
|
|
RequestLen = (USHORT)pRequest->Length;
|
|
|
|
if (UnParsedBytes < RequestLen)
|
|
{
|
|
ATCP_DBGPRINT(("atcpParseRequest: too few bytes %d vs. %d\n",
|
|
UnParsedBytes,RequestLen));
|
|
return(ERROR_PPP_INVALID_PACKET);
|
|
}
|
|
|
|
//
|
|
// assume we're going to accept this option. We'll overwrite if that's
|
|
// not the case
|
|
//
|
|
ParseResult[pRequest->Type] = ATCP_ACK;
|
|
|
|
// the point where the data portion for this option starts
|
|
pOptData = &pRequest->Data[0];
|
|
|
|
// remove the Type and Len bytes, remaining is option data
|
|
OptDataLen = RequestLen - 2;
|
|
|
|
#if 0
|
|
ATCP_DBGPRINT(("atcpParseRequest: type %d OptLen %d (",
|
|
pRequest->Type,OptDataLen));
|
|
for (i=0; i<OptDataLen; i++)
|
|
{
|
|
DbgPrint(" 0x%x",pOptData[i]);
|
|
}
|
|
DbgPrint(" )\n");
|
|
#endif
|
|
|
|
|
|
//
|
|
// now look at each of the options and see if we should reject it,
|
|
// modify it or accept it (Rej, Nak or Ack)
|
|
//
|
|
switch (pRequest->Type)
|
|
{
|
|
//
|
|
// client wants an appletalk address. We don't allow the client to
|
|
// request which address he wants.
|
|
//
|
|
case ATCP_OPT_APPLETALK_ADDRESS:
|
|
|
|
if (RequestLen != 6)
|
|
{
|
|
ATCP_DBGPRINT(("atcpParseRequest: AT_ADDR wrong pktlen %d\n",
|
|
RequestLen));
|
|
return(ERROR_PPP_INVALID_PACKET);
|
|
}
|
|
|
|
ClientAddr.ata_Network =
|
|
WireToHostFormat16(&pOptData[1]);
|
|
|
|
ClientAddr.ata_Node = (USHORT)pOptData[3];
|
|
|
|
if ((ClientAddr.ata_Network == 0) ||
|
|
(ClientAddr.ata_Node == 0) ||
|
|
(ClientAddr.ata_Network != pAtcpConn->ClientAddr.ata_Network) ||
|
|
(ClientAddr.ata_Node != pAtcpConn->ClientAddr.ata_Node))
|
|
{
|
|
ParseResult[pRequest->Type] = ATCP_NAK;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
//
|
|
// client wants some routing protocol. we don't send out Routing
|
|
// info, so we should just Nak this option (unless the client also
|
|
// is telling us not to send any routing info)
|
|
//
|
|
case ATCP_OPT_ROUTING_PROTOCOL:
|
|
|
|
if (RequestLen < 4)
|
|
{
|
|
ATCP_DBGPRINT(("atcpParseRequest: ROUTING wrong pktlen %d\n",
|
|
RequestLen));
|
|
return(ERROR_PPP_INVALID_PACKET);
|
|
}
|
|
|
|
//
|
|
// we don't send out Routing info, so attempt to negotiate any
|
|
// other protocol should be Nak'ed
|
|
//
|
|
if ((*(USHORT *)&pOptData[0]) != ATCP_OPT_ROUTING_NONE)
|
|
{
|
|
ParseResult[pRequest->Type] = ATCP_NAK;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
//
|
|
// client wants to suppress broadcasts of some (or all) types of
|
|
// DDP types.
|
|
//
|
|
case ATCP_OPT_SUPPRESS_BROADCAST:
|
|
|
|
//
|
|
// client wants us to suppress only some bcasts?
|
|
//
|
|
if (OptDataLen > 0)
|
|
{
|
|
// if requesting RTMP data suppression, we'll allow it
|
|
if (pOptData[0] == DDPPROTO_RTMPRESPONSEORDATA)
|
|
{
|
|
pAtcpConn->SuppressRtmp = TRUE;
|
|
}
|
|
|
|
// hmm, some other protocol: sorry, no can do
|
|
else
|
|
{
|
|
ATCP_DBGPRINT(("atcpParseRequest: Naking suppression %d\n",
|
|
pOptData[0]));
|
|
ParseResult[pRequest->Type] = ATCP_NAK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pAtcpConn->SuppressAllBcast = TRUE;
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// client wants to negotiate some compression. No compression
|
|
// scheme is defined, so we just have to reject this option
|
|
//
|
|
case ATCP_OPT_AT_COMPRESSION_PROTOCOL:
|
|
|
|
ATCP_DBGPRINT(("atcpParseRequest: COMPRESSION sending Rej\n"));
|
|
|
|
if (BytesLeftInSendBuf >= RequestLen)
|
|
{
|
|
CopyMemory((PVOID)pReject, (PVOID)pRequest, RequestLen);
|
|
BytesLeftInSendBuf -= RequestLen;
|
|
}
|
|
else
|
|
{
|
|
ATCP_DBGPRINT(("atcpParseRequest: PPP engine's buffer too small\n",
|
|
RequestLen));
|
|
return(ERROR_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
pReject = (PPP_OPTION UNALIGNED *)((BYTE* )pReject + RequestLen);
|
|
|
|
*pfRejectingSomething = TRUE;
|
|
|
|
ParseResult[pRequest->Type] = ATCP_REJ;
|
|
|
|
break;
|
|
|
|
|
|
//
|
|
// for the following options, we just take note of the fact that
|
|
// the client has requested it and we send the info over. Nothing
|
|
// to negotiate in these options.
|
|
// (We aren't supposed to Nak these either)
|
|
//
|
|
case ATCP_OPT_RESERVED:
|
|
case ATCP_OPT_SERVER_INFORMATION:
|
|
case ATCP_OPT_ZONE_INFORMATION:
|
|
case ATCP_OPT_DEFAULT_ROUTER_ADDRESS:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ATCP_DBGPRINT(("atcpParseRequest: unknown type %d\n",
|
|
pRequest->Type));
|
|
return(ERROR_PPP_INVALID_PACKET);
|
|
}
|
|
|
|
//
|
|
// move to the next option
|
|
//
|
|
UnParsedBytes -= RequestLen;
|
|
|
|
pRequest = (PPP_OPTION UNALIGNED *)((BYTE* )pRequest + RequestLen);
|
|
}
|
|
|
|
//
|
|
// see if we are rejecting some option. If so, set some values
|
|
//
|
|
if (*pfRejectingSomething)
|
|
{
|
|
pSendBuf->Code = CONFIG_REJ;
|
|
|
|
HostToWireFormat16( (USHORT)((PBYTE)pReject - (PBYTE)pSendBuf),
|
|
pSendBuf->Length );
|
|
|
|
ATCP_DUMP_BYTES("atcpParseRequest: Rejecting these options:",
|
|
&pSendBuf->Data[0],
|
|
(DWORD)WireToHostFormat16( pSendBuf->Length)-4);
|
|
}
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: atcpPrepareResponse
|
|
// This routine prepares a response, depending on what all info
|
|
// was parsed out from the client's request.
|
|
//
|
|
// Parameters: pAtcpConn - the connection
|
|
// pSendBuf - PPP_CONFIG info: our response
|
|
// cbSendBuf - how big is the Data buffer for our response
|
|
// ParseResult - array where we have the parsed info
|
|
//
|
|
// Return: result of the operation
|
|
//
|
|
//***$
|
|
|
|
DWORD
|
|
atcpPrepareResponse(
|
|
IN PATCPCONN pAtcpConn,
|
|
OUT PPP_CONFIG *pSendBuf,
|
|
IN DWORD cbSendBuf,
|
|
OUT BYTE ParseResult[ATCP_OPT_MAX_VAL+1]
|
|
)
|
|
{
|
|
DWORD dwRetCode=NO_ERROR;
|
|
DWORD BytesLeftInSendBuf;
|
|
PPP_OPTION UNALIGNED *pResponse;
|
|
PBYTE pOptData;
|
|
USHORT OptDataLen;
|
|
USHORT OptionType;
|
|
DWORD i;
|
|
BOOL fNakingSomething=FALSE;
|
|
BOOL fRequestingSomething=FALSE;
|
|
BOOL fIncludeThisOption;
|
|
|
|
|
|
pResponse = (PPP_OPTION UNALIGNED* )pSendBuf->Data;
|
|
BytesLeftInSendBuf = cbSendBuf;
|
|
|
|
// first find out if we are going to be Nak'ing anything
|
|
for (OptionType=1; OptionType<ATCP_OPT_MAX_VAL; OptionType++ )
|
|
{
|
|
if (ParseResult[OptionType] == ATCP_NAK)
|
|
{
|
|
fNakingSomething = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// go through our array to see which options we must send Nak to
|
|
// (or construct Ack for the whole request)
|
|
//
|
|
for (OptionType=1; OptionType<ATCP_OPT_MAX_VAL; OptionType++ )
|
|
{
|
|
//
|
|
// if this option is not (to be) requested, we don't send anything
|
|
//
|
|
if (ParseResult[OptionType] == ATCP_NOT_REQUESTED)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// if Nak'ing something and it's not this option to be Nak'ed, skip it
|
|
if (fNakingSomething && (ParseResult[OptionType] != ATCP_NAK))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// make sure we have at least 2 bytes for the OptionType and OptionLen
|
|
//
|
|
if (BytesLeftInSendBuf < 2)
|
|
{
|
|
ATCP_DBGPRINT(("atcpPrepareResponse: A: buf too small\n"));
|
|
return(ERROR_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
BytesLeftInSendBuf -= 2;
|
|
|
|
pOptData = &pResponse->Data[0];
|
|
OptDataLen = 0;
|
|
|
|
fIncludeThisOption = TRUE;
|
|
|
|
switch (OptionType)
|
|
{
|
|
//
|
|
// tell client (again) the client's network address
|
|
//
|
|
case ATCP_OPT_APPLETALK_ADDRESS:
|
|
|
|
OptDataLen = sizeof(NET_ADDR);
|
|
|
|
if (BytesLeftInSendBuf < OptDataLen)
|
|
{
|
|
ATCP_DBGPRINT(("atcpPrepareResponse: B: buf too small\n"));
|
|
return(ERROR_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
// skip the reserved byte
|
|
*pOptData++ = 0;
|
|
|
|
//
|
|
// if we are sending our REQUEST, send server's address
|
|
//
|
|
if (ParseResult[OptionType] == ATCP_REQ)
|
|
{
|
|
// put in the network address
|
|
HostToWireFormat16(AtcpServerAddress.ata_Network, pOptData);
|
|
pOptData += sizeof(USHORT);
|
|
|
|
// put in the network node
|
|
ATCP_ASSERT(pAtcpConn->ClientAddr.ata_Node != 0);
|
|
*pOptData++ = (BYTE)AtcpServerAddress.ata_Node;
|
|
|
|
fRequestingSomething = TRUE;
|
|
}
|
|
|
|
//
|
|
// no, we must send the client's network address
|
|
//
|
|
else
|
|
{
|
|
// put in the network address
|
|
HostToWireFormat16(pAtcpConn->ClientAddr.ata_Network, pOptData);
|
|
pOptData += sizeof(USHORT);
|
|
|
|
// put in the network node
|
|
ATCP_ASSERT(pAtcpConn->ClientAddr.ata_Node != 0);
|
|
*pOptData++ = (BYTE)pAtcpConn->ClientAddr.ata_Node;
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// tell client (again) that we support no routing info
|
|
//
|
|
case ATCP_OPT_ROUTING_PROTOCOL:
|
|
|
|
OptDataLen = sizeof(USHORT);
|
|
|
|
HostToWireFormat16(ATCP_OPT_ROUTING_NONE, pOptData);
|
|
pOptData += sizeof(USHORT);
|
|
break;
|
|
|
|
//
|
|
// tell client that we can suppress RTMP or all Bcast
|
|
//
|
|
case ATCP_OPT_SUPPRESS_BROADCAST:
|
|
|
|
// if this is an ack, see if we have agreed to suppressing RTMP
|
|
if (!fNakingSomething)
|
|
{
|
|
if (pAtcpConn->SuppressRtmp)
|
|
{
|
|
OptDataLen = 1;
|
|
*pOptData++ = DDPPROTO_RTMPRESPONSEORDATA;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// we reach here only if are Acking the client's entire request
|
|
//
|
|
case ATCP_OPT_SERVER_INFORMATION:
|
|
|
|
ATCP_ASSERT(ParseResult[OptionType] != ATCP_NAK);
|
|
ATCP_ASSERT(!fNakingSomething);
|
|
|
|
OptDataLen = sizeof(USHORT) + sizeof(DWORD) + AtcpServerName[0];
|
|
|
|
if (BytesLeftInSendBuf < OptDataLen)
|
|
{
|
|
ATCP_DBGPRINT(("atcpPrepareResponse: C: buf too small\n"));
|
|
return(ERROR_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
// copy the server's class-id
|
|
HostToWireFormat16(ATCP_SERVER_CLASS, pOptData);
|
|
pOptData += sizeof(USHORT);
|
|
|
|
// copy the server's implementation-id
|
|
HostToWireFormat32(ATCP_SERVER_IMPLEMENTATION_ID, pOptData);
|
|
pOptData += sizeof(DWORD);
|
|
|
|
// copy the server's name
|
|
CopyMemory(pOptData, &AtcpServerName[1], AtcpServerName[0]);
|
|
|
|
break;
|
|
|
|
//
|
|
// we reach here only if are Acking the client's entire request
|
|
//
|
|
case ATCP_OPT_ZONE_INFORMATION:
|
|
|
|
ATCP_ASSERT(ParseResult[OptionType] != ATCP_NAK);
|
|
ATCP_ASSERT(!fNakingSomething);
|
|
|
|
// if we don't have a zone name, skip this option
|
|
if (AtcpZoneName[0] == 0)
|
|
{
|
|
fIncludeThisOption = FALSE;
|
|
break;
|
|
}
|
|
|
|
OptDataLen = AtcpZoneName[0];
|
|
|
|
if (BytesLeftInSendBuf < OptDataLen)
|
|
{
|
|
ATCP_DBGPRINT(("atcpPrepareResponse: D: buf too small\n"));
|
|
return(ERROR_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
// copy the zone name
|
|
CopyMemory(pOptData, &AtcpZoneName[1], AtcpZoneName[0]);
|
|
|
|
break;
|
|
|
|
|
|
//
|
|
// we reach here only if are Acking the client's entire request
|
|
//
|
|
case ATCP_OPT_DEFAULT_ROUTER_ADDRESS:
|
|
|
|
ATCP_ASSERT(ParseResult[OptionType] != ATCP_NAK);
|
|
ATCP_ASSERT(!fNakingSomething);
|
|
|
|
// if we don't have a router address, skip this option
|
|
if (AtcpDefaultRouter.ata_Network == 0)
|
|
{
|
|
fIncludeThisOption = FALSE;
|
|
break;
|
|
}
|
|
|
|
OptDataLen = sizeof(NET_ADDR);
|
|
|
|
if (BytesLeftInSendBuf < OptDataLen)
|
|
{
|
|
ATCP_DBGPRINT(("atcpPrepareResponse: E: buf too small\n"));
|
|
return(ERROR_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
// skip the reserved byte
|
|
*pOptData++ = 0;
|
|
|
|
// put in the network address
|
|
HostToWireFormat16(AtcpDefaultRouter.ata_Network, pOptData);
|
|
pOptData += sizeof(USHORT);
|
|
|
|
// put in the network node
|
|
*pOptData++ = (BYTE)AtcpDefaultRouter.ata_Node;
|
|
|
|
break;
|
|
|
|
default:
|
|
ATCP_DBGPRINT(("atcpPrepareResponse: opt %d ignored\n",OptionType));
|
|
ATCP_ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
if (fIncludeThisOption)
|
|
{
|
|
BytesLeftInSendBuf -= OptDataLen;
|
|
|
|
pResponse->Type = (BYTE)OptionType;
|
|
pResponse->Length = OptDataLen + 2; // 2 = 1 Type byte + 1 Length byte
|
|
|
|
pResponse = (PPP_OPTION UNALIGNED *)
|
|
((BYTE* )pResponse + pResponse->Length);
|
|
}
|
|
|
|
}
|
|
|
|
HostToWireFormat16( (USHORT)((PBYTE)pResponse - (PBYTE)pSendBuf),
|
|
pSendBuf->Length );
|
|
|
|
pSendBuf->Code = (fNakingSomething) ? CONFIG_NAK :
|
|
((fRequestingSomething)? CONFIG_REQ : CONFIG_ACK);
|
|
|
|
#if 0
|
|
if (pSendBuf->Code == CONFIG_REQ)
|
|
{
|
|
ATCP_DUMP_BYTES("atcpParseRequest: Sending our request:",
|
|
&pSendBuf->Data[0],
|
|
(DWORD)WireToHostFormat16( pSendBuf->Length)-4);
|
|
}
|
|
else if (pSendBuf->Code == CONFIG_NAK)
|
|
{
|
|
ATCP_DUMP_BYTES("atcpParseRequest: Nak'ing these options:",
|
|
&pSendBuf->Data[0],
|
|
(DWORD)WireToHostFormat16( pSendBuf->Length)-4);
|
|
}
|
|
else
|
|
{
|
|
ATCP_DUMP_BYTES("atcpParseRequest: Ack packet from us to client:",
|
|
&pSendBuf->Data[0],
|
|
(DWORD)WireToHostFormat16( pSendBuf->Length)-4);
|
|
}
|
|
#endif
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: atcpCloseAtalkConnection
|
|
// This routine tells the stack to close this ATCP connection
|
|
//
|
|
// Parameters: pAtcpConn - the connection to close
|
|
//
|
|
// Return: result of the operation
|
|
//
|
|
//***$
|
|
|
|
DWORD
|
|
atcpCloseAtalkConnection(
|
|
IN PATCPCONN pAtcpConn
|
|
)
|
|
{
|
|
DWORD dwRetCode=NO_ERROR;
|
|
|
|
// tell the stack that this connection is going away!
|
|
dwRetCode = atcpAtkSetup(pAtcpConn, IOCTL_ATCP_CLOSE_CONNECTION);
|
|
|
|
return(dwRetCode);
|
|
}
|
|
|
|
|
|
|
|
#if DBG
|
|
|
|
//***
|
|
//
|
|
// Function: atcpDumpBytes
|
|
// DEBUG only: This routine dumps out a given packet to debugger
|
|
//
|
|
// Parameters: Str - string, if any, to be printed out
|
|
// Packet - packet!
|
|
// PacketLen - how big is the packet
|
|
//
|
|
// Return: none
|
|
//
|
|
//***$
|
|
|
|
VOID
|
|
atcpDumpBytes(
|
|
IN PBYTE Str,
|
|
IN PBYTE Packet,
|
|
IN DWORD PacketLen
|
|
)
|
|
{
|
|
|
|
DWORD i;
|
|
|
|
|
|
if (Str)
|
|
{
|
|
DbgPrint("%s: Packet size %ld\n ",Str,PacketLen);
|
|
}
|
|
else
|
|
{
|
|
DbgPrint("Packet size %ld\n ",PacketLen);
|
|
}
|
|
|
|
for (i=0; i<PacketLen; i++)
|
|
{
|
|
DbgPrint("%x ",Packet[i]);
|
|
}
|
|
DbgPrint("\n");
|
|
}
|
|
#endif
|