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

524 lines
11 KiB

/*******************************************************************/
/* Copyright(c) 1993 Microsoft Corporation */
/*******************************************************************/
//***
//
// Filename: send.c
//
// Description: send packet routines
//
// Author: Stefan Solomon (stefans) October 11, 1993.
//
// Revision History:
//
//***
#include "rtdefs.h"
VOID
SendPacketComplete(PPACKET_TAG pktp);
UINT
SendPropagatedPacketComplete(PPACKET_TAG pktp);
VOID
UpdateSendStatistics(PNICCB niccb,
PPACKET_TAG pktp);
VOID
SetType20PktDestNet(PPACKET_TAG pktp);
VOID
UpdateRipResponseTickCount(PUCHAR hdrp,
PNICCB niccbp);
//*** max send pkts queued limit: over this limit the send pkts get discarded
ULONG MaxSendPktsQueued = MAX_SEND_PKTS_QUEUED;
//***
//
// Function: SendPacket
//
// Descr: enqueues the packet in the requested Nic queue and initiates
// the send
//
// Params: Packet
//
// Returns: none
//
//***
VOID
SendPacket(PPACKET_TAG pktp)
{
PNDIS_PACKET pktdescrp;
NDIS_STATUS NdisStatus;
UINT BufferCount;
PNDIS_BUFFER FirstBufferp;
USHORT pktlen;
PNICCB niccbp;
PUCHAR hdrp;
RtPrint(DBG_SEND, ("IpxRouter: SendPacket: pktp=0x%x\n", pktp));
// get the packet length
hdrp = pktp->DataBufferp;
GETSHORT2USHORT(&pktlen, hdrp + IPXH_LENGTH);
// get the pkt descr ptr
pktdescrp = CONTAINING_RECORD(pktp, NDIS_PACKET, ProtocolReserved);
// adjust the length of the packet to send
NdisQueryPacket(pktdescrp,
NULL,
&BufferCount,
&FirstBufferp,
NULL);
NdisAdjustBufferLength(FirstBufferp, pktlen);
// chain the mac hdr buff descr at the front (the mac hdr buff descr
// already points at the Mac header in the packet tag)
NdisChainBufferAtFront(pktdescrp, pktp->HeaderBuffDescrp);
// get the Nic Cb ptr where we should send this packet
niccbp = NicCbPtrTab[pktp->RemoteAddress.NicId];
// Do not send if it doesn't fit the max frame size
// for this adapter
if(pktlen > niccbp->MaximumPacketSize) {
SendPacketComplete(pktp);
return;
}
// if the packet is a RIP Response, update the tick count in the
// network entry fields
UpdateRipResponseTickCount(hdrp, niccbp);
ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
// check Nic Status. Do not send on a closed Nic
if(niccbp->NicState != NIC_ACTIVE) {
RELEASE_SPIN_LOCK(&niccbp->NicLock);
SendPacketComplete(pktp);
return;
}
// check if we are allowed to queue this packet (we aren't over limit)
if(niccbp->SendPktsQueuedCount >= MaxSendPktsQueued) {
RELEASE_SPIN_LOCK(&niccbp->NicLock);
SendPacketComplete(pktp);
return;
}
// Nic is active, we can send
UpdateSendStatistics(niccbp, pktp);
// set the QUEUE owner of the packet
pktp->QueueOwnerNicCbp = niccbp;
// enqueue the packet in the NIC's send list and wait for the
// transfer to complete
InsertTailList(&niccbp->SendQueue, &pktp->PacketLinkage);
// increment the queued pkts counter
niccbp->SendPktsQueuedCount++;
RELEASE_SPIN_LOCK(&niccbp->NicLock);
// send the packet
NdisStatus = IpxSendPacket(&pktp->RemoteAddress,
pktdescrp,
pktlen,
0);
if(NdisStatus != NDIS_STATUS_PENDING) {
RtSendComplete(pktdescrp, NdisStatus);
}
}
//***
//
// Function: RtSendComplete
//
// Descr: called by the IPX driver when send completed
//
// Params:
//
// Returns:
//
//***
VOID
RtSendComplete(PNDIS_PACKET pktdescrp,
NDIS_STATUS NdisStatus)
{
PNICCB niccbp;
PPACKET_TAG pktp;
pktp = (PPACKET_TAG)pktdescrp->ProtocolReserved;
RtPrint(DBG_SEND, ("IpxRouter: RtSendComplete: pktp=0x%x\n", pktp));
niccbp = pktp->QueueOwnerNicCbp;
#if DBG
// this is for debugging purposes
if(NdisStatus != NDIS_STATUS_SUCCESS) {
RtPrint(DBG_NOTIFY, ("IpxRouter: SendPacket: FAILED with %xl\n", NdisStatus));
}
#endif
// dequeue the packet from the send queue and complete processing
ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
RemoveEntryList(&pktp->PacketLinkage);
// decrement queued send pkts counter
niccbp->SendPktsQueuedCount--;
RELEASE_SPIN_LOCK(&niccbp->NicLock);
// complete the send packet processing
SendPacketComplete(pktp);
}
//***
//
// Function: SendPacketComplete
//
// Descr: post send processing
//
// Params: Packet
//
// Returns: None
//
//***
VOID
SendPacketComplete(PPACKET_TAG pktp)
{
PNDIS_PACKET NdisPacket;
PNDIS_BUFFER NdisBuffer = NULL;
UINT BufferCount;
RtPrint(DBG_SEND, ("IpxRouter: SendPacketComplete: Entered\n"));
// unchain the first buffer descriptor (MacHeader)
NdisPacket = CONTAINING_RECORD(pktp, NDIS_PACKET, ProtocolReserved);
NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
ASSERT(NdisBuffer == pktp->HeaderBuffDescrp);
// readjust the original buffer descriptor length
// get the pkt descr ptr
NdisQueryPacket(NdisPacket,
NULL,
&BufferCount,
&NdisBuffer,
NULL);
NdisAdjustBufferLength(NdisBuffer, pktp->DataBufferLength);
NdisRecalculatePacketCounts(NdisPacket);
// what to do next is controlled by the packet type
switch(pktp->PacketType) {
case RCV_PACKET:
// this has been a routed packet or a directed rip reply
// free it to the rcv pkt pool and discharge the nic
FreeRcvPkt(pktp);
break;
case RIP_SEND_PACKET:
// call the completion routines for these guys
SendRipPktCompleted(pktp);
break;
case PROPAGATED_BCAST_PACKET:
// send the packet on the next available net (if any left) or return it
// to the pool
if(SendPropagatedPacketComplete(pktp)) {
RtPrint(DBG_NETBIOS, ("IpxRouter: SendPacketComplete: free propagated pkt 0x%x\n", pktp));
// can't propagate further, return to rcv pkt pool
FreeRcvPkt(pktp);
}
break;
default:
// !!! break
ASSERT(FALSE);
break;
}
}
//***
//
// Function: SendPropagatedPacket
//
// Descr: marks the packet as a propagated packet type and sends it
// starting at the beginning of the LanNics list
//
// Params: Packet
//
// Returns: none
//
//***
VOID
SendPropagatedPacket(PPACKET_TAG pktp)
{
USHORT i;
PNICCB niccbp;
// check if there is an active Nic to send on next and if this Nic is
// active and is not the packet owner nic
for(i=0; i<MaximumNicCount; i++) {
niccbp = NicCbPtrTab[i];
if((niccbp->NicState == NIC_ACTIVE) &&
(IsNetbiosRoutingAllowed(pktp->PacketOwnerNicCbp, niccbp)) &&
(!IsNetInNbPacket(pktp, niccbp))) {
// send the packet on this nic
pktp->PacketType = PROPAGATED_BCAST_PACKET;
pktp->RemoteAddress.NicId = niccbp->NicId;
memcpy(pktp->RemoteAddress.MacAddress, bcastaddress, 6);
RtPrint(DBG_NETBIOS, ("IpxRouter: SendPropagatedPacket: send pkt 0x%x on Nic %d\n", pktp, niccbp->NicId));
SetType20PktDestNet(pktp);
SendPacket(pktp);
return;
}
}
// can't propagate this packet, free it
FreeRcvPkt(pktp);
}
//***
//
// Function: SendPropagatedPacketComplete
//
// Descr: If there is a next active NicCb to send the packet on, queues
// the packet in the propagation list and queues a Dpc to send the
// packet on this Nic.
//
// Params: Packet
//
// Returns: 0 - packet queued for propagation, 1 - can't propagate further
//
//***
UINT
SendPropagatedPacketComplete(PPACKET_TAG pktp)
{
PNICCB niccbp; // nic that has sent the packet
USHORT i;
// check if there is another active Nic to send on next and if this Nic is
// active and is not the packet owner nic
for(i=pktp->RemoteAddress.NicId+1; // next Nic Id
i<MaximumNicCount;
i++) {
niccbp = NicCbPtrTab[i];
if((niccbp->NicState == NIC_ACTIVE) &&
(IsNetbiosRoutingAllowed(pktp->PacketOwnerNicCbp, niccbp)) &&
(!IsNetInNbPacket(pktp, niccbp))) {
// We have found the next nic.
pktp->RemoteAddress.NicId = i;
// queue the packet for a propagated send.
ACQUIRE_SPIN_LOCK(&PropagatedPktsListLock);
InsertTailList(&PropagatedPktsList, &pktp->PacketLinkage);
if(!PropagatedPktsDpcQueued) {
// queue a Dpc to send the packet
KeInsertQueueDpc(&PropagatedPktsDpc, NULL, NULL);
PropagatedPktsDpcQueued = TRUE;
}
RELEASE_SPIN_LOCK(&PropagatedPktsListLock);
return 0;
}
}
// we are done with this packet
return 1;
}
//***
//
// Function: SendNextPropagatedPacket
//
// Descr: DPC called routine which dequeues the next packet from the
// propagated packets list and sends it
//
// Params: none
//
// Returns: none
//
//***
VOID
SendNextPropagatedPkt(PKDPC Dpc,
PVOID DefferedContext,
PVOID SystemArgument1,
PVOID SystemArgument2)
{
PLIST_ENTRY lep;
PPACKET_TAG pktp;
LIST_ENTRY sendlist;
InitializeListHead(&sendlist);
// get next item from the propagated bcast queue and send it
ACQUIRE_SPIN_LOCK(&PropagatedPktsListLock);
PropagatedPktsDpcQueued = FALSE;
while(!IsListEmpty(&PropagatedPktsList)) {
lep = RemoveHeadList(&PropagatedPktsList);
InsertTailList(&sendlist, lep);
}
RELEASE_SPIN_LOCK(&PropagatedPktsListLock);
while(!IsListEmpty(&sendlist)) {
lep = RemoveHeadList(&sendlist);
pktp = CONTAINING_RECORD(lep, PACKET_TAG, PacketLinkage);
SetType20PktDestNet(pktp);
SendPacket(pktp);
}
}
VOID
UpdateSendStatistics(PNICCB niccbp,
PPACKET_TAG pktp)
{
PUCHAR hdrp;
USHORT srcsock;
switch(pktp->PacketType) {
case RCV_PACKET:
hdrp = pktp->DataBufferp;
GETSHORT2USHORT(&srcsock, hdrp + IPXH_DESTSOCK);
if(srcsock == IPX_RIP_SOCKET) {
niccbp->StatRipSent++;
}
else
{
niccbp->StatRoutedSent++;
}
break;
case RIP_SEND_PACKET:
niccbp->StatRipSent++;
break;
case PROPAGATED_BCAST_PACKET:
niccbp->StatType20Sent++;
break;
default:
break;
}
}
VOID
SetType20PktDestNet(PPACKET_TAG pktp)
{
PNICCB niccbp;
PUCHAR hdrp;
// get the Nic Cb ptr where we should send this packet
niccbp = NicCbPtrTab[pktp->RemoteAddress.NicId];
// set the destination net in the packet
hdrp = pktp->DataBufferp;
memcpy(hdrp + IPXH_DESTNET, niccbp->Network, 4);
}
VOID
UpdateRipResponseTickCount(PUCHAR hdrp,
PNICCB niccbp)
{
USHORT resplen;
USHORT pktlen;
USHORT srcsock;
USHORT opcode;
USHORT nrofticks;
// check if this is a RIP Response packet
GETSHORT2USHORT(&srcsock, hdrp + IPXH_SRCSOCK);
if(srcsock != IPX_RIP_SOCKET) {
return;
}
GETSHORT2USHORT(&opcode, hdrp + RIP_OPCODE);
if(opcode != RIP_RESPONSE) {
return;
}
//*** RIP Response Packet ***
// get the response packet length
GETSHORT2USHORT(&pktlen, hdrp + IPXH_LENGTH);
// for each network entry, increment the number of ticks so that
// we add the nr of ticks for the nic to send the packet on
for(resplen = RIP_INFO;
resplen < pktlen;
resplen += NE_ENTRYSIZE) {
GETSHORT2USHORT(&nrofticks, hdrp + resplen + NE_NROFTICKS);
nrofticks += niccbp->TickCount;
PUTUSHORT2SHORT(hdrp + resplen + NE_NROFTICKS, nrofticks);
}
}