1050 lines
28 KiB
C
1050 lines
28 KiB
C
/********************************************************************/
|
||
/** 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;
|
||
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 );
|
||
|
||
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->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;
|
||
|
||
// 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
|
||
|