home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / netds / dlc / simplex.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  52KB  |  1,745 lines

  1. /*++
  2.  
  3. Copyright (c) 1994-1997  Microsoft Corporation
  4.  
  5. Module Name:
  6.  
  7.     simplex.c
  8.  
  9. Abstract:
  10.  
  11.     Simple single-threaded DLC test/example program. Need 2 instances of this
  12.     app - 1 to send and 1 to receive (i.e. the typical DLC situation hence
  13.     simplex, or half-duplex in old money). By default, both sides use SAP 4
  14.  
  15.     Receiver is started:
  16.  
  17.         simplex
  18.  
  19.     Transmitter is started e.g.
  20.  
  21.         simplex /t02608c4c970e
  22.  
  23.     in this example the node address is in canonical form (ethernet format) as
  24.     displayed by "net config wksta", e.g., not the non-canonical (token-ring
  25.     format) that the DLC API expects. If this test app is being run over
  26.     token ring then you would supply the non-canonical address, as used by
  27.     token ring, e.g.
  28.  
  29.         simplex /t10005a7b08b4
  30.  
  31.     Command line options are:
  32.  
  33.         /a# - use adapter #
  34.         /b# - change the buffer pool size from the default 20K to #
  35.         /o  - options:
  36.             /or# - set receive READ option
  37.             /ot# - set transmit READ option
  38.         /r# - send to remote SAP # (transmitter only)
  39.         /s# - open local SAP #
  40.         /t# - send to station address # (transmitter only)
  41.         /z# - transmit packets of size #, else send random sized packets
  42.               (transmitter only)
  43.  
  44.     Contents:
  45.         main
  46.         usage
  47.         get_funky_number
  48.         is_radical_digit
  49.         char_to_number
  50.         handle_ctrl_c
  51.         terminate
  52.         xtou
  53.         open_adapter
  54.         adapter_status
  55.         close_adapter
  56.         create_buffer
  57.         open_sap
  58.         open_station
  59.         connect_station
  60.         flow_control
  61.         get_buffer
  62.         free_buffer
  63.         post_receive
  64.         post_read
  65.         tx_i_frame
  66.         slush
  67.         do_transmit
  68.         do_receive
  69.         check_keyboard
  70.         dispatch_read_events
  71.         handle_status_change
  72.         handle_receive_data
  73.         handle_transmit_complete
  74.         handle_command_complete
  75.         twiddle_bits
  76.         swap_bits
  77.         my_malloc
  78.         my_calloc
  79.         my_free
  80.         nice_num
  81.  
  82. Author:
  83.  
  84.     Richard L Firth (rfirth) 6-Mar-1994
  85.  
  86. Environment:
  87.  
  88.     Win32 app (console)
  89.  
  90. Revision History:
  91.  
  92.     John Lee (johnlee) 22-Feb-1996
  93.  
  94. --*/
  95.  
  96. #include <stdio.h>
  97. #include <stdlib.h>
  98. #include <string.h>
  99. #include <memory.h>
  100. #include <conio.h>
  101. #include <signal.h>
  102. #undef tolower
  103. #include <windows.h>
  104. #include <dlcapi.h>
  105.  
  106. #include "dlcdebug.h"
  107.  
  108. #ifndef _CRTAPI1
  109. #define _CRTAPI1
  110. #endif
  111.  
  112. #define SIMPLEX_VERSION "1.11"
  113.  
  114. #define RECEIVE_MODE    0
  115. #define TRANSMIT_MODE   1
  116.  
  117. #define DLCBUFSIZE  20000
  118. #define SAP_NUMBER  4
  119. #define RECEIVE_COMPLETE_FLAG   0x50204030
  120. #define RECEIVE_DATA_FLAG       0x50204040
  121. #define TRANSMIT_COMPLETE_FLAG  0x50404030
  122.  
  123. #define TX_STATE_OPENING    1
  124. #define TX_STATE_OPENED     2
  125. #define TX_STATE_TRANSMITTING   3
  126. #define TX_STATE_BUSY       4
  127.  
  128. #define RX_STATE_LISTENING  1
  129. #define RX_STATE_RECEIVING  2
  130. #define RX_STATE_BLOCKED    3
  131.  
  132. #define MAX_OUTSTANDING_TRANSMIT_THRESHOLD  100
  133. #define MIN_OUTSTANDING_TRANSMIT_THRESHOLD  10
  134.  
  135. #define IS_ARG(c)   (((c) == '-') || ((c) == '/'))
  136. #define ZAP(thing)  memset(&thing, 0, sizeof(thing))
  137. #define MALLOC      my_malloc
  138. #define CALLOC      my_calloc
  139. #define FREE        my_free
  140.  
  141. typedef struct {
  142.     DWORD sequence;
  143.     DWORD size;
  144.     DWORD signature;
  145.     DWORD checksum;
  146.     char data[];
  147. } TEST_PACKET, *PTEST_PACKET;
  148.  
  149. void _CRTAPI1 main(int, char**);
  150. void usage(void);
  151. DWORD get_funky_number(char**);
  152. BOOL is_radical_digit(char, DWORD);
  153. DWORD char_to_number(char);
  154. void _CRTAPI1 handle_ctrl_c(int);
  155. void terminate(int);
  156. unsigned char xtou(char);
  157. void open_adapter(void);
  158. unsigned short adapter_status(void);
  159. void close_adapter(void);
  160. void create_buffer(int);
  161. void open_sap(int);
  162. void open_station(void);
  163. void connect_station(unsigned short);
  164. void flow_control(int);
  165. PLLC_BUFFER get_buffer(void);
  166. int free_buffer(PLLC_BUFFER);
  167. void post_receive(void);
  168. PLLC_CCB post_read(void);
  169. void tx_i_frame(void);
  170. DWORD slush(char*, int);
  171. void do_transmit(void);
  172. void do_receive(void);
  173. void check_keyboard(void);
  174. void dispatch_read_events(PLLC_CCB);
  175. void handle_status_change(PLLC_CCB);
  176. void handle_receive_data(PLLC_CCB);
  177. void handle_transmit_complete(PLLC_CCB);
  178. void handle_command_complete(PLLC_CCB);
  179. void twiddle_bits(LPBYTE, DWORD);
  180. unsigned char swap_bits(unsigned char);
  181. void* my_malloc(int);
  182. void* my_calloc(int, int);
  183. void my_free(void*);
  184. char* nice_num(unsigned long);
  185.  
  186. BYTE Adapter = 0;
  187. DWORD BufferPoolSize = DLCBUFSIZE;
  188. BYTE RemoteNode[6];
  189. WORD LocalSap = SAP_NUMBER;
  190. WORD RemoteSap = SAP_NUMBER;
  191. DWORD Mode = RECEIVE_MODE;
  192. BOOL SwapAddressBits = 0;
  193. HANDLE TheMainEvent;
  194. DWORD MaxFrameSize;
  195. DWORD TransmitDataLength = 0;
  196. LPBYTE BufferPool;
  197. HANDLE BufferHandle;
  198. USHORT StationId;
  199. DWORD RxState = 0;
  200. DWORD TxState = 0;
  201. DWORD LocalBusy = 0;
  202. DWORD RemoteBusy = 0;
  203. DWORD Verbose = 0;
  204. DWORD JustBufferInfo = 0;
  205. LONG AllocatedBytesOutstanding = 0;
  206. DWORD TotalBytesAllocated = 0;
  207. DWORD TotalBytesFreed = 0;
  208. LONG OutstandingTransmits = 0;
  209. DWORD DisplayBufferFreeInfo = 1;
  210. DWORD DisplayFrameReceivedInfo = 1;
  211. DWORD DisplayTransmitInfo = 0;
  212. DWORD DisplayCcb = 1;
  213. DWORD TotalTransmits = 0;
  214. DWORD TotalTransmitCompletions = 0;
  215. DWORD TransmitCompleteEvents = 0;
  216. DWORD CommandCompleteEvents = 0;
  217. DWORD StatusChangeEvents = 0;
  218. DWORD ReceiveDataEvents = 0;
  219. DWORD DataFramesReceived = 0;
  220. DWORD DlcBuffersReceived = 0;
  221. DWORD DlcBuffersFreed = 0;
  222. DWORD TotalBytesTransmitted = 0;
  223. DWORD TotalTxBytesCompleted = 0;
  224. DWORD TotalPacketBytesReceived = 0;
  225. DWORD TotalDlcBytesReceived = 0;
  226. DWORD TotalReadsChecked = 0;
  227. DWORD TotalReadEvents = 0;
  228. DWORD MaxChainedReceives = 0;
  229. DWORD MaxChainedTransmits = 0;
  230. DWORD MinBuffersAvailable = 0;
  231. DWORD MaxBuffersAvailable = 0;
  232.  
  233. DWORD LinkLostEvents = 0;
  234. DWORD DiscEvents = 0;
  235. DWORD FrmrReceivedEvents = 0;
  236. DWORD FrmrSentEvents = 0;
  237. DWORD SabmeResetEvents = 0;
  238. DWORD SabmeOpenEvents = 0;
  239. DWORD RemoteBusyEnteredEvents = 0;
  240. DWORD RemoteBusyLeftEvents = 0;
  241. DWORD TiExpiredEvents = 0;
  242. DWORD DlcCounterOverflowEvents = 0;
  243. DWORD AccessPriorityLoweredEvents = 0;
  244. DWORD InvalidStatusChangeEvents = 0;
  245. DWORD LocalBusyEvents = 0;
  246.  
  247. BYTE OptionChainReceiveData = 1;
  248. BYTE OptionChainTransmits = 0;
  249.  
  250. // The application ID is used on Windows 95, but not on Windows NT.
  251.  
  252. BYTE bApplId = 0;
  253.  
  254. void _CRTAPI1 main(int argc, char** argv) {
  255.  
  256.     printf("\nDLC simplex test. Version " SIMPLEX_VERSION " " __DATE__ " " __TIME__ "\n\n");
  257.  
  258.     for (--argc, ++argv; argc; --argc, ++argv) {
  259.         if (IS_ARG(**argv)) {
  260.             switch (tolower(*++*argv)) {
  261.             case 'a':
  262.                 Adapter = atoi(++*argv);
  263.                 break;
  264.  
  265.             case 'b':
  266.                 ++*argv;
  267.                 BufferPoolSize = get_funky_number(argv);
  268.                 break;
  269.  
  270.             case 'h':
  271.             case '?':
  272.                 usage();
  273.  
  274.             case 'o':
  275.                 ++*argv;
  276.                 while (**argv) {
  277.                     switch (tolower(**argv)) {
  278.                     case 'r':
  279.                         ++*argv;
  280.                         OptionChainReceiveData = (BYTE)get_funky_number(argv);
  281.                         break;
  282.  
  283.                     case 't':
  284.                         ++*argv;
  285.                         OptionChainTransmits = (BYTE)get_funky_number(argv);
  286.                         break;
  287.  
  288.                     default:
  289.                         printf("error: unrecognized option '%c'\n", **argv);
  290.                         usage();
  291.                     }
  292.                 }
  293.             case 'r':
  294.                 ++*argv;
  295.                 RemoteSap = (WORD)get_funky_number(argv);
  296.                 break;
  297.  
  298.             case 's':
  299.                 ++*argv;
  300.                 LocalSap = (WORD)get_funky_number(argv);
  301.                 break;
  302.  
  303.             case 't': {
  304.  
  305.                 int i;
  306.                 LPSTR p = ++*argv;
  307.  
  308.                 Mode = TRANSMIT_MODE;
  309.                 if (strlen(p) != 12) {
  310.                     printf("incorrect remote node format (12 hex digits required)\n");
  311.                     usage();
  312.                 }
  313.                 for (i = 0; i < 6; ++i) {
  314.                     RemoteNode[i] = (xtou(*p++) << 4) + xtou(*p++);
  315.                 }
  316.                 break;
  317.             }
  318.  
  319.             case 'v':
  320.                 Verbose = 1;
  321.                 break;
  322.  
  323.             case 'z':
  324.                 ++*argv;
  325.                 TransmitDataLength = get_funky_number(argv);
  326.                 break;
  327.             }
  328.         }
  329.     }
  330.  
  331.     if ((TheMainEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) {
  332.         printf("CreateEvent returns %d\n", GetLastError());
  333.         exit(1);
  334.     }
  335.  
  336.     printf("Running in %s mode.\n\n",
  337.             (Mode == TRANSMIT_MODE) ? "Transmit" : "Receive"
  338.             );
  339.  
  340.     if (Mode == TRANSMIT_MODE) {
  341.         printf("remote node = %02x-%02x-%02x-%02x-%02x-%02x\n",
  342.             RemoteNode[0] & 0xff,
  343.             RemoteNode[1] & 0xff,
  344.             RemoteNode[2] & 0xff,
  345.             RemoteNode[3] & 0xff,
  346.             RemoteNode[4] & 0xff,
  347.             RemoteNode[5] & 0xff
  348.             );
  349.         DisplayTransmitInfo = 1;
  350.     }
  351.     open_adapter();
  352.     MaxFrameSize = min((1500 - (14 + 4)), MaxFrameSize);
  353.     if (TransmitDataLength && (TransmitDataLength > MaxFrameSize)) {
  354.         TransmitDataLength = MaxFrameSize;
  355.     }
  356.     printf("opened adapter %d. maximum frame size = %d\n", Adapter, MaxFrameSize);
  357.     switch (adapter_status()) {
  358.     case 0:
  359.         printf("type of adapter %d is token ring: not flipping hamburgers (nor address bits)\n", Adapter);
  360.         SwapAddressBits = 0;
  361.         break;
  362.  
  363.     case 1:
  364.         printf("type of adapter %d is ethernet: will flip address bits\n", Adapter);
  365.         SwapAddressBits = 1;
  366.         break;
  367.  
  368.     case 2:
  369.         printf("type of adapter %d is PC/Network card: don't know how to handle\n", Adapter);
  370.         terminate(1);
  371.  
  372.     case 3:
  373.         printf("adapter %d is >> UNKNOWN <<. Will assume FDDI and flip bits.\n"
  374.                "If not correct, please fix\n", Adapter);
  375.         printf("hit a key to continue... "); getch(); putchar('\n');
  376.         break;
  377.     }
  378.     create_buffer(BufferPoolSize);
  379.     MinBuffersAvailable = free_buffer(get_buffer());
  380.     printf("created %d byte buffer pool @%x. Handle = %x. Initial buffers = %d\n",
  381.         BufferPoolSize, BufferPool, BufferHandle, MinBuffersAvailable);
  382.     open_sap(LocalSap);
  383.     if (Verbose) {
  384.         printf("opened SAP %d: StationId = %04x\n", LocalSap, StationId);
  385.     }
  386.     signal(SIGINT, handle_ctrl_c);
  387.     if (Mode == TRANSMIT_MODE) {
  388.         if (SwapAddressBits) {
  389.             twiddle_bits(RemoteNode, 6);
  390.         }
  391.         do_transmit();
  392.     } else {
  393.         do_receive();
  394.     }
  395.     terminate(0);
  396. }
  397.  
  398. void usage() {
  399.     printf("usage: simplex [/a#] [/b#] [/h] [/o<option>] [/r#] [/s#] [/t<node>] [/v] [/z#]\n"
  400.            "\n"
  401.            "       /a = adapter number. Default = 0\n"
  402.            "       /b = buffer pool size\n"
  403.            "       /h = this help\n"
  404.            "       /o = options:\n"
  405.            "       /or[#] = chain receive data\n"
  406.            "           0 = do NOT chain\n"
  407.            "           1 = chain on link station basis (DEFAULT)\n"
  408.            "           2 = chain on SAP basis\n"
  409.            "       /ot[#] = chain transmit completions\n"
  410.            "           0 = chain on link station basis (DEFAULT)\n"
  411.            "           1 = do NOT chain\n"
  412.            "           2 = chain on SAP basis\n"
  413.            "       /r = remote SAP number (transmitter)\n"
  414.            "       /s = local SAP number to use\n"
  415.            "       /t = transmit mode\n"
  416.            "       /v = verbose\n"
  417.            "       /z = transmit data length. If omitted, packet size is random\n"
  418.            "\n"
  419.            "<node> is remote node id in correct form for medium\n"
  420.            "default mode is receiver\n"
  421.            "The buffer pool minimum threshold is 25%% of the buffer pool size\n"
  422.            "\n"
  423.            );
  424.     exit(1);
  425. }
  426.  
  427. DWORD get_funky_number(char** string) {
  428.  
  429.     DWORD radix = 10;
  430.     char* p = *string;
  431.     DWORD num = 0, sign=1;
  432.  
  433.     if (!*p) {
  434.         return 0;
  435.     }
  436.  
  437.     if (*p=='-') {
  438.         sign = (DWORD)-1;
  439.         p++;
  440.     }
  441.  
  442.     if (!strnicmp(p, "0x", 2)) {
  443.         p += 2;
  444.         radix = 16;
  445.     }
  446.  
  447.     while (is_radical_digit(*p, radix)) {
  448.         num = num * radix + char_to_number(*p);
  449.         ++p;
  450.     }
  451.  
  452.     if (toupper(*p) == 'K') {
  453.         if (radix == 10) {
  454.             ++p;
  455.             num *= 1024;
  456.         } else {
  457.             *string = NULL;
  458.             return 0;
  459.         }
  460.     }
  461.     *string = p;
  462.     return sign * num;
  463. }
  464.  
  465. BOOL is_radical_digit(char possible_digit, DWORD radix) {
  466.     return (radix == 16) ? isxdigit(possible_digit) : isdigit(possible_digit);
  467. }
  468.  
  469. DWORD char_to_number(char character) {
  470.     if (isdigit(character)) {
  471.         return (DWORD)(character - '0');
  472.     } else {
  473.         return (DWORD)(toupper(character) - 'A') + 10;
  474.     }
  475. }
  476.  
  477. void _CRTAPI1 handle_ctrl_c(int sig) {
  478.  
  479.     char ch;
  480.  
  481.     printf("\a\n"
  482.            "Interrupted from console (control-c detected)\n"
  483.            "Quit program? [Y/N] "
  484.            );
  485.     do {
  486.         ch = tolower(getch());
  487.         if (ch != 'y' && ch != 'n') {
  488.             putchar('\a');
  489.         }
  490.     } while ( ch != 'y' && ch != 'n' );
  491.     putchar(ch);
  492.     putchar('\n');
  493.     if (ch == 'y') {
  494.         terminate(1);
  495.     }
  496.     signal(SIGINT, handle_ctrl_c);
  497. }
  498.  
  499. void terminate(int exit_code) {
  500.  
  501.     close_adapter();
  502.  
  503.     printf("\nterminating %s mode\n", (Mode == TRANSMIT_MODE) ? "transmit" : "receive");
  504.  
  505.     printf("\n"
  506.            "Memory statistics:\n");
  507.     printf("\tAllocatedBytesOutstanding    = %s\n", nice_num(AllocatedBytesOutstanding));
  508.     printf("\tTotalBytesAllocated          = %s\n", nice_num(TotalBytesAllocated));
  509.     printf("\tTotalBytesFreed              = %s\n", nice_num(TotalBytesFreed));
  510.  
  511.     printf("\n"
  512.            "Buffer statistics:\n");
  513.     printf("\tMinBuffersAvailable          = %s\n", nice_num(MinBuffersAvailable));
  514.     printf("\tMaxBuffersAvailable          = %s\n", nice_num(MaxBuffersAvailable));
  515.     printf("\tDlcBuffersFreed              = %s\n", nice_num(DlcBuffersFreed));
  516.  
  517.     printf("\n"
  518.            "READ statistics:\n");
  519.     printf("\tTotalReadsChecked            = %s\n", nice_num(TotalReadsChecked));
  520.     printf("\tTotalReadEvents              = %s\n", nice_num(TotalReadEvents));
  521.     printf("\tCommandCompleteEvents        = %s\n", nice_num(CommandCompleteEvents));
  522.     printf("\tTransmitCompleteEvents       = %s\n", nice_num(TransmitCompleteEvents));
  523.     printf("\tReceiveDataEvents            = %s\n", nice_num(ReceiveDataEvents));
  524.     printf("\tStatusChangeEvents           = %s\n", nice_num(StatusChangeEvents));
  525.  
  526.     if (Mode == TRANSMIT_MODE) {
  527.         printf("\n"
  528.                "Transmit statistics:\n");
  529.         printf("\tTotalTransmits               = %s\n", nice_num(TotalTransmits));
  530.         printf("\tTotalTransmitCompletions     = %s\n", nice_num(TotalTransmitCompletions));
  531.         printf("\tOutstandingTransmits         = %s\n", nice_num(OutstandingTransmits));
  532.         printf("\tTotalBytesTransmitted        = %s\n", nice_num(TotalBytesTransmitted));
  533.         printf("\tTotalTxBytesCompleted        = %s\n", nice_num(TotalTxBytesCompleted));
  534.         printf("\tMaxChainedTransmits          = %s\n", nice_num(MaxChainedTransmits));
  535.     } else {
  536.         printf("\n"
  537.                "Receive statistics:\n");
  538.         printf("\tDataFramesReceived           = %s\n", nice_num(DataFramesReceived));
  539.         printf("\tDlcBuffersReceived           = %s\n", nice_num(DlcBuffersReceived));
  540.         printf("\tTotalPacketBytesReceived     = %s\n", nice_num(TotalPacketBytesReceived));
  541.         printf("\tTotalDlcBytesReceived        = %s\n", nice_num(TotalDlcBytesReceived));
  542.         printf("\tMaxChainedReceives           = %s\n", nice_num(MaxChainedReceives));
  543.     }
  544.  
  545.     printf("\n"
  546.            "Status change statistics:\n");
  547.     printf("\tLinkLostEvents               = %s\n", nice_num(LinkLostEvents));
  548.     printf("\tDiscEvents                   = %s\n", nice_num(DiscEvents));
  549.     printf("\tFrmrReceivedEvents           = %s\n", nice_num(FrmrReceivedEvents));
  550.     printf("\tFrmrSentEvents               = %s\n", nice_num(FrmrSentEvents));
  551.     printf("\tSabmeResetEvents             = %s\n", nice_num(SabmeResetEvents));
  552.     printf("\tSabmeOpenEvents              = %s\n", nice_num(SabmeOpenEvents));
  553.     printf("\tRemoteBusyEnteredEvents      = %s\n", nice_num(RemoteBusyEnteredEvents));
  554.     printf("\tRemoteBusyLeftEvents         = %s\n", nice_num(RemoteBusyLeftEvents));
  555.     printf("\tTiExpiredEvents              = %s\n", nice_num(TiExpiredEvents));
  556.     printf("\tDlcCounterOverflowEvents     = %s\n", nice_num(DlcCounterOverflowEvents));
  557.     printf("\tAccessPriorityLoweredEvents  = %s\n", nice_num(AccessPriorityLoweredEvents));
  558.     printf("\tInvalidStatusChangeEvents    = %s\n", nice_num(InvalidStatusChangeEvents));
  559.     printf("\tLocalBusyEvents              = %s\n", nice_num(LocalBusyEvents));
  560.  
  561.     exit(exit_code);
  562. }
  563.  
  564. unsigned char xtou(char ch) {
  565.     return ((ch >= '0') && (ch <= '9'))
  566.         ? (unsigned char)(ch - '0')
  567.         : ((ch >= 'A') && (ch <= 'F'))
  568.             ? (unsigned char)((ch - 'A') + 10)
  569.             : (unsigned char)((ch - 'a') + 10);
  570. }
  571.  
  572. void open_adapter() {
  573.  
  574.     LLC_CCB ccb;
  575.     LLC_DIR_OPEN_ADAPTER_PARMS parms;
  576.     LLC_ADAPTER_OPEN_PARMS adapterParms;
  577.     LLC_DLC_PARMS dlcParms;
  578.     LLC_EXTENDED_ADAPTER_PARMS extendedParms;
  579.     LLC_STATUS status;
  580.  
  581.     ZAP(ccb);
  582.     ZAP(adapterParms);
  583.     ZAP(dlcParms);
  584.     ZAP(extendedParms);
  585.  
  586.     parms.pAdapterParms = &adapterParms;
  587.     parms.pExtendedParms = &extendedParms;
  588.     parms.pDlcParms = &dlcParms;
  589.  
  590.     ccb.uchAdapterNumber = Adapter;
  591.     ccb.uchDlcCommand = LLC_DIR_OPEN_ADAPTER;
  592.     ccb.u.pParameterTable = (PLLC_PARMS)&parms;
  593.     ccb.hCompletionEvent = TheMainEvent;
  594.     ResetEvent(TheMainEvent);
  595.  
  596.     status = AcsLan(&ccb, NULL);
  597.     if (status != ACSLAN_STATUS_COMMAND_ACCEPTED) {
  598.         printf("open_adapter: AcsLan returns %d [%#.2x]\n",
  599.             status, ccb.uchDlcStatus);
  600.         puts(MapCcbRetcode(ccb.uchDlcStatus));
  601.         terminate(1);
  602.     }
  603.     status = WaitForSingleObject(TheMainEvent, INFINITE);
  604.     if (status != WAIT_OBJECT_0) {
  605.         printf("open_adapter: WaitForSingleObject returns %d [%d]\n",
  606.             status, GetLastError());
  607.         terminate(1);
  608.     }
  609.     if (ccb.uchDlcStatus) {
  610.         printf("open_adapter: DLC returns %#.2x\n", ccb.uchDlcStatus);
  611.         puts(MapCcbRetcode(ccb.uchDlcStatus));
  612.         terminate(1);
  613.     }
  614.     bApplId = ccb.uchReserved2;
  615.     MaxFrameSize = adapterParms.usMaxFrameSize;
  616. }
  617.  
  618. unsigned short adapter_status() {
  619.  
  620.     LLC_CCB ccb;
  621.     LLC_DIR_STATUS_PARMS parms;
  622.     ACSLAN_STATUS status;
  623.  
  624.     ZAP(ccb);
  625.     ZAP(parms);
  626.  
  627.     ccb.uchAdapterNumber = Adapter;
  628.     ccb.uchDlcCommand = LLC_DIR_STATUS;
  629.     ccb.u.pParameterTable = (PLLC_PARMS)&parms;
  630.     ccb.hCompletionEvent = TheMainEvent;
  631.     ResetEvent(TheMainEvent);
  632.     ccb.uchReserved2 = bApplId;
  633.  
  634.     status = AcsLan(&ccb, NULL);
  635.     if (status != ACSLAN_STATUS_COMMAND_ACCEPTED) {
  636.         printf("adapter_status: AcsLan returns %d [%#.2x]\n",
  637.             status, ccb.uchDlcStatus);
  638.         puts(MapCcbRetcode(ccb.uchDlcStatus));
  639.         terminate(1);
  640.     }
  641.     status = WaitForSingleObject(TheMainEvent, INFINITE);
  642.     if (status != WAIT_OBJECT_0) {
  643.         printf("adapter_status: WaitForSingleObject returns %d [%d]\n",
  644.             status, GetLastError());
  645.         terminate(1);
  646.     }
  647.     if (ccb.uchDlcStatus) {
  648.         printf("adapter_status: DLC returns %#.2x\n", ccb.uchDlcStatus);
  649.         puts(MapCcbRetcode(ccb.uchDlcStatus));
  650.         terminate(1);
  651.     }
  652.     switch (parms.usAdapterType) {
  653.     case 0x0001:    // Token Ring Network PC Adapter
  654.     case 0x0002:    // Token Ring Network PC Adapter II
  655.     case 0x0004:    // Token Ring Network Adapter/A
  656.     case 0x0008:    // Token Ring Network PC Adapter II
  657.     case 0x0020:    // Token Ring Network 16/4 Adapter
  658.     case 0x0040:    // Token Ring Network 16/4 Adapter/A
  659.     case 0x0080:    // Token Ring Network Adapter/A
  660.         return 0;
  661.  
  662.     case 0x0100:    // Ethernet Adapter
  663.         return 1;
  664.  
  665.     case 0x4000:    // PC Network Adapter
  666.     case 0x8000:    // PC Network Adapter/A
  667.         return 2;
  668.     }
  669.     return 3;   // unknown
  670. }
  671.  
  672. void close_adapter() {
  673.  
  674.     LLC_CCB ccb;
  675.     ACSLAN_STATUS status;
  676.  
  677.     ZAP(ccb);
  678.  
  679.     ccb.uchAdapterNumber = Adapter;
  680.     ccb.uchDlcCommand = LLC_DIR_CLOSE_ADAPTER;
  681.     ccb.hCompletionEvent = TheMainEvent;
  682.     ResetEvent(TheMainEvent);
  683.     ccb.uchReserved2 = bApplId;
  684.  
  685.     status = AcsLan(&ccb, NULL);
  686.     if (status != ACSLAN_STATUS_COMMAND_ACCEPTED) {
  687.         printf("close_adapter: AcsLan returns %d [%#.2x]\n",
  688.             status, ccb.uchDlcStatus);
  689.         terminate(1);
  690.     }
  691.     status = WaitForSingleObject(TheMainEvent, INFINITE);
  692.     if (status != WAIT_OBJECT_0) {
  693.         printf("close_adapter: WaitForSingleObject returns %d [%d]\n",
  694.             status, GetLastError());
  695.         terminate(1);
  696.     }
  697.     if (ccb.uchDlcStatus) {
  698.         printf("close_adapter: DLC returns %#.2x\n", ccb.uchDlcStatus);
  699.         puts(MapCcbRetcode(ccb.uchDlcStatus));
  700.         terminate(1);
  701.     }
  702. }
  703.  
  704. void create_buffer(int buflen) {
  705.  
  706.     LLC_CCB ccb;
  707.     LLC_BUFFER_CREATE_PARMS parms;
  708.     LPBYTE buffer;
  709.     LLC_STATUS status;
  710.  
  711.     ZAP(ccb);
  712.     ZAP(parms);
  713.  
  714.     buffer = MALLOC(buflen);
  715.  
  716.     parms.pBuffer = buffer;
  717.     parms.cbBufferSize = buflen;
  718.     parms.cbMinimumSizeThreshold = buflen / 4;
  719.  
  720.     ccb.uchAdapterNumber = Adapter;
  721.     ccb.uchDlcCommand = LLC_BUFFER_CREATE;
  722.     ccb.u.pParameterTable = (PLLC_PARMS)&parms;
  723.     ccb.hCompletionEvent = TheMainEvent;
  724.     ResetEvent(TheMainEvent);
  725.     ccb.uchReserved2 = bApplId;
  726.  
  727.  
  728.     status = AcsLan(&ccb, NULL);
  729.     if (status != ACSLAN_STATUS_COMMAND_ACCEPTED || ccb.uchDlcStatus) {
  730.         printf("create_buffer: AcsLan returns %d [%#.2x]\n",
  731.             status, ccb.uchDlcStatus);
  732.         puts(MapCcbRetcode(ccb.uchDlcStatus));
  733.         terminate(1);
  734.     }
  735.     status = WaitForSingleObject(TheMainEvent, INFINITE);
  736.     if (status != WAIT_OBJECT_0) {
  737.         printf("create_buffer: WaitForSingleObject returns %d [%d]\n",
  738.             status, GetLastError());
  739.         terminate(1);
  740.     }
  741.     if (ccb.uchDlcStatus) {
  742.         printf("create_buffer: DLC returns %#.2x\n", ccb.uchDlcStatus);
  743.         puts(MapCcbRetcode(ccb.uchDlcStatus));
  744.         terminate(1);
  745.     }
  746.     BufferHandle = parms.hBufferPool;
  747.     BufferPool = buffer;
  748. }
  749.  
  750. void open_sap(int sap) {
  751.  
  752.     LLC_CCB ccb;
  753.     LLC_DLC_OPEN_SAP_PARMS parms;
  754.     LLC_STATUS status;
  755.  
  756.     ZAP(ccb);
  757.     ZAP(parms);
  758.  
  759.     ccb.uchAdapterNumber = Adapter;
  760.     ccb.uchDlcCommand = LLC_DLC_OPEN_SAP;
  761.     ccb.u.pParameterTable = (PLLC_PARMS)&parms;
  762.     ccb.hCompletionEvent = TheMainEvent;
  763.     ResetEvent(TheMainEvent);
  764.     ccb.uchReserved2 = bApplId;
  765.  
  766.  
  767.     parms.uchSapValue = (UCHAR)sap;
  768.     parms.uchOptionsPriority = LLC_INDIVIDUAL_SAP;
  769.     parms.uchcStationCount = 1;
  770.     // Set this to non-0 so event will be signalled.
  771.     // The ibm specs mandate that.
  772.     parms.DlcStatusFlags = 1;         // non-0 to get signalled - johnlee
  773.  
  774.     status = AcsLan(&ccb, NULL);
  775.     if (status != ACSLAN_STATUS_COMMAND_ACCEPTED || ccb.uchDlcStatus) {
  776.         printf("open_sap: AcsLan returns %d [%#.2x]\n",
  777.             status, ccb.uchDlcStatus);
  778.         terminate(1);
  779.     }
  780.     status = WaitForSingleObject(TheMainEvent, INFINITE);
  781.     if (status != WAIT_OBJECT_0) {
  782.         printf("open_sap: WaitForSingleObject returns %d [%d]\n",
  783.             status, GetLastError());
  784.         terminate(1);
  785.     }
  786.     if (ccb.uchDlcStatus) {
  787.         printf("open_sap: DLC returns %#.2x\n", ccb.uchDlcStatus);
  788.         puts(MapCcbRetcode(ccb.uchDlcStatus));
  789.         terminate(1);
  790.     }
  791.     StationId = parms.usStationId;
  792. }
  793.  
  794. void open_station() {
  795.  
  796.     LLC_CCB ccb;
  797.     LLC_DLC_OPEN_STATION_PARMS parms;
  798.     LLC_STATUS status;
  799.  
  800.     ZAP(ccb);
  801.     ZAP(parms);
  802.  
  803.     // This should not be LocalSap. Read the specs. -- johnlee
  804.     parms.usSapStationId = StationId; //(USHORT)LocalSap << 8;
  805.     parms.uchRemoteSap = (UCHAR)RemoteSap;
  806.     parms.pRemoteNodeAddress = (PVOID)RemoteNode;
  807.  
  808.     ccb.uchAdapterNumber = Adapter;
  809.     ccb.uchDlcCommand = LLC_DLC_OPEN_STATION;
  810.     ccb.u.pParameterTable = (PLLC_PARMS)&parms;
  811.     ccb.hCompletionEvent = TheMainEvent;
  812.     ResetEvent(TheMainEvent);
  813.     ccb.uchReserved2 = bApplId;
  814.  
  815.  
  816.     status = AcsLan(&ccb, NULL);
  817.     if (status != ACSLAN_STATUS_COMMAND_ACCEPTED || ccb.uchDlcStatus) {
  818.         printf("open_station: AcsLan returns %d [%#.2x]\n",
  819.             status, ccb.uchDlcStatus);
  820.         terminate(1);
  821.     }
  822.     status = WaitForSingleObject(TheMainEvent, INFINITE);
  823.     if (status != WAIT_OBJECT_0) {
  824.         printf("open_station: WaitForSingleObject returns %d [%d]\n",
  825.             status, GetLastError());
  826.         terminate(1);
  827.     }
  828.     if (ccb.uchDlcStatus) {
  829.         printf("open_station: DLC returns %#.2x\n", ccb.uchDlcStatus);
  830.         puts(MapCcbRetcode(ccb.uchDlcStatus));
  831.         terminate(1);
  832.     }
  833.     StationId = parms.usLinkStationId;
  834. }
  835.  
  836. void connect_station(unsigned short station) {
  837.  
  838.     LLC_CCB ccb;
  839.     LLC_DLC_CONNECT_PARMS parms;
  840.     ACSLAN_STATUS status;
  841.  
  842.     ZAP(ccb);
  843.     ZAP(parms);
  844.  
  845.     parms.usStationId = station;
  846.  
  847.     ccb.uchAdapterNumber = Adapter;
  848.     ccb.uchDlcCommand = LLC_DLC_CONNECT_STATION;
  849.     ccb.u.pParameterTable = (PLLC_PARMS)&parms;
  850.     ccb.hCompletionEvent = TheMainEvent;
  851.     ResetEvent(TheMainEvent);
  852.     ccb.uchReserved2 = bApplId;
  853.  
  854.  
  855.     status = AcsLan(&ccb, NULL);
  856.     if (status != ACSLAN_STATUS_COMMAND_ACCEPTED) {
  857.         printf("connect_station: AcsLan returns %d [%#.2x]\n",
  858.             status, ccb.uchDlcStatus);
  859.         terminate(1);
  860.     }
  861.     status = WaitForSingleObject(TheMainEvent, INFINITE);
  862.     if (status != WAIT_OBJECT_0) {
  863.         printf("connect_station: WaitForSingleObject returns %d [%d]\n",
  864.             status, GetLastError());
  865.         terminate(1);
  866.     }
  867.     if (ccb.uchDlcStatus) {
  868.         printf("connect_station: DLC returns %#.2x\n", ccb.uchDlcStatus);
  869.         puts(MapCcbRetcode(ccb.uchDlcStatus));
  870.         terminate(1);
  871.     }
  872.     if (Verbose) {
  873.         printf("connect_station: OK\n");
  874.     }
  875. }
  876.  
  877. void flow_control(int station) {
  878.  
  879.     LLC_CCB ccb;
  880.     ACSLAN_STATUS status;
  881.  
  882.     ZAP(ccb);
  883.  
  884.     ccb.uchAdapterNumber = Adapter;
  885.     ccb.uchDlcCommand = LLC_DLC_FLOW_CONTROL;
  886.     ccb.u.dlc.usStationId = station;
  887.     ccb.u.dlc.usParameter = 0xc0;
  888.     ccb.hCompletionEvent = TheMainEvent;
  889.     ResetEvent(TheMainEvent);
  890.     ccb.uchReserved2 = bApplId;
  891.  
  892.  
  893.     if (Verbose) {
  894.         printf("flow_control(%04x, c0)\n", station);
  895.     }
  896.     status = AcsLan(&ccb, NULL);
  897.     if (status != ACSLAN_STATUS_COMMAND_ACCEPTED) {
  898.         printf("flow_control: AcsLan returns %d [%#.2x]\n",
  899.             status, ccb.uchDlcStatus);
  900.         terminate(1);
  901.     }
  902.     status = WaitForSingleObject(TheMainEvent, INFINITE);
  903.     if (status != WAIT_OBJECT_0) {
  904.         printf("flow_control: WaitForSingleObject returns %d [%d]\n",
  905.             status, GetLastError());
  906.         terminate(1);
  907.     }
  908.     if (ccb.uchDlcStatus) {
  909.         printf("flow_control: DLC returns %#.2x\n", ccb.uchDlcStatus);
  910.         puts(MapCcbRetcode(ccb.uchDlcStatus));
  911.         terminate(1);
  912.     }
  913.     if (Verbose) {
  914.         printf("flow_control: OK\n");
  915.     }
  916.     LocalBusy = 0;
  917. }
  918.  
  919. PLLC_BUFFER get_buffer() {
  920.  
  921.     LLC_CCB ccb;
  922.     LLC_BUFFER_GET_PARMS parms;
  923.     ACSLAN_STATUS status;
  924.  
  925.     ZAP(ccb);
  926.     ZAP(parms);
  927.  
  928.     parms.cBuffersToGet = 1;
  929.     parms.cbBufferSize = 256;
  930.  
  931.     ccb.uchAdapterNumber = Adapter;
  932.     ccb.uchDlcCommand = LLC_BUFFER_GET;
  933.     ccb.u.pParameterTable = (PLLC_PARMS)&parms;
  934.     ccb.hCompletionEvent = TheMainEvent;
  935.     ResetEvent(TheMainEvent);
  936.     ccb.uchReserved2 = bApplId;
  937.  
  938.  
  939.     status = AcsLan(&ccb, NULL);
  940.     if (status != ACSLAN_STATUS_COMMAND_ACCEPTED) {
  941.         printf("get_buffer(): AcsLan returns %d [%#.2x]\n", status, ccb.uchDlcStatus);
  942.         //terminate(1);
  943.         return NULL;
  944.     }
  945.     if (WaitForSingleObject(TheMainEvent, INFINITE) != WAIT_OBJECT_0) {
  946.         printf("get_buffer: WaitForSingleObject returns %d\n", GetLastError());
  947.         terminate(1);
  948.     }
  949.     if (ccb.uchDlcStatus) {
  950.         printf("get_buffer: DLC returns %#.2x\n", ccb.uchDlcStatus);
  951.         puts(MapCcbRetcode(ccb.uchDlcStatus));
  952.         terminate(1);
  953.     }
  954.     if (parms.cBuffersLeft < MinBuffersAvailable) {
  955.         MinBuffersAvailable = parms.cBuffersLeft;
  956.     }
  957.     if (parms.cBuffersLeft > MaxBuffersAvailable) {
  958.         MaxBuffersAvailable = parms.cBuffersLeft;
  959.     }
  960.     return (PLLC_BUFFER)parms.pFirstBuffer;
  961. }
  962.  
  963. int free_buffer(PLLC_BUFFER buffer) {
  964.  
  965.     LLC_CCB ccb;
  966.     LLC_BUFFER_FREE_PARMS parms;
  967.     ACSLAN_STATUS status;
  968.  
  969.     if (!buffer) {
  970.  
  971.         //
  972.         // microhackette in case get_buffer failed
  973.         //
  974.  
  975.         return 0;
  976.     }
  977.  
  978.     ZAP(ccb);
  979.     ZAP(parms);
  980.  
  981.     parms.pFirstBuffer = (PLLC_XMIT_BUFFER)buffer;
  982.  
  983.     ccb.uchAdapterNumber = Adapter;
  984.     ccb.uchDlcCommand = LLC_BUFFER_FREE;
  985.     ccb.u.pParameterTable = (PLLC_PARMS)&parms;
  986.     ccb.hCompletionEvent = TheMainEvent;
  987.     ResetEvent(TheMainEvent);
  988.     ccb.uchReserved2 = bApplId;
  989.  
  990.  
  991.     status = AcsLan(&ccb, NULL);
  992.     if (status != ACSLAN_STATUS_COMMAND_ACCEPTED) {
  993.         printf("free_buffer(%x): AcsLan returns %d [%#.2x]\n", buffer, status, ccb.uchDlcStatus);
  994.         terminate(1);
  995.     }
  996.     if (WaitForSingleObject(TheMainEvent, INFINITE) != WAIT_OBJECT_0) {
  997.         printf("free_buffer: WaitForSingleObject returns %d\n", GetLastError());
  998.         terminate(1);
  999.     }
  1000.     if (ccb.uchDlcStatus) {
  1001.         printf("free_buffer(%#x): DLC returns %#.2x\n", buffer, ccb.uchDlcStatus);
  1002.         puts(MapCcbRetcode(ccb.uchDlcStatus));
  1003.         terminate(1);
  1004.     }
  1005.     if (DisplayBufferFreeInfo) {
  1006.         printf("free_buffer(%x): %u buffers left\n", buffer, parms.cBuffersLeft);
  1007.     }
  1008.     if (parms.cBuffersLeft < MinBuffersAvailable) {
  1009.         MinBuffersAvailable = parms.cBuffersLeft;
  1010.     }
  1011.     if (parms.cBuffersLeft > MaxBuffersAvailable) {
  1012.         MaxBuffersAvailable = parms.cBuffersLeft;
  1013.     }
  1014.     return parms.cBuffersLeft;
  1015. }
  1016.  
  1017. void post_receive() {
  1018.  
  1019.     PLLC_CCB pccb;
  1020.     PLLC_RECEIVE_PARMS pparms;
  1021.     ACSLAN_STATUS status;
  1022.  
  1023.     pccb = CALLOC(1, sizeof(*pccb));
  1024.     pparms = CALLOC(1, sizeof(*pparms));
  1025.  
  1026.     pparms->usStationId = StationId;
  1027.     pparms->ulReceiveFlag = RECEIVE_DATA_FLAG;
  1028.     pparms->uchRcvReadOption = OptionChainReceiveData;
  1029.  
  1030.     pccb->uchAdapterNumber = Adapter;
  1031.     pccb->uchDlcCommand = LLC_RECEIVE;
  1032.     pccb->ulCompletionFlag = RECEIVE_COMPLETE_FLAG;
  1033.     pccb->u.pParameterTable = (PLLC_PARMS)pparms;
  1034.     pccb->uchReserved2 = bApplId;
  1035.  
  1036.  
  1037.     status = AcsLan(pccb, NULL);
  1038.     if (status != ACSLAN_STATUS_COMMAND_ACCEPTED) {
  1039.         printf("post_receive: AcsLan returns %d [%#.2x]\n", status, pccb->uchDlcStatus);
  1040.         terminate(1);
  1041.     }
  1042.     if (pccb->uchDlcStatus != 0xFF) {
  1043.         printf("post_receive: CCB.RETCODE = %#.2x\n", pccb->uchDlcStatus);
  1044.         puts(MapCcbRetcode(pccb->uchDlcStatus));
  1045.         terminate(1);
  1046.     }
  1047.     if (Verbose) {
  1048.         printf("receive posted on station %04x\n", StationId);
  1049.     }
  1050. }
  1051.  
  1052. PLLC_CCB post_read() {
  1053.  
  1054.     PLLC_CCB pccb;
  1055.     PLLC_READ_PARMS pparms;
  1056.     ACSLAN_STATUS status;
  1057.  
  1058.     pccb = CALLOC(1, sizeof(*pccb));
  1059.     pparms = CALLOC(1, sizeof(*pparms));
  1060.  
  1061.     pparms->usStationId = StationId;
  1062.     pparms->uchOptionIndicator = 2; // retrieve ALL events for this app
  1063.     pparms->uchEventSet = 0x7f;     // interested in ALL possible events
  1064.  
  1065.    
  1066.  pccb->uchAdapterNumber = Adapter;
  1067.     pccb->uchDlcCommand = LLC_READ;
  1068.     pccb->u.pParameterTable = (PLLC_PARMS)pparms;
  1069.     pccb->hCompletionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  1070.     if (!pccb->hCompletionEvent) {
  1071.         printf("post_read: CreateEvent returns %d\n", GetLastError());
  1072.         terminate(1);
  1073.     }
  1074.  
  1075.     pccb->uchReserved2 = bApplId;
  1076.  
  1077.     status = AcsLan(pccb, NULL);
  1078.     if (status != ACSLAN_STATUS_COMMAND_ACCEPTED) {
  1079.         printf("post_read: AcsLan returns %d [%#.2x]\n", status, pccb->uchDlcStatus);
  1080.         terminate(1);
  1081.     }
  1082.     return pccb;
  1083. }
  1084.  
  1085. void tx_i_frame() {
  1086.  
  1087.     PLLC_CCB pccb;
  1088.     PLLC_TRANSMIT_PARMS pparms;
  1089.     ACSLAN_STATUS status;
  1090.     int data_size;
  1091.     PTEST_PACKET packet;
  1092.  
  1093.     static DWORD PacketSequenceNumber = 0;
  1094.  
  1095.     pccb = CALLOC(1, sizeof(*pccb));
  1096.     pparms = CALLOC(1, sizeof(*pparms));
  1097.  
  1098.     data_size = TransmitDataLength
  1099.               ? TransmitDataLength
  1100.               : (rand() * 600) / RAND_MAX;    
  1101.               // since this app does not specify max i-frame
  1102.               // 600 will be used by windows dlc32 as specified by
  1103.               // the ibm dlc specs -- johnlee
  1104.               //: (rand() * MaxFrameSize) / RAND_MAX;
  1105.     data_size = max(data_size, sizeof(TEST_PACKET));
  1106.  
  1107.     packet = (PTEST_PACKET)MALLOC(data_size);
  1108.     packet->sequence = PacketSequenceNumber++;
  1109.     packet->size = data_size;
  1110.     packet->signature = 0x11191962;
  1111.  
  1112.     packet->checksum = slush(packet->data, data_size - sizeof(TEST_PACKET));
  1113.  
  1114.     pparms->usStationId = StationId;
  1115.     pparms->cbBuffer1 = data_size;
  1116.     pparms->pBuffer1 = packet;
  1117.     pparms->uchXmitReadOption = OptionChainTransmits;
  1118.  
  1119.     pccb->uchAdapterNumber = Adapter;
  1120.     pccb->uchDlcCommand = LLC_TRANSMIT_I_FRAME;
  1121.     pccb->ulCompletionFlag = TRANSMIT_COMPLETE_FLAG;
  1122.     pccb->u.pParameterTable = (PLLC_PARMS)pparms;
  1123.  
  1124.     pccb->uchReserved2 = bApplId;
  1125.  
  1126.  
  1127.     status = AcsLan(pccb, NULL);
  1128.  
  1129.     //
  1130.     // this may fail with 0x69 (or maybe 0xa1) if the system is out of MDL
  1131.     // resources. This can happen if we have a lot of completed transmits
  1132.     // waiting to be deallocated. In this case just deallocate resources and
  1133.     // return - do_transmit should spin removing completed transmits until we
  1134.     // can continue
  1135.     //
  1136.  
  1137.     if (status != ACSLAN_STATUS_COMMAND_ACCEPTED) {
  1138.         printf("tx_i_frame: AcsLan returns %d [%#.2x]\n",
  1139.                status,
  1140.                pccb->uchDlcStatus
  1141.                );
  1142.         puts(MapCcbRetcode(pccb->uchDlcStatus));
  1143.         printf("AllocatedBytesOutstanding = %s [%#x]\n",
  1144.                 nice_num(AllocatedBytesOutstanding),
  1145.                 AllocatedBytesOutstanding
  1146.                 );
  1147.         printf("TotalBytesAllocated       = %s [%#x]\n",
  1148.                 nice_num(TotalBytesAllocated)
  1149.                 , TotalBytesAllocated
  1150.                 );
  1151.         printf("OutstandingTransmits      = %s\n",
  1152.                 nice_num(OutstandingTransmits)
  1153.                 );
  1154.         printf("TotalTransmits            = %s\n",
  1155.                 nice_num(TotalTransmits)
  1156.                 );
  1157.         printf("TotalTransmitCompletions  = %s\n",
  1158.                 nice_num(TotalTransmitCompletions)
  1159.                 );
  1160.         printf("TransmitCompleteEvents    = %s\n",
  1161.                 nice_num(TransmitCompleteEvents)
  1162.                 );
  1163.         if (DisplayCcb) {
  1164.             DUMPCCB(pccb, TRUE, FALSE);
  1165.         }
  1166.         FREE(packet);
  1167.         FREE(pparms);
  1168.         FREE(pccb);
  1169.         --PacketSequenceNumber; // didn't tx this sequence #
  1170.     } else {
  1171.         if (Verbose) {
  1172.             printf("tx_i_frame: transmitted %4d bytes\n", data_size);
  1173.         }
  1174.         ++OutstandingTransmits;
  1175.         ++TotalTransmits;
  1176.         TotalBytesTransmitted += (DWORD)data_size;
  1177.     }
  1178. }
  1179.  
  1180. DWORD slush(char* buffer, int length) {
  1181.  
  1182.     DWORD cs = 0;
  1183.     unsigned char ch;
  1184.  
  1185.     while (length--) {
  1186.         ch = (unsigned char)(rand() & 0xff);
  1187.         *buffer++ = ch;
  1188.         cs += (DWORD)ch;
  1189.     }
  1190.     return cs;
  1191. }
  1192.  
  1193. void do_transmit() {
  1194.  
  1195.     PLLC_CCB read_ccb;
  1196.     BOOL need_read = TRUE;
  1197.     BOOL wait_min = FALSE;
  1198.  
  1199.     TxState = TX_STATE_OPENING;
  1200.     open_station();
  1201.     if (Verbose) {
  1202.         printf("opened link station. StationId = %04x\n", StationId);
  1203.     }
  1204.     connect_station(StationId);
  1205.     TxState = TX_STATE_OPENED;
  1206.     if (Verbose) {
  1207.         printf("connected to remote\n");
  1208.     }
  1209.  
  1210.     while (1) {
  1211.         if (need_read) {
  1212.             read_ccb = post_read();
  1213.             need_read = FALSE;
  1214.         }
  1215.         if (WaitForSingleObject(read_ccb->hCompletionEvent, 0) == WAIT_OBJECT_0) {
  1216.             dispatch_read_events(read_ccb);
  1217.             need_read = TRUE;
  1218.         }
  1219.         if (wait_min) {
  1220.             if (OutstandingTransmits <= MIN_OUTSTANDING_TRANSMIT_THRESHOLD) {
  1221.                 wait_min = FALSE;
  1222.             }
  1223.         } else if (OutstandingTransmits > MAX_OUTSTANDING_TRANSMIT_THRESHOLD) {
  1224.             if (Verbose) {
  1225.                 printf("do_transmit: not transmitting: outstanding transmits (%d) > threshold (%d)\n",
  1226.                     OutstandingTransmits, MAX_OUTSTANDING_TRANSMIT_THRESHOLD);
  1227.             }
  1228.             wait_min = TRUE;
  1229.         } else if (RemoteBusy) {
  1230.             if (Verbose) {
  1231.                 printf("do_transmit: not transmitting: remote busy\n");
  1232.             }
  1233.             Sleep(100);
  1234.         } else {
  1235.             tx_i_frame();
  1236.         }
  1237.         check_keyboard();
  1238.     }
  1239. }
  1240.  
  1241. void do_receive() {
  1242.  
  1243.     PLLC_CCB read_ccb;
  1244.     DWORD waitStatus;
  1245.  
  1246.     post_receive();
  1247.  
  1248.     RxState = RX_STATE_LISTENING;
  1249.     while (1) {
  1250.         read_ccb = post_read();
  1251.         waitStatus = WaitForSingleObject(read_ccb->hCompletionEvent, INFINITE);
  1252.         if (waitStatus != WAIT_OBJECT_0) {
  1253.             printf("do_receive: WaitForSingleObject returns %d??\n", GetLastError());
  1254.             continue;
  1255.         }
  1256.         dispatch_read_events(read_ccb);
  1257.         check_keyboard();
  1258.     }
  1259. }
  1260.  
  1261. void check_keyboard() {
  1262.     if (kbhit()) {
  1263.         switch (tolower(getch())) {
  1264.         case 'b':   // just the facts ma'am
  1265.             JustBufferInfo = !JustBufferInfo;
  1266.             if (JustBufferInfo) {
  1267.                 Verbose = 0;
  1268.             }
  1269.             break;
  1270.  
  1271.         case 'd':
  1272.             DisplayCcb = !DisplayCcb;
  1273.             break;
  1274.  
  1275.         case 'f':
  1276.             DisplayFrameReceivedInfo = !DisplayFrameReceivedInfo;
  1277.             break;
  1278.  
  1279.         case 'i':
  1280.             DisplayBufferFreeInfo = !DisplayBufferFreeInfo;
  1281.             break;
  1282.  
  1283.         case 's':   // Stop & Go
  1284.             while (tolower(getch()) != 'g') {
  1285.                 putchar('\a');
  1286.             }
  1287.             break;
  1288.  
  1289.         case 't':
  1290.             DisplayTransmitInfo = !DisplayTransmitInfo;
  1291.             break;
  1292.  
  1293.         case 'v':   // toggle Verbose
  1294.             Verbose = !Verbose;
  1295.             break;
  1296.  
  1297.         case 'x':   // eXit
  1298.             terminate(0);
  1299.  
  1300.         default:
  1301.             putchar('\a');
  1302.         }
  1303.     }
  1304. }
  1305.  
  1306. void dispatch_read_events(PLLC_CCB read_ccb) {
  1307.  
  1308.     BYTE event;
  1309.     BYTE comb;
  1310.  
  1311.     ++TotalReadsChecked;
  1312.  
  1313.     if (read_ccb->uchDlcStatus == LLC_STATUS_SUCCESS) {
  1314.         event = ((PLLC_READ_PARMS)read_ccb->u.pParameterTable)->uchEvent;
  1315.         if (Verbose) {
  1316.             printf("dispatch_read_events: event %02x occurred: ", event);
  1317.         }
  1318.         for (comb = 0x80; comb; comb >>= 1) {
  1319.             if (event & comb) {
  1320.                 ++TotalReadEvents;
  1321.             }
  1322.             switch (event & comb) {
  1323.             case 0x80:
  1324.                 if (Verbose) {
  1325.                     printf("RESERVED - shouldn't happen??!!\n");
  1326.                 }
  1327.                 break;
  1328.  
  1329.             case 0x40:
  1330.                 if (Verbose) {
  1331.                     printf("SYSTEM ACTION (non-critical)?\n");
  1332.                 }
  1333.                 break;
  1334.  
  1335.             case 0x20:
  1336.                 if (Verbose) {
  1337.                     printf("NETWORK STATUS (non-critical)?\n");
  1338.                 }
  1339.                 break;
  1340.  
  1341.             case 0x10:
  1342.                 if (Verbose) {
  1343.                     printf("CRITICAL EXCEPTION?\n");
  1344.                 }
  1345.                 break;
  1346.  
  1347.             case 0x08:
  1348.                 if (Verbose) {
  1349.                     printf("DLC STATUS CHANGE\n");
  1350.                 }
  1351.                 handle_status_change(read_ccb);
  1352.                 break;
  1353.  
  1354.             case 0x04:
  1355.                 if (Verbose) {
  1356.                     printf("RECEIVED DATA\n");
  1357.                 }
  1358.                 handle_receive_data(read_ccb);
  1359.                 break;
  1360.  
  1361.             case 0x02:
  1362.                 if (Verbose) {
  1363.                     printf("TRANSMIT COMPLETION\n");
  1364.                 }
  1365.                 handle_transmit_complete(read_ccb);
  1366.                 break;
  1367.  
  1368.             case 0x01:
  1369.                 if (Verbose) {
  1370.                     printf("COMMAND COMPLETION\n");
  1371.                 }
  1372.                 handle_command_complete(read_ccb);
  1373.                 break;
  1374.             }
  1375.         }
  1376.     } else {
  1377.         printf("dispatch_read_events: read error %#.2x\n", read_ccb->uchDlcStatus);
  1378.     }
  1379.     FREE(read_ccb->u.pParameterTable);
  1380.     CloseHandle(read_ccb->hCompletionEvent);
  1381.     FREE(read_ccb);
  1382. }
  1383.  
  1384. void handle_status_change(PLLC_CCB read_ccb) {
  1385.  
  1386.     PLLC_READ_PARMS parms = (PLLC_READ_PARMS)read_ccb->u.pParameterTable;
  1387.     USHORT status = parms->Type.Status.usDlcStatusCode;
  1388.     USHORT comb;
  1389.     BOOL lost_it = FALSE;
  1390.  
  1391.     for (comb = 0x8000; comb; comb >>= 1) {
  1392.         if (status & comb) {
  1393.             ++StatusChangeEvents;
  1394.         }
  1395.         switch (status & comb) {
  1396.         case 0x8000:
  1397.             printf("LINK LOST\n");
  1398.             lost_it = TRUE;
  1399.             ++LinkLostEvents;
  1400.             break;
  1401.  
  1402.         case 0x4000:
  1403.             printf("DM/DISC received or DISC acked\n");
  1404.             lost_it = TRUE;
  1405.             ++DiscEvents;
  1406.             break;
  1407.  
  1408.         case 0x2000:
  1409.             printf("FRMR received\n");
  1410.             lost_it = TRUE;
  1411.             ++FrmrReceivedEvents;
  1412.             break;
  1413.  
  1414.         case 0x1000:
  1415.             printf("FRMR sent\n");
  1416.             ++FrmrSentEvents;
  1417.             break;
  1418.  
  1419.         case 0x0800:
  1420.             printf("SABME received on open LINK station\n");
  1421.             ++SabmeResetEvents;
  1422.             break;
  1423.  
  1424.         case 0x0400:
  1425.             memcpy(RemoteNode, parms->Type.Status.uchRemoteNodeAddress, 6);
  1426.             if (SwapAddressBits) {
  1427.                 twiddle_bits(RemoteNode, 6);
  1428.             }
  1429.             printf("SABME received - new link %04x. RemoteNode = %02x-%02x-%02x-%02x-%02x-%02x\n",
  1430.                     parms->Type.Status.usStationId,
  1431.                     RemoteNode[0] & 0xff,
  1432.                     RemoteNode[1] & 0xff,
  1433.                     RemoteNode[2] & 0xff,
  1434.                     RemoteNode[3] & 0xff,
  1435.                     RemoteNode[4] & 0xff,
  1436.                     RemoteNode[5] & 0xff
  1437.                     );
  1438.             if (Mode == RECEIVE_MODE) {
  1439.                 connect_station(parms->Type.Status.usStationId);
  1440.                 RxState = RX_STATE_RECEIVING;
  1441.             } else {
  1442.                 printf(" - ON TRANSMITTING SIDE????\n");
  1443.             }
  1444.             ++SabmeOpenEvents;
  1445.             break;
  1446.  
  1447.         case 0x0200:
  1448.             printf("REMOTE BUSY\n");
  1449.             RemoteBusy = 1;
  1450.             ++RemoteBusyEnteredEvents;
  1451.             break;
  1452.  
  1453.         case 0x0100:
  1454.             printf("REMOTE BUSY CLEARED\n");
  1455.             RemoteBusy = 0;
  1456.             ++RemoteBusyLeftEvents;
  1457.             break;
  1458.  
  1459.         case 0x0080:
  1460.             printf("Ti EXPIRED\n");
  1461.             ++TiExpiredEvents;
  1462.             break;
  1463.  
  1464.         case 0x0040:
  1465.             printf("DLC counter overflow\n");
  1466.             ++DlcCounterOverflowEvents;
  1467.             break;
  1468.  
  1469.         case 0x0020:
  1470.             printf("Access priority lowered (on ethernet????!)\n");
  1471.             ++AccessPriorityLoweredEvents;
  1472.             break;
  1473.  
  1474.         case 0x0010:
  1475.         case 0x0008:
  1476.         case 0x0004:
  1477.         case 0x0002:
  1478.             printf("\aThis status code (%04x) should be reserved!\n", status & comb);
  1479.             ++InvalidStatusChangeEvents;
  1480.             break;
  1481.  
  1482.         case 0x0001: {
  1483.  
  1484.             int bufs_avail;
  1485.  
  1486.             LocalBusy = 1;
  1487.             flow_control(parms->Type.Status.usStationId);
  1488.             ++LocalBusyEvents;
  1489.             bufs_avail = free_buffer(get_buffer());
  1490.             printf("LOCAL BUSY: %d buffers left\n", bufs_avail);
  1491.             if (bufs_avail) {
  1492.                 LocalBusy = 0;
  1493.                 printf("LOCAL BUSY CLEARED\n");
  1494.             }
  1495.             break;
  1496.         }
  1497.         }
  1498.     }
  1499.     if (lost_it) {
  1500.         printf("lost it - quitting\n");
  1501.         terminate(1);
  1502.     }
  1503. }
  1504.  
  1505. void handle_receive_data(PLLC_CCB read_ccb) {
  1506.  
  1507.     PLLC_READ_PARMS parms = (PLLC_READ_PARMS)read_ccb->u.pParameterTable;
  1508.     DWORD i;
  1509.     PLLC_BUFFER rx_frame;
  1510.     PLLC_BUFFER next_frame;
  1511.     DWORD nframes;
  1512.     DWORD bufs_left;
  1513.     PLLC_BUFFER pbuf;
  1514.  
  1515.     ++ReceiveDataEvents;
  1516.  
  1517.     nframes = parms->Type.Event.usReceivedFrameCount;
  1518.     if (nframes > MaxChainedReceives) {
  1519.         MaxChainedReceives = nframes;
  1520.     }
  1521.     rx_frame = parms->Type.Event.pReceivedFrame;
  1522.     bufs_left = rx_frame->NotContiguous.cBuffersLeft;
  1523.     if (bufs_left < MinBuffersAvailable) {
  1524.         MinBuffersAvailable = bufs_left;
  1525.     }
  1526.     if (bufs_left > MaxBuffersAvailable) {
  1527.         MaxBuffersAvailable = bufs_left;
  1528.     }
  1529.     if (DisplayFrameReceivedInfo) {
  1530.         printf("handle_receive_data: %d frames received, %d buffers left\n",
  1531.             nframes,
  1532.             bufs_left
  1533.             );
  1534.     }
  1535.     for (i = 0; i < nframes; ++i) {
  1536.         ++DataFramesReceived;
  1537.         next_frame = rx_frame->NotContiguous.pNextFrame;
  1538.         if (!JustBufferInfo) {
  1539.             printf("Packet Sequence %08x  # bytes = %4d  %d buffers left\n",
  1540.                 ((PTEST_PACKET)&rx_frame->NotCont.auchData)->sequence,
  1541.                 ((PTEST_PACKET)&rx_frame->NotCont.auchData)->size,
  1542.                 rx_frame->NotContiguous.cBuffersLeft
  1543.                 );
  1544.         }
  1545.         TotalDlcBytesReceived += rx_frame->Next.cbFrame;
  1546.         TotalPacketBytesReceived += ((PTEST_PACKET)&rx_frame->NotCont.auchData)->size;
  1547.         for (pbuf = rx_frame; pbuf; pbuf = pbuf->pNext) {
  1548.             ++DlcBuffersReceived;
  1549.         }
  1550.         free_buffer(rx_frame);
  1551.         ++DlcBuffersFreed;
  1552.         if (!next_frame && i != nframes - 1) {
  1553.             printf("handle_receive_data: unexpected NULL pointer terminates list @ %d\n", i);
  1554.             break;
  1555.         }
  1556.         rx_frame = next_frame;
  1557.     }
  1558. }
  1559.  
  1560. void handle_transmit_complete(PLLC_CCB read_ccb) {
  1561.  
  1562.     PLLC_READ_PARMS parms = (PLLC_READ_PARMS)read_ccb->u.pParameterTable;
  1563.     DWORD i;
  1564.     PLLC_CCB tx_ccb;
  1565.     PLLC_CCB next_ccb;
  1566.     DWORD nframes;
  1567.     DWORD txlen;
  1568.  
  1569.     ++TransmitCompleteEvents;
  1570.  
  1571.     nframes = parms->Type.Event.usCcbCount;
  1572.     if (nframes > MaxChainedTransmits) {
  1573.         MaxChainedTransmits = nframes;
  1574.     }
  1575.     if (Verbose || DisplayTransmitInfo) {
  1576.         printf("handle_transmit_complete: %d transmits completed\n", nframes);
  1577.     }
  1578.     tx_ccb = parms->Type.Event.pCcbCompletionList;
  1579.     for (i = 0; i < nframes; ++i) {
  1580.         next_ccb = tx_ccb->pNext;
  1581.         txlen = ((PLLC_TRANSMIT_PARMS)tx_ccb->u.pParameterTable)->cbBuffer1;
  1582.         TotalTxBytesCompleted += txlen;
  1583.         if (tx_ccb->uchDlcStatus) {
  1584.             printf("\ahandle_transmit_complete: TX CCB %08x error %#.2x\n",
  1585.                 tx_ccb, tx_ccb->uchDlcStatus);
  1586.             if (tx_ccb->uchDlcStatus == LLC_STATUS_INVALID_FRAME_LENGTH) {
  1587.                 printf("data length = %d\n", txlen);
  1588.             }
  1589.         }
  1590.         FREE(((PLLC_TRANSMIT_PARMS)tx_ccb->u.pParameterTable)->pBuffer1);
  1591.         FREE(tx_ccb->u.pParameterTable);
  1592.         FREE(tx_ccb);
  1593.         --OutstandingTransmits;
  1594.         if (OutstandingTransmits < 0) {
  1595.             printf("handle_transmit_complete: more transmit completions than transmits (%d)\n",
  1596.                 OutstandingTransmits);
  1597.         }
  1598.         ++TotalTransmitCompletions;
  1599.         tx_ccb = next_ccb;
  1600.         if (!next_ccb && i != nframes - 1) {
  1601.             printf("handle_transmit_complete: unexpected NULL pointer terminates list @ %d\n", i);
  1602.             break;
  1603.         }
  1604.     }
  1605. }
  1606.  
  1607. void handle_command_complete(PLLC_CCB read_ccb) {
  1608.  
  1609.     PLLC_READ_PARMS parms = (PLLC_READ_PARMS)read_ccb->u.pParameterTable;
  1610.  
  1611.     ++CommandCompleteEvents;
  1612.  
  1613.     printf("handle_command_complete: %d CCBs, %d buffers, %d received frames\n",
  1614.         parms->Type.Event.usCcbCount,
  1615.         parms->Type.Event.usBufferCount,
  1616.         parms->Type.Event.usReceivedFrameCount
  1617.         );
  1618. }
  1619.  
  1620. void twiddle_bits(LPBYTE buffer, DWORD length) {
  1621.  
  1622.     while (length--) {
  1623.         *buffer = swap_bits(*buffer);
  1624.         ++buffer;
  1625.     }
  1626. }
  1627.  
  1628. unsigned char swap_bits(unsigned char b) {
  1629.  
  1630.     unsigned char bb = 0;
  1631.     unsigned char mask;
  1632.  
  1633.     for (mask = 1; mask; mask <<= 1) {
  1634.         bb <<= 1;
  1635.         bb |= ((b & mask) ? 1 : 0);
  1636.     }
  1637.     return bb;
  1638. }
  1639.  
  1640. void* my_malloc(int size) {
  1641.  
  1642.     void* ptr;
  1643.  
  1644.     size += 2 * sizeof(DWORD);
  1645.     ptr = malloc(size);
  1646.     if (ptr) {
  1647.         *((LPDWORD)ptr)++ = (DWORD)size;
  1648.         *((LPDWORD)ptr)++ = 0xcec171a2;
  1649.         AllocatedBytesOutstanding += (LONG)size;
  1650.         if (AllocatedBytesOutstanding < 0) {
  1651.             printf("my_malloc: alloc overflow? AllocatedBytesOutstanding=%x\n", AllocatedBytesOutstanding);
  1652.         }
  1653.         TotalBytesAllocated += (DWORD)size;
  1654.     }
  1655.     return ptr;
  1656. }
  1657.  
  1658. void* my_calloc(int num, int size) {
  1659.  
  1660.     void* ptr;
  1661.  
  1662.     size = (num * size) + 2 * sizeof(DWORD);
  1663.     ptr = calloc(1, size);
  1664.     if (ptr) {
  1665.         *((LPDWORD)ptr)++ = (DWORD)size;
  1666.         *((LPDWORD)ptr)++ = 0xcec171a2;
  1667.         AllocatedBytesOutstanding += (LONG)size;
  1668.         if (AllocatedBytesOutstanding < 0) {
  1669.             printf("my_calloc: alloc overflow? AllocatedBytesOutstanding=%x\n", AllocatedBytesOutstanding);
  1670.         }
  1671.         TotalBytesAllocated += (DWORD)size;
  1672.     }
  1673.     return ptr;
  1674. }
  1675.  
  1676. void my_free(void* ptr) {
  1677.  
  1678.     DWORD size;
  1679.  
  1680.     ((LPDWORD)ptr) -= 2;
  1681.     size = ((LPDWORD)ptr)[0];
  1682.  
  1683.     if (((LPDWORD)ptr)[1] != 0xcec171a2) {
  1684.         printf("\amy_free: bad block %x?\n", ptr);
  1685.     } else {
  1686.         AllocatedBytesOutstanding -= size;
  1687.         if (AllocatedBytesOutstanding < 0) {
  1688.             printf("my_free: free underflow? AllocatedBytesOutstanding=%x\n", AllocatedBytesOutstanding);
  1689.         }
  1690.         free(ptr);
  1691.         TotalBytesFreed += (DWORD)size;
  1692.     }
  1693. }
  1694.  
  1695. char* nice_num(unsigned long number) {
  1696.  
  1697.     int fwidth = 0;
  1698.     int i;
  1699.     static char buffer[32];
  1700.     char* buf = buffer;
  1701.  
  1702.     if (!number) {
  1703.         if (!fwidth) {
  1704.             buf[0] = '0';
  1705.             buf[1] = 0;
  1706.         } else {
  1707.             memset(buf, ' ', fwidth);
  1708.             buf[fwidth-1] = '0';
  1709.             buf[fwidth] = 0;
  1710.         }
  1711.     } else {
  1712.         if (!fwidth) {
  1713.  
  1714.             ULONG n = number;
  1715.  
  1716.             ++fwidth;
  1717.             for (i = 10; i <= 1000000000; i *= 10) {
  1718.                 if (n/i) {
  1719.                     ++fwidth;
  1720.                 } else {
  1721.                     break;
  1722.                 }
  1723.             }
  1724.             fwidth += (fwidth / 3) - (((fwidth % 3) == 0) ? 1 : 0);
  1725.         }
  1726.         buf[fwidth] = 0;
  1727.         buf += fwidth;
  1728.         i=0;
  1729.         while (number && fwidth) {
  1730.             *--buf = (char)((number%10)+'0');
  1731.             --fwidth;
  1732.             number /= 10;
  1733.             if (++i == 3 && fwidth) {
  1734.                 if (number) {
  1735.                     *--buf = ',';
  1736.                     --fwidth;
  1737.                     i=0;
  1738.                 }
  1739.             }
  1740.         }
  1741.         while (fwidth--) *--buf = ' ';
  1742.     }
  1743.     return buf;
  1744. }
  1745.