Source code of Windows XP (NT5)
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.

319 lines
7.6 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. router.c
  5. Abstract:
  6. This module contains
  7. Author:
  8. Jameel Hyder (jameelh@microsoft.com)
  9. Nikhil Kamkolkar (nikhilk@microsoft.com)
  10. Revision History:
  11. 19 Jun 1992 Initial Version
  12. Notes: Tab stop: 4
  13. --*/
  14. #include <atalk.h>
  15. #pragma hdrstop
  16. #define FILENUM ROUTER
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(PAGE_RTR, AtalkDdpRouteInPkt)
  19. #endif
  20. VOID
  21. AtalkDdpRouteInPkt(
  22. IN PPORT_DESCRIPTOR pPortDesc,
  23. IN PATALK_ADDR pSrc,
  24. IN PATALK_ADDR pDest,
  25. IN BYTE ProtoType,
  26. IN PBYTE pPkt,
  27. IN USHORT PktLen,
  28. IN USHORT HopCnt
  29. )
  30. /*++
  31. Routine Description:
  32. Arguments:
  33. Return Value:
  34. --*/
  35. {
  36. PDDP_ADDROBJ pDdpAddr;
  37. PRTE pRte;
  38. PPORT_DESCRIPTOR pDestPort;
  39. PATALK_NODE pRouterNode;
  40. ATALK_ADDR actualDest;
  41. BUFFER_DESC BufDesc;
  42. PBUFFER_DESC pBufCopy = NULL;
  43. USHORT bufLen = 0;
  44. BOOLEAN delivered = FALSE;
  45. ATALK_ERROR error = ATALK_NO_ERROR;
  46. SEND_COMPL_INFO SendInfo;
  47. // AtalkDdpRouteOutBufDesc() will have already passed us a
  48. // copy if bcast is going to be TRUE, and AtalkDdpRouteInPkt() will
  49. // never call AtalkDdpRouter() for a bcast packet. They will also set
  50. // the completion routines to be different if they passed us a copy.
  51. // Those will free up the buffer descriptors.
  52. //
  53. // The completion routines are optional in the sense that the buffer
  54. // will never be freed if they are not set!
  55. // This algorithm is taken from the "Appletalk Phase 2 Specification".
  56. // If the destination network number is within the range of the reception
  57. // port's network range and the destination node number is broadcast, then
  58. // we can drop the packet on the floor -- it is a network specific broadcast
  59. // not for this router. Note that we've already delivered the packet, and
  60. // thus not gotten here, if it was really addressed to the network of any
  61. // node owned by the reception port (in AtalkDdpPacketIn).
  62. // Also:
  63. // Try to find an entry in the routing table that contains the target
  64. // network. If not found, discard the packet.
  65. if (((WITHIN_NETWORK_RANGE(pDest->ata_Network,
  66. &pPortDesc->pd_NetworkRange)) &&
  67. (pDest->ata_Node == ATALK_BROADCAST_NODE)) ||
  68. ((pRte = AtalkRtmpReferenceRte(pDest->ata_Network)) == NULL))
  69. {
  70. DBGPRINT(DBG_COMP_ROUTER, DBG_LEVEL_FATAL,
  71. ("AtalkDdpRouter: %lx RtmpRte/Not in ThisCableRange\n",
  72. pDest->ata_Network));
  73. return;
  74. }
  75. do
  76. {
  77. // Get the port descriptor for this port number.
  78. pDestPort = pRte->rte_PortDesc;
  79. ASSERT(VALID_PORT(pDestPort));
  80. DBGPRINT(DBG_COMP_ROUTER, DBG_LEVEL_WARN,
  81. ("ROUTER: Routing pkt from port %Z.%lx to %Z.%lx\n",
  82. &pPortDesc->pd_AdapterKey, pSrc->ata_Network,
  83. &pDestPort->pd_AdapterKey, pDest->ata_Network));
  84. SendInfo.sc_TransmitCompletion = atalkDdpRouteComplete;
  85. SendInfo.sc_Ctx1 = pDestPort;
  86. // SendInfo.sc_Ctx3 = NULL;
  87. // If the target network's hop count is non-zero, we really need to send
  88. // the beast, so, just do it!
  89. if (pRte->rte_NumHops != 0)
  90. {
  91. // Too many hops?
  92. error = ATALK_FAILURE;
  93. if (HopCnt < RTMP_MAX_HOPS)
  94. {
  95. // We own the data. Call AtalkTransmitDdp() with the buffer descriptor.
  96. // Make a copy! Caller will free our current packet.
  97. // Alloc a buffer descriptor, copy data from packet to buffdesc.
  98. if ((pBufCopy = AtalkAllocBuffDesc(NULL,
  99. PktLen,
  100. (BD_FREE_BUFFER | BD_CHAR_BUFFER))) == NULL)
  101. {
  102. error = ATALK_RESR_MEM;
  103. break;
  104. }
  105. AtalkCopyBufferToBuffDesc(pPkt, PktLen, pBufCopy, 0);
  106. SendInfo.sc_Ctx2 = pBufCopy;
  107. error = AtalkDdpTransmit(pDestPort,
  108. pSrc,
  109. pDest,
  110. ProtoType,
  111. pBufCopy,
  112. NULL,
  113. 0,
  114. (USHORT)(HopCnt+1),
  115. NULL, // pZoneMcastAddr,
  116. &pRte->rte_NextRouter,
  117. &SendInfo);
  118. }
  119. INTERLOCKED_INCREMENT_LONG_DPC(
  120. &pDestPort->pd_PortStats.prtst_NumPktRoutedOut,
  121. &AtalkStatsLock.SpinLock);
  122. break;
  123. }
  124. // If the destination node is zero, the packet is really destined for the
  125. // router's node on this port.
  126. if (pDest->ata_Node == ANY_ROUTER_NODE)
  127. {
  128. // Grab the port lock and read the router node address.
  129. // No need to reference, just ensure its not null.
  130. ACQUIRE_SPIN_LOCK_DPC(&pDestPort->pd_Lock);
  131. pRouterNode = pDestPort->pd_RouterNode;
  132. if (pRouterNode != NULL)
  133. {
  134. actualDest.ata_Network = pRouterNode->an_NodeAddr.atn_Network;
  135. actualDest.ata_Node = pRouterNode->an_NodeAddr.atn_Node;
  136. // Set the actual destination socket.
  137. actualDest.ata_Socket = pDest->ata_Socket;
  138. }
  139. else
  140. {
  141. ASSERTMSG("AtalkDdpRouter: pRouter node is null!\n", 0);
  142. error = ATALK_DDP_NOTFOUND;
  143. }
  144. if (ATALK_SUCCESS(error))
  145. {
  146. AtalkDdpRefByAddrNode(pDestPort,
  147. &actualDest,
  148. pRouterNode,
  149. &pDdpAddr,
  150. &error);
  151. }
  152. RELEASE_SPIN_LOCK_DPC(&pDestPort->pd_Lock);
  153. if (ATALK_SUCCESS(error))
  154. {
  155. AtalkDdpInvokeHandler(pDestPort,
  156. pDdpAddr,
  157. pSrc,
  158. pDest, // Pass in the actual destination
  159. ProtoType,
  160. pPkt,
  161. PktLen);
  162. // Remove the reference on the socket
  163. AtalkDdpDereferenceDpc(pDdpAddr);
  164. }
  165. else
  166. {
  167. ASSERTMSG("AtalkDdpRouter: pSocket on router node is null!\n", 0);
  168. }
  169. break;
  170. }
  171. // Okay, now walk through the nodes on the target port, looking for a
  172. // home for this packet.
  173. BufDesc.bd_Next = NULL;
  174. BufDesc.bd_Flags = BD_CHAR_BUFFER;
  175. BufDesc.bd_Length = PktLen;
  176. BufDesc.bd_CharBuffer = pPkt;
  177. AtalkDdpOutBufToNodesOnPort(pDestPort,
  178. pSrc,
  179. pDest,
  180. ProtoType,
  181. &BufDesc,
  182. NULL,
  183. 0,
  184. &delivered);
  185. error = ATALK_NO_ERROR;
  186. if (!delivered)
  187. {
  188. // We need to deliver this packet to a local ports network.
  189. // delivered would have been set true *EVEN* if broadcast
  190. // were set, so we need to ensure it was delivered to a specific
  191. // socket by making sure broadcast was not true.
  192. if (HopCnt < RTMP_MAX_HOPS)
  193. {
  194. // We own the data. Call AtalkTransmitDdp() with the buffer descriptor.
  195. // Make a copy! Caller will free our current packet.
  196. // Alloc a buffer descriptor, copy data from packet to buffdesc.
  197. if ((pBufCopy = AtalkAllocBuffDesc(NULL,
  198. PktLen,
  199. (BD_FREE_BUFFER | BD_CHAR_BUFFER))) == NULL)
  200. {
  201. error = ATALK_RESR_MEM;
  202. break;
  203. }
  204. AtalkCopyBufferToBuffDesc(pPkt, PktLen, pBufCopy, 0);
  205. SendInfo.sc_Ctx2 = pBufCopy;
  206. error = AtalkDdpTransmit(pDestPort,
  207. pSrc,
  208. pDest,
  209. ProtoType,
  210. pBufCopy,
  211. NULL,
  212. 0,
  213. (USHORT)(HopCnt+1),
  214. NULL, // pZoneMcastAddr
  215. NULL,
  216. &SendInfo);
  217. INTERLOCKED_INCREMENT_LONG_DPC(
  218. &pDestPort->pd_PortStats.prtst_NumPktRoutedOut,
  219. &AtalkStatsLock.SpinLock);
  220. }
  221. else error = ATALK_FAILURE;
  222. break;
  223. }
  224. } while (FALSE);
  225. if ((error != ATALK_PENDING) && (pBufCopy != NULL))
  226. {
  227. // Free the copied buffer descriptor if a copy was made.
  228. AtalkFreeBuffDesc(pBufCopy);
  229. }
  230. AtalkRtmpDereferenceRte(pRte, FALSE); // Lock held?
  231. INTERLOCKED_INCREMENT_LONG_DPC(
  232. &pPortDesc->pd_PortStats.prtst_NumPktRoutedIn,
  233. &AtalkStatsLock.SpinLock);
  234. }
  235. VOID FASTCALL
  236. atalkDdpRouteComplete(
  237. IN NDIS_STATUS Status,
  238. IN PSEND_COMPL_INFO pSendInfo
  239. )
  240. /*++
  241. Routine Description:
  242. Arguments:
  243. Return Value:
  244. --*/
  245. {
  246. PPORT_DESCRIPTOR pPortDesc = (PPORT_DESCRIPTOR)(pSendInfo->sc_Ctx1);
  247. PBUFFER_DESC pBuffDesc = (PBUFFER_DESC)(pSendInfo->sc_Ctx2);
  248. if (pBuffDesc != NULL)
  249. {
  250. ASSERT(pBuffDesc->bd_Flags & (BD_CHAR_BUFFER | BD_FREE_BUFFER));
  251. AtalkFreeBuffDesc(pBuffDesc);
  252. }
  253. }
  254.