Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1420 lines
43 KiB

/*----------------------------------------------------------------------
nic.c - routines for protocol access to NIC card via upper edge NDIS
routines.
Change History:
1-18-99 - avoid sending empty HDLC packet(ACK only) up stack.
4-10-98 - Allow for NDIS40 dynamic bind capability if available.
11-14-97 - Created a thread to retry opening NIC's req by NT5.0. DCS
Copyright 1996-98 Comtrol Corporation. All rights reserved.
|--------------------------------------------------------------------*/
#include "precomp.h"
#define DbgNicSet(n) {sz_modid[3] = nic->RefIndex + '0';}
#define Trace1(s,p1) GTrace1(D_Nic, sz_modid, s, p1)
#define TraceStr(s) GTrace(D_Nic, sz_modid, s)
#define TraceErr(s) GTrace(D_Error, sz_modid_err, s)
static char *sz_modid = {"Nic#"};
static char *sz_modid_err = {"Error,Nic"};
#ifdef NT50
#define DO_AUTO_CONFIG 1
#endif
//---- local functions
static PSERIAL_DEVICE_EXTENSION need_mac_autoassign(void);
int NicOpenAdapter(Nic *nic, IN PUNICODE_STRING NicName);
NDIS_STATUS NicWaitForCompletion(Nic *nic);
#ifdef OLD_BINDING_GATHER
NTSTATUS PacketReadRegistry(
IN PWSTR *MacDriverName,
IN PWSTR *PacketDriverName,
IN PUNICODE_STRING RegistryPath,
IN int style); // 0=nt4.0 location, 1=nt5.0 location
NTSTATUS PacketQueryRegistryRoutine(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext);
#endif
VOID PacketRequestComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_REQUEST NdisRequest,
IN NDIS_STATUS Status);
VOID PacketSendComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET pPacket,
IN NDIS_STATUS Status);
NDIS_STATUS PacketReceiveIndicate (
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer,
IN UINT LookAheadBufferSize,
IN UINT PacketSize);
VOID PacketTransferDataComplete (
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET pPacket,
IN NDIS_STATUS Status,
IN UINT BytesTransfered);
VOID PacketOpenAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN NDIS_STATUS OpenErrorStatus);
VOID PacketCloseAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status);
VOID PacketResetComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status);
VOID PacketReceiveComplete(IN NDIS_HANDLE ProtocolBindingContext);
VOID PacketStatus(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN PVOID StatusBuffer,
IN UINT StatusBufferSize);
VOID PacketStatusComplete(IN NDIS_HANDLE ProtocolBindingContext);
#ifdef TRY_DYNAMIC_BINDING
void PacketBind(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE BindContext,
IN PNDIS_STRING DeviceName,
IN PVOID SystemSpecific1,
IN PVOID SystemSpecific2);
VOID PacketUnBind(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE UnbindContext);
#endif
VOID GotOurPkt(Nic *nic);
void eth_rx_async(Nic *nic);
void eth_rx_admin(Nic *nic, BYTE *rx, BYTE *pkt_hdr, int len, int server);
Hdlc *find_hdlc_handle(BYTE *rx);
static int nic_handle_to_index(Nic *nic);
BYTE broadcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
BYTE mac_zero_addr[6] = {0,0,0,0,0,0};
BYTE mac_bogus_addr[6] = {0,0xc0,0x4e,0,0,0};
/*----------------------------------------------------------------------
ProtocolOpen -
|----------------------------------------------------------------------*/
int ProtocolOpen(void)
{
NTSTATUS Status = STATUS_SUCCESS;
NDIS_PROTOCOL_CHARACTERISTICS ProtocolChar;
NDIS_STRING ProtoName = NDIS_STRING_CONST("VSLinka");
int i;
MyKdPrint(D_Init,("Proto Open\n"))
if (Driver.NdisProtocolHandle == NULL)
{
MyKdPrint(D_Init,("P1\n"))
RtlZeroMemory(&ProtocolChar,sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
ProtocolChar.MajorNdisVersion = 4;
ProtocolChar.MinorNdisVersion = 0;
ProtocolChar.Reserved = 0;
ProtocolChar.OpenAdapterCompleteHandler = PacketOpenAdapterComplete;
ProtocolChar.CloseAdapterCompleteHandler = PacketCloseAdapterComplete;
ProtocolChar.SendCompleteHandler = PacketSendComplete;
ProtocolChar.TransferDataCompleteHandler = PacketTransferDataComplete;
ProtocolChar.ResetCompleteHandler = PacketResetComplete;
ProtocolChar.RequestCompleteHandler = PacketRequestComplete;
ProtocolChar.ReceiveHandler = PacketReceiveIndicate;
ProtocolChar.ReceiveCompleteHandler = PacketReceiveComplete;
ProtocolChar.StatusHandler = PacketStatus;
ProtocolChar.StatusCompleteHandler = PacketStatusComplete;
ProtocolChar.Name = ProtoName;
// version 4.0 NDIS parts:
ProtocolChar.ReceivePacketHandler = NULL;
#ifdef TRY_DYNAMIC_BINDING
ProtocolChar.BindAdapterHandler = PacketBind;
ProtocolChar.UnbindAdapterHandler = PacketUnBind;
#endif
//ProtocolChar.TranslateHandler = NULL;
ProtocolChar.UnloadHandler = NULL;
Driver.ndis_version = 4;
#ifdef TRY_DYNAMIC_BINDING
// don't do this yet(not fully debugged)
NdisRegisterProtocol(
&Status,
&Driver.NdisProtocolHandle,
&ProtocolChar,
sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
if (Status != NDIS_STATUS_SUCCESS)
#endif
{
MyKdPrint(D_Init,("No NDIS40\n"))
// try NDIS30
ProtocolChar.MajorNdisVersion = 3;
ProtocolChar.BindAdapterHandler = NULL;
ProtocolChar.UnbindAdapterHandler = NULL;
NdisRegisterProtocol(
&Status,
&Driver.NdisProtocolHandle,
&ProtocolChar,
sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
if (Status != NDIS_STATUS_SUCCESS)
{
MyKdPrint(D_Init,("No NDIS30\n"))
return 1; // error
}
Driver.ndis_version = 3;
}
}
MyKdPrint(D_Init,("NDIS V%d\n",Driver.ndis_version))
return 0; // ok
}
/*----------------------------------------------------------------------
NicOpen - Setup all our stuff for our own protocol, so we can
talk ethernet. Setup our callbacks to upper edge NDIS routines,
grab registry entries which tell us who we are and what NIC cards
we are bound to. Take care of all init stuff associated with using
the NIC card.
|----------------------------------------------------------------------*/
int NicOpen(Nic *nic, IN PUNICODE_STRING NicName)
{
NTSTATUS Status = STATUS_SUCCESS;
//NDIS_HANDLE NdisProtocolHandle;
int i;
NDIS_STATUS ErrorStatus;
PNDIS_BUFFER NdisBuffer;
//MyKdPrint(D_Init,("Nic Open\n"))
DbgNicSet(nic);
TraceStr("NicOpen");
//----- This event is used in case any of the NDIS requests pend;
KeInitializeEvent(&nic->CompletionEvent,
NotificationEvent, FALSE);
Status = NicOpenAdapter(nic, NicName);
if (Status)
{
MyKdPrint(D_Init,("Nic Fail Open\n"))
NicClose(nic);
return Status;
}
MyKdPrint(D_Init,("Nic Open OK\n"))
#ifdef COMMENT_OUT
Nic->MacInfo.DestinationOffset = 0;
Nic->MacInfo.SourceOffset = 6;
Nic->MacInfo.SourceRouting = FALSE;
Nic->MacInfo.AddressLength = 6;
Nic->MacInfo.MaxHeaderLength = 14;
Nic->MacInfo.MediumType = NdisMedium802_3;
#endif
// NDIS packets consist of one or more buffer descriptors which point
// to the actual data. We send or receive single packets made up of
// 1 or more buffers. A MDL is used as a buffer descriptor under NT.
//--------- Allocate a packet pool for our tx packets
NdisAllocatePacketPool(&Status, &nic->TxPacketPoolTemp, 1,
sizeof(PVOID));
// sizeof(PACKET_RESERVED));
if (Status != NDIS_STATUS_SUCCESS)
{
NicClose(nic);
return 4;
}
//--------- Allocate a buffer pool for our tx packets
// we will only use 1 buffer per packet.
NdisAllocateBufferPool(&Status, &nic->TxBufferPoolTemp, 1);
if (Status != NDIS_STATUS_SUCCESS)
{
NicClose(nic);
return 5;
}
//-------- create tx data buffer area
nic->TxBufTemp = our_locked_alloc( MAX_PKT_SIZE,"ncTX");
if (nic->TxBufTemp == NULL)
{
NicClose(nic);
return 16;
}
//-------- form our tx queue packets so they link to our tx buffer area
{
// Get a packet from the pool
NdisAllocatePacket(&Status, &nic->TxPacketsTemp, nic->TxPacketPoolTemp);
if (Status != NDIS_STATUS_SUCCESS)
{
NicClose(nic);
return 8;
}
nic->TxPacketsTemp->ProtocolReserved[0] = 0; // mark with our index
nic->TxPacketsTemp->ProtocolReserved[1] = 0; // free for use
// get a buffer for the temp output packet
NdisAllocateBuffer(&Status, &NdisBuffer, nic->TxBufferPoolTemp,
&nic->TxBufTemp[0], 1520);
if (Status != NDIS_STATUS_SUCCESS)
{
NicClose(nic);
return 9;
}
// we use only one data buffer per packet
NdisChainBufferAtFront(nic->TxPacketsTemp, NdisBuffer);
}
//---------- Allocate a packet pool for our rx packets
NdisAllocatePacketPool(&Status, &nic->RxPacketPool, MAX_RX_PACKETS,
sizeof(PVOID));
// sizeof(PACKET_RESERVED));
if (Status != NDIS_STATUS_SUCCESS)
{
NicClose(nic);
return 6;
}
//--------- Allocate a buffer pool for our rx packets
// we will only use 1 buffer per packet.
NdisAllocateBufferPool(&Status, &nic->RxBufferPool, MAX_RX_PACKETS);
if (Status != NDIS_STATUS_SUCCESS)
{
NicClose(nic);
return 7;
}
//-------- create rx data buffer area, add in space at front
// of packets to put our private data
nic->RxBuf = our_locked_alloc(
(MAX_PKT_SIZE+HDR_SIZE) * MAX_RX_PACKETS,"ncRX");
//------- form our rx queue packets so they link to our rx buffer area
for (i=0; i<MAX_RX_PACKETS; i++)
{
// Get a packet from the pool
NdisAllocatePacket(&Status, &nic->RxPackets[i], nic->RxPacketPool);
if (Status != NDIS_STATUS_SUCCESS)
{
NicClose(nic);
return 10;
}
nic->RxPackets[i]->ProtocolReserved[0] = i; // mark with our index
nic->RxPackets[i]->ProtocolReserved[1] = 0; // free for use
//--- link the buffer to our actual buffer space, leaving 20 bytes
// at start of buffer for our private data(length, index, etc)
NdisAllocateBuffer(&Status, &NdisBuffer, nic->RxBufferPool,
&nic->RxBuf[((MAX_PKT_SIZE+HDR_SIZE) * i)+HDR_SIZE], MAX_PKT_SIZE);
if (Status != NDIS_STATUS_SUCCESS)
{
NicClose(nic);
return 11;
}
// we use only one data buffer per packet
NdisChainBufferAtFront(nic->RxPackets[i], NdisBuffer);
}
strcpy(nic->NicName, UToC1(NicName));
Trace1("Done Open NicName %s", nic->NicName);
nic->Open = 1;
return 0; // ok
}
/*----------------------------------------------------------------------
NicOpenAdapter -
|----------------------------------------------------------------------*/
int NicOpenAdapter(Nic *nic, IN PUNICODE_STRING NicName)
{
UINT Medium;
NDIS_MEDIUM MediumArray=NdisMedium802_3;
NTSTATUS Status = STATUS_SUCCESS;
NDIS_STATUS ErrorStatus;
ULONG RBuf;
DbgNicSet(nic);
NdisOpenAdapter(
&Status, // return status
&ErrorStatus,
&nic->NICHandle, // return handle value
&Medium,
&MediumArray,
1,
Driver.NdisProtocolHandle, // pass in our protocol handle
(NDIS_HANDLE) nic, // our handle passed to protocol callback routines
NicName, // name of nic-card to open
0,
NULL);
if (Status == NDIS_STATUS_SUCCESS)
PacketOpenAdapterComplete(nic, Status, NDIS_STATUS_SUCCESS);
else if (Status == NDIS_STATUS_PENDING)
{
TraceErr("NicOpen Pended");
Status = NicWaitForCompletion(nic); // wait for completion
}
if (Status != NDIS_STATUS_SUCCESS)
{
GTrace2(D_Nic, sz_modid, "NicOpen fail:%xH Err:%xH", Status, ErrorStatus);
TraceStr(UToC1(NicName));
nic->NICHandle = NULL;
NicClose(nic);
return 3;
}
GTrace1(D_Nic, sz_modid, "Try NicOpened:%s", nic->NicName);
//----- get the local NIC card identifier address
Status = NicGetNICInfo(nic, OID_802_3_CURRENT_ADDRESS,
(PVOID)nic->address, 6);
//----- set the rx filter
RBuf = NDIS_PACKET_TYPE_DIRECTED;
Status = NicSetNICInfo(nic, OID_GEN_CURRENT_PACKET_FILTER,
(PVOID)&RBuf, sizeof(ULONG));
return 0; // ok
}
/*----------------------------------------------------------------------
NicClose - Shut down our NIC access. Deallocate any NIC resources.
|----------------------------------------------------------------------*/
int NicClose(Nic *nic)
{
NTSTATUS Status;
DbgNicSet(nic);
TraceStr("NicClose");
nic->Open = 0;
nic->NicName[0] = 0;
if (nic->NICHandle != NULL)
{
NdisCloseAdapter(&Status, nic->NICHandle);
if (Status == NDIS_STATUS_PENDING)
{
Status = NicWaitForCompletion(nic); // wait for completion
}
nic->NICHandle = NULL;
}
if (nic->TxPacketPoolTemp != NULL)
NdisFreePacketPool(nic->TxPacketPoolTemp);
nic->TxPacketPoolTemp = NULL;
if (nic->TxBufferPoolTemp != NULL)
NdisFreeBufferPool(nic->TxBufferPoolTemp);
nic->TxBufferPoolTemp = NULL;
if (nic->TxBufTemp != NULL)
our_free(nic->TxBufTemp, "ncTX");
nic->TxBufTemp = NULL;
if (nic->RxPacketPool != NULL)
NdisFreePacketPool(nic->RxPacketPool);
nic->RxPacketPool = NULL;
if (nic->RxBufferPool != NULL)
NdisFreeBufferPool(nic->RxBufferPool);
nic->RxBufferPool = NULL;
if (nic->RxBuf != NULL)
our_free(nic->RxBuf,"ncRX");
nic->RxBuf = NULL;
MyKdPrint(D_Nic,("Nic Close End\n"))
return 0;
}
/*----------------------------------------------------------------------
NicProtocolClose - Deregister our protocol.
|----------------------------------------------------------------------*/
int NicProtocolClose(void)
{
NTSTATUS Status;
MyKdPrint(D_Nic,("Nic Proto Close\n"))
if (Driver.NdisProtocolHandle != NULL)
NdisDeregisterProtocol(&Status, Driver.NdisProtocolHandle);
Driver.NdisProtocolHandle = NULL;
return 0;
}
/*----------------------------------------------------------------------
PacketRequestComplete - If a call is made to NdisRequest() to get
information about the NIC card(OID), then it may return PENDING and
this routine would then be called by NDIS to finalize the call.
|----------------------------------------------------------------------*/
VOID PacketRequestComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_REQUEST NdisRequest,
IN NDIS_STATUS Status)
{
Nic *nic = (Nic *)ProtocolBindingContext;
MyKdPrint(D_Nic,("PacketReqComp\n"))
//MyDeb(NULL, 0xffff, "PktRqComp\n");
nic->PendingStatus = Status;
KeSetEvent(&nic->CompletionEvent, 0L, FALSE);
return;
}
/*----------------------------------------------------------------------
PacketSendComplete - Callback routine if NdisSend() returns PENDING.
|----------------------------------------------------------------------*/
VOID PacketSendComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET pPacket,
IN NDIS_STATUS Status)
{
Nic *nic = (Nic *)ProtocolBindingContext;
#if DBG
if (nic == NULL)
{
MyKdPrint(D_Error, ("**** NicP Err1"))
return;
}
DbgNicSet(nic);
//nic->PendingStatus = Status;
if (Status == STATUS_SUCCESS)
{TraceStr("PcktSendComplete");}
else
{TraceErr("PcktSendComplete Error!");}
#endif
pPacket->ProtocolReserved[1] = 0; // free for use
//--- not using this
//KeSetEvent(&nic->CompletionEvent, 0L, FALSE);
return;
}
/*----------------------------------------------------------------------
NicWaitForCompletion - Utility routine to wait for async. routine
to complete.
|----------------------------------------------------------------------*/
NDIS_STATUS NicWaitForCompletion(Nic *nic)
{
MyKdPrint(D_Nic,("WaitOnComp\n"))
// The completion routine will set PendingStatus.
KeWaitForSingleObject(
&nic->CompletionEvent,
Executive,
KernelMode,
TRUE,
(PLARGE_INTEGER)NULL);
KeResetEvent(&nic->CompletionEvent);
MyKdPrint(D_Nic,("WaitOnCompEnd\n"))
return nic->PendingStatus;
}
/*----------------------------------------------------------------------
PacketReceiveIndicate - When a packet comes in, this routine is called
to let us(protocol) know about it. We may peek at the data and
optionally arrange for NDIS to transfer the complete packet data to
one of our packets.
LookAheadBufferSize is guarenteed to be as big as the
OID_GEN_CURRENT_LOOKAHEAD value or packet size, whichever is smaller.
If (PacketSize != LookAheadBufferSize) then a NdisTransferData() is
required. Otherwise the complete packet is available in the
lookahead buffer.
!!!!Check the OID_GEN_somethin or other, there is a bit which indicates
if we can copy out of lookahead buffer.
The header len is typically 14 bytes in length for ethernet.
|----------------------------------------------------------------------*/
NDIS_STATUS PacketReceiveIndicate (
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer,
IN UINT LookAheadBufferSize,
IN UINT PacketSize)
{
NDIS_STATUS Status;
UINT BytesTransfered;
WORD LenOrId;
// int stat;
//static char tmparr[60];
Nic *nic = (Nic *)ProtocolBindingContext;
#if DBG
if (nic == NULL)
{
MyKdPrint(D_Error, ("Eth15b\n"))
}
if (!nic->Open)
{
MyKdPrint(D_Error, ("Eth15a\n"))
return 1;
}
#endif
DbgNicSet(nic);
TraceStr("pkt_rec_ind");
if (HeaderBufferSize != 14)
{
TraceErr("Header Size!");
++nic->pkt_rcvd_not_ours;
return NDIS_STATUS_NOT_ACCEPTED;
}
LenOrId = *(PWORD)(((PBYTE)HeaderBuffer)+12);
if (LenOrId != 0xfe11)
{
// this not our packet
++nic->pkt_rcvd_not_ours;
return NDIS_STATUS_NOT_ACCEPTED;
}
if (LookAheadBufferSize > 1)
{
//------ lets check for our product id header
LenOrId = *(PBYTE)(((PBYTE)HeaderBuffer)+14);
// serial concentrator product line
if (LenOrId != ASYNC_PRODUCT_HEADER_ID)
{
if (LenOrId != 0xff)
{
TraceStr("nic,not async");
// this not our packet
++nic->pkt_rcvd_not_ours;
return NDIS_STATUS_NOT_ACCEPTED;
}
}
}
#ifdef BREAK_NIC_STUFF
if (nic->RxPackets[0]->ProtocolReserved[1] & 1) // marked as pending
{
// our one rx buffer is in use! (should never happen)
MyKdPrint(D_Error, ("****** RxBuf in use!"))
//TraceErr("Rx Buf In Use!");
return NDIS_STATUS_NOT_ACCEPTED;
}
nic->RxPackets[0]->ProtocolReserved[1] |= 1; // marked as pending
#endif
memcpy(nic->RxBuf, (BYTE *)HeaderBuffer, 14); // copy the eth. header
if (LookAheadBufferSize == PacketSize)
{
TraceStr("nic,got complete");
++nic->RxNonPendingMoves;
// we can just copy complete packet out of lookahead buffer
// store the 14 byte header data at start of buffer
memcpy(&nic->RxBuf[HDR_SIZE], (BYTE *)LookAheadBuffer, PacketSize);
HDR_PKTLEN(nic->RxBuf) = PacketSize; // save the pkt size here
++nic->pkt_rcvd_ours;
GotOurPkt(nic);
}
else // LookAhead not complete buffer, pending, do transfer
{
++nic->RxPendingMoves;
//MyDeb(NULL, 0xffff, "PktRecInd, Pend\n");
// Call the Mac to transfer the packet
NdisTransferData(&Status, nic->NICHandle, MacReceiveContext,
0, PacketSize, nic->RxPackets[0], &BytesTransfered);
if (Status == NDIS_STATUS_SUCCESS)
{
TraceStr("nic,got trsfer complete");
HDR_PKTLEN(nic->RxBuf) = PacketSize;
//------ lets check for our product id header
if ((nic->RxBuf[HDR_SIZE] != ASYNC_PRODUCT_HEADER_ID) &&
(nic->RxBuf[HDR_SIZE] != 0xff) )
{
nic->RxPackets[0]->ProtocolReserved[1] = 0; // marked as not use
TraceStr("nic,not async");
// this not our packet
++nic->pkt_rcvd_not_ours;
return NDIS_STATUS_NOT_ACCEPTED;
}
++nic->pkt_rcvd_ours;
GotOurPkt(nic);
}
else if (Status == NDIS_STATUS_PENDING)
{
TraceStr("nic,got pending");
// ndis will call PacketTransferDataComplete.
}
else // an error occurred(adapter maybe getting reset)
{
MyKdPrint(D_Error, ("nic, Err1D"))
nic->RxPackets[0]->ProtocolReserved[1] = 0; // marked as not use
//MyDeb(NULL, 0xffff, "PktRecInd, PendError\n");
}
}
return NDIS_STATUS_SUCCESS;
}
/*----------------------------------------------------------------------
GotOurPkt - Its our packet(0x11fe for id at [12,13],
and ASYNC(VS1000) or ff as [14],
index byte we don't care about[16],
rx = ptr to rx_pkt[16].
[12,13] WORD 11fe(comtrol-pci-id, used as ethertype)
[14] Product(55H=async, 15H=isdn, FFH=all)
[15] Index Field(Server assigned box index)
[16] Packet Class, 1=ADMIN, 0x55=VS1000 packet
[17] word len for admin packet
[17] hdlc control field for vs1000 packet
|----------------------------------------------------------------------*/
VOID GotOurPkt(Nic *nic)
{
// [HDR_SIZE] is after 14 byte header, so contains [14] data
// [14]=55H or FFH, [15]=Index, not used [16]=1(ADMIN),55H=ASYNC_MESSAGE
switch(nic->RxBuf[HDR_SIZE+2])
{
case ADMIN_FRAME: // ADMIN function, special setup admin functions
TraceStr("admin");
eth_rx_admin(nic,
nic->RxBuf+(HDR_SIZE+3), // ptr to admin data
nic->RxBuf, // ptr to ethernet header data
HDR_PKTLEN(nic->RxBuf), // we embed length at [12] 0x11fe
1); // server flag
break;
case ASYNC_FRAME: // async frame(normal iframe/control hdlc packets)
TraceStr("iframe");
eth_rx_async(nic);
break;
default:
TraceStr("badf");
Tprintf("D: %x %x %x %x",
nic->RxBuf[HDR_SIZE],
nic->RxBuf[HDR_SIZE+1],
nic->RxBuf[HDR_SIZE+2],
nic->RxBuf[HDR_SIZE+3]);
break;
}
nic->RxPackets[0]->ProtocolReserved[1] = 0; // mark as not use
}
/*----------------------------------------------------------------
eth_rx_async - We receive from layer1, validate using the
hdlc validation call, and ship rx-pkt up to the next upper layer.
|-----------------------------------------------------------------*/
void eth_rx_async(Nic *nic)
{
int i;
Hdlc *hd;
//WORD hd_index;
WORD id;
BYTE *rx;
PSERIAL_DEVICE_EXTENSION ext;
rx = nic->RxBuf;
#ifdef USE_INDEX_FIELD
id = rx[HDR_SIZE];
#endif
// find the HDLC level with the reply address
//hd_index = 0xffff; // save index to hdlc handle in header area
hd = NULL;
i = 0;
ext = Driver.board_ext;
while (ext != NULL)
{
#ifdef USE_INDEX_FIELD
if (id == ext->pm->unique_id)
#else
if (mac_match(&rx[6], ext->hd->dest_addr))
#endif
{
hd = ext->hd;
break;
}
++i;
ext = ext->board_ext; // next one
}
if (hd == NULL)
{
TraceErr("no Mac Match!");
return;
}
if (!hd->nic || !hd->nic->Open)
{
TraceErr("notOpen!");
return;
}
// 55 0 55 control snd_index ack_index
rx += (HDR_SIZE+3); // skip over header
i = hdlc_validate_rx_pkt(hd, rx); // validate the packet
if (i == 0)
{
TraceStr("nic, pass upper");
if (hd->upper_layer_proc != NULL)
{
if (*(rx+3) != 0) // not an empty packet(HDLC ACK packets, t1 timeout)
{
(*hd->upper_layer_proc)(hd->context,
EV_L2_RX_PACKET,
(DWORD) (rx+3) );
}
++(hd->frames_rcvd);
}
}
else
{
switch (i)
{
case ERR_GET_EMPTY : // 1 // empty
TraceErr("Empty!");
break;
case ERR_GET_BAD_INDEX : // 2 // error, packet out of sequence
TraceErr("LanIdx!");
break;
case ERR_GET_BADHDR : // 3 // error, not our packet
// TraceErr("LanHdr!");
break;
case ERR_CONTROL_PACKET :
break;
default: TraceErr("LanErr!"); break;
}
} // else hdlc, error or control, not iframe
}
/*----------------------------------------------------------------------------
| eth_rx_admin - PortMan handles admin functions, validate and pass on as
event messages. rx is ptr to admin data, [17][18]=len, [19]=sub-admin-header
|----------------------------------------------------------------------------*/
void eth_rx_admin(Nic *nic, BYTE *rx, BYTE *pkt_hdr, int len, int server)
{
Hdlc *hd;
rx += 2;
TraceStr("AdminPkt");
if (mac_match(pkt_hdr, broadcast_addr)) // its a broadcast
{
if ((*rx == 2) && (!server)) // Product ID request, Broadcast by server
{
// ok, we will reply
}
else if ((*rx == 3) && (server)) // Product ID reply, reply by concentrator.
{
// might be box waking up, or responding to server request.
// shouldn't see it broadcast, but ISDN box currently broadcasts
// on power-up.
}
else
{
TraceErr("bad b-admin!");
}
TraceErr("broadcast admin!");
return;
}
switch(*rx)
{
#ifdef COMMENT_OUT
case 2: // Product ID request, Broadcast or sent by server
TraceStr("idreq");
if (!server) // we are not a server, we are box
eth_id_req(&pkt_hdr[6]);
break;
#endif
case 1: // boot loader query
if (!server) // we are a server
break;
if ((hd = find_hdlc_handle(&pkt_hdr[6])) != NULL)
{
PortMan *pm = (PortMan *) hd->context;
if (pm->state != ST_SENDCODE)
{
#if 0
// not functional at this point.
// port manager is not uploading code, so it must be debug pkt
// let port.c code handle boot-loader ADMIN reply.
debug_device_reply(pm,
rx+1,
pkt_hdr);
#endif
}
else
{
TraceStr("load_reply");
// tell upper layer(port-manager) about ID reply
// port-manager does code loading.
if (hd->upper_layer_proc != NULL)
(*hd->upper_layer_proc)(hd->context,
EV_L2_BOOT_REPLY,
(DWORD) (rx+1));
}
}
#ifdef COMMENT_OUT
#endif
break;
case 3: // Product ID reply, reply by concentrator.
TraceStr("id_reply");
if (!server) // we are a server
break;
{
BYTE *list;
BYTE *new;
int i, found;
// driver previously sent out directed or broadcast query
// on network to detect boxes.
// build a list of units which reply.
// (rx+1) = ptr to reply address
// *(rx+1+6) = flags byte which indicate if main-driver loaded.
found = 0; // default to "did not find mac addr in list"
new = rx+1;
if (Driver.NumBoxMacs < MAX_NUM_BOXES)
{
for (i=0; i<Driver.NumBoxMacs; i++)
{
list = &Driver.BoxMacs[i*8];
if (mac_match(list, new))
found = 1; // found mac addr in list
}
}
if (!found) // then add to list of mac addresses found on network
{
if (Driver.NumBoxMacs < MAX_NUM_BOXES)
{
memcpy(&Driver.BoxMacs[Driver.NumBoxMacs*8], rx+1, 8);
Driver.BoxMacs[Driver.NumBoxMacs*8+7] = (BYTE)
nic_handle_to_index(nic);
Driver.BoxMacs[Driver.NumBoxMacs*8+6] = *(rx+1+6); // flags byte
if (Driver.NumBoxMacs < (MAX_NUM_BOXES-1))
++Driver.NumBoxMacs;
}
}
if (!Driver.TimerCreated) // init time(no hdlc levels active)
break; // so don't try to use hdlc
if ((hd = find_hdlc_handle(&pkt_hdr[6])) != NULL)
{
// stash the nic index in byte after flags byte
*(rx+1+7) = (BYTE) nic_handle_to_index(nic);
// tell upper layer(port-mananger) about ID reply
if (hd->upper_layer_proc != NULL)
(*hd->upper_layer_proc)(hd->context,
EV_L2_ADMIN_REPLY,
(DWORD) (rx+1));
}
else
{
#ifdef DO_AUTO_CONFIG
PSERIAL_DEVICE_EXTENSION need_ext;
MyKdPrint(D_Test,("Got Reply, Check AutoAssign\n"))
if (!(*(rx+1+6) & FLAG_APPL_RUNNING)) // no box driver running
{
MyKdPrint(D_Test,("AutoAssign1\n"))
// so probably free to auto-assign.
// see if any extensions need auto assignment
need_ext =need_mac_autoassign();
if ((need_ext != NULL) && (Driver.AutoMacDevExt == NULL))
{
MyKdPrint(D_Test,("AutoAssigned!\n"))
// set the mac addr for use
memcpy(need_ext->config->MacAddr, (rx+1), 6);
// signal the thread that auto-config needs
// to be written out to registry
Driver.AutoMacDevExt = need_ext;
}
}
#endif
}
}
break;
case 4: // Loopback request
TraceStr("aloop");
//eth_loop_back(rx, pkt_hdr, len);
break;
case 5: // Command, Reset
TraceStr("reset");
//eth_command_reset(rx, pkt_hdr, len);
break;
default:
TraceErr("admin, badpkt!");
break;
}
}
/*----------------------------------------------------------------------
find_hdlc_handle - find the Hdlc object with the same mac-address
as the ethernet header source mac address.
|----------------------------------------------------------------------*/
Hdlc *find_hdlc_handle(BYTE *rx)
{
PSERIAL_DEVICE_EXTENSION ext;
ext = Driver.board_ext;
while (ext != NULL)
{
if (mac_match(rx, ext->hd->dest_addr))
{
return ext->hd;
}
ext = ext->board_ext; // next one
}
TraceStr("find,NoMac Match!");
return NULL;
}
/*----------------------------------------------------------------------
need_mac_autoassign - Used for autoconfig of mac-address.
|----------------------------------------------------------------------*/
static PSERIAL_DEVICE_EXTENSION need_mac_autoassign(void)
{
PSERIAL_DEVICE_EXTENSION board_ext;
board_ext = Driver.board_ext;
while (board_ext != NULL)
{
// see if not configured
if ( (mac_match(board_ext->config->MacAddr, mac_zero_addr)) ||
(mac_match(board_ext->config->MacAddr, mac_bogus_addr)) )
return board_ext; // needs auto-assignment
board_ext = board_ext->board_ext;
}
return NULL; // its not used
}
/*----------------------------------------------------------------------
PacketReceiveComplete -
|----------------------------------------------------------------------*/
VOID PacketReceiveComplete(IN NDIS_HANDLE ProtocolBindingContext)
{
//Nic *nic = (Nic *)ProtocolBindingContext;
TraceStr("PcktRxComp");
//MyDeb(NULL, 0xffff, "PktRecComp, 1\n");
//lan_rec_proc(Driver->lan, nic->RxBuf, nic->len);
//netio_got_packet(Driver->lan, nic->RxBuf);
return;
}
/*----------------------------------------------------------------------
PacketTransferDataComplete -
|----------------------------------------------------------------------*/
VOID PacketTransferDataComplete (
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET pPacket,
IN NDIS_STATUS Status,
IN UINT BytesTransfered)
{
Nic *nic = (Nic *)ProtocolBindingContext;
TraceStr("nic, pend rx complete");
if ((nic->RxBuf[HDR_SIZE] != ASYNC_PRODUCT_HEADER_ID) &&
(nic->RxBuf[HDR_SIZE] != 0xff) )
{
TraceStr("not ours");
++nic->pkt_rcvd_not_ours;
nic->RxPackets[0]->ProtocolReserved[1] = 0; // mark as not use
return;
}
++nic->pkt_rcvd_ours;
GotOurPkt(nic);
return;
}
/*----------------------------------------------------------------------
PacketOpenAdapterComplete - Callback.
|----------------------------------------------------------------------*/
VOID PacketOpenAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN NDIS_STATUS OpenErrorStatus)
{
Nic *nic = (Nic *)ProtocolBindingContext;
nic->PendingStatus = Status;
TraceStr("PcktOpenAd");
KeSetEvent(&nic->CompletionEvent, 0L, FALSE);
return;
}
/*----------------------------------------------------------------------
PacketCloseAdapterComplete -
|----------------------------------------------------------------------*/
VOID PacketCloseAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status)
{
Nic *nic = (Nic *)ProtocolBindingContext;
TraceStr("PcktCloseAd");
nic->PendingStatus = Status;
KeSetEvent(&nic->CompletionEvent, 0L, FALSE);
return;
}
/*----------------------------------------------------------------------
PacketResetComplete -
|----------------------------------------------------------------------*/
VOID PacketResetComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status)
{
Nic *nic = (Nic *)ProtocolBindingContext;
TraceStr("PcktResetComplete");
nic->PendingStatus = Status;
KeSetEvent(&nic->CompletionEvent, 0L, FALSE);
return;
}
/*----------------------------------------------------------------------
PacketStatus -
|----------------------------------------------------------------------*/
VOID PacketStatus(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN PVOID StatusBuffer,
IN UINT StatusBufferSize)
{
TraceStr("PcktStat");
return;
}
/*----------------------------------------------------------------------
PacketStatusComplete -
|----------------------------------------------------------------------*/
VOID PacketStatusComplete(IN NDIS_HANDLE ProtocolBindingContext)
{
TraceStr("PcktStatComplete");
return;
}
/*----------------------------------------------------------------------
NicSetNICInfo -
|----------------------------------------------------------------------*/
NDIS_STATUS NicSetNICInfo(Nic *nic, NDIS_OID Oid, PVOID Data, ULONG Size)
{
NDIS_STATUS Status;
NDIS_REQUEST Request;
// Setup the request to send
Request.RequestType=NdisRequestSetInformation;
Request.DATA.SET_INFORMATION.Oid=Oid;
Request.DATA.SET_INFORMATION.InformationBuffer=Data;
Request.DATA.SET_INFORMATION.InformationBufferLength=Size;
NdisRequest(&Status,
nic->NICHandle,
&Request);
if (Status == NDIS_STATUS_SUCCESS)
{}
else if (Status == NDIS_STATUS_PENDING)
Status = NicWaitForCompletion(nic); // wait for completion
if (Status != NDIS_STATUS_SUCCESS)
{
MyKdPrint (D_Init,("NdisRequest Failed- Status %x\n",Status))
}
return Status;
}
/*----------------------------------------------------------------------
NicGetNICInfo - To call the NICs QueryInformationHandler
|----------------------------------------------------------------------*/
NDIS_STATUS NicGetNICInfo(Nic *nic, NDIS_OID Oid, PVOID Data, ULONG Size)
{
NDIS_STATUS Status;
NDIS_REQUEST Request;
// Setup the request to send
Request.RequestType=NdisRequestQueryInformation;
Request.DATA.SET_INFORMATION.Oid=Oid;
Request.DATA.SET_INFORMATION.InformationBuffer=Data;
Request.DATA.SET_INFORMATION.InformationBufferLength=Size;
NdisRequest(&Status,
nic->NICHandle,
&Request);
if (Status == NDIS_STATUS_SUCCESS)
{}
else if (Status == NDIS_STATUS_PENDING)
Status = NicWaitForCompletion(nic); // wait for completion
if (Status != NDIS_STATUS_SUCCESS)
{
MyKdPrint (D_Init,("NdisRequest Failed- Status %x\n",Status))
}
return Status;
}
/*--------------------------------------------------------------------------
| nic_send_pkt -
|--------------------------------------------------------------------------*/
int nic_send_pkt(Nic *nic, BYTE *buf, int len)
{
// BYTE *bptr;
// int cnt;
NTSTATUS Status;
//int pkt_num;
if (nic == NULL)
{
MyKdPrint(D_Error, ("E1\n"))
TraceErr("snd1a");
return 1;
}
if (nic->TxBufTemp == NULL)
{
MyKdPrint(D_Error, ("E2\n"))
TraceErr("snd1b");
return 1;
}
if (nic->TxPacketsTemp == NULL)
{
MyKdPrint(D_Error, ("E3\n"))
TraceErr("snd1c");
return 1;
}
if (nic->Open == 0)
{
MyKdPrint(D_Error, ("E4\n"))
TraceErr("snd1d");
return 1;
}
DbgNicSet(nic);
TraceStr("send_pkt");
if (nic->TxPacketsTemp->ProtocolReserved[1] & 1) // marked as pending
{
TraceErr("snd1e");
// reset in case it got stuck
// nic->TxPacketsTemp->ProtocolReserved[1] = 0;
return 3;
}
memcpy(nic->TxBufTemp, buf, len);
nic->TxPacketsTemp->Private.TotalLength = len;
NdisAdjustBufferLength(nic->TxPacketsTemp->Private.Head, len);
nic->TxPacketsTemp->ProtocolReserved[1] = 1; // mark as pending
NdisSend(&Status, nic->NICHandle, nic->TxPacketsTemp);
if (Status == NDIS_STATUS_SUCCESS)
{
TraceStr("snd ok");
nic->TxPacketsTemp->ProtocolReserved[1] = 0; // free for use
}
else if (Status == NDIS_STATUS_PENDING)
{
TraceStr("snd pend");
// Status = NicWaitForCompletion(nic); // wait for completion
}
else
{
nic->TxPacketsTemp->ProtocolReserved[1] = 0; // free for use
TraceErr("send1A");
return 1;
}
++nic->pkt_sent; // statistics
nic->send_bytes += len; // statistics
return 0;
}
#ifdef TRY_DYNAMIC_BINDING
/*----------------------------------------------------------------------
PacketBind - Called when nic card ready to use. Passes in name of
nic card. NDIS40 protocol only.
|----------------------------------------------------------------------*/
VOID PacketBind(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE BindContext,
IN PNDIS_STRING DeviceName,
IN PVOID SystemSpecific1,
IN PVOID SystemSpecific2)
{
int i,stat;
MyKdPrint(D_Init,("Dyn. Bind\n"))
TraceErr("DynBind");
TraceErr(UToC1(DeviceName));
// NIC not open - retry open
for (i=0; i<VS1000_MAX_NICS; i++)
{
MyKdPrint(D_Init,("D1\n"))
if((Driver.nics[i].NICHandle == NULL) &&
(Driver.NicName[i].Buffer == NULL))
{
MyKdPrint(D_Init,("D2\n"))
// make a copy of the nic-name
Driver.NicName[i].Buffer =
our_locked_alloc(DeviceName->Length + sizeof(WCHAR), "pkbd");
memcpy(Driver.NicName[i].Buffer, DeviceName->Buffer, DeviceName->Length);
Driver.NicName[i].Length = DeviceName->Length;
Driver.NicName[i].MaximumLength = DeviceName->Length;
stat = NicOpen(&Driver.nics[i], &Driver.NicName[i]);
if (stat)
{
TraceErr("Bad NicOpen");
*Status = NDIS_STATUS_NOT_ACCEPTED;
return;
}
else
{
MyKdPrint(D_Init,("D3\n"))
Driver.BindContext[i] = BindContext; // save this for the unbind
*Status = NDIS_STATUS_SUCCESS;
return;
}
}
}
MyKdPrint(D_Init,("D4\n"))
*Status = NDIS_STATUS_NOT_ACCEPTED;
return;
//if (pended)
// NdisCompleteBindAdapter(BindContext);
}
/*----------------------------------------------------------------------
PacketUnBind - Called when nic card is shutting down, going away.
NDIS40 protocol only.
|----------------------------------------------------------------------*/
VOID PacketUnBind(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE UnbindContext)
{
int i, pi;
TraceErr("DynUnBind");
//if (pend)
// NdisCompleteUnBindAdapter(BindContext);
// NIC not open - retry open
// find the nic card which is closing up shop
for (i=0; i<Driver.num_nics; i++)
{
if (Driver.BindContext[i] == ProtocolBindingContext) // a match!
{
TraceErr("fnd UnBind");
if((Driver.nics[i].NICHandle != NULL) &&
(Driver.nics[i].Open))
{
// first find all the box objects, and shut them down
// BUGBUG: we should use some spinlocks here, we are in danger of
// doing two things at once(pulling the rug out from under
// port.c operations while it is running.
ext = Driver.board_ext;
while (ext)
{
if (Driver.pm[pi].nic_index == i) // its using this nic card
{
if (Driver.pm[pi].state == Driver.pm[i].state)
{
TraceErr("Shutdown box");
Driver.pm[pi].state = ST_INIT;
}
}
ext = ext->board_ext;
}
NicClose(&Driver.nics[i]);
if (Driver.NicName[i].Buffer)
{
our_free(Driver.NicName[i].Buffer, "pkbd"); // free up the unicode buf
Driver.NicName[i].Buffer = 0;
}
}
Driver.BindContext[i] = 0;
}
}
*Status = NDIS_STATUS_SUCCESS;
return;
}
#endif
/*----------------------------------------------------------------------
nic_handle_to_index - given a nic handle, give the index into the
linked list, or array.
|----------------------------------------------------------------------*/
static int nic_handle_to_index(Nic *nic)
{
int i;
for (i=0; i<VS1000_MAX_NICS; i++)
{
if ((&Driver.nics[i]) == nic)
return i;
}
TraceErr("BadIndex");
return 0;
}
#if 0
/*----------------------------------------------------------------------
PacketTranslate -
|----------------------------------------------------------------------*/
VOID PacketTranslate(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE ProtocolBindingContext,
OUT PNET_PNP_ID IdList,
IN ULONG IdListLength,
OUT PULONG BytesReturned)
{
}
/*----------------------------------------------------------------------
PacketUnLoad -
|----------------------------------------------------------------------*/
VOID PacketUnLoad(VOID)
{
}
#endif