|
|
/*++
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); } }
|