Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

4648 lines
156 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Copyright (c) 1991 Nokia Data Systems
Module Name:
advanc.c
Abstract:
The module includes advanced testing thread procedures
for link level protocols:
DlcServer()
- generic DLC server module, used against all
DLC link level clients.
LinkFunctionalityTest()
- tests session setup and data transfer
LinkConnectStressTest()
- stress tests the link connection, small data transfer,
and disconnection
StressLinkDataTransfer()
- ultimate stress test for data transfer over link
Author:
Antti Saarenheimo (o-anttis) 10-Oct-1991
Revision History:
--*/
#include "dlctest.h"
#include <stdlib.h>
#include <dlcdebug.h>
//
// what's a foobar header? Originally, DLC (AcsLan) was skipping 3 bytes out
// of the start of a transmit buffer for most transmit commands. It was doing
// this because the IBM LAN Tech. Ref. kind of insinuates that this is what
// DLC should do. However it isn't. So to easily change 3 to 0 (and back again?)
// use FOOBAR_HEADER_LENGTH
//
#define FOOBAR_HEADER_LENGTH 0
UCHAR
TranslateLanHeader(
IN UINT AddressTranslationMode,
IN PUCHAR pSrcLanHeader,
OUT PUCHAR pDestLanHeader
);
enum _LLC_FRAME_XLATE_MODES {
LLC_SEND_802_5_TO_802_3,
LLC_SEND_802_5_TO_DIX,
LLC_SEND_802_5_TO_802_5,
LLC_SEND_DIX_TO_DIX,
LLC_SEND_802_3_TO_802_3,
LLC_SEND_802_3_TO_DIX,
LLC_SEND_802_3_TO_802_5,
LLC_SEND_UNMODIFIED
};
UCHAR FunctionalAddress1[4] = {0, 0, 1, 0};
static UCHAR FunctionalAddress2[4] = {0, 0x80, 0, 0};
static UCHAR FunctionalAddress3[4] = {0, 0x40, 0, 0};
static BOOLEAN TraceFlagSet = FALSE;
//static UCHAR DebugTable[256];
#define MAX_ALTERNATE_PARMS 4
static PVOID AlternateParms[MAX_ALTERNATE_PARMS];
UCHAR BroadcastHeader[16] = {0, 0x40, 0xc0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0, 0, 0xe2, 0x70};
static UCHAR TestBroadcastHeader[16] = {0, 0x40, 0xc0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0, 0, 0xe2, 0x70};
static UCHAR LanHeader[16] = {0, 0x40, 0xc0, 0, 0, 1, 0, 0, 0x80, 0, 0, 0, 0, 0, 0xe2, 0x70};
//static UCHAR TestLanHeader[16] =
// {0, 0x40, 0x10, 0, 0x5a, 0x7a, 0xa3, 0xb7, 0, 0, 0, 0, 0, 0, 0xc2, 0x70};
static UCHAR DixLanHeader[12];
static HANDLE hStartSignal;
BOOLEAN EventCheckDisabled = TRUE;
#ifdef OS2_EMU_DLC
static LLC_DLC_MODIFY_PARMS FirstModifyParms = {
0,
0,
10, // response timer (uchT1)
1, // aknowledgment timer (uchT2)
10, // inactivity timer (uchTi)
1, // max transmits without ack (uchMaxOut)
1, // max receives without ack (uchMaxIn)
1, // dynamic window increment value (uchMaxOutIncr)
5, // N2 value (retries) (uchMaxRetryCnt)
0, // (remote sap value for open link station)
-1, // (max i-field if DlcOpenSap or DlcOpenStation)
1, // token ring access priority (uchAccessPriority)
{0, 0, 0, 0},
0,
(PUCHAR)NULL
};
static LLC_DLC_MODIFY_PARMS DlcModifyParms1 = {
0,
0,
10, // response timer (uchT1)
1, // aknowledgment timer (uchT2)
10, // inactivity timer (uchTi)
1, // max transmits without ack (uchMaxOut)
1, // max receives without ack (uchMaxIn)
1, // dynamic window increment value (uchMaxOutIncr)
5, // N2 value (retries) (uchMaxRetryCnt)
0, // (remote sap value for open link station)
-1, // (max i-field if DlcOpenSap or DlcOpenStation)
1, // token ring access priority (uchAccessPriority)
{0, 0, 0, 0},
0,
(PUCHAR)NULL
};
static LLC_DLC_MODIFY_PARMS DlcModifyParms2 = {
0,
0,
10, // response timer (uchT1)
5, // aknowledgment timer (uchT2)
10, // inactivity timer (uchTi)
127, // max transmits without ack (uchMaxOut)
127, // max receives without ack (uchMaxIn)
255, // dynamic window increment value (uchMaxOutIncr)
255, // N2 value (retries) (uchMaxRetryCnt)
0, // (remote sap value for open link station)
-1, // (max i-field if DlcOpenSap or DlcOpenStation)
1, // token ring access priority (uchAccessPriority)
{0, 0, 0, 0},
0,
(PUCHAR)NULL
};
static LLC_DLC_MODIFY_PARMS DlcModifyParms3 = {
0,
0,
10, // response timer (uchT1)
1, // aknowledgment timer (uchT2)
10, // inactivity timer (uchTi)
10, // max transmits without ack (uchMaxOut)
5, // max receives without ack (uchMaxIn)
13, // dynamic window increment value (uchMaxOutIncr)
5, // N2 value (retries) (uchMaxRetryCnt)
0, // (remote sap value for open link station)
-1, // (max i-field if DlcOpenSap or DlcOpenStation)
1, // token ring access priority (uchAccessPriority)
{0, 0, 0, 0},
0,
(PUCHAR)NULL
};
static LLC_DLC_MODIFY_PARMS WrongDlcModifyParms = {
0,
0,
11, // response timer (uchT1)
1, // aknowledgment timer (uchT2)
10, // inactivity timer (uchTi)
10, // max transmits without ack (uchMaxOut)
5, // max receives without ack (uchMaxIn)
13, // dynamic window increment value (uchMaxOutIncr)
3, // N2 value (retries) (uchMaxRetryCnt)
0, // (remote sap value for open link station)
-1, // (max i-field if DlcOpenSap or DlcOpenStation)
4, // token ring access priority (uchAccessPriority)
{0, 0, 0, 0},
0,
(PUCHAR)NULL
};
#else
static LLC_DLC_MODIFY_PARMS DlcModifyParms1 = {
0,
0,
2, // response timer (uchT1)
1, // aknowledgment timer (uchT2)
5, // inactivity timer (uchTi)
1, // max transmits without ack (uchMaxOut)
1, // max receives without ack (uchMaxIn)
1, // dynamic window increment value (uchMaxOutIncr)
5, // N2 value (retries) (uchMaxRetryCnt)
0, // (remote sap value for open link station)
-1, // (max i-field if DlcOpenSap or DlcOpenStation)
1, // token ring access priority (uchAccessPriority)
{0, 0, 0, 0},
0,
(PUCHAR)NULL
};
static LLC_DLC_MODIFY_PARMS DlcModifyParms2 = {
0,
0,
5, // response timer (uchT1)
4, // aknowledgment timer (uchT2)
10, // inactivity timer (uchTi)
127, // max transmits without ack (uchMaxOut)
127, // max receives without ack (uchMaxIn)
255, // dynamic window increment value (uchMaxOutIncr)
255, // N2 value (retries) (uchMaxRetryCnt)
0, // (remote sap value for open link station)
-1, // (max i-field if DlcOpenSap or DlcOpenStation)
1, // token ring access priority (uchAccessPriority)
{0, 0, 0, 0},
0,
(PUCHAR)NULL
};
static LLC_DLC_MODIFY_PARMS DlcModifyParms3 = {
0,
0,
4, // response timer (uchT1)
1, // aknowledgment timer (uchT2)
7, // inactivity timer (uchTi)
10, // max transmits without ack (uchMaxOut)
5, // max receives without ack (uchMaxIn)
13, // dynamic window increment value (uchMaxOutIncr)
5, // N2 value (retries) (uchMaxRetryCnt)
0, // (remote sap value for open link station)
-1, // (max i-field if DlcOpenSap or DlcOpenStation)
1, // token ring access priority (uchAccessPriority)
{0, 0, 0, 0},
0,
(PUCHAR)NULL
};
static LLC_DLC_MODIFY_PARMS WrongDlcModifyParms = {
0,
0,
11, // response timer (uchT1)
1, // aknowledgment timer (uchT2)
10, // inactivity timer (uchTi)
10, // max transmits without ack (uchMaxOut)
5, // max receives without ack (uchMaxIn)
13, // dynamic window increment value (uchMaxOutIncr)
3, // N2 value (retries) (uchMaxRetryCnt)
0, // (remote sap value for open link station)
-1, // (max i-field if DlcOpenSap or DlcOpenStation)
4, // token ring access priority (uchAccessPriority)
{0, 0, 0, 0},
0,
(PUCHAR)NULL
};
static LLC_DLC_MODIFY_PARMS FirstModifyParms = {
0,
0,
2, // response timer (uchT1)
1, // aknowledgment timer (uchT2)
5, // inactivity timer (uchTi)
1, // max transmits without ack (uchMaxOut)
1, // max receives without ack (uchMaxIn)
1, // dynamic window increment value (uchMaxOutIncr)
40, // N2 value (retries) (uchMaxRetryCnt)
0, // (remote sap value for open link station)
-1, // (max i-field if DlcOpenSap or DlcOpenStation)
1, // token ring access priority (uchAccessPriority)
{0, 0, 0, 0},
0,
(PUCHAR)NULL
};
#endif
static LLC_DLC_MODIFY_PARMS DlcModifyQuickDeathParms = {
0,
0,
1, // response timer (uchT1)
1, // aknowledgment timer (uchT2)
5, // inactivity timer (uchTi)
1, // max transmits without ack (uchMaxOut)
1, // max receives without ack (uchMaxIn)
1, // dynamic window increment value (uchMaxOutIncr)
1, // N2 value (retries) (uchMaxRetryCnt)
0, // (remote sap value for open link station)
-1, // (max i-field if DlcOpenSap or DlcOpenStation)
1, // token ring access priority (uchAccessPriority)
{0, 0, 0, 0},
0,
(PUCHAR)NULL
};
UINT cSrvFramesTransmitted = 0;
UINT cSrvFramesReceived = 0;
UINT cSrvFramesReleased = 0;
UINT cSrvFramesSecondaryXmits = 0;
extern HANDLE hServerReady;
extern BOOL VerboseMode;
ULONG TestLinkStation(DLC_TEST_THREAD_PARMS *pThreadParms);
ULONG TestLinkStation(DLC_TEST_THREAD_PARMS *pThreadParms) {
PDLC_TEST_THREAD_PARMS pParms;
UINT CloseCounter;
UINT i = 0;
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
pThreadParms->pCloseCounter = &CloseCounter;
//
// We use these parameters to stress the extream parameter values
// of link station
//
AlternateParms[0] = &DlcModifyParms1;
AlternateParms[1] = &DlcModifyParms2;
AlternateParms[2] = &DlcModifyParms3;
AlternateParms[3] = NULL; // uses defaults
//
// We use the same buffer pool are for all functions
//
pThreadParms->pPool = ALLOC(DEFAULT_BUFFER_SIZE);
//
// We may execute the functionality test from the main thread
//
pParms = ALLOC(sizeof(DLC_TEST_THREAD_PARMS));
*pParms = *pThreadParms;
LinkFunctionalityTest(pParms);
//
// Start the link station connection stress threads
//
CloseCounter = 0;
pParms = ALLOC(sizeof(DLC_TEST_THREAD_PARMS));
*pParms = *pThreadParms;
puts("LinkConnectStressTest");
LinkConnectStressTest(pParms);
//
// Start the link station data transfer stress threads,
// Test at first the very fast data transfer (with compare)
// 25 * 48kB = 1.2 MB
//
pParms = ALLOC(sizeof(DLC_TEST_THREAD_PARMS));
*pParms = *pThreadParms;
pParms->ResetCommand = 0;
// pParms->LoopCount = 5;
pParms->LoopCount = 25;
puts("LinkDataTransferTest");
LinkDataTransferTest(pParms);
//
// Test the close commands when the link transmit is active
//
pThreadParms->AllocatedStations = 1;
puts("LinkDataTransferTest & closing with DIR_INITIALIZE");
pParms->LoopCount = 2;
pParms = ALLOC(sizeof(DLC_TEST_THREAD_PARMS));
*pParms = *pThreadParms;
pParms->ResetCommand = LLC_DIR_INITIALIZE;
LinkDataTransferTest(pParms);
//
// HERE WE USE AN INCORRECT RESET FUNCTION (DirOpenAdapter),
// but has been proved very use to test several different bugs
// in driver. We leave this here to prevent those damn bugs to
// come back.
//
puts("LinkDataTransferTest & closing with DIR_OPEN_ADAPTER (I know it's wrong)");
pParms = ALLOC(sizeof(DLC_TEST_THREAD_PARMS));
*pParms = *pThreadParms;
pParms->ResetCommand = LLC_DIR_OPEN_ADAPTER;
LinkDataTransferTest(pParms);
puts("LinkDataTransferTest & closing with DLC_RESET");
pParms = ALLOC(sizeof(DLC_TEST_THREAD_PARMS));
*pParms = *pThreadParms;
pParms->ResetCommand = LLC_DLC_RESET;
puts("LinkDataTransferTest & closing with DIR_CLOSE_ADAPTER");
pParms = ALLOC(sizeof(DLC_TEST_THREAD_PARMS));
*pParms = *pThreadParms;
pParms->ResetCommand = LLC_DIR_CLOSE_ADAPTER;
LinkDataTransferTest(pParms);
EnterCriticalSection(&CloseSection);
(*pThreadParms->pCloseCounter)--;
LeaveCriticalSection(&CloseSection);
//
// ThreadParms is not malloc'd
//
// FREE(pThreadParms);
puts("Test completed successfully.");
exit(0);
return 0;
}
/*
LLC_DIRECT_TRANSMIT = 0x0000, // transmit
LLC_DIRECT_MAC = 0x0002, // receive
LLC_I_FRAME = 0x0004, // receive & transmit
LLC_UI_FRAME = 0x0006, // receive & transmit
LLC_XID_COMMAND_POLL = 0x0008, // receive & transmit
LLC_XID_COMMAND_NOT_POLL = 0x000A, // receive & transmit
LLC_XID_RESPONSE_FINAL = 0x000C, // receive & transmit
LLC_XID_RESPONSE_NOT_FINAL = 0x000E, // receive & transmit
LLC_TEST_RESPONSE_FINAL = 0x0010, // receive & transmit
LLC_TEST_RESPONSE_NOT_FINAL = 0x0012, // receive & transmit
LLC_DIRECT_8022 = 0x0014, // receive (direct station)
LLC_TEST_COMMAND_POLL = 0x0016, // transmit
LLC_DIRECT_ETHERNET_TYPE = 0x0018, // receive (direct station)
*/
static USHORT ResponseTable[(LLC_DIRECT_ETHERNET_TYPE + 2) / 2] = {
0, // LLC_DIRECT_TRANSMIT = 0x0000, // transmit
0, // LLC_DIRECT_MAC = 0x0002, // receive
0, // LLC_I_FRAME = 0x0004, // receive & transmit
LLC_UI_FRAME,
LLC_XID_RESPONSE_FINAL,
LLC_XID_RESPONSE_NOT_FINAL,
0, // LLC_XID_RESPONSE_FINAL = 0x000C, // receive & transmit
0, // LLC_XID_RESPONSE_NOT_FINAL = 0x000E, // receive & transmit
0, // LLC_TEST_RESPONSE_FINAL = 0x0010, // receive & transmit
0, // LLC_TEST_RESPONSE_NOT_FINAL = 0x0012, // receive & transmit
0, // LLC_DIRECT_8022 = 0x0014, // receive (direct station)
0, // LLC_TEST_COMMAND_POLL = 0x0016, // transmit
-1 // LLC_DIRECT_ETHERNET_TYPE = 0x0018, // receive (direct station)
};
ULONG
DlcServer(
IN PDLC_TEST_THREAD_PARMS pParms
);
UINT
FreeReceiveBuffers(
UCHAR AdapterNumber,
PLLC_BUFFER pFirstBuffer,
PLLC_BUFFER *ppNextFrame,
PUINT pcLeft
)
/*++
This routine frees all chained frames received by Dlc test server.
This procedure makes only one BufferFree command for
a very large number of received frames.
--*/
{
PLLC_BUFFER pBuffer;
PLLC_BUFFER pFrame;
UINT FrameCount = 1;
UINT Status;
//
// Create buffer chain of all 'TEST_COMMAND_READ' packets
// in the buffer chain.
//
pBuffer = pFirstBuffer;
for (pFrame = pFirstBuffer->Contiguous.pNextFrame;
pFrame != NULL;
pFrame = pFrame->Contiguous.pNextFrame
) {
PDLC_TEST_PACKET pDlcPacket;
pDlcPacket = (PDLC_TEST_PACKET)((PUCHAR)pFrame
+ pFrame->Next.cbUserData
+ pFrame->Next.offUserData
);
if ((pDlcPacket->PacketId != DLC_TEST_ID)
|| (pDlcPacket->Command != TEST_COMMAND_READ)) {
break;
}
FrameCount++;
while (pBuffer->pNext != NULL) {
pBuffer = pBuffer->pNext;
}
pBuffer->pNext = pFrame;
pBuffer = pFrame;
}
Status = BufferFree(AdapterNumber,
pFirstBuffer,
pcLeft
);
DBG_ASSERT(Status);
*ppNextFrame = pFrame;
return FrameCount;
}
ULONG
DlcServer(
IN PDLC_TEST_THREAD_PARMS pParms
)
/*++
Generic DLC server module, used against all
DLC client test programs.
--*/
{
UINT Status;
UINT OpenError;
UINT MaxFrameLength;
USHORT DlcStatus;
PLLC_BUFFER pNextFrame;
PLLC_BUFFER pFirstBuffer;
PDLC_TEST_PACKET pDlcPacket;
LLC_TEST_CCB_POOL TransmitCcbPool;
PLLC_TRANSMIT2_COMMAND pTransmitBuffer;
UCHAR SapStation;
USHORT LastSapStationId;
PLLC_READ_PARMS pReadParms;
PLLC_CCB pCcb;
PLLC_CCB pReadCcb;
PLLC_CCB pNextCcb;
UCHAR LinksAvail;
BOOLEAN EndTest;
PLLC_BUFFER SavedLinkBuffers[255];
PLLC_BUFFER pCurrentBuffer;
UCHAR MaxStations;
UINT iStation;
UINT SapOptions;
UCHAR StationsLeft;
UINT cGroupSaps;
UINT i;
static UCHAR GroupSaps[3] = { GROUP_SAP1, GROUP_SAP2, GROUP_SAP3 };
PVOID pPool;
LLC_DLC_MODIFY_PARMS DlcModifyParms;
USHORT GroupSapHost;
UINT cLeft;
UINT PendingCcbCount = 0;
UINT cTransmitted;
UINT FrameCount;
static PVOID hPool = NULL;
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
memset(SavedLinkBuffers, 0, sizeof(SavedLinkBuffers));
pTransmitBuffer = (PLLC_TRANSMIT2_COMMAND)
ALLOC(sizeof(LLC_TRANSMIT2_COMMAND)
+ sizeof(LLC_TRANSMIT_DESCRIPTOR) * MAX_XMIT_BUFFERS
);
//
// Initialize the Transmit ccb pool
//
CcbPoolInitialize(&TransmitCcbPool,
pParms->AdapterNumber,
LLC_TRANSMIT_FRAMES,
TEST_TRANSMIT_COMPLETION_FLAG
);
Status = LlcDirOpenAdapter(pParms->AdapterNumber,
NULL,
hPool,
&OpenError,
NULL,
&MaxFrameLength,
NULL
);
DBG_ASSERT(Status);
if (hPool == NULL) {
Status = BufferCreate(pParms->AdapterNumber,
pPool = ALLOC(SERVER_BUFFER_SIZE),
SERVER_BUFFER_SIZE,
min(0xfff0, SERVER_BUFFER_SIZE),
SERVER_BUFFER_SIZE / 2,
&pParms->hPool
);
DBG_ASSERT(Status);
}
Status = DirSetFunctionalAddress(pParms->AdapterNumber,
pParms->FunctionalAddress
);
DBG_ASSERT(Status);
Status = DirSetGroupAddress(pParms->AdapterNumber, pParms->GroupAddress);
if (Status != STATUS_SUCCESS) {
puts("Group address is not supported by NDIS driver!");
}
//
// Open the group saps (not really necessary in NT DLC)
//
for (i = 0; i < 3; i++) {
if (VerboseMode) {
printf("Server: opening group SAP %02x\n", GroupSaps[i]);
}
Status = LlcDlcOpenSap((UINT)pParms->AdapterNumber,
MaxFrameLength,
(UCHAR)(GroupSaps[i] & (UCHAR)0xfe),
LLC_GROUP_SAP | LLC_XID_HANDLING_IN_DLC,
0,
0,
NULL,
0,
NULL,
&LastSapStationId,
&LinksAvail
);
DBG_ASSERT(Status);
}
MaxStations = (UCHAR)((256 * pParms->ThreadCount) / pParms->SapCount);
GroupSapHost = (USHORT)(pParms->FirstServerSap + 2) << 8;
memset(&DlcModifyParms, 0, sizeof(DlcModifyParms));
DlcModifyParms.pGroupList = GroupSaps;
StationsLeft = 255;
for (SapStation = (UCHAR)(pParms->FirstServerSap + (pParms->AdapterNumber >> 4) * 2);
SapStation < (UCHAR)(pParms->FirstServerSap + pParms->SapCount * 2);
SapStation += (2 * pParms->ThreadCount)) {
//
// This first SAP is NOT MEMBER of groups saps and it handles
// the XID frames by itself (they are handled as any XID commands).
// ALL OTHER SAPS ARE MEMBERS OF GROUPS SAPS AND THEY LET LINK LAYER
// TO HANDLE XID FRAMES!
//
if (SapStation == pParms->FirstServerSap) {
cGroupSaps = 0;
SapOptions = LLC_INDIVIDUAL_SAP | LLC_XID_HANDLING_IN_APPLICATION;
} else {
cGroupSaps = sizeof(GroupSaps);
SapOptions = LLC_INDIVIDUAL_SAP | LLC_MEMBER_OF_GROUP_SAP | LLC_XID_HANDLING_IN_DLC;
}
//
// We have only 255 link stations! The last sap must take
// all stations ids, that are left.
//
if ((SapStation + (pParms->ThreadCount * 2)) >= (UCHAR)(pParms->FirstServerSap + pParms->SapCount * 2)) {
MaxStations = StationsLeft;
} else {
StationsLeft -= MaxStations;
}
if (VerboseMode) {
printf("Server: opening individual SAP %02x\n", SapStation);
}
Status = LlcDlcOpenSap(pParms->AdapterNumber,
MaxFrameLength,
SapStation,
SapOptions,
MaxStations,
cGroupSaps,
GroupSaps,
TEST_DLC_STATUS_FLAG,
NULL,
&LastSapStationId,
&LinksAvail
);
DBG_ASSERT(Status);
//
// Setup immediately a pending receive
//
pCcb = ReceiveInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
LastSapStationId,
0,
TEST_RECEIVE_FLAG,
LLC_NOT_CONTIGUOUS_DATA,
LLC_RCV_CHAIN_FRAMES_ON_LINK
// LLC_RCV_READ_INDIVIDUAL_FRAMES
);
Status = AcsLan(pCcb, NULL);
//
// We setup all group saps using DlcModify (actually we
// first reset the group saps and then set them again)
//
DlcModifyParms.cGroupCount = 0;
Status = DlcModify((UINT)pParms->AdapterNumber,
(USHORT)((USHORT)SapStation << 8),
&DlcModifyParms
);
DBG_ASSERT(Status);
DlcModifyParms.cGroupCount = sizeof(GroupSaps);
Status = DlcModify(pParms->AdapterNumber,
(USHORT)((USHORT)SapStation << 8),
&DlcModifyParms
);
DBG_ASSERT(Status);
} // for
//
// And finally we setup direct station to read frames
// from a specific dix station.
//
Status = LlcDirOpenDirect(pParms->AdapterNumber, 0, TEST_DIX_TYPE);
//
// Dix stations doesn't work on token-ring
//
if (Status == STATUS_SUCCESS) {
pCcb = ReceiveInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
0,
0,
TEST_RECEIVE_FLAG,
LLC_NOT_CONTIGUOUS_DATA,
LLC_RCV_CHAIN_FRAMES_ON_LINK
);
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
}
pReadCcb = ReadInit(pParms->AdapterNumber,
0,
LLC_OPTION_READ_ALL,
LLC_READ_ALL_EVENTS
);
pReadParms = &pReadCcb->u.pParameterTable->Read;
SetEvent(hServerReady);
EndTest = FALSE;
while (EndTest == FALSE) {
Status = AcsLan(pReadCcb, NULL);
if (pReadCcb->uchDlcStatus == LLC_STATUS_ADAPTER_CLOSED) {
break;
}
Status = WaitForSingleObject(pReadCcb->hCompletionEvent, INFINITE);
if (Status != STATUS_SUCCESS) {
break;
}
switch (pReadParms->uchEvent) {
case LLC_EVENT_TRANSMIT_COMPLETION:
if (pReadParms->ulNotificationFlag != TEST_TRANSMIT_COMPLETION_FLAG) {
DlcDebugBreak();
}
for (pCcb = pReadParms->Type.Event.pCcbCompletionList;
pCcb != NULL && pReadParms->Type.Event.usCcbCount != 0;
pCcb = pNextCcb) {
pNextCcb = pCcb->pNext;
if (pCcb->uchDlcStatus == LLC_STATUS_LINK_PROTOCOL_ERROR
|| pCcb->uchDlcStatus == LLC_STATUS_INVALID_STATION_ID) {
PRINTF("T: LLC_STATUS_LINK_PROTOCOL_ERROR\n");
} else {
DBG_ASSERT(pCcb->uchDlcStatus);
}
CcbPoolFree(&TransmitCcbPool, pCcb);
}
break;
case LLC_EVENT_COMMAND_COMPLETION:
if (pReadParms->ulNotificationFlag != TEST_COMMAND_COMPLETION_FLAG) {
DlcDebugBreak();
}
for (pCcb = pReadParms->Type.Event.pCcbCompletionList;
pCcb != NULL && pReadParms->Type.Event.usCcbCount != 0;
pCcb = pNextCcb) {
pNextCcb = pCcb->pNext;
//
// Restore the receive command, if we have run out
// of the buffers. The receive command should
// expand the buffer pool, if it is necessary.
//
if ((pCcb->uchDlcCommand == LLC_RECEIVE)
&& (pCcb->u.pParameterTable->Receive.ulReceiveFlag != 0)) {
printf("cSrvFramesTransmitted: %x\n",cSrvFramesTransmitted);
printf("cSrvFramesReceived: %x\n", cSrvFramesReceived);
printf("cSrvFramesReleased: %x\n", cSrvFramesReleased);
printf("cSrvFramesSecondaryXmits: %x\n", cSrvFramesSecondaryXmits);
if (pCcb->uchDlcStatus != LLC_STATUS_LOST_DATA_NO_BUFFERS) {
printf("Invalid Receive ret code: %xh\n", pCcb->uchDlcStatus);
}
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
} else {
if ((pCcb->uchDlcCommand == LLC_DLC_CLOSE_STATION)
&& (pReadParms->Type.Event.pFirstBuffer != NULL)) {
cSrvFramesReleased += FreeAllFrames(pParms->AdapterNumber,
pReadParms->Type.Event.pFirstBuffer,
&cLeft
);
}
if ((pCcb->uchDlcStatus == LLC_STATUS_LINK_PROTOCOL_ERROR)
|| (pCcb->uchDlcStatus == LLC_STATUS_INVALID_STATION_ID)) {
PRINTF("C: LLC_STATUS_LINK_PROTOCOL_ERROR\n");
} else {
DBG_ASSERT(pCcb->uchDlcStatus);
}
PendingCcbCount--;
FreeCcb(pCcb);
}
}
break;
case LLC_EVENT_STATUS_CHANGE:
if (pReadParms->ulNotificationFlag != TEST_DLC_STATUS_FLAG) {
DlcDebugBreak();
}
DlcStatus = pReadParms->Type.Status.usDlcStatusCode;
if (DlcStatus & LLC_INDICATE_LINK_LOST) {
pCcb = LlcCloseInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
LLC_DLC_CLOSE_STATION,
pReadParms->Type.Status.usStationId
);
Status = AcsLan(pCcb, NULL);
PendingCcbCount++;
DBG_ASSERT(pCcb->uchDlcStatus);
PRINTF("SERVER: LLC_INDICATE_LINK_LOST (%u pending extra CCBs)\n", PendingCcbCount);
}
if (DlcStatus & LLC_INDICATE_DM_DISC_RECEIVED) {
pCcb = LlcCloseInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
LLC_DLC_CLOSE_STATION,
pReadParms->Type.Status.usStationId
);
Status = AcsLan(pCcb, NULL);
PendingCcbCount++;
PRINTF("SERVER: LLC_INDICATE_DM_DISC_RECEIVED (%x)", pReadParms->Type.Status.usStationId);
PRINTF("; %u pending extra CCBs\n", PendingCcbCount);
}
if (DlcStatus & LLC_INDICATE_FRMR_RECEIVED) {
PRINTF("SERVER: LLC_INDICATE_FRMR_RECEIVED\n");
}
if (DlcStatus & LLC_INDICATE_FRMR_SENT) {
PRINTF("SERVER: LLC_INDICATE_FRMR_SENT\n");
}
if (DlcStatus & LLC_INDICATE_CONNECT_REQUEST) {
pCcb = DlcConnectStationInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
pReadParms->Type.Status.usStationId,
NULL
);
Status = AcsLan(pCcb, NULL);
PendingCcbCount++;
//
// The link may have been disconnected by the remote node.
//
if (pCcb->uchDlcStatus != LLC_STATUS_INVALID_STATION_ID) {
DBG_ASSERT(pCcb->uchDlcStatus);
}
PRINTF("SERVER: LLC_INDICATE_CONNECT_REQUEST (%u pending extra CCBs)\n", PendingCcbCount);
}
if (DlcStatus & LLC_INDICATE_RESET) {
//
// We must reconnect after a reset, Reset happens
// when the remote side has closed the adapter
// while a link was in a checkpointing state (when
// it cannot send DISC) and then immediately reconnects
// the same link station.
//
// DLC.CLOSE.STATION and DLC.RESET wait always the DLC
// protocol to complete the disconnect and eventually
// to send DISC, but DIR.CLOSE.ADAPTER and DIR.INITIALIZE
// shuts down immediately the network traffic (any the
// pending NDIS packets are waited)
//
pCcb = DlcConnectStationInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
pReadParms->Type.Status.usStationId,
NULL
);
Status = AcsLan(pCcb, NULL);
PendingCcbCount++;
PRINTF("SERVER: LLC_INDICATE_RESET (%u pending extra CCBs)\n", PendingCcbCount);
}
if (DlcStatus & LLC_INDICATE_REMOTE_BUSY) {
PRINTF("SERVER: LLC_INDICATE_REMOTE_BUSY\n");
}
if (DlcStatus & LLC_INDICATE_REMOTE_READY) {
PRINTF("SERVER: LLC_INDICATE_REMOTE_READY\n");
}
if (DlcStatus & LLC_INDICATE_TI_TIMER_EXPIRED) {
PRINTF("SERVER: LLC_INDICATE_TI_TIMER_EXPIRED\n");
}
if (DlcStatus & LLC_INDICATE_DLC_COUNTER_OVERFLOW) {
PRINTF("SERVER: LLC_INDICATE_DLC_COUNTER_OVERFLOW\n");
ReportDlcStatistics(pParms->AdapterNumber,
pReadParms->Type.Status.usStationId
);
}
if (DlcStatus & LLC_INDICATE_ACCESS_PRTY_LOWERED) {
PRINTF("SERVER: LLC_INDICATE_ACCESS_PRTY_LOWERED\n");
}
if (DlcStatus & LLC_INDICATE_LOCAL_STATION_BUSY) {
//
// Let's hope there is now enough buffers to
// receive the data. Clear the out of buffer busy state.
//
PRINTF("SERVER: LLC_INDICATE_LOCAL_STATION_BUSY\n");
DlcFlowControl(pParms->AdapterNumber,
pReadParms->Type.Status.usStationId,
LLC_RESET_LOCAL_BUSY_BUFFER
);
}
break;
case LLC_EVENT_RECEIVE_DATA:
if (pReadParms->ulNotificationFlag != TEST_RECEIVE_FLAG) {
DlcDebugBreak();
}
//
// We will echo back all connect requests sent to any SAP
// from DLC test stations.
//
for (pFirstBuffer = pReadParms->Type.Event.pReceivedFrame;
pFirstBuffer != NULL;
pFirstBuffer = pNextFrame) {
cSrvFramesReceived++;
pNextFrame = pFirstBuffer->Contiguous.pNextFrame;
pDlcPacket = (PDLC_TEST_PACKET)
((PUCHAR)pFirstBuffer
+ pFirstBuffer->Next.cbUserData
+ pFirstBuffer->Next.offUserData
);
if (((pFirstBuffer->NotContiguous.usStationId & 0xff) == 0)
&& (pDlcPacket->PacketId == DLC_TEST_ID)) {
//
// Only the first sap number responds to queries sent
// to group saps. And only the first virtual adapters
// responds to any connectionless frames!
//
if (((pParms->AdapterNumber & 0xf0) != 0)
|| ((pFirstBuffer->NotContiguous.cbDlcHeader == 3)
&& (pFirstBuffer->NotContiguous.auchDlcHeader[0] & 0x01)
&& pFirstBuffer->NotContiguous.usStationId != LastSapStationId)) {
//
// We just free the received buffers
//
Status = BufferFree(pParms->AdapterNumber,
pFirstBuffer,
&cLeft
);
cSrvFramesReleased++;
continue;
}
switch (pDlcPacket->Command) {
case TEST_COMMAND_ECHO_BACK:
pFirstBuffer->Contiguous.pNextFrame = NULL;
pTransmitBuffer->usStationId = pFirstBuffer->NotContiguous.usStationId;
pTransmitBuffer->usFrameType = ResponseTable[pFirstBuffer->NotContiguous.uchMsgType / 2];
if (pTransmitBuffer->usFrameType == 0) {
Status = BufferFree(pParms->AdapterNumber,
pFirstBuffer,
&cLeft
);
cSrvFramesReleased++;
break;
} else if (pTransmitBuffer->usFrameType == (USHORT)-1) {
//
// Send to the same ethernet type as used
// in the received dlc header.
// (note small endian byte order)
//
pTransmitBuffer->usFrameType =
(USHORT)((((USHORT)pFirstBuffer->NotContiguous.auchDlcHeader[0]) << 8)
+ pFirstBuffer->NotContiguous.auchDlcHeader[1]);
//
// Modify the lan header to a network address.
// We use ethernet header format for dix frames
//
memcpy(&pFirstBuffer->NotContiguous.auchLanHeader[0],
&pFirstBuffer->NotContiguous.auchLanHeader[6],
6
);
//
// Reset the possible broadcast bit,
//
pFirstBuffer->NotContiguous.auchLanHeader[0] &= (UCHAR)0x7f;
} else {
//
// Modify the lan header to a network address.
// We expect to have here always a token-ring
// header.
//
memcpy(&pFirstBuffer->NotContiguous.auchLanHeader[2],
&pFirstBuffer->NotContiguous.auchLanHeader[8],
6
);
//
// Reset the possible broadcast bit,
// Reverse the direction bit of the source routing
// info, if the source routing is enabled.
// Reset the broadcast indicators, we response
// always with the directed frames
//
pFirstBuffer->NotContiguous.auchLanHeader[2] &= 0x7f;
pFirstBuffer->NotContiguous.auchLanHeader[15] ^= 0x80;
pFirstBuffer->NotContiguous.auchLanHeader[14] &= 0x1f;
}
pTransmitBuffer->uchRemoteSap = pFirstBuffer->NotContiguous.auchDlcHeader[1] & (UCHAR)0xfe;
pTransmitBuffer->uchXmitReadOption = LLC_CHAIN_XMIT_COMMANDS_ON_SAP;
pTransmitBuffer->aXmitBuffer[0].eSegmentType = LLC_FIRST_DATA_SEGMENT;
pTransmitBuffer->aXmitBuffer[0].boolFreeBuffer = TRUE;
pTransmitBuffer->aXmitBuffer[0].cbBuffer = pFirstBuffer->NotContiguous.cbLanHeader;
pTransmitBuffer->aXmitBuffer[0].pBuffer = pFirstBuffer->NotContiguous.auchLanHeader;
Status = TransmitBuffers(pFirstBuffer,
pTransmitBuffer,
&TransmitCcbPool,
1,
1,
TRUE,
FALSE,
&cTransmitted
);
if (cTransmitted == 0) {
DebugBreak();
}
cSrvFramesTransmitted += cTransmitted;
//
// We must free the buffers (the transmitted
// data was released)
//
if ((Status != LLC_STATUS_PENDING) && (Status != LLC_STATUS_SUCCESS)) {
UINT cReleased;
cReleased = FreeAllFrames(pParms->AdapterNumber,
pFirstBuffer,
&cLeft
);
cSrvFramesReleased += cReleased;
cSrvFramesTransmitted -= cReleased;
}
break;
case TEST_COMMAND_EXIT:
EndTest = TRUE;
break;
case TEST_COMMAND_READ:
default:
//
// We just free the received buffers
//
FrameCount = FreeReceiveBuffers(pParms->AdapterNumber,
pFirstBuffer,
&pNextFrame,
&cLeft
);
cSrvFramesReleased += FrameCount;
cSrvFramesReceived += (FrameCount - 1);
break;
}
} else if ((pFirstBuffer->NotContiguous.usStationId & 0xff00) != 0) {
//
// We got an invalid data packet over link
//
if (pDlcPacket->PacketId != DLC_TEST_ID) {
printf("Invalid Data: READ CCB=%x\n", pReadCcb);
DlcDebugBreak();
}
switch (pDlcPacket->Command) {
case TEST_COMMAND_ECHO_BACK:
case TEST_COMMAND_DELAYED_ECHO:
pFirstBuffer->Contiguous.pNextFrame = NULL;
iStation = (pFirstBuffer->NotContiguous.usStationId & 0xff) - 1;
if (SavedLinkBuffers[iStation] != NULL) {
for (pCurrentBuffer = SavedLinkBuffers[iStation];
pCurrentBuffer->Contiguous.pNextFrame != NULL;
pCurrentBuffer = pCurrentBuffer->Contiguous.pNextFrame) {
//
// NOTHING (?)
//
}
pCurrentBuffer->Contiguous.pNextFrame = pFirstBuffer;
pFirstBuffer = SavedLinkBuffers[iStation];
} else {
SavedLinkBuffers[iStation] = pFirstBuffer;
}
if (pDlcPacket->Command == TEST_COMMAND_ECHO_BACK) {
//
// Small performance trick, send multiple
// frames with the same command, if sequential
// packets are from the same link station and
// they have the same type.
//
if ((pNextFrame != NULL)
&& (pNextFrame->NotContiguous.usStationId == pFirstBuffer->NotContiguous.usStationId)) {
pDlcPacket = (PDLC_TEST_PACKET)((PUCHAR)pNextFrame
+ pNextFrame->Next.cbUserData
+ pNextFrame->Next.offUserData
);
if (pDlcPacket->Command == TEST_COMMAND_ECHO_BACK) {
//
// Send the packet in the next time
//
cSrvFramesSecondaryXmits++;
continue;
}
}
pTransmitBuffer->usStationId = pFirstBuffer->NotContiguous.usStationId;
pTransmitBuffer->usFrameType = LLC_I_FRAME;
Status = TransmitBuffers(SavedLinkBuffers[iStation],
pTransmitBuffer,
&TransmitCcbPool,
1,
0,
TRUE,
TRUE,
&cTransmitted
);
if (cTransmitted == 0) {
DebugBreak();
}
cSrvFramesTransmitted += cTransmitted;
//
// We must free the buffers (the transmitted
// data was released)
//
if ((Status != LLC_STATUS_PENDING) && (Status != LLC_STATUS_SUCCESS)) {
UINT cReleased;
cReleased = FreeAllFrames(pParms->AdapterNumber,
SavedLinkBuffers[iStation],
&cLeft
);
cSrvFramesReleased += cReleased;
cSrvFramesTransmitted -= cReleased;
}
SavedLinkBuffers[iStation] = NULL;
}
break;
case TEST_COMMAND_READ:
default:
//
// We just free the received buffers
//
FrameCount = FreeReceiveBuffers(pParms->AdapterNumber,
pFirstBuffer,
&pNextFrame,
&cLeft
);
cSrvFramesReleased += FrameCount;
cSrvFramesReceived += (FrameCount - 1);
break;
}
} else {
Status = BufferFree(pParms->AdapterNumber,
pFirstBuffer,
&cLeft
);
cSrvFramesReleased++;
DBG_ASSERT(Status);
}
} // end_for
//if ((pReadParms->Type.Event.pReceivedFrame->NotContiguous.usStationId & 0xff00) != 0) {
// PRINTF("%u ", pReadParms->Type.Event.pReceivedFrame->NotContiguous.cBuffersLeft);
//}
break;
}
}
FREE(pTransmitBuffer);
FREE(pPool);
CcbPoolDelete(&TransmitCcbPool);
FreeCcb(pReadCcb);
ExitThread(STATUS_SUCCESS);
}
UINT
LinkFunctionalityTest(
IN PDLC_TEST_THREAD_PARMS pParms
)
/*++
This tests the basic functionality of link station:
- connection setup
- data send and receive
- local busy state and its opening
- out of local receive buffers
- the closing of data link connection
--*/
{
UINT Status;
UINT OpenError;
UINT MaxFrameLength;
USHORT SapStationId;
USHORT SapStationId2;
USHORT LinkStationId;
PVOID hPool;
PLLC_BUFFER pFirstBuffer;
PLLC_TRANSMIT2_COMMAND pTransmitBuffer;
DLC_TEST_PACKET TestPacket;
PLLC_CCB pCcb;
PLLC_CCB pReadCcb;
PLLC_CCB pLinkReadCcb;
LLC_TEST_CCB_POOL TransmitCcbPool;
UCHAR LinksAvail;
PLLC_READ_PARMS pReadParms;
PLLC_BUFFER pBuffer1;
PLLC_BUFFER pBuffer2;
UCHAR SendBuffer[sizeof(TestPacket) + FOOBAR_HEADER_LENGTH];
HANDLE hEvent;
PVOID pPool;
LLC_TRANSMIT2_VAR_PARMS(2) TransmitParms;
UCHAR NodeAddress[6];
UCHAR DestinationSap = 2;
PLLC_CCB aCcb[10];
UINT i;
UINT cLeft;
BOOLEAN GlobalSapIsWorking = TRUE; // doesn't work with ibmtok
PUCHAR pSourceRoutingInfo;
puts("****** Link Functionality Test ******");
hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
pTransmitBuffer = (PLLC_TRANSMIT2_COMMAND)
ALLOC(sizeof(LLC_TRANSMIT2_COMMAND)
+ sizeof(LLC_TRANSMIT_DESCRIPTOR) * MAX_XMIT_BUFFERS
);
//
// Initialize the Transmit ccb pool
//
CcbPoolInitialize(&TransmitCcbPool,
pParms->AdapterNumber,
LLC_TRANSMIT_FRAMES,
TEST_TRANSMIT_COMPLETION_FLAG
);
Status = LlcDirOpenAdapter(pParms->AdapterNumber + 16,
NULL,
NULL,
&OpenError,
NULL,
&MaxFrameLength,
NULL
);
if (Status && Status != LLC_STATUS_ADAPTER_OPEN) {
DBG_ASSERT(Status);
}
printf("MaxFrameLength: %u\n", MaxFrameLength);
Status = BufferCreate(pParms->AdapterNumber + 16,
pPool = ALLOC(SMALL_BUFFER_POOL_SIZE),
SMALL_BUFFER_POOL_SIZE,
min(0xfff0, SMALL_BUFFER_POOL_SIZE),
0x2000,
&hPool
);
if (Status && Status != LLC_STATUS_DUPLICATE_COMMAND) {
DBG_ASSERT(Status);
}
Status = LlcDirOpenAdapter(pParms->AdapterNumber,
NULL,
hPool,
&OpenError,
NULL,
&MaxFrameLength,
NULL
);
if (Status && Status != LLC_STATUS_ADAPTER_OPEN) {
DBG_ASSERT(Status);
}
//
// Now we may close the actual owner of the buffer pool!
//
pCcb = LlcCloseInit((UCHAR)(pParms->AdapterNumber + 16),
0,
LLC_DIR_CLOSE_ADAPTER,
0
);
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
Status = LlcDlcOpenSap(pParms->AdapterNumber,
MaxFrameLength,
pParms->FirstClientSap,
LLC_INDIVIDUAL_SAP | LLC_XID_HANDLING_IN_DLC,
pParms->AllocatedStations,
0,
NULL,
TEST_DLC_STATUS_FLAG,
NULL,
&SapStationId,
&LinksAvail
);
DBG_ASSERT(Status);
Status = LlcDlcOpenSap(pParms->AdapterNumber,
MaxFrameLength,
(UCHAR)(pParms->FirstClientSap + (UCHAR)2),
LLC_INDIVIDUAL_SAP | LLC_XID_HANDLING_IN_APPLICATION,
pParms->AllocatedStations,
0,
NULL,
TEST_DLC_STATUS_FLAG,
NULL,
&SapStationId2,
&LinksAvail
);
DBG_ASSERT(Status);
ReportDirStatus(pParms->AdapterNumber);
//
// Test DlcReallocate
//
ReportDlcReallocate(pParms->AdapterNumber,
SapStationId2,
LLC_INCREASE_LINK_STATIONS,
0,
FALSE
);
ReportDlcReallocate(pParms->AdapterNumber,
SapStationId2,
LLC_DECREASE_LINK_STATIONS,
(UCHAR)(pParms->AllocatedStations - 1),
FALSE
);
ReportDlcReallocate(pParms->AdapterNumber,
SapStationId2,
LLC_DECREASE_LINK_STATIONS,
(UCHAR)2,
FALSE
);
ReportDlcReallocate(pParms->AdapterNumber,
SapStationId2,
LLC_INCREASE_LINK_STATIONS,
(UCHAR)pParms->AllocatedStations,
FALSE
);
//
// Setup immediately a pending receive
//
pCcb = ReceiveInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
SapStationId,
0,
TEST_RECEIVE_FLAG,
LLC_NOT_CONTIGUOUS_DATA,
LLC_RCV_READ_INDIVIDUAL_FRAMES
);
Status = AcsLan(pCcb, NULL);
//
// Setup immediately a pending receive
//
pCcb = ReceiveInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
SapStationId2,
0,
TEST_RECEIVE_FLAG,
LLC_NOT_CONTIGUOUS_DATA,
LLC_RCV_READ_INDIVIDUAL_FRAMES
);
Status = AcsLan(pCcb, NULL);
//
// **** TEST FUNCTIONAL AND BROADCAST ADDRESSES ****
//
TestPacket.PacketId = DLC_TEST_ID;
TestPacket.Command = TEST_COMMAND_READ;
TestPacket.RepeatCount = 1;
memcpy(&SendBuffer[FOOBAR_HEADER_LENGTH], &TestPacket, sizeof(TestPacket));
//
// read the broadcast responses to figure out the real destination address
//
pReadCcb = ReadInit(pParms->AdapterNumber,
0,
LLC_OPTION_READ_ALL,
LLC_READ_ALL_EVENTS // THIS DOESN't MEAN ANYTHING ANY MORE
);
pReadParms = &pReadCcb->u.pParameterTable->Read;
#ifdef OS2_EMU_DLC
for (i = 0; i < 4; i++) {
#else
for (i = 0; i < 5; i++) {
#endif
aCcb[i] = TransmitInit(pParms->AdapterNumber,
LLC_TRANSMIT_UI_FRAME,
TEST_TRANSMIT_COMPLETION_FLAG,
SapStationId,
(UCHAR)(SapStationId >> 8),
LLC_CHAIN_XMIT_COMMANDS_ON_SAP
);
aCcb[i]->u.pParameterTable->Transmit.pBuffer1 = TestBroadcastHeader;
aCcb[i]->u.pParameterTable->Transmit.cbBuffer1 = sizeof(TestBroadcastHeader);
aCcb[i]->u.pParameterTable->Transmit.pBuffer2 = SendBuffer;
aCcb[i]->u.pParameterTable->Transmit.cbBuffer2 = sizeof(SendBuffer);
//aCcb[i]->u.pParameterTable->Transmit.cbBuffer2 = SIZEOF_TEST_PACKET;
aCcb[i]->hCompletionEvent = hEvent;
switch (i) {
case 0:
//
// NDIS emulator needs the first frame to synchronize again
// with the client (I don't really know what happens,
// but the first frame is lost, when the ndis emulator
// is reconnected),
//
memcpy(&TestBroadcastHeader[4], FunctionalAddress1, 4);
break;
case 1:
TestPacket.Command = TEST_COMMAND_ECHO_BACK;
memcpy(&SendBuffer[FOOBAR_HEADER_LENGTH], &TestPacket, sizeof(TestPacket));
memcpy(&TestBroadcastHeader[4], FunctionalAddress1, 4);
break;
case 2:
memcpy(&TestBroadcastHeader[4], FunctionalAddress2, 4);
break;
case 3:
memcpy(&TestBroadcastHeader[4], FunctionalAddress3, 4);
break;
case 4:
memcpy(&TestBroadcastHeader[4], pParms->GroupAddress, 4);
break;
}
Status = AcsLan(aCcb[i], NULL);
DBG_ASSERT(aCcb[i]->uchDlcStatus);
Status = WaitForSingleObject(aCcb[i]->hCompletionEvent, 10000);
DBG_ASSERT(Status);
DBG_ASSERT(aCcb[i]->uchDlcStatus);
aCcb[i]->hCompletionEvent = NULL;
}
Status = ReadClientEvent(pReadCcb,
NULL,
LLC_EVENT_RECEIVE_DATA,
2,
5000L,
NULL
);
DBG_ASSERT(Status);
pFirstBuffer = pReadCcb->u.pParameterTable->Read.Type.Event.pReceivedFrame;
memcpy(NodeAddress, &pFirstBuffer->NotContiguous.auchLanHeader[8], 6);
memcpy(LanHeader, pFirstBuffer->NotContiguous.auchLanHeader, 32);
memcpy(&LanHeader[2], &pFirstBuffer->NotContiguous.auchLanHeader[8], 6);
pSourceRoutingInfo = ((LanHeader[8] & 0x80) ? &LanHeader[14] : NULL);
NodeAddress[0] &= (UCHAR)0x7f;
LanHeader[2] &= (UCHAR)0x7f;
//
// Toggle the direction bit and reset the source routing info bit
// in the destination address (leave the source address as it, because
// it will be updated by DLC)
//
LanHeader[15] ^= (UCHAR)0x80;
DestinationSap = (UCHAR)(pFirstBuffer->NotContiguous.auchDlcHeader[1] & 0xfe);
Status = ReadClientEvent(pReadCcb,
NULL,
LLC_EVENT_RECEIVE_DATA,
1,
1000L,
NULL
);
if (Status != STATUS_SUCCESS) {
puts("ERROR! GROUP ADDRESS DOESN'T WORK!!!!");
}
Status = ReadClientEvent(pReadCcb,
NULL,
LLC_EVENT_RECEIVE_DATA,
1,
100L,
NULL
);
// if (Status == STATUS_SUCCESS)
// DBG_ASSERT(-1);
Status = ReadClientEvent(pReadCcb,
&TransmitCcbPool,
LLC_EVENT_TRANSMIT_COMPLETION,
// 5,
3,
1000L,
NULL
);
DBG_ASSERT(Status);
//
// **** TESTING: ****
// - GROUP SAPs
// - Global SAP
// - null sap
// - Xid commands (xid handling in data link & in application)
// - test command
//
pCcb = TransmitInit(pParms->AdapterNumber,
LLC_TRANSMIT_UI_FRAME,
TEST_TRANSMIT_COMPLETION_FLAG,
SapStationId,
(UCHAR)(SapStationId >> 8),
LLC_CHAIN_XMIT_COMMANDS_ON_SAP
);
pCcb->u.pParameterTable->Transmit.pBuffer1 = LanHeader;
// pCcb->u.pParameterTable->Transmit.pBuffer1 = TestLanHeader;
pCcb->u.pParameterTable->Transmit.cbBuffer1 = sizeof(LanHeader);
pCcb->u.pParameterTable->Transmit.pBuffer2 = SendBuffer;
pCcb->u.pParameterTable->Transmit.cbBuffer2 = sizeof(SendBuffer);
//pCcb->u.pParameterTable->Transmit.cbBuffer2 = SIZEOF_TEST_PACKET;
pCcb->hCompletionEvent = hEvent;
pCcb->ulCompletionFlag = 0;
pCcb->u.pParameterTable->Transmit.uchRemoteSap = 0xff;
Status = DlcTestTransact(pCcb, pReadCcb, LLC_UI_FRAME);
if (Status != STATUS_SUCCESS) {
GlobalSapIsWorking = FALSE;
puts("ERROR!!!!, IBMTOK ADAPTER ATE A PACKET SENT TO THE GLOBAL SAP!!!!");
}
pCcb->u.pParameterTable->Transmit.uchRemoteSap = GROUP_SAP1;
Status = DlcTestTransact(pCcb, pReadCcb, LLC_UI_FRAME);
if (Status != STATUS_SUCCESS) {
puts("HELP!!!!, IBMTOK ADAPTER ATE A PACKET SENT TO A GROUP SAP!!!!");
} else {
pCcb->u.pParameterTable->Transmit.uchRemoteSap = GROUP_SAP3;
Status = DlcTestTransact(pCcb, pReadCcb, LLC_UI_FRAME);
DBG_ASSERT(Status);
}
//
// Test TEST and XID commands agains the null sap
// !!!! XID HANDLING IN DLC !!!!
//
pCcb->u.pParameterTable->Transmit.cbBuffer2 = 3;
pCcb->u.pParameterTable->Transmit.uchRemoteSap = 0;
pCcb->uchDlcCommand = LLC_TRANSMIT_TEST_CMD;
Status = DlcTestTransact(pCcb, pReadCcb, LLC_TEST_RESPONSE_FINAL);
if (Status != STATUS_SUCCESS) {
puts("HELP!!!!, IBMTOK ADAPTER ATE A PACKET SENT TO A GROUP SAP!!!!");
}
pCcb->uchDlcCommand = LLC_TRANSMIT_XID_CMD;
Status = DlcTestTransact(pCcb, pReadCcb, LLC_XID_RESPONSE_FINAL);
DBG_ASSERT(Status);
//
// Test TEST the test frame with a big buffer, send any stuff
// from the stack (exclude the max lan header (32))
//
pCcb->u.pParameterTable->Transmit.pBuffer2 = ALLOC(MaxFrameLength);
if (pCcb->u.pParameterTable->Transmit.pBuffer2 == NULL) {
DBG_ASSERT(-1);
}
pCcb->u.pParameterTable->Transmit.cbBuffer2 = (USHORT)(3 + MaxFrameLength - 32);
pCcb->u.pParameterTable->Transmit.uchRemoteSap = 0;
pCcb->uchDlcCommand = LLC_TRANSMIT_TEST_CMD;
Status = DlcTestTransact(pCcb, pReadCcb, LLC_TEST_RESPONSE_FINAL);
DBG_ASSERT(Status);
FREE(pCcb->u.pParameterTable->Transmit.pBuffer2);
pCcb->u.pParameterTable->Transmit.cbBuffer2 = 3; // sizeof dlc header
pCcb->u.pParameterTable->Transmit.pBuffer2 = SendBuffer;
pCcb->u.pParameterTable->Transmit.uchRemoteSap = GROUP_SAP3;
pCcb->uchDlcCommand = LLC_TRANSMIT_TEST_CMD;
Status = DlcTestTransact(pCcb, pReadCcb, LLC_TEST_RESPONSE_FINAL);
if (Status != STATUS_SUCCESS) {
puts("HELP!!!!, IBMTOK ADAPTER ATE A LLC TEST FRAME SENT TO A GROUP SAP!!!!");
} else {
pCcb->uchDlcCommand = LLC_TRANSMIT_XID_CMD;
Status = DlcTestTransact(pCcb, pReadCcb, LLC_XID_RESPONSE_FINAL);
DBG_ASSERT(Status);
}
//
// !!!! XID HANDLING IN DLC !!!!
//
if (GlobalSapIsWorking) {
pCcb->u.pParameterTable->Transmit.uchRemoteSap = 0xff;
pCcb->uchDlcCommand = LLC_TRANSMIT_TEST_CMD;
Status = DlcTestTransact(pCcb, pReadCcb, LLC_TEST_RESPONSE_FINAL);
DBG_ASSERT(Status);
pCcb->uchDlcCommand = LLC_TRANSMIT_XID_CMD;
Status = DlcTestTransact(pCcb, pReadCcb, LLC_XID_RESPONSE_FINAL);
DBG_ASSERT(Status);
}
/*
pCcb->uchDlcCommand = LLC_TRANSMIT_XID_CMD;
Status = DlcTestTransact(pCcb, pReadCcb, LLC_XID_RESPONSE_FINAL);
DBG_ASSERT(Status);
*/
//
// The first remote sap station should handle the XID stations by itself,
// The first server sap in the other side does the same thing =>
// we can use XID's to exchange data.
//
pCcb->u.pParameterTable->Transmit.uchRemoteSap = DestinationSap;
pCcb->uchDlcCommand = LLC_TRANSMIT_TEST_CMD;
Status = DlcTestTransact(pCcb, pReadCcb, LLC_TEST_RESPONSE_FINAL);
if (Status != STATUS_SUCCESS) {
puts("HELP!!!!, IBMTOK ADAPTER ATE A LLC TEST FRAME!!!!");
}
//
// This will fail, because remote sap will not answer to 802.2 xids
//
// pCcb->uchDlcCommand = LLC_TRANSMIT_XID_CMD;
// Status = DlcTestTransact(pCcb, pReadCcb, LLC_XID_RESPONSE_FINAL);
// if (Status == STATUS_SUCCESS)
// DBG_ASSERT(-1);
//
// Send now the packet header (=> server echoes it back)
// *** XID CHANGE BEWTEEN APPLICATIONS ***
//
pCcb->u.pParameterTable->Transmit.usStationId = SapStationId2;
pCcb->u.pParameterTable->Transmit.cbBuffer2 = sizeof(SendBuffer);
//pCcb->u.pParameterTable->Transmit.cbBuffer2 = SIZEOF_TEST_PACKET;
pCcb->uchDlcCommand = LLC_TRANSMIT_XID_CMD;
Status = DlcTestTransact(pCcb, pReadCcb, LLC_XID_RESPONSE_FINAL);
DBG_ASSERT(Status);
//
// Read all extra connectionless frames (XID/TEST duplicates or
// broadcasts from the net.
//
//
// Here we test the send and receive on a dix station
//
Status = LlcDirOpenDirect(pParms->AdapterNumber, 0, TEST_DIX_TYPE);
//
// Dix stations doesn't work on token-ring
//
if (Status == STATUS_SUCCESS) {
pCcb = ReceiveInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
0,
0,
TEST_RECEIVE_FLAG,
LLC_NOT_CONTIGUOUS_DATA,
LLC_RCV_READ_INDIVIDUAL_FRAMES
);
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(Status);
//
// DIX interface always uses Ethernet LAN headers and Ethernet
// format.
//
TranslateLanHeader(LLC_SEND_802_5_TO_802_3, LanHeader, DixLanHeader);
memset(&TransmitParms, 0, sizeof(TransmitParms));
TransmitParms.usStationId = 0;
TransmitParms.usFrameType = TEST_DIX_TYPE;
TransmitParms.uchRemoteSap = 0; // ignored
TransmitParms.uchXmitReadOption = LLC_CHAIN_XMIT_COMMANDS_ON_SAP;
TransmitParms.cXmitBufferCount = 2;
TransmitParms.XmitBuffer[0].pBuffer = DixLanHeader;
TransmitParms.XmitBuffer[0].cbBuffer = sizeof(DixLanHeader);
TransmitParms.XmitBuffer[0].eSegmentType = LLC_FIRST_DATA_SEGMENT;
TransmitParms.XmitBuffer[1].pBuffer = &TestPacket;
TransmitParms.XmitBuffer[1].cbBuffer = sizeof(TestPacket);
TransmitParms.XmitBuffer[1].eSegmentType = LLC_NEXT_DATA_SEGMENT;
pCcb = AllocCcb(pParms->AdapterNumber, LLC_TRANSMIT_FRAMES, 0);
pCcb->u.pParameterTable = (PVOID)&TransmitParms;
Status = DlcTestTransact(pCcb, pReadCcb, LLC_DIRECT_ETHERNET_TYPE);
DBG_ASSERT(Status);
FreeCcb(pCcb);
}
//
// Open a link station,
// we have the destination station node address and sap number
// in the received frame.
//
Status = DlcOpenStation(pParms->AdapterNumber,
SapStationId,
DestinationSap,
NodeAddress,
NULL,
&LinkStationId
);
DBG_ASSERT(Status);
pCcb = DlcConnectStationInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
LinkStationId,
pSourceRoutingInfo
);
//
// Connect to the remote node
// BUG-BUG-BUG-BUG-BUG-: THIS DOESN'T WORK WITH SOURCE ROUTING INFO!!!
//
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
Status = ReadClientEvent(pReadCcb,
&TransmitCcbPool,
LLC_EVENT_COMMAND_COMPLETION,
1,
20000L,
NULL
);
DBG_ASSERT(Status);
//
// Setup receive
//
pCcb = ReceiveInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
LinkStationId,
0,
TEST_RECEIVE_FLAG,
LLC_NOT_CONTIGUOUS_DATA,
LLC_RCV_CHAIN_FRAMES_ON_LINK
);
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(Status);
//
// We read the events only on this link station
//
pLinkReadCcb = ReadInit(pParms->AdapterNumber,
LinkStationId,
LLC_OPTION_READ_STATION,
0
);
Status = BufferGet(pParms->AdapterNumber, 1, 0x100, &pBuffer1, &cLeft);
DBG_ASSERT(Status);
Status = BufferGet(pParms->AdapterNumber, 15, 0x100, &pBuffer2, &cLeft);
DBG_ASSERT(Status);
SetBuffers(pBuffer1, TEST_COMMAND_ECHO_BACK, 1, '0', '9');
//
// Send data and receive it back
//
pTransmitBuffer->usStationId = LinkStationId;
pTransmitBuffer->usFrameType = LLC_I_FRAME;
pTransmitBuffer->uchXmitReadOption = LLC_CHAIN_XMIT_COMMANDS_ON_LINK;
TransmitBuffers(pBuffer1, // DLC buffer list
pTransmitBuffer, //
&TransmitCcbPool, // pool for transmit CCBs
1, // repeat count
0, // current index in buffer table
FALSE,
FALSE,
NULL
);
Status = ReadClientEvent(pLinkReadCcb,
&TransmitCcbPool,
LLC_EVENT_TRANSMIT_COMPLETION + LLC_EVENT_RECEIVE_DATA,
2,
5000L,
NULL
);
DBG_ASSERT(Status);
//
// Set local station busy
//
DlcFlowControl(pParms->AdapterNumber, LinkStationId, LLC_SET_LOCAL_BUSY_USER);
//
// Send a lot of data with an echo request
//
TransmitBuffers(pBuffer1, // DLC buffer list
pTransmitBuffer, //
&TransmitCcbPool, // pool for transmit CCBs
50, // repeat count
0, // current index in buffer table
FALSE,
FALSE,
NULL
);
Status = ReadClientEvent(pLinkReadCcb,
&TransmitCcbPool,
LLC_EVENT_RECEIVE_DATA,
1,
500L,
NULL
);
if (Status == STATUS_SUCCESS) {
DBG_ASSERT(-1);
}
//
// reset local busy
//
DlcFlowControl(pParms->AdapterNumber, LinkStationId, LLC_RESET_LOCAL_BUSY_USER);
//
// Sleep a second to wait receive buffers to overflow
//
Sleep(1000L);
//
// Check the out of buffers problem
//
Status = ReadClientEvent(pLinkReadCcb,
&TransmitCcbPool,
LLC_EVENT_STATUS_CHANGE,
1,
5000L,
NULL
);
DBG_ASSERT(Status);
Status = BufferFree(pParms->AdapterNumber, pBuffer2, &cLeft);
DBG_ASSERT(Status);
//
// reset local out of buffer busy and receive the data
//
DlcFlowControl(pParms->AdapterNumber, LinkStationId, LLC_RESET_LOCAL_BUSY_BUFFER);
Status = ReadClientEvent(pLinkReadCcb,
&TransmitCcbPool,
LLC_EVENT_RECEIVE_DATA,
50,
5000L,
NULL
);
DBG_ASSERT(Status);
ReportDlcStatistics(pParms->AdapterNumber, SapStationId);
ReportDlcStatistics(pParms->AdapterNumber, LinkStationId);
//
// Send a lot of data and close the station when all
// this data is pending.
//
SetBuffers(pBuffer1, TEST_COMMAND_READ, 1, '0', '9');
TransmitBuffers(pBuffer1, // DLC buffer list
pTransmitBuffer,
&TransmitCcbPool, // pool for transmit CCBs
20, // repeat count
0, // current index in buffer table
FALSE,
FALSE,
NULL
);
//
// Close station
//
pCcb = LlcCloseInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
LLC_DLC_CLOSE_STATION,
LinkStationId
);
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
//
// Read the close command and the receive command linked to it
//
Status = ReadClientEvent(pReadCcb,
&TransmitCcbPool,
LLC_EVENT_COMMAND_COMPLETION,
1,
10000L,
NULL
);
DBG_ASSERT(Status);
//
// TEST LINK TIMEOUT (By sending a too large frame => disconnects
// the link station, when we cannot send the frame (its discarded
// every time as too big).
//
Status = DlcOpenStation(pParms->AdapterNumber,
SapStationId,
DestinationSap,
NodeAddress,
NULL,
&LinkStationId
);
DBG_ASSERT(Status);
pCcb = DlcConnectStationInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
LinkStationId,
pSourceRoutingInfo
);
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(Status);
DBG_ASSERT(pCcb->uchDlcStatus);
Status = ReadClientEvent(pReadCcb,
&TransmitCcbPool,
LLC_EVENT_COMMAND_COMPLETION,
1,
5000L,
NULL
);
DBG_ASSERT(Status);
//
// Set parameters, that makes the linkstation die quickly
//
Status = DlcModify((UINT)pParms->AdapterNumber,
LinkStationId,
&DlcModifyQuickDeathParms
);
DBG_ASSERT(Status);
pCcb = TransmitInit(pParms->AdapterNumber,
LLC_TRANSMIT_I_FRAME,
0,
LinkStationId,
0,
LLC_CHAIN_XMIT_COMMANDS_ON_LINK
);
pCcb->u.pParameterTable->Transmit.pBuffer1 = ALLOC(20000);
pCcb->u.pParameterTable->Transmit.cbBuffer1 = 20000;
pCcb->hCompletionEvent = hEvent;
Status = AcsLan(pCcb, NULL);
if (pCcb->uchDlcStatus == LLC_STATUS_PENDING) {
Status = WaitForSingleObject(hEvent, 10000);
}
if (pCcb->uchDlcStatus == STATUS_SUCCESS) {
puts("ERROR: the sending of too large frame succeeded!");
DBG_ASSERT(-1);
}
FREE(pCcb->u.pParameterTable->Transmit.pBuffer1);
FreeCcb(pCcb);
/*
*******************************************************************************
* Change in the code: the link always discards too long frames
* before they are queued => too long frames cannot disconnect
* the link any more.
*
* //
* // There must be an indication of the lost link station
* //
* Status =
* ReadClientEvent(
* pReadCcb,
* &TransmitCcbPool,
* LLC_EVENT_STATUS_CHANGE,
* 1,
* 5000L,
* NULL
* );
* //
* // The lost link station event returns an error code!
* //
* if (Status != -1)
* {
* DBG_ASSERT(-1);
* }
*
* // close sap
* pCcb =
* LlcCloseInit(
* pParms->AdapterNumber,
* TEST_COMMAND_COMPLETION_FLAG,
* LLC_DLC_CLOSE_SAP,
* SapStationId
* );
* Status = AcsLan(pCcb, NULL);
* DBG_ASSERT(pCcb->uchDlcStatus);
*******************************************************************************
*/
pCcb = LlcCloseInit(pParms->AdapterNumber, 0, LLC_DIR_CLOSE_ADAPTER, 0);
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
//
// Free all uncompleted commands on this adapter
//
while (pCcb != NULL) {
PLLC_CCB pNextCcb;
pNextCcb = pCcb->pNext;
FreeCcb(pCcb);
pCcb = pNextCcb;
}
FREE(pTransmitBuffer);
CcbPoolDelete(&TransmitCcbPool);
FreeCcb(pReadCcb);
FreeCcb(pLinkReadCcb);
FREE(pParms);
FREE(pPool);
#ifdef OS2_EMU_DLC
LlcTraceDumpAndReset(-1, 1, NULL);
#endif
return STATUS_SUCCESS;
}
UINT
LinkConnectStressTest(
IN PDLC_TEST_THREAD_PARMS pParms
)
/*++
This procedure stress tests the connection,
small data transfer, and disconnection of very
many link stations.
--*/
{
UINT Status;
UINT OpenError;
UINT MaxFrameLength;
PVOID hPool;
LLC_TEST_CCB_POOL TransmitCcbPool;
PLLC_TRANSMIT2_COMMAND pTransmitBuffer;
USHORT aLinkStationIds[255];
USHORT aSapStationIds[128];
UINT iSap;
UINT MaxSapStations;
UINT iLink;
UINT MaxLinks;
UINT i;
DLC_TEST_PACKET TestPacket;
PLLC_CCB pCcb;
PLLC_CCB pReadCcb;
PLLC_CCB pConnectCcb;
PLLC_CCB pReceiveCcb;
UCHAR LinksAvail;
UINT LoopCounter;
UINT TotalBuffers;
UCHAR MaxStations;
UCHAR SapStation;
UCHAR RemoteSap;
PLLC_BUFFER pFirstBuffer;
PLLC_BUFFER pBuffer1;
PLLC_BUFFER pBuffer;
PLLC_BUFFER* ppBuffer;
UINT OpenLinks;
UINT AllocatedLinks;
UCHAR SendBuffer[sizeof(TestPacket) + FOOBAR_HEADER_LENGTH];
UCHAR FirstAvailRemoteSap;
UCHAR LanHeader[32];
UINT LanHeaderLength;
UINT cLeft;
BOOLEAN FirstTime;
PUCHAR pSourceRoutingInfo;
puts("****** LinkConnectStressTest ******");
pTransmitBuffer = (PLLC_TRANSMIT2_COMMAND)
ALLOC(sizeof(LLC_TRANSMIT2_COMMAND)
+ sizeof(LLC_TRANSMIT_DESCRIPTOR) * MAX_XMIT_BUFFERS
);
//
// Initialize the Transmit ccb pool
//
CcbPoolInitialize(&TransmitCcbPool,
pParms->AdapterNumber,
LLC_TRANSMIT_FRAMES,
TEST_TRANSMIT_COMPLETION_FLAG
);
Status = LlcDirOpenAdapter(pParms->AdapterNumber,
NULL,
NULL,
&OpenError,
NULL,
&MaxFrameLength,
NULL
);
DBG_ASSERT(Status);
Status = BufferCreate(pParms->AdapterNumber,
pParms->pPool,
DEFAULT_BUFFER_SIZE,
min(0xfff0, DEFAULT_BUFFER_SIZE),
0x1000,
&hPool
);
DBG_ASSERT(Status);
Status = LlcDlcOpenSap(pParms->AdapterNumber,
MaxFrameLength,
pParms->FirstServerSap,
LLC_INDIVIDUAL_SAP,
0, // the stations are allocated by DlcRealloc
0,
NULL,
TEST_DLC_STATUS_FLAG,
NULL,
&aSapStationIds[0],
&LinksAvail
);
DBG_ASSERT(Status);
//
// We will use that strange mode of receive command to
// receive one frame without read command.
//
pReceiveCcb = ReceiveInit(pParms->AdapterNumber,
0,
aSapStationIds[0],
0,
0,
LLC_NOT_CONTIGUOUS_DATA,
0
);
Status = AcsLan(pReceiveCcb, NULL);
//
// search first a the network address of the DLC server and
// its all available sap stations
// (query command: returns number of saps, etc.)
//
//
// Send a broadcast to figure out the destination
//
pCcb = TransmitInit(pParms->AdapterNumber,
LLC_TRANSMIT_UI_FRAME,
TEST_TRANSMIT_COMPLETION_FLAG,
aSapStationIds[0],
(UCHAR)(aSapStationIds[0] >> 8),
LLC_CHAIN_XMIT_COMMANDS_ON_SAP
);
memcpy(&BroadcastHeader[4], FunctionalAddress1, 4);
pCcb->u.pParameterTable->Transmit.pBuffer1 = BroadcastHeader;
pCcb->u.pParameterTable->Transmit.cbBuffer1 = sizeof(BroadcastHeader);
pCcb->u.pParameterTable->Transmit.pBuffer2 = SendBuffer;
pCcb->u.pParameterTable->Transmit.cbBuffer2 = sizeof(SendBuffer);
TestPacket.PacketId = DLC_TEST_ID;
TestPacket.Command = TEST_COMMAND_ECHO_BACK;
TestPacket.RepeatCount = 1;
memcpy(&SendBuffer[FOOBAR_HEADER_LENGTH], &TestPacket, sizeof(TestPacket));
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
Status = WaitForSingleObject(pReceiveCcb->hCompletionEvent, 5000L);
DBG_ASSERT(Status);
DBG_ASSERT(pReceiveCcb->uchDlcStatus);
//
// BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG
// pFirstBuffer has already been returned to driver,
// the driver can reuse it in any moment and overwrite
// the data!!!!
// BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG
//
pFirstBuffer = pReceiveCcb->u.pParameterTable->Receive.pFirstBuffer;
LanHeaderLength = pFirstBuffer->NotContiguous.cbLanHeader;
memcpy(LanHeader,
pFirstBuffer->NotContiguous.auchLanHeader,
pFirstBuffer->NotContiguous.cbLanHeader
);
memcpy(&LanHeader[2], &LanHeader[8], 6);
//
// Toggle the direction bit and reset the source routing info bit
// in the destination address (leave the source address as it, because
// it will be updated by DLC)
//
LanHeader[2] &= (UCHAR)0x7f;
LanHeader[15] ^= (UCHAR)0x80;
pSourceRoutingInfo = ((LanHeader[8] & 0x80) ? &LanHeader[14] : NULL);
FreeCcb(pReceiveCcb);
/*
*******************************************************************************
*We transfer data only over links, don't need receive for a sap station.
*
* //
* // Setup immediately a pending receive, link stations
* // data will be read from link stations and sap station
* // data from sap stations by default
* //
* pCcb =
* ReceiveInit(
* pParms->AdapterNumber,
* TEST_COMMAND_COMPLETION_FLAG,
* aSapStationIds[0],
* 0,
* TEST_RECEIVE_FLAG,
* LLC_NOT_CONTIGUOUS_DATA,
* LLC_RCV_CHAIN_FRAMES_ON_SAP
* );
* Status = AcsLan(pCcb, NULL);
*
*******************************************************************************
*/
pReadCcb = ReadInit(pParms->AdapterNumber,
0,
LLC_OPTION_READ_ALL,
LLC_READ_ALL_EVENTS
);
Status = ReadClientEvent(pReadCcb,
&TransmitCcbPool,
LLC_EVENT_TRANSMIT_COMPLETION,
1,
5000L,
NULL
);
DBG_ASSERT(Status);
/*
*******************************************************************************
* Status =
* ReadClientEvent(
* pReadCcb,
* &TransmitCcbPool,
* LLC_EVENT_RECEIVE_DATA,
* 1,
* 5000L
* );
* DBG_ASSERT(Status);
*******************************************************************************
*/
iSap = 1;
MaxStations = (UCHAR)(256 / pParms->SapCount);
for (SapStation = (UCHAR)(pParms->FirstServerSap + 2);
SapStation < (UCHAR)(pParms->FirstClientSap + pParms->SapCount * 2);
SapStation += 2) {
Status = LlcDlcOpenSap(pParms->AdapterNumber,
MaxFrameLength,
SapStation,
LLC_INDIVIDUAL_SAP,
0, // MaxStations,
0,
NULL,
TEST_DLC_STATUS_FLAG,
NULL,
&aSapStationIds[iSap],
&LinksAvail
);
DBG_ASSERT(Status);
iSap++;
}
MaxSapStations = iSap;
//
// prepare a transmit buffer
//
Status = BufferGet(pParms->AdapterNumber, 1, 0x100, &pBuffer1, &cLeft);
DBG_ASSERT(Status);
//
// Allocate all buffers left in the buffer pool
//
ppBuffer = &pBuffer;
TotalBuffers = 0;
while (BufferGet(pParms->AdapterNumber, 1, 0x100, ppBuffer, &cLeft) == STATUS_SUCCESS) {
TotalBuffers++;
ppBuffer = &(*ppBuffer)->Next.pNextBuffer;
}
PRINTF("Total buffer available: %u\n", TotalBuffers);
Status = BufferFree(pParms->AdapterNumber, pBuffer, &cLeft);
DBG_ASSERT(Status);
//
// We must be able to allocate the same number of buffer as before
// the test. Otherwise we have lost buffers.
//
Status = BufferGet(pParms->AdapterNumber, TotalBuffers, 0x100, &pBuffer, &cLeft);
DBG_ASSERT(Status);
Status = BufferFree(pParms->AdapterNumber, pBuffer, &cLeft);
DBG_ASSERT(Status);
pBuffer1->Next.cbBuffer = 0x80;
pTransmitBuffer->usFrameType = LLC_I_FRAME;
pTransmitBuffer->uchXmitReadOption = LLC_CHAIN_XMIT_COMMANDS_ON_SAP;
pConnectCcb = DlcConnectStationInit(pParms->AdapterNumber,
0,
0,
pSourceRoutingInfo
);
for (LoopCounter = 0; LoopCounter < pParms->LoopCount; LoopCounter++) {
//
// Reset all linkstation counts
//
for (iSap = 0; iSap < pParms->SapCount; iSap++) {
Status = ReportDlcReallocate(pParms->AdapterNumber,
aSapStationIds[iSap],
LLC_DECREASE_LINK_STATIONS,
127,
TRUE
);
}
//
// Setup a link sessions to all possible remote stations
// this loop try to create a maximum number of cross
// connections between two machines.
// There may be several other threads creating link stations
// parallelly. (Parallelly Jones I presume?)
//
FirstTime = TRUE;
FirstAvailRemoteSap = pParms->FirstServerSap;
iLink = 0;
for (iSap = 0; iSap < pParms->SapCount; iSap++) {
MaxLinks = iLink + MaxStations;
AllocatedLinks = OpenLinks = 0;
for (RemoteSap = FirstAvailRemoteSap;
RemoteSap <= (UCHAR)(pParms->FirstServerSap + pParms->SapCount * 2);
RemoteSap += 2) {
//
// We increase the allocated link stations one by one
//
if (OpenLinks >= AllocatedLinks) {
Status = ReportDlcReallocate(pParms->AdapterNumber,
aSapStationIds[iSap],
LLC_INCREASE_LINK_STATIONS,
1,
TRUE
);
DBG_ASSERT(Status);
AllocatedLinks++;
}
//
// Open a link station,
// we have the destination station node address and sap number
// in the received frame.
//
if (VerboseMode) {
printf("Opening link station %d: SSAP = %04x DSAP = %04x\n",
iSap,
aSapStationIds[iSap],
RemoteSap
);
}
Status = DlcOpenStation(pParms->AdapterNumber,
aSapStationIds[iSap],
RemoteSap,
&LanHeader[2],
NULL,
&aLinkStationIds[iLink]
);
DBG_ASSERT(Status);
if (Status == STATUS_SUCCESS) {
//*
//
// The first link connection must have a high retry
// count, because server cannot response too fast
// when its processing close command completions
//
if (iLink == 0) {
Status = DlcModify(pParms->AdapterNumber,
aLinkStationIds[iLink],
&FirstModifyParms
);
}
//
// Here we will change DLC parameters, when the
// station is not yet active
//
else if (AlternateParms[iLink % MAX_ALTERNATE_PARMS] != NULL) {
Status = DlcModify(pParms->AdapterNumber,
aLinkStationIds[iLink],
AlternateParms[iLink % MAX_ALTERNATE_PARMS]
);
}
//*/
//
// Connect to the remote node
//
pConnectCcb->u.pParameterTable->DlcConnectStation.usStationId = aLinkStationIds[iLink];
AcsLan(pConnectCcb, NULL);
//
// The trace printing in the server side may take a
// very long time, before it completes
//
if (FirstTime == TRUE) {
FirstTime = FALSE;
Status = WaitForSingleObject(pConnectCcb->hCompletionEvent, 20000L);
} else {
Status = WaitForSingleObject(pConnectCcb->hCompletionEvent, 5000L);
}
DBG_ASSERT(Status);
if (pConnectCcb->uchDlcStatus == LLC_STATUS_CONNECT_FAILED) {
//
// The other side has no link stations allocated
// for this sap. Try the next one.
//
pCcb = LlcCloseInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
LLC_DLC_CLOSE_STATION,
aLinkStationIds[iLink]
);
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
Status = ReadClientEvent(pReadCcb,
&TransmitCcbPool,
LLC_EVENT_COMMAND_COMPLETION,
1,
5000L,
NULL
);
DBG_ASSERT(Status);
FirstAvailRemoteSap += 2;
} else {
DBG_ASSERT(pConnectCcb->uchDlcStatus);
pCcb = ReceiveInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
aLinkStationIds[iLink],
0,
TEST_RECEIVE_FLAG,
LLC_NOT_CONTIGUOUS_DATA,
LLC_RCV_CHAIN_FRAMES_ON_SAP
);
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
iLink++;
OpenLinks++;
}
if ((iSap != (UINT)(pParms->SapCount - 1)
&& OpenLinks == (UINT)(256 / pParms->SapCount))
|| iLink == 255) {
break;
}
}
}
if (iLink == 255) {
break;
}
}
MaxLinks = iLink;
if (iLink != 255) {
printf(" Couldn't open all link stations (only %u/255)!", iLink);
DBG_ASSERT(-1);
}
SetBuffers(pBuffer1, TEST_COMMAND_ECHO_BACK, 1, '0', '9');
for (i = 0; i < 2; i++) {
puts("Sending data to all link stations.");
for (iLink = 0; iLink < MaxLinks; iLink++) {
pTransmitBuffer->usStationId = aLinkStationIds[iLink];
TransmitBuffers(pBuffer1, // DLC buffer list
pTransmitBuffer, //
&TransmitCcbPool, // pool for transmit CCBs
DEFAULT_REPEAT_COUNT, // repeat count
0, // cur index in buf table
FALSE,
FALSE,
NULL
);
}
Status = ReadClientEvent(pReadCcb,
&TransmitCcbPool,
LLC_EVENT_RECEIVE_DATA | LLC_EVENT_TRANSMIT_COMPLETION,
MaxLinks * (DEFAULT_REPEAT_COUNT + 1),
20000L,
NULL
);
DBG_ASSERT(Status);
}
SetBuffers(pBuffer1, TEST_COMMAND_READ, 1, 'a', 'z');
for (iLink = 0; iLink < MaxLinks; iLink++) {
pTransmitBuffer->usStationId = aLinkStationIds[iLink];
TransmitBuffers(pBuffer1, // DLC buffer list
pTransmitBuffer, //
&TransmitCcbPool, // pool for transmit CCBs
1, // repeat count
0, // current index in buffer table
FALSE,
FALSE,
NULL
);
if (LoopCounter < pParms->LoopCount - 1) {
pCcb = LlcCloseInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
LLC_DLC_CLOSE_STATION,
aLinkStationIds[iLink]
);
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
}
}
if (LoopCounter < pParms->LoopCount - 1) {
//
// XMIT, CLOSE and RECEIVE for each link:
//
puts("Reading DLC.CLOSE.STATIONs & xmit command completions.");
Status = ReadClientEvent(pReadCcb,
&TransmitCcbPool,
LLC_EVENT_COMMAND_COMPLETION
| LLC_EVENT_TRANSMIT_COMPLETION,
MaxLinks * 3,
15000L,
NULL
);
DBG_ASSERT(Status);
}
}
//
// Overload the also the sap transmit queues just before everything
// is reset
//
pTransmitBuffer->usFrameType = LLC_UI_FRAME;
pTransmitBuffer->uchRemoteSap = pParms->FirstServerSap;
pTransmitBuffer->aXmitBuffer[0].pBuffer = LanHeader;
pTransmitBuffer->aXmitBuffer[0].cbBuffer = (USHORT)LanHeaderLength;
pTransmitBuffer->aXmitBuffer[0].eSegmentType = LLC_FIRST_DATA_SEGMENT;
pTransmitBuffer->aXmitBuffer[0].boolFreeBuffer = FALSE;
for (iSap = 0; iSap < MaxSapStations; iSap++) {
pTransmitBuffer->usStationId = aSapStationIds[iSap];
TransmitBuffers(pBuffer1, // DLC buffer list
pTransmitBuffer, //
&TransmitCcbPool, // pool for transmit CCBs
1, // repeat count
1, // current index in buffer table
FALSE,
FALSE,
NULL
);
}
#ifdef OS2_EMU_DLC
//
// Wait a short time to start the data transmission
//
Sleep(500L);
#endif
//
// Use reset to close all open sap stations and link stations
//
pCcb = LlcCloseInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
LLC_DLC_RESET,
0
);
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
//TraceFlagSet = TRUE;
puts("Reading DLC.RESET & command completions");
Status = ReadClientEvent(pReadCcb,
&TransmitCcbPool,
LLC_EVENT_COMMAND_COMPLETION
| LLC_EVENT_TRANSMIT_COMPLETION,
1 + MaxLinks * 2 + MaxSapStations,
15000L,
NULL
);
DBG_ASSERT(Status);
//TraceFlagSet = FALSE;
//
// We must be able to allocate the same number of buffer as before
// the test. Otherwise we have lost buffers.
//
Status = BufferGet(pParms->AdapterNumber, TotalBuffers, 0x100, &pBuffer, &cLeft);
DBG_ASSERT(Status);
// Status = BufferFree(pParms->AdapterNumber, pBuffer1, &cLeft);
// DBG_ASSERT(Status);
pCcb = LlcCloseInit(pParms->AdapterNumber, 0, LLC_DIR_CLOSE_ADAPTER, 0);
Status = AcsLan(pCcb, NULL);
while (pCcb->uchDlcStatus == LLC_STATUS_PENDING) {
Sleep(100L);
}
DBG_ASSERT(pCcb->uchDlcStatus);
FreeCcb(pCcb);
FREE(pTransmitBuffer);
CcbPoolDelete(&TransmitCcbPool);
FreeCcb(pReadCcb);
FreeCcb(pConnectCcb);
EnterCriticalSection(&CloseSection);
*(pParms->pCloseCounter)--;
LeaveCriticalSection(&CloseSection);
FREE(pParms);
puts("****** LinkConnectStressTest complete ******");
return STATUS_SUCCESS;
}
UINT
LinkDataTransferTest(
IN PDLC_TEST_THREAD_PARMS pParms
)
/*++
This procedure stress tests the heavy data transfer on
several link stations.
--*/
{
//
// The idea:
// Allocate buffer, fill it with the data, do various tests, that
// sends and receives the orginal data and check the received
// data buffer again in the end. To minimize the network load
// the main part of test is made with a small packet size.
// The test does the given number of loops or it
// takes forever.
//
// Test types:
// - sending from user buffers
// - full/half duplex data flow: having simultaneous data flow
// to both directions / or having data flow first to
// - sharing the sap by several link stations.
// - Packet size:
// * using variable length packets (including 0 length packets)
// * using very small packets
// * using maximum packet size
// - taking the time stamps?
//
//
// This thread is the main thread of the DLC data transfer
// stress. It opens the sap, open and connects the link stations
// for the test, create the worker threads and then starts the
// testing simultaneously in all threads.
// This thread also handles
//
UINT Status;
UINT i;
UINT OpenError;
UINT MaxFrameLength;
USHORT SapStationId;
USHORT LinkStationId;
PVOID hPool;
PLLC_BUFFER pFirstBuffer;
DLC_TEST_PACKET TestPacket;
PLLC_CCB pCcb;
PLLC_CCB pReadCcb;
PLLC_CCB pReceiveCcb;
LLC_TEST_CCB_POOL TransmitCcbPool;
UCHAR LinksAvail;
PLLC_READ_PARMS pReadParms;
PUCHAR pBuffer;
UCHAR Ch;
ULONG Tid = 0;
PXMIT_STRESS_WORKER pWorkerParms;
PXMIT_STRESS_WORKER aWorkerParms[40];
UCHAR SendBuffer[sizeof(TestPacket) + FOOBAR_HEADER_LENGTH];
UCHAR RemoteSap;
UCHAR LanHeader[32];
UINT LanHeaderLength;
LLC_DLC_MODIFY_PARMS DlcModifyParms;
HANDLE hThread;
BOOLEAN FirstTime = TRUE;
PUCHAR pSourceRoutingInfo;
puts("****** LinkDataTransferTest ******");
memset(&DlcModifyParms, 0, sizeof(DlcModifyParms));
pBuffer = ALLOC(pParms->TestBufferSize);
Ch = 'A';
for (i = 0; i < pParms->TestBufferSize; i++) {
if ((pBuffer[i] = Ch++) == 'Z') {
Ch = 'A';
}
}
//
// Initialize the Transmit ccb pool
//
CcbPoolInitialize(&TransmitCcbPool,
pParms->AdapterNumber,
LLC_TRANSMIT_FRAMES,
TEST_TRANSMIT_COMPLETION_FLAG
);
Status = LlcDirOpenAdapter(pParms->AdapterNumber,
NULL,
NULL,
&OpenError,
NULL,
&MaxFrameLength,
NULL
);
DBG_ASSERT(Status);
Status = BufferCreate(pParms->AdapterNumber,
pParms->pPool,
DEFAULT_BUFFER_SIZE,
min(0xff00, DEFAULT_BUFFER_SIZE),
0x1000,
&hPool
);
DBG_ASSERT(Status);
Status = LlcDlcOpenSap(pParms->AdapterNumber,
MaxFrameLength,
pParms->FirstClientSap,
LLC_INDIVIDUAL_SAP,
255,
0,
NULL,
TEST_DLC_STATUS_FLAG,
NULL,
&SapStationId,
&LinksAvail
);
DBG_ASSERT(Status);
//
// Setup immediately a pending receive
//
pReceiveCcb = ReceiveInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
SapStationId,
0,
TEST_RECEIVE_FLAG,
LLC_NOT_CONTIGUOUS_DATA,
LLC_RCV_READ_INDIVIDUAL_FRAMES
);
Status = AcsLan(pReceiveCcb, NULL);
pCcb = TransmitInit(pParms->AdapterNumber,
LLC_TRANSMIT_UI_FRAME,
TEST_TRANSMIT_COMPLETION_FLAG,
SapStationId,
pParms->FirstServerSap,
LLC_CHAIN_XMIT_COMMANDS_ON_SAP
);
pCcb->u.pParameterTable->Transmit.pBuffer1 = BroadcastHeader;
pCcb->u.pParameterTable->Transmit.cbBuffer1 = sizeof(BroadcastHeader);
memcpy(&BroadcastHeader[4], FunctionalAddress1, 4);
pCcb->u.pParameterTable->Transmit.pBuffer2 = SendBuffer;
pCcb->u.pParameterTable->Transmit.cbBuffer2 = sizeof(SendBuffer);
TestPacket.PacketId = DLC_TEST_ID;
TestPacket.Command = TEST_COMMAND_ECHO_BACK;
TestPacket.RepeatCount = 1;
memcpy(&SendBuffer[FOOBAR_HEADER_LENGTH], &TestPacket, sizeof(TestPacket));
//
// Send a broadcast to figure out the destination
//
pReadCcb = ReadInit(pParms->AdapterNumber,
SapStationId,
LLC_OPTION_READ_STATION,
LLC_EVENT_RECEIVE_DATA
);
pReadParms = &pReadCcb->u.pParameterTable->Read;
do {
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
Status = ReadClientEvent(pReadCcb,
&TransmitCcbPool,
LLC_EVENT_TRANSMIT_COMPLETION,
1,
// -1L
5000L,
NULL
);
DBG_ASSERT(Status);
Status = ReadClientEvent(pReadCcb,
&TransmitCcbPool,
LLC_EVENT_RECEIVE_DATA,
1,
5000L,
NULL
);
DBG_ASSERT(Status);
} while (Status != STATUS_SUCCESS);
//
// Save the lan header for later use
// BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG
// pFirstBuffer has already been returned to driver,
// the driver can reuse it in any moment and overwrite
// the data!!!!
// BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG-BUG
//
pFirstBuffer = pReadCcb->u.pParameterTable->Read.Type.Event.pReceivedFrame;
LanHeaderLength = pFirstBuffer->NotContiguous.cbLanHeader;
memcpy(LanHeader,
pFirstBuffer->NotContiguous.auchLanHeader,
pFirstBuffer->NotContiguous.cbLanHeader
);
memcpy(&LanHeader[2],
&LanHeader[8],
6
);
//
// Toggle the direction bit and reset the source routing info bit
// in the destination address (leave the source address as it, because
// it will be updated by DLC)
//
LanHeader[2] &= (UCHAR)0x7f;
LanHeader[15] ^= (UCHAR)0x80;
pSourceRoutingInfo = ((LanHeader[8] & 0x80) ? &LanHeader[14] : NULL);
//
// No we cancel the old receive command and make a new one,
// that by default links all received frames on link stations
//
Status = ReceiveCancel(pReceiveCcb);
DBG_ASSERT(Status);
pReceiveCcb = ReceiveInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
SapStationId,
0,
TEST_RECEIVE_FLAG,
LLC_NOT_CONTIGUOUS_DATA,
LLC_RCV_CHAIN_FRAMES_ON_LINK
);
Status = AcsLan(pReceiveCcb, NULL);
//
// Open a link station for each worker thread.
// We have the destination station node address
// and sap number in the received frame.
//
hStartSignal = CreateEvent(NULL, FALSE, TRUE, NULL);
pCcb = DlcConnectStationInit(pParms->AdapterNumber,
0, // no completion flag this time
LinkStationId,
pSourceRoutingInfo
);
RemoteSap = pParms->FirstServerSap;
for (i = 0; i < pParms->AllocatedStations; i++) {
pWorkerParms = ALLOC(sizeof(XMIT_STRESS_WORKER));
Status = DlcOpenStation(pParms->AdapterNumber,
SapStationId,
RemoteSap,
&LanHeader[2],
NULL,
// AlternateParms[i % MAX_ALTERNATE_PARMS],
&LinkStationId
);
RemoteSap += 2;
//
// Connect to the remote node
//
pCcb->u.pParameterTable->DlcConnectStation.usStationId = LinkStationId;
Status = AcsLan(pCcb, NULL);
//
// It takes a long time for the server end to print all trace
// in the link connect stratess test.
//
if (FirstTime == TRUE) {
FirstTime = FALSE;
Status = WaitForSingleObject(pCcb->hCompletionEvent, 40000L);
} else {
Status = WaitForSingleObject(pCcb->hCompletionEvent, 10000L);
}
DBG_ASSERT(pCcb->uchDlcStatus);
DBG_ASSERT(Status);
Status = DlcModify(pParms->AdapterNumber, LinkStationId, &DlcModifyParms);
DBG_ASSERT(Status);
pWorkerParms->MaxI_Field = DlcModifyParms.usMaxInfoFieldLength;
printf("MaxI_Field: %u\n", DlcModifyParms.usMaxInfoFieldLength);
pReceiveCcb = ReceiveInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
LinkStationId,
0,
TEST_RECEIVE_FLAG,
LLC_NOT_CONTIGUOUS_DATA,
LLC_RCV_CHAIN_FRAMES_ON_LINK
);
Status = AcsLan(pReceiveCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
pWorkerParms->hPool = hPool;
pWorkerParms->LinkStationId = LinkStationId;
pWorkerParms->pBuffer = pBuffer;
pWorkerParms->pParms = pParms;
aWorkerParms[i] = pWorkerParms;
}
FreeCcb(pCcb);
for (i = 0; i < pParms->AllocatedStations; i++) {
//
// This here because of the stupid os/2 emulation env.
// 64kb buffer pool is too small to run all 4 tests
// simultanously. Change this when the test has been
// ported to Windows/Nt
//
if (pParms->ResetCommand == 0) {
SetEvent(hStartSignal);
DataTransferWorker(aWorkerParms[i]);
} else {
hThread = CreateThread(NULL,
0,
DataTransferWorker,
aWorkerParms[i],
0,
&Tid
);
if (hThread != NULL) {
SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
}
}
}
//
// Wait until all threads are ready to start.
//
Sleep(1000L);
SetEvent(hStartSignal);
FreeCcb(pReadCcb);
pReadCcb = ReadInit(pParms->AdapterNumber,
SapStationId,
LLC_OPTION_READ_ALL,
0
);
pReadParms = &pReadCcb->u.pParameterTable->Read;
//
// Here we can test all global close commands, when the stations
// are sending data in the full speed. The upper level may
// define an optional global close command (dir.initialize,
// dir.close.adapter or dlc.reset)
//
if (pParms->ResetCommand != 0) {
pCcb = LlcCloseInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
pParms->ResetCommand,
0
);
pCcb->pNext = pReadCcb;
pCcb->uchReadFlag = 1;
Sleep(1000L);
Status = AcsLan(pCcb, NULL);
//
// pParms->ResetCommand may be invalid on purpose
//
if (Status == STATUS_SUCCESS || pParms->ResetCommand != LLC_DIR_OPEN_ADAPTER) {
DBG_ASSERT(Status);
Status = WaitForSingleObject(pReadCcb->hCompletionEvent, 10000L);
DBG_ASSERT(Status);
}
DBG_ASSERT(pReadCcb->uchDlcStatus);
FreeCcb(pCcb);
} else {
//
// We can wait until all worker threads have completed
// (ie. link station close command is completed
// by sap read).
//
Status = ReadClientEvent(pReadCcb,
&TransmitCcbPool,
LLC_EVENT_COMMAND_COMPLETION,
pParms->AllocatedStations * 2,
-1L,
NULL
);
//
// close sap
//
pCcb = LlcCloseInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
LLC_DLC_CLOSE_SAP,
SapStationId
);
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
Status = ReadClientEvent(pReadCcb,
&TransmitCcbPool,
LLC_EVENT_COMMAND_COMPLETION,
1,
5000L,
NULL
);
DBG_ASSERT(Status);
}
//
// This will terminate the DLC server, if this
// is the last operation against it.
//
if (pParms->CloseServer) {
Status = LlcDlcOpenSap(pParms->AdapterNumber,
MaxFrameLength,
pParms->FirstClientSap,
LLC_INDIVIDUAL_SAP | LLC_MEMBER_OF_GROUP_SAP,
0,
0,
NULL,
TEST_DLC_STATUS_FLAG,
NULL,
&SapStationId,
&LinksAvail
);
DBG_ASSERT(Status);
pCcb = TransmitInit(pParms->AdapterNumber,
LLC_TRANSMIT_UI_FRAME,
0,
SapStationId,
pParms->FirstServerSap,
LLC_CHAIN_XMIT_COMMANDS_ON_SAP
);
pCcb->u.pParameterTable->Transmit.pBuffer1 = LanHeader;
pCcb->u.pParameterTable->Transmit.cbBuffer1 = sizeof(LanHeader);
pCcb->u.pParameterTable->Transmit.pBuffer2 = SendBuffer;
pCcb->u.pParameterTable->Transmit.cbBuffer2 = sizeof(SendBuffer);
TestPacket.PacketId = DLC_TEST_ID;
TestPacket.Command = TEST_COMMAND_EXIT;
TestPacket.RepeatCount = 1;
memcpy(&SendBuffer[FOOBAR_HEADER_LENGTH], &TestPacket, sizeof(TestPacket));
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(Status);
Status = WaitForSingleObject(pCcb->hCompletionEvent, 10000L);
DBG_ASSERT(Status);
DBG_ASSERT(pCcb->uchDlcStatus);
FreeCcb(pCcb);
}
if (pParms->ResetCommand != LLC_DIR_CLOSE_ADAPTER && pParms->ResetCommand != LLC_DIR_INITIALIZE) {
pCcb = LlcCloseInit(pParms->AdapterNumber, 0, LLC_DIR_CLOSE_ADAPTER, 0);
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(Status);
Status = WaitForSingleObject(pCcb->hCompletionEvent, 10000L);
DBG_ASSERT(Status);
DBG_ASSERT(pCcb->uchDlcStatus);
FreeCcb(pCcb);
}
CcbPoolDelete(&TransmitCcbPool);
FreeCcb(pReadCcb);
CloseHandle(hStartSignal);
*(pParms->pCloseCounter)--;
FREE(pParms);
puts("****** LinkDataTransferTest complete ******");
return STATUS_SUCCESS;
}
ULONG
DataTransferWorker(
PVOID hXmitParms
)
/*++
This procedure stress tests the heavy data transfer on
several link stations.
--*/
{
PXMIT_STRESS_WORKER pXmitParms = (PXMIT_STRESS_WORKER)hXmitParms;
UINT Status;
UINT i;
UINT PacketLength;
UINT TransmitElements;
PLLC_TRANSMIT2_COMMAND pTransmitBuffer;
PDLC_TEST_PACKET pTestPacket;
PDLC_TEST_PACKET pTestPacket2;
PLLC_CCB pCcb;
PLLC_CCB pReadCcb;
PLLC_READ_PARMS pReadParms;
LLC_TEST_CCB_POOL TransmitCcbPool;
PDLC_TEST_THREAD_PARMS pParms = pXmitParms->pParms;
PLLC_BUFFER pBuffer;
PLLC_BUFFER pBuffer1;
PLLC_BUFFER pBuffer2;
ULONG TotalDataLength;
ULONG ReceiveOffset;
ULONG TransmitOffset;
ULONG DataLength;
UINT FrameCount;
UINT ReceivedFrameCount;
PLLC_BUFFER pReceivedFrames;
UINT cLeft;
puts("\nDataTransferWorker\n");
//
// Initialize the Transmit ccb pool
//
CcbPoolInitialize(&TransmitCcbPool,
pParms->AdapterNumber,
LLC_TRANSMIT_FRAMES,
TEST_TRANSMIT_COMPLETION_FLAG
);
//
// Send a broadcast to figure out the destination
//
pReadCcb = ReadInit(pParms->AdapterNumber,
pXmitParms->LinkStationId,
LLC_OPTION_READ_STATION,
LLC_EVENT_RECEIVE_DATA
);
pReadParms = &pReadCcb->u.pParameterTable->Read;
pTransmitBuffer = (PLLC_TRANSMIT2_COMMAND)ALLOC(
sizeof(LLC_TRANSMIT2_COMMAND) +
sizeof(LLC_TRANSMIT_DESCRIPTOR) * MAX_XMIT_BUFFERS
);
//
// Send data and receive it back
//
pTransmitBuffer->usStationId = pXmitParms->LinkStationId;
pTransmitBuffer->usFrameType = LLC_I_FRAME;
pTransmitBuffer->uchXmitReadOption = LLC_CHAIN_XMIT_COMMANDS_ON_LINK;
//
// We must keep the buffer headers in the buffer pool, because
// otherwise the tranmsit commands may fail, because this process
// has too many locked pages.
//
Status = BufferGet(pParms->AdapterNumber, 1, 0x100, &pBuffer1, &cLeft);
pTestPacket = (PDLC_TEST_PACKET)&pBuffer1->Contiguous.usStationId;
Status = BufferGet(pParms->AdapterNumber, 1, 0x100, &pBuffer2, &cLeft);
pTestPacket2 = (PDLC_TEST_PACKET)&pBuffer2->Contiguous.usStationId;
pTestPacket->PacketId = DLC_TEST_ID;
pTestPacket->Command = TEST_COMMAND_ECHO_BACK;
pTestPacket->RepeatCount = 1;
TotalDataLength = (ULONG)pParms->LoopCount * (ULONG)pParms->TestBufferSize;
TransmitOffset = 0;
ReceiveOffset = 0;
DataLength = 0;
switch ((pXmitParms->LinkStationId & 0xff) % 4) {
case 0:
//
// Small packets, full speed, full duplex:
// two-way data stream
//
for (i = 0; DataLength < pParms->TestBufferSize; i += 2) {
if (DataLength + SMALL_PACKET_SIZE < pParms->TestBufferSize) {
PacketLength = SMALL_PACKET_SIZE;
} else {
PacketLength = (UINT)(pParms->TestBufferSize - DataLength);
}
pTransmitBuffer->aXmitBuffer[i].pBuffer = pTestPacket;
pTransmitBuffer->aXmitBuffer[i].cbBuffer = sizeof(*pTestPacket);
pTransmitBuffer->aXmitBuffer[i].eSegmentType = LLC_FIRST_DATA_SEGMENT;
pTransmitBuffer->aXmitBuffer[i].boolFreeBuffer = FALSE;
pTransmitBuffer->aXmitBuffer[i+1].pBuffer = &pXmitParms->pBuffer[DataLength];
pTransmitBuffer->aXmitBuffer[i+1].cbBuffer = (USHORT)PacketLength;
pTransmitBuffer->aXmitBuffer[i+1].eSegmentType = LLC_NEXT_DATA_SEGMENT;
pTransmitBuffer->aXmitBuffer[i+1].boolFreeBuffer = FALSE;
DataLength += PacketLength;
}
pTransmitBuffer->cXmitBufferCount = i;
break;
case 1:
//
// Variable length packets & full-duplex:
// two-way data stream
//
PacketLength = 0;
for (i = 0; DataLength < pParms->TestBufferSize; i += 2) {
if (DataLength + PacketLength > pParms->TestBufferSize) {
PacketLength = (UINT)(pParms->TestBufferSize - DataLength);
}
pTransmitBuffer->aXmitBuffer[i].pBuffer = pTestPacket;
pTransmitBuffer->aXmitBuffer[i].cbBuffer = sizeof(*pTestPacket);
pTransmitBuffer->aXmitBuffer[i].eSegmentType = LLC_FIRST_DATA_SEGMENT;
pTransmitBuffer->aXmitBuffer[i].boolFreeBuffer = FALSE;
pTransmitBuffer->aXmitBuffer[i+1].pBuffer = &pXmitParms->pBuffer[DataLength];
pTransmitBuffer->aXmitBuffer[i+1].cbBuffer = (USHORT)PacketLength;
pTransmitBuffer->aXmitBuffer[i+1].eSegmentType = LLC_NEXT_DATA_SEGMENT;
pTransmitBuffer->aXmitBuffer[i+1].boolFreeBuffer = FALSE;
DataLength += PacketLength;
PacketLength++;
}
pTransmitBuffer->cXmitBufferCount = i;
break;
case 2:
//
// Half-duplex data transfer:
//
*pTestPacket2 = *pTestPacket;
//
// IDIOT!!!, This was worth of almost 2 days work, we cannot use
// delayed echoing when the data transfer may be stopped in the middle!!!
//
// pTestPacket->Command = TEST_COMMAND_DELAYED_ECHO;
for (i = 0; DataLength < pParms->TestBufferSize; i += 2) {
if (DataLength + SMALL_PACKET_SIZE < pParms->TestBufferSize) {
PacketLength = SMALL_PACKET_SIZE;
} else {
PacketLength = (UINT)(pParms->TestBufferSize - DataLength);
}
pTransmitBuffer->aXmitBuffer[i].pBuffer = pTestPacket;
pTransmitBuffer->aXmitBuffer[i].cbBuffer = sizeof(*pTestPacket);
pTransmitBuffer->aXmitBuffer[i].eSegmentType = LLC_FIRST_DATA_SEGMENT;
pTransmitBuffer->aXmitBuffer[i].boolFreeBuffer = FALSE;
pTransmitBuffer->aXmitBuffer[i+1].pBuffer = &pXmitParms->pBuffer[DataLength];
pTransmitBuffer->aXmitBuffer[i+1].cbBuffer = (USHORT)PacketLength;
pTransmitBuffer->aXmitBuffer[i+1].eSegmentType = LLC_NEXT_DATA_SEGMENT;
pTransmitBuffer->aXmitBuffer[i+1].boolFreeBuffer = FALSE;
DataLength += PacketLength;
}
pTransmitBuffer->aXmitBuffer[i-2].pBuffer = pTestPacket2;
pTransmitBuffer->cXmitBufferCount = i;
break;
case 3:
//
// Test the maximum length packets
//
for (i = 0; DataLength < pParms->TestBufferSize; i += 2) {
if (DataLength + pXmitParms->MaxI_Field - sizeof(*pTestPacket) < pParms->TestBufferSize) {
PacketLength = pXmitParms->MaxI_Field - sizeof(*pTestPacket);
} else {
PacketLength = (UINT)(pParms->TestBufferSize - DataLength);
}
pTransmitBuffer->aXmitBuffer[i].pBuffer = pTestPacket;
pTransmitBuffer->aXmitBuffer[i].cbBuffer = sizeof(*pTestPacket);
pTransmitBuffer->aXmitBuffer[i].eSegmentType = LLC_FIRST_DATA_SEGMENT;
pTransmitBuffer->aXmitBuffer[i].boolFreeBuffer = FALSE;
pTransmitBuffer->aXmitBuffer[i+1].pBuffer = &pXmitParms->pBuffer[DataLength];
pTransmitBuffer->aXmitBuffer[i+1].cbBuffer = (USHORT)PacketLength;
pTransmitBuffer->aXmitBuffer[i+1].eSegmentType = LLC_NEXT_DATA_SEGMENT;
pTransmitBuffer->aXmitBuffer[i+1].boolFreeBuffer = FALSE;
DataLength += PacketLength;
}
pTransmitBuffer->cXmitBufferCount = i;
break;
}
TransmitOffset = DataLength;
TransmitElements = i;
//
// This loop rotates the given amount the data from a data buffer.
// All received data is compared.
//
pReadParms->Type.Event.pReceivedFrame = NULL;
do {
//
// Free all extra buffers, when the transmit offset
// exceeds the given amout of the data.
//
/*
TransmitOffset = FreeExtraBuffers(&pReadParms->Type.Event.pReceivedFrame,
TransmitOffset,
TotalDataLength,
pParms->AdapterNumber,
pXmitParms->LinkStationId
);
*/
puts("Transmitting the packets.");
//getchar();
Status = TransmitBuffers(NULL,
pTransmitBuffer,
&TransmitCcbPool, // pool for transmit CCBs
1, // repeat count
TransmitElements, // current index in buffer table
//i, // current index in buffer table
FALSE, // free all sent buffers
FALSE,
&FrameCount
);
WORKER_ASSERT(Status);
puts("Reading the transmit completion.");
Status = ReadClientEvent(pReadCcb,
&TransmitCcbPool,
LLC_EVENT_TRANSMIT_COMPLETION,
1,
//-1L
//20000L,
60000L,
NULL
);
WORKER_ASSERT(Status);
puts("Receiving the data.");
//
// Receive all sent packets back and compare them with the
// orginal data.
//
ReceivedFrameCount = 0;
i = 0;
do {
pReceivedFrames = NULL;
Status = ReadClientEvent(pReadCcb,
NULL,
LLC_EVENT_RECEIVE_DATA,
1,
10000L,
//1000L,
&pReceivedFrames
);
WORKER_ASSERT(Status);
ReceivedFrameCount += pReadParms->Type.Event.usReceivedFrameCount;
ReceiveOffset = CompareReceiveBuffers(pReceivedFrames,
pXmitParms->pBuffer,
(ULONG)pParms->TestBufferSize,
ReceiveOffset,
pParms->CompareAllData,
&i
);
if (FreeAllFrames(pParms->AdapterNumber,
pReceivedFrames,
&cLeft
) != pReadParms->Type.Event.usReceivedFrameCount) {
printf("Error: FreeAllFrames() != ReceivedFrameCount\n");
}
} while (ReceivedFrameCount < FrameCount);
} while (ReceiveOffset < TotalDataLength);
ReportDlcStatistics(pParms->AdapterNumber, pXmitParms->LinkStationId);
Status = BufferGet(pParms->AdapterNumber, 1, 0x100, &pBuffer, &cLeft);
WORKER_ASSERT(Status);
Status = BufferFree(pParms->AdapterNumber, pBuffer, &cLeft);
WORKER_ASSERT(Status);
//
// Free the transmit headers
//
Status = BufferFree(pParms->AdapterNumber, pBuffer1, &cLeft);
WORKER_ASSERT(Status);
Status = BufferFree(pParms->AdapterNumber, pBuffer2, &cLeft);
WORKER_ASSERT(Status);
#ifdef OS2_EMU_DLC
LlcTraceDumpAndReset(-1, 1, NULL);
#endif
//
// close the link station
//
pCcb = LlcCloseInit(pParms->AdapterNumber,
TEST_COMMAND_COMPLETION_FLAG,
LLC_DLC_CLOSE_STATION,
pXmitParms->LinkStationId
);
pCcb->hCompletionEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
Status = AcsLan(pCcb, NULL);
if (Status == STATUS_PENDING) {
Status = WaitForSingleObject(pCcb->hCompletionEvent, 10000L);
WORKER_ASSERT(Status);
}
WORKER_ASSERT(pCcb->uchDlcStatus);
CcbPoolDelete(&TransmitCcbPool);
FREE(pTransmitBuffer);
FREE(pXmitParms);
FreeCcb(pReadCcb);
return STATUS_SUCCESS;
}
ULONG
FreeExtraBuffers(
IN PLLC_BUFFER *ppFirstBuffer,
IN ULONG TransmitOffset,
IN ULONG TotalDataLength,
IN UCHAR AdapterNumber,
IN USHORT StationId
)
{
PLLC_BUFFER pNext;
UINT cLeft;
UNREFERENCED_PARAMETER(StationId);
for (; *ppFirstBuffer != NULL; ppFirstBuffer = &(*ppFirstBuffer)->Contiguous.pNextFrame) {
//
// We know, that total length is even with the frame data length
//
if (TransmitOffset < TotalDataLength) {
for (pNext = *ppFirstBuffer; pNext != NULL; pNext = pNext->Next.pNextBuffer) {
TransmitOffset += pNext->Next.cbBuffer - sizeof(DLC_TEST_PACKET);
}
} else {
FreeAllFrames(AdapterNumber, *ppFirstBuffer, &cLeft);
*ppFirstBuffer = NULL;
break;
}
}
return TransmitOffset;
}
UINT
FreeAllFrames(
IN UCHAR AdapterNumber,
IN PLLC_BUFFER pFirstBuffer,
IN PUINT pcLeft
)
{
PLLC_BUFFER pNextFrame;
UINT cReleased = 0;
UINT Status;
for (; pFirstBuffer != NULL; pFirstBuffer = pNextFrame) {
pNextFrame = pFirstBuffer->Contiguous.pNextFrame;
Status = BufferFree(AdapterNumber, pFirstBuffer, pcLeft);
//
// Stop immediately, if the buffer pool is deleted!
//
if (Status == STATUS_SUCCESS) {
cReleased++;
} else if (Status == LLC_STATUS_ADAPTER_CLOSED) {
ExitThread(STATUS_SUCCESS);
}
}
return cReleased;
}
ULONG
CompareReceiveBuffers(
IN PLLC_BUFFER pFirstBuffer,
IN PUCHAR pBuffer,
IN ULONG BufferLength,
IN ULONG DataOffset,
IN BOOLEAN CompareData,
IN PUINT pIndex
)
{
PLLC_BUFFER pNext;
PLLC_BUFFER pPrevFirst;
UINT ProtocolHeaderLength, BufferOffset, Status;
PLLC_CCB pCcb;
static BOOLEAN CompareError = FALSE;
PLLC_BUFFER originalRxBuffer = pFirstBuffer;
PUCHAR originalTxBuffer = pBuffer;
ULONG originalLength = BufferLength;
ULONG originalOffset = DataOffset;
ULONG whichFrame = 0;
static FramesChecked = 0;
for (; pFirstBuffer != NULL; pFirstBuffer = pFirstBuffer->Contiguous.pNextFrame) {
ProtocolHeaderLength = sizeof(DLC_TEST_PACKET);
(*pIndex)++;
//
// Invalid response frame!!! The protocol header is missing!
//
if (ProtocolHeaderLength > pFirstBuffer->Next.cbBuffer) {
DBG_ASSERT(-1);
}
for (pNext = pFirstBuffer; pNext != NULL; pNext = pNext->Next.pNextBuffer) {
BufferOffset = pNext->Next.cbUserData
+ pNext->Next.offUserData
+ ProtocolHeaderLength;
if (CompareError) {
CompareData = FALSE;
}
if (CompareData && memcmp(&pBuffer[DataOffset % BufferLength],
(PUCHAR)pNext + BufferOffset,
pNext->Next.cbBuffer - ProtocolHeaderLength
)) {
PUCHAR Source = (PUCHAR)pNext + BufferOffset;
PUCHAR Dest = &pBuffer[DataOffset % BufferLength];
UINT i;
UINT Length = pNext->Next.cbBuffer - ProtocolHeaderLength;
//for (i = 0; Source[i] != Dest[i]; i++);
//if (i > 0) i--;
//if (i + 40 < Length) Length = i + 40;
//Source[Length - 1] = 0;
//Dest[Length - 1] = 0;
for (i = 0; Source[i] == Dest[i]; i++);
puts("The data is corrupted!!");
printf("data offset : %u\n", DataOffset);
printf("packet number : %u\n", *pIndex);
printf("fail offset : %d\n", i);
printf("original rx buf = %x\n", originalRxBuffer);
printf("failing rx buf = %x\n", pFirstBuffer);
printf("original tx buf = %x\n", originalTxBuffer);
printf("original length = %d\n", originalLength);
printf("original offset = %d\n", originalOffset);
printf("frame # %d\n", whichFrame);
printf("FramesChecked = %d\n", FramesChecked);
//{
// UINT i, j;
//
// for (j = pNext->Next.cbBuffer, i=0; j; --j, ++i) {
// if () {
// }
// }
// printf("characters : s=%02.2x, d=%02.2x\n", Source
//}
//#ifdef i386
// SetAcslanDebugFlags(DEBUG_DUMP_RX_DATA
// | DEBUG_DUMP_DATA_CHAIN
// | DEBUG_DUMP_FRAME_CHAIN
// | DEBUG_DUMP_RX_ASCII
// );
// DumpReceiveDataBuffer(originalRxBuffer);
//#endif
DebugBreak();
// DlcDebugBreak();
pCcb = LlcCloseInit(pFirstBuffer->NotContiguous.uchAdapterNumber,
0,
LLC_DIR_CLOSE_ADAPTER,
0
);
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
FreeCcb(pCcb);
DBG_ASSERT(-1);
CompareError = TRUE;
}
DataOffset += pNext->Next.cbBuffer - ProtocolHeaderLength;
ProtocolHeaderLength = 0;
}
pPrevFirst = pFirstBuffer;
++whichFrame;
++FramesChecked;
}
return DataOffset;
}
UINT
TransmitBuffers(
PLLC_BUFFER pFirstBuffer,
PLLC_TRANSMIT2_COMMAND pTransmitBuffer,
PLLC_TEST_CCB_POOL pTransmitCcbPool,
UINT RepeatCount,
UINT cElement,
BOOLEAN FreeTransmitBuffers,
BOOLEAN SendReceiveBuffer,
OUT PUINT pFrameCount
)
{
UINT cTotalElements;
UINT cTransmitElements;
UINT i;
UINT Status = LLC_STATUS_LINK_NOT_TRANSMITTING;
PLLC_CCB pCcb;
PLLC_BUFFER pBuffer;
UINT FrameCount = 0;
for (; pFirstBuffer != NULL; pFirstBuffer = pFirstBuffer->NotContiguous.pNextFrame) {
if (cElement >= MAX_XMIT_BUFFERS) {
return LLC_STATUS_NO_MEMORY;
}
if (cElement == 0 || SendReceiveBuffer) {
pTransmitBuffer->aXmitBuffer[cElement].eSegmentType = LLC_FIRST_DATA_SEGMENT;
} else {
pTransmitBuffer->aXmitBuffer[cElement].eSegmentType = LLC_NEXT_DATA_SEGMENT;
}
for (pBuffer = pFirstBuffer; pBuffer != NULL; pBuffer = pBuffer->Next.pNextBuffer) {
if (cElement >= MAX_XMIT_BUFFERS) {
return LLC_STATUS_NO_MEMORY;
}
//
// The first data buffer is exceptional
//
if (pBuffer != pFirstBuffer) {
pTransmitBuffer->aXmitBuffer[cElement].eSegmentType = LLC_NEXT_DATA_SEGMENT;
}
pTransmitBuffer->aXmitBuffer[cElement].boolFreeBuffer = FALSE;
pTransmitBuffer->aXmitBuffer[cElement].cbBuffer = pBuffer->Next.cbBuffer;
pTransmitBuffer->aXmitBuffer[cElement].pBuffer = (PUCHAR)pBuffer + pBuffer->Next.cbUserData + pBuffer->Next.offUserData;
//
// All the rest buffers have the default format:
//
cElement++;
}
if (!SendReceiveBuffer)
break;
}
//
// Send as many packets in the same time as possible.
//
cTotalElements = RepeatCount * cElement;
cTransmitElements = cElement;
if (RepeatCount > 1 && (RepeatCount * cElement) < MAX_XMIT_BUFFERS) {
for (i = 1; i < RepeatCount; i++) {
memcpy(&pTransmitBuffer->aXmitBuffer[cTransmitElements],
&pTransmitBuffer->aXmitBuffer[0],
sizeof(pTransmitBuffer->aXmitBuffer[0]) * cElement
);
cTransmitElements += cElement;
}
}
while (cTotalElements > 0) {
for (i = 0; i < cTransmitElements; i++) {
if (pTransmitBuffer->aXmitBuffer[i].eSegmentType == LLC_FIRST_DATA_SEGMENT) {
FrameCount++;
}
//
// Free the transmit buffers in the last loop.
//
if (FreeTransmitBuffers && cTotalElements == cTransmitElements) {
pTransmitBuffer->aXmitBuffer[i].boolFreeBuffer = TRUE;
}
}
pTransmitBuffer->cXmitBufferCount = cTransmitElements;
pCcb = CcbPoolAlloc(pTransmitCcbPool);
pCcb->u.pParameterTable = (PVOID)pTransmitBuffer;
//
// The link returns a protocol error, when the remote link
// station is lost or disconnected. It is completely normal state,
// we just sleep for a while for the other side to clear
// up the busy state. It's the driver's business to handle
// a situation, when
//
Status = AcsLan(pCcb, NULL);
Status = pCcb->uchDlcStatus;
if (Status != LLC_STATUS_SUCCESS
&& Status != LLC_STATUS_PENDING
&& Status != LLC_STATUS_CANCELLED_BY_SYSTEM_ACTION
&& Status != LLC_STATUS_CANCELLED_BY_USER
&& Status != LLC_STATUS_LINK_NOT_TRANSMITTING
&& Status != LLC_STATUS_INVALID_STATION_ID) {
printf("Xmit: %x)\n", Status);
break;
}
cTotalElements -= cTransmitElements;
}
if (pFrameCount != NULL) {
*pFrameCount = FrameCount;
}
return Status;
}
VOID
SetBuffers(
IN PLLC_BUFFER pBuffer,
IN USHORT Command,
IN USHORT RepeatCount,
IN UCHAR FirstChar,
IN UCHAR LastChar
)
{
UINT i;
UINT cbData;
PCHAR pData;
UCHAR Ch;
PDLC_TEST_PACKET pTestPacket;
BOOLEAN IsFirstTime = TRUE;
pTestPacket = (PDLC_TEST_PACKET)((PUCHAR)pBuffer
+ pBuffer->Next.offUserData
+ pBuffer->Next.cbUserData);
pTestPacket->PacketId = DLC_TEST_ID;
pTestPacket->Command = Command;
pTestPacket->RepeatCount = RepeatCount;
for (; pBuffer != NULL; pBuffer = pBuffer->Next.pNextBuffer) {
pData = (PUCHAR)pBuffer
+ pBuffer->Next.offUserData
+ pBuffer->Next.cbUserData;
cbData = pBuffer->Next.cbBuffer
- (pBuffer->Next.offUserData
+ pBuffer->Next.cbUserData);
if (IsFirstTime) {
IsFirstTime = FALSE;
cbData -= sizeof(DLC_TEST_PACKET);
pData += sizeof(DLC_TEST_PACKET);
}
Ch = FirstChar;
for (i = 0; i < cbData; i++) {
pData[i] = Ch;
if ((++Ch) > LastChar) {
Ch = FirstChar;
}
}
}
}
UINT
DlcTestTransact(
IN PLLC_CCB pCcb,
IN PLLC_CCB pReadCcb,
IN UCHAR ExpectedMessageType
) {
UINT Status;
pCcb->pNext = NULL;
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
if (pCcb->ulCompletionFlag == 0) {
Status = WaitForSingleObject(pCcb->hCompletionEvent, 10000L);
DBG_ASSERT(Status);
DBG_ASSERT(pCcb->uchDlcStatus);
} else {
Status = ReadClientEvent(pReadCcb,
NULL,
LLC_EVENT_TRANSMIT_COMPLETION,
1,
10000L,
NULL
);
DBG_ASSERT(Status);
}
do {
Status = ReadClientEvent(pReadCcb,
NULL,
LLC_EVENT_RECEIVE_DATA,
1,
// 2000L
// 500L
5000L,
NULL
);
if (Status != STATUS_SUCCESS) {
return Status;
}
} while (ExpectedMessageType != pReadCcb->u.pParameterTable->Read.Type.Event.pReceivedFrame->Contiguous.uchMsgType);
return Status;
}
UINT
ReadClientEvent(
IN PLLC_CCB pReadCcb,
IN PLLC_TEST_CCB_POOL pTransmitCcbPool,
IN UCHAR EventMask,
IN UINT EventCount,
IN ULONG Timeout,
PLLC_BUFFER *ppBuffer OPTIONAL // chain of all received buffers
)
/*++
Generic DLC READ procedure, that handles all requested events
and returns.
--*/
{
UINT Status = STATUS_SUCCESS;
UINT DlcStatus;
PLLC_READ_PARMS pReadParms;
PDLC_TEST_PACKET pDlcPacket;
PLLC_BUFFER pFirstBuffer, pNextFrame;
PLLC_CCB pNextCcb, pCcb;
struct {
UINT Receives;
UINT CmdCompletion;
UINT XmitCompletion;
UINT Status;
} Count;
UINT NewEvents;
UINT cBuffersLeft = -1;
UINT cLeft = -1;
BOOLEAN LocalBusy = FALSE;
PLLC_BUFFER* ppCurFrame = ppBuffer;
UINT AllEvents;
// UINT CurrentSap;
Count.Receives = 0;
Count.CmdCompletion = 0;
Count.XmitCompletion = 0;
Count.Status = 0;
pReadParms = &pReadCcb->u.pParameterTable->Read;
//
// We must always monitor the link station status in receive,
// because the out of buffers state must be released
// by the DlcFlowControl command.
//
pReadParms->uchEventSet = EventMask | (UCHAR)LLC_EVENT_STATUS_CHANGE;
while (EventCount != 0) {
Status = AcsLan(pReadCcb, NULL);
if (pReadCcb->uchDlcStatus == LLC_STATUS_PENDING) {
Status = WaitForSingleObject(pReadCcb->hCompletionEvent, Timeout);
if (Status != STATUS_SUCCESS) {
if (Timeout > 2000) {
printf("Read timeout, events left: %u\n", EventCount);
printf("Count.Receives: %u\n", Count.Receives);
printf("Count.CmdCompletion: %u\n", Count.CmdCompletion);
printf("Count.XmitCompletion: %u\n", Count.XmitCompletion);
printf("Count.Status: %u\n", Count.Status);
}
ReadCancel(pReadCcb);
pReadCcb->uchDlcStatus = LLC_STATUS_PENDING;
return Status;
}
} else if (pReadCcb->uchDlcStatus != STATUS_SUCCESS) {
printf("Error in READ CCB: %xH\n", pReadCcb->uchDlcStatus);
return pReadCcb->uchDlcStatus;
}
NewEvents = 1;
switch (pReadParms->uchEvent) {
case LLC_EVENT_RECEIVE_DATA:
if (pReadParms->ulNotificationFlag != TEST_RECEIVE_FLAG) {
DlcDebugBreak();
}
/*
*******************************************************************************
AllEvents = 0;
for (
pFirstBuffer = pReadParms->Type.Event.pReceivedFrame;
pFirstBuffer != NULL;
pFirstBuffer = pFirstBuffer->Contiguous.pNextFrame)
{
AllEvents++;
}
if (AllEvents > 40)
{
printf("\n");
}
*******************************************************************************
*/
//CurrentSap = pReadParms->Type.Event.pReceivedFrame->Contiguous.usStationId >> 8;
NewEvents = 0;
for (pFirstBuffer = pReadParms->Type.Event.pReceivedFrame;
pFirstBuffer != NULL;
pFirstBuffer = pNextFrame) {
cBuffersLeft = pFirstBuffer->NotContiguous.cBuffersLeft;
pDlcPacket = (PDLC_TEST_PACKET)((PUCHAR)pFirstBuffer
+ pFirstBuffer->NotContiguous.cbUserData
+ pFirstBuffer->NotContiguous.offUserData);
//
// Discard all UI frames sent to the sap
// station and having wrong id. The connection oriented
// packets and TEST and XID frames cannot be wrong (????).
// The contiguous frames are too complicated to be
// intepreted here. We must always accept them.
//
if ((pFirstBuffer->Contiguous.uchOptions == LLC_CONTIGUOUS_DATA)
|| !((pFirstBuffer->NotContiguous.uchMsgType == LLC_UI_FRAME)
&& (pDlcPacket->PacketId != DLC_TEST_ID)
&& (pReadParms->uchEvent & EventMask))) {
NewEvents++;
}
pNextFrame = pFirstBuffer->Contiguous.pNextFrame;
Count.Receives++;
//
// The caller may optionally gather all received frames
// into a list.
//
if (ppCurFrame == NULL) {
/*
*******************************************************************************
if (AllEvents > 40)
{
if ((NewEvents % 5) == 0)
{
printf("%4x: %08X\n",
pFirstBuffer->Contiguous.usStationId, pFirstBuffer);
}
else
{
printf("%4x: %08X, ",
pFirstBuffer->Contiguous.usStationId, pFirstBuffer);
}
}
*******************************************************************************
*/
Status = BufferFree(pReadCcb->uchAdapterNumber,
pFirstBuffer,
&cLeft
);
// DBG_ASSERT(Status);
} else {
*ppCurFrame = pFirstBuffer;
ppCurFrame = &(pFirstBuffer->Contiguous.pNextFrame);
}
if (Status != STATUS_SUCCESS) {
printf("\nBufferFree= %xH (%u)\n", Status, NewEvents);
return Status;
}
}
//printf("R(%x:%u) ", CurrentSap, NewEvents);
//printf("R(%u) ", NewEvents);
break;
//
// ******************** TRANSMIT COMPLETION ********************
//
case LLC_EVENT_TRANSMIT_COMPLETION:
if (pReadParms->ulNotificationFlag != TEST_TRANSMIT_COMPLETION_FLAG) {
DlcDebugBreak();
}
// Can't do this, param table is static
//CurrentSap =
//pReadParms->Type.Event.pCcbCompletionList->u.pParameterTable->Transmit2.usStationId
//>> 8;
NewEvents = 0;
for (pCcb = pReadParms->Type.Event.pCcbCompletionList;
pCcb != NULL && pReadParms->Type.Event.usCcbCount != 0;
pCcb = pNextCcb) {
NewEvents++;
Count.XmitCompletion++;
// DBG_ASSERT(Status = pCcb->uchDlcStatus);
pNextCcb = pCcb->pNext;
if (pTransmitCcbPool != NULL) {
CcbPoolFree(pTransmitCcbPool, pCcb);
} else {
FreeCcb(pCcb);
}
}
//printf("T(%u) ", NewEvents);
break;
//
// ******************** COMMAND COMPLETION ********************
//
case LLC_EVENT_COMMAND_COMPLETION:
//putchar('C');
NewEvents = 0;
if (pReadParms->ulNotificationFlag != TEST_COMMAND_COMPLETION_FLAG) {
DlcDebugBreak();
}
if (TraceFlagSet)
printf("\nCompleted CCB: ");
for (pCcb = pReadParms->Type.Event.pCcbCompletionList;
pCcb != NULL && pReadParms->Type.Event.usCcbCount != 0;
pCcb = pNextCcb
)
{
if (TraceFlagSet)
printf("%u, ", pCcb->uchDlcCommand);
NewEvents++;
DBG_ASSERT(Status = pCcb->uchDlcStatus);
pNextCcb = pCcb->pNext;
if (pCcb->uchDlcCommand >= LLC_TRANSMIT_FRAMES &&
pCcb->uchDlcCommand <= LLC_TRANSMIT_TEST_CMD)
{
Count.XmitCompletion++;
if (pTransmitCcbPool != NULL)
{
CcbPoolFree(pTransmitCcbPool, pCcb);
}
else
{
FreeCcb(pCcb);
}
}
else
{
Count.CmdCompletion++;
FreeCcb(pCcb);
}
}
if (pReadParms->Type.Event.usReceivedFrameCount != 0)
{
FreeAllFrames(
pReadCcb->uchAdapterNumber,
pReadParms->Type.Event.pReceivedFrame,
&cLeft
);
}
break;
case LLC_EVENT_STATUS_CHANGE:
Count.Status++;
if (pReadParms->ulNotificationFlag != TEST_DLC_STATUS_FLAG) {
DlcDebugBreak();
}
PRINTF("Link (%u,%x):",
pReadCcb->uchAdapterNumber,
pReadParms->Type.Status.usStationId
);
DlcStatus = pReadParms->Type.Status.usDlcStatusCode;
if (DlcStatus & LLC_INDICATE_LINK_LOST) {
printf("Error: Link Lost: StationId: %04x, Status Code: %04x, RSap: %02x\n",
pReadParms->Type.Status.usStationId,
pReadParms->Type.Status.usDlcStatusCode,
pReadParms->Type.Status.uchRemoteSap
);
PRINTF("LLC_INDICATE_LINK_LOST, StationID: %X\n",
pReadParms->Type.Status.usStationId
);
//
// close the link station. If an error occurs from the close
// return that
//
pCcb = LlcCloseInit(pReadCcb->uchAdapterNumber,
0,
LLC_DLC_CLOSE_STATION,
pReadParms->Type.Status.usStationId
);
Status = AcsLan(pCcb, NULL);
if (Status != STATUS_SUCCESS || (Status = pCcb->uchDlcStatus) != STATUS_SUCCESS) {
return Status;
}
//
// else return arbitrary error code
//
return -1;
}
if (DlcStatus & LLC_INDICATE_DM_DISC_RECEIVED) {
PRINTF("LLC_INDICATE_DM_DISC_RECEIVED\n");
pCcb = LlcCloseInit(pReadCcb->uchAdapterNumber,
0,
LLC_DLC_CLOSE_STATION,
pReadParms->Type.Status.usStationId
);
Status = AcsLan(pCcb, NULL);
if (Status != STATUS_SUCCESS || (Status = pCcb->uchDlcStatus) != STATUS_SUCCESS) {
return Status;
}
}
if (DlcStatus & LLC_INDICATE_FRMR_RECEIVED) {
printf(" LLC_INDICATE_FRMR_RECEIVED\n");
return LLC_STATUS_LINK_PROTOCOL_ERROR;
}
if (DlcStatus & LLC_INDICATE_FRMR_SENT) {
printf(" LLC_INDICATE_FRMR_SENT\n");
return LLC_STATUS_LINK_PROTOCOL_ERROR;
}
if (DlcStatus & LLC_INDICATE_CONNECT_REQUEST) {
pCcb = LlcCloseInit(pReadCcb->uchAdapterNumber,
0,
LLC_DLC_CLOSE_STATION,
pReadParms->Type.Status.usStationId
);
Status = AcsLan(pCcb, NULL);
DBG_ASSERT(pCcb->uchDlcStatus);
PRINTF(" ERROR: LLC_INDICATE_CONNECT_REQUEST\n");
}
if (DlcStatus & LLC_INDICATE_RESET) {
PRINTF(" LLC_INDICATE_RESET\n");
}
if (DlcStatus & LLC_INDICATE_REMOTE_BUSY) {
//putchar('r');
PRINTF(" LLC_INDICATE_REMOTE_BUSY\n");
}
if (DlcStatus & LLC_INDICATE_REMOTE_READY) {
PRINTF(" LLC_INDICATE_REMOTE_READY\n");
}
if (DlcStatus & LLC_INDICATE_TI_TIMER_EXPIRED) {
PRINTF(" LLC_INDICATE_TI_TIMER_EXPIRED\n");
}
if (DlcStatus & LLC_INDICATE_DLC_COUNTER_OVERFLOW) {
PRINTF(" LLC_INDICATE_DLC_COUNTER_OVERFLOW\n");
ReportDlcStatistics(pReadCcb->uchAdapterNumber,
pReadParms->Type.Status.usStationId
);
}
if (DlcStatus & LLC_INDICATE_ACCESS_PRTY_LOWERED) {
PRINTF(" LLC_INDICATE_ACCESS_PRTY_LOWERED\n");
}
if (DlcStatus & LLC_INDICATE_LOCAL_STATION_BUSY) {
PRINTF(" LLC_INDICATE_LOCAL_STATION_BUSY\n");
//
// Let's hope there is now enough buffers to
// receive the data. Clear the out of buffer busy state.
//
DlcFlowControl(pReadCcb->uchAdapterNumber,
pReadParms->Type.Status.usStationId,
LLC_RESET_LOCAL_BUSY_BUFFER
);
LocalBusy = TRUE;
/*
{
PLLC_BUFFER pBuffer;
putchar('l');
BufferGet(pReadCcb->uchAdapterNumber, 0, 0, &pBuffer, &cLeft);
printf("(%u)", cLeft);
}
*/
}
break;
} // switch
if (pReadParms->uchEvent & EventMask) {
if (EventCount >= NewEvents) {
EventCount -= NewEvents;
} else {
EventCount = 0;
}
}
}
if (cLeft != -1) {
PRINTF("Buffers left: %u\n", cLeft);
}
return STATUS_SUCCESS;
}
//
// This table is used to translate the bits within a byte.
// The bits are in a reverse order in the token-ring frame header.
// We must swap the bits in a ethernet frame header, whent the header
// is copied to a user buffer.
//
UCHAR BitSwap[256] =
{
0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
};
//
// Copies and swaps the memory unconditionally
//
//VOID
//SwappingMemCpy(
// IN PUCHAR pDest,
// IN PUCHAR pSrc,
// IN UINT Len
// )
//
#define SwappingMemCpy(pDest, pSrc, Len) {\
UINT i; \
for (i = 0; i < Len; i++) \
((PUCHAR)pDest)[i] = BitSwap[((PUCHAR)pSrc)[i]]; \
}
UCHAR
TranslateLanHeader(
IN UINT AddressTranslationMode,
IN PUCHAR pSrcLanHeader,
OUT PUCHAR pDestLanHeader
)
/*++
Routine Description:
The primitive translates the given lan header and its type to
a real network header and patches the local node address to
the source address field. It also returns the length
of the lan header (== offset of llc header).
Arguments:
IN UINT AddressTranslationMode - the network format mapping case
IN PUCHAR pSrcLanHeader - the initial lan header
IN PUCHAR pNodeAddress - the current node address
OUT PUCHAR pDestLanHeader - storage for the new lan header
Return Value:
Length of the built network header.
--*/
{
UCHAR LlcOffset = 14;
UCHAR NodeAddressOffset = 6;
UCHAR SourceRoutingFlag = 0;
//
// LLC driver API supports both 802.3 (ethernet) and 802.5 (token-ring)
// address presentation formats. The 802.3 header may include the source
// routing information, when it is used on token-ring.
//
// Internally LLC supports 802.3, DIX and 802.5 networks.
// The transport level driver needs to support only one format. It is
// translated to the actual network header by LLC.
// Thus we have these six address mappings.
//
switch (AddressTranslationMode) {
case LLC_SEND_802_5_TO_802_5:
//
// TOKEN-RING 802.5 -> TOKEN-RING 802.5
//
NodeAddressOffset = 8;
memcpy(pDestLanHeader, pSrcLanHeader, 8);
SourceRoutingFlag = pSrcLanHeader[8] & (UCHAR)0x80;
if (SourceRoutingFlag) {
//
// Copy the source routing info
//
pDestLanHeader[8] |= 0x80;
LlcOffset += pSrcLanHeader[14] & 0x1f;
memcpy(&pDestLanHeader[14],
&pSrcLanHeader[14],
pSrcLanHeader[14] & 0x1f
);
}
break;
case LLC_SEND_802_5_TO_DIX:
//
// TOKEN-RING -> DIX-ETHERNET
//
//
// The ethernet type is a small endiand!!
//
pDestLanHeader[12] = 0x80;
pDestLanHeader[13] = 0xD5;
LlcOffset = 17;
case LLC_SEND_802_5_TO_802_3:
//
// TOKEN-RING 802.5 -> ETHERNET 802.3
//
SwappingMemCpy(pDestLanHeader, &pSrcLanHeader[2], 12);
break;
case LLC_SEND_DIX_TO_DIX:
LlcOffset = 12;
case LLC_SEND_802_3_TO_802_3:
//
// ETHERNET 802.3 -> ETHERNET 802.3
//
memcpy(pDestLanHeader, pSrcLanHeader, 12);
break;
case LLC_SEND_802_3_TO_DIX:
//
// The ethernet type is a small endiand!!
//
pDestLanHeader[12] = 0x80;
pDestLanHeader[13] = 0xD5;
LlcOffset = 17;
//
// ETHERNET 802.3 -> DIX-ETHERNET
//
memcpy(pDestLanHeader, pSrcLanHeader, 12);
break;
case LLC_SEND_802_3_TO_802_5:
//
// ETHERNET 802.3 -> TOKEN-RING 802.5
//
NodeAddressOffset = 8;
pDestLanHeader[0] = 0; // AC = no pritority
pDestLanHeader[1] = 0x40; // FS = Non-MAC
SwappingMemCpy(pDestLanHeader + 2, pSrcLanHeader, 12);
//
// Note: Ethernet source routing info indication flag is swapped!
//
if (pSrcLanHeader[6] & 0x01) {
SourceRoutingFlag = 0x80;
//
// Copy the source routing info, the source routing info
// must always be in token-ring bit order (reverse)
//
pDestLanHeader[8] |= 0x80;
LlcOffset += pSrcLanHeader[12] & 0x1f;
memcpy(&pDestLanHeader[14],
&pSrcLanHeader[12],
pSrcLanHeader[12] & 0x1f
);
}
break;
case LLC_SEND_UNMODIFIED:
return 0;
break;
}
pDestLanHeader[NodeAddressOffset] |= SourceRoutingFlag;
return LlcOffset;
}