Leaked source code of windows server 2003
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.

1316 lines
50 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. ntos\tdi\isn\fwd\send.c
  5. Abstract:
  6. Send routines
  7. Author:
  8. Vadim Eydelman
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. ULONG SpoofingTimeout=DEF_SPOOFING_TIMEOUT;
  13. LIST_ENTRY SpoofingQueue;
  14. KSPIN_LOCK SpoofingQueueLock;
  15. WORK_QUEUE_ITEM SpoofingWorker;
  16. BOOLEAN SpoofingWorkerActive = FALSE;
  17. ULONG DontSuppressNonAgentSapAdvertisements = 0;
  18. #define IsLocalSapNonAgentAdvertisement(hdr,data,ln,ifCB) ( \
  19. (DontSuppressNonAgentSapAdvertisements==0) \
  20. && (GETUSHORT(hdr+IPXH_DESTSOCK)==IPX_SAP_SOCKET) \
  21. && (GETUSHORT(hdr+IPXH_SRCSOCK)!=IPX_SAP_SOCKET) \
  22. && (ln>=IPXH_HDRSIZE+2) \
  23. && (GETUSHORT(data)==2) \
  24. && ((IPX_NODE_CMP(hdr+IPXH_DESTNODE,BROADCAST_NODE)==0) \
  25. || (IPX_NODE_CMP(hdr+IPXH_DESTNODE,ifCB->ICB_RemoteNode)==0)) \
  26. )
  27. /*++
  28. *******************************************************************
  29. D o S e n d
  30. Routine Description:
  31. Prepares and sends packet. Interface lock must be help while
  32. callin this routine
  33. Arguments:
  34. dstIf - over which interface to send
  35. pktTag - packet to send
  36. Return Value:
  37. result returned by IPX
  38. *******************************************************************
  39. --*/
  40. NDIS_STATUS
  41. DoSend (
  42. PINTERFACE_CB dstIf,
  43. PPACKET_TAG pktTag,
  44. KIRQL oldIRQL
  45. ) {
  46. NDIS_STATUS status;
  47. PNDIS_PACKET pktDscr;
  48. PNDIS_BUFFER bufDscr, aDscr;
  49. UINT dataLen;
  50. ULONG dstNet = GETULONG (pktTag->PT_Data+IPXH_DESTNET);
  51. if (dstIf!=InternalInterface) {
  52. ADAPTER_CONTEXT_TO_LOCAL_TARGET (dstIf->ICB_AdapterContext,
  53. &pktTag->PT_Target);
  54. }
  55. else {
  56. CONSTANT_ADAPTER_CONTEXT_TO_LOCAL_TARGET (
  57. VIRTUAL_NET_ADAPTER_CONTEXT,
  58. &pktTag->PT_Target);
  59. }
  60. #if DBG
  61. // Keep track of packets being processed by IPX stack
  62. InsertTailList (&dstIf->ICB_InSendQueue, &pktTag->PT_QueueLink);
  63. #endif
  64. KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
  65. if (pktTag->PT_Flags&PT_SOURCE_IF)
  66. ReleaseInterfaceReference (pktTag->PT_SourceIf);
  67. pktTag->SEND_RESERVED[0] = pktTag->SEND_RESERVED[1] = 0;
  68. pktDscr = CONTAINING_RECORD(pktTag, NDIS_PACKET, ProtocolReserved);
  69. NdisQueryPacket(pktDscr, NULL, NULL, &bufDscr, NULL);
  70. #if DBG
  71. { // Verify packet integrity
  72. PUCHAR dataPtr;
  73. UINT bufLen;
  74. ASSERT (NDIS_BUFFER_LINKAGE (bufDscr)==NULL);
  75. NdisQueryBuffer (bufDscr, &dataPtr, &bufLen);
  76. ASSERT (dataPtr==pktTag->PT_Data);
  77. ASSERT (bufLen==pktTag->PT_Segment->PS_SegmentList->SL_BlockSize);
  78. }
  79. #endif
  80. // Prepare packet for IPX stack (mac header buffer goes in
  81. // front and packet length adjusted to reflect the size of the data
  82. dataLen = GETUSHORT(pktTag->PT_Data+IPXH_LENGTH);
  83. NdisAdjustBufferLength(bufDscr, dataLen);
  84. NdisChainBufferAtFront(pktDscr, pktTag->PT_MacHdrBufDscr);
  85. if (EnterForwarder ()) {// To make sure that we won't unload
  86. // until IPX driver has a chance to call us back
  87. status = IPXSendProc (&pktTag->PT_Target, pktDscr, dataLen, 0);
  88. if (status!=NDIS_STATUS_PENDING) {
  89. LeaveForwarder (); // No callback
  90. // Restore original packet structure
  91. NdisUnchainBufferAtFront (pktDscr, &aDscr);
  92. #if DBG
  93. // Make sure IPX stack did not mess our packet
  94. ASSERT (aDscr==pktTag->PT_MacHdrBufDscr);
  95. NdisQueryPacket(pktDscr, NULL, NULL, &aDscr, NULL);
  96. ASSERT (aDscr==bufDscr);
  97. ASSERT (NDIS_BUFFER_LINKAGE (aDscr)==NULL);
  98. #endif
  99. // Restore original packet size
  100. NdisAdjustBufferLength(bufDscr,
  101. pktTag->PT_Segment->PS_SegmentList->SL_BlockSize);
  102. #if DBG
  103. // Remove packet from temp queue
  104. KeAcquireSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, &oldIRQL);
  105. RemoveEntryList (&pktTag->PT_QueueLink);
  106. KeReleaseSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, oldIRQL);
  107. #endif
  108. }
  109. }
  110. else {
  111. // We are going down, restore the packet
  112. NdisUnchainBufferAtFront (pktDscr, &aDscr);
  113. NdisAdjustBufferLength(bufDscr,
  114. pktTag->PT_Segment->PS_SegmentList->SL_BlockSize);
  115. NdisRecalculatePacketCounts (pktDscr);
  116. status = STATUS_UNSUCCESSFUL;
  117. #if DBG
  118. KeAcquireSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, &oldIRQL);
  119. RemoveEntryList (&pktTag->PT_QueueLink);
  120. KeReleaseSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, oldIRQL);
  121. #endif
  122. }
  123. return status;
  124. }
  125. /*++
  126. *******************************************************************
  127. P r o c e s s S e n t P a c k e t
  128. Routine Description:
  129. Process completed sent packets
  130. Arguments:
  131. dstIf - interface over which packet was sent
  132. pktTag - completed packet
  133. status - result of send operation
  134. Return Value:
  135. None
  136. *******************************************************************
  137. --*/
  138. VOID
  139. ProcessSentPacket (
  140. PINTERFACE_CB dstIf,
  141. PPACKET_TAG pktTag,
  142. NDIS_STATUS status
  143. ) {
  144. KIRQL oldIRQL;
  145. // Packet processing is completed -> can take more packets
  146. InterlockedIncrement (&dstIf->ICB_PendingQuota);
  147. if (*(pktTag->PT_Data+IPXH_PKTTYPE) == IPX_NETBIOS_TYPE) {
  148. // Continue processing netbios packets
  149. if (status==NDIS_STATUS_SUCCESS) {
  150. IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
  151. ("IpxFwd: NB Packet %08lx sent.", pktTag));
  152. InterlockedIncrement (&dstIf->ICB_Stats.OutDelivers);
  153. InterlockedIncrement (&dstIf->ICB_Stats.NetbiosSent);
  154. }
  155. else {
  156. IpxFwdDbgPrint (DBG_NETBIOS, DBG_ERROR,
  157. ("IpxFwd: NB Packet %08lx send failed with error: %08lx.\n",
  158. pktTag, status));
  159. }
  160. // Queue nb packet for further processing (broadcast on all interfaces)
  161. QueueNetbiosPacket (pktTag);
  162. }
  163. else {
  164. // Destroy completed packet
  165. if (status==NDIS_STATUS_SUCCESS) {
  166. InterlockedIncrement (&dstIf->ICB_Stats.OutDelivers);
  167. IpxFwdDbgPrint (DBG_SEND, DBG_INFORMATION,
  168. ("IpxFwd: Packet %08lx sent.", pktTag));
  169. }
  170. else {
  171. InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
  172. IpxFwdDbgPrint (DBG_SEND, DBG_ERROR,
  173. ("IpxFwd: Packet %08lx send failed with error: %08lx.\n",
  174. pktTag, status));
  175. }
  176. ReleaseInterfaceReference (dstIf);
  177. if (MeasuringPerformance
  178. && (pktTag->PT_PerfCounter!=0)) {
  179. LARGE_INTEGER PerfCounter = KeQueryPerformanceCounter (NULL);
  180. PerfCounter.QuadPart -= pktTag->PT_PerfCounter;
  181. KeAcquireSpinLock (&PerfCounterLock, &oldIRQL);
  182. ASSERT (PerfCounter.QuadPart<ActivityTreshhold);
  183. PerfBlock.TotalPacketProcessingTime += PerfCounter.QuadPart;
  184. PerfBlock.PacketCounter += 1;
  185. if (PerfBlock.MaxPacketProcessingTime < PerfCounter.QuadPart)
  186. PerfBlock.MaxPacketProcessingTime = PerfCounter.QuadPart;
  187. KeReleaseSpinLock (&PerfCounterLock, oldIRQL);
  188. }
  189. FreePacket (pktTag);
  190. }
  191. }
  192. /*++
  193. *******************************************************************
  194. S e n d P a c k e t
  195. Routine Description:
  196. Enqueues packets to be sent by IPX stack
  197. Arguments:
  198. dstIf - over which interface to send
  199. pktTag - packet to send
  200. Return Value:
  201. None
  202. *******************************************************************
  203. --*/
  204. VOID
  205. SendPacket (
  206. PINTERFACE_CB dstIf,
  207. PPACKET_TAG pktTag
  208. ) {
  209. NDIS_STATUS status;
  210. KIRQL oldIRQL;
  211. ASSERT (dstIf->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX);
  212. // Make sure we have not exceded the quota of pending packets on the interface
  213. if (InterlockedDecrement (&dstIf->ICB_PendingQuota)>=0) {
  214. KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
  215. // Decide what to do with the packet based on the interface state
  216. switch (dstIf->ICB_Stats.OperationalState) {
  217. case FWD_OPER_STATE_UP:
  218. if (*(pktTag->PT_Data + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
  219. NOTHING;
  220. else {
  221. PUTULONG (dstIf->ICB_Network, pktTag->PT_Data+IPXH_DESTNET);
  222. }
  223. status = DoSend (dstIf, pktTag, oldIRQL);
  224. IpxFwdDbgPrint (DBG_SEND, DBG_INFORMATION,
  225. ("IpxFwd: Sent external packet %08lx on if %ld.\n",
  226. pktTag, dstIf->ICB_Index));
  227. break;
  228. case FWD_OPER_STATE_SLEEPING:
  229. if ((*(pktTag->PT_Data+IPXH_PKTTYPE)!=0)
  230. || (GETUSHORT(pktTag->PT_Data+IPXH_LENGTH)!=IPXH_HDRSIZE+2)
  231. || (*(pktTag->PT_Data+IPXH_HDRSIZE+1)!='?')) {
  232. // Queue this packet on the interface until it is connected
  233. // by Router Manager (DIM) if this is not a NCP keepalive
  234. // (watchdog)
  235. InsertTailList (&dstIf->ICB_ExternalQueue, &pktTag->PT_QueueLink);
  236. if (!IS_IF_CONNECTING (dstIf)) {
  237. // Ask for connection if interface is not in the connection
  238. // queue yet
  239. QueueConnectionRequest (dstIf,
  240. CONTAINING_RECORD (pktTag,
  241. NDIS_PACKET,
  242. ProtocolReserved),
  243. pktTag->PT_Data,
  244. oldIRQL);
  245. IpxFwdDbgPrint (DBG_DIALREQS, DBG_WARNING,
  246. ("IpxFwd: Queued dd request on if %ld (ifCB:%08lx)"
  247. " for packet to %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%02x%02x"
  248. " from %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%02x%02x\n",
  249. dstIf->ICB_Index, dstIf,
  250. *(pktTag->PT_Data+6),*(pktTag->PT_Data+7),
  251. *(pktTag->PT_Data+8),*(pktTag->PT_Data+9),
  252. *(pktTag->PT_Data+10),*(pktTag->PT_Data+11),
  253. *(pktTag->PT_Data+12),*(pktTag->PT_Data+13),
  254. *(pktTag->PT_Data+14),*(pktTag->PT_Data+15),
  255. *(pktTag->PT_Data+16),*(pktTag->PT_Data+17),
  256. *(pktTag->PT_Data+18),*(pktTag->PT_Data+19),
  257. *(pktTag->PT_Data+20),*(pktTag->PT_Data+21),
  258. *(pktTag->PT_Data+22),*(pktTag->PT_Data+23),
  259. *(pktTag->PT_Data+24),*(pktTag->PT_Data+25),
  260. *(pktTag->PT_Data+26),*(pktTag->PT_Data+27),
  261. *(pktTag->PT_Data+28),*(pktTag->PT_Data+29)));
  262. }
  263. else
  264. KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
  265. IpxFwdDbgPrint (DBG_SEND, DBG_INFORMATION,
  266. ("IpxFwd: Queued external packet %08lx on if %ld.\n",
  267. pktTag, dstIf->ICB_Index));
  268. if (*(pktTag->PT_Data + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
  269. NOTHING;
  270. else if (!(pktTag->PT_Flags&PT_NB_DESTROY)) {
  271. // If this nb packet is not to be destroyed after this
  272. // send, we have to make a copy of it to send on
  273. // other interfaces while the original is waiting
  274. // for connection
  275. PPACKET_TAG newPktTag;
  276. DuplicatePacket (pktTag, newPktTag);
  277. if (newPktTag!=NULL) {
  278. UINT bytesCopied;
  279. PNDIS_PACKET packet = CONTAINING_RECORD (pktTag,
  280. NDIS_PACKET,
  281. ProtocolReserved);
  282. PNDIS_PACKET newPacket = CONTAINING_RECORD (newPktTag,
  283. NDIS_PACKET,
  284. ProtocolReserved);
  285. NdisCopyFromPacketToPacket (newPacket, 0,
  286. GETUSHORT(pktTag->PT_Data+IPXH_LENGTH),
  287. packet, 0, &bytesCopied);
  288. ASSERT (bytesCopied==GETUSHORT(pktTag->PT_Data+IPXH_LENGTH));
  289. IpxFwdDbgPrint (DBG_NETBIOS,
  290. DBG_INFORMATION,
  291. ("IpxFwd: Duplicated queued nb packet"
  292. " %08lx -> %08lx on if %ld.\n",
  293. pktTag, newPktTag, dstIf->ICB_Index));
  294. AcquireInterfaceReference (dstIf);
  295. newPktTag->PT_InterfaceReference = dstIf;
  296. newPktTag->PT_PerfCounter = pktTag->PT_PerfCounter;
  297. QueueNetbiosPacket (newPktTag);
  298. // The original copy will have to be
  299. // destroyed after it is sent on the
  300. // connected interface
  301. pktTag->PT_Flags |= PT_NB_DESTROY;
  302. }
  303. }
  304. status = NDIS_STATUS_PENDING;
  305. break;
  306. }
  307. else { // Process keepalives
  308. LONGLONG curTime;
  309. KeQuerySystemTime ((PLARGE_INTEGER)&curTime);
  310. if (((curTime-dstIf->ICB_DisconnectTime)/10000000) < SpoofingTimeout) {
  311. KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
  312. IpxFwdDbgPrint (DBG_SPOOFING, DBG_INFORMATION,
  313. ("IpxFwd: Queueing reply to keepalive from server"
  314. " on if %ld (ifCB %lx)"
  315. " at %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%02x%02x.\n",
  316. dstIf->ICB_Index, dstIf,
  317. *(pktTag->PT_Data+IPXH_SRCNET),*(pktTag->PT_Data+IPXH_SRCNET+1),
  318. *(pktTag->PT_Data+IPXH_SRCNET+2),*(pktTag->PT_Data+IPXH_SRCNET+3),
  319. *(pktTag->PT_Data+IPXH_SRCNODE),*(pktTag->PT_Data+IPXH_SRCNODE+1),
  320. *(pktTag->PT_Data+IPXH_SRCNODE+2),*(pktTag->PT_Data+IPXH_SRCNODE+3),
  321. *(pktTag->PT_Data+IPXH_SRCNODE+4),*(pktTag->PT_Data+IPXH_SRCNODE+5),
  322. *(pktTag->PT_Data+IPXH_SRCSOCK),*(pktTag->PT_Data+IPXH_SRCNODE+1)));
  323. // Spoof the packet if timeout has not been exceeded
  324. KeAcquireSpinLock (&SpoofingQueueLock, &oldIRQL);
  325. InsertTailList (&SpoofingQueue, &pktTag->PT_QueueLink);
  326. if (!SpoofingWorkerActive
  327. && EnterForwarder()) {
  328. SpoofingWorkerActive = TRUE;
  329. ExQueueWorkItem (&SpoofingWorker, DelayedWorkQueue);
  330. }
  331. KeReleaseSpinLock (&SpoofingQueueLock, oldIRQL);
  332. // We will actually send this packet though
  333. // in other direction, so mark it as pending
  334. // to prevent ProcessSentPacket to be called
  335. status = NDIS_STATUS_PENDING;
  336. break;
  337. }
  338. // else don't spoof (fall through and fail the packet)
  339. }
  340. case FWD_OPER_STATE_DOWN:
  341. KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
  342. status = NDIS_STATUS_ADAPTER_NOT_READY;
  343. IpxFwdDbgPrint (DBG_SEND, DBG_WARNING,
  344. ("IpxFwd: Failed external packet %08lx on if %ld(down?).\n",
  345. pktTag, dstIf->ICB_Index));
  346. break;
  347. default:
  348. status = STATUS_UNSUCCESSFUL;
  349. ASSERTMSG ("Invalid operational state ", FALSE);
  350. }
  351. }
  352. else {
  353. IpxFwdDbgPrint (DBG_SEND, DBG_WARNING,
  354. ("IpxFwd: Could not send packet %08lx on if %ld (quota exceeded).\n",
  355. pktTag, dstIf->ICB_Index));
  356. status = NDIS_STATUS_RESOURCES;
  357. }
  358. if (status!=NDIS_STATUS_PENDING)
  359. ProcessSentPacket (dstIf, pktTag, status);
  360. }
  361. /*++
  362. *******************************************************************
  363. F w S e n d C o m p l e t e
  364. Routine Description:
  365. Called by IPX stack when send completes asynchronously
  366. Arguments:
  367. pktDscr - descriptor of the completed packet
  368. status - result of send operation
  369. Return Value:
  370. None
  371. *******************************************************************
  372. --*/
  373. VOID
  374. IpxFwdSendComplete (
  375. PNDIS_PACKET pktDscr,
  376. NDIS_STATUS status
  377. ) {
  378. PPACKET_TAG pktTag;
  379. PNDIS_BUFFER bufDscr;
  380. pktTag = (PPACKET_TAG)pktDscr->ProtocolReserved;
  381. NdisUnchainBufferAtFront (pktDscr, &bufDscr);
  382. ASSERT (bufDscr==pktTag->PT_MacHdrBufDscr);
  383. NdisQueryPacket(pktDscr,
  384. NULL,
  385. NULL,
  386. &bufDscr,
  387. NULL);
  388. NdisAdjustBufferLength(bufDscr,
  389. pktTag->PT_Segment->PS_SegmentList->SL_BlockSize);
  390. NdisRecalculatePacketCounts (pktDscr);
  391. #if DBG
  392. {
  393. KIRQL oldIRQL;
  394. KeAcquireSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, &oldIRQL);
  395. RemoveEntryList (&pktTag->PT_QueueLink);
  396. KeReleaseSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, oldIRQL);
  397. }
  398. #endif
  399. ProcessSentPacket (pktTag->PT_InterfaceReference, pktTag, status);
  400. LeaveForwarder (); // Entered before calling IpxSendPacket
  401. }
  402. /*++
  403. *******************************************************************
  404. F w I n t e r n a l S e n d
  405. Routine Description:
  406. Filter and routes packets sent by IPX stack
  407. Arguments:
  408. LocalTarget - the NicId and next hop router MAC address
  409. Context - preferred interface on which to send
  410. Packet - packet to be sent
  411. ipxHdr - pointer to ipx header inside the packet
  412. PacketLength - length of the packet
  413. fIterate - a flag to indicate if this is a packet for the
  414. iteration of which the Fwd takes responsibility
  415. - typically type 20 NetBIOS frames
  416. Return Value:
  417. STATUS_SUCCESS - if the preferred NIC was OK and packet passed filtering
  418. STATUS_NETWORK_UNREACHABLE - if the preferred was not OK or packet failed filtering
  419. STATUS_PENDING - packet was queued until connection is established
  420. *******************************************************************
  421. --*/
  422. NTSTATUS
  423. IpxFwdInternalSend (
  424. IN OUT PIPX_LOCAL_TARGET LocalTarget,
  425. IN ULONG_PTR Context,
  426. IN PNDIS_PACKET pktDscr,
  427. IN PUCHAR ipxHdr,
  428. IN PUCHAR data,
  429. IN ULONG PacketLength,
  430. IN BOOLEAN fIterate
  431. ) {
  432. PINTERFACE_CB dstIf = NULL, // Initialized to indicate
  433. // first path through the iteration
  434. // as well as the fact the we do not
  435. // know it initially
  436. stDstIf = NULL; // Static destination for
  437. // NetBIOS names
  438. PFWD_ROUTE fwRoute = NULL;
  439. ULONG dstNet;
  440. USHORT dstSock;
  441. NTSTATUS status;
  442. if (!EnterForwarder())
  443. return STATUS_NETWORK_UNREACHABLE;
  444. if (IS_IF_ENABLED(InternalInterface)
  445. && ((*(ipxHdr+IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
  446. || InternalInterface->ICB_NetbiosAccept)) {
  447. // Print out the fact that we're going to send and display the nic id's
  448. IpxFwdDbgPrint (DBG_INT_SEND, DBG_INFORMATION,
  449. ("IpxFwd: InternalSend entered: nicid= %d if= %d ifnic= %d fIterate: %d",
  450. LocalTarget->NicId,
  451. ((Context!=INVALID_CONTEXT_VALUE) & (Context!=VIRTUAL_NET_FORWARDER_CONTEXT)) ? ((PINTERFACE_CB)Context)->ICB_Index : -1,
  452. ((Context!=INVALID_CONTEXT_VALUE) & (Context!=VIRTUAL_NET_FORWARDER_CONTEXT)) ? ((PINTERFACE_CB)Context)->ICB_NicId : -1,
  453. fIterate
  454. ));
  455. do { // Big loop used to iterate over interfaces
  456. status = STATUS_SUCCESS; // Assume success
  457. // fIterate is normally set to false and so the following codepath
  458. // is the most common. The only time fIterate is set to true is when
  459. // this is a type 20 broadcast that needs to be sent over each interface.
  460. if (!fIterate) {
  461. dstNet = GETULONG (ipxHdr+IPXH_DESTNET);
  462. if (Context!=INVALID_CONTEXT_VALUE) {
  463. if (Context!=VIRTUAL_NET_FORWARDER_CONTEXT) {
  464. // IPX driver supplied interface context, just verify that it
  465. // exists and can be used to reach the destination network
  466. dstIf = InterfaceContextToReference ((PVOID)Context,
  467. LocalTarget->NicId);
  468. }
  469. else {
  470. dstIf = InternalInterface;
  471. AcquireInterfaceReference (dstIf);
  472. }
  473. if (dstIf!=NULL) {
  474. // It does exist
  475. // First process direct connections
  476. if ((dstNet==0)
  477. || (dstNet==dstIf->ICB_Network)) {
  478. NOTHING;
  479. }
  480. else { // Network is not connected directly
  481. PINTERFACE_CB dstIf2;
  482. // Verify the route
  483. dstIf2 = FindDestination (dstNet,
  484. ipxHdr+IPXH_DESTNODE,
  485. &fwRoute);
  486. if (dstIf==dstIf2) {
  487. // Route OK, release the extra interface reference
  488. ReleaseInterfaceReference (dstIf2);
  489. }
  490. else {
  491. // Route not OK, release interface/route references
  492. InterlockedIncrement (&InternalInterface->ICB_Stats.InNoRoutes);
  493. IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
  494. ("IpxFwd: Failed direct internal send on"
  495. " if %ld to %08lx:%02x%02x%02x%02x%02x%02x"
  496. " (no route).\n",
  497. dstIf->ICB_Index, dstNet,
  498. LocalTarget->MacAddress[0],
  499. LocalTarget->MacAddress[1],
  500. LocalTarget->MacAddress[2],
  501. LocalTarget->MacAddress[3],
  502. LocalTarget->MacAddress[4],
  503. LocalTarget->MacAddress[5]));
  504. if (dstIf2!=NULL) {
  505. ReleaseInterfaceReference (dstIf2);
  506. }
  507. status = STATUS_NETWORK_UNREACHABLE;
  508. break;
  509. }
  510. }
  511. }
  512. else {
  513. InterlockedIncrement (&InternalInterface->ICB_Stats.InDiscards);
  514. IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
  515. ("IpxFwd: Invalid interface context (%08lx)"
  516. " from IPX driver on internal send to"
  517. " %08lx:%02x%02x%02x%02x%02x%02x.\n",
  518. Context, dstNet,
  519. LocalTarget->MacAddress[0],
  520. LocalTarget->MacAddress[1],
  521. LocalTarget->MacAddress[2],
  522. LocalTarget->MacAddress[3],
  523. LocalTarget->MacAddress[4],
  524. LocalTarget->MacAddress[5]));
  525. status = STATUS_NO_SUCH_DEVICE;
  526. break;
  527. }
  528. }
  529. else {// No interface context supplied by IPX driver, have to find the route
  530. dstIf = FindDestination (dstNet, ipxHdr+IPXH_DESTNODE,
  531. &fwRoute);
  532. if (dstIf!=NULL)
  533. NOTHING;
  534. else {
  535. InterlockedIncrement (&InternalInterface->ICB_Stats.InNoRoutes);
  536. IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
  537. ("IpxFwd: Failed internal send because no route to"
  538. " %08lx:%02x%02x%02x%02x%02x%02x exists.\n",
  539. LocalTarget->MacAddress[0],
  540. LocalTarget->MacAddress[1],
  541. LocalTarget->MacAddress[2],
  542. LocalTarget->MacAddress[3],
  543. LocalTarget->MacAddress[4],
  544. LocalTarget->MacAddress[5]));
  545. status = STATUS_NETWORK_UNREACHABLE;
  546. break;
  547. }
  548. }
  549. InterlockedIncrement (&InternalInterface->ICB_Stats.InDelivers);
  550. }
  551. // fIterate was set to true.
  552. // In this case, the stack is calling the forwarder with fIterate set
  553. // to true until the fwd returns STATUS_NETWORK_UNREACHABLE. It is
  554. // the fwd's job to return the NEXT nicid over which to send each time
  555. // it is called. This allows the fwd to not enumerate interfaces which
  556. // have been disabled for netbios delivery.
  557. else {
  558. dstNet = 0; // Don't care, it must be a local send
  559. // See if it's a type 20 broadcast
  560. if (*(ipxHdr+IPXH_PKTTYPE) == IPX_NETBIOS_TYPE) {
  561. // dstIf is initialized to null. The only way it
  562. // would be non-null is if this is not our first time through
  563. // the big do-while loop in this function and if on the last
  564. // time through this big loop, we found an interface that we
  565. // can't send the packet over so we're looking for the next
  566. // one now.
  567. if (dstIf==NULL) { // First time through internal loop
  568. dstSock = GETUSHORT (ipxHdr+IPXH_DESTSOCK);
  569. // See if we can get a static route for this packet
  570. if (dstSock==IPX_NETBIOS_SOCKET)
  571. stDstIf = FindNBDestination (data+(NB_NAME-IPXH_HDRSIZE));
  572. else if (dstSock==IPX_SMB_NAME_SOCKET)
  573. stDstIf = FindNBDestination (data+(SMB_NAME-IPXH_HDRSIZE));
  574. else
  575. stDstIf = NULL;
  576. }
  577. // The first time the stack calls us with fIterate==TRUE, it will
  578. // give us an INVALID_CONTEXT_VALUE so we can tell it which is the
  579. // first nic id in the iteration as per our interface table.
  580. if ((Context==INVALID_CONTEXT_VALUE) && (dstIf==NULL)) {
  581. // First time through the loop, increment counters
  582. InterlockedIncrement (&InternalInterface->ICB_Stats.InDelivers);
  583. InterlockedIncrement (&InternalInterface->ICB_Stats.NetbiosSent);
  584. // stDstIf is the interface to use if there is a static route
  585. // to the given network.
  586. if (stDstIf!=NULL) {
  587. dstIf = stDstIf;
  588. IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
  589. ("IpxFwd: Allowed internal NB broadcast (1st iteration) on if %d (%lx)"
  590. " to static name %.16s.\n",
  591. dstIf->ICB_Index, dstIf,
  592. (dstSock==IPX_NETBIOS_SOCKET)
  593. ? data+(NB_NAME-IPXH_HDRSIZE)
  594. : ((dstSock==IPX_SMB_NAME_SOCKET)
  595. ? data+(SMB_NAME-IPXH_HDRSIZE)
  596. : "Not a name frame")
  597. ));
  598. }
  599. // There is no static route. Tell the stack to use the
  600. // next interface in this enumeration.
  601. else {
  602. dstIf = GetNextInterfaceReference (NULL);
  603. if (dstIf!=NULL)
  604. IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
  605. ("IpxFwd: Allowed internal nb broadcast (1st iteration) on if %d (%lx),"
  606. " to name %.16s.\n",
  607. dstIf->ICB_Index, dstIf,
  608. (dstSock==IPX_NETBIOS_SOCKET)
  609. ? data+(NB_NAME-IPXH_HDRSIZE)
  610. : ((dstSock==IPX_SMB_NAME_SOCKET)
  611. ? data+(SMB_NAME-IPXH_HDRSIZE)
  612. : "Not a name frame")
  613. ));
  614. else {
  615. IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
  616. ("IpxFwd: Nb broadcast no destinations"
  617. " to name %.16s.\n",
  618. (dstSock==IPX_NETBIOS_SOCKET)
  619. ? data+(NB_NAME-IPXH_HDRSIZE)
  620. : ((dstSock==IPX_SMB_NAME_SOCKET)
  621. ? data+(SMB_NAME-IPXH_HDRSIZE)
  622. : "Not a name frame")
  623. ));
  624. status = STATUS_NETWORK_UNREACHABLE;
  625. break;
  626. }
  627. }
  628. }
  629. // The following path is taken if the stack provided a
  630. // valid context and set fIterate to true. Our job here
  631. // is to return the next nic id according to our interface
  632. // table over which to send the pack.
  633. else {
  634. // This path is taken if there is no static netbios route
  635. if (stDstIf==NULL) {
  636. // dstIf will be null if this is the first time through the
  637. // big do-while loop in this function.
  638. if (dstIf==NULL)
  639. dstIf = InterfaceContextToReference ((PVOID)Context,
  640. LocalTarget->NicId);
  641. dstIf = GetNextInterfaceReference (dstIf);
  642. // If we find a next interface over which to send we'll
  643. // put the nic id of that interface into the local target
  644. // after exiting the big do-while loop.
  645. if (dstIf!=NULL) {
  646. IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
  647. ("IpxFwd: Allowed internal NB broadcast (1+ iteration)"
  648. " on if %d (%lx, ctx: %08lx, nic: %d)"
  649. " to name %.16s.\n",
  650. dstIf->ICB_Index, dstIf,
  651. Context, LocalTarget->NicId,
  652. (dstSock==IPX_NETBIOS_SOCKET)
  653. ? data+(NB_NAME-IPXH_HDRSIZE)
  654. : ((dstSock==IPX_SMB_NAME_SOCKET)
  655. ? data+(SMB_NAME-IPXH_HDRSIZE)
  656. : "Not a name frame")
  657. ));
  658. }
  659. // Otherwise, we'll break out here and return
  660. // STATUS_NETWORK_UNREACHABLE which will signal to the
  661. // stack that we have finished the iteration.
  662. else {
  663. IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
  664. ("IpxFwd: NB broadcast no more iterations"
  665. " for ctx: %08lx, nic: %d"
  666. " to name %.16s.\n",
  667. Context, LocalTarget->NicId,
  668. (dstSock==IPX_NETBIOS_SOCKET)
  669. ? data+(NB_NAME-IPXH_HDRSIZE)
  670. : ((dstSock==IPX_SMB_NAME_SOCKET)
  671. ? data+(SMB_NAME-IPXH_HDRSIZE)
  672. : "Not a name frame")
  673. ));
  674. status = STATUS_NETWORK_UNREACHABLE;
  675. break;
  676. }
  677. }
  678. // This path is taken if there is a static netbios route. In this
  679. // case, we don't need to iterate over all interfaces so we break
  680. // and tell the stack that we finished our iteration.
  681. else {
  682. IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
  683. ("IpxFwd: Static NB broadcast (1+ iteration)"
  684. " on if %d (%lx, ctx: %08lx, nic: %d)"
  685. " to name %.16s.\n",
  686. stDstIf->ICB_Index, stDstIf,
  687. Context, LocalTarget->NicId,
  688. (dstSock==IPX_NETBIOS_SOCKET)
  689. ? data+(NB_NAME-IPXH_HDRSIZE)
  690. : ((dstSock==IPX_SMB_NAME_SOCKET)
  691. ? data+(SMB_NAME-IPXH_HDRSIZE)
  692. : "Not a name frame")
  693. ));
  694. ReleaseInterfaceReference (stDstIf);
  695. status = STATUS_NETWORK_UNREACHABLE;
  696. break;
  697. }
  698. }
  699. }
  700. // This path is taken if fIterate was set to true but this
  701. // is not a type 20 broadcast. I doubt that this path is
  702. // ever even taken since for general broadcasts, the stack
  703. // handles the iteration.
  704. else {
  705. if ((dstIf==NULL)
  706. && (Context!=INVALID_CONTEXT_VALUE))
  707. dstIf = InterfaceContextToReference ((PVOID)Context,
  708. LocalTarget->NicId);
  709. dstIf = GetNextInterfaceReference (dstIf);
  710. if (dstIf!=NULL) {
  711. IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
  712. ("IpxFwd: Allowed internal iterative send"
  713. " on if %d (%lx, ctx: %08lx, nic: %d)"
  714. " to %02x%02x%02x%02x%02x%02x.\n",
  715. dstIf->ICB_Index, dstIf,
  716. Context, LocalTarget->NicId,
  717. LocalTarget->MacAddress[0],
  718. LocalTarget->MacAddress[1],
  719. LocalTarget->MacAddress[2],
  720. LocalTarget->MacAddress[3],
  721. LocalTarget->MacAddress[4],
  722. LocalTarget->MacAddress[5]));
  723. }
  724. else {
  725. IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
  726. ("IpxFwd: No destinations to internal iterative send"
  727. " for ctx: %08lx, nic: %d"
  728. " to %02x%02x%02x%02x%02x%02x.\n",
  729. Context, LocalTarget->NicId,
  730. LocalTarget->MacAddress[0],
  731. LocalTarget->MacAddress[1],
  732. LocalTarget->MacAddress[2],
  733. LocalTarget->MacAddress[3],
  734. LocalTarget->MacAddress[4],
  735. LocalTarget->MacAddress[5]));
  736. status = STATUS_NETWORK_UNREACHABLE;
  737. break;
  738. }
  739. }
  740. } // End iterative send processing
  741. // We were able to find a destination interface
  742. if (IS_IF_ENABLED (dstIf)
  743. && ((*(ipxHdr+IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
  744. || (dstIf->ICB_NetbiosDeliver==FWD_NB_DELIVER_ALL)
  745. || ((dstIf->ICB_NetbiosDeliver==FWD_NB_DELIVER_IF_UP)
  746. && (dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP))
  747. || ((stDstIf!=NULL)
  748. && (dstIf->ICB_NetbiosDeliver==FWD_NB_DELIVER_STATIC)))) {
  749. KIRQL oldIRQL;
  750. FILTER_ACTION action;
  751. // In/Out filter check and statistics update
  752. action = FltFilter (ipxHdr, IPXH_HDRSIZE,
  753. InternalInterface->ICB_FilterInContext,
  754. dstIf->ICB_FilterOutContext);
  755. if (action==FILTER_PERMIT) {
  756. NOTHING;
  757. }
  758. else {
  759. InterlockedIncrement (&dstIf->ICB_Stats.OutFiltered);
  760. status = STATUS_NETWORK_UNREACHABLE;
  761. break;
  762. }
  763. KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
  764. // All set, try to send now
  765. switch (dstIf->ICB_Stats.OperationalState) {
  766. case FWD_OPER_STATE_UP:
  767. // Interface is up, let it go right away
  768. // Set NIC ID
  769. if (dstIf!=InternalInterface) {
  770. ADAPTER_CONTEXT_TO_LOCAL_TARGET (
  771. dstIf->ICB_AdapterContext,
  772. LocalTarget);
  773. }
  774. else {
  775. CONSTANT_ADAPTER_CONTEXT_TO_LOCAL_TARGET (
  776. VIRTUAL_NET_ADAPTER_CONTEXT,
  777. LocalTarget);
  778. }
  779. // Set destination node
  780. if (IsLocalSapNonAgentAdvertisement (ipxHdr,data,PacketLength,dstIf)) {
  781. // Loop back sap ads from non-sap socket
  782. IPX_NODE_CPY (&LocalTarget->MacAddress,
  783. dstIf->ICB_LocalNode);
  784. }
  785. else if ((dstNet==0) || (dstNet==dstIf->ICB_Network)) {
  786. // Direct connection: send to destination specified
  787. // in the header
  788. IPX_NODE_CPY (LocalTarget->MacAddress,
  789. ipxHdr+IPXH_DESTNODE);
  790. }
  791. else { // Indirect connection: send to next hop router
  792. if (dstIf->ICB_InterfaceType==FWD_IF_PERMANENT) {
  793. ASSERT (fwRoute!=NULL);
  794. IPX_NODE_CPY (LocalTarget->MacAddress,
  795. fwRoute->FR_NextHopAddress);
  796. }
  797. else {
  798. // Only one peer on the other side
  799. IPX_NODE_CPY (LocalTarget->MacAddress,
  800. dstIf->ICB_RemoteNode);
  801. }
  802. }
  803. KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
  804. // Update statistics
  805. InterlockedIncrement (
  806. &dstIf->ICB_Stats.OutDelivers);
  807. if (*(ipxHdr+IPXH_PKTTYPE)==IPX_NETBIOS_TYPE)
  808. InterlockedIncrement (
  809. &dstIf->ICB_Stats.NetbiosSent);
  810. IpxFwdDbgPrint (DBG_INT_SEND, DBG_INFORMATION,
  811. ("IpxFwd: Allowed internal send:"
  812. " %ld-%08lx:%02x%02x%02x%02x%02x%02x.\n",
  813. dstIf->ICB_Index, dstNet,
  814. LocalTarget->MacAddress[0],
  815. LocalTarget->MacAddress[1],
  816. LocalTarget->MacAddress[2],
  817. LocalTarget->MacAddress[3],
  818. LocalTarget->MacAddress[4],
  819. LocalTarget->MacAddress[5]));
  820. // status = STATUS_SUCCESS; // Let it go
  821. break;
  822. case FWD_OPER_STATE_SLEEPING:
  823. // Interface is disconnected, queue the packet and try to connecte
  824. if ((*(ipxHdr+IPXH_PKTTYPE)!=0)
  825. || (*(ipxHdr+IPXH_LENGTH)!=IPXH_HDRSIZE+2)
  826. || (*(data+1)!='?')) {
  827. // Not a keep-alive packet,
  828. if (((*(ipxHdr+IPXH_PKTTYPE)!=IPX_NETBIOS_TYPE))
  829. || (dstIf->ICB_NetbiosDeliver!=FWD_NB_DELIVER_IF_UP)) {
  830. // Not a netbios broadcast or we are allowed to connect
  831. // the interface to deliver netbios broadcasts
  832. if (InterlockedDecrement (&dstIf->ICB_PendingQuota)>=0) {
  833. PINTERNAL_PACKET_TAG pktTag;
  834. // Create a queue element to enqueue the packet
  835. pktTag = (PINTERNAL_PACKET_TAG)ExAllocatePoolWithTag (
  836. NonPagedPool,
  837. sizeof (INTERNAL_PACKET_TAG),
  838. FWD_POOL_TAG);
  839. if (pktTag!=NULL) {
  840. pktTag->IPT_Packet = pktDscr;
  841. pktTag->IPT_Length = PacketLength;
  842. pktTag->IPT_DataPtr = ipxHdr;
  843. // Save next hop address if after connection is
  844. // established we determine that destination net
  845. // is not connected directly
  846. if (fwRoute!=NULL)
  847. IPX_NODE_CPY (pktTag->IPT_Target.MacAddress,
  848. fwRoute->FR_NextHopAddress);
  849. AcquireInterfaceReference (dstIf); // To make sure interface
  850. // block won't go away until we are done with
  851. // the packet
  852. pktTag->IPT_InterfaceReference = dstIf;
  853. InsertTailList (&dstIf->ICB_InternalQueue,
  854. &pktTag->IPT_QueueLink);
  855. if (!IS_IF_CONNECTING (dstIf)) {
  856. QueueConnectionRequest (dstIf, pktDscr, ipxHdr, oldIRQL);
  857. IpxFwdDbgPrint (DBG_DIALREQS, DBG_WARNING,
  858. ("IpxFwd: Queued dd request on if %ld (ifCB:%08lx)"
  859. " for internal packet"
  860. " to %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%02x%02x"
  861. " from socket:%02x%02x\n",
  862. dstIf->ICB_Index, dstIf,
  863. *(ipxHdr+6),*(ipxHdr+7),
  864. *(ipxHdr+8),*(ipxHdr+9),
  865. *(ipxHdr+10),*(ipxHdr+11),
  866. *(ipxHdr+12),*(ipxHdr+13),
  867. *(ipxHdr+14),*(ipxHdr+15),
  868. *(ipxHdr+16),*(ipxHdr+17),
  869. *(ipxHdr+28),*(ipxHdr+29)));
  870. }
  871. else
  872. KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
  873. IpxFwdDbgPrint (DBG_INT_SEND, DBG_INFORMATION,
  874. ("IpxFwd: Queueing internal send packet %08lx on if %ld.\n",
  875. pktTag, dstIf->ICB_Index));
  876. status = STATUS_PENDING;
  877. break;
  878. }
  879. else {
  880. IpxFwdDbgPrint (DBG_INT_SEND, DBG_ERROR,
  881. ("IpxFwd: Could not allocate"
  882. " internal packet tag.\n"));
  883. }
  884. }
  885. InterlockedIncrement (&dstIf->ICB_PendingQuota);
  886. }
  887. else {
  888. IpxFwdDbgPrint (DBG_NETBIOS, DBG_WARNING,
  889. ("IpxFwd: Droped internal NB packet"
  890. " because FWD_NB_DELIVER_IF_UP.\n"));
  891. }
  892. }
  893. else { // Process keep-alives
  894. LONGLONG curTime;
  895. KeQuerySystemTime ((PLARGE_INTEGER)&curTime);
  896. if (((curTime-dstIf->ICB_DisconnectTime)/10000000) < SpoofingTimeout) {
  897. PPACKET_TAG pktTag;
  898. // Spoofing timeout has not been exceeded,
  899. // Create a reply packet
  900. AllocatePacket (WanPacketListId,
  901. WanPacketListId,
  902. pktTag);
  903. if (pktTag!=NULL) {
  904. KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
  905. PUTUSHORT (0xFFFF, pktTag->PT_Data+IPXH_CHECKSUM);
  906. PUTUSHORT ((IPXH_HDRSIZE+2), pktTag->PT_Data+IPXH_LENGTH);
  907. *(pktTag->PT_Data+IPXH_XPORTCTL) = 0;
  908. *(pktTag->PT_Data+IPXH_PKTTYPE) = 0;
  909. memcpy (pktTag->PT_Data+IPXH_DESTADDR,
  910. ipxHdr+IPXH_SRCADDR,
  911. 12);
  912. memcpy (pktTag->PT_Data+IPXH_SRCADDR,
  913. ipxHdr+IPXH_DESTADDR,
  914. 12);
  915. *(pktTag->PT_Data+IPXH_HDRSIZE) = *data;
  916. *(pktTag->PT_Data+IPXH_HDRSIZE+1) = 'Y';
  917. // Destination for this packet will have to
  918. // be the first active LAN adapter in the system
  919. // SHOULD BE REMOVED WHEN LOOPBACK SUPPORT US ADDED BY IPX
  920. pktTag->PT_InterfaceReference = NULL;
  921. IpxFwdDbgPrint (DBG_SPOOFING, DBG_INFORMATION,
  922. ("IpxFwd: Queueing reply to keepalive from internal server"
  923. " at %02x%02x.\n",*(ipxHdr+IPXH_DESTSOCK),*(ipxHdr+IPXH_DESTSOCK+1)));
  924. // Enqueue to spoofing queue to be sent back
  925. // to the server
  926. KeAcquireSpinLock (&SpoofingQueueLock, &oldIRQL);
  927. InsertTailList (&SpoofingQueue, &pktTag->PT_QueueLink);
  928. // Start worker if not running already
  929. if (!SpoofingWorkerActive
  930. && EnterForwarder()) {
  931. SpoofingWorkerActive = TRUE;
  932. ExQueueWorkItem (&SpoofingWorker, DelayedWorkQueue);
  933. }
  934. KeReleaseSpinLock (&SpoofingQueueLock, oldIRQL);
  935. status = STATUS_DROP_SILENTLY;
  936. break;
  937. }
  938. else {
  939. IpxFwdDbgPrint (DBG_SPOOFING, DBG_ERROR,
  940. ("IpxFwd: Could not allocate"
  941. " packet tag for spoofing.\n"));
  942. }
  943. }
  944. else {
  945. IpxFwdDbgPrint (DBG_SPOOFING, DBG_WARNING,
  946. ("IpxFwd: Internal spoofing"
  947. " timeout exceded.\n"));
  948. }
  949. }
  950. case FWD_OPER_STATE_DOWN:
  951. // Interface down or send failed
  952. KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
  953. if (*(ipxHdr+IPXH_PKTTYPE)!=IPX_NETBIOS_TYPE)
  954. InterlockedIncrement (
  955. &dstIf->ICB_Stats.OutDiscards);
  956. IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
  957. ("IpxFwd: Internal send not allowed"
  958. " on if %ld (down?).\n", dstIf->ICB_Index));
  959. status = STATUS_NETWORK_UNREACHABLE;
  960. break;
  961. default:
  962. ASSERTMSG ("Invalid operational state ", FALSE);
  963. }
  964. }
  965. else {// Interface is disabled
  966. if (*(ipxHdr+IPXH_PKTTYPE)!=IPX_NETBIOS_TYPE)
  967. InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
  968. IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
  969. ("IpxFwd: Internal send not allowed"
  970. " on because dst if (or Netbios deliver on it) %ld (ifCB: %08lx) is disabled.\n",
  971. dstIf->ICB_Index, dstIf));
  972. status = STATUS_NETWORK_UNREACHABLE;
  973. }
  974. }
  975. while (fIterate && (status!=STATUS_SUCCESS) && (status!=STATUS_PENDING));
  976. if (dstIf!=NULL)
  977. ReleaseInterfaceReference (dstIf);
  978. if (fwRoute!=NULL)
  979. ReleaseRouteReference (fwRoute);
  980. }
  981. else { // Internal interface is disabled
  982. IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
  983. ("IpxFwd: Internal send not allowed"
  984. " because internal if (or Netbios accept on it) is disabled.\n"));
  985. InterlockedIncrement (
  986. &InternalInterface->ICB_Stats.InDiscards);
  987. status = STATUS_NETWORK_UNREACHABLE;
  988. }
  989. LeaveForwarder ();
  990. return status;
  991. }
  992. /*++
  993. *******************************************************************
  994. P r o c e s s I n t e r n a l Q u e u e
  995. Routine Description:
  996. Processes packets in the interface internal queue.
  997. Called when connection request completes
  998. Arguments:
  999. dstIf - interface to process
  1000. Return Value:
  1001. None
  1002. *******************************************************************
  1003. --*/
  1004. VOID
  1005. ProcessInternalQueue (
  1006. PINTERFACE_CB dstIf
  1007. ) {
  1008. KIRQL oldIRQL;
  1009. LIST_ENTRY tempQueue;
  1010. KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
  1011. InsertHeadList (&dstIf->ICB_InternalQueue, &tempQueue);
  1012. RemoveEntryList (&dstIf->ICB_InternalQueue);
  1013. InitializeListHead (&dstIf->ICB_InternalQueue);
  1014. KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
  1015. while (!IsListEmpty (&tempQueue)) {
  1016. PINTERNAL_PACKET_TAG pktTag;
  1017. PLIST_ENTRY cur;
  1018. NTSTATUS status;
  1019. cur = RemoveHeadList (&tempQueue);
  1020. pktTag = CONTAINING_RECORD (cur, INTERNAL_PACKET_TAG, IPT_QueueLink);
  1021. InterlockedIncrement (&dstIf->ICB_PendingQuota);
  1022. KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
  1023. if (IS_IF_ENABLED(dstIf)
  1024. && (dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP)) {
  1025. IPX_NODE_CPY (pktTag->IPT_Target.MacAddress,
  1026. dstIf->ICB_RemoteNode);
  1027. ADAPTER_CONTEXT_TO_LOCAL_TARGET (
  1028. dstIf->ICB_AdapterContext,
  1029. &pktTag->IPT_Target);
  1030. KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
  1031. InterlockedIncrement (&dstIf->ICB_Stats.OutDelivers);
  1032. if (*(pktTag->IPT_DataPtr + IPXH_PKTTYPE) == IPX_NETBIOS_TYPE) {
  1033. InterlockedIncrement (&dstIf->ICB_Stats.NetbiosSent);
  1034. }
  1035. status = STATUS_SUCCESS;
  1036. }
  1037. else {
  1038. KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
  1039. InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
  1040. status = STATUS_NETWORK_UNREACHABLE;
  1041. }
  1042. IPXInternalSendCompletProc (&pktTag->IPT_Target,
  1043. pktTag->IPT_Packet,
  1044. pktTag->IPT_Length,
  1045. status);
  1046. IpxFwdDbgPrint (DBG_INT_SEND,
  1047. NT_SUCCESS (status) ? DBG_INFORMATION : DBG_WARNING,
  1048. ("IpxFwd: Returned internal packet %08lx"
  1049. " for send on if %ld with status %08lx.\n",
  1050. pktTag, dstIf->ICB_Index, status));
  1051. ReleaseInterfaceReference (pktTag->IPT_InterfaceReference);
  1052. ExFreePool (pktTag);
  1053. }
  1054. }
  1055. /*++
  1056. *******************************************************************
  1057. P r o c e s s E x t e r n a l Q u e u e
  1058. Routine Description:
  1059. Processes packets in the interface external queue.
  1060. Called when connection request completes
  1061. Arguments:
  1062. dstIf - interface to process
  1063. Return Value:
  1064. None
  1065. *******************************************************************
  1066. --*/
  1067. VOID
  1068. ProcessExternalQueue (
  1069. PINTERFACE_CB dstIf
  1070. ) {
  1071. KIRQL oldIRQL;
  1072. LIST_ENTRY tempQueue;
  1073. KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
  1074. InsertHeadList (&dstIf->ICB_ExternalQueue, &tempQueue);
  1075. RemoveEntryList (&dstIf->ICB_ExternalQueue);
  1076. InitializeListHead (&dstIf->ICB_ExternalQueue);
  1077. KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
  1078. while (!IsListEmpty (&tempQueue)) {
  1079. PPACKET_TAG pktTag;
  1080. PLIST_ENTRY cur;
  1081. NDIS_STATUS status;
  1082. cur = RemoveHeadList (&tempQueue);
  1083. pktTag = CONTAINING_RECORD (cur, PACKET_TAG, PT_QueueLink);
  1084. KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
  1085. if (IS_IF_ENABLED(dstIf)
  1086. && (dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP)) {
  1087. IPX_NODE_CPY (pktTag->PT_Target.MacAddress,
  1088. dstIf->ICB_RemoteNode);
  1089. if (*(pktTag->PT_Data + IPXH_PKTTYPE) == IPX_NETBIOS_TYPE) {
  1090. PUTULONG (dstIf->ICB_Network, pktTag->PT_Data+IPXH_DESTNET);
  1091. }
  1092. status = DoSend (dstIf, pktTag, oldIRQL);
  1093. IpxFwdDbgPrint (DBG_SEND, DBG_INFORMATION,
  1094. ("IpxFwd: Sent queued external packet %08lx if %ld.\n",
  1095. pktTag, dstIf->ICB_Index));
  1096. }
  1097. else {
  1098. KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
  1099. IpxFwdDbgPrint (DBG_SEND, DBG_WARNING,
  1100. ("IpxFwd: Dropped queued external packet %08lx on dead if %ld.\n",
  1101. pktTag, dstIf->ICB_Index));
  1102. status = STATUS_UNSUCCESSFUL;
  1103. }
  1104. if (status!=STATUS_PENDING)
  1105. ProcessSentPacket (dstIf, pktTag, status);
  1106. }
  1107. }
  1108. /*++
  1109. *******************************************************************
  1110. S p o o f e r
  1111. Routine Description:
  1112. Processes packets in spoofing queue
  1113. Arguments:
  1114. None
  1115. Return Value:
  1116. None
  1117. *******************************************************************
  1118. --*/
  1119. VOID
  1120. Spoofer (
  1121. PVOID Context
  1122. ) {
  1123. KIRQL oldIRQL;
  1124. NTSTATUS status;
  1125. UNREFERENCED_PARAMETER (Context);
  1126. KeAcquireSpinLock (&SpoofingQueueLock, &oldIRQL);
  1127. // Keep going till queue is empty
  1128. while (!IsListEmpty (&SpoofingQueue)) {
  1129. PINTERFACE_CB dstIf;
  1130. PPACKET_TAG pktTag = CONTAINING_RECORD (SpoofingQueue.Flink,
  1131. PACKET_TAG,
  1132. PT_QueueLink);
  1133. RemoveEntryList (&pktTag->PT_QueueLink);
  1134. KeReleaseSpinLock (&SpoofingQueueLock, oldIRQL);
  1135. dstIf = pktTag->PT_InterfaceReference;
  1136. if (dstIf==NULL) {
  1137. // Replies for internal server require first active LAN adapter
  1138. // SHOULD BE REMOVED WHEN LOOPBACK SUPPORT US ADDED BY IPX
  1139. while ((dstIf=GetNextInterfaceReference (dstIf))!=NULL) {
  1140. KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
  1141. if (IS_IF_ENABLED (dstIf)
  1142. && (dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP)
  1143. && (dstIf->ICB_InterfaceType==FWD_IF_PERMANENT)) {
  1144. pktTag->PT_InterfaceReference = dstIf;
  1145. IPX_NODE_CPY (&pktTag->PT_Target.MacAddress, dstIf->ICB_LocalNode);
  1146. status = DoSend (dstIf, pktTag, oldIRQL); // releases spin lock
  1147. if (status!=STATUS_PENDING)
  1148. ProcessSentPacket (dstIf, pktTag, status);
  1149. break;
  1150. }
  1151. else
  1152. KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
  1153. }
  1154. if (dstIf==NULL) {
  1155. FreePacket (pktTag);
  1156. }
  1157. }
  1158. else { // Reply for external server, interface is already known
  1159. UCHAR addr[12];
  1160. FILTER_ACTION action;
  1161. pktTag->PT_Flags &= (~PT_SOURCE_IF);
  1162. // Switch source and destination
  1163. memcpy (addr, pktTag->PT_Data+IPXH_DESTADDR, 12);
  1164. memcpy (pktTag->PT_Data+IPXH_DESTADDR,
  1165. pktTag->PT_Data+IPXH_SRCADDR, 12);
  1166. memcpy (pktTag->PT_Data+IPXH_SRCADDR, addr, 12);
  1167. // Say yes in reply
  1168. *(pktTag->PT_Data+IPXH_HDRSIZE+1) = 'Y';
  1169. action = FltFilter (pktTag->PT_Data,
  1170. GETUSHORT (pktTag->PT_Data+IPXH_LENGTH),
  1171. dstIf->ICB_FilterInContext,
  1172. pktTag->PT_SourceIf->ICB_FilterOutContext);
  1173. if (action==FILTER_PERMIT) {
  1174. // Release destination if and use source as destination
  1175. ReleaseInterfaceReference (dstIf);
  1176. dstIf = pktTag->PT_InterfaceReference = pktTag->PT_SourceIf;
  1177. // Send the packet if we can
  1178. KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
  1179. if (IS_IF_ENABLED (dstIf)
  1180. && (dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP)) {
  1181. status = DoSend (dstIf, pktTag, oldIRQL);
  1182. if (status!=STATUS_PENDING)
  1183. ProcessSentPacket (dstIf, pktTag, status);
  1184. }
  1185. else {
  1186. KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
  1187. InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
  1188. ReleaseInterfaceReference (dstIf);
  1189. FreePacket (pktTag);
  1190. }
  1191. }
  1192. else {
  1193. if (action==FILTER_DENY_OUT)
  1194. InterlockedIncrement (&pktTag->PT_SourceIf->ICB_Stats.OutFiltered);
  1195. else {
  1196. ASSERT (action==FILTER_DENY_IN);
  1197. InterlockedIncrement (&dstIf->ICB_Stats.InFiltered);
  1198. }
  1199. ReleaseInterfaceReference (dstIf);
  1200. ReleaseInterfaceReference (pktTag->PT_SourceIf);
  1201. FreePacket (pktTag);
  1202. }
  1203. }
  1204. KeAcquireSpinLock (&SpoofingQueueLock, &oldIRQL);
  1205. } // end while
  1206. SpoofingWorkerActive = FALSE;
  1207. KeReleaseSpinLock (&SpoofingQueueLock, oldIRQL);
  1208. LeaveForwarder ();
  1209. }