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.
2320 lines
74 KiB
2320 lines
74 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pmsim.c
|
|
|
|
Abstract:
|
|
|
|
Attempts to simulate print monitor functionality. Run in 2 modes - receiver
|
|
and transmitter. Receiver acts like a printer and receives 'print jobs' -
|
|
I-Frame transmissions which it then bins. Transmitter acts like print monitor
|
|
- creates link stations and sends I-Frames to receiver. Receiver is single
|
|
threaded. Transmitter (currently) has 2 threads - send thread and read thread
|
|
|
|
Contents:
|
|
main
|
|
usage
|
|
start
|
|
control_c_handler
|
|
finish
|
|
receiver
|
|
transmitter
|
|
read_thread
|
|
check_read
|
|
handle_status_change
|
|
handle_receive_data
|
|
handle_transmit_complete
|
|
handle_command_complete
|
|
add_receiver
|
|
remove_receiver
|
|
delete_receiver
|
|
send_to_receivers
|
|
maybe_send_ui_frame
|
|
xtoi
|
|
xton
|
|
twiddle_bits
|
|
swap_bits
|
|
map_frame_type
|
|
update_progress_meter
|
|
check_keyboard
|
|
display_elapsed_time
|
|
generate_job_length
|
|
dwpow
|
|
atox
|
|
char_to_hex
|
|
check_quit
|
|
quit_pmsim
|
|
rip
|
|
display_statistics
|
|
|
|
Author:
|
|
|
|
Richard L Firth (rfirth) 29-Mar-1994
|
|
|
|
Revision History:
|
|
|
|
29-Mar-1994 rfirth
|
|
Created
|
|
|
|
--*/
|
|
|
|
#include "pmsimh.h"
|
|
#pragma hdrstop
|
|
|
|
#ifndef _CRTAPI1
|
|
#define _CRTAPI1
|
|
#endif
|
|
|
|
//
|
|
// macros
|
|
//
|
|
|
|
#define IS_ARG(c) (((c) == '-') || ((c) == '/'))
|
|
#define NRAND(n) ((DWORD)((n * rand())/RAND_MAX))
|
|
|
|
//
|
|
// prototypes
|
|
//
|
|
|
|
void _CRTAPI1 main(int, char**);
|
|
void usage(void);
|
|
void start(void);
|
|
void _CRTAPI1 control_c_handler(int);
|
|
void _CRTAPI1 finish(void);
|
|
void receiver(void);
|
|
void transmitter(void);
|
|
void read_thread(void);
|
|
int check_read(PLLC_CCB, DWORD);
|
|
void handle_status_change(PLLC_CCB);
|
|
void handle_receive_data(PLLC_CCB);
|
|
void handle_transmit_complete(PLLC_CCB);
|
|
void handle_command_complete(PLLC_CCB);
|
|
void add_receiver(LPBYTE, WORD, BYTE, BYTE);
|
|
void remove_receiver(LPBYTE, BYTE, BYTE);
|
|
void delete_receiver(PRECEIVER);
|
|
void send_to_receivers(void);
|
|
void maybe_send_ui_frame(void);
|
|
int xtoi(char*);
|
|
int xton(char);
|
|
void twiddle_bits(LPBYTE, DWORD);
|
|
unsigned char swap_bits(unsigned char);
|
|
char* map_frame_type(char);
|
|
void update_progress_meter(void);
|
|
void check_keyboard(void);
|
|
void display_elapsed_time(void);
|
|
DWORD generate_job_length(void);
|
|
DWORD dwpow(DWORD, DWORD);
|
|
DWORD atox(char*);
|
|
BYTE char_to_hex(char);
|
|
void check_quit(void);
|
|
void quit_pmsim(void);
|
|
void rip(void);
|
|
void display_statistics(void);
|
|
|
|
//
|
|
// data
|
|
//
|
|
|
|
BYTE MyNodeAddress[6];
|
|
BYTE Adapter = 0;
|
|
int ReceiveMode = 0;
|
|
int TransmitterMode = JOB_BASED_MODE;
|
|
int Verbose = 0;
|
|
int Progresso = 1;
|
|
int NumberOfSaps = 1;
|
|
BYTE FirstSap = PMSIM_SAP;
|
|
BYTE ServerSap = PMSIM_SAP;
|
|
WORD MaxFrameSize;
|
|
WORD TypeOfAdapter;
|
|
DWORD BufferHandle;
|
|
DWORD BufferPool;
|
|
int FoundTransmitter = 0;
|
|
int TransmitterAlive = 0;
|
|
int CheckForOtherTransmitters = 1;
|
|
LIST_ENTRY Receivers;
|
|
CRITICAL_SECTION ReceiverLock;
|
|
HANDLE TransmitterWorkItem;
|
|
DWORD StartTickCount;
|
|
DWORD LastTickCount;
|
|
int TicksToNextUiFrame;
|
|
WORD UStation;
|
|
BYTE USap;
|
|
int Debugging = 0;
|
|
int GracefulTermination = 1;
|
|
int Terminating = 0;
|
|
char Mode = '*'; // default adapter open mode is DEFAULT
|
|
int JobLength = 0;
|
|
int ISwapBitsForCash = 0;
|
|
int NoMemoryUsageReporting = 1;
|
|
int AppLevelFlowControl = 0;
|
|
int HighWaterMark = DEFAULT_HIGH_WATER_MARK;
|
|
int LowWaterMark = DEFAULT_LOW_WATER_MARK;
|
|
int OutstandingIFrames = 0;
|
|
DWORD QuitTime = 0;
|
|
BOOL AccessViolate = FALSE;
|
|
|
|
SYSTEMTIME TimeStarted;
|
|
FILETIME FTimeStarted;
|
|
LARGE_INTEGER ITimeStarted;
|
|
|
|
BYTE MaxIn = 0; // default to value defined in IBM LAN Tech Ref
|
|
BYTE MaxOut = 0; // " " " " " " " " "
|
|
|
|
BYTE uHeader[14] = {0x10, 0x40, PMSIM_GROUP_DESTINATION, 0, 0, 0, 0, 0, 0};
|
|
BYTE uBuffer[10] = {'B', 'E', 'A', 'C', 'O', 'N', 0, 0, 0, 0};
|
|
BYTE xHeader[14] = {0x10, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
BYTE xBuffer[26] = {'P', 'M', 'S', 'I', 'M', 0, 0, 0, 0, 0};
|
|
BYTE sBuffer[12] = {'S', 'T', 'A', 'T', 'U', 'S', 0, 0xef, 0, 0, 0, 0};
|
|
BYTE dBuffer[10] = {'P', 'M', 'D', 'E', 'A', 'T', 'H', 0, 0, 0};
|
|
BYTE tHeader[14] = {0x10, 0x40, PMSIM_RGROUP_DESTINATION, 0, 0, 0, 0, 0, 0};
|
|
|
|
#define HEADER_LENGTH 14
|
|
|
|
#define MODE_INDEX 7
|
|
#define SAP_INDEX 8
|
|
#define COUNT_INDEX 9
|
|
#define TICK_INDEX 8
|
|
#define NAME_INDEX 10
|
|
|
|
//
|
|
// stats
|
|
//
|
|
|
|
DWORD MinBuffersAvailable = 0;
|
|
DWORD MaxBuffersAvailable = 0;
|
|
DWORD DlcBuffersFreed = 0;
|
|
DWORD TotalReadsChecked = 0;
|
|
DWORD TotalReadEvents = 0;
|
|
DWORD CommandCompleteEvents = 0;
|
|
DWORD TransmitCompleteEvents = 0;
|
|
DWORD ReceiveDataEvents = 0;
|
|
DWORD StatusChangeEvents = 0;
|
|
DWORD DataFramesReceived = 0;
|
|
DWORD DlcBuffersReceived = 0;
|
|
DWORD TotalPacketBytesReceived = 0;
|
|
DWORD TotalDlcBytesReceived = 0;
|
|
DWORD MaxChainedReceives = 0;
|
|
DWORD TotalTransmits = 0;
|
|
DWORD TotalTransmitCompletions = 0;
|
|
DWORD OutstandingTransmits = 0;
|
|
DWORD TotalBytesTransmitted = 0;
|
|
DWORD TotalTxBytesCompleted = 0;
|
|
DWORD MaxChainedTransmits = 0;
|
|
DWORD LinkLostEvents = 0;
|
|
DWORD DiscEvents = 0;
|
|
DWORD FrmrReceivedEvents = 0;
|
|
DWORD FrmrSentEvents = 0;
|
|
DWORD SabmeResetEvents = 0;
|
|
DWORD SabmeOpenEvents = 0;
|
|
DWORD RemoteBusyEnteredEvents = 0;
|
|
DWORD RemoteBusyLeftEvents = 0;
|
|
DWORD TiExpiredEvents = 0;
|
|
DWORD DlcCounterOverflowEvents = 0;
|
|
DWORD AccessPriorityLoweredEvents = 0;
|
|
DWORD InvalidStatusChangeEvents = 0;
|
|
DWORD LocalBusyEvents = 0;
|
|
|
|
//
|
|
// functions
|
|
//
|
|
|
|
void _CRTAPI1 main(int argc, char** argv) {
|
|
|
|
srand(GetTickCount());
|
|
|
|
printf("\nPMSIM - Print Monitor Simulator - Version " VERSION_STRING " " __DATE__ " " __TIME__ "\n\n");
|
|
|
|
for (--argc, ++argv; argc; --argc, ++argv) {
|
|
if (IS_ARG(**argv)) {
|
|
switch (*++*argv) {
|
|
case 'a':
|
|
++*argv;
|
|
if (tolower(**argv) == 'v') {
|
|
AccessViolate = TRUE;
|
|
} else {
|
|
Adapter = (BYTE)atoi(*argv);
|
|
}
|
|
break;
|
|
|
|
case 'c':
|
|
TransmitterMode = CONTINUOUS_MODE;
|
|
break;
|
|
|
|
case 'd':
|
|
Debugging = 1;
|
|
break;
|
|
|
|
case 'f':
|
|
AppLevelFlowControl = 1;
|
|
if (*++*argv) {
|
|
HighWaterMark = atoi(*argv);
|
|
}
|
|
break;
|
|
|
|
case 'h':
|
|
case '?':
|
|
usage();
|
|
|
|
case 'j':
|
|
JobLength = strtoul(++*argv, NULL, 0);
|
|
break;
|
|
|
|
case 'k':
|
|
CheckForOtherTransmitters = 0;
|
|
break;
|
|
|
|
case 'm':
|
|
switch (tolower(*++*argv)) {
|
|
case 'i':
|
|
MaxIn = atoi(++*argv);
|
|
break;
|
|
|
|
case 'o':
|
|
MaxOut = atoi(++*argv);
|
|
break;
|
|
|
|
default:
|
|
printf("error: unrecognized /M flag: '%c'\n", **argv);
|
|
usage();
|
|
}
|
|
break;
|
|
|
|
case 'n':
|
|
NumberOfSaps = atoi(++*argv);
|
|
if (NumberOfSaps < 1 || NumberOfSaps > 127) {
|
|
printf("error: invalid value for # of saps (/n): %d\n", NumberOfSaps);
|
|
usage();
|
|
}
|
|
break;
|
|
|
|
case 'o':
|
|
break;
|
|
|
|
case 'p':
|
|
Progresso = 0;
|
|
break;
|
|
|
|
case 'q':
|
|
if (*(*argv + 1)) {
|
|
QuitTime = (DWORD)atoi(*argv + 1);
|
|
} else {
|
|
QuitTime = NRAND(1000); // 1000 sec == 16 min 40 sec
|
|
QuitTime += 120; // at least 2 minutes
|
|
}
|
|
QuitTime *= 1000; // seconds to milliseconds
|
|
break;
|
|
|
|
case 'r':
|
|
ReceiveMode = 1;
|
|
break;
|
|
|
|
case 's':
|
|
FirstSap = (BYTE)xtoi(++*argv);
|
|
if (FirstSap & 1) {
|
|
printf("error: SAP value must be even (/s): %#x\n", FirstSap);
|
|
usage();
|
|
}
|
|
break;
|
|
|
|
case 'S':
|
|
ServerSap = (BYTE)xtoi(++*argv);
|
|
if (ServerSap & 1) {
|
|
printf("error: SAP value must be even (/s): %#x\n", ServerSap);
|
|
usage();
|
|
}
|
|
break;
|
|
|
|
case 'u':
|
|
GracefulTermination = 0;
|
|
break;
|
|
|
|
case 'v':
|
|
Verbose = 1;
|
|
break;
|
|
|
|
default:
|
|
printf("error: unrecognized flag: '%c'\n", **argv);
|
|
usage();
|
|
}
|
|
} else {
|
|
printf("error: unrecognized argument: \"%s\"\n", *argv);
|
|
usage();
|
|
}
|
|
}
|
|
|
|
start();
|
|
|
|
if (QuitTime) {
|
|
printf("PMSIM will auto-quit in %d seconds\n", QuitTime/1000);
|
|
QuitTime += GetTickCount();
|
|
}
|
|
|
|
if (ReceiveMode) {
|
|
receiver();
|
|
} else {
|
|
InitializeListHead(&Receivers);
|
|
transmitter();
|
|
}
|
|
|
|
printf("\nPMSIM Done.\n");
|
|
|
|
exit(0);
|
|
}
|
|
|
|
void usage() {
|
|
printf("usage: pmsim [/a#] [/av] [/c] [/f[#]] [/j#] [/k] [/mi#] [/mo#] [/n#] [/o<mode>]\n"
|
|
" [/p] [/q#] [/r] [/s#] [/S#] [/u] [/v]\n\n"
|
|
"where: /a = use adapter # (default is 0)\n"
|
|
" /av = cause access violation if /d instead of DebugBreak()\n"
|
|
" /c = continuous mode (default is job-based mode)\n"
|
|
" /f = use app-level flow-control. Specify # or default = %d\n"
|
|
" /j = job length. Specifies fixed job size. Default is random\n"
|
|
" /k = don't check for other transmitters\n"
|
|
" /m = set MaxIn (mi) and MaxOut (mo) values\n"
|
|
" /n = number of SAPs to open (at receiver). # is decimal (1 to 127)\n"
|
|
" /o = adapter open mode. <mode> = D(ix), A(uto) or 8(02.3). Ethernet\n"
|
|
" /p = disable the progress meter\n"
|
|
" /q = quits this program after # seconds, random if no # specified\n"
|
|
" /r = receive mode - receives packets. (transmit mode is default)\n"
|
|
" /s = first receiver SAP to open. # is hexadecimal (0x02 to 0xfe)\n"
|
|
" /S = SAP to open at transmitter. # is hexadecimal (0x02 to 0xfe)\n"
|
|
" /u = ungraceful termination at control-c exit, or quit if /q specified\n"
|
|
" /v = verbose mode\n",
|
|
DEFAULT_HIGH_WATER_MARK
|
|
);
|
|
exit(1);
|
|
}
|
|
|
|
void start() {
|
|
|
|
StartTickCount = LastTickCount = GetTickCount();
|
|
TicksToNextUiFrame = rand();
|
|
|
|
GetLocalTime(&TimeStarted);
|
|
SystemTimeToFileTime(&TimeStarted, &FTimeStarted);
|
|
ITimeStarted.LowPart = FTimeStarted.dwLowDateTime;
|
|
ITimeStarted.HighPart = FTimeStarted.dwHighDateTime;
|
|
|
|
initialize_memory_package();
|
|
InitializeCriticalSection(&ReceiverLock);
|
|
TransmitterWorkItem = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
open_adapter(Adapter, Mode, &MaxFrameSize);
|
|
TypeOfAdapter = adapter_status(Adapter, MyNodeAddress);
|
|
if (TypeOfAdapter != ADAPTER_TYPE_ETHERNET
|
|
&& TypeOfAdapter != ADAPTER_TYPE_TOKEN_RING
|
|
&& TypeOfAdapter != ADAPTER_TYPE_UNKNOWN) {
|
|
printf("fatal: adapter type %s not supported\n",
|
|
(TypeOfAdapter == ADAPTER_TYPE_PC_NETWORK)
|
|
? "PC/Network"
|
|
: "Unknown"
|
|
);
|
|
exit(1);
|
|
}
|
|
if (TypeOfAdapter == ADAPTER_TYPE_ETHERNET || TypeOfAdapter == ADAPTER_TYPE_UNKNOWN) {
|
|
ISwapBitsForCash = 1;
|
|
}
|
|
create_buffer(Adapter, DLC_BUFFER_SIZE, (LPVOID*)&BufferHandle, (LPVOID*)&BufferPool);
|
|
|
|
MinBuffersAvailable = MaxBuffersAvailable = free_buffer(Adapter, get_buffer(Adapter));
|
|
|
|
signal(SIGINT, control_c_handler);
|
|
atexit(finish);
|
|
}
|
|
|
|
void _CRTAPI1 control_c_handler(int sig) {
|
|
|
|
int err;
|
|
|
|
printf("\nControl-C exit\n");
|
|
if (ReceiveMode) {
|
|
dBuffer[SAP_INDEX] = FirstSap;
|
|
dBuffer[COUNT_INDEX] = (BYTE)NumberOfSaps;
|
|
++OutstandingTransmits;
|
|
err = transmit_frame(Adapter,
|
|
LLC_TRANSMIT_UI_FRAME,
|
|
(WORD)FirstSap << 8,
|
|
ServerSap,
|
|
sizeof(uHeader),
|
|
uHeader,
|
|
sizeof(dBuffer),
|
|
dBuffer,
|
|
COMPLETE_BY_GENERIC_READ,
|
|
RETURN_ERROR_TO_CALLER
|
|
);
|
|
if (err) {
|
|
printf("control_c_handler: transmit_frame(death packet) returns %x\n", err);
|
|
} else {
|
|
++TotalTransmits;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// broadcast transmitter death to global SAP on RGROUP address!
|
|
//
|
|
|
|
++OutstandingTransmits;
|
|
err = transmit_frame(Adapter,
|
|
LLC_TRANSMIT_UI_FRAME,
|
|
(WORD)ServerSap << 8,
|
|
0xFF,
|
|
sizeof(tHeader),
|
|
tHeader,
|
|
sizeof(dBuffer),
|
|
dBuffer,
|
|
COMPLETE_BY_GENERIC_READ,
|
|
RETURN_ERROR_TO_CALLER
|
|
);
|
|
if (err) {
|
|
printf("quit_pmsim: transmit_frame(death packet) returns %x\n", err);
|
|
} else {
|
|
++TotalTransmits;
|
|
}
|
|
if (GracefulTermination) {
|
|
err = close_sap(Adapter,
|
|
ServerSap,
|
|
COMPLETE_BY_GENERIC_READ,
|
|
RETURN_ERROR_TO_CALLER
|
|
);
|
|
if (err) {
|
|
printf("control_c_handler: close_sap(%02x) returns %#.2x\n", ServerSap, err);
|
|
err = reset(Adapter, 0, COMPLETE_BY_GENERIC_READ, RETURN_ERROR_TO_CALLER);
|
|
if (err) {
|
|
printf("control_c_handler: reset(0) returns %#.2x\n", err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Terminating = 1;
|
|
|
|
/*
|
|
err = close_adapter(Adapter, COMPLETE_BY_GENERIC_READ, RETURN_ERROR_TO_CALLER);
|
|
if (err) {
|
|
printf("control_c_handler: error: close_adapter returns %x\n", err);
|
|
}
|
|
*/
|
|
|
|
signal(SIGINT, control_c_handler);
|
|
|
|
report_allocs();
|
|
|
|
if (!GracefulTermination) {
|
|
ExitProcess((DWORD)-1);
|
|
} else {
|
|
/*
|
|
printf("waiting for various completions/closes...\n");
|
|
Sleep(5000);
|
|
*/
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void _CRTAPI1 finish() {
|
|
Terminating = 1;
|
|
rip();
|
|
close_adapter(Adapter, COMPLETE_BY_EVENT, QUIT_ON_ERROR);
|
|
DeleteCriticalSection(&ReceiverLock);
|
|
}
|
|
|
|
void receiver() {
|
|
|
|
int i;
|
|
BYTE sap = FirstSap;
|
|
WORD stationId;
|
|
PLLC_CCB readCcb;
|
|
|
|
BOOL foundTx = FALSE;
|
|
|
|
printf("Receiver mode\n\n");
|
|
|
|
set_group_address(Adapter, PMSIM_RGROUP_ADDRESS);
|
|
|
|
USap = ServerSap;
|
|
UStation = FirstSap << 8;
|
|
|
|
if (Verbose) {
|
|
printf("receiver opening SAPs: ");
|
|
}
|
|
for (i = 0; i < NumberOfSaps; ++i) {
|
|
if (Verbose) {
|
|
printf("%02x ", sap);
|
|
}
|
|
open_sap(Adapter, sap, 1, &stationId, MaxFrameSize, MaxIn, MaxOut);
|
|
post_receive(Adapter,
|
|
stationId,
|
|
DATA_COMPLETE_FLAG,
|
|
RECEIVE_COMPLETE_FLAG,
|
|
LLC_RCV_CHAIN_FRAMES_ON_SAP
|
|
);
|
|
sap += 2;
|
|
}
|
|
if (Verbose) {
|
|
putchar('\n');
|
|
}
|
|
|
|
readCcb = post_read(Adapter, 0);
|
|
|
|
uBuffer[MODE_INDEX] = 'R';
|
|
uBuffer[SAP_INDEX] = FirstSap;
|
|
uBuffer[COUNT_INDEX] = (BYTE)NumberOfSaps;
|
|
|
|
while (1) {
|
|
|
|
int repost;
|
|
DWORD endTick = GetTickCount() + (10 * BEACON_COUNT * BEACON_WAIT);
|
|
|
|
FoundTransmitter = 0;
|
|
TransmitterAlive = 0;
|
|
printf("Searching for transmitter");
|
|
|
|
do {
|
|
|
|
int err;
|
|
|
|
++OutstandingTransmits;
|
|
err = transmit_frame(Adapter,
|
|
LLC_TRANSMIT_UI_FRAME,
|
|
(WORD)FirstSap << 8,
|
|
ServerSap,
|
|
sizeof(uHeader),
|
|
uHeader,
|
|
sizeof(uBuffer),
|
|
uBuffer,
|
|
COMPLETE_BY_EVENT,
|
|
QUIT_ON_ERROR
|
|
);
|
|
if (err) {
|
|
printf("receiver: error: transmit_frame(UI-Frame) returns %x\n", err);
|
|
} else {
|
|
++TotalTransmits;
|
|
}
|
|
repost = check_read(readCcb, BEACON_WAIT);
|
|
if (FoundTransmitter) {
|
|
putchar('\n');
|
|
break;
|
|
} else {
|
|
putchar('.');
|
|
if (repost) {
|
|
repost_read(readCcb, 0);
|
|
}
|
|
}
|
|
|
|
} while ( GetTickCount() < endTick );
|
|
|
|
putchar('\n');
|
|
if (!FoundTransmitter) {
|
|
printf("receiver: fatal: transmitter didn't respond\n");
|
|
exit(1);
|
|
}
|
|
FoundTransmitter = 0;
|
|
TransmitterAlive = 1;
|
|
while (TransmitterAlive) {
|
|
repost_read(readCcb, 0);
|
|
check_read(readCcb, INFINITE);
|
|
maybe_send_ui_frame();
|
|
update_progress_meter();
|
|
check_keyboard();
|
|
check_quit();
|
|
}
|
|
repost_read(readCcb, 0);
|
|
}
|
|
}
|
|
|
|
void transmitter() {
|
|
|
|
WORD txStationId;
|
|
HANDLE hThread;
|
|
DWORD threadId;
|
|
int i;
|
|
|
|
printf("Transmitter mode - maximum frame size = %d\n\n", MaxFrameSize);
|
|
|
|
if (NumberOfSaps > 1) {
|
|
printf("warning: transmitter opening single SAP %#.2x\n", ServerSap);
|
|
}
|
|
|
|
set_group_address(Adapter, PMSIM_GROUP_ADDRESS);
|
|
open_sap(Adapter, ServerSap, 254, &txStationId, MaxFrameSize, MaxIn, MaxOut);
|
|
if (Verbose) {
|
|
printf("transmitter: opened SAP %02x\n", txStationId >> 8);
|
|
}
|
|
|
|
UStation = (WORD)ServerSap << 8;
|
|
|
|
post_receive(Adapter,
|
|
(WORD)ServerSap << 8,
|
|
DATA_COMPLETE_FLAG,
|
|
RECEIVE_COMPLETE_FLAG,
|
|
LLC_RCV_CHAIN_FRAMES_ON_SAP
|
|
);
|
|
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)read_thread, NULL, 0, &threadId);
|
|
if (!hThread) {
|
|
printf("fatal: transmitter: couldn't create read_thread\n");
|
|
exit(1);
|
|
}
|
|
if (CheckForOtherTransmitters) {
|
|
uBuffer[MODE_INDEX] = 'T';
|
|
if (Verbose) {
|
|
printf("looking for other transmitters");
|
|
}
|
|
for (i = 0; i < BEACON_COUNT; ++i) {
|
|
|
|
int err;
|
|
|
|
++OutstandingTransmits;
|
|
err = transmit_frame(Adapter,
|
|
LLC_TRANSMIT_UI_FRAME,
|
|
(WORD)ServerSap << 8,
|
|
ServerSap,
|
|
sizeof(uHeader),
|
|
uHeader,
|
|
sizeof(uBuffer),
|
|
uBuffer,
|
|
COMPLETE_BY_GENERIC_READ,
|
|
QUIT_ON_ERROR
|
|
);
|
|
if (err) {
|
|
printf("transmitter: error: transmit_frame(UI-Frame) returns %x\n", err);
|
|
} else {
|
|
++TotalTransmits;
|
|
}
|
|
if (!FoundTransmitter) {
|
|
if (Verbose) {
|
|
putchar('.');
|
|
}
|
|
Sleep(BEACON_WAIT);
|
|
}
|
|
}
|
|
if (Verbose) {
|
|
putchar('\n');
|
|
}
|
|
if (FoundTransmitter) {
|
|
printf("transmitter: found station already acting as PMSIM transmitter. Quitting\n");
|
|
exit(0);
|
|
}
|
|
}
|
|
while (1) {
|
|
printf("transmitter: waiting for something to do...\n");
|
|
WaitForSingleObject(TransmitterWorkItem, INFINITE);
|
|
ResetEvent(TransmitterWorkItem);
|
|
send_to_receivers();
|
|
update_progress_meter();
|
|
if (Terminating) {
|
|
ExitThread(1);
|
|
}
|
|
check_keyboard();
|
|
check_quit();
|
|
}
|
|
}
|
|
|
|
void read_thread() {
|
|
|
|
PLLC_CCB pccb;
|
|
DWORD wait_index;
|
|
|
|
pccb = post_read(Adapter, 0);
|
|
while (1) {
|
|
wait_index = WaitForSingleObject(pccb->hCompletionEvent, INFINITE);
|
|
if (wait_index != WAIT_OBJECT_0) {
|
|
printf("fatal: read_thread: WaitForSingleObject returns %d\n",
|
|
GetLastError());
|
|
exit(1);
|
|
}
|
|
check_read(pccb, INFINITE);
|
|
repost_read(pccb, 0);
|
|
if (Terminating) {
|
|
ExitThread(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
int check_read(PLLC_CCB pccb, DWORD waitTime) {
|
|
if (WaitForSingleObject(pccb->hCompletionEvent, waitTime) == WAIT_OBJECT_0) {
|
|
|
|
PLLC_READ_PARMS parms = (PLLC_READ_PARMS)pccb->u.pParameterTable;
|
|
BYTE comb;
|
|
BYTE event;
|
|
|
|
if (Verbose) {
|
|
printf("check_read: Cmplt=%#.2x Station=%#.4x Event=%#.2x\n",
|
|
pccb->uchDlcStatus,
|
|
((PLLC_READ_PARMS)pccb->u.pParameterTable)->usStationId,
|
|
((PLLC_READ_PARMS)pccb->u.pParameterTable)->uchEvent
|
|
);
|
|
}
|
|
if (pccb->uchDlcStatus != LLC_STATUS_SUCCESS) {
|
|
printf("fatal: check_read: READ status %#.2x\n", pccb->uchDlcStatus);
|
|
puts(MapCcbRetcode(pccb->uchDlcStatus));
|
|
exit(1);
|
|
}
|
|
|
|
++TotalReadsChecked;
|
|
|
|
event = parms->uchEvent;
|
|
for (comb = 0x80; comb; comb >>= 1) {
|
|
if (event & comb) {
|
|
++TotalReadEvents;
|
|
}
|
|
switch (event & comb) {
|
|
case 0x80:
|
|
if (Verbose) {
|
|
printf("check_read: event = RESERVED - shouldn't happen??!!\n");
|
|
}
|
|
break;
|
|
|
|
case 0x40:
|
|
if (Verbose) {
|
|
printf("check_read: event = SYSTEM ACTION (non-critical)?\n");
|
|
}
|
|
break;
|
|
|
|
case 0x20:
|
|
if (Verbose) {
|
|
printf("check_read: event = NETWORK STATUS (non-critical)?\n");
|
|
}
|
|
break;
|
|
|
|
case 0x10:
|
|
if (Verbose) {
|
|
printf("check_read: event = CRITICAL EXCEPTION?\n");
|
|
}
|
|
break;
|
|
|
|
case 0x08:
|
|
if (Verbose) {
|
|
printf("check_read: event = DLC STATUS CHANGE\n");
|
|
}
|
|
handle_status_change(pccb);
|
|
break;
|
|
|
|
case 0x04:
|
|
if (Verbose) {
|
|
printf("check_read: event = RECEIVED DATA\n");
|
|
}
|
|
handle_receive_data(pccb);
|
|
break;
|
|
|
|
case 0x02:
|
|
if (Verbose) {
|
|
printf("check_read: event = TRANSMIT COMPLETION\n");
|
|
}
|
|
handle_transmit_complete(pccb);
|
|
break;
|
|
|
|
case 0x01:
|
|
if (Verbose) {
|
|
printf("check_read: event = COMMAND COMPLETION\n");
|
|
}
|
|
handle_command_complete(pccb);
|
|
break;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void handle_status_change(PLLC_CCB pccb) {
|
|
|
|
PLLC_READ_PARMS parms = (PLLC_READ_PARMS)pccb->u.pParameterTable;
|
|
USHORT status = parms->Type.Status.usDlcStatusCode;
|
|
USHORT comb;
|
|
BOOL lost_it = FALSE;
|
|
int err;
|
|
|
|
++StatusChangeEvents;
|
|
|
|
for (comb = 0x8000; comb; comb >>= 1) {
|
|
switch (status & comb) {
|
|
case 0x8000:
|
|
if (Verbose) {
|
|
printf("LINK LOST\n");
|
|
}
|
|
lost_it = TRUE;
|
|
++LinkLostEvents;
|
|
break;
|
|
|
|
case 0x4000:
|
|
if (Verbose) {
|
|
printf("DM/DISC received or DISC acked\n");
|
|
}
|
|
lost_it = TRUE;
|
|
++DiscEvents;
|
|
break;
|
|
|
|
case 0x2000:
|
|
if (Verbose) {
|
|
printf("FRMR received\n");
|
|
}
|
|
lost_it = TRUE;
|
|
++FrmrReceivedEvents;
|
|
break;
|
|
|
|
case 0x1000:
|
|
if (Verbose) {
|
|
printf("FRMR sent\n");
|
|
}
|
|
++FrmrSentEvents;
|
|
break;
|
|
|
|
case 0x0800:
|
|
if (Verbose) {
|
|
printf("SABME received on open LINK station\n");
|
|
}
|
|
++SabmeResetEvents;
|
|
break;
|
|
|
|
case 0x0400:
|
|
if (Verbose) {
|
|
|
|
BYTE remoteNode[6];
|
|
|
|
memcpy(remoteNode, parms->Type.Status.uchRemoteNodeAddress, 6);
|
|
twiddle_bits(remoteNode, 6);
|
|
printf("SABME received - new link %04x. RemoteNode = %02x-%02x-%02x-%02x-%02x-%02x\n",
|
|
parms->Type.Status.usStationId,
|
|
remoteNode[0] & 0xff,
|
|
remoteNode[1] & 0xff,
|
|
remoteNode[2] & 0xff,
|
|
remoteNode[3] & 0xff,
|
|
remoteNode[4] & 0xff,
|
|
remoteNode[5] & 0xff
|
|
);
|
|
}
|
|
err = connect_station(Adapter,
|
|
parms->Type.Status.usStationId,
|
|
RETURN_ERROR_TO_CALLER
|
|
);
|
|
if (err) {
|
|
printf("handle_status_change: error: connect_station returns %#.2x\n", err);
|
|
}
|
|
++SabmeOpenEvents;
|
|
break;
|
|
|
|
case 0x0200:
|
|
if (Verbose) {
|
|
printf("REMOTE BUSY\n");
|
|
}
|
|
++RemoteBusyEnteredEvents;
|
|
break;
|
|
|
|
case 0x0100:
|
|
if (Verbose) {
|
|
printf("REMOTE BUSY CLEARED\n");
|
|
}
|
|
++RemoteBusyLeftEvents;
|
|
break;
|
|
|
|
case 0x0080:
|
|
if (Verbose) {
|
|
printf("Ti EXPIRED\n");
|
|
}
|
|
++TiExpiredEvents;
|
|
break;
|
|
|
|
case 0x0040:
|
|
if (Verbose) {
|
|
printf("DLC counter overflow\n");
|
|
}
|
|
++DlcCounterOverflowEvents;
|
|
break;
|
|
|
|
case 0x0020:
|
|
if (Verbose) {
|
|
printf("Access priority lowered (on ethernet????!)\n");
|
|
}
|
|
++AccessPriorityLoweredEvents;
|
|
break;
|
|
|
|
case 0x0010:
|
|
case 0x0008:
|
|
case 0x0004:
|
|
case 0x0002:
|
|
if (Verbose) {
|
|
printf(CONSOLE_ALERT "This status code (%04x) should not occur!\n", status & comb);
|
|
}
|
|
++InvalidStatusChangeEvents;
|
|
break;
|
|
|
|
case 0x0001:
|
|
if (Verbose) {
|
|
printf("LOCAL BUSY\n");
|
|
}
|
|
++LocalBusyEvents;
|
|
flow_control(Adapter,
|
|
parms->Type.Status.usStationId,
|
|
RETURN_ERROR_TO_CALLER
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
if (lost_it) {
|
|
if (Verbose) {
|
|
printf("lost it - closing station %04x\n", parms->Type.Status.usStationId);
|
|
}
|
|
err = close_station(Adapter,
|
|
parms->Type.Status.usStationId,
|
|
COMPLETE_BY_GENERIC_READ,
|
|
RETURN_ERROR_TO_CALLER
|
|
);
|
|
if (err) {
|
|
printf("handle_status_change: error: close_station(%04x) returns %#.2x\n",
|
|
parms->Type.Status.usStationId,
|
|
err
|
|
);
|
|
// if (Debugging) {
|
|
// DebugBreak();
|
|
// }
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void handle_receive_data(PLLC_CCB pccb) {
|
|
|
|
PLLC_READ_PARMS parms = (PLLC_READ_PARMS)pccb->u.pParameterTable;
|
|
int i;
|
|
PLLC_BUFFER frame;
|
|
PLLC_BUFFER nextFrame;
|
|
LPBYTE data;
|
|
BYTE sender[6];
|
|
int err;
|
|
LPBYTE echo_packet;
|
|
int frame_count = 0;
|
|
|
|
++ReceiveDataEvents;
|
|
|
|
frame = parms->Type.Event.pReceivedFrame;
|
|
i = parms->Type.Event.usReceivedFrameCount;
|
|
|
|
if (i > MaxChainedReceives) {
|
|
MaxChainedReceives = i;
|
|
}
|
|
|
|
if (!frame || !i) {
|
|
printf("handle_receive_data: error: count=%d frame=%#x\n", i, frame);
|
|
return;
|
|
} else if (Verbose) {
|
|
printf("handle_receive_data: %d frames received, 1st=%x\n", i, frame);
|
|
}
|
|
memcpy(sender, &frame->NotContiguous.auchLanHeader[8], 6);
|
|
twiddle_bits(sender, 6);
|
|
while (i--) {
|
|
|
|
PLLC_BUFFER pbuf;
|
|
|
|
if (!frame) {
|
|
printf("handle_receive_data: error: %d frames indicated, only received %d\n",
|
|
i, frame_count);
|
|
}
|
|
if (Verbose) {
|
|
printf("handle_receive_data: received frame type %d (%s) StationId %04x\n",
|
|
frame->NotContiguous.uchMsgType,
|
|
map_frame_type(frame->NotContiguous.uchMsgType),
|
|
frame->NotContiguous.usStationId
|
|
);
|
|
}
|
|
|
|
++DataFramesReceived;
|
|
++DlcBuffersReceived;
|
|
for (pbuf = frame->pNext; pbuf; pbuf = pbuf->pNext) {
|
|
++DlcBuffersReceived;
|
|
}
|
|
TotalDlcBytesReceived += frame->NotContiguous.cbFrame;
|
|
|
|
data = (LPBYTE)frame + sizeof(LLC_NOT_CONTIGUOUS_BUFFER);
|
|
switch (frame->NotContiguous.uchMsgType) {
|
|
case LLC_I_FRAME:
|
|
if (Verbose) {
|
|
printf("I-Frame: Type=%#x\n", ((PJOB)data)->type);
|
|
}
|
|
if (((PJOB)data)->type == JOB_TYPE_OUTBOUND) {
|
|
|
|
int datalen = ((PJOB)data)->packet_length + sizeof(JOB);
|
|
|
|
TotalPacketBytesReceived += datalen;
|
|
|
|
if (AppLevelFlowControl && (OutstandingIFrames == HighWaterMark)) {
|
|
if (Verbose) {
|
|
printf("handle_receive_data: Hit high-water mark (%d)\n",
|
|
HighWaterMark
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (echo_packet = (LPBYTE)ID_MALLOC(datalen, ID_ECHO_PACKET)) {
|
|
memcpy(echo_packet, data, sizeof(JOB));
|
|
((PJOB)echo_packet)->type = JOB_TYPE_ECHO;
|
|
memset(((PJOB)echo_packet) + 1, 'Z', datalen - sizeof(JOB));
|
|
++OutstandingTransmits;
|
|
err = transmit_frame(Adapter,
|
|
LLC_TRANSMIT_I_FRAME,
|
|
frame->NotContiguous.usStationId,
|
|
frame->NotContiguous.auchDlcHeader[1],
|
|
0,
|
|
NULL,
|
|
datalen,
|
|
echo_packet,
|
|
COMPLETE_BY_GENERIC_READ,
|
|
RETURN_ERROR_TO_CALLER
|
|
);
|
|
if (err) {
|
|
if (!Verbose && err == LLC_STATUS_INVALID_STATION_ID) {
|
|
err = 0;
|
|
}
|
|
if (err) {
|
|
printf("handle_receive_data: error: transmit_frame(I-Frame) returns %#x\n", err);
|
|
}
|
|
FREE(echo_packet);
|
|
} else if (AppLevelFlowControl) {
|
|
++OutstandingIFrames;
|
|
++TotalTransmits;
|
|
}
|
|
}
|
|
} else if (Verbose) {
|
|
if (((PJOB)data)->type == JOB_TYPE_ECHO) {
|
|
printf("handle_receive_data: I-Frame is ECHO: not responding\n");
|
|
} else {
|
|
printf("handle_receive_data: Unrecognized I-Frame: not responding\n");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LLC_UI_FRAME:
|
|
if (frame->NotContiguous.cbBuffer >= 10) {
|
|
if (!strcmp(data, "BEACON")) {
|
|
if (data[MODE_INDEX] == 'T') {
|
|
FoundTransmitter = memcmp(&frame->NotContiguous.auchLanHeader[8],
|
|
MyNodeAddress,
|
|
6
|
|
);
|
|
} else if (data[MODE_INDEX] == 'R') {
|
|
|
|
DWORD namelen = 16;
|
|
|
|
if (Verbose) {
|
|
printf("handle_receive_data: receiver at %02x-%02x-%02x-%02x-%02x-%02x FirstSap=%02x\n",
|
|
sender[0] & 0xff,
|
|
sender[1] & 0xff,
|
|
sender[2] & 0xff,
|
|
sender[3] & 0xff,
|
|
sender[4] & 0xff,
|
|
sender[5] & 0xff,
|
|
data[SAP_INDEX]
|
|
);
|
|
}
|
|
memcpy(&xHeader[2],
|
|
&frame->NotContiguous.auchLanHeader[8],
|
|
6
|
|
);
|
|
USap = data[SAP_INDEX];
|
|
xBuffer[MODE_INDEX] = 'T';
|
|
GetComputerName(&xBuffer[NAME_INDEX], &namelen);
|
|
++OutstandingTransmits;
|
|
err = transmit_frame(Adapter,
|
|
LLC_TRANSMIT_XID_CMD,
|
|
frame->NotContiguous.usStationId,
|
|
frame->NotContiguous.auchDlcHeader[1],
|
|
sizeof(xHeader),
|
|
xHeader,
|
|
sizeof(xBuffer),
|
|
xBuffer,
|
|
COMPLETE_BY_GENERIC_READ,
|
|
QUIT_ON_ERROR
|
|
);
|
|
if (err) {
|
|
printf("handle_receive_data: transmit_frame(XID) returns %x\n", err);
|
|
} else {
|
|
++TotalTransmits;
|
|
}
|
|
} else {
|
|
printf("handle_receive_data: error: unrecognized BEACON frame: '%c'\n"
|
|
"\tsender is %02x-%02x-%02x-%02x-%02x-%02x\n",
|
|
data[MODE_INDEX],
|
|
sender[0] & 0xff,
|
|
sender[1] & 0xff,
|
|
sender[2] & 0xff,
|
|
sender[3] & 0xff,
|
|
sender[4] & 0xff,
|
|
sender[5] & 0xff
|
|
);
|
|
}
|
|
} else if (!strcmp(data, "STATUS")) {
|
|
if (Verbose) {
|
|
printf("handle_receive_data: Status UI-Frame (ticks=%d)\n",
|
|
*(LPDWORD)&data[TICK_INDEX]);
|
|
}
|
|
} else if (!strcmp(data, "PMDEATH")) {
|
|
//if (Verbose) {
|
|
printf("\r\nhandle_receive_data: PmDeath UI-Frame from %02x-%02x-%02x-%02x-%02x-%02x StationId=%04x\n",
|
|
sender[0] & 0xff,
|
|
sender[1] & 0xff,
|
|
sender[2] & 0xff,
|
|
sender[3] & 0xff,
|
|
sender[4] & 0xff,
|
|
sender[5] & 0xff,
|
|
frame->NotContiguous.usStationId
|
|
);
|
|
//}
|
|
if (ReceiveMode) {
|
|
TransmitterAlive = 0;
|
|
} else {
|
|
remove_receiver(sender,
|
|
data[SAP_INDEX],
|
|
data[COUNT_INDEX]
|
|
);
|
|
}
|
|
} else {
|
|
printf("handle_receive_data: unexpected UI-Frame (not BEACON or STATUS)\n");
|
|
dump_frame(frame);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LLC_XID_COMMAND_POLL:
|
|
if (!ReceiveMode) {
|
|
printf("handle_receive_data: transmitter got XID Cmd-Poll?\n");
|
|
} else if (frame->NotContiguous.cbBuffer >= 10) {
|
|
if (!strcmp(data, "PMSIM")) {
|
|
if (Verbose) {
|
|
printf("handle_receive_data: XID Cmd-Poll received from %02x-%02x-%02x-%02x-%02x-%02x\n",
|
|
sender[0] & 0xff,
|
|
sender[1] & 0xff,
|
|
sender[2] & 0xff,
|
|
sender[3] & 0xff,
|
|
sender[4] & 0xff,
|
|
sender[5] & 0xff
|
|
);
|
|
}
|
|
if (data[MODE_INDEX] != 'T') {
|
|
printf("handle_receive_data: error: XID Cmd-Poll not from transmitter ('%c')\n",
|
|
data[MODE_INDEX]
|
|
);
|
|
} else {
|
|
|
|
DWORD namelen = 16;
|
|
|
|
memcpy(&xHeader[2],
|
|
&frame->NotContiguous.auchLanHeader[8],
|
|
6
|
|
);
|
|
xBuffer[MODE_INDEX] = 'R';
|
|
xBuffer[SAP_INDEX] = FirstSap;
|
|
xBuffer[COUNT_INDEX] = (BYTE)NumberOfSaps;
|
|
GetComputerName(&xBuffer[NAME_INDEX], &namelen);
|
|
++OutstandingTransmits;
|
|
err = transmit_frame(Adapter,
|
|
LLC_TRANSMIT_XID_RESP_FINAL,
|
|
frame->NotContiguous.usStationId,
|
|
frame->NotContiguous.auchDlcHeader[1],
|
|
sizeof(xHeader),
|
|
xHeader,
|
|
sizeof(xBuffer),
|
|
xBuffer,
|
|
COMPLETE_BY_GENERIC_READ,
|
|
QUIT_ON_ERROR
|
|
);
|
|
if (err) {
|
|
printf("handle_receive_data: error: transmit_frame(XID Rsp) returns %x\n", err);
|
|
} else {
|
|
++TotalTransmits;
|
|
}
|
|
|
|
FoundTransmitter = 1;
|
|
|
|
printf("\nFound Transmitter \"%s\" at %02x-%02x-%02x-%02x-%02x-%02x\n",
|
|
&data[NAME_INDEX],
|
|
sender[0] & 0xff,
|
|
sender[1] & 0xff,
|
|
sender[2] & 0xff,
|
|
sender[3] & 0xff,
|
|
sender[4] & 0xff,
|
|
sender[5] & 0xff
|
|
);
|
|
}
|
|
} else {
|
|
printf("handle_receive_data: unexpected XID Cmd-Poll from %02x-%02x-%02x-%02x-%02x-%02x\n",
|
|
sender[0] & 0xff,
|
|
sender[1] & 0xff,
|
|
sender[2] & 0xff,
|
|
sender[3] & 0xff,
|
|
sender[4] & 0xff,
|
|
sender[5] & 0xff
|
|
);
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LLC_XID_RESPONSE_FINAL:
|
|
if (ReceiveMode) {
|
|
printf("handle_receive_data: receiver got XID Resp-Final?\n"
|
|
"\tsender is %02x-%02x-%02x-%02x-%02x-%02x\n",
|
|
sender[0] & 0xff,
|
|
sender[1] & 0xff,
|
|
sender[2] & 0xff,
|
|
sender[3] & 0xff,
|
|
sender[4] & 0xff,
|
|
sender[5] & 0xff
|
|
);
|
|
} else if (frame->NotContiguous.cbBuffer >= 10) {
|
|
if (!strcmp(data, "PMSIM")) {
|
|
if (Verbose) {
|
|
printf("handle_receive_data: XID Resp-Final received from %02x-%02x-%02x-%02x-%02x-%02x\n",
|
|
sender[0] & 0xff,
|
|
sender[1] & 0xff,
|
|
sender[2] & 0xff,
|
|
sender[3] & 0xff,
|
|
sender[4] & 0xff,
|
|
sender[5] & 0xff
|
|
);
|
|
}
|
|
if (data[MODE_INDEX] != 'R') {
|
|
printf("handle_receive_data: error: XID Cmd-Poll not from transmitter ('%c')\n",
|
|
data[MODE_INDEX]
|
|
);
|
|
} else {
|
|
if (Verbose) {
|
|
printf("handle_receive_data: %d SAPs at Station %02x-%02x-%02x-%02x-%02x-%02x. First=%02x\n",
|
|
data[COUNT_INDEX],
|
|
sender[0] & 0xff,
|
|
sender[1] & 0xff,
|
|
sender[2] & 0xff,
|
|
sender[3] & 0xff,
|
|
sender[4] & 0xff,
|
|
sender[5] & 0xff,
|
|
data[SAP_INDEX]
|
|
);
|
|
}
|
|
add_receiver(frame->NotContiguous.auchLanHeader,
|
|
frame->NotContiguous.cbLanHeader,
|
|
data[SAP_INDEX],
|
|
data[COUNT_INDEX]
|
|
);
|
|
|
|
printf("\nFound Receiver \"%s\" at %02x-%02x-%02x-%02x-%02x-%02x: %d SAPs, first = %#.2x\n",
|
|
&data[NAME_INDEX],
|
|
sender[0] & 0xff,
|
|
sender[1] & 0xff,
|
|
sender[2] & 0xff,
|
|
sender[3] & 0xff,
|
|
sender[4] & 0xff,
|
|
sender[5] & 0xff,
|
|
data[COUNT_INDEX],
|
|
data[SAP_INDEX] & 0xff
|
|
);
|
|
}
|
|
} else {
|
|
printf("handle_receive_data: unexpected XID Resp-Final from %02x-%02x-%02x-%02x-%02x-%02x\n",
|
|
sender[0] & 0xff,
|
|
sender[1] & 0xff,
|
|
sender[2] & 0xff,
|
|
sender[3] & 0xff,
|
|
sender[4] & 0xff,
|
|
sender[5] & 0xff
|
|
);
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
printf("error: not expecting this frame type: %d (%s)!\n",
|
|
frame->NotContiguous.uchMsgType,
|
|
map_frame_type(frame->NotContiguous.uchMsgType)
|
|
);
|
|
}
|
|
nextFrame = frame->NotContiguous.pNextFrame;
|
|
frame->NotContiguous.pNextFrame = NULL;
|
|
free_buffer(Adapter, frame);
|
|
frame = nextFrame;
|
|
++frame_count;
|
|
}
|
|
}
|
|
|
|
void handle_transmit_complete(PLLC_CCB readCcb) {
|
|
|
|
PLLC_READ_PARMS parms = (PLLC_READ_PARMS)readCcb->u.pParameterTable;
|
|
int i = parms->Type.Event.usCcbCount;
|
|
PLLC_CCB pccb = parms->Type.Event.pCcbCompletionList;
|
|
PLLC_CCB nextCcb;
|
|
|
|
++TransmitCompleteEvents;
|
|
|
|
if (!i || !pccb) {
|
|
printf(CONSOLE_ALERT "handle_transmit_complete: error: count=%d CCB list=%x\n", i, pccb);
|
|
if (Debugging) {
|
|
if (AccessViolate) {
|
|
*(LPDWORD)0 = 0;
|
|
} else {
|
|
DebugBreak();
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
if (Verbose) {
|
|
printf("handle_transmit_complete: %d transmits completed\n", i);
|
|
}
|
|
while (i--) {
|
|
if (!pccb) {
|
|
printf(CONSOLE_ALERT "handle_transmit_complete: DLC BUG: NULL ccb, count = %d\n", i);
|
|
if (Debugging) {
|
|
if (AccessViolate) {
|
|
*(LPDWORD)0 = 0;
|
|
} else {
|
|
DebugBreak();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (Verbose) {
|
|
printf("handle_transmit_complete: Cmd=%#.2x Retcode=%#.2x\n",
|
|
pccb->uchDlcCommand, pccb->uchDlcStatus);
|
|
}
|
|
nextCcb = pccb->pNext;
|
|
pccb->pNext = NULL;
|
|
if (pccb->uchDlcCommand == LLC_TRANSMIT_I_FRAME) {
|
|
FREE(((PLLC_TRANSMIT_PARMS)pccb->u.pParameterTable)->pBuffer2);
|
|
if (AppLevelFlowControl) {
|
|
--OutstandingIFrames;
|
|
}
|
|
}
|
|
FREE(pccb->u.pParameterTable);
|
|
FREE(pccb);
|
|
pccb = nextCcb;
|
|
++TotalTransmitCompletions;
|
|
--OutstandingTransmits;
|
|
}
|
|
}
|
|
|
|
void handle_command_complete(PLLC_CCB readCcb) {
|
|
|
|
PLLC_READ_PARMS parms = (PLLC_READ_PARMS)readCcb->u.pParameterTable;
|
|
int i = parms->Type.Event.usCcbCount;
|
|
PLLC_CCB pccb = parms->Type.Event.pCcbCompletionList;
|
|
PLLC_CCB nextCcb;
|
|
|
|
++CommandCompleteEvents;
|
|
|
|
if (!i || !pccb) {
|
|
printf(CONSOLE_ALERT "handle_command_complete: error: count=%d CCB list=%x\n", i, pccb);
|
|
if (Debugging) {
|
|
if (AccessViolate) {
|
|
*(LPDWORD)0 = 0;
|
|
} else {
|
|
DebugBreak();
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
if (Verbose) {
|
|
printf("handle_command_complete: %d CCBs completed\n", i);
|
|
}
|
|
while (i--) {
|
|
if (!pccb) {
|
|
printf(CONSOLE_ALERT "handle_command_complete: DLC BUG: NULL ccb, count = %d\n", i);
|
|
if (Debugging) {
|
|
if (AccessViolate) {
|
|
*(LPDWORD)0 = 0;
|
|
} else {
|
|
DebugBreak();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (Verbose) {
|
|
printf("handle_command_complete: Cmd=%#.2x Retcode=%#.2x\n",
|
|
pccb->uchDlcCommand, pccb->uchDlcStatus);
|
|
}
|
|
if (pccb->uchDlcCommand == LLC_RECEIVE && !ReceiveMode) {
|
|
printf("Transmitter: receive completed w/ %#.2x. Reposting\n",
|
|
pccb->uchDlcStatus
|
|
);
|
|
post_receive(Adapter,
|
|
(WORD)ServerSap << 8,
|
|
DATA_COMPLETE_FLAG,
|
|
RECEIVE_COMPLETE_FLAG,
|
|
LLC_RCV_CHAIN_FRAMES_ON_SAP
|
|
);
|
|
}
|
|
|
|
nextCcb = pccb->pNext;
|
|
pccb->pNext = NULL;
|
|
if (pccb->ulCompletionFlag == OPEN_SAP_FLAG
|
|
|| pccb->ulCompletionFlag == OPEN_STATION_FLAG
|
|
|| pccb->ulCompletionFlag == CONNECT_STATION_FLAG
|
|
|| pccb->ulCompletionFlag == GET_BUFFER_FLAG
|
|
|| pccb->ulCompletionFlag == FREE_BUFFER_FLAG
|
|
|| pccb->ulCompletionFlag == RECEIVE_COMPLETE_FLAG
|
|
|| pccb->ulCompletionFlag == TRANSMIT_COMPLETE_FLAG) {
|
|
FREE(pccb->u.pParameterTable);
|
|
FREE(pccb);
|
|
} else if (pccb->ulCompletionFlag == CLOSE_ADAPTER_FLAG
|
|
|| pccb->ulCompletionFlag == CLOSE_SAP_FLAG
|
|
|| pccb->ulCompletionFlag == CLOSE_STATION_FLAG
|
|
|| pccb->ulCompletionFlag == RESET_FLAG) {
|
|
FREE(pccb);
|
|
}
|
|
pccb = nextCcb;
|
|
}
|
|
}
|
|
|
|
void add_receiver(LPBYTE header, WORD header_length, BYTE sap, BYTE count) {
|
|
|
|
PRECEIVER p;
|
|
PSTATION ps;
|
|
PSTATION ps_prev;
|
|
|
|
if (p = (PRECEIVER)ID_MALLOC(sizeof(RECEIVER), ID_RECEIVER)) {
|
|
InitializeListHead(&p->list);
|
|
p->marked_for_death = FALSE;
|
|
memcpy(p->node, &header[8], 6);
|
|
twiddle_bits(p->node, 6);
|
|
p->first_sap = sap;
|
|
p->sap_count = count;
|
|
memcpy(p->lan_header, header, header_length);
|
|
p->lan_header_length = 14;
|
|
p->refcount = 1;
|
|
p->station_list = NULL;
|
|
ps_prev = (PSTATION)&p->station_list;
|
|
while (count--) {
|
|
if (ps = (PSTATION)ID_MALLOC(sizeof(STATION), ID_STATION)) {
|
|
ps_prev->next = ps;
|
|
ps_prev = ps;
|
|
ps->next = NULL;
|
|
ps->station_id = 0;
|
|
ps->remote_sap = sap;
|
|
sap += 2;
|
|
}
|
|
}
|
|
|
|
if (Terminating) {
|
|
return;
|
|
}
|
|
|
|
EnterCriticalSection(&ReceiverLock);
|
|
InsertTailList(&Receivers, &p->list);
|
|
SetEvent(TransmitterWorkItem);
|
|
LeaveCriticalSection(&ReceiverLock);
|
|
} else {
|
|
printf(CONSOLE_ALERT "add_receiver: error: can't allocate memory\n");
|
|
}
|
|
}
|
|
|
|
void remove_receiver(LPBYTE node, BYTE sap, BYTE count) {
|
|
|
|
PRECEIVER pr;
|
|
PSTATION ps;
|
|
PSTATION ps_next;
|
|
|
|
if (Terminating) {
|
|
return;
|
|
}
|
|
|
|
EnterCriticalSection(&ReceiverLock);
|
|
|
|
for (pr = (PRECEIVER)Receivers.Flink;
|
|
pr != (PRECEIVER)&Receivers;
|
|
pr = (PRECEIVER)pr->list.Flink) {
|
|
|
|
if (pr->first_sap == sap
|
|
&& pr->sap_count == count
|
|
&& !memcmp(pr->node, node, 6)
|
|
&& !pr->marked_for_death) {
|
|
if (!--pr->refcount) {
|
|
printf("*** remove_receiver: RECEIVER %02x-%02x-%02x-%02x-%02x-%02x S=%02x N=%d deleted\n",
|
|
pr->node[0] & 0xff,
|
|
pr->node[1] & 0xff,
|
|
pr->node[2] & 0xff,
|
|
pr->node[3] & 0xff,
|
|
pr->node[4] & 0xff,
|
|
pr->node[5] & 0xff,
|
|
pr->first_sap,
|
|
pr->sap_count
|
|
);
|
|
RemoveEntryList(&pr->list);
|
|
for (ps = pr->station_list; ps; ) {
|
|
ps_next = ps->next;
|
|
FREE(ps);
|
|
ps = ps_next;
|
|
}
|
|
FREE(pr);
|
|
} else {
|
|
printf("*** remove_receiver: deferring delete of %02x-%02x-%02x-%02x-%02x-%02x S=%02x N=%d #=%d\n",
|
|
pr->node[0] & 0xff,
|
|
pr->node[1] & 0xff,
|
|
pr->node[2] & 0xff,
|
|
pr->node[3] & 0xff,
|
|
pr->node[4] & 0xff,
|
|
pr->node[5] & 0xff,
|
|
pr->first_sap,
|
|
pr->sap_count,
|
|
pr->refcount
|
|
);
|
|
pr->marked_for_death = TRUE;
|
|
}
|
|
break;
|
|
} else if (pr->marked_for_death) {
|
|
printf(CONSOLE_ALERT "*** remove_receiver: error: RECEIVER %02x-%02x-%02x-%02x-%02x-%02x S=%02x N=%d marked dead\n",
|
|
pr->node[0] & 0xff,
|
|
pr->node[1] & 0xff,
|
|
pr->node[2] & 0xff,
|
|
pr->node[3] & 0xff,
|
|
pr->node[4] & 0xff,
|
|
pr->node[5] & 0xff,
|
|
pr->first_sap,
|
|
pr->sap_count
|
|
);
|
|
|
|
}
|
|
}
|
|
if (!pr) {
|
|
printf(CONSOLE_ALERT "*** remove_receiver: error: couldn't find %02x-%02x-%02x-%02x-%02x-%02x S=%02x N=%d\n",
|
|
node[0] & 0xff,
|
|
node[1] & 0xff,
|
|
node[2] & 0xff,
|
|
node[3] & 0xff,
|
|
node[4] & 0xff,
|
|
node[5] & 0xff,
|
|
sap,
|
|
count
|
|
);
|
|
}
|
|
LeaveCriticalSection(&ReceiverLock);
|
|
}
|
|
|
|
void delete_receiver(PRECEIVER pr) {
|
|
|
|
PSTATION ps;
|
|
int err;
|
|
|
|
printf("*** delete_receiver %02x-%02x-%02x-%02x-%02x-%02x S=%02x N=%d #=%d\n",
|
|
pr->node[0] & 0xff,
|
|
pr->node[1] & 0xff,
|
|
pr->node[2] & 0xff,
|
|
pr->node[3] & 0xff,
|
|
pr->node[4] & 0xff,
|
|
pr->node[5] & 0xff,
|
|
pr->first_sap,
|
|
pr->sap_count,
|
|
pr->refcount
|
|
);
|
|
|
|
for (ps = pr->station_list; ps; ps = ps->next) {
|
|
if (ps->station_id) {
|
|
err = close_station(Adapter,
|
|
ps->station_id,
|
|
COMPLETE_BY_GENERIC_READ,
|
|
RETURN_ERROR_TO_CALLER
|
|
);
|
|
if (err) {
|
|
printf("delete_receiver: error: close_station(%04x) returns %#.2x\n",
|
|
ps->station_id,
|
|
err
|
|
);
|
|
// if (Debugging) {
|
|
// DebugBreak();
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
remove_receiver(pr->node, pr->first_sap, pr->sap_count);
|
|
}
|
|
|
|
void send_to_receivers() {
|
|
|
|
PRECEIVER pr;
|
|
PRECEIVER pr_next = NULL;
|
|
PSTATION ps;
|
|
int err;
|
|
LPBYTE data;
|
|
int dlc_error;
|
|
|
|
if (Terminating) {
|
|
return;
|
|
}
|
|
EnterCriticalSection(&ReceiverLock);
|
|
if (!IsListEmpty(&Receivers)) {
|
|
pr = (PRECEIVER)Receivers.Flink;
|
|
++pr->refcount;
|
|
LeaveCriticalSection(&ReceiverLock);
|
|
} else {
|
|
LeaveCriticalSection(&ReceiverLock);
|
|
return;
|
|
}
|
|
while (!IsListEmpty(&Receivers)) {
|
|
if (Terminating) {
|
|
return;
|
|
}
|
|
for (ps = pr->station_list; ps; ps = ps->next) {
|
|
if (pr->refcount == 1) {
|
|
pr_next = (PRECEIVER)pr->list.Flink;
|
|
delete_receiver(pr);
|
|
break;
|
|
}
|
|
if (!ps->station_id) {
|
|
err = open_station(Adapter,
|
|
ServerSap,
|
|
ps->remote_sap,
|
|
&pr->lan_header[8],
|
|
&ps->station_id,
|
|
RETURN_ERROR_TO_CALLER,
|
|
&dlc_error
|
|
);
|
|
if (!err) {
|
|
err = connect_station(Adapter,
|
|
ps->station_id,
|
|
RETURN_ERROR_TO_CALLER
|
|
);
|
|
if (!err) {
|
|
ps->job_length = 0;
|
|
ps->job_sequence = 0;
|
|
} else {
|
|
if (!Verbose && err == LLC_STATUS_INVALID_STATION_ID) {
|
|
err = 0;
|
|
}
|
|
if (err) {
|
|
printf("send_to_receivers: error: connect_station(%04x) returns %#.2x\n",
|
|
ps->station_id,
|
|
err
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
printf("send_to_receivers: error: open_station(%02x, %02x) returns %#.2x [%#.2x]\n",
|
|
ServerSap,
|
|
ps->remote_sap,
|
|
err,
|
|
dlc_error
|
|
);
|
|
}
|
|
}
|
|
if (!ps->job_length) {
|
|
if (ps->job_sequence) {
|
|
if (TransmitterMode == JOB_BASED_MODE) {
|
|
if (ps->station_id) {
|
|
err = close_station(Adapter,
|
|
ps->station_id,
|
|
COMPLETE_BY_GENERIC_READ,
|
|
RETURN_ERROR_TO_CALLER
|
|
);
|
|
if (err) {
|
|
if (!Verbose && err == LLC_STATUS_INVALID_STATION_ID) {
|
|
err = 0;
|
|
}
|
|
if (err) {
|
|
printf("send_to_receivers: error: close_station(%04x) returns %x\n",
|
|
ps->station_id,
|
|
err
|
|
);
|
|
}
|
|
}
|
|
}
|
|
ps->station_id = 0;
|
|
} else {
|
|
ps->job_sequence = 0;
|
|
}
|
|
} else {
|
|
ps->job_length = generate_job_length();
|
|
if (Verbose) {
|
|
printf("send_to_receivers: new job: %d bytes to %02x-%02x-%02x-%02x-%02x-%02x : %04x\n",
|
|
ps->job_length,
|
|
pr->node[0] & 0xff,
|
|
pr->node[1] & 0xff,
|
|
pr->node[2] & 0xff,
|
|
pr->node[3] & 0xff,
|
|
pr->node[4] & 0xff,
|
|
pr->node[5] & 0xff,
|
|
ps->station_id
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
|
|
int txlen = min((int)(sizeof(JOB) + ps->job_length), (int)(MaxFrameSize - 32));
|
|
PJOB pj;
|
|
|
|
if (!(AppLevelFlowControl && (OutstandingIFrames == HighWaterMark))) {
|
|
|
|
if (data = (LPBYTE)ID_MALLOC(txlen, ID_JOB)) {
|
|
pj = (PJOB)data;
|
|
pj->type = JOB_TYPE_OUTBOUND;
|
|
pj->sequence = ps->job_sequence++;
|
|
pj->length = ps->job_length;
|
|
pj->packet_length = txlen - sizeof(JOB);
|
|
memset(pj + 1, 'A', txlen - sizeof(JOB));
|
|
ps->job_length -= txlen - sizeof(JOB);
|
|
|
|
++OutstandingTransmits;
|
|
err = transmit_frame(Adapter,
|
|
LLC_TRANSMIT_I_FRAME,
|
|
ps->station_id,
|
|
ps->remote_sap,
|
|
0,
|
|
NULL,
|
|
(WORD)txlen,
|
|
data,
|
|
COMPLETE_BY_GENERIC_READ,
|
|
RETURN_ERROR_TO_CALLER
|
|
);
|
|
if (err) {
|
|
if (!Verbose && err == LLC_STATUS_INVALID_STATION_ID) {
|
|
err = 0;
|
|
}
|
|
if (err) {
|
|
printf("send_to_receivers: error: transmit_frame(I-Frame) returns %#x\n", err);
|
|
}
|
|
// printf("freeing I-Frame: err = %x\n", err);
|
|
FREE(data);
|
|
} else if (AppLevelFlowControl) {
|
|
++TotalTransmits;
|
|
++OutstandingIFrames;
|
|
}
|
|
} else {
|
|
printf(CONSOLE_ALERT "send_to_receivers: error: failed to allocate memory for JOB\n");
|
|
}
|
|
} else if (AppLevelFlowControl && Verbose) {
|
|
printf("send_to_receivers: Flow-Control: %d I-Frames outstanding\n", OutstandingIFrames);
|
|
}
|
|
}
|
|
update_progress_meter();
|
|
check_keyboard();
|
|
check_quit();
|
|
}
|
|
if (Terminating) {
|
|
return;
|
|
}
|
|
EnterCriticalSection(&ReceiverLock);
|
|
if (!pr_next) {
|
|
pr_next = (PRECEIVER)pr->list.Flink;
|
|
if (!--pr->refcount) {
|
|
++pr->refcount;
|
|
delete_receiver(pr);
|
|
}
|
|
}
|
|
pr = pr_next;
|
|
pr_next = NULL;
|
|
if (pr == (PRECEIVER)&Receivers) {
|
|
pr = (PRECEIVER)Receivers.Flink;
|
|
}
|
|
if (!IsListEmpty(&Receivers)) {
|
|
++pr->refcount;
|
|
LeaveCriticalSection(&ReceiverLock);
|
|
} else {
|
|
LeaveCriticalSection(&ReceiverLock);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void maybe_send_ui_frame() {
|
|
|
|
int diff;
|
|
int err;
|
|
|
|
diff = GetTickCount() - LastTickCount;
|
|
LastTickCount = GetTickCount();
|
|
TicksToNextUiFrame -= diff;
|
|
if (TicksToNextUiFrame <= 0) {
|
|
TicksToNextUiFrame = rand();
|
|
*(LPDWORD)&sBuffer[TICK_INDEX] = TicksToNextUiFrame;
|
|
++OutstandingTransmits;
|
|
err = transmit_frame(Adapter,
|
|
LLC_TRANSMIT_UI_FRAME,
|
|
UStation,
|
|
USap,
|
|
sizeof(uHeader),
|
|
uHeader,
|
|
sizeof(sBuffer),
|
|
sBuffer,
|
|
COMPLETE_BY_POLL,
|
|
RETURN_ERROR_TO_CALLER
|
|
);
|
|
if (err) {
|
|
printf("maybe_send_ui_frame: error: transmit_frame returns %x\n", err);
|
|
} else {
|
|
++TotalTransmits;
|
|
}
|
|
--OutstandingTransmits;
|
|
}
|
|
}
|
|
|
|
int xtoi(char* p) {
|
|
|
|
int num = 0;
|
|
|
|
if (!_strnicmp(p, "0x", 2)) {
|
|
p += 2;
|
|
}
|
|
while (isxdigit(*p)) {
|
|
num = num * 16 + xton(*p++);
|
|
}
|
|
return num;
|
|
}
|
|
|
|
int xton(char ch) {
|
|
return isdigit(ch) ? (ch - '0')
|
|
: isupper(ch) ? ((ch - 'A') + 10)
|
|
: ((ch - 'a') + 10);
|
|
}
|
|
|
|
void twiddle_bits(LPBYTE buffer, DWORD length) {
|
|
if (ISwapBitsForCash) {
|
|
while (length--) {
|
|
*buffer = swap_bits(*buffer);
|
|
++buffer;
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned char swap_bits(unsigned char b) {
|
|
|
|
unsigned char bb = 0;
|
|
unsigned char mask;
|
|
|
|
for (mask = 1; mask; mask <<= 1) {
|
|
bb <<= 1;
|
|
bb |= ((b & mask) ? 1 : 0);
|
|
}
|
|
return bb;
|
|
}
|
|
|
|
char* map_frame_type(char ft) {
|
|
switch (ft) {
|
|
case LLC_DIRECT_TRANSMIT:
|
|
return "DIRECT TRANSMIT";
|
|
|
|
case LLC_DIRECT_MAC:
|
|
return "DIRECT MAC";
|
|
|
|
case LLC_I_FRAME:
|
|
return "I-Frame";
|
|
|
|
case LLC_UI_FRAME:
|
|
return "UI-Frame";
|
|
|
|
case LLC_XID_COMMAND_POLL:
|
|
return "XID Cmd-Poll";
|
|
|
|
case LLC_XID_COMMAND_NOT_POLL:
|
|
return "XID Cmd (not Poll)";
|
|
|
|
case LLC_XID_RESPONSE_FINAL:
|
|
return "XID Resp-Final";
|
|
|
|
case LLC_XID_RESPONSE_NOT_FINAL:
|
|
return "XID Resp (not Final)";
|
|
|
|
case LLC_TEST_RESPONSE_FINAL:
|
|
return "TEST Resp-Final";
|
|
|
|
case LLC_TEST_RESPONSE_NOT_FINAL:
|
|
return "TEST Resp (not Final)";
|
|
|
|
case LLC_DIRECT_8022:
|
|
return "DIRECT 802.2";
|
|
|
|
case LLC_TEST_COMMAND_POLL:
|
|
return "TEST Cmd-Poll";
|
|
|
|
case LLC_DIRECT_ETHERNET_TYPE:
|
|
return "DIRECT ETHERNET";
|
|
|
|
case LLC_LAST_FRAME_TYPE:
|
|
return "LAST FRAME TYPE";
|
|
|
|
case LLC_FIRST_ETHERNET_TYPE:
|
|
return "FIRST ETHERNET TYPE";
|
|
}
|
|
return "*** UNKNOWN FRAME TYPE ***";
|
|
}
|
|
|
|
#define METER_CHAR 219
|
|
#define METER_LENGTH 20
|
|
#define METER_DELAY 2
|
|
|
|
void update_progress_meter() {
|
|
if (!Verbose && Progresso) {
|
|
|
|
static int chars_printed = 0;
|
|
static int up = 1;
|
|
static int delay = METER_DELAY;
|
|
|
|
if (!--delay) {
|
|
delay = METER_DELAY;
|
|
if (up) {
|
|
putchar(METER_CHAR);
|
|
if (++chars_printed == METER_LENGTH) {
|
|
up = 0;
|
|
}
|
|
} else {
|
|
putchar(8);
|
|
putchar(' ');
|
|
putchar(8);
|
|
if (!--chars_printed) {
|
|
up = 1;
|
|
putchar('\r');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void check_keyboard() {
|
|
if (kbhit()) {
|
|
switch (tolower(getch())) {
|
|
case 'a':
|
|
report_allocs();
|
|
break;
|
|
|
|
case 'f':
|
|
AppLevelFlowControl = !AppLevelFlowControl;
|
|
break;
|
|
|
|
case 'h':
|
|
case '?':
|
|
printf("\n"
|
|
"The following keys are recognized:\n"
|
|
"\n"
|
|
"\ta - Displays a list of memory allocations by type\n"
|
|
"\tf - Toggles app-level flow-control. Currently %s\n"
|
|
"\th - Displays this help\n"
|
|
"\t? - Same as h\n"
|
|
"\tl - Traverse the memory list, displaying current allocations\n"
|
|
"\tm - Displays the current memory usage\n"
|
|
"\tp - Toggles the progress meter\n"
|
|
"\tq - Quit this program\n"
|
|
"\tr - Toggles memory usage reporting. Currently %s\n"
|
|
"\ts - Display statistics\n"
|
|
"\tt - Display the current elapsed time since program was started\n"
|
|
"\tv - Toggle Verbose mode\n"
|
|
"\t. - Traverse the memory list, but don't dump blocks\n"
|
|
"\n",
|
|
AppLevelFlowControl ? "ON" : "OFF",
|
|
NoMemoryUsageReporting ? "OFF" : "ON"
|
|
);
|
|
break;
|
|
|
|
case 'l':
|
|
traverse_mem_list(TRUE);
|
|
break;
|
|
|
|
case 'm':
|
|
report_memory_usage(TRUE);
|
|
break;
|
|
|
|
case 'p':
|
|
Progresso = !Progresso;
|
|
break;
|
|
|
|
case 'q':
|
|
exit(0);
|
|
|
|
case 'r':
|
|
NoMemoryUsageReporting = !NoMemoryUsageReporting;
|
|
break;
|
|
|
|
case 's':
|
|
display_statistics();
|
|
break;
|
|
|
|
case 't':
|
|
display_elapsed_time();
|
|
break;
|
|
|
|
case 'v':
|
|
Verbose = !Verbose;
|
|
break;
|
|
|
|
case '.':
|
|
traverse_mem_list(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void display_elapsed_time() {
|
|
|
|
SYSTEMTIME timeNow;
|
|
FILETIME ftimeNow;
|
|
LARGE_INTEGER iTimeNow;
|
|
LARGE_INTEGER timeDiff;
|
|
ULARGE_INTEGER uTimeDiff;
|
|
DWORD remainder;
|
|
DWORD msecDiff;
|
|
DWORD divisor;
|
|
DWORD months;
|
|
DWORD weeks;
|
|
DWORD days;
|
|
DWORD hours;
|
|
DWORD minutes;
|
|
DWORD seconds;
|
|
DWORD milliseconds;
|
|
char timeBuf[256];
|
|
char* ptr = timeBuf;
|
|
int sprinted;
|
|
|
|
GetLocalTime(&timeNow);
|
|
SystemTimeToFileTime(&timeNow, &ftimeNow);
|
|
|
|
iTimeNow.LowPart = ftimeNow.dwLowDateTime;
|
|
iTimeNow.HighPart = (LONG)ftimeNow.dwHighDateTime;
|
|
|
|
timeDiff.QuadPart = iTimeNow.QuadPart - ITimeStarted.QuadPart;
|
|
|
|
//
|
|
// timeDiff is now difference between time this program started and now,
|
|
// expressed as a number of 100 nanosecond increments. Convert difference
|
|
// to number of milliseconds, by dividing by 10,000
|
|
//
|
|
|
|
uTimeDiff.LowPart = timeDiff.LowPart;
|
|
uTimeDiff.HighPart = (ULONG)timeDiff.HighPart;
|
|
msecDiff = RtlEnlargedUnsignedDivide(uTimeDiff, 10000, &remainder);
|
|
|
|
//
|
|
// now get the number of months, weeks, days, hours, seconds and milliseconds
|
|
// by dividing by the appropriate number
|
|
//
|
|
|
|
divisor = (DWORD)1000 * (DWORD)60 * (DWORD)60 * (DWORD)24 * (DWORD)7 * (DWORD)4;
|
|
months = msecDiff / divisor;
|
|
msecDiff -= months * divisor;
|
|
|
|
divisor /= 4;
|
|
weeks = msecDiff / divisor;
|
|
msecDiff -= weeks * divisor;
|
|
|
|
divisor /= 7;
|
|
days = msecDiff / divisor;
|
|
msecDiff -= days * divisor;
|
|
|
|
divisor /= 24;
|
|
hours = msecDiff / divisor;
|
|
msecDiff -= hours * divisor;
|
|
|
|
divisor /= 60;
|
|
minutes = msecDiff / divisor;
|
|
msecDiff -= minutes * divisor;
|
|
|
|
divisor /= 60;
|
|
seconds = msecDiff / divisor;
|
|
milliseconds = msecDiff - seconds * divisor;
|
|
|
|
sprinted = 0;
|
|
timeBuf[0] = '\0';
|
|
if (months) {
|
|
ptr += sprintf(ptr, "%d months ", months);
|
|
++sprinted;
|
|
}
|
|
if (weeks || sprinted) {
|
|
ptr += sprintf(ptr, "%d weeks ", weeks);
|
|
++sprinted;
|
|
}
|
|
if (days || sprinted) {
|
|
ptr += sprintf(ptr, "%d days ", days);
|
|
++sprinted;
|
|
}
|
|
if (minutes || sprinted) {
|
|
ptr += sprintf(ptr, "%d minute%s ", minutes, (minutes != 1) ? "s" : "");
|
|
++sprinted;
|
|
}
|
|
sprintf(ptr, "%d.%03d seconds", seconds, milliseconds);
|
|
|
|
//
|
|
// display the following (e.g.):
|
|
//
|
|
// Elapsed time = 100 months 51 weeks 364 days 59 minutes 22.982 seconds
|
|
//
|
|
|
|
printf("\nElapsed time = %s\n\n", timeBuf);
|
|
}
|
|
|
|
DWORD generate_job_length() {
|
|
|
|
DWORD n;
|
|
|
|
if (JobLength) {
|
|
n = JobLength;
|
|
} else {
|
|
n = (DWORD)rand() * dwpow(10, NRAND(5));
|
|
}
|
|
if (Verbose) {
|
|
printf("generate_job_length(): returning %d (%x)\n", n, n);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
DWORD dwpow(DWORD base, DWORD power) {
|
|
return power ? base * dwpow(base, power - 1) : 1;
|
|
}
|
|
|
|
DWORD atox(char* a) {
|
|
|
|
DWORD num = 0;
|
|
|
|
if (!_strnicmp(a, "0x", 2)) {
|
|
a += 2;
|
|
}
|
|
while (isxdigit(*a)) {
|
|
num = num * 16 + ((char_to_hex(*a++) << 4) | char_to_hex(*a++));
|
|
}
|
|
return num;
|
|
}
|
|
|
|
BYTE char_to_hex(char ch) {
|
|
return (ch >= '0' && ch <= '9')
|
|
? (ch - '0')
|
|
: (ch >= 'a' && ch <= 'f')
|
|
? ((ch - 'a') + 10)
|
|
: ((ch - 'A') + 10);
|
|
}
|
|
|
|
void check_quit() {
|
|
if (QuitTime) {
|
|
if (GetTickCount() >= QuitTime) {
|
|
quit_pmsim();
|
|
}
|
|
}
|
|
}
|
|
|
|
void quit_pmsim() {
|
|
|
|
rip();
|
|
|
|
if (!ReceiveMode) {
|
|
if (GracefulTermination) {
|
|
|
|
int err;
|
|
|
|
err = reset(Adapter, 0, COMPLETE_BY_GENERIC_READ, RETURN_ERROR_TO_CALLER);
|
|
/*
|
|
err = close_sap(Adapter,
|
|
ServerSap,
|
|
COMPLETE_BY_GENERIC_READ,
|
|
RETURN_ERROR_TO_CALLER
|
|
);
|
|
*/
|
|
if (err) {
|
|
/*
|
|
printf("quit_pmsim: close_sap(%02x) returns %#.2x\n", ServerSap, err);
|
|
err = reset(Adapter, 0, COMPLETE_BY_GENERIC_READ, RETURN_ERROR_TO_CALLER);
|
|
*/
|
|
if (err) {
|
|
printf("quit_pmsim: reset(0) returns %#.2x\n", err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Terminating = 1;
|
|
|
|
report_allocs();
|
|
|
|
if (!GracefulTermination) {
|
|
ExitProcess((DWORD)-1);
|
|
} else {
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void rip() {
|
|
|
|
WORD stationId;
|
|
BYTE sap;
|
|
PBYTE header;
|
|
int err;
|
|
|
|
if (ReceiveMode) {
|
|
dBuffer[SAP_INDEX] = FirstSap;
|
|
dBuffer[COUNT_INDEX] = (BYTE)NumberOfSaps;
|
|
stationId = (WORD)FirstSap << 8;
|
|
sap = ServerSap;
|
|
header = uHeader;
|
|
} else {
|
|
|
|
//
|
|
// broadcast transmitter death to global SAP on RGROUP address!
|
|
//
|
|
|
|
stationId = (WORD)ServerSap << 8;
|
|
sap = 0xff;
|
|
header = tHeader;
|
|
}
|
|
|
|
++OutstandingTransmits;
|
|
err = transmit_frame(Adapter,
|
|
LLC_TRANSMIT_UI_FRAME,
|
|
stationId,
|
|
sap,
|
|
HEADER_LENGTH,
|
|
header,
|
|
sizeof(dBuffer),
|
|
dBuffer,
|
|
COMPLETE_BY_GENERIC_READ,
|
|
RETURN_ERROR_TO_CALLER
|
|
);
|
|
if (err) {
|
|
printf("rip: transmit_frame(death packet) returns %x\n", err);
|
|
--OutstandingTransmits;
|
|
} else {
|
|
++TotalTransmits;
|
|
}
|
|
}
|
|
|
|
void display_statistics() {
|
|
printf("\n"
|
|
"Buffer statistics:\n");
|
|
printf("\tMinBuffersAvailable. . . . . : %s\n", nice_num(MinBuffersAvailable));
|
|
printf("\tMaxBuffersAvailable. . . . . : %s\n", nice_num(MaxBuffersAvailable));
|
|
printf("\tDlcBuffersFreed. . . . . . . : %s\n", nice_num(DlcBuffersFreed));
|
|
|
|
printf("\n"
|
|
"READ statistics:\n");
|
|
printf("\tTotalReadsChecked. . . . . . : %s\n", nice_num(TotalReadsChecked));
|
|
printf("\tTotalReadEvents. . . . . . . : %s\n", nice_num(TotalReadEvents));
|
|
printf("\tCommandCompleteEvents. . . . : %s\n", nice_num(CommandCompleteEvents));
|
|
printf("\tTransmitCompleteEvents . . . : %s\n", nice_num(TransmitCompleteEvents));
|
|
printf("\tReceiveDataEvents. . . . . . : %s\n", nice_num(ReceiveDataEvents));
|
|
printf("\tStatusChangeEvents . . . . . : %s\n", nice_num(StatusChangeEvents));
|
|
|
|
if (ReceiveMode) {
|
|
printf("\n"
|
|
"Receive statistics:\n");
|
|
printf("\tDataFramesReceived . . . . . : %s\n", nice_num(DataFramesReceived));
|
|
printf("\tDlcBuffersReceived . . . . . : %s\n", nice_num(DlcBuffersReceived));
|
|
printf("\tTotalPacketBytesReceived . . : %s\n", nice_num(TotalPacketBytesReceived));
|
|
printf("\tTotalDlcBytesReceived. . . . : %s\n", nice_num(TotalDlcBytesReceived));
|
|
printf("\tMaxChainedReceives . . . . . : %s\n", nice_num(MaxChainedReceives));
|
|
} else {
|
|
printf("\n"
|
|
"Transmit statistics:\n");
|
|
printf("\tTotalTransmits . . . . . . . : %s\n", nice_num(TotalTransmits));
|
|
printf("\tTotalTransmitCompletions . . : %s\n", nice_num(TotalTransmitCompletions));
|
|
printf("\tOutstandingTransmits . . . . : %s\n", nice_num(OutstandingTransmits));
|
|
printf("\tTotalBytesTransmitted. . . . : %s\n", nice_num(TotalBytesTransmitted));
|
|
printf("\tTotalTxBytesCompleted. . . . : %s\n", nice_num(TotalTxBytesCompleted));
|
|
printf("\tMaxChainedTransmits. . . . . : %s\n", nice_num(MaxChainedTransmits));
|
|
}
|
|
|
|
printf("\n"
|
|
"Status change statistics:\n");
|
|
printf("\tLinkLostEvents . . . . . . . : %s\n", nice_num(LinkLostEvents));
|
|
printf("\tDiscEvents . . . . . . . . . : %s\n", nice_num(DiscEvents));
|
|
printf("\tFrmrReceivedEvents . . . . . : %s\n", nice_num(FrmrReceivedEvents));
|
|
printf("\tFrmrSentEvents . . . . . . . : %s\n", nice_num(FrmrSentEvents));
|
|
printf("\tSabmeResetEvents . . . . . . : %s\n", nice_num(SabmeResetEvents));
|
|
printf("\tSabmeOpenEvents. . . . . . . : %s\n", nice_num(SabmeOpenEvents));
|
|
printf("\tRemoteBusyEnteredEvents. . . : %s\n", nice_num(RemoteBusyEnteredEvents));
|
|
printf("\tRemoteBusyLeftEvents . . . . : %s\n", nice_num(RemoteBusyLeftEvents));
|
|
printf("\tTiExpiredEvents. . . . . . . : %s\n", nice_num(TiExpiredEvents));
|
|
printf("\tDlcCounterOverflowEvents . . : %s\n", nice_num(DlcCounterOverflowEvents));
|
|
printf("\tAccessPriorityLoweredEvents. : %s\n", nice_num(AccessPriorityLoweredEvents));
|
|
printf("\tInvalidStatusChangeEvents. . : %s\n", nice_num(InvalidStatusChangeEvents));
|
|
printf("\tLocalBusyEvents. . . . . . . : %s\n", nice_num(LocalBusyEvents));
|
|
putchar('\n');
|
|
}
|