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.
320 lines
7.9 KiB
320 lines
7.9 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
router.c
|
|
|
|
Abstract:
|
|
|
|
This module contains
|
|
|
|
Author:
|
|
|
|
Jameel Hyder ([email protected])
|
|
Nikhil Kamkolkar ([email protected])
|
|
|
|
Revision History:
|
|
19 Jun 1992 Initial Version
|
|
|
|
Notes: Tab stop: 4
|
|
--*/
|
|
|
|
#include <atalk.h>
|
|
#pragma hdrstop
|
|
#define FILENUM ROUTER
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE_RTR, AtalkDdpRouteInPkt)
|
|
#endif
|
|
|
|
VOID
|
|
AtalkDdpRouteInPkt(
|
|
IN PPORT_DESCRIPTOR pPortDesc,
|
|
IN PATALK_ADDR pSrc,
|
|
IN PATALK_ADDR pDest,
|
|
IN BYTE ProtoType,
|
|
IN PBYTE pPkt,
|
|
IN USHORT PktLen,
|
|
IN USHORT HopCnt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PDDP_ADDROBJ pDdpAddr;
|
|
PRTE pRte;
|
|
PPORT_DESCRIPTOR pDestPort;
|
|
PATALK_NODE pRouterNode;
|
|
ATALK_ADDR actualDest;
|
|
BUFFER_DESC BufDesc;
|
|
|
|
PBUFFER_DESC pBufCopy = NULL;
|
|
USHORT bufLen = 0;
|
|
BOOLEAN delivered = FALSE;
|
|
ATALK_ERROR error = ATALK_NO_ERROR;
|
|
SEND_COMPL_INFO SendInfo;
|
|
|
|
// AtalkDdpRouteOutBufDesc() will have already passed us a
|
|
// copy if bcast is going to be TRUE, and AtalkDdpRouteInPkt() will
|
|
// never call AtalkDdpRouter() for a bcast packet. They will also set
|
|
// the completion routines to be different if they passed us a copy.
|
|
// Those will free up the buffer descriptors.
|
|
//
|
|
// The completion routines are optional in the sense that the buffer
|
|
// will never be freed if they are not set!
|
|
|
|
// This algorithm is taken from the "Appletalk Phase 2 Specification".
|
|
|
|
// If the destination network number is within the range of the reception
|
|
// port's network range and the destination node number is broadcast, then
|
|
// we can drop the packet on the floor -- it is a network specific broadcast
|
|
// not for this router. Note that we've already delivered the packet, and
|
|
// thus not gotten here, if it was really addressed to the network of any
|
|
// node owned by the reception port (in AtalkDdpPacketIn).
|
|
// Also:
|
|
// Try to find an entry in the routing table that contains the target
|
|
// network. If not found, discard the packet.
|
|
|
|
if (((WITHIN_NETWORK_RANGE(pDest->ata_Network,
|
|
&pPortDesc->pd_NetworkRange)) &&
|
|
(pDest->ata_Node == ATALK_BROADCAST_NODE)) ||
|
|
((pRte = AtalkRtmpReferenceRte(pDest->ata_Network)) == NULL))
|
|
{
|
|
DBGPRINT(DBG_COMP_ROUTER, DBG_LEVEL_FATAL,
|
|
("AtalkDdpRouter: %lx RtmpRte/Not in ThisCableRange\n",
|
|
pDest->ata_Network));
|
|
return;
|
|
}
|
|
|
|
do
|
|
{
|
|
// Get the port descriptor for this port number.
|
|
pDestPort = pRte->rte_PortDesc;
|
|
|
|
ASSERT(VALID_PORT(pDestPort));
|
|
|
|
DBGPRINT(DBG_COMP_ROUTER, DBG_LEVEL_WARN,
|
|
("ROUTER: Routing pkt from port %Z.%lx to %Z.%lx\n",
|
|
&pPortDesc->pd_AdapterKey, pSrc->ata_Network,
|
|
&pDestPort->pd_AdapterKey, pDest->ata_Network));
|
|
|
|
SendInfo.sc_TransmitCompletion = atalkDdpRouteComplete;
|
|
SendInfo.sc_Ctx1 = pDestPort;
|
|
// SendInfo.sc_Ctx3 = NULL;
|
|
|
|
// If the target network's hop count is non-zero, we really need to send
|
|
// the beast, so, just do it!
|
|
if (pRte->rte_NumHops != 0)
|
|
{
|
|
// Too many hops?
|
|
error = ATALK_FAILURE;
|
|
if (HopCnt < RTMP_MAX_HOPS)
|
|
{
|
|
// We own the data. Call AtalkTransmitDdp() with the buffer descriptor.
|
|
// Make a copy! Caller will free our current packet.
|
|
// Alloc a buffer descriptor, copy data from packet to buffdesc.
|
|
|
|
if ((pBufCopy = AtalkAllocBuffDesc(NULL,
|
|
PktLen,
|
|
(BD_FREE_BUFFER | BD_CHAR_BUFFER))) == NULL)
|
|
{
|
|
error = ATALK_RESR_MEM;
|
|
break;
|
|
}
|
|
|
|
AtalkCopyBufferToBuffDesc(pPkt, PktLen, pBufCopy, 0);
|
|
SendInfo.sc_Ctx2 = pBufCopy;
|
|
|
|
error = AtalkDdpTransmit(pDestPort,
|
|
pSrc,
|
|
pDest,
|
|
ProtoType,
|
|
pBufCopy,
|
|
NULL,
|
|
0,
|
|
(USHORT)(HopCnt+1),
|
|
NULL, // pZoneMcastAddr,
|
|
&pRte->rte_NextRouter,
|
|
&SendInfo);
|
|
}
|
|
INTERLOCKED_INCREMENT_LONG_DPC(
|
|
&pDestPort->pd_PortStats.prtst_NumPktRoutedOut,
|
|
&AtalkStatsLock.SpinLock);
|
|
|
|
break;
|
|
}
|
|
|
|
// If the destination node is zero, the packet is really destined for the
|
|
// router's node on this port.
|
|
if (pDest->ata_Node == ANY_ROUTER_NODE)
|
|
{
|
|
// Grab the port lock and read the router node address.
|
|
// No need to reference, just ensure its not null.
|
|
ACQUIRE_SPIN_LOCK_DPC(&pDestPort->pd_Lock);
|
|
pRouterNode = pDestPort->pd_RouterNode;
|
|
if (pRouterNode != NULL)
|
|
{
|
|
actualDest.ata_Network = pRouterNode->an_NodeAddr.atn_Network;
|
|
actualDest.ata_Node = pRouterNode->an_NodeAddr.atn_Node;
|
|
|
|
// Set the actual destination socket.
|
|
actualDest.ata_Socket = pDest->ata_Socket;
|
|
}
|
|
else
|
|
{
|
|
ASSERTMSG("AtalkDdpRouter: pRouter node is null!\n", 0);
|
|
error = ATALK_DDP_NOTFOUND;
|
|
}
|
|
|
|
if (ATALK_SUCCESS(error))
|
|
{
|
|
AtalkDdpRefByAddrNode(pDestPort,
|
|
&actualDest,
|
|
pRouterNode,
|
|
&pDdpAddr,
|
|
&error);
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pDestPort->pd_Lock);
|
|
|
|
if (ATALK_SUCCESS(error))
|
|
{
|
|
AtalkDdpInvokeHandler(pDestPort,
|
|
pDdpAddr,
|
|
pSrc,
|
|
pDest, // Pass in the actual destination
|
|
ProtoType,
|
|
pPkt,
|
|
PktLen);
|
|
|
|
// Remove the reference on the socket
|
|
AtalkDdpDereferenceDpc(pDdpAddr);
|
|
}
|
|
else
|
|
{
|
|
ASSERTMSG("AtalkDdpRouter: pSocket on router node is null!\n", 0);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
// Okay, now walk through the nodes on the target port, looking for a
|
|
// home for this packet.
|
|
BufDesc.bd_Next = NULL;
|
|
BufDesc.bd_Flags = BD_CHAR_BUFFER;
|
|
BufDesc.bd_Length = PktLen;
|
|
BufDesc.bd_CharBuffer = pPkt;
|
|
|
|
AtalkDdpOutBufToNodesOnPort(pDestPort,
|
|
pSrc,
|
|
pDest,
|
|
ProtoType,
|
|
&BufDesc,
|
|
NULL,
|
|
0,
|
|
&delivered);
|
|
|
|
error = ATALK_NO_ERROR;
|
|
if (!delivered)
|
|
{
|
|
// We need to deliver this packet to a local ports network.
|
|
// delivered would have been set true *EVEN* if broadcast
|
|
// were set, so we need to ensure it was delivered to a specific
|
|
// socket by making sure broadcast was not true.
|
|
if (HopCnt < RTMP_MAX_HOPS)
|
|
{
|
|
// We own the data. Call AtalkTransmitDdp() with the buffer descriptor.
|
|
// Make a copy! Caller will free our current packet.
|
|
// Alloc a buffer descriptor, copy data from packet to buffdesc.
|
|
|
|
if ((pBufCopy = AtalkAllocBuffDesc(NULL,
|
|
PktLen,
|
|
(BD_FREE_BUFFER | BD_CHAR_BUFFER))) == NULL)
|
|
{
|
|
error = ATALK_RESR_MEM;
|
|
break;
|
|
}
|
|
|
|
AtalkCopyBufferToBuffDesc(pPkt, PktLen, pBufCopy, 0);
|
|
SendInfo.sc_Ctx2 = pBufCopy;
|
|
|
|
error = AtalkDdpTransmit(pDestPort,
|
|
pSrc,
|
|
pDest,
|
|
ProtoType,
|
|
pBufCopy,
|
|
NULL,
|
|
0,
|
|
(USHORT)(HopCnt+1),
|
|
NULL, // pZoneMcastAddr
|
|
NULL,
|
|
&SendInfo);
|
|
INTERLOCKED_INCREMENT_LONG_DPC(
|
|
&pDestPort->pd_PortStats.prtst_NumPktRoutedOut,
|
|
&AtalkStatsLock.SpinLock);
|
|
|
|
}
|
|
else error = ATALK_FAILURE;
|
|
|
|
break;
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
if ((error != ATALK_PENDING) && (pBufCopy != NULL))
|
|
{
|
|
// Free the copied buffer descriptor if a copy was made.
|
|
AtalkFreeBuffDesc(pBufCopy);
|
|
}
|
|
|
|
AtalkRtmpDereferenceRte(pRte, FALSE); // Lock held?
|
|
|
|
INTERLOCKED_INCREMENT_LONG_DPC(
|
|
&pPortDesc->pd_PortStats.prtst_NumPktRoutedIn,
|
|
&AtalkStatsLock.SpinLock);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID FASTCALL
|
|
atalkDdpRouteComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN PSEND_COMPL_INFO pSendInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PPORT_DESCRIPTOR pPortDesc = (PPORT_DESCRIPTOR)(pSendInfo->sc_Ctx1);
|
|
PBUFFER_DESC pBuffDesc = (PBUFFER_DESC)(pSendInfo->sc_Ctx2);
|
|
|
|
if (pBuffDesc != NULL)
|
|
{
|
|
ASSERT(pBuffDesc->bd_Flags & (BD_CHAR_BUFFER | BD_FREE_BUFFER));
|
|
AtalkFreeBuffDesc(pBuffDesc);
|
|
}
|
|
}
|
|
|
|
|