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.
860 lines
23 KiB
860 lines
23 KiB
/* |
|
* Copyright (c) 1993,1994 |
|
* Texas A&M University. All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* 3. All advertising materials mentioning features or use of this software |
|
* must display the following acknowledgement: |
|
* This product includes software developed by Texas A&M University |
|
* and its contributors. |
|
* 4. Neither the name of the University nor the names of its contributors |
|
* may be used to endorse or promote products derived from this software |
|
* without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
* SUCH DAMAGE. |
|
* |
|
* Developers: |
|
* David K. Hess, Douglas Lee Schales, David R. Safford |
|
* |
|
* Heavily modified for Metaware HighC + GNU C 2.8+ |
|
* Gisle Vanem 1998 |
|
*/ |
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <dos.h> |
|
#include <io.h> |
|
#include <fcntl.h> |
|
#include <malloc.h> |
|
#include <string.h> |
|
|
|
#include "pcap-dos.h" |
|
#include "pcap-int.h" |
|
#include "msdos/ndis2.h" |
|
|
|
#if defined(USE_NDIS2) |
|
|
|
/* |
|
* Packet buffer handling |
|
*/ |
|
extern int FreePktBuf (PktBuf *buf); |
|
extern int EnquePktBuf (PktBuf *buf); |
|
extern PktBuf* AllocPktBuf (void); |
|
|
|
/* |
|
* Various defines |
|
*/ |
|
#define MAX_NUM_DEBUG_STRINGS 90 |
|
#define DEBUG_STRING_LENGTH 80 |
|
#define STACK_POOL_SIZE 6 |
|
#define STACK_SIZE 256 |
|
|
|
#define MEDIA_FDDI 1 |
|
#define MEDIA_ETHERNET 2 |
|
#define MEDIA_TOKEN 3 |
|
|
|
static int startDebug = 0; |
|
static int stopDebug = 0; |
|
|
|
static DWORD droppedPackets = 0L; |
|
static WORD frameSize = 0; |
|
static WORD headerSize = 0; |
|
static int mediaType = 0; |
|
static char *lastErr = NULL; |
|
|
|
static BYTE debugStrings [MAX_NUM_DEBUG_STRINGS][DEBUG_STRING_LENGTH]; |
|
static BYTE *freeStacks [STACK_POOL_SIZE]; |
|
static int freeStackPtr = STACK_POOL_SIZE - 1; |
|
|
|
static ProtMan protManEntry = NULL; |
|
static WORD protManDS = 0; |
|
static volatile int xmitPending; |
|
|
|
static struct _PktBuf *txBufPending; |
|
static struct _CardHandle *handle; |
|
static struct _CommonChars common; |
|
static struct _ProtocolChars protChars; |
|
static struct _ProtDispatch lowerTable; |
|
|
|
static struct _FailingModules failingModules; |
|
static struct _BindingsList bindings; |
|
|
|
static struct { |
|
WORD err_num; |
|
char *err_text; |
|
} ndis_errlist[] = { |
|
|
|
{ ERR_SUCCESS, |
|
"The function completed successfully.\n" }, |
|
|
|
{ ERR_WAIT_FOR_RELEASE, |
|
"The ReceiveChain completed successfully but the protocol has\n" |
|
"retained control of the buffer.\n" }, |
|
|
|
{ ERR_REQUEST_QUEUED, |
|
"The current request has been queued.\n" }, |
|
|
|
{ ERR_FRAME_NOT_RECOGNIZED, |
|
"Frame not recognized.\n" }, |
|
|
|
{ ERR_FRAME_REJECTED, |
|
"Frame was discarded.\n" }, |
|
|
|
{ ERR_FORWARD_FRAME, |
|
"Protocol wishes to forward frame to another protocol.\n" }, |
|
|
|
{ ERR_OUT_OF_RESOURCE, |
|
"Out of resource.\n" }, |
|
|
|
{ ERR_INVALID_PARAMETER, |
|
"Invalid parameter.\n" }, |
|
|
|
{ ERR_INVALID_FUNCTION, |
|
"Invalid function.\n" }, |
|
|
|
{ ERR_NOT_SUPPORTED, |
|
"Not supported.\n" }, |
|
|
|
{ ERR_HARDWARE_ERROR, |
|
"Hardware error.\n" }, |
|
|
|
{ ERR_TRANSMIT_ERROR, |
|
"The packet was not transmitted due to an error.\n" }, |
|
|
|
{ ERR_NO_SUCH_DESTINATION, |
|
"Token ring packet was not recognized when transmitted.\n" }, |
|
|
|
{ ERR_BUFFER_TOO_SMALL, |
|
"Provided buffer was too small.\n" }, |
|
|
|
{ ERR_ALREADY_STARTED, |
|
"Network drivers already started.\n" }, |
|
|
|
{ ERR_INCOMPLETE_BINDING, |
|
"Protocol driver could not complete its bindings.\n" }, |
|
|
|
{ ERR_DRIVER_NOT_INITIALIZED, |
|
"MAC did not initialize properly.\n" }, |
|
|
|
{ ERR_HARDWARE_NOT_FOUND, |
|
"Hardware not found.\n" }, |
|
|
|
{ ERR_HARDWARE_FAILURE, |
|
"Hardware failure.\n" }, |
|
|
|
{ ERR_CONFIGURATION_FAILURE, |
|
"Configuration failure.\n" }, |
|
|
|
{ ERR_INTERRUPT_CONFLICT, |
|
"Interrupt conflict.\n" }, |
|
|
|
{ ERR_INCOMPATIBLE_MAC, |
|
"The MAC is not compatible with the protocol.\n" }, |
|
|
|
{ ERR_INITIALIZATION_FAILED, |
|
"Initialization failed.\n" }, |
|
|
|
{ ERR_NO_BINDING, |
|
"Binding did not occur.\n" }, |
|
|
|
{ ERR_NETWORK_MAY_NOT_BE_CONNECTED, |
|
"The network may not be connected to the adapter.\n" }, |
|
|
|
{ ERR_INCOMPATIBLE_OS_VERSION, |
|
"The version of the operating system is incompatible with the protocol.\n" }, |
|
|
|
{ ERR_ALREADY_REGISTERED, |
|
"The protocol is already registered.\n" }, |
|
|
|
{ ERR_PATH_NOT_FOUND, |
|
"PROTMAN.EXE could not be found.\n" }, |
|
|
|
{ ERR_INSUFFICIENT_MEMORY, |
|
"Insufficient memory.\n" }, |
|
|
|
{ ERR_INFO_NOT_FOUND, |
|
"Protocol Mananger info structure is lost or corrupted.\n" }, |
|
|
|
{ ERR_GENERAL_FAILURE, |
|
"General failure.\n" } |
|
}; |
|
|
|
/* |
|
* Some handy macros |
|
*/ |
|
#define PERROR(str) printf("%s (%d): %s\n", __FILE__,__LINE__,str) |
|
#define DEBUG_RING() (debugStrings[stopDebug+1 == MAX_NUM_DEBUG_STRINGS ? \ |
|
stopDebug = 0 : ++stopDebug]) |
|
|
|
/* |
|
* needs rewrite for DOSX |
|
*/ |
|
#define MAC_DISPATCH(hnd) ((struct _MacUpperDispatch*)(hnd)->common->upperDispatchTable) |
|
#define MAC_STATUS(hnd) ((struct _MacStatusTable*) (hnd)->common->serviceStatus) |
|
#define MAC_CHAR(hnd) ((struct _MacChars*) (hnd)->common->serviceChars) |
|
|
|
#ifdef NDIS_DEBUG |
|
#define DEBUG0(str) printf (str) |
|
#define DEBUG1(fmt,a) printf (fmt,a) |
|
#define DEBUG2(fmt,a,b) printf (fmt,a,b) |
|
#define TRACE0(str) sprintf (DEBUG_RING(),str) |
|
#define TRACE1(fmt,a) sprintf (DEBUG_RING(),fmt,a) |
|
#else |
|
#define DEBUG0(str) ((void)0) |
|
#define DEBUG1(fmt,a) ((void)0) |
|
#define DEBUG2(fmt,a,b) ((void)0) |
|
#define TRACE0(str) ((void)0) |
|
#define TRACE1(fmt,a) ((void)0) |
|
#endif |
|
|
|
/* |
|
* This routine is called from both threads |
|
*/ |
|
void NdisFreeStack (BYTE *aStack) |
|
{ |
|
GUARD(); |
|
|
|
if (freeStackPtr == STACK_POOL_SIZE - 1) |
|
PERROR ("tried to free too many stacks"); |
|
|
|
freeStacks[++freeStackPtr] = aStack; |
|
|
|
if (freeStackPtr == 0) |
|
TRACE0 ("freeStackPtr went positive\n"); |
|
|
|
UNGUARD(); |
|
} |
|
|
|
/* |
|
* This routine is called from callbacks to allocate local data |
|
*/ |
|
BYTE *NdisAllocStack (void) |
|
{ |
|
BYTE *stack; |
|
|
|
GUARD(); |
|
|
|
if (freeStackPtr < 0) |
|
{ |
|
/* Ran out of stack buffers. Return NULL which will start |
|
* dropping packets |
|
*/ |
|
TRACE0 ("freeStackPtr went negative\n"); |
|
stack = 0; |
|
} |
|
else |
|
stack = freeStacks[freeStackPtr--]; |
|
|
|
UNGUARD(); |
|
return (stack); |
|
} |
|
|
|
CALLBACK (NdisSystemRequest (DWORD param1, DWORD param2, WORD param3, |
|
WORD opcode, WORD targetDS)) |
|
{ |
|
static int bindEntry = 0; |
|
struct _CommonChars *macCommon; |
|
volatile WORD result; |
|
|
|
switch (opcode) |
|
{ |
|
case REQ_INITIATE_BIND: |
|
macCommon = (struct _CommonChars*) param2; |
|
if (macCommon == NULL) |
|
{ |
|
printf ("There is an NDIS misconfiguration.\n"); |
|
result = ERR_GENERAL_FAILURE; |
|
break; |
|
} |
|
DEBUG2 ("module name %s\n" |
|
"module type %s\n", |
|
macCommon->moduleName, |
|
((MacChars*) macCommon->serviceChars)->macName); |
|
|
|
/* Binding to the MAC */ |
|
result = macCommon->systemRequest ((DWORD)&common, (DWORD)&macCommon, |
|
0, REQ_BIND, |
|
macCommon->moduleDS); |
|
|
|
if (!strcmp(bindings.moduleName[bindEntry], handle->moduleName)) |
|
handle->common = macCommon; |
|
else PERROR ("unknown module"); |
|
++bindEntry; |
|
break; |
|
|
|
case REQ_INITIATE_UNBIND: |
|
macCommon = (struct _CommonChars*) param2; |
|
result = macCommon->systemRequest ((DWORD)&common, 0, |
|
0, REQ_UNBIND, |
|
macCommon->moduleDS); |
|
break; |
|
|
|
default: |
|
result = ERR_GENERAL_FAILURE; |
|
break; |
|
} |
|
ARGSUSED (param1); |
|
ARGSUSED (param3); |
|
ARGSUSED (targetDS); |
|
return (result); |
|
} |
|
|
|
CALLBACK (NdisRequestConfirm (WORD protId, WORD macId, WORD reqHandle, |
|
WORD status, WORD request, WORD protDS)) |
|
{ |
|
ARGSUSED (protId); ARGSUSED (macId); |
|
ARGSUSED (reqHandle); ARGSUSED (status); |
|
ARGSUSED (request); ARGSUSED (protDS); |
|
return (ERR_SUCCESS); |
|
} |
|
|
|
CALLBACK (NdisTransmitConfirm (WORD protId, WORD macId, WORD reqHandle, |
|
WORD status, WORD protDS)) |
|
{ |
|
xmitPending--; |
|
FreePktBuf (txBufPending); /* Add passed ECB back to the free list */ |
|
|
|
ARGSUSED (reqHandle); |
|
ARGSUSED (status); |
|
ARGSUSED (protDS); |
|
return (ERR_SUCCESS); |
|
} |
|
|
|
|
|
/* |
|
* The primary function for receiving packets |
|
*/ |
|
CALLBACK (NdisReceiveLookahead (WORD macId, WORD frameSize, |
|
WORD bytesAvail, BYTE *buffer, |
|
BYTE *indicate, WORD protDS)) |
|
{ |
|
int result; |
|
PktBuf *pktBuf; |
|
WORD bytesCopied; |
|
struct _TDBufDescr tDBufDescr; |
|
|
|
#if 0 |
|
TRACE1 ("lookahead length = %d, ", bytesAvail); |
|
TRACE1 ("ecb = %08lX, ", *ecb); |
|
TRACE1 ("count = %08lX\n", count); |
|
TRACE1 ("offset = %08lX, ", offset); |
|
TRACE1 ("timesAllowed = %d, ", timesAllowed); |
|
TRACE1 ("packet size = %d\n", look->dataLookAheadLen); |
|
#endif |
|
|
|
/* Allocate a buffer for the packet |
|
*/ |
|
if ((pktBuf = AllocPktBuf()) == NULL) |
|
{ |
|
droppedPackets++; |
|
return (ERR_FRAME_REJECTED); |
|
} |
|
|
|
/* |
|
* Now kludge things. Note we will have to undo this later. This will |
|
* make the packet contiguous after the MLID has done the requested copy. |
|
*/ |
|
|
|
tDBufDescr.tDDataCount = 1; |
|
tDBufDescr.tDBufDescrRec[0].tDPtrType = NDIS_PTR_PHYSICAL; |
|
tDBufDescr.tDBufDescrRec[0].tDDataPtr = pktBuf->buffer; |
|
tDBufDescr.tDBufDescrRec[0].tDDataLen = pktBuf->length; |
|
tDBufDescr.tDBufDescrRec[0].dummy = 0; |
|
|
|
result = MAC_DISPATCH(handle)->transferData (&bytesCopied, 0, &tDBufDescr, |
|
handle->common->moduleDS); |
|
pktBuf->packetLength = bytesCopied; |
|
|
|
if (result == ERR_SUCCESS) |
|
EnquePktBuf(pktBuf); |
|
else FreePktBuf (pktBuf); |
|
|
|
ARGSUSED (frameSize); |
|
ARGSUSED (bytesAvail); |
|
ARGSUSED (indicate); |
|
ARGSUSED (protDS); |
|
|
|
return (ERR_SUCCESS); |
|
} |
|
|
|
CALLBACK (NdisIndicationComplete (WORD macId, WORD protDS)) |
|
{ |
|
ARGSUSED (macId); |
|
ARGSUSED (protDS); |
|
|
|
/* We don't give a hoot about these. Just return |
|
*/ |
|
return (ERR_SUCCESS); |
|
} |
|
|
|
/* |
|
* This is the OTHER way we may receive packets |
|
*/ |
|
CALLBACK (NdisReceiveChain (WORD macId, WORD frameSize, WORD reqHandle, |
|
struct _RxBufDescr *rxBufDescr, |
|
BYTE *indicate, WORD protDS)) |
|
{ |
|
struct _PktBuf *pktBuf; |
|
int i; |
|
|
|
/* |
|
* For now we copy the entire packet over to a PktBuf structure. This may be |
|
* a performance hit but this routine probably isn't called very much, and |
|
* it is a lot of work to do it otherwise. Also if it is a filter protocol |
|
* packet we could end up sucking up MAC buffes. |
|
*/ |
|
|
|
if ((pktBuf = AllocPktBuf()) == NULL) |
|
{ |
|
droppedPackets++; |
|
return (ERR_FRAME_REJECTED); |
|
} |
|
pktBuf->packetLength = 0; |
|
|
|
/* Copy the packet to the buffer |
|
*/ |
|
for (i = 0; i < rxBufDescr->rxDataCount; ++i) |
|
{ |
|
struct _RxBufDescrRec *rxDescr = &rxBufDescr->rxBufDescrRec[i]; |
|
|
|
memcpy (pktBuf->buffer + pktBuf->packetLength, |
|
rxDescr->rxDataPtr, rxDescr->rxDataLen); |
|
pktBuf->packetLength += rxDescr->rxDataLen; |
|
} |
|
|
|
EnquePktBuf (pktBuf); |
|
|
|
ARGSUSED (frameSize); |
|
ARGSUSED (reqHandle); |
|
ARGSUSED (indicate); |
|
ARGSUSED (protDS); |
|
|
|
/* This frees up the buffer for the MAC to use |
|
*/ |
|
return (ERR_SUCCESS); |
|
} |
|
|
|
CALLBACK (NdisStatusProc (WORD macId, WORD param1, BYTE *indicate, |
|
WORD opcode, WORD protDS)) |
|
{ |
|
switch (opcode) |
|
{ |
|
case STATUS_RING_STATUS: |
|
break; |
|
case STATUS_ADAPTER_CHECK: |
|
break; |
|
case STATUS_START_RESET: |
|
break; |
|
case STATUS_INTERRUPT: |
|
break; |
|
case STATUS_END_RESET: |
|
break; |
|
default: |
|
break; |
|
} |
|
ARGSUSED (macId); |
|
ARGSUSED (param1); |
|
ARGSUSED (indicate); |
|
ARGSUSED (opcode); |
|
ARGSUSED (protDS); |
|
|
|
/* We don't need to do anything about this stuff yet |
|
*/ |
|
return (ERR_SUCCESS); |
|
} |
|
|
|
/* |
|
* Tell the NDIS driver to start the delivery of the packet |
|
*/ |
|
int NdisSendPacket (struct _PktBuf *pktBuf, int macId) |
|
{ |
|
struct _TxBufDescr txBufDescr; |
|
int result; |
|
|
|
xmitPending++; |
|
txBufPending = pktBuf; /* we only have 1 pending Tx at a time */ |
|
|
|
txBufDescr.txImmedLen = 0; |
|
txBufDescr.txImmedPtr = NULL; |
|
txBufDescr.txDataCount = 1; |
|
txBufDescr.txBufDescrRec[0].txPtrType = NDIS_PTR_PHYSICAL; |
|
txBufDescr.txBufDescrRec[0].dummy = 0; |
|
txBufDescr.txBufDescrRec[0].txDataLen = pktBuf->packetLength; |
|
txBufDescr.txBufDescrRec[0].txDataPtr = pktBuf->buffer; |
|
|
|
result = MAC_DISPATCH(handle)->transmitChain (common.moduleId, |
|
pktBuf->handle, |
|
&txBufDescr, |
|
handle->common->moduleDS); |
|
switch (result) |
|
{ |
|
case ERR_OUT_OF_RESOURCE: |
|
/* Note that this should not happen but if it does there is not |
|
* much we can do about it |
|
*/ |
|
printf ("ERROR: transmit queue overflowed\n"); |
|
return (0); |
|
|
|
case ERR_SUCCESS: |
|
/* Everything was hunky dory and synchronous. Free up the |
|
* packet buffer |
|
*/ |
|
xmitPending--; |
|
FreePktBuf (pktBuf); |
|
return (1); |
|
|
|
case ERR_REQUEST_QUEUED: |
|
/* Everything was hunky dory and asynchronous. Do nothing |
|
*/ |
|
return (1); |
|
|
|
default: |
|
printf ("Tx fail, code = %04X\n", result); |
|
return (0); |
|
} |
|
} |
|
|
|
|
|
|
|
static int ndis_nerr = sizeof(ndis_errlist) / sizeof(ndis_errlist[0]); |
|
|
|
static char *Ndis_strerror (WORD errorCode) |
|
{ |
|
static char buf[30]; |
|
int i; |
|
|
|
for (i = 0; i < ndis_nerr; i++) |
|
if (errorCode == ndis_errlist[i].err_num) |
|
return (ndis_errlist[i].err_text); |
|
|
|
sprintf (buf,"unknown error %d",errorCode); |
|
return (buf); |
|
} |
|
|
|
|
|
char *NdisLastError (void) |
|
{ |
|
char *errStr = lastErr; |
|
lastErr = NULL; |
|
return (errStr); |
|
} |
|
|
|
int NdisOpen (void) |
|
{ |
|
struct _ReqBlock reqBlock; |
|
int result; |
|
int ndisFd = open (NDIS_PATH, O_RDONLY); |
|
|
|
if (ndisFd < 0) |
|
{ |
|
printf ("Could not open NDIS Protocol Manager device.\n"); |
|
return (0); |
|
} |
|
|
|
memset (&reqBlock, 0, sizeof(ReqBlock)); |
|
|
|
reqBlock.opcode = PM_GET_PROTOCOL_MANAGER_LINKAGE; |
|
|
|
result = NdisGetLinkage (ndisFd, (char*)&reqBlock, sizeof(ReqBlock)); |
|
if (result != 0) |
|
{ |
|
printf ("Could not get Protocol Manager linkage.\n"); |
|
close (ndisFd); |
|
return (0); |
|
} |
|
|
|
close (ndisFd); |
|
protManEntry = (ProtMan) reqBlock.pointer1; |
|
protManDS = reqBlock.word1; |
|
|
|
DEBUG2 ("Entry Point = %04X:%04X\n", FP_SEG(protManEntry),FP_OFF(protManEntry)); |
|
DEBUG1 ("ProtMan DS = %04X\n", protManDS); |
|
return (1); |
|
} |
|
|
|
|
|
int NdisRegisterAndBind (int promis) |
|
{ |
|
struct _ReqBlock reqBlock; |
|
WORD result; |
|
|
|
memset (&common,0,sizeof(common)); |
|
|
|
common.tableSize = sizeof (common); |
|
|
|
common.majorNdisVersion = 2; |
|
common.minorNdisVersion = 0; |
|
common.majorModuleVersion = 2; |
|
common.minorModuleVersion = 0; |
|
|
|
/* Indicates binding from below and dynamically loaded |
|
*/ |
|
common.moduleFlags = 0x00000006L; |
|
|
|
strcpy (common.moduleName, "PCAP"); |
|
|
|
common.protocolLevelUpper = 0xFF; |
|
common.protocolLevelLower = 1; |
|
common.interfaceLower = 1; |
|
#ifdef __DJGPP__ |
|
common.moduleDS = _dos_ds; /* the callback data segment */ |
|
#else |
|
common.moduleDS = _DS; |
|
#endif |
|
|
|
common.systemRequest = (SystemRequest) systemRequestGlue; |
|
common.serviceChars = (BYTE*) &protChars; |
|
common.serviceStatus = NULL; |
|
common.upperDispatchTable = NULL; |
|
common.lowerDispatchTable = (BYTE*) &lowerTable; |
|
|
|
protChars.length = sizeof (protChars); |
|
protChars.name[0] = 0; |
|
protChars.type = 0; |
|
|
|
lowerTable.backPointer = &common; |
|
lowerTable.requestConfirm = requestConfirmGlue; |
|
lowerTable.transmitConfirm = transmitConfirmGlue; |
|
lowerTable.receiveLookahead = receiveLookaheadGlue; |
|
lowerTable.indicationComplete = indicationCompleteGlue; |
|
lowerTable.receiveChain = receiveChainGlue; |
|
lowerTable.status = statusGlue; |
|
lowerTable.flags = 3; |
|
if (promis) |
|
lowerTable.flags |= 4; /* promiscous mode (receive everything) */ |
|
|
|
bindings.numBindings = 1; |
|
strcpy (bindings.moduleName[0], handle->moduleName); |
|
|
|
/* Register ourselves with NDIS |
|
*/ |
|
reqBlock.opcode = PM_REGISTER_MODULE; |
|
reqBlock.pointer1 = (BYTE FAR*) &common; |
|
reqBlock.pointer2 = (BYTE FAR*) &bindings; |
|
|
|
result = (*protManEntry) (&reqBlock, protManDS); |
|
if (result) |
|
{ |
|
printf ("Protman registering failed: %s\n", Ndis_strerror(result)); |
|
return (0); |
|
} |
|
|
|
/* Start the binding process |
|
*/ |
|
reqBlock.opcode = PM_BIND_AND_START; |
|
reqBlock.pointer1 = (BYTE FAR*) &failingModules; |
|
|
|
result = (*protManEntry) (&reqBlock, protManDS); |
|
if (result) |
|
{ |
|
printf ("Start binding failed: %s\n", Ndis_strerror(result)); |
|
return (0); |
|
} |
|
return (1); |
|
} |
|
|
|
static int CheckMacFeatures (CardHandle *card) |
|
{ |
|
DWORD serviceFlags; |
|
BYTE _far *mediaString; |
|
BYTE _far *mac_addr; |
|
|
|
DEBUG2 ("checking card features\n" |
|
"common table address = %08lX, macId = %d\n", |
|
card->common, card->common->moduleId); |
|
|
|
serviceFlags = MAC_CHAR (handle)->serviceFlags; |
|
|
|
if ((serviceFlags & SF_PROMISCUOUS) == 0) |
|
{ |
|
printf ("The MAC %s does not support promiscuous mode.\n", |
|
card->moduleName); |
|
return (0); |
|
} |
|
|
|
mediaString = MAC_CHAR (handle)->macName; |
|
|
|
DEBUG1 ("media type = %s\n",mediaString); |
|
|
|
/* Get the media type. And set the header size |
|
*/ |
|
if (!strncmp(mediaString,"802.3",5) || |
|
!strncmp(mediaString,"DIX",3) || |
|
!strncmp(mediaString,"DIX+802.3",9)) |
|
headerSize = sizeof (EthernetIIHeader); |
|
|
|
else if (!strncmp(mediaString,"FDDI",4)) |
|
headerSize = sizeof (FddiHeader) + |
|
sizeof (Ieee802Dot2SnapHeader); |
|
else |
|
{ |
|
printf ("Unsupported MAC type: `%s'\n", mediaString); |
|
return (0); |
|
} |
|
|
|
frameSize = MAC_CHAR (handle)->maxFrameSize; |
|
mac_addr = MAC_CHAR (handle)->currentAddress; |
|
|
|
printf ("Hardware address: %02X:%02X:%02X:%02X:%02X:%02X\n", |
|
mac_addr[0], mac_addr[1], mac_addr[2], |
|
mac_addr[3], mac_addr[4], mac_addr[5]); |
|
return (1); |
|
} |
|
|
|
static int NdisStartMac (CardHandle *card) |
|
{ |
|
WORD result; |
|
|
|
/* Set the lookahead length |
|
*/ |
|
result = MAC_DISPATCH(handle)->request (common.moduleId, 0, |
|
headerSize, 0, |
|
REQ_SET_LOOKAHEAD, |
|
card->common->moduleDS); |
|
|
|
/* We assume that if we got INVALID PARAMETER then either this |
|
* is not supported or will work anyway. NE2000 does this. |
|
*/ |
|
if (result != ERR_SUCCESS && result != ERR_INVALID_PARAMETER) |
|
{ |
|
DEBUG1 ("Set lookahead failed: %s\n", Ndis_strerror(result)); |
|
return (0); |
|
} |
|
|
|
/* Set the packet filter. Note that for some medias and drivers we |
|
* must specify all three flags or the card(s) will not operate correctly. |
|
*/ |
|
result = MAC_DISPATCH(handle)->request (common.moduleId, 0, |
|
/* all packets */ FILTER_PROMISCUOUS | |
|
/* packets to us */ FILTER_DIRECTED | |
|
/* broadcasts */ FILTER_BROADCAST, |
|
0, REQ_SET_PACKET_FILTER, |
|
card->common->moduleDS); |
|
if (result != ERR_SUCCESS) |
|
{ |
|
DEBUG1 ("Set packet filter failed: %s\n", Ndis_strerror(result)); |
|
return (0); |
|
} |
|
|
|
/* If OPEN/CLOSE supported then open the adapter |
|
*/ |
|
if (MAC_CHAR(handle)->serviceFlags & SF_OPEN_CLOSE) |
|
{ |
|
result = MAC_DISPATCH(handle)->request (common.moduleId, 0, 0, NULL, |
|
REQ_OPEN_ADAPTER, |
|
card->common->moduleDS); |
|
if (result != ERR_SUCCESS) |
|
{ |
|
DEBUG1 ("Opening the MAC failed: %s\n", Ndis_strerror(result)); |
|
return (0); |
|
} |
|
} |
|
return (1); |
|
} |
|
|
|
void NdisShutdown (void) |
|
{ |
|
struct _ReqBlock reqBlock; |
|
int result, i; |
|
|
|
if (!handle) |
|
return; |
|
|
|
/* If the adapters support open and are open then close them |
|
*/ |
|
if ((MAC_CHAR(handle)->serviceFlags & SF_OPEN_CLOSE) && |
|
(MAC_STATUS(handle)->macStatus & MAC_OPEN)) |
|
{ |
|
result = MAC_DISPATCH(handle)->request (common.moduleId, 0, 0, 0, |
|
REQ_CLOSE_ADAPTER, |
|
handle->common->moduleDS); |
|
if (result != ERR_SUCCESS) |
|
{ |
|
printf ("Closing the MAC failed: %s\n", Ndis_strerror(result)); |
|
return; |
|
} |
|
} |
|
|
|
/* Tell the Protocol Manager to unbind and stop |
|
*/ |
|
reqBlock.opcode = PM_UNBIND_AND_STOP; |
|
reqBlock.pointer1 = (BYTE FAR*) &failingModules; |
|
reqBlock.pointer2 = NULL; |
|
|
|
result = (*protManEntry) (&reqBlock, protManDS); |
|
if (result) |
|
printf ("Unbind failed: %s\n", Ndis_strerror(result)); |
|
|
|
for (i = 0; i < STACK_POOL_SIZE; ++i) |
|
free (freeStacks[i] - STACK_SIZE); |
|
|
|
handle = NULL; |
|
} |
|
|
|
int NdisInit (int promis) |
|
{ |
|
int i, result; |
|
|
|
/* Allocate the real mode stacks used for NDIS callbacks |
|
*/ |
|
for (i = 0; i < STACK_POOL_SIZE; ++i) |
|
{ |
|
freeStacks[i] = malloc (STACK_SIZE); |
|
if (!freeStacks[i]) |
|
return (0); |
|
freeStacks[i] += STACK_SIZE; |
|
} |
|
|
|
if (!NdisOpen()) |
|
return (0); |
|
|
|
if (!NdisRegisterAndBind(promis)) |
|
return (0); |
|
|
|
DEBUG1 ("My module id: %d\n", common.moduleId); |
|
DEBUG1 ("Handle id; %d\n", handle->common->moduleId); |
|
DEBUG1 ("MAC card: %-16s - ", handle->moduleName); |
|
|
|
atexit (NdisShutdown); |
|
|
|
if (!CheckMacFeatures(&handle)) |
|
return (0); |
|
|
|
switch (mediaType) |
|
{ |
|
case MEDIA_FDDI: |
|
DEBUG0 ("Media type: FDDI"); |
|
break; |
|
case MEDIA_ETHERNET: |
|
DEBUG0 ("Media type: ETHERNET"); |
|
break; |
|
default: |
|
DEBUG0 ("Unsupported media.\n"); |
|
return (0); |
|
} |
|
|
|
DEBUG1 (" - Frame size: %d\n", frameSize); |
|
|
|
if (!NdisStartMac(&handle)) |
|
return (0); |
|
return (1); |
|
} |
|
#endif /* USE_NDIS2 */ |
|
|
|
|