Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1609 lines
51 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
hpsim.c
Abstract:
Attempts to simulate HPMON functionality. Run in 2 modes - receiver and
transmitter. Receiver acts like HP III Si and receives 'print jobs' -
I-Frame transmissions which it then bins. Transmitter acts like HPMON -
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
Author:
Richard L Firth (rfirth) 29-Mar-1994
Revision History:
29-Mar-1994 rfirth
Created
--*/
#include "hpsim.h"
#ifndef _CRTAPI1
#define _CRTAPI1
#endif
//
// macros
//
#define IS_ARG(c) (((c) == '-') || ((c) == '/'))
//
// manifests
//
#define VERSION_STRING "1.0"
//
// types
//
typedef struct _STATION {
struct _STATION* next;
WORD station_id;
BYTE remote_sap;
DWORD job_sequence;
DWORD job_length;
} STATION, *PSTATION;
typedef struct {
LIST_ENTRY list;
BYTE node[6];
BYTE first_sap;
BYTE sap_count;
BYTE lan_header[14];
WORD lan_header_length;
DWORD refcount;
PSTATION station_list;
} RECEIVER, *PRECEIVER;
typedef struct {
DWORD type;
DWORD sequence;
DWORD length;
DWORD packet_length;
} JOB, *PJOB;
#define JOB_TYPE_OUTBOUND 0xE001B002
#define JOB_TYPE_ECHO 0xEC0EC0F0
//
// 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);
void 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);
//
// data
//
BYTE MyNodeAddress[6];
BYTE Adapter = 0;
int ReceiveMode = 0;
int TransmitterMode = JOB_BASED_MODE;
int Verbose = 0;
int NumberOfSaps = 1;
BYTE FirstSap = HPSIM_SAP;
BYTE ServerSap = HPSIM_SAP;
WORD MaxFrameSize;
WORD TypeOfAdapter;
DWORD BufferHandle;
DWORD BufferPool;
int FoundTransmitter = 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;
BYTE MaxIn = 0; // default to value defined in IBM LAN Tech Ref
BYTE MaxOut = 0; // " " " " " " " " "
BYTE uHeader[14] = {0x10, 0x40, HPSIM_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] = {'H', 'P', '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] = {'H', 'P', 'D', 'E', 'A', 'T', 'H', 0, 0, 0};
#define MODE_INDEX 7
#define SAP_INDEX 8
#define COUNT_INDEX 9
#define TICK_INDEX 8
#define NAME_INDEX 10
//
// functions
//
void _CRTAPI1 main(int argc, char** argv) {
printf("\nHPSIM - HPMON Simulator - Version " VERSION_STRING " " __DATE__ " " __TIME__ "\n\n");
for (--argc, ++argv; argc; --argc, ++argv) {
if (IS_ARG(**argv)) {
switch (*++*argv) {
case 'a':
Adapter = (BYTE)atoi(++*argv);
break;
case 'c':
TransmitterMode = CONTINUOUS_MODE;
break;
case 'd':
Debugging = 1;
break;
case 'h':
case '?':
usage();
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 '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 = atoi(++*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 (ReceiveMode) {
receiver();
} else {
InitializeListHead(&Receivers);
transmitter();
}
printf("\nHPSIM Done.\n");
exit(0);
}
void usage() {
printf("usage: hpsim [/a#] [/c] [/k] [/n#] [/r] [/s#] [/S#] [/u] [/v]\n\n"
"where: /a = use adapter # (default is 0)\n"
" /c = continuous mode (default is job-based mode)\n"
" /k = don't check for other transmitters (default is to check)\n"
" /n = number of SAPs to open (at receiver). # is decimal (1 to 127)\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\n"
" /v = verbose mode\n"
);
exit(1);
}
void start() {
InitializeCriticalSection(&ReceiverLock);
TransmitterWorkItem = CreateEvent(NULL, TRUE, FALSE, NULL);
open_adapter(Adapter, &MaxFrameSize);
TypeOfAdapter = adapter_status(Adapter, MyNodeAddress);
if (TypeOfAdapter != ADAPTER_TYPE_ETHERNET && TypeOfAdapter != ADAPTER_TYPE_UNKNOWN) {
printf("fatal: adapter type %s not supported\n",
(TypeOfAdapter == ADAPTER_TYPE_TOKEN_RING) ? "Token-Ring"
: (TypeOfAdapter == ADAPTER_TYPE_PC_NETWORK) ? "PC/Network"
: "Unknown"
);
exit(1);
}
create_buffer(Adapter, DLC_BUFFER_SIZE, (LPVOID*)&BufferHandle, (LPVOID*)&BufferPool);
signal(SIGINT, control_c_handler);
atexit(finish);
StartTickCount = LastTickCount = GetTickCount();
srand(StartTickCount);
TicksToNextUiFrame = rand();
}
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;
err = transmit_frame(Adapter,
LLC_TRANSMIT_UI_FRAME,
(WORD)FirstSap << 8,
HPSIM_SAP,
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 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);
if (!GracefulTermination) {
ExitProcess((DWORD)-1);
} else {
/*
printf("waiting for various completions/closes...\n");
Sleep(5000);
*/
exit(1);
}
}
void _CRTAPI1 finish() {
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");
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;
printf("Searching for transmitter");
for (i = 0; i < 2 * BEACON_COUNT; ++i) {
transmit_frame(Adapter,
LLC_TRANSMIT_UI_FRAME,
(WORD)FirstSap << 8,
ServerSap,
sizeof(uHeader),
uHeader,
sizeof(uBuffer),
uBuffer,
COMPLETE_BY_EVENT,
QUIT_ON_ERROR
);
check_read(readCcb, BEACON_WAIT);
if (FoundTransmitter) {
putchar('\n');
break;
} else {
putchar('.');
}
}
putchar('\n');
if (!FoundTransmitter) {
printf("receiver: fatal: transmitter didn't respond\n");
exit(1);
}
FoundTransmitter = 0;
while (1) {
repost_read(readCcb, 0);
check_read(readCcb, INFINITE);
maybe_send_ui_frame();
update_progress_meter();
}
}
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, HPSIM_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) {
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 (!FoundTransmitter) {
if (Verbose) {
putchar('.');
}
Sleep(BEACON_WAIT);
}
}
if (Verbose) {
putchar('\n');
}
if (FoundTransmitter) {
printf("transmitter: found station already acting as HPSIM 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);
}
}
}
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);
}
}
}
void 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);
}
event = parms->uchEvent;
for (comb = 0x80; comb; comb >>= 1) {
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;
}
}
}
}
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;
for (comb = 0x8000; comb; comb >>= 1) {
switch (status & comb) {
case 0x8000:
if (Verbose) {
printf("LINK LOST\n");
}
lost_it = TRUE;
break;
case 0x4000:
if (Verbose) {
printf("DM/DISC received or DISC acked\n");
}
lost_it = TRUE;
break;
case 0x2000:
if (Verbose) {
printf("FRMR received\n");
}
lost_it = TRUE;
break;
case 0x1000:
if (Verbose) {
printf("FRMR sent\n");
}
break;
case 0x0800:
if (Verbose) {
printf("SABME received on open LINK station\n");
}
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);
}
break;
case 0x0200:
if (Verbose) {
printf("REMOTE BUSY\n");
}
break;
case 0x0100:
if (Verbose) {
printf("REMOTE BUSY CLEARED\n");
}
break;
case 0x0080:
if (Verbose) {
printf("Ti EXPIRED\n");
}
break;
case 0x0040:
if (Verbose) {
printf("DLC counter overflow\n");
}
break;
case 0x0020:
if (Verbose) {
printf("Access priority lowered (on ethernet????!)\n");
}
break;
case 0x0010:
case 0x0008:
case 0x0004:
case 0x0002:
if (Verbose) {
printf(CONSOLE_ALERT "This status code (%04x) should not occur!\n", status & comb);
}
break;
case 0x0001:
if (Verbose) {
printf("LOCAL BUSY\n");
}
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);
}
close_station(Adapter,
parms->Type.Status.usStationId,
COMPLETE_BY_GENERIC_READ,
RETURN_ERROR_TO_CALLER
);
}
}
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;
frame = parms->Type.Event.pReceivedFrame;
i = parms->Type.Event.usReceivedFrameCount;
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--) {
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
);
}
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);
if (echo_packet = (LPBYTE)MALLOC(datalen)) {
memcpy(echo_packet, data, sizeof(JOB));
((PJOB)echo_packet)->type = JOB_TYPE_ECHO;
memset(((PJOB)echo_packet) + 1, 'Z', datalen - sizeof(JOB));
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);
}
}
}
}
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);
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
);
} 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, "HPDEATH")) {
//if (Verbose) {
printf("handle_receive_data: HpDeath UI-Frame 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
);
//}
remove_receiver(sender,
data[SAP_INDEX],
data[COUNT_INDEX]
);
} else {
printf("handle_receive_data: unexpected UI-Frame (not BEACON or STATUS)\n");
}
}
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, "HPSIM")) {
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);
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
);
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, "HPSIM")) {
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;
if (!i || !pccb) {
printf(CONSOLE_ALERT "handle_transmit_complete: error: count=%d CCB list=%x\n", i, pccb);
if (Debugging) {
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) {
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);
}
FREE(pccb->u.pParameterTable);
FREE(pccb);
pccb = nextCcb;
}
}
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;
if (!i || !pccb) {
printf(CONSOLE_ALERT "handle_command_complete: error: count=%d CCB list=%x\n", i, pccb);
if (Debugging) {
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) {
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);
}
pccb = nextCcb;
}
}
void add_receiver(LPBYTE header, WORD header_length, BYTE sap, BYTE count) {
PRECEIVER p;
PSTATION ps;
PSTATION ps_prev;
if (p = (PRECEIVER)MALLOC(sizeof(RECEIVER))) {
InitializeListHead(&p->list);
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)MALLOC(sizeof(STATION))) {
ps_prev->next = ps;
ps_prev = ps;
ps->next = NULL;
ps->station_id = 0;
ps->remote_sap = sap;
sap += 2;
}
}
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;
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)) {
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
);
}
break;
}
}
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) {
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
);
}
}
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;
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) {
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_length = rand();
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 (data = (LPBYTE)MALLOC(txlen)) {
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);
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);
}
}
} else {
printf(CONSOLE_ALERT "send_to_receivers: error: failed to allocate memory for JOB\n");
}
}
update_progress_meter();
}
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;
diff = GetTickCount() - LastTickCount;
LastTickCount = GetTickCount();
TicksToNextUiFrame -= diff;
if (TicksToNextUiFrame <= 0) {
TicksToNextUiFrame = rand();
*(LPDWORD)&sBuffer[TICK_INDEX] = TicksToNextUiFrame;
transmit_frame(Adapter,
LLC_TRANSMIT_UI_FRAME,
UStation,
USap,
sizeof(uHeader),
uHeader,
sizeof(sBuffer),
sBuffer,
COMPLETE_BY_POLL,
RETURN_ERROR_TO_CALLER
);
}
}
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) {
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) {
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');
}
}
}
}
}