mirror of https://github.com/lianthony/NT4.0
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.
1176 lines
27 KiB
1176 lines
27 KiB
/*******************************************************************/
|
|
/* Copyright(c) 1993 Microsoft Corporation */
|
|
/*******************************************************************/
|
|
|
|
//***
|
|
//
|
|
// Filename: ripsend.c
|
|
//
|
|
// Description: processes rip send requests queued at the different
|
|
// queues: send all nets and send one net
|
|
//
|
|
// Author: Stefan Solomon (stefans) October 11, 1993.
|
|
//
|
|
// Revision History:
|
|
//
|
|
//***
|
|
|
|
#include <memory.h>
|
|
#include <string.h>
|
|
#include "rtdefs.h"
|
|
|
|
NDIS_SPIN_LOCK RipGlobalSndListLock;
|
|
LIST_ENTRY RipGlobalSndList;
|
|
|
|
// this global specifies the type of RIP updates on WAN.
|
|
// For this first version it is set to 0 -> No Rip updates on WAN.
|
|
ULONG RipWanUpdate;
|
|
|
|
VOID
|
|
StartRipSndAtNic(PVOID Parameter);
|
|
|
|
VOID
|
|
InterPktGapTimeout(PKDPC Dpc,
|
|
PVOID DefferedContext,
|
|
PVOID SystemArgument1,
|
|
PVOID SystemArgument2);
|
|
|
|
PNICCB
|
|
GetFirstAvailabelNic(USHORT BaseNicId,
|
|
PNICCB DoNotSendNicCbp);
|
|
|
|
UINT
|
|
MakeRipSendPkts(PNICCB niccbp);
|
|
|
|
UINT
|
|
MakeRipGenResponsePkts(PNICCB niccbp);
|
|
|
|
PPACKET_TAG
|
|
AllocRipGenResponsePkt(PNICCB niccbp);
|
|
|
|
UINT
|
|
MakeRipUpdatePkt(PNICCB niccbp);
|
|
|
|
UINT
|
|
MakeRipGenRequestPkt(PNICCB niccbp);
|
|
|
|
PPACKET_TAG
|
|
CreateRipNdisPkt(PRIP_SNDPKT_BUFF rbp,
|
|
PNICCB niccbp);
|
|
|
|
PRIP_SNDPKT_BUFF
|
|
DestroyRipNdisPkt(PPACKET_TAG pktp);
|
|
|
|
PNICCB
|
|
GetFirstAvailableNic(USHORT BaseNicId,
|
|
PNICCB DoNotSendNicCbp);
|
|
|
|
|
|
VOID
|
|
StartInterPktGapTimer(PNICCB niccbp);
|
|
|
|
VOID
|
|
SetRipIpxHeader(PUCHAR hdrp, // pointer to the packet header
|
|
PNICCB niccbp, // pointer to the rip send request
|
|
USHORT RipOpcode);
|
|
|
|
VOID
|
|
SetRipRemoteAddress(PPACKET_TAG pktp,
|
|
PNICCB niccbp);
|
|
|
|
//***
|
|
//
|
|
// Function: InitRipSndDispatcher
|
|
//
|
|
// Descr: initializes the global Rip send dispatcher
|
|
//
|
|
// Params: none
|
|
//
|
|
// Returns: none
|
|
//
|
|
//***
|
|
|
|
VOID
|
|
InitRipSndDispatcher(VOID)
|
|
{
|
|
INITIALIZE_SPIN_LOCK(&RipGlobalSndListLock);
|
|
InitializeListHead(&RipGlobalSndList);
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: InitRipSndAtNic
|
|
//
|
|
// Descr: Called at nic init time.
|
|
// Initializes the nic based Rip send machine
|
|
//
|
|
// Params: none
|
|
//
|
|
// Returns: none
|
|
//
|
|
//***
|
|
|
|
|
|
VOID
|
|
InitRipSndAtNic(PNICCB niccbp)
|
|
{
|
|
InitializeListHead(&niccbp->RipSendQueue);
|
|
|
|
// set the rip send machine to IDLE state
|
|
niccbp->RipSndReqp = NULL;
|
|
|
|
InitializeListHead(&niccbp->RipSndPktsList);
|
|
|
|
ExInitializeWorkItem(&niccbp->RipSndReqWorkItem, StartRipSndAtNic, niccbp);
|
|
|
|
KeInitializeDpc(&niccbp->InterPktGapDpc, InterPktGapTimeout, niccbp);
|
|
KeInitializeTimer(&niccbp->InterPktGapTimer);
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: RipDispatchSndReq
|
|
//
|
|
// Descr:
|
|
//
|
|
//***
|
|
|
|
VOID
|
|
RipDispatchSndReq(PRIP_SNDREQ sndreqp)
|
|
{
|
|
PNICCB niccbp;
|
|
|
|
RtPrint(DBG_SNDREQ, ("IpxRouter: RipDispatchSndReq: Entered\n"));
|
|
|
|
// get the first available nic to get the send request
|
|
// a non-null value in the DoNotSendNicCbp indicates we should not use
|
|
// this nic as a sender
|
|
niccbp = GetFirstAvailableNic(0, sndreqp->DoNotSendNicCbp);
|
|
if(niccbp == NULL) {
|
|
|
|
// if this was an update AND we are unloading AND event has to be
|
|
// signaled, do it
|
|
if((sndreqp->SndReqId == RIP_UPDATE) &&
|
|
(sndreqp->SndCompleteEventp != NULL) &&
|
|
RouterUnloading) {
|
|
|
|
KeSetEvent(sndreqp->SndCompleteEventp, 0L, FALSE);
|
|
}
|
|
|
|
ExFreePool(sndreqp);
|
|
return;
|
|
}
|
|
ACQUIRE_SPIN_LOCK(&RipGlobalSndListLock);
|
|
|
|
InsertTailList(&RipGlobalSndList, &sndreqp->GlobalLinkage);
|
|
|
|
RELEASE_SPIN_LOCK(&RipGlobalSndListLock);
|
|
|
|
sndreqp->SenderNicCbp = niccbp;
|
|
if(!RipQueueSndReqAtNic(niccbp, sndreqp)) {
|
|
|
|
// can't dispatch to this nic, call completion
|
|
RipSendAtNicCompleted(sndreqp);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
RipSendAtNicCompleted(PRIP_SNDREQ sndreqp)
|
|
{
|
|
BOOLEAN Done = FALSE; // we are done with this snd req
|
|
BOOLEAN QueuedAtNic = FALSE; // request queued at a nic
|
|
PNICCB niccbp;
|
|
|
|
RtPrint(DBG_SNDREQ, ("IpxRouter: RipSendAtNicCompleted: Entered for NicId %d\n", sndreqp->SenderNicCbp->NicId));
|
|
|
|
if(!sndreqp->SendOnAllNics) {
|
|
|
|
// this request had to be sent on one nic only and is now terminated
|
|
Done = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// this request has to be sent on all nics
|
|
// loop until the request is queued at a nic OR there are no more
|
|
// nics available
|
|
while(!Done && !QueuedAtNic) {
|
|
|
|
// get the next available nic to get the send request
|
|
niccbp = GetFirstAvailableNic(sndreqp->SenderNicCbp->NicId,
|
|
sndreqp->DoNotSendNicCbp);
|
|
if(niccbp == NULL) {
|
|
|
|
// No nic available
|
|
ACQUIRE_SPIN_LOCK(&RipGlobalSndListLock);
|
|
|
|
RemoveEntryList(&sndreqp->GlobalLinkage);
|
|
|
|
RELEASE_SPIN_LOCK(&RipGlobalSndListLock);
|
|
Done = TRUE;
|
|
}
|
|
else
|
|
{
|
|
sndreqp->SenderNicCbp = niccbp;
|
|
QueuedAtNic = RipQueueSndReqAtNic(niccbp, sndreqp);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(Done) {
|
|
|
|
// if this was an update and we are unloading and event has to be
|
|
// signaled, do it
|
|
if((sndreqp->SndReqId == RIP_UPDATE) &&
|
|
(sndreqp->SndCompleteEventp != NULL) &&
|
|
RouterUnloading) {
|
|
|
|
KeSetEvent(sndreqp->SndCompleteEventp, 0L, FALSE);
|
|
}
|
|
|
|
ExFreePool(sndreqp);
|
|
}
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: RipQueueSndReqAtNic
|
|
//
|
|
// Descr: Queues the Rip send req at this nic for delivery
|
|
// The Nic has been verified that is active prior to queueing
|
|
//
|
|
// Returns: TRUE - queued OK, FALSE - could not queue
|
|
//
|
|
//***
|
|
|
|
BOOLEAN
|
|
RipQueueSndReqAtNic(PNICCB niccbp,
|
|
PRIP_SNDREQ sndreqp)
|
|
{
|
|
// check if we should start work right away or should queue it
|
|
// for deffered processing
|
|
|
|
ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
|
|
|
|
// check if rip sending is enabled on this nic
|
|
if(niccbp->NicState != NIC_ACTIVE) {
|
|
|
|
RELEASE_SPIN_LOCK(&niccbp->NicLock);
|
|
|
|
RtPrint(DBG_SNDREQ, ("IpxRouter: RipQueueSndReqAtNic: NicId %d is closed or closing, cannot queue the snd req\n", niccbp->NicId));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// check if the rip send machine is ACTIVE
|
|
if(niccbp->RipSndReqp != NULL) {
|
|
|
|
// the machine is ACTIVE processing another snd req; queue for later
|
|
InsertTailList(&niccbp->RipSendQueue, &sndreqp->NicLinkage);
|
|
|
|
RELEASE_SPIN_LOCK(&niccbp->NicLock);
|
|
|
|
RtPrint(DBG_SNDREQ, ("IpxRouter: RipQueueSndReqAtNic: Queued for NicId %d\n", niccbp->NicId));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// The RIP send machine for this Nic is IDLE. Activate it.
|
|
niccbp->RipSndReqp = sndreqp;
|
|
|
|
RELEASE_SPIN_LOCK(&niccbp->NicLock);
|
|
|
|
RtPrint(DBG_SNDREQ, ("IpxRouter: RipQueueSndReqAtNic: Started for NicId %d\n", niccbp->NicId));
|
|
|
|
// if this is a directed response queue it in the critical, else noncritical
|
|
if((sndreqp->SndReqId == RIP_GEN_RESPONSE) &&
|
|
(memcmp(sndreqp->DestNode, bcastaddress, IPX_NODE_LEN))) {
|
|
|
|
ExQueueWorkItem(&niccbp->RipSndReqWorkItem, CriticalWorkQueue);
|
|
}
|
|
else
|
|
{
|
|
ExQueueWorkItem(&niccbp->RipSndReqWorkItem, DelayedWorkQueue);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: StartRipSndAtNic
|
|
//
|
|
// Descr: This routine is the work item queued by
|
|
// RipQueueSndReqAtNic when it starts the Rip Send Machine for
|
|
// this Nic.
|
|
//
|
|
// Params: Ptr to the Nic
|
|
//
|
|
//***
|
|
|
|
VOID
|
|
StartRipSndAtNic(PVOID Parameter)
|
|
{
|
|
PNICCB niccbp;
|
|
PLIST_ENTRY lep;
|
|
PPACKET_TAG pktp;
|
|
|
|
niccbp = (PNICCB)Parameter;
|
|
|
|
// check that the rip send machine has been activated
|
|
ASSERT(niccbp->RipSndReqp != NULL);
|
|
|
|
// allocate and prepare the packets for this send and queue them
|
|
// at the nic
|
|
while(MakeRipSendPkts(niccbp)) {
|
|
|
|
// No packets have been prepared. Notify the dispatcher that we are
|
|
// done with this request.
|
|
RipSendAtNicCompleted(niccbp->RipSndReqp);
|
|
|
|
// try to get the next send request queued at this nic
|
|
ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
|
|
|
|
if(IsListEmpty(&niccbp->RipSendQueue)) {
|
|
|
|
// no more work for this Nic -> set it to IDLE state
|
|
niccbp->RipSndReqp = NULL;
|
|
|
|
// !!! announce the closing machine that the current Rip send processing has terminated !!!
|
|
|
|
RELEASE_SPIN_LOCK(&niccbp->NicLock);
|
|
return;
|
|
}
|
|
|
|
// there are snd requests queued
|
|
lep = RemoveHeadList(&niccbp->RipSendQueue);
|
|
|
|
// set rip send machine to ACTIVE state
|
|
niccbp->RipSndReqp = CONTAINING_RECORD(lep, RIP_SNDREQ, NicLinkage);
|
|
|
|
RELEASE_SPIN_LOCK(&niccbp->NicLock);
|
|
}
|
|
|
|
//*** send the first prepared packet ***
|
|
|
|
lep = RemoveHeadList(&niccbp->RipSndPktsList);
|
|
pktp = CONTAINING_RECORD(lep, PACKET_TAG, PacketLinkage);
|
|
SendPacket(pktp);
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: SendRipPktCompleted
|
|
//
|
|
// Descr: This function is called by the send completion routine when
|
|
// a Rip send packet has been completed.
|
|
//
|
|
//***
|
|
|
|
VOID
|
|
SendRipPktCompleted(PPACKET_TAG pktp)
|
|
{
|
|
PNICCB niccbp;
|
|
PRIP_SNDPKT_BUFF rbp;
|
|
|
|
niccbp = pktp->PacketOwnerNicCbp;
|
|
|
|
// Destroy the ndis parts of the packet and get back the original snd pkt
|
|
// structure
|
|
rbp = DestroyRipNdisPkt(pktp);
|
|
|
|
// If this was not an update broadcast, release the send pkt buffer struct
|
|
if(niccbp->RipSndReqp->SndReqId != RIP_UPDATE) {
|
|
|
|
// free the snd pkt buffer
|
|
ExFreePool(rbp);
|
|
}
|
|
|
|
// set the machine to wait for a interpacket gap
|
|
StartInterPktGapTimer(niccbp);
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: InterPktGapTimeout
|
|
//
|
|
// Descr: Called by the timer Nic interpacket gap timer DPC when the
|
|
// interpacket gap timeout expired. Sends the next packet in the list
|
|
//
|
|
//***
|
|
|
|
VOID
|
|
InterPktGapTimeout(PKDPC Dpc,
|
|
PVOID DefferedContext,
|
|
PVOID SystemArgument1,
|
|
PVOID SystemArgument2)
|
|
{
|
|
PNICCB niccbp;
|
|
PLIST_ENTRY lep;
|
|
PPACKET_TAG pktp;
|
|
|
|
niccbp = (PNICCB)DefferedContext;
|
|
|
|
// check if we have more packets to send from this request
|
|
if(!IsListEmpty(&niccbp->RipSndPktsList)) {
|
|
|
|
// dequeue the first packet from the list and send it
|
|
lep = RemoveHeadList(&niccbp->RipSndPktsList);
|
|
pktp = CONTAINING_RECORD(lep, PACKET_TAG, PacketLinkage);
|
|
|
|
SendPacket(pktp);
|
|
return;
|
|
}
|
|
|
|
//*** This Rip send has been completed ***
|
|
|
|
// Notify the UPPER machine
|
|
RipSendAtNicCompleted(niccbp->RipSndReqp);
|
|
|
|
// check if there are more send requests queued
|
|
ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
|
|
|
|
if(IsListEmpty(&niccbp->RipSendQueue)) {
|
|
|
|
// set the rip send machine to IDLE state
|
|
niccbp->RipSndReqp = NULL;
|
|
|
|
// !!! announce the closing machine that the current Rip send processing has terminated !!!
|
|
|
|
RELEASE_SPIN_LOCK(&niccbp->NicLock);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// there are snd requests queued
|
|
lep = RemoveHeadList(&niccbp->RipSendQueue);
|
|
|
|
// set the rip send machine to ACTIVE state
|
|
niccbp->RipSndReqp = CONTAINING_RECORD(lep, RIP_SNDREQ, NicLinkage);
|
|
|
|
RELEASE_SPIN_LOCK(&niccbp->NicLock);
|
|
}
|
|
|
|
// start a new work item to take care of this send
|
|
// if this is a directed response queue it in the critical, else noncritical
|
|
if((niccbp->RipSndReqp->SndReqId == RIP_GEN_RESPONSE) &&
|
|
(memcmp(niccbp->RipSndReqp->DestNode, bcastaddress, IPX_NODE_LEN))) {
|
|
|
|
ExQueueWorkItem(&niccbp->RipSndReqWorkItem, CriticalWorkQueue);
|
|
}
|
|
else
|
|
{
|
|
ExQueueWorkItem(&niccbp->RipSndReqWorkItem, DelayedWorkQueue);
|
|
}
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: GetFirstAvailableNic
|
|
//
|
|
// Descr: returns the nic cbp ptr of the first nic starting with the
|
|
// specified base, which is not the src nic and which is active
|
|
//
|
|
//***
|
|
|
|
PNICCB
|
|
GetFirstAvailableNic(USHORT BaseNicId,
|
|
PNICCB DoNotSendNicCbp)
|
|
{
|
|
USHORT i;
|
|
USHORT StartNicId;
|
|
PNICCB niccbp;
|
|
|
|
if(BaseNicId == 0) {
|
|
|
|
// we start from the beginning of the table
|
|
StartNicId = 0;
|
|
}
|
|
else
|
|
{
|
|
// check if this was the last nic
|
|
if(BaseNicId >= MaximumNicCount - 1) {
|
|
|
|
return NULL;
|
|
}
|
|
|
|
StartNicId = BaseNicId + 1;
|
|
}
|
|
|
|
for(i=StartNicId; i<MaximumNicCount; i++) {
|
|
|
|
niccbp = NicCbPtrTab[i];
|
|
if(niccbp->NicState == NIC_ACTIVE) {
|
|
|
|
// check if we should avoid this nic
|
|
if(DoNotSendNicCbp != NULL) {
|
|
|
|
if(niccbp->NicId == DoNotSendNicCbp->NicId) {
|
|
|
|
continue; // skip this nic
|
|
}
|
|
}
|
|
|
|
// if this nic doesn't have a net number, we don't
|
|
// send anything on it. (In other words, we are a ROUTER, we can't
|
|
// send rip packets with source net == 0)
|
|
if(!memcmp(niccbp->Network, nulladdress, IPX_NET_LEN)) {
|
|
|
|
continue; // skip this nic
|
|
}
|
|
|
|
// for LAN-WAN-LAN we should look at the RipWanUpdate parameter
|
|
// on how and what to send on WAN. For this version we just
|
|
// don't send anything on WAN, unless we received a request for it
|
|
if(niccbp->DeviceType == NdisMediumWan) {
|
|
|
|
continue; // skip this nic
|
|
}
|
|
|
|
// we found it
|
|
return niccbp;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: MakeRipSendPkts
|
|
//
|
|
// Descr: Invokes the make pkts routine according to the snd req type
|
|
//
|
|
//***
|
|
|
|
UINT
|
|
MakeRipSendPkts(PNICCB niccbp)
|
|
{
|
|
PRIP_SNDREQ sndreqp;
|
|
UINT rc = 0; // assume success
|
|
|
|
sndreqp = niccbp->RipSndReqp;
|
|
|
|
switch(sndreqp->SndReqId) {
|
|
|
|
case RIP_GEN_RESPONSE:
|
|
|
|
rc = MakeRipGenResponsePkts(niccbp);
|
|
break;
|
|
|
|
case RIP_UPDATE:
|
|
|
|
rc = MakeRipUpdatePkt(niccbp);
|
|
break;
|
|
|
|
case RIP_GEN_REQUEST:
|
|
|
|
rc = MakeRipGenRequestPkt(niccbp);
|
|
break;
|
|
|
|
default:
|
|
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: MakeRipGenResponsePkts
|
|
//
|
|
// Descr: allocates and prepares all packets for the RIP gen response
|
|
// The routing table is walked and all network entries which
|
|
// were not received from this nic are copied into RIP response
|
|
// packets. As packets are built, they are queued into the rip
|
|
// send pkts queue at the nic.
|
|
//
|
|
// Params: nic
|
|
//
|
|
// Returns: 0 - success, 1 - did not prepare any packets
|
|
//
|
|
//***
|
|
|
|
UINT
|
|
MakeRipGenResponsePkts(PNICCB niccbp)
|
|
{
|
|
PPACKET_TAG pktp;
|
|
UINT seg;
|
|
PUCHAR hdrp;
|
|
USHORT pktlen;
|
|
BOOLEAN FirstRoute;
|
|
PRIP_SNDPKT_BUFF rbp;
|
|
KIRQL oldirql;
|
|
PIPX_ROUTE_ENTRY rtep;
|
|
PNICCB rtniccbp;
|
|
|
|
// allocate first packet and set net entry ptr in the packet
|
|
if((pktp = AllocRipGenResponsePkt(niccbp)) == NULL) {
|
|
|
|
return 1;
|
|
}
|
|
|
|
// find out what type of Nic is this Nic
|
|
|
|
|
|
hdrp = pktp->DataBufferp;
|
|
pktlen = RIP_INFO;
|
|
|
|
for(seg=0; seg<SegmentCount; seg++) {
|
|
|
|
FirstRoute = TRUE;
|
|
|
|
// LOCK THE ROUTING TABLE
|
|
ExAcquireSpinLock(&SegmentLocksTable[seg], &oldirql);
|
|
|
|
while((rtep = GetRoute(seg, FirstRoute)) != NULL) {
|
|
|
|
FirstRoute = FALSE;
|
|
|
|
// SPLIT HORIZON !
|
|
// check if this network entry originates from this nic
|
|
// For the global WAN network, rtep->NicId = 0xFFFE !
|
|
if(rtep->NicId != niccbp->NicId) {
|
|
|
|
// check if the target net is a global wan net
|
|
if(!(rtep->Flags & IPX_ROUTER_GLOBAL_WAN_NET)) {
|
|
|
|
// the target is not the global wan net
|
|
rtniccbp = NicCbPtrTab[rtep->NicId];
|
|
|
|
// if the response will be sent on a WAN link then there
|
|
// is some filtering to do
|
|
if(niccbp->DeviceType == NdisMediumWan) {
|
|
|
|
// check if the target net is visible via a WAN-Disabled LAN
|
|
if((rtniccbp->DeviceType != NdisMediumWan) &&
|
|
(rtniccbp->WanRoutingDisabled)) {
|
|
|
|
// skip it!
|
|
continue;
|
|
}
|
|
|
|
// check if the nic to send on is a WAN client.
|
|
if(niccbp->WanConnectionClient) {
|
|
|
|
// Check if LAN-WAN-LAN connectivity is enabled
|
|
if(!LanWanLan) {
|
|
|
|
// this node can only inform about its virtual net
|
|
if(rtniccbp->NicId != VirtualNicId) {
|
|
|
|
// skip it!
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The response will be sent on a LAN net
|
|
// check if LAN to LAN routing is enabled
|
|
if(!EnableLanRouting) {
|
|
|
|
// LAN to LAN routing is disabled
|
|
// We will send a response only if the target net
|
|
// is WAN or virtual nic id
|
|
if(rtniccbp->NicId != VirtualNicId) {
|
|
|
|
// The target is not the virtual net, check if
|
|
// it is a WAN net
|
|
if(rtniccbp->DeviceType != NdisMediumWan) {
|
|
|
|
// The target net is a LAN -> don't answer
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if the route originates from a wan client nic and
|
|
// LAN-WAN-LAN connectivity is not enabled, we do not propagate
|
|
// this route
|
|
if(!LanWanLan) {
|
|
|
|
if((rtniccbp->DeviceType == NdisMediumWan) &&
|
|
(rtniccbp->WanConnectionClient)) {
|
|
|
|
// skip it!
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the target net is the global wan net
|
|
// check if the nic to send on is WAN
|
|
if(niccbp->DeviceType == NdisMediumWan) {
|
|
|
|
// check if the WAN nic to send on doesn't have the same address
|
|
if(!memcmp(rtep->Network, niccbp->Network, 4)) {
|
|
|
|
// skip it!
|
|
continue;
|
|
}
|
|
|
|
// check if the WAN nic to send on is a connection client.
|
|
// We can send this info on a connection client only if LanWanLan
|
|
// is enabled
|
|
|
|
if(niccbp->WanConnectionClient) {
|
|
|
|
if(!LanWanLan) {
|
|
|
|
// skip it!
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SetNetworkEntry(hdrp + pktlen, rtep);
|
|
pktlen += NE_ENTRYSIZE;
|
|
}
|
|
|
|
if(pktlen >= RIP_RESPONSE_PACKET_LEN) {
|
|
|
|
// we are done with this packet
|
|
PUTUSHORT2SHORT(hdrp + IPXH_LENGTH, pktlen);
|
|
InsertTailList(&niccbp->RipSndPktsList, &pktp->PacketLinkage);
|
|
|
|
if((pktp = AllocRipGenResponsePkt(niccbp)) == NULL) {
|
|
|
|
// we can't go any further, we are partially done and we
|
|
// send what we have got so far
|
|
|
|
// UNLOCK THE ROUTING TABLE
|
|
ExReleaseSpinLock(&SegmentLocksTable[seg], oldirql);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// we have got a new packet
|
|
hdrp = pktp->DataBufferp;
|
|
pktlen = RIP_INFO;
|
|
}
|
|
|
|
} // while
|
|
|
|
// UNLOCK THE ROUTING TABLE
|
|
ExReleaseSpinLock(&SegmentLocksTable[seg], oldirql);
|
|
}
|
|
|
|
// we are done with this last packet.
|
|
// check if it has any entries
|
|
if(pktlen > RIP_INFO) {
|
|
|
|
PUTUSHORT2SHORT(hdrp + IPXH_LENGTH, pktlen);
|
|
InsertTailList(&niccbp->RipSndPktsList, &pktp->PacketLinkage);
|
|
}
|
|
else
|
|
{
|
|
// this packet does not have any rip info => free it
|
|
rbp = DestroyRipNdisPkt(pktp);
|
|
ExFreePool(rbp);
|
|
}
|
|
|
|
// check if we have produced any packets
|
|
if(IsListEmpty(&niccbp->RipSndPktsList)) {
|
|
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: GetRoute
|
|
//
|
|
// Descr: invokes getfisrt route the first time, then get next route.
|
|
//
|
|
//***
|
|
|
|
PIPX_ROUTE_ENTRY
|
|
GetRoute(UINT segment,
|
|
BOOLEAN FirstRoute)
|
|
{
|
|
if(FirstRoute) {
|
|
|
|
return(IpxGetFirstRoute(segment));
|
|
}
|
|
else
|
|
{
|
|
return(IpxGetNextRoute(segment));
|
|
}
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: AllocRipGenResponsePkt
|
|
//
|
|
// Descr: allocates the data buffer and the ndis descriptors and makes a
|
|
// gen response packet header in the data buffer.
|
|
//
|
|
//***
|
|
|
|
PPACKET_TAG
|
|
AllocRipGenResponsePkt(PNICCB niccbp)
|
|
{
|
|
PPACKET_TAG pktp;
|
|
PRIP_SNDPKT_BUFF rbp;
|
|
|
|
// allocate the send packet buffer for this packet. Do a max len allocation
|
|
if((rbp = ExAllocatePool(NonPagedPool,
|
|
sizeof(RIP_SNDPKT_BUFF) + RIP_SNDPKT_MAXLEN)) == NULL) {
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// create the ndis packet structures
|
|
// an ndis packet gets created and associated with the snd pkt buffer
|
|
if((pktp = CreateRipNdisPkt(rbp, niccbp)) == NULL) {
|
|
|
|
ExFreePool(rbp);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// set the ipx header in the packet
|
|
SetRipIpxHeader(pktp->DataBufferp, niccbp, RIP_RESPONSE);
|
|
|
|
// set the remote (destination) address
|
|
SetRipRemoteAddress(pktp, niccbp);
|
|
|
|
return pktp;
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: MakeRipUpdatePkt
|
|
//
|
|
// Descr: allocates only the ndis pkt and buff descriptors. The data buff
|
|
// has been already allocated in the snd req pkt.
|
|
// Then makes the ndis packet, formats the ipx header and queues
|
|
// the packet int the nic's rip send pkts queue
|
|
//***
|
|
|
|
UINT
|
|
MakeRipUpdatePkt(PNICCB niccbp)
|
|
{
|
|
PPACKET_TAG pktp;
|
|
PRIP_SNDPKT_BUFF rbp;
|
|
PRIP_UPDATE_SNDREQ rup;
|
|
|
|
// get the ptr to the send pkt buffer
|
|
rup = (PRIP_UPDATE_SNDREQ)(niccbp->RipSndReqp);
|
|
rbp = &rup->RipSndPktBuff;
|
|
|
|
// create the ndis packet for this update send
|
|
if((pktp = CreateRipNdisPkt(rbp, niccbp)) == NULL) {
|
|
|
|
return 1;
|
|
}
|
|
|
|
// set up the ipx header in the packet
|
|
SetRipIpxHeader(pktp->DataBufferp, niccbp, RIP_RESPONSE);
|
|
|
|
// set up the remote address
|
|
SetRipRemoteAddress(pktp, niccbp);
|
|
|
|
// insert the packet in the list of packets at the nic
|
|
InsertTailList(&niccbp->RipSndPktsList, &pktp->PacketLinkage);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: MakeRipGenRequestPkt
|
|
//
|
|
// Descr: allocates the data buffer and the buffer descr and makes
|
|
// the ndis packet. Formats the request header and data and queues
|
|
// the packet in the RipSndPktsList
|
|
//
|
|
//***
|
|
|
|
UINT
|
|
MakeRipGenRequestPkt(PNICCB niccbp)
|
|
{
|
|
PPACKET_TAG pktp;
|
|
PRIP_SNDPKT_BUFF rbp;
|
|
PUCHAR hdrp;
|
|
|
|
// allocate the minimum send packet buffer for this packet
|
|
if((rbp = ExAllocatePool(NonPagedPool,
|
|
sizeof(RIP_SNDPKT_BUFF) + RIP_SNDPKT_MINLEN)) == NULL) {
|
|
|
|
return 1;
|
|
}
|
|
|
|
// create the ndis packet structures
|
|
// an ndis packet gets created and associated with the snd pkt buffer
|
|
if((pktp = CreateRipNdisPkt(rbp, niccbp)) == NULL) {
|
|
|
|
ExFreePool(rbp);
|
|
|
|
return 1;
|
|
}
|
|
// create the Ipx packet header in the data buffer part of the snd pkt buff
|
|
hdrp = pktp->DataBufferp;
|
|
|
|
PUTUSHORT2SHORT(hdrp + IPXH_LENGTH, RIP_INFO + NE_ENTRYSIZE);
|
|
|
|
// set the rest of the ipx header
|
|
SetRipIpxHeader(hdrp, niccbp, RIP_REQUEST);
|
|
|
|
// set up the remote address in the packet to send
|
|
SetRipRemoteAddress(pktp, niccbp);
|
|
|
|
// set up the gen request net entry in the packet
|
|
memcpy(hdrp + RIP_INFO + NE_NETNUMBER, bcastaddress, IPX_NET_LEN);
|
|
PUTUSHORT2SHORT(hdrp + RIP_INFO + NE_NROFHOPS, 0xFFFF);
|
|
PUTUSHORT2SHORT(hdrp + RIP_INFO + NE_NROFTICKS, 0xFFFF);
|
|
|
|
// insert the packet in the list of packets at the nic
|
|
InsertTailList(&niccbp->RipSndPktsList, &pktp->PacketLinkage);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: CreateRipNdisPkt
|
|
//
|
|
// Descr: allocates the ndis pkt descr pool of 1 and buff descr pool of
|
|
// 2, allocates the pkt descr and buff descrs and chains them to
|
|
// form the necessary ndis pkt structure using the received snd
|
|
// buffer
|
|
//***
|
|
|
|
PPACKET_TAG
|
|
CreateRipNdisPkt(PRIP_SNDPKT_BUFF rbp,
|
|
PNICCB niccbp)
|
|
{
|
|
NDIS_STATUS NdisStatus;
|
|
PNDIS_PACKET NdisPacket;
|
|
PNDIS_BUFFER NdisDataBuffer;
|
|
PNDIS_BUFFER NdisMacBuffer;
|
|
UINT PktReservedLen;
|
|
PPACKET_TAG pktp;
|
|
|
|
// Allocate the packet descriptor and buffer descriptor pools
|
|
// for this packet
|
|
PktReservedLen = sizeof(PACKET_TAG);
|
|
rbp->PktDescrPoolSize = 1;
|
|
|
|
NdisAllocatePacketPool(
|
|
&NdisStatus,
|
|
&rbp->PktDescrPoolHandle,
|
|
rbp->PktDescrPoolSize,
|
|
PktReservedLen);
|
|
|
|
if(NdisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// each packet has 2 buffer descriptors
|
|
rbp->BuffDescrPoolSize = 2;
|
|
|
|
NdisAllocateBufferPool (
|
|
&NdisStatus,
|
|
&rbp->BuffDescrPoolHandle,
|
|
rbp->BuffDescrPoolSize);
|
|
|
|
if(NdisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisFreePacketPool(rbp->PktDescrPoolHandle);
|
|
return NULL;
|
|
}
|
|
|
|
// allocate the pkt descr, buff descriptors and chain them
|
|
NdisAllocatePacket(&NdisStatus,
|
|
&NdisPacket,
|
|
rbp->PktDescrPoolHandle);
|
|
|
|
if(NdisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisFreePacketPool(rbp->PktDescrPoolHandle);
|
|
NdisFreeBufferPool(rbp->BuffDescrPoolHandle);
|
|
return NULL;
|
|
}
|
|
|
|
pktp = (PPACKET_TAG)&NdisPacket->ProtocolReserved;
|
|
RtlZeroMemory(pktp, sizeof(PACKET_TAG));
|
|
|
|
NdisAllocateBuffer(&NdisStatus,
|
|
&NdisDataBuffer,
|
|
rbp->BuffDescrPoolHandle,
|
|
rbp->IpxPacket,
|
|
432);
|
|
|
|
if(NdisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisFreePacket(NdisPacket);
|
|
NdisFreePacketPool(rbp->PktDescrPoolHandle);
|
|
NdisFreeBufferPool(rbp->BuffDescrPoolHandle);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
NdisAllocateBuffer(&NdisStatus,
|
|
&NdisMacBuffer,
|
|
rbp->BuffDescrPoolHandle,
|
|
pktp->MacHeader,
|
|
MacHeaderNeeded);
|
|
|
|
if(NdisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisFreePacket(NdisPacket);
|
|
NdisFreeBuffer(NdisDataBuffer);
|
|
NdisFreePacketPool(rbp->PktDescrPoolHandle);
|
|
NdisFreeBufferPool(rbp->BuffDescrPoolHandle);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
NdisChainBufferAtFront(NdisPacket, NdisDataBuffer);
|
|
pktp->Identifier = IDENTIFIER_RIP;
|
|
pktp->ReservedPvoid[0] = NULL;
|
|
pktp->ReservedPvoid[1] = NULL;
|
|
pktp->PacketType = RIP_SEND_PACKET;
|
|
pktp->RcvPktSegmentp = NULL;
|
|
pktp->DataBufferp = (PUCHAR)(rbp->IpxPacket);
|
|
pktp->DataBufferLength = 432;
|
|
pktp->PacketOwnerNicCbp = niccbp;
|
|
pktp->HeaderBuffDescrp = NdisMacBuffer;
|
|
|
|
RtPrint(DBG_SNDREQ, ("IpxRouter: CreateRipNdisPkt pktp=0x%x\n", pktp));
|
|
|
|
return pktp;
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: DestroyRipNdisPkt
|
|
//
|
|
// Descr: Frees the allocated ndis structures used in sending this packet
|
|
//
|
|
// Returns: ptr to the snd buffer used in this packets
|
|
//
|
|
//***
|
|
|
|
PRIP_SNDPKT_BUFF
|
|
DestroyRipNdisPkt(PPACKET_TAG pktp)
|
|
{
|
|
PRIP_SNDPKT_BUFF rbp;
|
|
PNDIS_PACKET NdisPacket;
|
|
PNDIS_BUFFER NdisBuffer;
|
|
PNICCB niccbp;
|
|
|
|
RtPrint(DBG_SNDREQ, ("IpxRouter: DestroyRipNdisPkt pktp=0x%x\n", pktp));
|
|
|
|
niccbp = pktp->PacketOwnerNicCbp;
|
|
|
|
// get a ptr to the send buff structure
|
|
rbp = CONTAINING_RECORD(pktp->DataBufferp, RIP_SNDPKT_BUFF, IpxPacket);
|
|
|
|
NdisPacket = CONTAINING_RECORD(pktp, NDIS_PACKET, ProtocolReserved);
|
|
|
|
// free the data buffer descr
|
|
NdisUnchainBufferAtBack (NdisPacket, &NdisBuffer);
|
|
if (NdisBuffer != NULL) {
|
|
NdisFreeBuffer (NdisBuffer);
|
|
}
|
|
else
|
|
{
|
|
// !!! break
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
// free the mac hdr buff descr
|
|
NdisFreeBuffer(pktp->HeaderBuffDescrp);
|
|
|
|
NdisFreePacket(NdisPacket);
|
|
|
|
NdisFreePacketPool(rbp->PktDescrPoolHandle);
|
|
NdisFreeBufferPool(rbp->BuffDescrPoolHandle);
|
|
|
|
return rbp;
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: StartInterPktGapTimer
|
|
//
|
|
// Descr: Starts the timer for 55 ms at this Nic Cb
|
|
//
|
|
// Params: pointer to Nic Cb
|
|
//
|
|
// Returns: none
|
|
//
|
|
//***
|
|
|
|
VOID
|
|
StartInterPktGapTimer(PNICCB niccbp)
|
|
{
|
|
LARGE_INTEGER timeout;
|
|
|
|
timeout.LowPart = (ULONG)(-55 * 10000L); // 55 ms
|
|
timeout.HighPart = -1;
|
|
|
|
KeSetTimer(&niccbp->InterPktGapTimer, timeout, &niccbp->InterPktGapDpc);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SetRipIpxHeader(PUCHAR hdrp, // pointer to the packet header
|
|
PNICCB niccbp, // pointer to the rip send request
|
|
USHORT RipOpcode)
|
|
{
|
|
PUTUSHORT2SHORT(hdrp + IPXH_CHECKSUM, 0xFFFF);
|
|
*(hdrp + IPXH_XPORTCTL) = 0;
|
|
*(hdrp + IPXH_PKTTYPE) = 1; // RIP packet
|
|
memcpy(hdrp + IPXH_DESTNET, niccbp->Network, IPX_NET_LEN);
|
|
memcpy(hdrp + IPXH_DESTNODE, niccbp->RipSndReqp->DestNode, IPX_NODE_LEN);
|
|
PUTUSHORT2SHORT(hdrp + IPXH_DESTSOCK, niccbp->RipSndReqp->DestSock);
|
|
memcpy(hdrp + IPXH_SRCNET, niccbp->Network, IPX_NET_LEN);
|
|
memcpy(hdrp + IPXH_SRCNODE, niccbp->Node, IPX_NODE_LEN);
|
|
PUTUSHORT2SHORT(hdrp + IPXH_SRCSOCK, IPX_RIP_SOCKET);
|
|
|
|
// set the opcode
|
|
PUTUSHORT2SHORT(hdrp + RIP_OPCODE, RipOpcode);
|
|
}
|
|
|
|
VOID
|
|
SetRipRemoteAddress(PPACKET_TAG pktp,
|
|
PNICCB niccbp)
|
|
{
|
|
// set up the remote address in the packet to send
|
|
pktp->RemoteAddress.NicId = niccbp->NicId;
|
|
if(niccbp->DeviceType != NdisMediumWan) {
|
|
|
|
// we send on a LAN
|
|
memcpy(pktp->RemoteAddress.MacAddress, niccbp->RipSndReqp->DestNode, IPX_NODE_LEN);
|
|
}
|
|
else
|
|
{
|
|
// we send on a WAN line. If the destination socket is broadcast, replace
|
|
// it with the address of the remote node
|
|
if(!memcmp(niccbp->RipSndReqp->DestNode, bcastaddress, IPX_NODE_LEN)) {
|
|
|
|
memcpy(pktp->RemoteAddress.MacAddress, niccbp->RemoteNode, IPX_NODE_LEN);
|
|
}
|
|
else
|
|
{
|
|
memcpy(pktp->RemoteAddress.MacAddress, niccbp->RipSndReqp->DestNode, IPX_NODE_LEN);
|
|
}
|
|
}
|
|
}
|