1/*
2 * Copyright (c) 1993,1994
3 *      Texas A&M University.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *      This product includes software developed by Texas A&M University
16 *      and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Developers:
34 *             David K. Hess, Douglas Lee Schales, David R. Safford
35 *
36 * Heavily modified for Metaware HighC + GNU C 2.8+
37 *             Gisle Vanem 1998
38 */
39
40#include <stdio.h>
41#include <stdlib.h>
42#include <dos.h>
43#include <io.h>
44#include <fcntl.h>
45#include <malloc.h>
46#include <string.h>
47
48#include "pcap-dos.h"
49#include "pcap-int.h"
50#include "msdos/ndis2.h"
51
52#if defined(USE_NDIS2)
53
54/*
55 *  Packet buffer handling
56 */
57extern int     FreePktBuf  (PktBuf *buf);
58extern int     EnquePktBuf (PktBuf *buf);
59extern PktBuf* AllocPktBuf (void);
60
61/*
62 *  Various defines
63 */
64#define MAX_NUM_DEBUG_STRINGS 90
65#define DEBUG_STRING_LENGTH   80
66#define STACK_POOL_SIZE       6
67#define STACK_SIZE            256
68
69#define MEDIA_FDDI            1
70#define MEDIA_ETHERNET        2
71#define MEDIA_TOKEN           3
72
73static int     startDebug     = 0;
74static int     stopDebug      = 0;
75
76static DWORD   droppedPackets = 0L;
77static WORD    frameSize      = 0;
78static WORD    headerSize     = 0;
79static int     mediaType      = 0;
80static char   *lastErr        = NULL;
81
82static BYTE    debugStrings [MAX_NUM_DEBUG_STRINGS][DEBUG_STRING_LENGTH];
83static BYTE   *freeStacks   [STACK_POOL_SIZE];
84static int     freeStackPtr = STACK_POOL_SIZE - 1;
85
86static ProtMan protManEntry = NULL;
87static WORD    protManDS    = 0;
88static volatile int xmitPending;
89
90static struct _PktBuf        *txBufPending;
91static struct _CardHandle    *handle;
92static struct _CommonChars    common;
93static struct _ProtocolChars  protChars;
94static struct _ProtDispatch   lowerTable;
95
96static struct _FailingModules failingModules;
97static struct _BindingsList   bindings;
98
99static struct {
100         WORD  err_num;
101         char *err_text;
102       } ndis_errlist[] = {
103
104  { ERR_SUCCESS,
105    "The function completed successfully.\n"  },
106
107  { ERR_WAIT_FOR_RELEASE,
108    "The ReceiveChain completed successfully but the protocol has\n"
109    "retained control of the buffer.\n"  },
110
111  { ERR_REQUEST_QUEUED,
112    "The current request has been queued.\n"  },
113
114  { ERR_FRAME_NOT_RECOGNIZED,
115    "Frame not recognized.\n"  },
116
117  { ERR_FRAME_REJECTED,
118    "Frame was discarded.\n"  },
119
120  { ERR_FORWARD_FRAME,
121    "Protocol wishes to forward frame to another protocol.\n"  },
122
123  { ERR_OUT_OF_RESOURCE,
124    "Out of resource.\n"  },
125
126  { ERR_INVALID_PARAMETER,
127    "Invalid parameter.\n"  },
128
129  { ERR_INVALID_FUNCTION,
130    "Invalid function.\n"  },
131
132  { ERR_NOT_SUPPORTED,
133    "Not supported.\n"  },
134
135  { ERR_HARDWARE_ERROR,
136    "Hardware error.\n"  },
137
138  { ERR_TRANSMIT_ERROR,
139    "The packet was not transmitted due to an error.\n"  },
140
141  { ERR_NO_SUCH_DESTINATION,
142    "Token ring packet was not recognized when transmitted.\n"  },
143
144  { ERR_BUFFER_TOO_SMALL,
145    "Provided buffer was too small.\n"  },
146
147  { ERR_ALREADY_STARTED,
148    "Network drivers already started.\n"  },
149
150  { ERR_INCOMPLETE_BINDING,
151    "Protocol driver could not complete its bindings.\n"  },
152
153  { ERR_DRIVER_NOT_INITIALIZED,
154    "MAC did not initialize properly.\n"  },
155
156  { ERR_HARDWARE_NOT_FOUND,
157    "Hardware not found.\n"  },
158
159  { ERR_HARDWARE_FAILURE,
160    "Hardware failure.\n"  },
161
162  { ERR_CONFIGURATION_FAILURE,
163    "Configuration failure.\n"  },
164
165  { ERR_INTERRUPT_CONFLICT,
166    "Interrupt conflict.\n"  },
167
168  { ERR_INCOMPATIBLE_MAC,
169    "The MAC is not compatible with the protocol.\n"  },
170
171  { ERR_INITIALIZATION_FAILED,
172    "Initialization failed.\n"  },
173
174  { ERR_NO_BINDING,
175    "Binding did not occur.\n"  },
176
177  { ERR_NETWORK_MAY_NOT_BE_CONNECTED,
178    "The network may not be connected to the adapter.\n"  },
179
180  { ERR_INCOMPATIBLE_OS_VERSION,
181    "The version of the operating system is incompatible with the protocol.\n"  },
182
183  { ERR_ALREADY_REGISTERED,
184    "The protocol is already registered.\n"  },
185
186  { ERR_PATH_NOT_FOUND,
187    "PROTMAN.EXE could not be found.\n"  },
188
189  { ERR_INSUFFICIENT_MEMORY,
190    "Insufficient memory.\n"  },
191
192  { ERR_INFO_NOT_FOUND,
193    "Protocol Mananger info structure is lost or corrupted.\n"  },
194
195  { ERR_GENERAL_FAILURE,
196    "General failure.\n"  }
197};
198
199/*
200 *  Some handy macros
201 */
202#define PERROR(str)    printf("%s (%d): %s\n", __FILE__,__LINE__,str)
203#define DEBUG_RING()   (debugStrings[stopDebug+1 == MAX_NUM_DEBUG_STRINGS ? \
204                        stopDebug = 0 : ++stopDebug])
205
206/*
207 * needs rewrite for DOSX
208 */
209#define MAC_DISPATCH(hnd)  ((struct _MacUpperDispatch*)(hnd)->common->upperDispatchTable)
210#define MAC_STATUS(hnd)    ((struct _MacStatusTable*)  (hnd)->common->serviceStatus)
211#define MAC_CHAR(hnd)      ((struct _MacChars*)        (hnd)->common->serviceChars)
212
213#ifdef NDIS_DEBUG
214  #define DEBUG0(str)      printf (str)
215  #define DEBUG1(fmt,a)    printf (fmt,a)
216  #define DEBUG2(fmt,a,b)  printf (fmt,a,b)
217  #define TRACE0(str)      sprintf (DEBUG_RING(),str)
218  #define TRACE1(fmt,a)    sprintf (DEBUG_RING(),fmt,a)
219#else
220  #define DEBUG0(str)      ((void)0)
221  #define DEBUG1(fmt,a)    ((void)0)
222  #define DEBUG2(fmt,a,b)  ((void)0)
223  #define TRACE0(str)      ((void)0)
224  #define TRACE1(fmt,a)    ((void)0)
225#endif
226
227/*
228 * This routine is called from both threads
229 */
230void NdisFreeStack (BYTE *aStack)
231{
232  GUARD();
233
234  if (freeStackPtr == STACK_POOL_SIZE - 1)
235     PERROR ("tried to free too many stacks");
236
237  freeStacks[++freeStackPtr] = aStack;
238
239  if (freeStackPtr == 0)
240     TRACE0 ("freeStackPtr went positive\n");
241
242  UNGUARD();
243}
244
245/*
246 * This routine is called from callbacks to allocate local data
247 */
248BYTE *NdisAllocStack (void)
249{
250  BYTE *stack;
251
252  GUARD();
253
254  if (freeStackPtr < 0)
255  {
256    /* Ran out of stack buffers. Return NULL which will start
257     * dropping packets
258     */
259    TRACE0 ("freeStackPtr went negative\n");
260    stack = 0;
261  }
262  else
263    stack = freeStacks[freeStackPtr--];
264
265  UNGUARD();
266  return (stack);
267}
268
269CALLBACK (NdisSystemRequest (DWORD param1, DWORD param2, WORD param3,
270                             WORD opcode, WORD targetDS))
271{
272  static int            bindEntry = 0;
273  struct _CommonChars  *macCommon;
274  volatile WORD result;
275
276  switch (opcode)
277  {
278    case REQ_INITIATE_BIND:
279         macCommon = (struct _CommonChars*) param2;
280         if (macCommon == NULL)
281	 {
282           printf ("There is an NDIS misconfiguration.\n");
283           result = ERR_GENERAL_FAILURE;
284	   break;
285	 }
286         DEBUG2 ("module name %s\n"
287                 "module type %s\n",
288                 macCommon->moduleName,
289                 ((MacChars*) macCommon->serviceChars)->macName);
290
291         /* Binding to the MAC */
292         result = macCommon->systemRequest ((DWORD)&common, (DWORD)&macCommon,
293                                            0, REQ_BIND,
294                                            macCommon->moduleDS);
295
296         if (!strcmp(bindings.moduleName[bindEntry], handle->moduleName))
297              handle->common = macCommon;
298         else PERROR ("unknown module");
299         ++bindEntry;
300	 break;
301
302    case REQ_INITIATE_UNBIND:
303         macCommon = (struct _CommonChars*) param2;
304         result = macCommon->systemRequest ((DWORD)&common, 0,
305                                            0, REQ_UNBIND,
306                                            macCommon->moduleDS);
307         break;
308
309    default:
310         result = ERR_GENERAL_FAILURE;
311	 break;
312  }
313  ARGSUSED (param1);
314  ARGSUSED (param3);
315  ARGSUSED (targetDS);
316  return (result);
317}
318
319CALLBACK (NdisRequestConfirm (WORD protId, WORD macId,   WORD reqHandle,
320                              WORD status, WORD request, WORD protDS))
321{
322  ARGSUSED (protId);    ARGSUSED (macId);
323  ARGSUSED (reqHandle); ARGSUSED (status);
324  ARGSUSED (request);   ARGSUSED (protDS);
325  return (ERR_SUCCESS);
326}
327
328CALLBACK (NdisTransmitConfirm (WORD protId, WORD macId, WORD reqHandle,
329                               WORD status, WORD protDS))
330{
331  xmitPending--;
332  FreePktBuf (txBufPending);  /* Add passed ECB back to the free list */
333
334  ARGSUSED (reqHandle);
335  ARGSUSED (status);
336  ARGSUSED (protDS);
337  return (ERR_SUCCESS);
338}
339
340
341/*
342 * The primary function for receiving packets
343 */
344CALLBACK (NdisReceiveLookahead (WORD  macId,      WORD  frameSize,
345                                WORD  bytesAvail, BYTE *buffer,
346                                BYTE *indicate,   WORD  protDS))
347{
348  int     result;
349  PktBuf *pktBuf;
350  WORD    bytesCopied;
351  struct _TDBufDescr tDBufDescr;
352
353#if 0
354  TRACE1 ("lookahead length = %d, ", bytesAvail);
355  TRACE1 ("ecb = %08lX, ",          *ecb);
356  TRACE1 ("count = %08lX\n",         count);
357  TRACE1 ("offset = %08lX, ",        offset);
358  TRACE1 ("timesAllowed = %d, ",     timesAllowed);
359  TRACE1 ("packet size = %d\n",      look->dataLookAheadLen);
360#endif
361
362  /* Allocate a buffer for the packet
363   */
364  if ((pktBuf = AllocPktBuf()) == NULL)
365  {
366    droppedPackets++;
367    return (ERR_FRAME_REJECTED);
368  }
369
370  /*
371   * Now kludge things. Note we will have to undo this later. This will
372   * make the packet contiguous after the MLID has done the requested copy.
373   */
374
375  tDBufDescr.tDDataCount = 1;
376  tDBufDescr.tDBufDescrRec[0].tDPtrType = NDIS_PTR_PHYSICAL;
377  tDBufDescr.tDBufDescrRec[0].tDDataPtr = pktBuf->buffer;
378  tDBufDescr.tDBufDescrRec[0].tDDataLen = pktBuf->length;
379  tDBufDescr.tDBufDescrRec[0].dummy     = 0;
380
381  result = MAC_DISPATCH(handle)->transferData (&bytesCopied, 0, &tDBufDescr,
382                                               handle->common->moduleDS);
383  pktBuf->packetLength = bytesCopied;
384
385  if (result == ERR_SUCCESS)
386       EnquePktBuf(pktBuf);
387  else FreePktBuf (pktBuf);
388
389  ARGSUSED (frameSize);
390  ARGSUSED (bytesAvail);
391  ARGSUSED (indicate);
392  ARGSUSED (protDS);
393
394  return (ERR_SUCCESS);
395}
396
397CALLBACK (NdisIndicationComplete (WORD macId, WORD protDS))
398{
399  ARGSUSED (macId);
400  ARGSUSED (protDS);
401
402  /* We don't give a hoot about these. Just return
403   */
404  return (ERR_SUCCESS);
405}
406
407/*
408 * This is the OTHER way we may receive packets
409 */
410CALLBACK (NdisReceiveChain (WORD macId, WORD frameSize, WORD reqHandle,
411                            struct _RxBufDescr *rxBufDescr,
412                            BYTE *indicate, WORD protDS))
413{
414  struct _PktBuf *pktBuf;
415  int     i;
416
417  /*
418   * For now we copy the entire packet over to a PktBuf structure. This may be
419   * a performance hit but this routine probably isn't called very much, and
420   * it is a lot of work to do it otherwise. Also if it is a filter protocol
421   * packet we could end up sucking up MAC buffes.
422   */
423
424  if ((pktBuf = AllocPktBuf()) == NULL)
425  {
426    droppedPackets++;
427    return (ERR_FRAME_REJECTED);
428  }
429  pktBuf->packetLength = 0;
430
431  /* Copy the packet to the buffer
432   */
433  for (i = 0; i < rxBufDescr->rxDataCount; ++i)
434  {
435    struct _RxBufDescrRec *rxDescr = &rxBufDescr->rxBufDescrRec[i];
436
437    memcpy (pktBuf->buffer + pktBuf->packetLength,
438            rxDescr->rxDataPtr, rxDescr->rxDataLen);
439    pktBuf->packetLength += rxDescr->rxDataLen;
440  }
441
442  EnquePktBuf (pktBuf);
443
444  ARGSUSED (frameSize);
445  ARGSUSED (reqHandle);
446  ARGSUSED (indicate);
447  ARGSUSED (protDS);
448
449  /* This frees up the buffer for the MAC to use
450   */
451  return (ERR_SUCCESS);
452}
453
454CALLBACK (NdisStatusProc (WORD macId,  WORD param1, BYTE *indicate,
455                          WORD opcode, WORD protDS))
456{
457  switch (opcode)
458  {
459    case STATUS_RING_STATUS:
460	 break;
461    case STATUS_ADAPTER_CHECK:
462	 break;
463    case STATUS_START_RESET:
464	 break;
465    case STATUS_INTERRUPT:
466	 break;
467    case STATUS_END_RESET:
468	 break;
469    default:
470	 break;
471  }
472  ARGSUSED (macId);
473  ARGSUSED (param1);
474  ARGSUSED (indicate);
475  ARGSUSED (opcode);
476  ARGSUSED (protDS);
477
478  /* We don't need to do anything about this stuff yet
479   */
480  return (ERR_SUCCESS);
481}
482
483/*
484 * Tell the NDIS driver to start the delivery of the packet
485 */
486int NdisSendPacket (struct _PktBuf *pktBuf, int macId)
487{
488  struct _TxBufDescr txBufDescr;
489  int     result;
490
491  xmitPending++;
492  txBufPending = pktBuf;    /* we only have 1 pending Tx at a time */
493
494  txBufDescr.txImmedLen  = 0;
495  txBufDescr.txImmedPtr  = NULL;
496  txBufDescr.txDataCount = 1;
497  txBufDescr.txBufDescrRec[0].txPtrType = NDIS_PTR_PHYSICAL;
498  txBufDescr.txBufDescrRec[0].dummy     = 0;
499  txBufDescr.txBufDescrRec[0].txDataLen = pktBuf->packetLength;
500  txBufDescr.txBufDescrRec[0].txDataPtr = pktBuf->buffer;
501
502  result = MAC_DISPATCH(handle)->transmitChain (common.moduleId,
503                                                pktBuf->handle,
504                                                &txBufDescr,
505                                                handle->common->moduleDS);
506  switch (result)
507  {
508    case ERR_OUT_OF_RESOURCE:
509         /* Note that this should not happen but if it does there is not
510          * much we can do about it
511          */
512         printf ("ERROR: transmit queue overflowed\n");
513         return (0);
514
515    case ERR_SUCCESS:
516         /* Everything was hunky dory and synchronous. Free up the
517          * packet buffer
518          */
519         xmitPending--;
520         FreePktBuf (pktBuf);
521         return (1);
522
523    case ERR_REQUEST_QUEUED:
524         /* Everything was hunky dory and asynchronous. Do nothing
525          */
526         return (1);
527
528    default:
529         printf ("Tx fail, code = %04X\n", result);
530         return (0);
531  }
532}
533
534
535
536static int ndis_nerr = sizeof(ndis_errlist) / sizeof(ndis_errlist[0]);
537
538static char *Ndis_strerror (WORD errorCode)
539{
540  static char buf[30];
541  int    i;
542
543  for (i = 0; i < ndis_nerr; i++)
544      if (errorCode == ndis_errlist[i].err_num)
545         return (ndis_errlist[i].err_text);
546
547  sprintf (buf,"unknown error %d",errorCode);
548  return (buf);
549}
550
551
552char *NdisLastError (void)
553{
554  char *errStr = lastErr;
555  lastErr = NULL;
556  return (errStr);
557}
558
559int NdisOpen (void)
560{
561  struct _ReqBlock reqBlock;
562  int     result;
563  int     ndisFd = open (NDIS_PATH, O_RDONLY);
564
565  if (ndisFd < 0)
566  {
567    printf ("Could not open NDIS Protocol Manager device.\n");
568    return (0);
569  }
570
571  memset (&reqBlock, 0, sizeof(ReqBlock));
572
573  reqBlock.opcode = PM_GET_PROTOCOL_MANAGER_LINKAGE;
574
575  result = NdisGetLinkage (ndisFd, (char*)&reqBlock, sizeof(ReqBlock));
576  if (result != 0)
577  {
578    printf ("Could not get Protocol Manager linkage.\n");
579    close (ndisFd);
580    return (0);
581  }
582
583  close (ndisFd);
584  protManEntry = (ProtMan) reqBlock.pointer1;
585  protManDS    = reqBlock.word1;
586
587  DEBUG2 ("Entry Point = %04X:%04X\n", FP_SEG(protManEntry),FP_OFF(protManEntry));
588  DEBUG1 ("ProtMan DS  = %04X\n", protManDS);
589  return (1);
590}
591
592
593int NdisRegisterAndBind (int promis)
594{
595  struct _ReqBlock reqBlock;
596  WORD    result;
597
598  memset (&common,0,sizeof(common));
599
600  common.tableSize = sizeof (common);
601
602  common.majorNdisVersion   = 2;
603  common.minorNdisVersion   = 0;
604  common.majorModuleVersion = 2;
605  common.minorModuleVersion = 0;
606
607  /* Indicates binding from below and dynamically loaded
608   */
609  common.moduleFlags = 0x00000006L;
610
611  strcpy (common.moduleName, "PCAP");
612
613  common.protocolLevelUpper = 0xFF;
614  common.protocolLevelLower = 1;
615  common.interfaceLower     = 1;
616#ifdef __DJGPP__
617  common.moduleDS           = _dos_ds; /* the callback data segment */
618#else
619  common.moduleDS           = _DS;
620#endif
621
622  common.systemRequest      = (SystemRequest) systemRequestGlue;
623  common.serviceChars       = (BYTE*) &protChars;
624  common.serviceStatus      = NULL;
625  common.upperDispatchTable = NULL;
626  common.lowerDispatchTable = (BYTE*) &lowerTable;
627
628  protChars.length  = sizeof (protChars);
629  protChars.name[0] = 0;
630  protChars.type    = 0;
631
632  lowerTable.backPointer        = &common;
633  lowerTable.requestConfirm     = requestConfirmGlue;
634  lowerTable.transmitConfirm    = transmitConfirmGlue;
635  lowerTable.receiveLookahead   = receiveLookaheadGlue;
636  lowerTable.indicationComplete = indicationCompleteGlue;
637  lowerTable.receiveChain       = receiveChainGlue;
638  lowerTable.status             = statusGlue;
639  lowerTable.flags              = 3;
640  if (promis)
641     lowerTable.flags |= 4;   /* promiscous mode (receive everything) */
642
643  bindings.numBindings = 1;
644  strcpy (bindings.moduleName[0], handle->moduleName);
645
646  /* Register ourselves with NDIS
647   */
648  reqBlock.opcode   = PM_REGISTER_MODULE;
649  reqBlock.pointer1 = (BYTE FAR*) &common;
650  reqBlock.pointer2 = (BYTE FAR*) &bindings;
651
652  result = (*protManEntry) (&reqBlock, protManDS);
653  if (result)
654  {
655    printf ("Protman registering failed: %s\n", Ndis_strerror(result));
656    return (0);
657  }
658
659  /* Start the binding process
660   */
661  reqBlock.opcode   = PM_BIND_AND_START;
662  reqBlock.pointer1 = (BYTE FAR*) &failingModules;
663
664  result = (*protManEntry) (&reqBlock, protManDS);
665  if (result)
666  {
667    printf ("Start binding failed: %s\n", Ndis_strerror(result));
668    return (0);
669  }
670  return (1);
671}
672
673static int CheckMacFeatures (CardHandle *card)
674{
675  DWORD      serviceFlags;
676  BYTE _far *mediaString;
677  BYTE _far *mac_addr;
678
679  DEBUG2 ("checking card features\n"
680          "common table address = %08lX, macId = %d\n",
681          card->common, card->common->moduleId);
682
683  serviceFlags = MAC_CHAR (handle)->serviceFlags;
684
685  if ((serviceFlags & SF_PROMISCUOUS) == 0)
686  {
687    printf ("The MAC %s does not support promiscuous mode.\n",
688            card->moduleName);
689    return (0);
690  }
691
692  mediaString = MAC_CHAR (handle)->macName;
693
694  DEBUG1 ("media type = %s\n",mediaString);
695
696  /* Get the media type. And set the header size
697   */
698  if (!strncmp(mediaString,"802.3",5) ||
699      !strncmp(mediaString,"DIX",3)   ||
700      !strncmp(mediaString,"DIX+802.3",9))
701       headerSize = sizeof (EthernetIIHeader);
702
703  else if (!strncmp(mediaString,"FDDI",4))
704       headerSize = sizeof (FddiHeader) +
705                    sizeof (Ieee802Dot2SnapHeader);
706  else
707  {
708    printf ("Unsupported MAC type: `%s'\n", mediaString);
709    return (0);
710  }
711
712  frameSize = MAC_CHAR (handle)->maxFrameSize;
713  mac_addr  = MAC_CHAR (handle)->currentAddress;
714
715  printf ("Hardware address: %02X:%02X:%02X:%02X:%02X:%02X\n",
716          mac_addr[0], mac_addr[1], mac_addr[2],
717          mac_addr[3], mac_addr[4], mac_addr[5]);
718  return (1);
719}
720
721static int NdisStartMac (CardHandle *card)
722{
723  WORD result;
724
725  /* Set the lookahead length
726   */
727  result = MAC_DISPATCH(handle)->request (common.moduleId, 0,
728                                          headerSize, 0,
729                                          REQ_SET_LOOKAHEAD,
730                                          card->common->moduleDS);
731
732  /* We assume that if we got INVALID PARAMETER then either this
733   * is not supported or will work anyway. NE2000 does this.
734   */
735  if (result != ERR_SUCCESS && result != ERR_INVALID_PARAMETER)
736  {
737    DEBUG1 ("Set lookahead failed: %s\n", Ndis_strerror(result));
738    return (0);
739  }
740
741  /* Set the packet filter. Note that for some medias and drivers we
742   * must specify all three flags or the card(s) will not operate correctly.
743   */
744  result = MAC_DISPATCH(handle)->request (common.moduleId, 0,
745                      /* all packets */   FILTER_PROMISCUOUS |
746                      /* packets to us */ FILTER_DIRECTED    |
747                      /* broadcasts */    FILTER_BROADCAST,
748                                          0, REQ_SET_PACKET_FILTER,
749                                          card->common->moduleDS);
750  if (result != ERR_SUCCESS)
751  {
752    DEBUG1 ("Set packet filter failed: %s\n", Ndis_strerror(result));
753    return (0);
754  }
755
756  /* If OPEN/CLOSE supported then open the adapter
757   */
758  if (MAC_CHAR(handle)->serviceFlags & SF_OPEN_CLOSE)
759  {
760    result = MAC_DISPATCH(handle)->request (common.moduleId, 0, 0, NULL,
761                                            REQ_OPEN_ADAPTER,
762                                            card->common->moduleDS);
763    if (result != ERR_SUCCESS)
764    {
765      DEBUG1 ("Opening the MAC failed: %s\n", Ndis_strerror(result));
766      return (0);
767    }
768  }
769  return (1);
770}
771
772void NdisShutdown (void)
773{
774  struct _ReqBlock reqBlock;
775  int     result, i;
776
777  if (!handle)
778     return;
779
780  /* If the adapters support open and are open then close them
781   */
782  if ((MAC_CHAR(handle)->serviceFlags & SF_OPEN_CLOSE) &&
783      (MAC_STATUS(handle)->macStatus & MAC_OPEN))
784  {
785    result = MAC_DISPATCH(handle)->request (common.moduleId, 0, 0, 0,
786                                            REQ_CLOSE_ADAPTER,
787                                            handle->common->moduleDS);
788    if (result != ERR_SUCCESS)
789    {
790      printf ("Closing the MAC failed: %s\n", Ndis_strerror(result));
791      return;
792    }
793  }
794
795  /* Tell the Protocol Manager to unbind and stop
796   */
797  reqBlock.opcode   = PM_UNBIND_AND_STOP;
798  reqBlock.pointer1 = (BYTE FAR*) &failingModules;
799  reqBlock.pointer2 = NULL;
800
801  result = (*protManEntry) (&reqBlock, protManDS);
802  if (result)
803     printf ("Unbind failed: %s\n",  Ndis_strerror(result));
804
805  for (i = 0; i < STACK_POOL_SIZE; ++i)
806     free (freeStacks[i] - STACK_SIZE);
807
808  handle = NULL;
809}
810
811int NdisInit (int promis)
812{
813  int i, result;
814
815  /* Allocate the real mode stacks used for NDIS callbacks
816   */
817  for (i = 0; i < STACK_POOL_SIZE; ++i)
818  {
819    freeStacks[i] = malloc (STACK_SIZE);
820    if (!freeStacks[i])
821       return (0);
822    freeStacks[i] += STACK_SIZE;
823  }
824
825  if (!NdisOpen())
826     return (0);
827
828  if (!NdisRegisterAndBind(promis))
829     return (0);
830
831  DEBUG1 ("My module id: %d\n", common.moduleId);
832  DEBUG1 ("Handle id;    %d\n", handle->common->moduleId);
833  DEBUG1 ("MAC card:     %-16s - ", handle->moduleName);
834
835  atexit (NdisShutdown);
836
837  if (!CheckMacFeatures(&handle))
838     return (0);
839
840  switch (mediaType)
841  {
842    case MEDIA_FDDI:
843         DEBUG0 ("Media type: FDDI");
844	 break;
845    case MEDIA_ETHERNET:
846         DEBUG0 ("Media type: ETHERNET");
847	 break;
848    default:
849         DEBUG0 ("Unsupported media.\n");
850         return (0);
851  }
852
853  DEBUG1 (" - Frame size: %d\n", frameSize);
854
855  if (!NdisStartMac(&handle))
856     return (0);
857  return (1);
858}
859#endif  /* USE_NDIS2 */
860
861