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.

2718 lines
102 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. send.c
  5. Abstract:
  6. This module contains code that implements the send engine for the
  7. IPX transport provider.
  8. Environment:
  9. Kernel mode
  10. Revision History:
  11. Sanjay Anand (SanjayAn) - August-25-1995
  12. Bug Fixes - tagged [SA]
  13. Sanjay Anand (SanjayAn) - 22-Sept-1995
  14. BackFill optimization changes added under #if BACK_FILL
  15. --*/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. //
  19. // Using the macro for performance reasons. Should be taken out
  20. // when NdisQueryPacket is optimized. In the near future (after PPC release)
  21. // move this to a header file and use it at other places.
  22. //
  23. #define IPX_PACKET_HEAD(Pkt) (Pkt)->Private.Head
  24. #if 0
  25. #define IpxGetMdlChainLength(Mdl, Length) { \
  26. PMDL _Mdl = (Mdl); \
  27. *(Length) = 0; \
  28. while (_Mdl) { \
  29. *(Length) += MmGetMdlByteCount(_Mdl); \
  30. _Mdl = _Mdl->Next; \
  31. } \
  32. }
  33. #endif
  34. VOID
  35. IpxSendComplete(
  36. IN NDIS_HANDLE ProtocolBindingContext,
  37. IN PNDIS_PACKET NdisPacket,
  38. IN NDIS_STATUS NdisStatus
  39. )
  40. /*++
  41. Routine Description:
  42. This routine is called by the I/O system to indicate that a connection-
  43. oriented packet has been shipped and is no longer needed by the Physical
  44. Provider.
  45. Arguments:
  46. ProtocolBindingContext - The ADAPTER structure for this binding.
  47. NdisPacket/RequestHandle - A pointer to the NDIS_PACKET that we sent.
  48. NdisStatus - the completion status of the send.
  49. Return Value:
  50. none.
  51. --*/
  52. {
  53. PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(NdisPacket->ProtocolReserved);
  54. PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
  55. PREQUEST Request;
  56. PADDRESS_FILE AddressFile;
  57. PDEVICE Device = IpxDevice;
  58. PBINDING Binding, pBinding= NULL;
  59. USHORT NewId, OldId;
  60. ULONG NewOffset, OldOffset;
  61. PIPX_HEADER IpxHeader, pIpxHeader;
  62. IPX_LOCAL_TARGET LocalTarget;
  63. PIO_STACK_LOCATION irpSp;
  64. BOOLEAN IsLoopback= FALSE;
  65. IPX_DEFINE_LOCK_HANDLE(LockHandle1)
  66. #if DBG
  67. if (Adapter != NULL) {
  68. ASSERT_ADAPTER(Adapter);
  69. }
  70. #endif
  71. //
  72. // See if this send was padded.
  73. //
  74. RealFunctionStart:;
  75. if (Reserved->PaddingBuffer) {
  76. UINT Offset;
  77. //
  78. // Check if we simply need to re-adjust the buffer length. This will
  79. // happen if we incremented the buffer length in MAC.C.
  80. //
  81. if (Reserved->PreviousTail) {
  82. CTEAssert (NDIS_BUFFER_LINKAGE(Reserved->PaddingBuffer->NdisBuffer) == NULL);
  83. NDIS_BUFFER_LINKAGE (Reserved->PreviousTail) = (PNDIS_BUFFER)NULL;
  84. } else {
  85. PNDIS_BUFFER LastBuffer = (PNDIS_BUFFER)Reserved->PaddingBuffer;
  86. UINT BufferLength;
  87. NdisQueryBufferOffset( LastBuffer, &Offset, &BufferLength );
  88. NdisAdjustBufferLength( LastBuffer, (BufferLength - 1) );
  89. }
  90. Reserved->PaddingBuffer = NULL;
  91. if (Reserved->Identifier < IDENTIFIER_IPX) {
  92. NdisRecalculatePacketCounts (NdisPacket);
  93. }
  94. }
  95. FunctionStart:;
  96. switch (Reserved->Identifier) {
  97. case IDENTIFIER_IPX:
  98. // #if DBG
  99. CTEAssert (Reserved->SendInProgress);
  100. Reserved->SendInProgress = FALSE;
  101. // #endif
  102. //
  103. // Check if this packet should be sent to all
  104. // networks.
  105. //
  106. if (Reserved->u.SR_DG.CurrentNicId) {
  107. if (NdisStatus == NDIS_STATUS_SUCCESS) {
  108. Reserved->u.SR_DG.Net0SendSucceeded = TRUE;
  109. }
  110. OldId = Reserved->u.SR_DG.CurrentNicId;
  111. IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
  112. {
  113. ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
  114. Binding = NULL;
  115. for (NewId = OldId+1; NewId <= Index; NewId++) {
  116. if ((Binding = NIC_ID_TO_BINDING(Device, NewId))
  117. &&
  118. ((!Device->SingleNetworkActive) ||
  119. (Device->ActiveNetworkWan == Binding->Adapter->MacInfo.MediumAsync))
  120. &&
  121. (Device->ForwarderBound ||
  122. (!Device->DisableDialoutSap) ||
  123. (!Binding->DialOutAsync) ||
  124. (!Reserved->u.SR_DG.OutgoingSap))) {
  125. //
  126. // The binding exists, and we either are not configured
  127. // for "SingleNetworkActive", or we are and this binding
  128. // is the right type (i.e. the active network is wan and
  129. // this is a wan binding, or the active network is not
  130. // wan and this is not a wan binding), and if the FWD is
  131. // not bound; and this is not an outgoing sap that we are
  132. // trying to send with "DisableDialoutSap" set.
  133. //
  134. //
  135. // 179436 - If forwarder is bound then ensure that we are picking a Binding that
  136. // the forwarder has an open context on. Otherwise, go to the next good binding
  137. //
  138. if (Device->ForwarderBound) {
  139. if (GET_LONG_VALUE(Binding->ReferenceCount) == 2) {
  140. break;
  141. }
  142. } else {
  143. break;
  144. }
  145. }
  146. }
  147. }
  148. if (Binding != NULL && NewId <= MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
  149. IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  150. IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
  151. //
  152. // Yes, we found another net to send it on, so
  153. // move the header around if needed and do so.
  154. //
  155. Reserved->u.SR_DG.CurrentNicId = NewId;
  156. CTEAssert ((Reserved->DestinationType == DESTINATION_BCAST) ||
  157. (Reserved->DestinationType == DESTINATION_MCAST));
  158. #if 0
  159. NewOffset = Binding->BcMcHeaderSize;
  160. OldOffset = Device->Bindings[OldId]->BcMcHeaderSize;
  161. if (OldOffset != NewOffset) {
  162. RtlMoveMemory(
  163. &Reserved->Header[NewOffset],
  164. &Reserved->Header[OldOffset],
  165. sizeof(IPX_HEADER));
  166. }
  167. IpxHeader = (PIPX_HEADER)(&Reserved->Header[NewOffset]);
  168. #endif
  169. #if BACK_FILL
  170. // This should be a normal packet. Backfill packet is never used for
  171. // reserved other than IPX type
  172. CTEAssert(!Reserved->BackFill);
  173. // Check if this is backfilled. If so restore users Mdl back to its original shape
  174. // Also, push the packet on to backfillpacket queue if the packet is not owned by the address
  175. if (Reserved->BackFill) {
  176. IPX_DEBUG(SEND, ("MSVa:%lx, UL:%d\n", Reserved->MappedSystemVa, Reserved->UserLength));
  177. Reserved->HeaderBuffer->MappedSystemVa = Reserved->MappedSystemVa;
  178. Reserved->HeaderBuffer->ByteCount = Reserved->UserLength;
  179. #ifdef SUNDOWN
  180. Reserved->HeaderBuffer->StartVa = (PCHAR)((ULONG_PTR)Reserved->HeaderBuffer->MappedSystemVa & ~(PAGE_SIZE-1));
  181. // ByteOffset is & with 0xfff. PAGE_SIZE is unlikely to > 0x100000000, so we are save to convert to ulong.
  182. Reserved->HeaderBuffer->ByteOffset = (ULONG) ((ULONG_PTR)Reserved->HeaderBuffer->MappedSystemVa & (PAGE_SIZE-1));
  183. #else
  184. Reserved->HeaderBuffer->StartVa = (PCHAR)((ULONG)Reserved->HeaderBuffer->MappedSystemVa & ~(PAGE_SIZE-1));
  185. Reserved->HeaderBuffer->ByteOffset = (ULONG)Reserved->HeaderBuffer->MappedSystemVa & (PAGE_SIZE-1);
  186. #endif
  187. IPX_DEBUG(SEND, ("completeing back filled userMdl %x\n",Reserved->HeaderBuffer));
  188. Reserved->HeaderBuffer->ByteOffset -= sizeof(IPX_HEADER);
  189. #ifdef SUNDOWN
  190. (ULONG_PTR)Reserved->HeaderBuffer->MappedSystemVa-= sizeof(IPX_HEADER);
  191. #else
  192. (ULONG)Reserved->HeaderBuffer->MappedSystemVa-= sizeof(IPX_HEADER);
  193. #endif
  194. ASSERT((LONG)Reserved->HeaderBuffer->ByteOffset >= 0);
  195. NdisAdjustBufferLength(Reserved->HeaderBuffer, (Reserved->HeaderBuffer->ByteCount+sizeof(IPX_HEADER)));
  196. IPX_DEBUG(SEND, ("Adjusting backfill userMdl Ipxheader %x RESD : %x\n",Reserved->HeaderBuffer, Reserved));
  197. }
  198. #endif
  199. IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
  200. FILL_LOCAL_TARGET(&LocalTarget, NewId);
  201. RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
  202. if (Device->MultiCardZeroVirtual ||
  203. (IpxHeader->DestinationSocket == SAP_SOCKET)) {
  204. //
  205. // SAP frames need to look like they come from the
  206. // local network, not the virtual one. The same is
  207. // true if we are running multiple nets without
  208. // a virtual net.
  209. //
  210. *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
  211. RtlCopyMemory (IpxHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
  212. }
  213. //
  214. // Fill in the MAC header and submit the frame to NDIS.
  215. //
  216. // #if DBG
  217. CTEAssert (!Reserved->SendInProgress);
  218. Reserved->SendInProgress = TRUE;
  219. // #endif
  220. //
  221. // [FW] Call the InternalSendHandler of the Forwarder
  222. //
  223. if (Device->ForwarderBound) {
  224. //
  225. // Call the InternalSend to filter the packet and get to know
  226. // the correct adapter context
  227. //
  228. NTSTATUS ret;
  229. PUCHAR IpxHeader;
  230. PUCHAR Data;
  231. PNDIS_BUFFER HeaderBuffer;
  232. UINT TempHeaderBufferLength;
  233. UINT DataLength;
  234. #ifdef SUNDOWN
  235. ULONG_PTR FwdAdapterCtx = INVALID_CONTEXT_VALUE;
  236. #else
  237. ULONG FwdAdapterCtx = INVALID_CONTEXT_VALUE;
  238. #endif
  239. if (GET_LONG_VALUE(Binding->ReferenceCount) == 2) {
  240. FwdAdapterCtx = Binding->FwdAdapterContext;
  241. }
  242. //
  243. // Figure out the IpxHeader - it is always at the top of the second MDL.
  244. //
  245. NdisQueryPacket (NdisPacket, NULL, NULL, &HeaderBuffer, NULL);
  246. NdisQueryBufferSafe (NDIS_BUFFER_LINKAGE(HeaderBuffer), &IpxHeader, &TempHeaderBufferLength, HighPagePriority);
  247. //
  248. // Data is always at the top of the third MDL.
  249. //
  250. NdisQueryBufferSafe (NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(HeaderBuffer)), &Data, &DataLength, HighPagePriority);
  251. if (IpxHeader != NULL && Data != NULL) {
  252. #ifdef SUNDOWN
  253. // upper driver interface needs ULONG
  254. ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)(
  255. &LocalTarget,
  256. FwdAdapterCtx,
  257. NdisPacket,
  258. IpxHeader,
  259. Data,
  260. (ULONG) (REQUEST_INFORMATION(Reserved->u.SR_DG.Request)) + sizeof(IPX_HEADER),
  261. FALSE);
  262. #else
  263. ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)(
  264. &LocalTarget,
  265. FwdAdapterCtx,
  266. NdisPacket,
  267. IpxHeader,
  268. Data,
  269. REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
  270. FALSE);
  271. #endif
  272. //
  273. // The return shd not be a silent drop - we dont broadcast keepalives.
  274. //
  275. CTEAssert(ret != STATUS_DROP_SILENTLY);
  276. if (ret == STATUS_SUCCESS) {
  277. //
  278. // The adapter could have gone away and we have indicated to the Forwarder
  279. // but the Forwarder has not yet closed the adapter.
  280. // [ZZ] adapters do not go away now.
  281. //
  282. // what if the binding is NULL here? Can we trust the Forwarder to
  283. // give us a non-NULL binding?
  284. //
  285. Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&LocalTarget));
  286. NewId = NIC_FROM_LOCAL_TARGET(&LocalTarget);
  287. if (Binding == NULL || GET_LONG_VALUE(Binding->ReferenceCount) == 1) {
  288. Adapter = Binding->Adapter;
  289. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  290. FILL_LOCAL_TARGET(&Reserved->LocalTarget, NewId);
  291. goto FunctionStart;
  292. } else {
  293. goto send_packet;
  294. }
  295. } else if (ret == STATUS_PENDING) {
  296. //
  297. // LocalTarget will get filled up in InternalSendComplete
  298. //
  299. return;
  300. }
  301. }
  302. //
  303. // else DISCARD
  304. //
  305. Adapter = Binding->Adapter;
  306. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  307. goto FunctionStart;
  308. } else {
  309. send_packet:
  310. //
  311. // [FW] Use the frametype specific send handler
  312. //
  313. // if ((NdisStatus = IpxSendFrame(
  314. // &LocalTarget,
  315. // NdisPacket,
  316. // REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
  317. // sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
  318. //
  319. // Adapter = Binding->Adapter;
  320. // goto FunctionStart;
  321. // }
  322. //
  323. // return;
  324. if ((IPX_NODE_EQUAL(IpxHeader->SourceNode, IpxHeader->DestinationNode)) &&
  325. (*(UNALIGNED ULONG *)IpxHeader->SourceNetwork == *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork)) {
  326. IPX_DEBUG(TEMP, ("It is self-directed. Loop it back ourselves (tdisenddatagram)\n"));
  327. IsLoopback = TRUE;
  328. }
  329. pBinding = NIC_ID_TO_BINDING(Device, Reserved->LocalTarget.NicId);
  330. if (pBinding) {
  331. if ((IPX_NODE_EQUAL(Reserved->LocalTarget.MacAddress, pBinding->LocalAddress.NodeAddress)) ||
  332. (IPX_NODE_EQUAL(pBinding->LocalAddress.NodeAddress, IpxHeader->DestinationNode))) {
  333. IPX_DEBUG(TEMP, ("Source Net:%lx, Source Address: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
  334. *(UNALIGNED ULONG *)IpxHeader->SourceNetwork,
  335. IpxHeader->SourceNode[0],
  336. IpxHeader->SourceNode[1],
  337. IpxHeader->SourceNode[2],
  338. IpxHeader->SourceNode[3],
  339. IpxHeader->SourceNode[4],
  340. IpxHeader->SourceNode[5]));
  341. IPX_DEBUG(TEMP, ("Dest Net:%lx, DestAddress: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x \n",
  342. *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork,
  343. IpxHeader->DestinationNode[0],
  344. IpxHeader->DestinationNode[1],
  345. IpxHeader->DestinationNode[2],
  346. IpxHeader->DestinationNode[3],
  347. IpxHeader->DestinationNode[4],
  348. IpxHeader->DestinationNode[5]
  349. ));
  350. IPX_DEBUG(TEMP, ("Well, It is self-directed. Loop it back ourselves (TDISENDDATAGRAM - NIC_HANDLE is the same!)\n"));
  351. IsLoopback = TRUE;
  352. }
  353. }
  354. IPX_DEBUG(TEMP, ("Sending a packet now Loopback - %x\n", IsLoopback));
  355. if (IsLoopback) {
  356. //
  357. // Enque this packet to the LoopbackQueue on the binding.
  358. // If the LoopbackRtn is not already scheduled, schedule it.
  359. //
  360. IPX_DEBUG(LOOPB, ("Packet: %lx\n", NdisPacket));
  361. //
  362. // Recalculate packet counts here.
  363. //
  364. // NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
  365. #if BACK_FILL
  366. if (Reserved->BackFill) {
  367. //
  368. // Set the Header pointer and chain the first MDL
  369. //
  370. Reserved->Header = (PCHAR)Reserved->HeaderBuffer->MappedSystemVa;
  371. NdisChainBufferAtFront(NdisPacket,(PNDIS_BUFFER)Reserved->HeaderBuffer);
  372. }
  373. #endif
  374. NdisRecalculatePacketCounts (NdisPacket);
  375. IpxLoopbackEnque(NdisPacket, NIC_ID_TO_BINDING(Device, 1)->Adapter);
  376. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  377. return;
  378. } else {
  379. #ifdef SUNDOWN
  380. if ((NdisStatus = (*Binding->SendFrameHandler)(
  381. Binding->Adapter,
  382. &LocalTarget,
  383. NdisPacket,
  384. (ULONG) (REQUEST_INFORMATION(Reserved->u.SR_DG.Request)) + sizeof(IPX_HEADER),
  385. sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING)
  386. #else
  387. if ((NdisStatus = (*Binding->SendFrameHandler)(
  388. Binding->Adapter,
  389. &LocalTarget,
  390. NdisPacket,
  391. REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
  392. sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING)
  393. #endif
  394. {
  395. Adapter = Binding->Adapter;
  396. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  397. goto RealFunctionStart;
  398. }
  399. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  400. return;
  401. }
  402. }
  403. } else {
  404. IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
  405. //
  406. // If any of the sends succeeded then return
  407. // success on the datagram send, otherwise
  408. // use the most recent failure status.
  409. //
  410. if (Reserved->u.SR_DG.Net0SendSucceeded) {
  411. NdisStatus = NDIS_STATUS_SUCCESS;
  412. }
  413. }
  414. }
  415. #if 0
  416. //
  417. // NOTE: We don't NULL out the linkage field of the
  418. // HeaderBuffer, which will leave the old buffer chain
  419. // hanging off it; but that is OK because if we reuse
  420. // this packet we will replace that chain with the new
  421. // one, and before we free it we NULL it out.
  422. //
  423. // I.e. we don't do this:
  424. //
  425. NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer) = NULL;
  426. NdisRecalculatePacketCounts (NdisPacket);
  427. #endif
  428. #if 0
  429. {
  430. ULONG ActualLength;
  431. IpxGetMdlChainLength(NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer), &ActualLength);
  432. if (ActualLength != REQUEST_INFORMATION(Reserved->u.SR_DG.Request)) {
  433. DbgPrint ("IPX: At completion, IRP %lx has parameter length %d, buffer chain length %d\n",
  434. Reserved->u.SR_DG.Request, REQUEST_INFORMATION(Reserved->u.SR_DG.Request), ActualLength);
  435. DbgBreakPoint();
  436. }
  437. }
  438. #endif
  439. //
  440. // Save these so we can free the packet.
  441. //
  442. Request = Reserved->u.SR_DG.Request;
  443. AddressFile = Reserved->u.SR_DG.AddressFile;
  444. #if BACK_FILL
  445. // Check if this is backfilled. If so restore users Mdl back to its original shape
  446. // Also, push the packet on to backfillpacket queue if the packet is not owned by the address
  447. if (Reserved->BackFill) {
  448. IPX_DEBUG(SEND, ("MSVa:%lx, UL:%d\n", Reserved->MappedSystemVa, Reserved->UserLength));
  449. Reserved->HeaderBuffer->MappedSystemVa = Reserved->MappedSystemVa;
  450. Reserved->HeaderBuffer->ByteCount = Reserved->UserLength;
  451. #ifdef SUNDOWN
  452. Reserved->HeaderBuffer->StartVa = (PCHAR)((ULONG_PTR)Reserved->HeaderBuffer->MappedSystemVa & ~(PAGE_SIZE-1));
  453. Reserved->HeaderBuffer->ByteOffset = (ULONG) ((ULONG_PTR)Reserved->HeaderBuffer->MappedSystemVa & (PAGE_SIZE-1));
  454. #else
  455. Reserved->HeaderBuffer->StartVa = (PCHAR)((ULONG)Reserved->HeaderBuffer->MappedSystemVa & ~(PAGE_SIZE-1));
  456. Reserved->HeaderBuffer->ByteOffset = (ULONG)Reserved->HeaderBuffer->MappedSystemVa & (PAGE_SIZE-1);
  457. #endif
  458. ASSERT((LONG)Reserved->HeaderBuffer->ByteOffset >= 0);
  459. IPX_DEBUG(SEND, ("completeing back filled userMdl %x\n",Reserved->HeaderBuffer));
  460. NdisPacket->Private.ValidCounts = FALSE;
  461. NdisPacket->Private.Head = NULL;
  462. NdisPacket->Private.Tail = NULL;
  463. Reserved->HeaderBuffer = NULL;
  464. if (Reserved->OwnedByAddress) {
  465. // Reserved->Address->BackFillPacketInUse = FALSE;
  466. InterlockedDecrement(&Reserved->Address->BackFillPacketInUse);
  467. IPX_DEBUG(SEND, ("Freeing owned backfill %x\n", Reserved));
  468. } else {
  469. IPX_PUSH_ENTRY_LIST(
  470. &Device->BackFillPacketList,
  471. &Reserved->PoolLinkage,
  472. &Device->SListsLock);
  473. }
  474. }
  475. // not a back fill packet. Push it on sendpacket pool
  476. else {
  477. if (Reserved->OwnedByAddress) {
  478. // Reserved->Address->SendPacketInUse = FALSE;
  479. InterlockedDecrement(&Reserved->Address->SendPacketInUse);
  480. } else {
  481. IPX_PUSH_ENTRY_LIST(
  482. &Device->SendPacketList,
  483. &Reserved->PoolLinkage,
  484. &Device->SListsLock);
  485. }
  486. }
  487. #else
  488. if (Reserved->OwnedByAddress) {
  489. Reserved->Address->SendPacketInUse = FALSE;
  490. } else {
  491. IPX_PUSH_ENTRY_LIST(
  492. &Device->SendPacketList,
  493. &Reserved->PoolLinkage,
  494. &Device->SListsLock);
  495. }
  496. #endif
  497. ++Device->Statistics.PacketsSent;
  498. //
  499. // If this is a fast send irp, we bypass the file system and
  500. // call the completion routine directly.
  501. //
  502. REQUEST_STATUS(Request) = NdisStatus;
  503. irpSp = IoGetCurrentIrpStackLocation( Request );
  504. if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
  505. Request->CurrentLocation++,
  506. Request->Tail.Overlay.CurrentStackLocation++;
  507. (VOID) irpSp->CompletionRoutine(
  508. NULL,
  509. Request,
  510. irpSp->Context
  511. );
  512. } else {
  513. IpxCompleteRequest (Request);
  514. }
  515. IpxFreeRequest(Device, Request);
  516. IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
  517. break;
  518. case IDENTIFIER_RIP_INTERNAL:
  519. CTEAssert (Reserved->SendInProgress);
  520. Reserved->SendInProgress = FALSE;
  521. break;
  522. case IDENTIFIER_RIP_RESPONSE:
  523. CTEAssert (Reserved->SendInProgress);
  524. Reserved->SendInProgress = FALSE;
  525. Reserved->Identifier = IDENTIFIER_IPX;
  526. IPX_PUSH_ENTRY_LIST(
  527. &Device->SendPacketList,
  528. &Reserved->PoolLinkage,
  529. &Device->SListsLock);
  530. IpxDereferenceDevice (Device, DREF_RIP_PACKET);
  531. break;
  532. case IDENTIFIER_NB:
  533. case IDENTIFIER_SPX:
  534. //
  535. // See if this is an iterative send
  536. //
  537. if (OldId = Reserved->CurrentNicId) {
  538. PNDIS_BUFFER HeaderBuffer;
  539. UINT TempHeaderBufferLength;
  540. PUCHAR Header;
  541. PIPX_HEADER IpxHeader;
  542. BOOLEAN fFwdDecides=FALSE;
  543. if (NdisStatus == NDIS_STATUS_SUCCESS) {
  544. Reserved->Net0SendSucceeded = TRUE;
  545. }
  546. //
  547. // Figure out the IpxHeader - it is always at the top of the second MDL.
  548. //
  549. NdisQueryPacket (NdisPacket, NULL, NULL, &HeaderBuffer, NULL);
  550. NdisQueryBufferSafe (NDIS_BUFFER_LINKAGE(HeaderBuffer), &IpxHeader, &TempHeaderBufferLength, HighPagePriority);
  551. if (IpxHeader == NULL) {
  552. DbgPrint("IpxSendComplete: NdisQuerryBufferSafe failed. Stop iterative send\n");
  553. goto NoMoreSends;
  554. }
  555. //
  556. // For Type 20 pkts, we let the Fwd decide the next Nic to send on, so we pass
  557. // the old Nic itself and let the Fwd change it for us.
  558. //
  559. if ((Device->ForwarderBound) &&
  560. (IpxHeader->PacketType == 0x14)) {
  561. NewId = NIC_FROM_LOCAL_TARGET(&Reserved->LocalTarget);
  562. fFwdDecides=TRUE;
  563. Binding = NIC_ID_TO_BINDING(Device, NewId);
  564. //
  565. // 206647: It is likely that after we sent the previous packet, the binding on which we
  566. // sent it is gone (due to an unbindadapter or whatever). if it is Null, get the previous
  567. // good NICID and pass it to the forwarder to get the next one. We should be in sync
  568. // with the forwarder and so it will tell us the next logical one it thinks is right.
  569. //
  570. //
  571. if (!Binding) {
  572. USHORT Index = NewId;
  573. while (Index-- > 0) { //using 0, since we should atleast have Loopback - nicid 1
  574. if( Binding = NIC_ID_TO_BINDING(Device, Index)) {
  575. //
  576. // So we found something good. Let's set newid to this Index and we should
  577. // be all set.
  578. //
  579. NewId = Index;
  580. break;
  581. }
  582. }
  583. }
  584. IPX_DEBUG(SEND, ("SendComplete: IpxHeader has Type20: %lx\n", IpxHeader));
  585. } else {
  586. IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
  587. {
  588. ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
  589. Binding = NULL;
  590. for (NewId = OldId+1; NewId <= Index; NewId++) {
  591. if (Binding = NIC_ID_TO_BINDING(Device, NewId)) {
  592. //
  593. // Found next NIC to send on
  594. //
  595. //
  596. // 179436 - If forwarder is bound then ensure that we are picking a Binding that
  597. // the forwarder has an open context on. Otherwise, go to the next good binding
  598. //
  599. if (Device->ForwarderBound) {
  600. if (GET_LONG_VALUE(Binding->ReferenceCount) == 2) {
  601. break;
  602. }
  603. } else {
  604. break;
  605. }
  606. }
  607. }
  608. }
  609. }
  610. if (Binding != NULL && NewId <= MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
  611. IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  612. IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
  613. //
  614. // Yes, we found another net to send it on, so
  615. // move the header around if needed and do so.
  616. //
  617. IPX_DEBUG(SEND, ("ISN iteration: OldId: %lx, NewId: %lx\n", OldId, NewId));
  618. Reserved->CurrentNicId = NewId;
  619. FILL_LOCAL_TARGET(&LocalTarget, NewId);
  620. RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
  621. //
  622. // [FW] Call the InternalSendHandler of the Forwarder
  623. //
  624. if (Device->ForwarderBound) {
  625. //
  626. // Call the InternalSend to filter the packet and get to know
  627. // the correct adapter context
  628. //
  629. NTSTATUS ret;
  630. PUCHAR Data;
  631. UINT DataLength;
  632. #ifdef SUNDOWN
  633. ULONG_PTR FwdAdapterCtx = INVALID_CONTEXT_VALUE;
  634. #else
  635. ULONG FwdAdapterCtx = INVALID_CONTEXT_VALUE;
  636. #endif
  637. if (GET_LONG_VALUE(Binding->ReferenceCount) == 2) {
  638. FwdAdapterCtx = Binding->FwdAdapterContext;
  639. }
  640. ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)(
  641. &LocalTarget,
  642. FwdAdapterCtx,
  643. NdisPacket,
  644. (PUCHAR)IpxHeader,
  645. ((PUCHAR)IpxHeader)+sizeof(IPX_HEADER), // the data starts after the IPX Header.
  646. Reserved->PacketLength,
  647. TRUE); // iterate is true
  648. //
  649. // The return shd not be a silent drop - we dont broadcast keepalives.
  650. //
  651. CTEAssert(ret != STATUS_DROP_SILENTLY);
  652. if (ret == STATUS_SUCCESS) {
  653. //
  654. // The adapter could have gone away and we have indicated to the Forwarder
  655. // but the Forwarder has not yet closed the adapter.
  656. // [ZZ] adapters do not go away now.
  657. //
  658. // what if the binding is NULL here? Can we trust the Forwarder to
  659. // give us a non-NULL binding?
  660. //
  661. Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&LocalTarget));
  662. NewId = NIC_FROM_LOCAL_TARGET(&LocalTarget);
  663. if (Binding == NULL || GET_LONG_VALUE(Binding->ReferenceCount) == 1) {
  664. if (Binding != NULL) {
  665. Adapter = Binding->Adapter;
  666. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  667. }
  668. FILL_LOCAL_TARGET(&Reserved->LocalTarget, NewId);
  669. DbgPrint("IPX: FWD returns an invalid nic id %d, no more sends\n", NewId);
  670. goto NoMoreSends;
  671. } else {
  672. goto send_packet1;
  673. }
  674. } else if (ret == STATUS_PENDING) {
  675. //
  676. // LocalTarget will get filled up in InternalSendComplete
  677. //
  678. return;
  679. }
  680. //
  681. // else DISCARD
  682. //
  683. Adapter = Binding->Adapter;
  684. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  685. //
  686. // If Fwd decides, then this is end of Nic list - complete the send.
  687. //
  688. if (fFwdDecides) {
  689. goto NoMoreSends;
  690. } else {
  691. goto FunctionStart;
  692. }
  693. } else {
  694. #if DBG
  695. NdisQueryPacket (NdisPacket, NULL, NULL, &HeaderBuffer, NULL);
  696. NdisQueryBufferSafe(HeaderBuffer, &Header, &TempHeaderBufferLength, LowPagePriority);
  697. if (Header != NULL) {
  698. IpxHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
  699. IPX_DEBUG(SEND, ("SendComplete: IpxHeader: %lx\n", IpxHeader));
  700. }
  701. #endif
  702. send_packet1:
  703. FILL_LOCAL_TARGET(&Reserved->LocalTarget, NewId);
  704. if ((IPX_NODE_EQUAL(IpxHeader->SourceNode, IpxHeader->DestinationNode)) &&
  705. (*(UNALIGNED ULONG *)IpxHeader->SourceNetwork == *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork)) {
  706. IPX_DEBUG(TEMP, ("It is self-directed. Loop it back ourselves (tdisenddatagram)\n"));
  707. IsLoopback = TRUE;
  708. }
  709. pBinding = NIC_ID_TO_BINDING(Device, Reserved->LocalTarget.NicId);
  710. if (pBinding) {
  711. if ((IPX_NODE_EQUAL(Reserved->LocalTarget.MacAddress, pBinding->LocalAddress.NodeAddress)) ||
  712. (IPX_NODE_EQUAL(pBinding->LocalAddress.NodeAddress, IpxHeader->DestinationNode))) {
  713. IPX_DEBUG(TEMP, ("Source Net:%lx, Source Address: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
  714. *(UNALIGNED ULONG *)IpxHeader->SourceNetwork,
  715. IpxHeader->SourceNode[0],
  716. IpxHeader->SourceNode[1],
  717. IpxHeader->SourceNode[2],
  718. IpxHeader->SourceNode[3],
  719. IpxHeader->SourceNode[4],
  720. IpxHeader->SourceNode[5]));
  721. IPX_DEBUG(TEMP, ("Dest Net:%lx, DestAddress: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x \n",
  722. *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork,
  723. IpxHeader->DestinationNode[0],
  724. IpxHeader->DestinationNode[1],
  725. IpxHeader->DestinationNode[2],
  726. IpxHeader->DestinationNode[3],
  727. IpxHeader->DestinationNode[4],
  728. IpxHeader->DestinationNode[5]
  729. ));
  730. IPX_DEBUG(TEMP, ("Well, It is self-directed. Loop it back ourselves (TDISENDDATAGRAM - NIC_HANDLE is the same!)\n"));
  731. IsLoopback = TRUE;
  732. }
  733. }
  734. IPX_DEBUG(TEMP, ("Sending a packet now. Loopback?:%x\n", IsLoopback));
  735. if (IsLoopback) {
  736. //
  737. // Enque this packet to the LoopbackQueue on the binding.
  738. // If the LoopbackRtn is not already scheduled, schedule it.
  739. //
  740. IPX_DEBUG(LOOPB, ("Packet: %lx\n", NdisPacket));
  741. //
  742. // Recalculate packet counts here.
  743. //
  744. // NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
  745. NdisRecalculatePacketCounts (NdisPacket);
  746. IpxLoopbackEnque(NdisPacket, NIC_ID_TO_BINDING(Device, 1)->Adapter);
  747. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  748. return;
  749. } else {
  750. //
  751. // We don't need to so this since the macaddress is replaced in
  752. // IpxSendFrame anyway. The LocalTarget is the same as the one on
  753. // the original send - this is passed down for further sends.
  754. //
  755. // RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
  756. //
  757. // Fill in the MAC header and submit the frame to NDIS.
  758. //
  759. if ((NdisStatus = IpxSendFrame(
  760. &Reserved->LocalTarget,
  761. NdisPacket,
  762. Reserved->PacketLength,
  763. sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
  764. Adapter = Binding->Adapter;
  765. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  766. goto FunctionStart;
  767. }
  768. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  769. return;
  770. }
  771. }
  772. } else {
  773. IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
  774. NoMoreSends:
  775. //
  776. // If any of the sends succeeded then return
  777. // success on the datagram send, otherwise
  778. // use the most recent failure status.
  779. //
  780. if (Reserved->Net0SendSucceeded) {
  781. NdisStatus = NDIS_STATUS_SUCCESS;
  782. }
  783. }
  784. }
  785. //
  786. // fall thru'
  787. //
  788. default:
  789. ASSERT((*Device->UpperDrivers[Reserved->Identifier].SendCompleteHandler) != NULL);
  790. (*Device->UpperDrivers[Reserved->Identifier].SendCompleteHandler)(
  791. NdisPacket,
  792. NdisStatus);
  793. break;
  794. }
  795. } /* IpxSendComplete */
  796. NTSTATUS
  797. IpxTdiSendDatagram(
  798. IN PDEVICE_OBJECT DeviceObject,
  799. IN PREQUEST Request
  800. )
  801. /*++
  802. Routine Description:
  803. This routine performs the TdiSendDatagram request for the transport
  804. provider.
  805. Arguments:
  806. Request - Pointer to the request.
  807. Return Value:
  808. NTSTATUS - status of operation.
  809. --*/
  810. {
  811. PADDRESS_FILE AddressFile;
  812. PADDRESS Address;
  813. PNDIS_PACKET Packet;
  814. PIPX_SEND_RESERVED Reserved;
  815. PSLIST_ENTRY s;
  816. TDI_ADDRESS_IPX UNALIGNED * RemoteAddress;
  817. TDI_ADDRESS_IPX TempAddress;
  818. TA_ADDRESS * AddressName;
  819. PTDI_CONNECTION_INFORMATION Information;
  820. PTDI_REQUEST_KERNEL_SENDDG Parameters;
  821. PBINDING Binding, pBinding = NULL;
  822. IPX_LOCAL_TARGET TempLocalTarget;
  823. PIPX_LOCAL_TARGET LocalTarget;
  824. PDEVICE Device = IpxDevice;
  825. UCHAR PacketType;
  826. NTSTATUS Status;
  827. PIPX_HEADER IpxHeader, pIpxHeader;
  828. NDIS_STATUS NdisStatus;
  829. USHORT LengthIncludingHeader;
  830. IPX_DEFINE_SYNC_CONTEXT (SyncContext)
  831. IPX_DEFINE_LOCK_HANDLE (LockHandle)
  832. PIO_STACK_LOCATION irpSp; \
  833. BOOLEAN IsLoopback = FALSE;
  834. IPX_FIND_ROUTE_REQUEST routeEntry;
  835. PIPX_DATAGRAM_OPTIONS2 Options;
  836. KPROCESSOR_MODE PreviousMode;
  837. IPX_DEFINE_LOCK_HANDLE(LockHandle1)
  838. #ifdef SNMP
  839. ++IPX_MIB_ENTRY(Device, SysOutRequests);
  840. #endif SNMP
  841. //
  842. // Do a quick check of the validity of the address.
  843. //
  844. AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
  845. IPX_BEGIN_SYNC (&SyncContext);
  846. if ((AddressFile->Size == sizeof (ADDRESS_FILE)) &&
  847. (AddressFile->Type == IPX_ADDRESSFILE_SIGNATURE) &&
  848. ((Address = AddressFile->Address) != NULL)) {
  849. IPX_GET_LOCK (&Address->Lock, &LockHandle);
  850. if (AddressFile->State != ADDRESSFILE_STATE_CLOSING) {
  851. Parameters = (PTDI_REQUEST_KERNEL_SENDDG)REQUEST_PARAMETERS(Request);
  852. //
  853. // Previously it was kmode, so things are trusted.
  854. //
  855. Information = Parameters->SendDatagramInformation;
  856. if (!REQUEST_SPECIAL_SEND(Request)) {
  857. AddressName = &((TRANSPORT_ADDRESS UNALIGNED *)(Information->RemoteAddress))->Address[0];
  858. if ((AddressName->AddressType == TDI_ADDRESS_TYPE_IPX) &&
  859. (AddressName->AddressLength >= sizeof(TDI_ADDRESS_IPX))) {
  860. RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)(AddressName->Address);
  861. } else if ((RemoteAddress = IpxParseTdiAddress (Information->RemoteAddress)) == NULL) {
  862. IPX_FREE_LOCK (&Address->Lock, LockHandle);
  863. Status = STATUS_INVALID_ADDRESS;
  864. #ifdef SNMP
  865. ++IPX_MIB_ENTRY(Device, SysOutDiscards);
  866. #endif SNMP
  867. goto error_send_no_packet;
  868. }
  869. } else {
  870. ASSERT(OPEN_REQUEST_EA_LENGTH(Request) == sizeof(IPX_DATAGRAM_OPTIONS2));
  871. Options = ((PIPX_DATAGRAM_OPTIONS2)(OPEN_REQUEST_EA_INFORMATION(Request)));
  872. RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)(&Options->RemoteAddress);
  873. IPX_DEBUG(SEND, ("IpxTdiSendDatagram: Options buffer supplied as input buffer\n"));
  874. }
  875. IPX_DEBUG (SEND, ("Send on %lx, network %lx socket %lx\n",
  876. Address, RemoteAddress->NetworkAddress, RemoteAddress->Socket));
  877. #if 0
  878. if (Parameters->SendLength > IpxDevice->RealMaxDatagramSize) {
  879. IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
  880. Parameters->SendLength,
  881. IpxDevice->RealMaxDatagramSize));
  882. REQUEST_INFORMATION(Request) = 0;
  883. IPX_FREE_LOCK (&Address->Lock, LockHandle);
  884. Status = STATUS_INVALID_BUFFER_SIZE;
  885. goto error_send_no_packet;
  886. }
  887. #endif
  888. //
  889. // Every address has one packet committed to it, use that
  890. // if possible, otherwise take one out of the pool.
  891. //
  892. #if BACK_FILL
  893. // If the request is coming from the server, which resrves transport header space
  894. // build the header in its space. Allocate a special packet to which does not contain
  895. // mac and ipx headers in its reserved space.
  896. if ((PMDL)REQUEST_NDIS_BUFFER(Request) &&
  897. (((PMDL)REQUEST_NDIS_BUFFER(Request))->MdlFlags & MDL_NETWORK_HEADER) &&
  898. (!(Information->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS))) &&
  899. (RemoteAddress->NodeAddress[0] != 0xff)) {
  900. //if (!Address->BackFillPacketInUse) {
  901. if (InterlockedExchangeAdd(&Address->BackFillPacketInUse, 0) == 0) {
  902. //Address->BackFillPacketInUse = TRUE;
  903. InterlockedIncrement(&Address->BackFillPacketInUse);
  904. Packet = PACKET(&Address->BackFillPacket);
  905. Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
  906. IPX_DEBUG(SEND, ("Getting owned backfill %x %x \n", Packet,Reserved));
  907. }else {
  908. s = IPX_POP_ENTRY_LIST(
  909. &Device->BackFillPacketList,
  910. &Device->SListsLock);
  911. if (s != NULL) {
  912. goto GotBackFillPacket;
  913. }
  914. //
  915. // This function tries to allocate another packet pool.
  916. //
  917. s = IpxPopBackFillPacket(Device);
  918. //
  919. // Possibly we should queue the packet up to wait
  920. // for one to become free.
  921. //
  922. if (s == NULL) {
  923. IPX_FREE_LOCK (&Address->Lock, LockHandle);
  924. Status = STATUS_INSUFFICIENT_RESOURCES;
  925. #ifdef SNMP
  926. ++IPX_MIB_ENTRY(Device, SysOutDiscards);
  927. #endif SNMP
  928. goto error_send_no_packet;
  929. }
  930. GotBackFillPacket:
  931. Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
  932. Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
  933. IPX_DEBUG(SEND, ("getting backfill packet %x %x %x\n", s, Reserved, RemoteAddress->NodeAddress));
  934. if(!Reserved->BackFill)DbgBreakPoint();
  935. }
  936. }else {
  937. // if (!Address->SendPacketInUse) {
  938. if (InterlockedExchangeAdd(&Address->SendPacketInUse, 0) == 0) {
  939. // Address->SendPacketInUse = TRUE;
  940. InterlockedIncrement(&Address->SendPacketInUse);
  941. Packet = PACKET(&Address->SendPacket);
  942. Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
  943. } else {
  944. s = IPX_POP_ENTRY_LIST(
  945. &Device->SendPacketList,
  946. &Device->SListsLock);
  947. if (s != NULL) {
  948. goto GotPacket;
  949. }
  950. //
  951. // This function tries to allocate another packet pool.
  952. //
  953. s = IpxPopSendPacket(Device);
  954. //
  955. // Possibly we should queue the packet up to wait
  956. // for one to become free.
  957. //
  958. if (s == NULL) {
  959. IPX_FREE_LOCK (&Address->Lock, LockHandle);
  960. Status = STATUS_INSUFFICIENT_RESOURCES;
  961. #ifdef SNMP
  962. ++IPX_MIB_ENTRY(Device, SysOutDiscards);
  963. #endif SNMP
  964. goto error_send_no_packet;
  965. }
  966. GotPacket:
  967. Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
  968. Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
  969. Reserved->BackFill = FALSE;
  970. }
  971. }
  972. #else
  973. if (!Address->SendPacketInUse) {
  974. Address->SendPacketInUse = TRUE;
  975. Packet = PACKET(&Address->SendPacket);
  976. Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
  977. } else {
  978. s = IPX_POP_ENTRY_LIST(
  979. &Device->SendPacketList,
  980. &Device->SListsLock);
  981. if (s != NULL) {
  982. goto GotPacket;
  983. }
  984. //
  985. // This function tries to allocate another packet pool.
  986. //
  987. s = IpxPopSendPacket(Device);
  988. //
  989. // Possibly we should queue the packet up to wait
  990. // for one to become free.
  991. //
  992. if (s == NULL) {
  993. IPX_FREE_LOCK (&Address->Lock, LockHandle);
  994. Status = STATUS_INSUFFICIENT_RESOURCES;
  995. goto error_send_no_packet;
  996. }
  997. GotPacket:
  998. Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
  999. Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
  1000. }
  1001. #endif
  1002. IpxReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
  1003. IPX_FREE_LOCK (&Address->Lock, LockHandle);
  1004. //
  1005. // Save this now while we have Parameters available.
  1006. //
  1007. REQUEST_INFORMATION(Request) = Parameters->SendLength;
  1008. LengthIncludingHeader = (USHORT)(Parameters->SendLength + sizeof(IPX_HEADER));
  1009. #if 0
  1010. {
  1011. ULONG ActualLength;
  1012. IpxGetMdlChainLength(REQUEST_NDIS_BUFFER(Request), &ActualLength);
  1013. if (ActualLength != Parameters->SendLength) {
  1014. DbgPrint ("IPX: IRP %lx has parameter length %d, buffer chain length %d\n",
  1015. Request, Parameters->SendLength, ActualLength);
  1016. DbgBreakPoint();
  1017. }
  1018. }
  1019. #endif
  1020. Reserved->u.SR_DG.AddressFile = AddressFile;
  1021. Reserved->u.SR_DG.Request = Request;
  1022. CTEAssert (Reserved->Identifier == IDENTIFIER_IPX);
  1023. //
  1024. // Set this to 0; this means the packet is not one that
  1025. // should be broadcast on all nets. We will change it
  1026. // later if it turns out this is the case.
  1027. //
  1028. Reserved->u.SR_DG.CurrentNicId = 0;
  1029. //
  1030. // We need this to track these packets specially.
  1031. //
  1032. Reserved->u.SR_DG.OutgoingSap = AddressFile->IsSapSocket;
  1033. //
  1034. // Add the MDL chain after the pre-allocated header buffer.
  1035. // NOTE: THIS WILL ONLY WORK IF WE EVENTUALLY CALL
  1036. // NDISRECALCULATEPACKETCOUNTS (which we do in IpxSendFrame).
  1037. //
  1038. //
  1039. #if BACK_FILL
  1040. if (Reserved->BackFill) {
  1041. Reserved->HeaderBuffer = REQUEST_NDIS_BUFFER(Request);
  1042. //remove the ipx mdl from the packet.
  1043. Reserved->UserLength = Reserved->HeaderBuffer->ByteCount;
  1044. IPX_DEBUG(SEND, ("back filling userMdl Reserved %x %x\n", Reserved->HeaderBuffer, Reserved));
  1045. } else {
  1046. NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = REQUEST_NDIS_BUFFER(Request);
  1047. }
  1048. #else
  1049. NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = REQUEST_NDIS_BUFFER(Request);
  1050. #endif
  1051. //
  1052. // If IrpSp does not have a buffer for the right size for
  1053. // datagram options and there is no input buffer
  1054. //
  1055. if (!REQUEST_SPECIAL_SEND(Request) &&
  1056. (Information->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS))) {
  1057. //
  1058. // The caller did not supply the local target for this
  1059. // send, so we look it up ourselves.
  1060. //
  1061. UINT Segment;
  1062. //
  1063. // We calculate this now since we need to know
  1064. // if it is directed below.
  1065. //
  1066. if (RemoteAddress->NodeAddress[0] == 0xff) {
  1067. // What about multicast?
  1068. if ((*(UNALIGNED ULONG *)(RemoteAddress->NodeAddress) != 0xffffffff) ||
  1069. (*(UNALIGNED USHORT *)(RemoteAddress->NodeAddress+4) != 0xffff)) {
  1070. Reserved->DestinationType = DESTINATION_MCAST;
  1071. } else {
  1072. Reserved->DestinationType = DESTINATION_BCAST;
  1073. }
  1074. } else {
  1075. Reserved->DestinationType = DESTINATION_DEF; // directed send
  1076. }
  1077. //
  1078. // If there are no options, then check if the
  1079. // caller is passing the packet type as a final byte
  1080. // in the remote address; if not use the default.
  1081. //
  1082. if (Information->OptionsLength == 0) {
  1083. if (AddressFile->ExtendedAddressing) {
  1084. PacketType = ((PUCHAR)(RemoteAddress+1))[0];
  1085. } else {
  1086. PacketType = AddressFile->DefaultPacketType;
  1087. }
  1088. } else {
  1089. PacketType = ((PUCHAR)(Information->Options))[0];
  1090. }
  1091. if ((Reserved->DestinationType != DESTINATION_DEF) &&
  1092. ((RemoteAddress->NetworkAddress == 0) ||
  1093. (Device->VirtualNetwork &&
  1094. (RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)))) {
  1095. //
  1096. // Do we have any REAL adapters? If not, just get out now.
  1097. //
  1098. if (!Device->RealAdapters) {
  1099. IPX_END_SYNC (&SyncContext);
  1100. irpSp = IoGetCurrentIrpStackLocation( Request );
  1101. if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
  1102. REQUEST_STATUS(Request) = STATUS_SUCCESS;
  1103. Request->CurrentLocation++,
  1104. Request->Tail.Overlay.CurrentStackLocation++;
  1105. (VOID) irpSp->CompletionRoutine(
  1106. NULL,
  1107. Request,
  1108. irpSp->Context
  1109. );
  1110. IpxFreeRequest (DeviceObject, Request);
  1111. }
  1112. IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
  1113. return STATUS_SUCCESS;
  1114. }
  1115. //
  1116. // This packet needs to be broadcast to all networks.
  1117. // Make sure it is not too big for any of them.
  1118. //
  1119. if (Parameters->SendLength > Device->RealMaxDatagramSize) {
  1120. IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
  1121. Parameters->SendLength, Device->RealMaxDatagramSize));
  1122. Status = STATUS_INVALID_BUFFER_SIZE;
  1123. #ifdef SNMP
  1124. ++IPX_MIB_ENTRY(Device, SysOutMalformedRequests);
  1125. #endif SNMP
  1126. goto error_send_with_packet;
  1127. }
  1128. //
  1129. // If this is a broadcast to the virtual net, we
  1130. // need to construct a fake remote address which
  1131. // has network 0 in there instead.
  1132. //
  1133. if (Device->VirtualNetwork &&
  1134. (RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)) {
  1135. RtlCopyMemory (&TempAddress, (PVOID)RemoteAddress, sizeof(TDI_ADDRESS_IPX));
  1136. TempAddress.NetworkAddress = 0;
  1137. RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)&TempAddress;
  1138. }
  1139. //
  1140. // If someone is sending to the SAP socket and
  1141. // we are running with multiple cards without a
  1142. // virtual network, AND this packet is a SAP response,
  1143. // then we log an error to warn them that the
  1144. // system may not work as they like (since there
  1145. // is no virtual network to advertise, we use
  1146. // the first card's net/node as our local address).
  1147. // We only do this once per boot, using the
  1148. // SapWarningLogged variable to control that.
  1149. //
  1150. if ((RemoteAddress->Socket == SAP_SOCKET) &&
  1151. (!Device->SapWarningLogged) &&
  1152. (Device->MultiCardZeroVirtual)) {
  1153. PNDIS_BUFFER FirstBuffer;
  1154. UINT FirstBufferLength;
  1155. USHORT UNALIGNED * FirstBufferData;
  1156. if ((FirstBuffer = REQUEST_NDIS_BUFFER(Request)) != NULL) {
  1157. NdisQueryBufferSafe (
  1158. FirstBuffer,
  1159. (PVOID *)&FirstBufferData,
  1160. &FirstBufferLength, NormalPagePriority);
  1161. if (FirstBufferData != NULL) {
  1162. //
  1163. // The first two bytes of a SAP packet are the
  1164. // operation, 0x2 (in network order) is response.
  1165. //
  1166. if ((FirstBufferLength >= sizeof(USHORT)) &&
  1167. (*FirstBufferData == 0x0200)) {
  1168. Device->SapWarningLogged = TRUE;
  1169. IpxWriteGeneralErrorLog(
  1170. Device->DeviceObject,
  1171. EVENT_IPX_SAP_ANNOUNCE,
  1172. 777,
  1173. STATUS_NOT_SUPPORTED,
  1174. NULL,
  1175. 0,
  1176. NULL);
  1177. }
  1178. }
  1179. }
  1180. }
  1181. //
  1182. // In this case we do not RIP but instead set the
  1183. // packet up so it is sent to each network in turn.
  1184. //
  1185. // Special case: If this packet is from the SAP
  1186. // socket and we are running with multiple cards
  1187. // without a virtual network, we only send this
  1188. // on the card with NIC ID 1, so we leave
  1189. // CurrentNicId set to 0.
  1190. //
  1191. //
  1192. // What if NicId 1 is invalid? Should scan
  1193. // for first valid one, fail send if none.
  1194. //
  1195. if ((Address->Socket != SAP_SOCKET) ||
  1196. (!Device->MultiCardZeroVirtual)) {
  1197. if (Device->SingleNetworkActive) {
  1198. if (Device->ActiveNetworkWan) {
  1199. Reserved->u.SR_DG.CurrentNicId = Device->FirstWanNicId;
  1200. } else {
  1201. Reserved->u.SR_DG.CurrentNicId = Device->FirstLanNicId;
  1202. }
  1203. } else {
  1204. //
  1205. // Is this the change I need to make?
  1206. //
  1207. Reserved->u.SR_DG.CurrentNicId = FIRST_REAL_BINDING;
  1208. }
  1209. Reserved->u.SR_DG.Net0SendSucceeded = FALSE;
  1210. //
  1211. // In this case, we need to scan for the first
  1212. // non-dialout wan socket.
  1213. //
  1214. if ((Device->DisableDialoutSap) &&
  1215. (Address->Socket == SAP_SOCKET)) {
  1216. PBINDING TempBinding;
  1217. CTEAssert (Reserved->u.SR_DG.CurrentNicId <= Device->ValidBindings);
  1218. while (Reserved->u.SR_DG.CurrentNicId <= MIN (Device->MaxBindings, Device->ValidBindings)) {
  1219. // No need to lock the access path since he just looks at it
  1220. //
  1221. TempBinding = NIC_ID_TO_BINDING(Device, Reserved->u.SR_DG.CurrentNicId);
  1222. if ((TempBinding != NULL) &&
  1223. (!TempBinding->DialOutAsync)) {
  1224. break;
  1225. }
  1226. ++Reserved->u.SR_DG.CurrentNicId;
  1227. }
  1228. if (Reserved->u.SR_DG.CurrentNicId > MIN (Device->MaxBindings, Device->ValidBindings)) {
  1229. //
  1230. // [SA] Bug #17273 return proper error mesg.
  1231. //
  1232. // Status = STATUS_DEVICE_DOES_NOT_EXIST;
  1233. Status = STATUS_NETWORK_UNREACHABLE;
  1234. goto error_send_with_packet;
  1235. }
  1236. }
  1237. FILL_LOCAL_TARGET(&TempLocalTarget, Reserved->u.SR_DG.CurrentNicId);
  1238. } else {
  1239. FILL_LOCAL_TARGET(&TempLocalTarget, FIRST_REAL_BINDING);
  1240. }
  1241. RtlCopyMemory(TempLocalTarget.MacAddress, RemoteAddress->NodeAddress, 6);
  1242. IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
  1243. Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&TempLocalTarget));
  1244. IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  1245. IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
  1246. //
  1247. // [FW] the localtarget shd be in the packet's reserved section
  1248. //
  1249. LocalTarget = &Reserved->LocalTarget;
  1250. Reserved->LocalTarget = TempLocalTarget;
  1251. } else {
  1252. //
  1253. // [FW] If router installed, call the Forwarder's FindRouteHandler.
  1254. // This returns a STATUS_SUCCESS if a route is available
  1255. //
  1256. if (Device->ForwarderBound) {
  1257. Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) (
  1258. (PUCHAR)&RemoteAddress->NetworkAddress,
  1259. RemoteAddress->NodeAddress,
  1260. &routeEntry);
  1261. if (Status != STATUS_SUCCESS) {
  1262. IPX_DEBUG (SEND, ("RouteHandler failed, network: %lx\n",
  1263. REORDER_ULONG(RemoteAddress->NetworkAddress)));
  1264. goto error_send_with_packet;
  1265. } else {
  1266. //
  1267. // Fill in the LocalTarget from the RouteEntry
  1268. //
  1269. LocalTarget = &Reserved->LocalTarget;
  1270. Reserved->LocalTarget = routeEntry.LocalTarget;
  1271. IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: LocalTarget is: %lx\n", Reserved->LocalTarget));
  1272. if (NIC_ID_TO_BINDING(Device, LocalTarget->NicId) == NULL || GET_LONG_VALUE(NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->ReferenceCount) == 1) {
  1273. IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned SUCCESS, Ref count is 1\n"));
  1274. Status = NDIS_STATUS_SUCCESS;
  1275. goto error_send_with_packet;
  1276. }
  1277. if (Parameters->SendLength >
  1278. NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->RealMaxDatagramSize) {
  1279. IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
  1280. Parameters->SendLength,
  1281. NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->RealMaxDatagramSize));
  1282. REQUEST_INFORMATION(Request) = 0;
  1283. Status = STATUS_INVALID_BUFFER_SIZE;
  1284. goto error_send_with_packet;
  1285. }
  1286. //
  1287. // [FW] we dont need to check this since the FWD does it for us.
  1288. //
  1289. /*
  1290. if ((Device->DisableDialoutSap) &&
  1291. (Address->Socket == SAP_SOCKET) &&
  1292. (NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->DialOutAsync)) {
  1293. REQUEST_INFORMATION(Request) = 0;
  1294. Status = STATUS_NETWORK_UNREACHABLE;
  1295. goto error_send_with_packet;
  1296. }
  1297. */
  1298. IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
  1299. Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
  1300. IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  1301. IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
  1302. IPX_DEBUG(SEND, ("FindRoute for %02x-%02x-%02x-%02x-%02x-%02x returned %lx\n",
  1303. LocalTarget->MacAddress[0],
  1304. LocalTarget->MacAddress[1],
  1305. LocalTarget->MacAddress[2],
  1306. LocalTarget->MacAddress[3],
  1307. LocalTarget->MacAddress[4],
  1308. LocalTarget->MacAddress[5],
  1309. Status));
  1310. }
  1311. } else {
  1312. Segment = RipGetSegment((PUCHAR)&RemoteAddress->NetworkAddress);
  1313. IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
  1314. //
  1315. // This call will return STATUS_PENDING if we need to
  1316. // RIP for the packet.
  1317. //
  1318. Status = RipGetLocalTarget(
  1319. Segment,
  1320. RemoteAddress,
  1321. IPX_FIND_ROUTE_RIP_IF_NEEDED,
  1322. &TempLocalTarget,
  1323. NULL);
  1324. if (Status == STATUS_SUCCESS) {
  1325. //
  1326. // We found the route, TempLocalTarget is filled in.
  1327. //
  1328. IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
  1329. IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
  1330. if (NIC_FROM_LOCAL_TARGET(&TempLocalTarget) == (USHORT)LOOPBACK_NIC_ID) {
  1331. IPX_DEBUG(LOOPB, ("Loopback TDI packet: remoteaddr: %lx\n", RemoteAddress));
  1332. IsLoopback = TRUE;
  1333. //FILL_LOCAL_TARGET(&TempLocalTarget, FIRST_REAL_BINDING);
  1334. //DbgPrint("Real Adapters?:%lx\n", Device->RealAdapters);
  1335. }
  1336. Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&TempLocalTarget));
  1337. IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  1338. IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
  1339. if (Binding == NULL || Parameters->SendLength >
  1340. Binding->RealMaxDatagramSize) {
  1341. IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
  1342. Parameters->SendLength,
  1343. Binding->RealMaxDatagramSize));
  1344. REQUEST_INFORMATION(Request) = 0;
  1345. Status = STATUS_INVALID_BUFFER_SIZE;
  1346. #ifdef SNMP
  1347. ++IPX_MIB_ENTRY(Device, SysOutMalformedRequests);
  1348. #endif SNMP
  1349. goto error_send_with_packet;
  1350. }
  1351. if (!Device->ForwarderBound &&
  1352. (Device->DisableDialoutSap) &&
  1353. (Address->Socket == SAP_SOCKET) &&
  1354. (Binding->DialOutAsync)) {
  1355. REQUEST_INFORMATION(Request) = 0;
  1356. //
  1357. // [SA] Bug #17273 return proper error mesg.
  1358. //
  1359. // Status = STATUS_DEVICE_DOES_NOT_EXIST;
  1360. Status = STATUS_NETWORK_UNREACHABLE;
  1361. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  1362. #ifdef SNMP
  1363. ++IPX_MIB_ENTRY(Device, SysOutDiscards);
  1364. #endif SNMP
  1365. goto error_send_with_packet;
  1366. }
  1367. } else if (Status == STATUS_PENDING) {
  1368. //
  1369. // A RIP request went out on the network; we queue
  1370. // this packet for transmission when the RIP
  1371. // response arrives. First we fill in the IPX
  1372. // header; the only thing we don't know is where
  1373. // exactly to fill it in, so we choose
  1374. // the most common location.
  1375. //
  1376. IpxConstructHeader(
  1377. &Reserved->Header[Device->IncludedHeaderOffset],
  1378. LengthIncludingHeader,
  1379. PacketType,
  1380. RemoteAddress,
  1381. &Address->LocalAddress);
  1382. //
  1383. // Adjust the 2nd mdl's size
  1384. //
  1385. NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
  1386. IPX_DEBUG (RIP, ("Queueing packet %lx\n", Reserved));
  1387. InsertTailList(
  1388. &Device->Segments[Segment].WaitingForRoute,
  1389. &Reserved->WaitLinkage);
  1390. IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
  1391. IPX_END_SYNC (&SyncContext);
  1392. return STATUS_PENDING;
  1393. } else {
  1394. IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
  1395. #ifdef SNMP
  1396. ++IPX_MIB_ENTRY(Device, SysOutDiscards);
  1397. #endif SNMP
  1398. goto error_send_with_packet;
  1399. }
  1400. //
  1401. // [FW] The localtarget shd be in the reserved section.
  1402. //
  1403. LocalTarget = &Reserved->LocalTarget;
  1404. Reserved->LocalTarget = TempLocalTarget;
  1405. }
  1406. }
  1407. //
  1408. // [FW] moved to the conditions above so we save a copy in the RIP case
  1409. //
  1410. // LocalTarget = &TempLocalTarget;
  1411. //
  1412. // Now we know the local target, we can figure out
  1413. // the offset for the IPX header.
  1414. //
  1415. // Remember that we have got the binding with ref above....
  1416. IpxHeader = (PIPX_HEADER)&Reserved->Header[MAC_HEADER_SIZE];
  1417. #if 0
  1418. if (Reserved->DestinationType == DESTINATION_DEF) {
  1419. IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->DefHeaderSize];
  1420. } else {
  1421. IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->BcMcHeaderSize];
  1422. }
  1423. #endif
  1424. } else {
  1425. if (!REQUEST_SPECIAL_SEND(Request)) {
  1426. PacketType = ((PUCHAR)(Information->Options))[0];
  1427. LocalTarget = &((PIPX_DATAGRAM_OPTIONS)(Information->Options))->LocalTarget;
  1428. } else {
  1429. ASSERT(OPEN_REQUEST_EA_LENGTH(Request) == sizeof(IPX_DATAGRAM_OPTIONS2));
  1430. if (OPEN_REQUEST_EA_LENGTH(Request) == sizeof(IPX_DATAGRAM_OPTIONS2)) {
  1431. //IpxPrint0("IpxTdiSendDatagram: We have an input buffer of the right size\n");
  1432. } else {
  1433. //IpxPrint1("IpxTdiSendDatagram: Wrong sized buffer. Buff size is =(%d)\n", OPEN_REQUEST_EA_LENGTH(Request));
  1434. Status = STATUS_INVALID_BUFFER_SIZE;
  1435. goto error_send_with_packet;
  1436. }
  1437. PacketType = Options->DgrmOptions.PacketType;
  1438. LocalTarget = &Options->DgrmOptions.LocalTarget;
  1439. }
  1440. //
  1441. // Calculate the binding and the correct location
  1442. // for the IPX header. We can do this at the same
  1443. // time as we calculate the DestinationType which
  1444. // saves an if like the one 15 lines up.
  1445. //
  1446. // Get lock to ref.
  1447. IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
  1448. //
  1449. // If a loopback packet, use the first binding as place holder
  1450. //
  1451. if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID) {
  1452. IsLoopback = TRUE;
  1453. }
  1454. Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
  1455. IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
  1456. if (Binding == NULL) {
  1457. DbgPrint("Binding %d does not exist.\n",NIC_FROM_LOCAL_TARGET(LocalTarget));
  1458. Status = STATUS_NOT_FOUND;
  1459. goto error_send_with_packet;
  1460. }
  1461. IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  1462. if (Parameters->SendLength > Binding->RealMaxDatagramSize) {
  1463. IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
  1464. Parameters->SendLength,
  1465. Binding->RealMaxDatagramSize));
  1466. REQUEST_INFORMATION(Request) = 0;
  1467. Status = STATUS_INVALID_BUFFER_SIZE;
  1468. #ifdef SNMP
  1469. ++IPX_MIB_ENTRY(Device, SysOutMalformedRequests);
  1470. #endif SNMP
  1471. goto error_send_with_packet;
  1472. }
  1473. #if 0
  1474. //
  1475. // This shouldn't be needed because even WAN bindings
  1476. // don't go away once they are added.
  1477. //
  1478. if (Binding == NULL) {
  1479. Status = STATUS_DEVICE_DOES_NOT_EXIST;
  1480. goto error_send_with_packet;
  1481. }
  1482. #endif
  1483. if (RemoteAddress->NodeAddress[0] == 0xff) {
  1484. // What about multicast?
  1485. if ((*(UNALIGNED ULONG *)(RemoteAddress->NodeAddress) != 0xffffffff) ||
  1486. (*(UNALIGNED USHORT *)(RemoteAddress->NodeAddress+4) != 0xffff)) {
  1487. Reserved->DestinationType = DESTINATION_MCAST;
  1488. } else {
  1489. Reserved->DestinationType = DESTINATION_BCAST;
  1490. }
  1491. // IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->BcMcHeaderSize];
  1492. } else {
  1493. Reserved->DestinationType = DESTINATION_DEF; // directed send
  1494. // IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->DefHeaderSize];
  1495. }
  1496. IpxHeader = (PIPX_HEADER)&Reserved->Header[MAC_HEADER_SIZE];
  1497. }
  1498. // ++Device->TempDatagramsSent;
  1499. // Device->TempDatagramBytesSent += Parameters->SendLength;
  1500. ADD_TO_LARGE_INTEGER(&Device->Statistics.DatagramBytesSent,
  1501. Parameters->SendLength);
  1502. Device->Statistics.DatagramsSent++;
  1503. #if BACK_FILL
  1504. if (Reserved->BackFill) {
  1505. Reserved->MappedSystemVa = Reserved->HeaderBuffer->MappedSystemVa;
  1506. IpxHeader = (PIPX_HEADER)((PCHAR)Reserved->HeaderBuffer->MappedSystemVa - sizeof(IPX_HEADER));
  1507. Reserved->HeaderBuffer->ByteOffset -= sizeof(IPX_HEADER);
  1508. ASSERT((LONG)Reserved->HeaderBuffer->ByteOffset >= 0);
  1509. #ifdef SUNDOWN
  1510. (ULONG_PTR)Reserved->HeaderBuffer->MappedSystemVa-= sizeof(IPX_HEADER);
  1511. #else
  1512. (ULONG)Reserved->HeaderBuffer->MappedSystemVa-= sizeof(IPX_HEADER);
  1513. #endif
  1514. IPX_DEBUG(SEND, ("Adjusting backfill userMdl Ipxheader %x %x \n",Reserved->HeaderBuffer,IpxHeader));
  1515. }
  1516. #endif
  1517. //
  1518. // In case the packet is being sent to a SAP socket or
  1519. // we have multiple cards and a zero virtual net or
  1520. // it is a special send (on a nic), we need to use
  1521. // the binding's address instead of the virtual address.
  1522. //
  1523. if (Device->MultiCardZeroVirtual ||
  1524. (Address->LocalAddress.Socket == SAP_SOCKET) ||
  1525. (RemoteAddress->Socket == SAP_SOCKET) ||
  1526. (REQUEST_SPECIAL_SEND(Request))) {
  1527. //
  1528. // SAP frames need to look like they come from the
  1529. // local network, not the virtual one. The same is
  1530. // true if we are running multiple nets without
  1531. // a virtual network number.
  1532. //
  1533. // If this is a binding set member and a local target
  1534. // was provided we will send using the real node of
  1535. // the binding, even if it was a slave. This is
  1536. // intentional. If no local target was provided then
  1537. // this will not be a binding slave.
  1538. //
  1539. IpxConstructHeader(
  1540. (PUCHAR)IpxHeader,
  1541. LengthIncludingHeader,
  1542. PacketType,
  1543. RemoteAddress,
  1544. &Binding->LocalAddress);
  1545. IpxHeader->SourceSocket = Address->SendSourceSocket;
  1546. } else {
  1547. IpxConstructHeader(
  1548. (PUCHAR)IpxHeader,
  1549. LengthIncludingHeader,
  1550. PacketType,
  1551. RemoteAddress,
  1552. &Address->LocalAddress);
  1553. }
  1554. //
  1555. // Fill in the MAC header and submit the frame to NDIS.
  1556. //
  1557. // #if DBG
  1558. CTEAssert (!Reserved->SendInProgress);
  1559. Reserved->SendInProgress = TRUE;
  1560. // #endif
  1561. //
  1562. // Adjust the 2nd mdl's size
  1563. //
  1564. #if BACK_FILL
  1565. if (Reserved->BackFill) {
  1566. NdisAdjustBufferLength(Reserved->HeaderBuffer, (Reserved->HeaderBuffer->ByteCount+sizeof(IPX_HEADER)));
  1567. } else {
  1568. NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
  1569. }
  1570. #else
  1571. NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
  1572. #endif
  1573. IPX_DEBUG(SEND, ("Packet Head %x\n",IPX_PACKET_HEAD(Packet)));
  1574. /*
  1575. if (Address->RtAdd)
  1576. {
  1577. REQUEST_OPEN_CONTEXT(Request) = (PVOID)(pRtInfo);
  1578. }
  1579. */
  1580. //
  1581. // [FW] If Forwarder installed, send the packet out for filtering
  1582. //
  1583. // STEFAN: 3/28/96:
  1584. // Dont filter IPXWAN config packets since the FWD does not have this adapter opened yet.
  1585. //
  1586. IPX_DEBUG(SEND, ("LocalAddress.Socket %x, IPXWAN_SOCKET\n", Address->LocalAddress.Socket, IPXWAN_SOCKET));
  1587. if (Address->LocalAddress.Socket != IPXWAN_SOCKET &&
  1588. Device->ForwarderBound) {
  1589. //
  1590. // Call the InternalSend to filter the packet and get to know
  1591. // the correct adapter context
  1592. //
  1593. NTSTATUS ret;
  1594. #ifdef SUNDOWN
  1595. ULONG_PTR FwdAdapterCtx = INVALID_CONTEXT_VALUE;
  1596. #else
  1597. ULONG FwdAdapterCtx = INVALID_CONTEXT_VALUE;
  1598. #endif
  1599. PUCHAR Data;
  1600. UINT DataLength;
  1601. if (GET_LONG_VALUE(Binding->ReferenceCount) == 2) {
  1602. FwdAdapterCtx = Binding->FwdAdapterContext;
  1603. }
  1604. //
  1605. // Figure out the location of the data in the packet
  1606. // For BackFill packets, the data is in the first (and only) MDL.
  1607. // For others, it is in the third MDL.
  1608. //
  1609. if (Reserved->BackFill) {
  1610. Data = (PUCHAR)(IpxHeader+sizeof(IPX_HEADER));
  1611. } else {
  1612. NdisQueryBufferSafe(NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)), &Data, &DataLength, HighPagePriority);
  1613. }
  1614. if (Data != NULL) {
  1615. ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)(
  1616. LocalTarget,
  1617. FwdAdapterCtx,
  1618. Packet,
  1619. (PUCHAR)IpxHeader,
  1620. Data,
  1621. LengthIncludingHeader,
  1622. FALSE);
  1623. if (ret == STATUS_SUCCESS) {
  1624. //
  1625. // The adapter could have gone away and we have indicated to the Forwarder
  1626. // but the Forwarder has not yet closed the adapter.
  1627. //
  1628. // what if the binding is NULL here? Can we trust the Forwarder to
  1629. // give us a non-NULL binding?
  1630. //
  1631. Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
  1632. // 302384
  1633. if (Binding == NULL) {
  1634. DbgPrint("IPX:nwlnkfwd has returned invalid nic id (%d) in LocalTarget (%p).\n",NIC_FROM_LOCAL_TARGET(LocalTarget), LocalTarget);
  1635. Status = STATUS_UNSUCCESSFUL;
  1636. CTEAssert (Reserved->SendInProgress);
  1637. Reserved->SendInProgress = FALSE;
  1638. goto error_send_with_packet;
  1639. }
  1640. if (GET_LONG_VALUE(Binding->ReferenceCount) == 1) {
  1641. Status = NDIS_STATUS_SUCCESS;
  1642. // #if DBG
  1643. CTEAssert (Reserved->SendInProgress);
  1644. Reserved->SendInProgress = FALSE;
  1645. // #endif
  1646. goto error_send_with_packet;
  1647. } else {
  1648. IsLoopback = (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID);
  1649. goto send_packet;
  1650. }
  1651. } else if (ret == STATUS_PENDING) {
  1652. //
  1653. // LocalTarget will get filled up in InternalSendComplete
  1654. //
  1655. //
  1656. // this is a NULL macro - include this?
  1657. //
  1658. IPX_END_SYNC (&SyncContext);
  1659. return STATUS_PENDING;
  1660. } else if (ret == STATUS_DROP_SILENTLY) {
  1661. IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned STATUS_DROP_SILENTLY - dropping pkt.\n"));
  1662. Status = NDIS_STATUS_SUCCESS;
  1663. // #if DBG
  1664. CTEAssert (Reserved->SendInProgress);
  1665. Reserved->SendInProgress = FALSE;
  1666. // #endif
  1667. goto error_send_with_packet;
  1668. }
  1669. }
  1670. //
  1671. // else DISCARD
  1672. //
  1673. //
  1674. // 179436 - If forwarder is bound then its likely that we still wanna send.
  1675. //
  1676. if (Device->ForwarderBound && (GET_LONG_VALUE(NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget))->ReferenceCount) == 1)) {
  1677. goto send_packet;
  1678. }
  1679. // #if DBG
  1680. CTEAssert (Reserved->SendInProgress);
  1681. Reserved->SendInProgress = FALSE;
  1682. // #endif
  1683. Status = STATUS_NETWORK_UNREACHABLE;
  1684. goto error_send_with_packet;
  1685. } else {
  1686. //
  1687. // [FW] Jump here if the Forwarder gave us the go ahead on this send.
  1688. // We also come here to send if the Forwarder is not installed.
  1689. //
  1690. send_packet:
  1691. //
  1692. // The workaround what is a NdisMSendX bug -
  1693. // IPX checks if it is the same network.
  1694. //
  1695. if (Reserved->BackFill) {
  1696. pIpxHeader = (PIPX_HEADER)((PCHAR)Reserved->HeaderBuffer->MappedSystemVa);
  1697. } else {
  1698. pIpxHeader = IpxHeader;
  1699. }
  1700. if ((IPX_NODE_EQUAL(pIpxHeader->SourceNode, pIpxHeader->DestinationNode)) &&
  1701. (*(UNALIGNED ULONG *)pIpxHeader->SourceNetwork == *(UNALIGNED ULONG *)pIpxHeader->DestinationNetwork)) {
  1702. IPX_DEBUG(TEMP, ("It is self-directed. Loop it back ourselves (tdisenddatagram)\n"));
  1703. IsLoopback = TRUE;
  1704. }
  1705. pBinding = NIC_ID_TO_BINDING(Device, Reserved->LocalTarget.NicId);
  1706. if (pBinding) {
  1707. if ((IPX_NODE_EQUAL(Reserved->LocalTarget.MacAddress, pBinding->LocalAddress.NodeAddress)) ||
  1708. (IPX_NODE_EQUAL(pBinding->LocalAddress.NodeAddress, pIpxHeader->DestinationNode))) {
  1709. IPX_DEBUG(TEMP, ("Source Net:%lx, Source Address: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
  1710. *(UNALIGNED ULONG *)pIpxHeader->SourceNetwork,
  1711. pIpxHeader->SourceNode[0],
  1712. pIpxHeader->SourceNode[1],
  1713. pIpxHeader->SourceNode[2],
  1714. pIpxHeader->SourceNode[3],
  1715. pIpxHeader->SourceNode[4],
  1716. pIpxHeader->SourceNode[5]));
  1717. IPX_DEBUG(TEMP, ("Dest Net:%lx, DestAddress: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x \n",
  1718. *(UNALIGNED ULONG *)pIpxHeader->DestinationNetwork,
  1719. pIpxHeader->DestinationNode[0],
  1720. pIpxHeader->DestinationNode[1],
  1721. pIpxHeader->DestinationNode[2],
  1722. pIpxHeader->DestinationNode[3],
  1723. pIpxHeader->DestinationNode[4],
  1724. pIpxHeader->DestinationNode[5]
  1725. ));
  1726. IPX_DEBUG(TEMP, ("Well, It is self-directed. Loop it back ourselves (TDISENDDATAGRAM - NIC_HANDLE is the same!)\n"));
  1727. IsLoopback = TRUE;
  1728. }
  1729. }
  1730. IPX_DEBUG(TEMP, ("Sending a packet now\n"));
  1731. IPX_DEBUG(TEMP, ("**** RemoteAddress: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x LocalAddress: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x \n",
  1732. RemoteAddress->NodeAddress[0],
  1733. RemoteAddress->NodeAddress[1],
  1734. RemoteAddress->NodeAddress[2],
  1735. RemoteAddress->NodeAddress[3],
  1736. RemoteAddress->NodeAddress[4],
  1737. RemoteAddress->NodeAddress[5],
  1738. Reserved->LocalTarget.MacAddress[0],
  1739. Reserved->LocalTarget.MacAddress[1],
  1740. Reserved->LocalTarget.MacAddress[2],
  1741. Reserved->LocalTarget.MacAddress[3],
  1742. Reserved->LocalTarget.MacAddress[4],
  1743. Reserved->LocalTarget.MacAddress[5]
  1744. ));
  1745. if (IsLoopback) {
  1746. //
  1747. // Enque this packet to the LoopbackQueue on the binding.
  1748. // If the LoopbackRtn is not already scheduled, schedule it.
  1749. //
  1750. IPX_DEBUG(LOOPB, ("Packet: %lx, Addr: %lx, Addr->SendPacket: %lx\n", Packet, Address, Address->SendPacket));
  1751. //
  1752. // Recalculate packet counts here.
  1753. //
  1754. // NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
  1755. #if BACK_FILL
  1756. if (Reserved->BackFill) {
  1757. //
  1758. // Set the Header pointer and chain the first MDL
  1759. //
  1760. Reserved->Header = (PCHAR)Reserved->HeaderBuffer->MappedSystemVa;
  1761. NdisChainBufferAtFront(Packet,(PNDIS_BUFFER)Reserved->HeaderBuffer);
  1762. }
  1763. #endif
  1764. NdisRecalculatePacketCounts (Packet);
  1765. IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
  1766. } else {
  1767. if ((NdisStatus = (*Binding->SendFrameHandler)(
  1768. Binding->Adapter,
  1769. LocalTarget,
  1770. Packet,
  1771. Parameters->SendLength + sizeof(IPX_HEADER),
  1772. sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
  1773. IpxSendComplete(
  1774. (NDIS_HANDLE)Binding->Adapter,
  1775. Packet,
  1776. NdisStatus);
  1777. }
  1778. }
  1779. IPX_END_SYNC (&SyncContext);
  1780. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  1781. return STATUS_PENDING;
  1782. }
  1783. } else {
  1784. //
  1785. // The address file state was closing.
  1786. //
  1787. IPX_FREE_LOCK (&Address->Lock, LockHandle);
  1788. Status = STATUS_INVALID_HANDLE;
  1789. #ifdef SNMP
  1790. ++IPX_MIB_ENTRY(Device, SysOutDiscards);
  1791. #endif SNMP
  1792. goto error_send_no_packet;
  1793. }
  1794. } else {
  1795. //
  1796. // The address file didn't look like one.
  1797. //
  1798. Status = STATUS_INVALID_HANDLE;
  1799. #ifdef SNMP
  1800. ++IPX_MIB_ENTRY(Device, SysOutDiscards);
  1801. #endif SNMP
  1802. goto error_send_no_packet;
  1803. }
  1804. //
  1805. // Jump here if we want to fail the send and we have already
  1806. // allocated the packet and ref'ed the address file.
  1807. //
  1808. error_send_with_packet:
  1809. #if BACK_FILL
  1810. //
  1811. // Check if this is backfilled. If so, set the headerbuffer to NULL. Note that we dont need
  1812. // restore to restore the user's MDL since it was never touched when this error occurred.
  1813. // Also, push the packet on to backfillpacket queue if the packet is not owned by the address
  1814. //
  1815. if (Reserved->BackFill) {
  1816. Reserved->HeaderBuffer = NULL;
  1817. if (Reserved->OwnedByAddress) {
  1818. // Reserved->Address->BackFillPacketInUse = FALSE;
  1819. InterlockedDecrement(&Reserved->Address->BackFillPacketInUse);
  1820. IPX_DEBUG(SEND, ("Freeing owned backfill %x\n", Reserved));
  1821. } else {
  1822. IPX_PUSH_ENTRY_LIST(
  1823. &Device->BackFillPacketList,
  1824. &Reserved->PoolLinkage,
  1825. &Device->SListsLock);
  1826. }
  1827. } else {
  1828. // not a back fill packet. Push it on sendpacket pool
  1829. if (Reserved->OwnedByAddress) {
  1830. // Reserved->Address->SendPacketInUse = FALSE;
  1831. InterlockedDecrement(&Reserved->Address->SendPacketInUse);
  1832. } else {
  1833. IPX_PUSH_ENTRY_LIST(
  1834. &Device->SendPacketList,
  1835. &Reserved->PoolLinkage,
  1836. &Device->SListsLock);
  1837. }
  1838. }
  1839. #else
  1840. if (Reserved->OwnedByAddress) {
  1841. Reserved->Address->SendPacketInUse = FALSE;
  1842. } else {
  1843. IPX_PUSH_ENTRY_LIST(
  1844. &Device->SendPacketList,
  1845. &Reserved->PoolLinkage,
  1846. &Device->SListsLock);
  1847. }
  1848. #endif
  1849. IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
  1850. error_send_no_packet:
  1851. //
  1852. // Jump here if we fail before doing any of that.
  1853. //
  1854. IPX_END_SYNC (&SyncContext);
  1855. irpSp = IoGetCurrentIrpStackLocation( Request );
  1856. if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
  1857. REQUEST_STATUS(Request) = Status;
  1858. Request->CurrentLocation++,
  1859. Request->Tail.Overlay.CurrentStackLocation++;
  1860. (VOID) irpSp->CompletionRoutine(
  1861. NULL,
  1862. Request,
  1863. irpSp->Context
  1864. );
  1865. IpxFreeRequest (DeviceObject, Request);
  1866. }
  1867. return Status;
  1868. } /* IpxTdiSendDatagram */
  1869. #if DBG
  1870. VOID
  1871. IpxConstructHeader(
  1872. IN PUCHAR Header,
  1873. IN USHORT PacketLength,
  1874. IN UCHAR PacketType,
  1875. IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
  1876. IN PTDI_ADDRESS_IPX LocalAddress
  1877. )
  1878. /*++
  1879. Routine Description:
  1880. This routine constructs an IPX header in a packet.
  1881. Arguments:
  1882. Header - The location at which the header should be built.
  1883. PacketLength - The length of the packet, including the IPX header.
  1884. PacketType - The packet type of the frame.
  1885. RemoteAddress - The remote IPX address.
  1886. LocalAddress - The local IPX address.
  1887. Return Value:
  1888. None.
  1889. --*/
  1890. {
  1891. PIPX_HEADER IpxHeader = (PIPX_HEADER)Header;
  1892. IpxHeader->CheckSum = 0xffff;
  1893. IpxHeader->PacketLength[0] = (UCHAR)(PacketLength / 256);
  1894. IpxHeader->PacketLength[1] = (UCHAR)(PacketLength % 256);
  1895. IpxHeader->TransportControl = 0;
  1896. IpxHeader->PacketType = PacketType;
  1897. //
  1898. // These copies depend on the fact that the destination
  1899. // network is the first field in the 12-byte address.
  1900. //
  1901. RtlCopyMemory(IpxHeader->DestinationNetwork, (PVOID)RemoteAddress, 12);
  1902. RtlCopyMemory(IpxHeader->SourceNetwork, LocalAddress, 12);
  1903. } /* IpxConstructHeader */
  1904. #endif
  1905. //
  1906. // [FW]
  1907. //
  1908. VOID
  1909. IpxInternalSendComplete(
  1910. IN PIPX_LOCAL_TARGET LocalTarget,
  1911. IN PNDIS_PACKET Packet,
  1912. IN ULONG PacketLength,
  1913. IN NTSTATUS Status
  1914. )
  1915. /*++
  1916. Routine Description:
  1917. This routine is called by the Kernel Forwarder to indicate that a pending
  1918. internal send to it has completed.
  1919. Arguments:
  1920. LocalTarget - if Status is OK, this has the local target for the send.
  1921. Packet - A pointer to the NDIS_PACKET that we sent.
  1922. PacketLength - length of the packet (including the IPX header)
  1923. Can IpxSendFrame use the local var. PktLength instead? What about IpxSendFrameXXX (frame specific)
  1924. Status - the completion status of the send - STATUS_SUCCESS or STATUS_NETWORK_UNREACHABLE
  1925. Return Value:
  1926. none.
  1927. --*/
  1928. {
  1929. PDEVICE Device=IpxDevice;
  1930. PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
  1931. PBINDING Binding;
  1932. NDIS_STATUS NdisStatus;
  1933. PIO_STACK_LOCATION irpSp;
  1934. PREQUEST Request;
  1935. PADDRESS_FILE AddressFile;
  1936. switch (Reserved->Identifier)
  1937. {
  1938. case IDENTIFIER_IPX:
  1939. //
  1940. // datagrams can be sent to the frame-specific handlers directly
  1941. //
  1942. // Make this change in SendComplete too
  1943. //
  1944. if ((Status == STATUS_SUCCESS) &&
  1945. (Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget))) &&
  1946. (GET_LONG_VALUE(Binding->ReferenceCount) == 2)) {
  1947. if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID) {
  1948. //
  1949. // Enque this packet to the LoopbackQueue on the binding.
  1950. // If the LoopbackRtn is not already scheduled, schedule it.
  1951. //
  1952. IPX_DEBUG(LOOPB, ("Packet: %lx \n", Packet));
  1953. //
  1954. // Recalculate packet counts here.
  1955. //
  1956. // NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
  1957. #if BACK_FILL
  1958. if (Reserved->BackFill) {
  1959. //
  1960. // Set the Header pointer and chain the first MDL
  1961. //
  1962. Reserved->Header = (PCHAR)Reserved->HeaderBuffer->MappedSystemVa;
  1963. NdisChainBufferAtFront(Packet,(PNDIS_BUFFER)Reserved->HeaderBuffer);
  1964. }
  1965. #endif
  1966. NdisRecalculatePacketCounts (Packet);
  1967. IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
  1968. } else {
  1969. if ((NdisStatus = (*Binding->SendFrameHandler)(
  1970. Binding->Adapter,
  1971. LocalTarget,
  1972. Packet,
  1973. PacketLength,
  1974. sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
  1975. //
  1976. // Call SendComplete here so it can send broadcasts over other
  1977. // Nic's and remove any padding if used.
  1978. //
  1979. IpxSendComplete((NDIS_HANDLE)Binding->Adapter,
  1980. Packet,
  1981. NdisStatus);
  1982. }
  1983. }
  1984. } else {
  1985. //
  1986. // DISCARD was returned - complete the IRP
  1987. //
  1988. NdisStatus = STATUS_NETWORK_UNREACHABLE;
  1989. //
  1990. // We need to free the packet and deref the addressfile...
  1991. //
  1992. // #if DBG
  1993. CTEAssert (Reserved->SendInProgress);
  1994. Reserved->SendInProgress = FALSE;
  1995. // #endif
  1996. if (Reserved->OwnedByAddress) {
  1997. Reserved->Address->SendPacketInUse = FALSE;
  1998. } else {
  1999. IPX_PUSH_ENTRY_LIST(
  2000. &Device->SendPacketList,
  2001. &Reserved->PoolLinkage,
  2002. &Device->Lock);
  2003. }
  2004. AddressFile = Reserved->u.SR_DG.AddressFile;
  2005. IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
  2006. Request = Reserved->u.SR_DG.Request;
  2007. REQUEST_STATUS(Request) = NdisStatus;
  2008. irpSp = IoGetCurrentIrpStackLocation( Request );
  2009. //
  2010. // If this is a fast send irp, we bypass the file system and
  2011. // call the completion routine directly.
  2012. //
  2013. if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
  2014. Request->CurrentLocation++,
  2015. Request->Tail.Overlay.CurrentStackLocation++;
  2016. (VOID) irpSp->CompletionRoutine(
  2017. NULL,
  2018. Request,
  2019. irpSp->Context
  2020. );
  2021. } else {
  2022. IpxCompleteRequest (Request);
  2023. }
  2024. IpxFreeRequest(Device, Request);
  2025. }
  2026. break;
  2027. default:
  2028. //
  2029. // for all other packet types
  2030. //
  2031. if ((Status == STATUS_SUCCESS) &&
  2032. (Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget))) &&
  2033. (GET_LONG_VALUE(Binding->ReferenceCount) == 2)) {
  2034. //
  2035. // IncludedHeaderLength is only used to check for RIP packets (==0)
  2036. // so IPX_HEADER size is OK. Should finally remove this parameter.
  2037. //
  2038. if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID) {
  2039. //
  2040. // Enque this packet to the LoopbackQueue on the binding.
  2041. // If the LoopbackRtn is not already scheduled, schedule it.
  2042. //
  2043. IPX_DEBUG(LOOPB, ("Packet: %lx\n", Packet));
  2044. //
  2045. // Recalculate packet counts here.
  2046. //
  2047. // NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
  2048. #if BACK_FILL
  2049. if (Reserved->BackFill) {
  2050. //
  2051. // Set the Header pointer and chain the first MDL
  2052. //
  2053. Reserved->Header = (PCHAR)Reserved->HeaderBuffer->MappedSystemVa;
  2054. NdisChainBufferAtFront(Packet,(PNDIS_BUFFER)Reserved->HeaderBuffer);
  2055. }
  2056. #endif
  2057. NdisRecalculatePacketCounts (Packet);
  2058. IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
  2059. } else {
  2060. NdisStatus = IpxSendFrame(LocalTarget, Packet, PacketLength, sizeof(IPX_HEADER));
  2061. if (NdisStatus != NDIS_STATUS_PENDING) {
  2062. IPX_DEBUG (SEND, ("IpxSendFrame status %lx on NICid %lx, packet %lx \n",
  2063. NdisStatus, LocalTarget->NicId, Packet));
  2064. goto error_complete;
  2065. }
  2066. }
  2067. } else {
  2068. //
  2069. // DISCARD was returned - call the upper driver's sendcomplete with error
  2070. //
  2071. //
  2072. // Else return STATUS_NETWORK_UNREACHABLE
  2073. //
  2074. NdisStatus = STATUS_NETWORK_UNREACHABLE;
  2075. error_complete:
  2076. IPX_DEBUG (SEND, ("Calling the SendCompleteHandler of tightly bound driver with status: %lx\n", NdisStatus));
  2077. (*Device->UpperDrivers[Reserved->Identifier].SendCompleteHandler)(
  2078. Packet,
  2079. NdisStatus);
  2080. }
  2081. }
  2082. }