320 lines
7.6 KiB
C
320 lines
7.6 KiB
C
/*++
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
router.c
|
||
|
||
Abstract:
|
||
|
||
This module contains
|
||
|
||
Author:
|
||
|
||
Jameel Hyder (jameelh@microsoft.com)
|
||
Nikhil Kamkolkar (nikhilk@microsoft.com)
|
||
|
||
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);
|
||
}
|
||
}
|
||
|
||
|