mirror of https://github.com/lianthony/NT4.0
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
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;
|
|
}
|