summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/ndiswan/send.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/ndis/ndiswan/send.c')
-rw-r--r--private/ntos/ndis/ndiswan/send.c3080
1 files changed, 3080 insertions, 0 deletions
diff --git a/private/ntos/ndis/ndiswan/send.c b/private/ntos/ndis/ndiswan/send.c
new file mode 100644
index 000000000..1cf740be1
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/send.c
@@ -0,0 +1,3080 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Send.c
+
+Abstract:
+
+ This file contains the procedures for doing a send from a protocol, bound
+ to the upper interface of NdisWan, to a Wan Miniport link, bound to the
+ lower interfaceof NdisWan. The upper interface of NdisWan conforms to the
+ NDIS 3.1 Miniport specification. The lower interface of NdisWan conforms
+ to the NDIS 3.1 Extentions for Wan Miniport drivers.
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+#include "wan.h"
+#include "tcpip.h"
+#include "vjslip.h"
+#include "compress.h"
+#include <rc4.h>
+
+#define EXTRA_COPY 1
+
+//
+// Local function prototypes
+//
+NDIS_STATUS
+FrameAndSend(
+ PBUNDLECB BundleCB,
+ PPROTOCOLCB ProtocolCB,
+ PNDIS_PACKET NdisPacket,
+ BOOLEAN DoMultilink,
+ PULONG BytesSent
+ );
+
+NDIS_STATUS
+SendPacketOnBundle(
+ PBUNDLECB BundleCB
+ );
+
+#ifdef BANDWIDTH_ON_DEMAND
+BOOLEAN
+IsProtocolQuotaFilled(
+ PPROTOCOLCB ProtocolCB
+ );
+
+VOID
+AgeSampleTable(
+ PSAMPLE_TABLE SampleTable
+ );
+
+VOID
+UpdateSampleTable(
+ PSAMPLE_TABLE SampleTable,
+ ULONG BytesSent
+ );
+
+BOOLEAN
+IsSampleTableFull(
+ PSAMPLE_TABLE SampleTable
+ );
+
+VOID
+UpdateBandwidthOnDemand(
+ PBUNDLECB BundleCB,
+ ULONG BytesSent
+ );
+VOID
+CheckUpperThreshold(
+ PBUNDLECB BundleCB
+ );
+
+VOID
+CheckLowerThreshold(
+ PBUNDLECB BundleCB
+ );
+
+#endif // end of BANDWIDTH_ON_DEMAND
+
+ULONG
+GetNumSendingLinks(
+ PBUNDLECB BundleCB
+ );
+
+PLINKCB
+GetNextLinkToXmitOn(
+ PBUNDLECB BundleCB
+ );
+
+VOID
+BuildLinkHeader(
+ PHEADER_FRAMING_INFO FramingInfo,
+ PUCHAR StartBuffer
+ );
+
+//VOID
+//AddPPPProtocolID(
+// PHEADER_FRAMING_INFO FramingInfo,
+// USHORT ProtocolID
+// );
+
+//VOID
+//AddMultilinkInfo(
+// PHEADER_FRAMING_INFO FramingInfo,
+// UCHAR Flags,
+// ULONG SequenceNumber,
+// ULONG SequenceMask
+// );
+
+//VOID
+//AddCompressionInfo(
+// PHEADER_FRAMING_INFO FramingInfo,
+// USHORT CoherencyCounter
+// );
+
+
+PNDIS_WAN_PACKET
+GetWanPacketFromLink(
+ PLINKCB LinkCB
+ );
+
+VOID
+ReturnWanPacketToLink(
+ PLINKCB LinkCB,
+ PNDIS_WAN_PACKET WanPacket
+ );
+
+VOID
+DestroyIoPacket(
+ PNDIS_PACKET NdisPacket
+ );
+
+#if DBG
+VOID
+InsertDbgPacket(
+ PDBG_SEND_CONTEXT DbgContext
+ );
+
+BOOLEAN
+RemoveDbgPacket(
+ PDBG_SEND_CONTEXT DbgContext
+ );
+#endif
+
+//
+// end of local function prototypes
+//
+
+NDIS_STATUS
+NdisWanSend(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN UINT Flags
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PADAPTERCB AdapterCB = (PADAPTERCB)MiniportAdapterContext;
+ ULONG BundleIndex = 0, ProtocolIndex = 0, BytesCopied = 0;
+ BOOLEAN SendOnWire;
+ PBUNDLECB BundleCB;
+ PPROTOCOLCB ProtocolCB;
+ PETH_HEADER EthernetHeader;
+ PUCHAR DestAddr, SrcAddr;
+ USHORT ProtocolType = AdapterCB->ProtocolType;
+ PNDIS_BUFFER FirstBuffer;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("NdisWanSend: Enter"));
+ NdisWanDbgOut(DBG_INFO, DBG_SEND, ("s-0x%8.8x, 0x%8.8x, 0x%8.8x", NdisPacket,
+ *((PULONG)&NdisPacket->WrapperReserved[0]), *((PULONG)&NdisPacket->WrapperReserved[4])));
+
+ NdisWanInterlockedInc(&AdapterCB->ulReferenceCount);
+
+ //
+ // Get the ethernet address. This is stolen from the
+ // NDIS wrapper code. This may be a Win95 portability issue.
+ //
+ FirstBuffer = NdisPacket->Private.Head;
+ EthernetHeader = (PETH_HEADER)MDL_ADDRESS(FirstBuffer);
+
+// NdisWanCopyFromPacketToBuffer(NdisPacket,
+// 0,
+// sizeof(ETH_HEADER),
+// (PUCHAR)&EthernetHeader,
+// &BytesCopied);
+
+// if (BytesCopied < ETH_LENGTH_OF_ADDRESS) {
+//
+// goto NdisWanSendExit;
+// }
+
+ DestAddr = EthernetHeader->DestAddr;
+ SrcAddr = EthernetHeader->SrcAddr;
+
+ //
+ // Is this destined for the wire or is it self directed?
+ // If SendOnWire is FALSE this is a self directed packet.
+ //
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(DestAddr, SrcAddr, &SendOnWire);
+
+ //
+ // Do we need to do loopback? We can check for both multicast
+ // and broadcast with one check because we don't differentiate
+ // between the two.
+ //
+ if (!SendOnWire || (DestAddr[0] & 1)) {
+
+ //
+ // Put on loopback queue
+ //
+ NdisWanQueueLoopbackPacket(AdapterCB, NdisPacket);
+
+ }
+
+ if (!SendOnWire || AdapterCB == NdisWanCB.PromiscuousAdapter) {
+
+ goto NdisWanSendExit;
+ }
+
+ //
+ // We play special tricks with NBF because NBF is
+ // guaranteed to have a one-to-one mapping between
+ // an adapter and a bundle.
+ //
+ if (AdapterCB->ProtocolType == PROTOCOL_NBF) {
+
+ BundleCB = AdapterCB->NbfBundleCB;
+
+ if (BundleCB == NULL) {
+ //
+ // This should just fall through and complete successfully.
+ //
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: BundleCB is NULL!, BundleHandle: 0x%8.8x", BundleIndex));
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: AdapterCB: 0x%8.8x, ProtocolType: 0x%4.4x!", AdapterCB, ProtocolType));
+
+ goto NdisWanSendExit;
+ }
+
+ ProtocolIndex = (ULONG)AdapterCB->NbfProtocolHandle;
+
+ } else {
+
+ //
+ // If this a multicast or broadcast our destination
+ // address context has been compromised. We have to
+ // lift the bundle information out of the SRC address.
+ //
+ //
+ if (DestAddr[0] & 1) {
+
+ //
+ // Get the stashed BundleIndex
+ //
+ GetTransportBundleIndex(SrcAddr, BundleIndex);
+
+ BUNDLECB_FROM_BUNDLEH(BundleCB, BundleIndex);
+
+ if (BundleCB == NULL) {
+ //
+ // This should just fall through and complete successfully.
+ //
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: BundleCB is NULL!, BundleHandle: 0x%8.8x", BundleIndex));
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: AdapterCB: 0x%8.8x, ProtocolType: 0x%4.4x!", AdapterCB, ProtocolType));
+
+ goto NdisWanSendExit;
+ }
+
+ //
+ // Get the ProtocolIndex from the BundleCB's
+ // list of protocols.
+ //
+ GetProtocolIndexFromProtocolList(&BundleCB->ProtocolCBList,
+ ProtocolType,
+ ProtocolIndex);
+
+ } else {
+
+ //
+ // Get the Bundle Index and BundleCB
+ //
+ GetNdisWanBundleIndex(DestAddr, BundleIndex);
+
+ BUNDLECB_FROM_BUNDLEH(BundleCB, BundleIndex);
+
+ if (BundleCB == NULL) {
+ //
+ // This should just fall through and complete successfully.
+ //
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: BundleCB is NULL!, BundleHandle: 0x%8.8x", BundleIndex));
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: AdapterCB: 0x%8.8x, ProtocolType: 0x%4.4x!", AdapterCB, ProtocolType));
+
+ goto NdisWanSendExit;
+ }
+
+ //
+ // Get the Protocol Index
+ //
+ GetNdisWanProtocolIndex(DestAddr, ProtocolIndex);
+ }
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // Get the ProtocolCB from the BundleCB->ProtocolCBTable
+ //
+ ProtocolCBFromProtocolH(BundleCB, ProtocolIndex, ProtocolCB);
+
+ if ((BundleCB->State != BUNDLE_UP) || !(BundleCB->Flags & BUNDLE_ROUTED) ||
+ !IsValidProtocolCB(ProtocolCB) || !(ProtocolCB->Flags & PROTOCOL_ROUTED) ||
+ ProtocolCB->hProtocolHandle == 0) {
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,("NdisWanSend: Problem with route!"));
+
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: BundleCB: 0x%8.8x State: 0x%8.8x, Flags: 0x%8.8x",
+ BundleCB, BundleCB->State, BundleCB->Flags));
+
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: ProtocolCB: 0x%8.8x, ProtocolHandle: 0x%8.8x, Flags: 0x%8.8x",
+ ProtocolCB, ProtocolIndex, ProtocolCB->Flags));
+
+ goto NdisWanSendExit;
+ }
+
+ NdisWanInterlockedInc(&NdisWanCB.SendCount);
+
+#if DBG
+ {
+ DBG_SEND_CONTEXT DbgContext;
+ DbgContext.Packet = NdisPacket;
+ DbgContext.PacketType = PACKET_TYPE_NDIS;
+ DbgContext.BundleCB = BundleCB;
+ DbgContext.ProtocolCB = ProtocolCB;
+ DbgContext.LinkCB = NULL;
+ DbgContext.ListHead = &ProtocolCB->AdapterCB->DbgNdisPacketList;
+ DbgContext.ListLock = &ProtocolCB->AdapterCB->Lock;
+
+ InsertDbgPacket(&DbgContext);
+ }
+#endif
+
+ //
+ // Queue the packet on the ProtocolCB NdisPacketQueue
+ //
+ InsertTailNdisPacketQueue(ProtocolCB, NdisPacket);
+
+ //
+ // Try to send a packet on the BundleCB. Called
+ // with bundle lock held but returns with lock
+ // free.
+ //
+ Status = SendPacketOnBundle(BundleCB);
+
+ ASSERT (Status == NDIS_STATUS_PENDING);
+
+NdisWanSendExit:
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("NdisWanSend: Exit, Status: 0x%8.8x", Status));
+
+ NdisWanInterlockedDec(&AdapterCB->ulReferenceCount);
+
+ return (Status);
+}
+
+VOID
+NdisWanSendCompleteHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_WAN_PACKET WanPacket,
+ IN NDIS_STATUS Status
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+)
+{
+ PLINKCB LinkCB;
+ PBUNDLECB BundleCB;
+ PPROTOCOLCB ProtocolCB;
+ PWAN_IO_PROTOCOL_RESERVED ProtocolReserved;
+ PNDIS_PACKET NdisPacket;
+ BOOLEAN FreeLink = FALSE;
+ BOOLEAN FreeBundle = FALSE;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("NdisWanSendComplete: Enter"));
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("WanPacket: 0x%8.8x", WanPacket));
+
+ //
+ // Get info from the WanPacket
+ //
+ LinkCB = (PLINKCB)WanPacket->ProtocolReserved1;
+ NdisPacket = (PNDIS_PACKET)WanPacket->ProtocolReserved2;
+ ProtocolCB = (PPROTOCOLCB)WanPacket->ProtocolReserved3;
+
+ NdisWanDbgOut(DBG_INFO, DBG_SEND, ("sc-0x%8.8x, 0x%8.8x, 0x%8.8x", NdisPacket,
+ *((PULONG)&NdisPacket->WrapperReserved[0]), *((PULONG)&NdisPacket->WrapperReserved[4])));
+
+ //
+ // Bundle that this link is on
+ //
+ BundleCB = LinkCB->BundleCB;
+
+#if DBG
+{
+ DBG_SEND_CONTEXT DbgContext;
+
+ DbgContext.Packet = WanPacket;
+ DbgContext.PacketType = PACKET_TYPE_WAN;
+ DbgContext.BundleCB = BundleCB;
+ DbgContext.ProtocolCB = ProtocolCB;
+ DbgContext.LinkCB = LinkCB;
+ DbgContext.ListHead = &LinkCB->WanAdapterCB->DbgWanPacketList;
+ DbgContext.ListLock = &LinkCB->WanAdapterCB->Lock;
+ RemoveDbgPacket(&DbgContext);
+}
+#endif
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // Return the WanPacket to the link
+ //
+ ReturnWanPacketToLink(LinkCB, WanPacket);
+
+ //
+ // Update link stats
+ //
+
+ if ((--LinkCB->OutstandingFrames == 0) &&
+ (LinkCB->State == LINK_GOING_DOWN)) {
+
+ LinkCB->State = LINK_DOWN;
+
+ FreeLink = TRUE;
+
+ RemoveLinkFromBundle(BundleCB, LinkCB);
+
+ if (BundleCB->ulLinkCBCount == 0) {
+ BundleCB->State = BUNDLE_GOING_DOWN;
+ }
+ }
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ ASSERT((SHORT)PMINIPORT_RESERVED_FROM_NDIS(NdisPacket)->ReferenceCount > 0);
+
+ //
+ // See if the reference count is zero
+ //
+ if (--(PMINIPORT_RESERVED_FROM_NDIS(NdisPacket)->ReferenceCount)) {
+
+ //
+ // The reference count is not yet zero
+ //
+ return;
+ }
+
+ TryToCompleteNdisPacket(ProtocolCB->AdapterCB, NdisPacket);
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // If this bundle is going away but is waiting on all outstanding frames
+ // we need to do cleanup.
+ //
+ if (--BundleCB->OutstandingFrames == 0) {
+
+ //
+ // If this bundle is going away but unroute is waiting on
+ // all outstanding frames we need to signal the waiting thread.
+ //
+ if (BundleCB->Flags & FRAMES_PENDING) {
+
+ NdisWanSetSyncEvent(&BundleCB->OutstandingFramesEvent);
+
+ } else if ((BundleCB->State == BUNDLE_GOING_DOWN) &&
+ !(BundleCB->Flags & BUNDLE_ROUTED)){
+
+ BundleCB->State = BUNDLE_DOWN;
+ FreeBundle = TRUE;
+ }
+ }
+
+ //
+ // Called with bundle lock help but returns with lock released
+ //
+ SendPacketOnBundle(BundleCB);
+
+ if (FreeLink) {
+ //
+ // Remove this link from the connection table
+ //
+ RemoveLinkFromConnectionTable(LinkCB);
+ NdisWanReturnLinkCB(LinkCB);
+ }
+
+ if (FreeBundle) {
+ //
+ // Remove this bundle from the connection table
+ //
+ RemoveBundleFromConnectionTable(BundleCB);
+ NdisWanReturnBundleCB(BundleCB);
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("NdisWanSendComplete: Exit"));
+}
+
+VOID
+TryToCompleteNdisPacket(
+ PADAPTERCB AdapterCB,
+ PNDIS_PACKET NdisPacket
+ )
+{
+ //
+ // If this is a packet that we created we need to free the resources
+ //
+ if (PMINIPORT_RESERVED_FROM_NDIS(NdisPacket)->MagicNumber == NDISWAN_MAGIC_NUMBER) {
+
+ DestroyIoPacket(NdisPacket);
+
+ } else {
+ PDEFERRED_DESC DeferredDesc;
+
+ if ((AdapterCB->ulReferenceCount == 0) &&
+ NdisWanAcquireMiniportLock(AdapterCB)) {
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ if (IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[SendComplete])) {
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+#if DBG
+{
+ DBG_SEND_CONTEXT DbgContext;
+ DbgContext.Packet = NdisPacket;
+ DbgContext.PacketType = PACKET_TYPE_NDIS;
+ DbgContext.BundleCB = NULL;
+ DbgContext.ProtocolCB = NULL;
+ DbgContext.LinkCB = NULL;
+ DbgContext.ListHead = &AdapterCB->DbgNdisPacketList;
+ DbgContext.ListLock = &AdapterCB->Lock;
+ RemoveDbgPacket(&DbgContext);
+}
+#endif
+ //
+ // We got the lock and there are no pending send completes
+ // so go ahead and complete this one!
+ //
+ NdisMSendComplete(AdapterCB->hMiniportHandle,
+ NdisPacket,
+ NDIS_STATUS_SUCCESS);
+
+ //
+ // Increment global count
+ //
+ NdisWanInterlockedInc(&NdisWanCB.SendCompleteCount);
+
+ NdisWanReleaseMiniportLock(AdapterCB);
+
+ return;
+ }
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ NdisWanReleaseMiniportLock(AdapterCB);
+ }
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ NdisWanGetDeferredDesc(AdapterCB, &DeferredDesc);
+
+ DeferredDesc->Context = NdisPacket;
+
+ InsertTailDeferredQueue(&AdapterCB->DeferredQueue[SendComplete], DeferredDesc);
+
+ NdisWanSetDeferred(AdapterCB);
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+ }
+}
+
+VOID
+NdisWanProcessSendCompletes(
+ PADAPTERCB AdapterCB
+ )
+{
+
+ while (!IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[SendComplete])) {
+
+ PNDIS_PACKET NdisPacket;
+ PDEFERRED_DESC ReturnDesc;
+
+ ReturnDesc = RemoveHeadDeferredQueue(&AdapterCB->DeferredQueue[SendComplete]);
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ NdisPacket = ReturnDesc->Context;
+
+#if DBG
+{
+ DBG_SEND_CONTEXT DbgContext;
+ DbgContext.Packet = NdisPacket;
+ DbgContext.PacketType = PACKET_TYPE_NDIS;
+ DbgContext.BundleCB = NULL;
+ DbgContext.ProtocolCB = NULL;
+ DbgContext.LinkCB = NULL;
+ DbgContext.ListHead = &AdapterCB->DbgNdisPacketList;
+ DbgContext.ListLock = &AdapterCB->Lock;
+ RemoveDbgPacket(&DbgContext);
+}
+#endif
+ NdisMSendComplete(AdapterCB->hMiniportHandle,
+ NdisPacket,
+ NDIS_STATUS_SUCCESS);
+
+ //
+ // Increment global count
+ //
+ NdisWanInterlockedInc(&NdisWanCB.SendCompleteCount);
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ InsertHeadDeferredQueue(&AdapterCB->FreeDeferredQueue, ReturnDesc);
+ }
+}
+
+NDIS_STATUS
+SendPacketOnBundle(
+ PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+ Called with bundle lock held but returns with lock released!!!
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_PENDING;
+ ULONG ulProtocolSending, BytesSent;
+ PLIST_ENTRY ProtocolCBList;
+ PPROTOCOLCB IOProtocolCB;
+ PPROTOCOLCB ProtocolCB;
+ BOOLEAN DoMultilink = TRUE;
+ PLINKCB LinkCB;
+#ifdef BANDWIDTH_ON_DEMAND
+ ULONG ulFirstTime;
+#endif
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("SendPacketOnBundle: Enter"));
+
+ //
+ // Are we already involved in a send on this bundlecb?
+ //
+ if (BundleCB->Flags & IN_SEND) {
+
+ //
+ // If so flag that we should try back later
+ // and get the hell out.
+ //
+ BundleCB->Flags |= TRY_SEND_AGAIN;
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ return (NDIS_STATUS_PENDING);
+ }
+
+ BundleCB->Flags |= IN_SEND;
+
+ ProtocolCBList = &BundleCB->ProtocolCBList;
+ IOProtocolCB = (PPROTOCOLCB)ProtocolCBList->Flink;
+
+SendPacketOnBundleTryAgain:
+
+ //
+ // This contains a bit mask with a bit set for each possible send queue.
+ // To start off we will set all of the bits so each send queue will have
+ // a chance to send. If a send queue can send it just sets the bit in
+ // the mask so sends will continue to happen. If the send queue does not
+ // have anything to send the bit for that send queue is turned off. When
+ // all bits are turned off we will fall through the send loop.
+ //
+ ulProtocolSending = BundleCB->SendMask;
+
+#ifdef BANDWIDTH_ON_DEMAND
+ ulFirstTime = (ulProtocolSending & ~IOProtocolCB->SendMaskBit);
+#endif
+
+ if ((PVOID)(ProtocolCB = (PPROTOCOLCB)IOProtocolCB->Linkage.Flink) ==
+ (PVOID)ProtocolCBList) {
+ ProtocolCB = NULL;
+ }
+
+ //
+ // Stay in loop as long as we have protocols sending and endpoints
+ // accepting sends.
+ //
+
+ while (ulProtocolSending && (BundleCB->SendingLinks != 0)) {
+ PNDIS_PACKET NdisPacket;
+ PPROTOCOLCB SendingProtocolCB = NULL;
+ ULONG MagicNumber = 0;
+
+ //
+ // Always check to see if there is an I/O (PPP) packet to
+ // be sent!
+ //
+ if (!IsNdisPacketQueueEmpty(IOProtocolCB)) {
+ PWAN_IO_PROTOCOL_RESERVED pProtocolReserved;
+ PLINKCB LinkCB;
+
+ MagicNumber = NDISWAN_MAGIC_NUMBER;
+
+ NdisPacket = IOProtocolCB->HeadNdisPacketQueue;
+
+ pProtocolReserved = (PWAN_IO_PROTOCOL_RESERVED)NdisPacket->ProtocolReserved;
+
+ //
+ // Is this a directed PPP packet
+ //
+ if (((LinkCB = pProtocolReserved->LinkCB) == NULL) ||
+ (LinkCB->State != LINK_UP)) {
+
+ //
+ // The link has gone down since this send was
+ // queued so destroy the packet
+ //
+ RemoveHeadNdisPacketQueue(IOProtocolCB);
+ DestroyIoPacket(NdisPacket);
+ BundleCB->Flags |= TRY_SEND_AGAIN;
+ break;
+
+ }
+
+ if (!IsLinkSendWindowOpen(LinkCB)) {
+ //
+ // We can not send from the I/O queue because the send
+ // window for this link is closed. We will not send
+ // any data until the link has resources!
+ //
+ break;
+
+ }
+
+ BundleCB->NextLinkToXmit = LinkCB;
+ DoMultilink = FALSE;
+
+ //
+ // We are sending this packet so take it off of the list
+ //
+ RemoveHeadNdisPacketQueue(IOProtocolCB);
+
+ ulProtocolSending |= IOProtocolCB->SendMaskBit;
+
+ SendingProtocolCB = IOProtocolCB;
+
+ //
+ // End of I/O send check
+ //
+ } else {
+
+ ulProtocolSending &= ~IOProtocolCB->SendMaskBit;
+
+ //
+ // If there is not another protocol to check get out
+ //
+ if (ProtocolCB == NULL)
+ break;
+
+ if (!IsNdisPacketQueueEmpty(ProtocolCB)) {
+#ifdef BANDWIDTH_ON_DEMAND
+ BOOLEAN FirstPass;
+
+ FirstPass = (ulFirstTime != 0);
+
+ //
+ // Clear the first time bit. The entire mask will only be
+ // cleared when all of the protocols have had a chance to
+ // send at least once.
+ //
+ ulFirstTime &= ~ProtocolCB->SendMaskBit;
+
+ if (IsSampleTableFull(&ProtocolCB->SampleTable)) {
+
+ //
+ // We don't want this protocol to send again
+ // until its sampletable has an open entry so clear
+ // the protocols send bit.
+ //
+ ulProtocolSending &= ~ProtocolCB->SendMaskBit;
+ goto GetNextProtocolCB;
+ }
+
+ //
+ // We will send a packet from this protocol if it's bandwidth
+ // quota has not been met or if it's quota has been met we
+ // can still send if this is not the first time through the
+ // send loop (all other protocols have had a change to send).
+ //
+ if (IsProtocolQuotaFilled(ProtocolCB) && FirstPass) {
+
+ goto GetNextProtocolCB;
+ }
+#endif // end of BANDWIDTH_ON_DEMAND
+
+ ulProtocolSending |= ProtocolCB->SendMaskBit;
+
+ NdisPacket = RemoveHeadNdisPacketQueue(ProtocolCB);
+
+ SendingProtocolCB = ProtocolCB;
+
+ } else {
+
+ //
+ // Protocol does not have anything to send so mark it
+ // and get the next protocol.
+ //
+ ulProtocolSending &= ~ProtocolCB->SendMaskBit;
+
+#ifdef BANDWIDTH_ON_DEMAND
+ ulFirstTime &= ~ProtocolCB->SendMaskBit;
+#endif
+ goto GetNextProtocolCB;
+
+ }
+ }
+
+ ASSERT(NdisPacket != NULL);
+ ASSERT(SendingProtocolCB != NULL);
+
+ //
+ // We we get here we should have a valid NdisPacket with at least one link
+ // that is accepting sends
+ //
+
+ //
+ // The magic number is only set to a non-zero value if this is a send
+ // through our I/O interface.
+ //
+ PMINIPORT_RESERVED_FROM_NDIS(NdisPacket)->MagicNumber = MagicNumber;
+
+ //
+ // We will get the packet into a contiguous buffer, and do framing,
+ // compression and encryption. This is called with the bundle lock
+ // held and returns with it released.
+ //
+ Status = FrameAndSend(BundleCB,
+ SendingProtocolCB,
+ NdisPacket,
+ DoMultilink,
+ &BytesSent);
+
+#ifdef BANDWIDTH_ON_DEMAND
+ //
+ // Update this protocols sample array with the latest send.
+ //
+ UpdateProtocolQuota(SendingProtocolCB, BytesSent);
+
+ //
+ // Update the bandwidth on demand sample array with the latest send.
+ // If we need to notify someone of a bandwidth event do it.
+ //
+ UpdateBandwidthOnDemand(BundleCB, BytesSent);
+#endif
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // This will force round-robin sends if no protocol
+ // prioritization has been set.
+ //
+#ifdef BANDWIDTH_ON_DEMAND
+
+ if (!(BundleCB->Flags & PROTOCOL_PRIORITY) &&
+ (ProtocolCB != NULL)) {
+
+#else // end of BANDWIDTH_ON_DEMAND
+
+ if (ProtocolCB != NULL) {
+
+#endif // end of !BANDWIDTH_ON_DEMAND
+
+GetNextProtocolCB:
+
+ if ((PVOID)(ProtocolCB = (PPROTOCOLCB)ProtocolCB->Linkage.Flink) ==
+ (PVOID)ProtocolCBList) {
+ ProtocolCB = (PPROTOCOLCB)IOProtocolCB->Linkage.Flink;
+ }
+ }
+
+ } // end of the send while loop
+
+ //
+ // Did someone try to do a send while we were already
+ // sending on this bundle?
+ //
+ if (BundleCB->Flags & TRY_SEND_AGAIN) {
+
+ //
+ // If so clear the flag and try another send.
+ //
+ BundleCB->Flags &= ~TRY_SEND_AGAIN;
+ goto SendPacketOnBundleTryAgain;
+ }
+
+ //
+ // Clear the in send flag.
+ //
+ BundleCB->Flags &= ~IN_SEND;
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("SendPacketOnBundle: Exit"));
+
+ return (Status);
+}
+
+NDIS_STATUS
+FrameAndSend(
+ PBUNDLECB BundleCB,
+ PPROTOCOLCB ProtocolCB,
+ PNDIS_PACKET NdisPacket,
+ BOOLEAN DoMultilink,
+ PULONG BytesSent
+ )
+/*++
+
+Routine Name:
+
+ FrameAndSend
+
+Routine Description:
+
+ This routine does all of the data manipulation required to take the
+ NdisPacket and make it into the appropriate number of WanPackets. These
+ WanPackets will be queued on a list on their linkcbs. The manipulation
+ that occurs includes getting the data from the ndispacket into a contiguous
+ buffer, protocol header compression, data compression, data encryption,
+ PPP framing, multilink fragmentation and framing.
+
+ Called with bundle lock held but returns with lock released!!!
+
+ A finished frame will look like
+
+ PPPHeader
+ ProtocolHeader
+ Data
+
+Arguments:
+
+ BundleCB - Pointer to the BundleCB that we are sending over
+ ProtocolCB - Pointer to the ProtocolCB that this send is for
+ NdisPacket - Pointer to the NdisPacket that is being sent
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ ULONG BytesCopied, PacketDataOffset;
+ ULONG FragmentsLeft, FragmentsSent, DataLeft;
+ PWAN_STATS BundleStats = &BundleCB->BundleStats;
+ USHORT PPPProtocolID = ProtocolCB->usPPPProtocolID;
+
+ //
+ // Framing information flags
+ //
+ ULONG BundleFraming = BundleCB->FramingInfo.SendFramingBits;
+ ULONG LinkFraming;
+
+ //
+ // This is the next link to be transmitted over
+ //
+ PLINKCB LinkCB;
+
+ //
+ // These are pointers to the active WanPacket and
+ // data buffer.
+ //
+ // WanPacket points to the active WanPacket
+ // StartBuffer points to the begining of the frame
+ // DataBuffer points to where the data begins in the frame
+ // FrameLength is the length of the frame
+ // DataLength is the length of the data
+ //
+ PNDIS_WAN_PACKET WanPacket;
+ PUCHAR StartBuffer, CurrentBuffer, DataBuffer;
+ ULONG DataLength = 0;
+
+ //
+ // These are points to the second WanPacket and
+ // data buffer. These are used to compress into
+ // if compression is on.
+ //
+ // WanPacket2 points to the WanPacket used if compression occurs
+ // PacketNotUsed points to the WanPacket that is to be returned
+ // StartBuffer2 points to the begining of the data buffer in WanPacket2
+ //
+ PNDIS_WAN_PACKET WanPacket2, PacketNotUsed;
+ PUCHAR StartBuffer2, CurrentBuffer2, DataBuffer2;
+
+ //
+ // Flags set to make decisions on whether to compress and/or encrypt the data
+ //
+ ULONG Flags;
+
+ BOOLEAN FirstFragment = TRUE;
+
+ //
+ // Used to gather information about the link header
+ //
+ HEADER_FRAMING_INFO FramingInfo1, FramingInfo2;
+ PHEADER_FRAMING_INFO FramingInfo = &FramingInfo1;
+
+ ULONG ProtocolHeaderLength;
+ UCHAR ProtocolBuffer[40];
+ PUCHAR ProtocolHeader = ProtocolBuffer;
+
+ ULONG EthernetHeaderLength;
+#ifdef EXTRA_COPY
+ PUCHAR EthernetHeader;
+#else
+ UCHAR EthernetHeader[12];
+#endif
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("FrameAndSend: Enter"));
+
+ //
+ // Clear out the bytes sent count
+ //
+ *BytesSent = 0;
+
+ //
+ // Get the next link to xmit on.
+ //
+ LinkCB = GetNextLinkToXmitOn(BundleCB);
+
+ ASSERT(LinkCB != NULL);
+
+ ASSERT(IsLinkSendWindowOpen(LinkCB));
+
+ //
+ // Set flags for compression, encryption and multilink
+ //
+ Flags = ((BundleCB->SendCompInfo.MSCompType & NDISWAN_COMPRESSION) &&
+ (BundleCB->SendCompressContext != NULL)) ? DO_COMPRESSION : 0;
+
+ if (BundleCB->SendRC4Key != NULL) {
+ if (BundleCB->SendCompInfo.MSCompType & NDISWAN_ENCRYPTION) {
+ Flags |= (DO_ENCRYPTION | DO_LEGACY_ENCRYPTION);
+ } else if (BundleCB->SendCompInfo.MSCompType & NDISWAN_40_ENCRYPTION) {
+ Flags |= (DO_ENCRYPTION | DO_40_ENCRYPTION);
+ }
+#ifdef ENCRYPT_128BIT
+ else if (BundleCB->SendCompInfo.MSCompType & NDISWAN_128_ENCRYPTION) {
+ Flags |= (DO_ENCRYPTION | DO_128_ENCRYPTION);
+ }
+#endif
+ }
+
+ Flags |= (DoMultilink && (BundleFraming & PPP_FRAMING) &&
+ (BundleFraming & PPP_MULTILINK_FRAMING)) ? DO_MULTILINK : 0;
+
+ if (PPPProtocolID == PPP_PROTOCOL_PRIVATE_IO) {
+ Flags |= IO_PROTOCOLID;
+ Flags &= ~(DO_COMPRESSION | DO_ENCRYPTION);
+ }
+
+ Flags |= FIRST_FRAGMENT;
+
+ //
+ // Did the last receive cause us to flush?
+ //
+ if (BundleCB->Flags & RECV_PACKET_FLUSH) {
+ BundleCB->Flags &= ~RECV_PACKET_FLUSH;
+ Flags |= DO_FLUSH;
+ }
+
+ FramingInfo->FramingBits =
+ LinkFraming = LinkCB->LinkInfo.SendFramingBits;
+ FramingInfo->Flags = Flags;
+
+ //
+ // Bump the outstanding frames on the bundle
+ //
+ BundleCB->OutstandingFrames++;
+
+ //
+ // If we are in promiscuous mode we should indicate this
+ // baby back up.
+ //
+ if (NdisWanCB.PromiscuousAdapter != NULL) {
+ NdisWanQueueLoopbackPacket(NdisWanCB.PromiscuousAdapter, NdisPacket);
+ }
+
+ //
+ // See if we are in pass through mode
+ //
+ if (!(BundleFraming & PASS_THROUGH_MODE) &&
+ !(BundleFraming & RAW_PASS_THROUGH_MODE)) {
+
+ //
+ // Get two wanpackets from the next to send link.
+ //
+ WanPacket = GetWanPacketFromLink(LinkCB);
+ PacketNotUsed =
+ WanPacket2 = GetWanPacketFromLink(LinkCB);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ //
+ // This is where we will build the frame. This needs to be
+ // on a 8 byte boundary.
+ //
+ StartBuffer = WanPacket->StartBuffer +
+ LinkCB->LinkInfo.HeaderPadding +
+ sizeof(PVOID);
+
+ (ULONG)StartBuffer &= (ULONG)~(sizeof(PVOID) - 1);
+
+ //
+ // This is where we will build the frame. This needs to be
+ // on a 8 byte boundary.
+ //
+ StartBuffer2 = WanPacket2->StartBuffer +
+ LinkCB->LinkInfo.HeaderPadding +
+ sizeof(PVOID);
+
+ (ULONG)StartBuffer2 &= (ULONG)~(sizeof(PVOID) - 1);
+
+ BuildLinkHeader(FramingInfo, StartBuffer);
+
+ FramingInfo2.FramingBits = FramingInfo->FramingBits;
+ FramingInfo2.Flags = FramingInfo->Flags;
+
+ BuildLinkHeader(&FramingInfo2, StartBuffer2);
+
+ DataBuffer =
+ CurrentBuffer = StartBuffer + FramingInfo->HeaderLength;
+
+ DataBuffer2 =
+ CurrentBuffer2 = StartBuffer2 + FramingInfo->HeaderLength;
+
+ //
+ // If this is a netbios frame and we have to ship the mac header
+ //
+ if ((BundleFraming & NBF_PRESERVE_MAC_ADDRESS) &&
+ (PPPProtocolID == PPP_PROTOCOL_NBF)) {
+
+#ifdef EXTRA_COPY
+
+ EthernetHeader = CurrentBuffer;
+
+#endif
+
+ //
+ // Copy Ethernet header to temp buffer
+ //
+ NdisWanCopyFromPacketToBuffer(NdisPacket,
+ 0,
+ 12,
+ EthernetHeader,
+ &BytesCopied);
+ ASSERT(BytesCopied == 12);
+
+ CurrentBuffer += BytesCopied;
+ DataLength += BytesCopied;
+
+ EthernetHeaderLength = BytesCopied;
+ }
+
+ //
+ // We are beyond the mac header (also skip the length/protocoltype field)
+ //
+ if (PPPProtocolID == PPP_PROTOCOL_PRIVATE_IO) {
+ PacketDataOffset = 12;
+ } else {
+ PacketDataOffset = 14;
+ }
+
+ //
+ // Do protocol header compression - IP only!
+ //
+ if ((PPPProtocolID == PPP_PROTOCOL_IP) &&
+ (BundleCB->VJCompress != NULL) &&
+ ((BundleFraming & SLIP_VJ_COMPRESSION) || (BundleFraming & PPP_FRAMING))) {
+ UCHAR CompType = TYPE_IP;
+
+ BundleStats->BytesTransmittedUncompressed += 40;
+
+ //
+ // Get the protocol header
+ //
+ NdisWanCopyFromPacketToBuffer(NdisPacket,
+ PacketDataOffset,
+ 40,
+ ProtocolHeader,
+ &ProtocolHeaderLength);
+
+
+ PacketDataOffset += ProtocolHeaderLength;
+
+ NdisWanDbgOut(DBG_INFO, DBG_SEND_VJ,
+ ("svj %d", ProtocolHeaderLength));
+
+ //
+ // Are we compressing TCP/IP headers? There is a nasty
+ // hack in VJs implementation for attempting to detect
+ // interactive TCP/IP sessions. That is, telnet, login,
+ // klogin, eklogin, and ftp sessions. If detected,
+ // the traffic gets put on a higher TypeOfService (TOS). We do
+ // no such hack for RAS. Also, connection ID compression
+ // is negotiated, but we always don't compress it.
+ //
+ CompType = sl_compress_tcp(&ProtocolHeader,
+ &ProtocolHeaderLength,
+ BundleCB->VJCompress,
+ 0);
+
+
+ if (BundleFraming & SLIP_VJ_COMPRESSION) {
+
+ //
+ // For SLIP, the upper bits of the first byte
+ // are for VJ header compression control bits
+ //
+ ProtocolHeader[0] |= CompType;
+ }
+
+
+#ifdef EXTRA_COPY
+
+ NdisMoveMemory(CurrentBuffer, ProtocolHeader, ProtocolHeaderLength);
+
+ CurrentBuffer += ProtocolHeaderLength;
+ DataLength += ProtocolHeaderLength;
+#else
+
+#endif
+ NdisWanDbgOut(DBG_INFO, DBG_SEND_VJ,
+ ("svj %2.2x %d",CompType, ProtocolHeaderLength));
+
+ BundleStats->BytesTransmittedCompressed += ProtocolHeaderLength;
+
+
+ switch (CompType) {
+ case TYPE_IP:
+ PPPProtocolID = PPP_PROTOCOL_IP;
+ break;
+
+ case TYPE_UNCOMPRESSED_TCP:
+ PPPProtocolID = PPP_PROTOCOL_UNCOMPRESSED_TCP;
+ break;
+
+ case TYPE_COMPRESSED_TCP:
+ PPPProtocolID = PPP_PROTOCOL_COMPRESSED_TCP;
+ break;
+
+ default:
+ DbgBreakPoint();
+ break;
+ }
+
+ }
+
+#ifdef EXTRA_COPY
+ //
+ // Copy the rest of the data from the ndis packet to
+ // a contiguous buffer
+ //
+ NdisWanCopyFromPacketToBuffer(NdisPacket,
+ PacketDataOffset,
+ 0xFFFFFFFF,
+ CurrentBuffer,
+ &BytesCopied);
+
+ DataLength += BytesCopied;
+#endif
+
+ //
+ // Add the PPP Protocol ID to the PPP header
+ //
+ AddPPPProtocolID(FramingInfo, PPPProtocolID);
+
+ //
+ // At this point we have our framinginfo structure created
+ // StartBuffer points to the begining of the frame, DataBuffer
+ // points to the place where the data starts in the frame,
+ // DataLength is the length of the data in the frame.
+ //
+
+ //
+ // If compression and/or encryption is on and this is not a PPP CP frame do
+ // data compression.
+ //
+ if (Flags & (DO_COMPRESSION | DO_ENCRYPTION)) {
+ union {
+ USHORT uShort;
+ UCHAR uChar[2];
+ }CoherencyCounter;
+
+ //
+ // If we are compressing/encrypting, the ProtocolID
+ // is part of the compressed data so fix the pointer
+ // and the length;
+ //
+ DataBuffer -= FramingInfo->ProtocolID.Length;
+ DataBuffer2 -= FramingInfo->ProtocolID.Length;
+
+ DataLength += FramingInfo->ProtocolID.Length;
+ FramingInfo->HeaderLength -= FramingInfo->ProtocolID.Length;
+
+ //
+ // Get the coherency counter
+ //
+ CoherencyCounter.uShort = BundleCB->SCoherencyCounter;
+ CoherencyCounter.uChar[1] &= 0x0F;
+
+ //
+ // Bump the coherency count
+ //
+ BundleCB->SCoherencyCounter++;
+
+ if (Flags & DO_COMPRESSION) {
+
+ BundleStats->BytesTransmittedUncompressed += DataLength;
+
+ if (Flags & DO_FLUSH) {
+ //
+ // Init the compression history table and tree
+ //
+ initsendcontext(BundleCB->SendCompressContext);
+ }
+
+#ifdef EXTRA_COPY
+
+ //
+ // We are doing the copy to get things into a contiguous buffer before
+ // compression occurs
+ //
+ CoherencyCounter.uChar[1] |= compress(DataBuffer,
+ DataBuffer2,
+ &DataLength,
+ BundleCB->SendCompressContext);
+
+#else
+
+ //
+ // Compression will occur on fragments. We are not doing a copy
+ // to get things into a contiguous buffer before compressing
+ //
+
+ //
+ // If we need to include the ethernet header, compress it
+ //
+
+ //
+ // If we have a compressed protocol header, compress it again
+ //
+
+ //
+ // Now we need to walk the NdisBuffer chain compressing each
+ // buffer as we go. We need to get to the buffer where our
+ // current DataOffset is. Once we get to this buffer we will
+ // compress what is left of the buffer. We then go into a loop
+ // that walks the rest of the buffers in the buffer chain.
+ //
+#endif
+
+ if (CoherencyCounter.uChar[1] & PACKET_FLUSHED) {
+
+ //
+ // If encryption is enabled this will force a
+ // reinit of the table
+ //
+ Flags |= DO_FLUSH;
+
+ } else {
+ //
+ // We compressed the packet so now the active WanPacket will be
+ // WanPacket2. We need to copy the PPP header from WanPacket to
+ // WanPacket2. The header includes everything except for the
+ // protocolid field.
+ //
+
+ NdisMoveMemory(StartBuffer2,
+ StartBuffer,
+ FramingInfo->HeaderLength - FramingInfo->ProtocolID.Length);
+
+ //
+ // Now WanPacket2 and all of it's relevant pointers
+ // and structures are active.
+ //
+ PacketNotUsed = WanPacket;
+ WanPacket = WanPacket2;
+ DataBuffer = DataBuffer2;
+ StartBuffer = StartBuffer2;
+ FramingInfo = &FramingInfo2;
+ FramingInfo->HeaderLength -= FramingInfo->ProtocolID.Length;
+ }
+
+ BundleStats->BytesTransmittedCompressed += DataLength;
+ }
+
+ //
+ // Do data encryption
+ //
+ if (Flags & DO_ENCRYPTION) {
+ PUCHAR SessionKey = BundleCB->SendEncryptInfo.SessionKey;
+ ULONG SessionKeyLength = BundleCB->SendEncryptInfo.SessionKeyLength;
+ PVOID SendRC4Key = BundleCB->SendRC4Key;
+
+ //
+ // We may need to reinit the rc4 table
+ //
+ if (Flags & DO_FLUSH) {
+ rc4_key(SendRC4Key, SessionKeyLength, SessionKey);
+ }
+
+ //
+ // Mark this as being encrypted
+ //
+ CoherencyCounter.uChar[1] |= PACKET_ENCRYPTED;
+
+ //
+ // Every 256 frames change the RC4 session key
+ //
+ if ((BundleCB->SCoherencyCounter & 0xFF) == 0) {
+
+ if (Flags & DO_LEGACY_ENCRYPTION) {
+ //
+ // Simple munge for legacy encryption
+ //
+ SessionKey[3] += 1;
+ SessionKey[4] += 3;
+ SessionKey[5] += 13;
+ SessionKey[6] += 57;
+ SessionKey[7] += 19;
+
+ } else {
+
+ //
+ // Use SHA to get new sessionkey
+ //
+ GetNewKeyFromSHA(&BundleCB->SendEncryptInfo);
+
+ }
+
+ //
+ // We use rc4 to scramble and recover a new key
+ //
+
+ //
+ // Re-initialize the rc4 receive table to the
+ // intermediate value
+ //
+ rc4_key(SendRC4Key, SessionKeyLength, SessionKey);
+
+ //
+ // Scramble the existing session key
+ //
+ rc4(SendRC4Key, SessionKeyLength, SessionKey);
+
+ //
+ // If this is 40 bit encryption we need to fix
+ // the first 3 bytes of the key.
+ //
+#ifdef ENCRYPT_128BIT
+ if (!(Flags & DO_128_ENCRYPTION)) {
+
+#endif
+ //
+ // Re-Salt the first 3 bytes
+ //
+ SessionKey[0] = 0xD1;
+ SessionKey[1] = 0x26;
+ SessionKey[2] = 0x9E;
+
+#ifdef ENCRYPT_128BIT
+ }
+
+#endif
+ NdisWanDbgOut(DBG_TRACE, DBG_CCP,
+ ("RC4 Send encryption KeyLength %d", BundleCB->SendEncryptInfo.SessionKeyLength));
+ NdisWanDbgOut(DBG_TRACE, DBG_CCP,
+ ("RC4 Send encryption Key %.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
+ BundleCB->SendEncryptInfo.SessionKey[0],
+ BundleCB->SendEncryptInfo.SessionKey[1],
+ BundleCB->SendEncryptInfo.SessionKey[2],
+ BundleCB->SendEncryptInfo.SessionKey[3],
+ BundleCB->SendEncryptInfo.SessionKey[4],
+ BundleCB->SendEncryptInfo.SessionKey[5],
+ BundleCB->SendEncryptInfo.SessionKey[6],
+ BundleCB->SendEncryptInfo.SessionKey[7],
+ BundleCB->SendEncryptInfo.SessionKey[8],
+ BundleCB->SendEncryptInfo.SessionKey[9],
+ BundleCB->SendEncryptInfo.SessionKey[10],
+ BundleCB->SendEncryptInfo.SessionKey[11],
+ BundleCB->SendEncryptInfo.SessionKey[12],
+ BundleCB->SendEncryptInfo.SessionKey[13],
+ BundleCB->SendEncryptInfo.SessionKey[14],
+ BundleCB->SendEncryptInfo.SessionKey[15]));
+
+ //
+ // Re-initialize the rc4 receive table to the
+ // scrambled session key
+ //
+ rc4_key(SendRC4Key, SessionKeyLength, SessionKey);
+
+ }
+
+ //
+ // Encrypt the data
+ //
+ rc4(SendRC4Key, DataLength, DataBuffer);
+
+ }
+
+
+ //
+ // Did the last receive cause us to flush?
+ //
+ if (Flags & DO_FLUSH) {
+ CoherencyCounter.uChar[1] |= PACKET_FLUSHED;
+ }
+
+ //
+ // Add the coherency bytes to the frame
+ //
+ AddCompressionInfo(FramingInfo, CoherencyCounter.uShort);
+
+ ASSERT(((CoherencyCounter.uShort + 1) & 0x0FFF) ==
+ (BundleCB->SCoherencyCounter & 0x0FFF));
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // Return the unused wanpacket to the pool
+ //
+ ReturnWanPacketToLink(LinkCB, PacketNotUsed);
+
+ //
+ // At this point we have our framinginfo structure initialized,
+ // StartBuffer pointing to the begining of the frame, DataBuffer
+ // pointing to the begining of the data, DataLength is the
+ // length of the data.
+ //
+ FragmentsLeft = BundleCB->SendingLinks;
+ DataLeft = DataLength;
+ FragmentsSent = 0;
+ FirstFragment = TRUE;
+
+ //
+ // For all fragments we loop fixing up the multilink header
+ // if multilink is on, fixing up pointers in the wanpacket,
+ // and queuing the wanpackets for further processing.
+ //
+ while (DataLeft) {
+ ULONG FragDataLength;
+ ULONG LinkBandwidth;
+
+ if (!FirstFragment) {
+
+ //
+ // We had more than one fragment, get the next
+ // link to send over and a wanpacket from the
+ // link.
+ //
+
+ LinkCB = GetNextLinkToXmitOn(BundleCB);
+
+ ASSERT(IsLinkSendWindowOpen(LinkCB));
+
+ WanPacket = GetWanPacketFromLink(LinkCB);
+
+ //
+ // This is where we will build the frame. This needs to be
+ // on a 8 byte boundary.
+ //
+ StartBuffer = WanPacket->StartBuffer +
+ LinkCB->LinkInfo.HeaderPadding +
+ sizeof(PVOID);
+
+ (ULONG)StartBuffer &= (ULONG)~(sizeof(PVOID) - 1);
+
+ //
+ // Get new framing information and build a new
+ // header for the new link.
+ //
+ FramingInfo->FramingBits =
+ LinkFraming = LinkCB->LinkInfo.SendFramingBits;
+
+ FramingInfo->Flags = (DoMultilink) ? DO_MULTILINK : 0;
+
+ BuildLinkHeader(FramingInfo, StartBuffer);
+ }
+
+ LinkBandwidth = LinkCB->ulBandwidth;
+
+ if ((Flags & DO_MULTILINK) && (FragmentsLeft > 1) &&
+ (LinkBandwidth < 85)) {
+
+ //
+ // Calculate the length of this fragment
+ //
+ FragDataLength = (DataLength * LinkBandwidth / 100);
+
+ FragDataLength = (FragDataLength < NdisWanCB.ulMinFragmentSize) ?
+ NdisWanCB.ulMinFragmentSize : FragDataLength;
+
+ if ((FragDataLength > DataLeft) ||
+ ((LONG)DataLeft - FragDataLength < NdisWanCB.ulMinFragmentSize)) {
+ //
+ // This will leave a fragment of less than min frag size
+ // so send all of the data
+ //
+ FragDataLength = DataLeft;
+ FragmentsLeft = 1;
+ }
+
+
+ } else {
+ //
+ // We either have one fragment left or this link has
+ // more than 85 percent of the bundle so send what
+ // data is left
+ //
+ FragDataLength = DataLeft;
+ FragmentsLeft = 1;
+ }
+
+ if (!FirstFragment) {
+ //
+ // Copy the data to the new buffer from the old buffer.
+ //
+ NdisMoveMemory(StartBuffer + FramingInfo->HeaderLength,
+ DataBuffer,
+ FragDataLength);
+
+ }
+
+ //
+ // Update the data pointer and the length left to send
+ //
+ DataBuffer += FragDataLength;
+ DataLeft -= FragDataLength;
+
+ if (Flags & DO_MULTILINK) {
+ UCHAR MultilinkFlags = 0;
+
+
+ //
+ // Multlink is on so create flags for this
+ // fragment.
+ //
+ if (FirstFragment) {
+ MultilinkFlags = MULTILINK_BEGIN_FRAME;
+ FirstFragment = FALSE;
+ }
+
+ if (FragmentsLeft == 1) {
+ MultilinkFlags |= MULTILINK_END_FRAME;
+ }
+
+ //
+ // Add the multilink header information and
+ // take care of the sequence number.
+ //
+ AddMultilinkInfo(FramingInfo,
+ MultilinkFlags,
+ BundleCB->SendSeqNumber,
+ BundleCB->SendSeqMask);
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_SEND, ("sf %8.8x %8.8x %d",
+ BundleCB->SendSeqNumber, MultilinkFlags, FragDataLength));
+
+ BundleCB->SendSeqNumber++;
+
+ }
+
+ //
+ // Initialize the WanPacket
+ //
+ WanPacket->CurrentBuffer = StartBuffer;
+ WanPacket->CurrentLength = FragDataLength + FramingInfo->HeaderLength;
+
+ WanPacket->ProtocolReserved1 = (PVOID)LinkCB;
+ WanPacket->ProtocolReserved2 = (PVOID)NdisPacket;
+ WanPacket->ProtocolReserved3 = (PVOID)ProtocolCB;
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_SEND,
+ ("l %8.8x %8.8x", LinkCB->hLinkHandle));
+ //
+ // Add up the bytes that we are sending over all
+ // links in this bundle.
+ //
+ *BytesSent += WanPacket->CurrentLength;
+
+ //
+ // Queue for further processing.
+ //
+ InsertTailList(&BundleCB->SendPacketQueue, &WanPacket->WanPacketQueue);
+
+ FragmentsSent++;
+ FragmentsLeft--;
+
+ } // end of the fragment loop
+
+ ASSERT(FragmentsLeft == 0);
+
+ //
+ // Get the mac reserved structure from the ndispacket. This
+ // is where we will keep the reference count on the packet.
+ //
+ ASSERT((LONG)FragmentsSent > 0 && FragmentsSent <= BundleCB->ulLinkCBCount);
+ PMINIPORT_RESERVED_FROM_NDIS(NdisPacket)->ReferenceCount = (USHORT)FragmentsSent;
+
+ BundleCB->BundleStats.FramesTransmitted++;
+
+ //
+ // At this point we have a list of wanpackets that need to be sent,
+ // update the total bytes associated with this send, and send
+ // the packets over their links.
+ //
+ while (!IsListEmpty(&BundleCB->SendPacketQueue)) {
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Get the wanpacket off of the list
+ //
+ WanPacket = (PNDIS_WAN_PACKET)RemoveHeadList(&BundleCB->SendPacketQueue);
+
+ //
+ // Get the link to send over
+ //
+ LinkCB = WanPacket->ProtocolReserved1;
+
+ //
+ // Update the outstanding frames on the link
+ //
+ LinkCB->LinkStats.FramesTransmitted++;
+ LinkCB->LinkStats.BytesTransmitted += WanPacket->CurrentLength;
+ BundleCB->BundleStats.BytesTransmitted += WanPacket->CurrentLength;
+
+#if DBG
+ {
+ DBG_SEND_CONTEXT DbgContext;
+ DbgContext.Packet = WanPacket;
+ DbgContext.PacketType = PACKET_TYPE_WAN;
+ DbgContext.BundleCB = BundleCB;
+ DbgContext.ProtocolCB = ProtocolCB;
+ DbgContext.LinkCB = LinkCB;
+ DbgContext.ListHead = &LinkCB->WanAdapterCB->DbgWanPacketList;
+ DbgContext.ListLock = &LinkCB->WanAdapterCB->Lock;
+
+ InsertDbgPacket(&DbgContext);
+ }
+#endif
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ //
+ // If the link is up send the packet
+ //
+ if (LinkCB->State == LINK_UP) {
+
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("FrameAndSend: LinkCB: 0x%8.8x, WanPacket: 0x%8.8x", LinkCB, WanPacket));
+
+ WanMiniportSend(&Status,
+ LinkCB->WanAdapterCB->hNdisBindingHandle,
+ LinkCB->LineUpInfo.NdisLinkHandle,
+ WanPacket);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("FrameAndSend: Status: 0x%8.8x", Status));
+ }
+
+ //
+ // If we get something other than pending back we need to
+ // do the send complete.
+ //
+ if (Status != NDIS_STATUS_PENDING) {
+
+ NdisWanSendCompleteHandler(NULL,
+ WanPacket,
+ NDIS_STATUS_SUCCESS);
+
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+ }
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ } else {
+ //
+ // We need to get a WanPacket
+ //
+ WanPacket = GetWanPacketFromLink(LinkCB);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ //
+ // Copy the data into the WanPacket
+ //
+ //
+ // This is where we will build the frame. This needs to be
+ // on a 8 byte boundary.
+ //
+ StartBuffer = WanPacket->StartBuffer +
+ LinkCB->LinkInfo.HeaderPadding +
+ sizeof(PVOID);
+
+ (ULONG)StartBuffer &= (ULONG)~(sizeof(PVOID) - 1);
+
+ NdisWanCopyFromPacketToBuffer(NdisPacket,
+ 0,
+ 0xFFFFFFFF,
+ StartBuffer,
+ &BytesCopied);
+
+ //
+ // If we are in pass through mode set the protocol type
+ //
+ if (BundleFraming & PASS_THROUGH_MODE) {
+ StartBuffer[12] = (UCHAR)(ProtocolCB->usProtocolType << 8);
+ StartBuffer[13] = (UCHAR)ProtocolCB->usProtocolType;
+ }
+
+ WanPacket->CurrentBuffer = StartBuffer;
+ WanPacket->CurrentLength = BytesCopied;
+ WanPacket->ProtocolReserved1 = (PVOID)LinkCB;
+ WanPacket->ProtocolReserved2 = (PVOID)NdisPacket;
+ WanPacket->ProtocolReserved3 = (PVOID)ProtocolCB;
+
+ if (LinkCB->State == LINK_UP) {
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("FrameAndSend: LinkCB: 0x%8.8x, WanPacket: 0x%8.8x", LinkCB, WanPacket));
+
+ WanMiniportSend(&Status,
+ LinkCB->WanAdapterCB->hNdisBindingHandle,
+ LinkCB->LineUpInfo.NdisLinkHandle,
+ WanPacket);
+ }
+
+ //
+ // If we get something other than pending back we need to
+ // do the send complete.
+ //
+ if (Status != NDIS_STATUS_PENDING) {
+
+ NdisWanSendCompleteHandler(NULL,
+ WanPacket,
+ NDIS_STATUS_SUCCESS);
+
+ Status = NDIS_STATUS_PENDING;
+ }
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("FrameAndSend: Exit"));
+
+ return (Status);
+}
+
+#ifdef BANDWIDTH_ON_DEMAND
+
+BOOLEAN
+IsProtocolQuotaFilled(
+ PPROTOCOLCB ProtocolCB
+ )
+/*++
+
+Routine Name:
+
+ IsProtocolQuotaFilled
+
+Routine Description:
+
+ This routine checks to see if the protocol has filled it's
+ bandwidth quota.
+
+Arguments:
+
+ ProtocolCB - Pointer to the protocolcb that is sending.
+
+Return Values:
+
+ TRUE Quota filled
+ FALSE Quota not filled
+
+--*/
+{
+ BOOLEAN QuotaMet = FALSE;
+ PSAMPLE_TABLE SampleTable = &ProtocolCB->SampleTable;
+ PSEND_SAMPLE FirstSample, CurrentSample;
+
+ AgeSampleTable(SampleTable);
+ if (ProtocolCB->ulByteQuota < SampleTable->ulCurrentSampleByteCount) {
+ QuotaMet = TRUE;
+ }
+
+ return (QuotaMet);
+}
+
+VOID
+AgeSampleTable(
+ PSAMPLE_TABLE SampleTable
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ WAN_TIME CurrentTime, TimeDiff;
+ ULONG FirstIndex = SampleTable->ulFirstIndex;
+ ULONG CurrentIndex = SampleTable->ulCurrentIndex;
+ PSEND_SAMPLE FirstSample = &SampleTable->SampleArray[FirstIndex];
+
+ //
+ // Should return CurrentTime in 100ns units
+ //
+ NdisWanGetSystemTime(&CurrentTime);
+
+ //
+ // We will search through the sample indexing over samples that are more than
+ // one second older than the current time.
+ //
+ NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &FirstSample->TimeStamp);
+
+ while ( !NdisWanIsTimeDiffLess(&TimeDiff, &SampleTable->SamplePeriod) &&
+ (FirstIndex != CurrentIndex) ) {
+
+ SampleTable->ulCurrentSampleByteCount -= FirstSample->ulBytesThisSend;
+
+ ASSERT((LONG)SampleTable->ulCurrentSampleByteCount >= 0);
+
+ FirstSample->ulReferenceCount = 0;
+
+ if (++FirstIndex == SampleTable->ulSampleArraySize) {
+ FirstIndex = 0;
+ }
+
+ SampleTable->ulFirstIndex = FirstIndex ;
+
+ FirstSample = &SampleTable->SampleArray[FirstIndex];
+
+ NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &FirstSample->TimeStamp);
+ }
+
+}
+
+BOOLEAN
+IsSampleTableFull(
+ PSAMPLE_TABLE SampleTable
+ )
+{
+ LONG Diff;
+
+// AgeSampleTable(SampleTable);
+ Diff = (LONG)(SampleTable->ulCurrentIndex - SampleTable->ulFirstIndex);
+ return((Diff == (LONG)(SampleTable->ulSampleArraySize - 1)) || (Diff == -1));
+}
+
+VOID
+UpdateSampleTable(
+ PSAMPLE_TABLE SampleTable,
+ ULONG BytesSent
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ WAN_TIME CurrentTime, TimeDiff;
+ ULONG CurrentIndex = SampleTable->ulCurrentIndex;
+ PSEND_SAMPLE CurrentSample = &SampleTable->SampleArray[CurrentIndex];
+
+ NdisWanGetSystemTime(&CurrentTime);
+
+ NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &CurrentSample->TimeStamp);
+
+ if ( NdisWanIsTimeDiffLess(&TimeDiff, &SampleTable->SampleRate) ||
+ IsSampleTableFull(SampleTable)) {
+ //
+ // Add this send on the previous sample
+ //
+ CurrentSample->ulBytesThisSend += BytesSent;
+ CurrentSample->ulReferenceCount++;
+ } else {
+ //
+ // We need a new sample
+ //
+ if (++CurrentIndex == SampleTable->ulSampleArraySize) {
+ CurrentIndex = 0;
+ }
+
+ SampleTable->ulCurrentIndex = CurrentIndex;
+ CurrentSample = &SampleTable->SampleArray[CurrentIndex];
+ CurrentSample->TimeStamp = CurrentTime;
+ CurrentSample->ulBytesThisSend = BytesSent;
+ CurrentSample->ulReferenceCount = 1;
+ }
+
+ SampleTable->ulCurrentSampleByteCount += BytesSent;
+
+}
+
+VOID
+UpdateBandwidthOnDemand(
+ PBUNDLECB BundleCB,
+ ULONG BytesSent
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ULONG EventCount;
+ PSAMPLE_TABLE UpperSampleTable = &BundleCB->UpperBonDInfo.SampleTable;
+ PSAMPLE_TABLE LowerSampleTable = &BundleCB->LowerBonDInfo.SampleTable;
+
+ //
+ // Age and update the sample table
+ //
+ AgeSampleTable(UpperSampleTable);
+ UpdateSampleTable(UpperSampleTable, BytesSent);
+ AgeSampleTable(LowerSampleTable);
+ UpdateSampleTable(LowerSampleTable, BytesSent);
+
+ GetGlobalListCount(ThresholdEventQueue, EventCount);
+
+ if (EventCount != 0) {
+
+ CheckUpperThreshold(BundleCB);
+ CheckLowerThreshold(BundleCB);
+
+ }
+
+}
+
+VOID
+CheckUpperThreshold(
+ PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ WAN_TIME CurrentTime, TimeDiff;
+ PBOND_INFO BonDInfo = &BundleCB->UpperBonDInfo;
+ PSAMPLE_TABLE SampleTable = &BonDInfo->SampleTable;
+ ULONG Bps = SampleTable->ulCurrentSampleByteCount;
+ //
+ // Switch on the current state
+ //
+ switch (BonDInfo->State) {
+ case BonDIdle:
+ //
+ // We are currently below the upper threshold. If we
+ // go over the upperthreshold we will set the time and
+ // transition to the monitor state.
+ //
+ if (Bps >= BonDInfo->ulBytesThreshold) {
+ NdisWanGetSystemTime(&BonDInfo->StartTime);
+ BonDInfo->State = BonDMonitor;
+ }
+ break;
+
+ case BonDMonitor:
+
+ //
+ // We are currently in the monitor state which means that
+ // we have gone above the upper threshold. If we fall below
+ // the upper threshold we will go back to the idle state.
+ //
+ if (Bps < BonDInfo->ulBytesThreshold) {
+ BonDInfo->State = BonDIdle;
+
+ } else {
+
+ NdisWanGetSystemTime(&CurrentTime);
+
+ NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &BonDInfo->StartTime);
+
+ if (!NdisWanIsTimeDiffLess(&TimeDiff, &SampleTable->SamplePeriod)) {
+ //
+ // We have been above the threshold for time greater than the
+ // threshold sample period so we need to notify someone of this
+ // historic event!
+ //
+ CompleteThresholdEvent(BundleCB, UPPER_THRESHOLD);
+
+ //
+ // I'm not sure what state we should be in now!
+ //
+ BonDInfo->State = BonDSignaled;
+ }
+ }
+ break;
+
+ case BonDSignaled:
+ break;
+
+ }
+}
+
+VOID
+CheckLowerThreshold(
+ PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ WAN_TIME CurrentTime, TimeDiff;
+ PBOND_INFO BonDInfo = &BundleCB->LowerBonDInfo;
+ PSAMPLE_TABLE SampleTable = &BonDInfo->SampleTable;
+ ULONG Bps = SampleTable->ulCurrentSampleByteCount;
+
+ //
+ // Switch on the current state
+ //
+ switch (BonDInfo->State) {
+ case BonDIdle:
+ //
+ // We are currently above the lower threshold. If we
+ // go below the lowerthreshold we will set the time and
+ // transition to the monitor state.
+ //
+ if (Bps <= BonDInfo->ulBytesThreshold) {
+ NdisWanGetSystemTime(&BonDInfo->StartTime);
+ BonDInfo->State = BonDMonitor;
+ }
+ break;
+
+ case BonDMonitor:
+
+ //
+ // We are currently in the monitor state which means that
+ // we have gone below the lower threshold. If we rise above
+ // the lower threshold we will go back to the idle state.
+ //
+ if (Bps > BonDInfo->ulBytesThreshold) {
+ BonDInfo->State = BonDIdle;
+
+ } else {
+
+ NdisWanGetSystemTime(&CurrentTime);
+
+ NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &BonDInfo->StartTime);
+
+ if (!NdisWanIsTimeDiffLess(&TimeDiff, &SampleTable->SamplePeriod)) {
+ //
+ // We have been below the lower threshold for time greater than the
+ // threshold sample period so we need to notify someone of this
+ // historic event!
+ //
+ CompleteThresholdEvent(BundleCB, LOWER_THRESHOLD);
+
+ //
+ // I'm not sure what state we should be in now!
+ //
+ BonDInfo->State = BonDSignaled;
+ }
+ }
+ break;
+
+ case BonDSignaled:
+ break;
+
+ }
+}
+
+#endif // end of BANDWIDTH_ON_DEMAND
+
+PLINKCB
+GetNextLinkToXmitOn(
+ PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PLINKCB LinkCB = BundleCB->NextLinkToXmit;
+ PLIST_ENTRY LinkCBList = &BundleCB->LinkCBList;
+
+ //
+ // We need to find the first link that has an open send window
+ //
+ while (LinkCB->ulWanPacketCount < 2) {
+ LinkCB = (PLINKCB)LinkCB->Linkage.Flink;
+
+ if ((PVOID)LinkCB == (PVOID)LinkCBList) {
+ LinkCB = (PLINKCB)LinkCBList->Flink;
+ }
+ }
+
+ BundleCB->NextLinkToXmit =
+ ((PVOID)LinkCB->Linkage.Flink == (PVOID)LinkCBList) ?
+ (PLINKCB)LinkCBList->Flink : (PLINKCB)LinkCB->Linkage.Flink;
+
+ LinkCB->OutstandingFrames++;
+
+ return(LinkCB);
+}
+
+NDIS_STATUS
+BuildIoPacket(
+ IN PNDISWAN_IO_PACKET pWanIoPacket,
+ IN BOOLEAN SendImmediate
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_RESOURCES;
+ PWAN_IO_PROTOCOL_RESERVED pProtocolReserved;
+ PPROTOCOLCB ProtocolCB;
+ ULONG Stage = 0, ulAllocationSize = 0;
+ PUCHAR pAllocatedMemory = NULL, pSrcAddr, pDestAddr;
+ NDIS_HANDLE hPacketPool, hBufferPool, hBundle, hLink;
+ PNDIS_PACKET pNdisPacket;
+ PNDIS_BUFFER pNdisBuffer;
+ PBUNDLECB BundleCB;
+ PLINKCB LinkCB = NULL;
+ UCHAR SendHeader[] = {' ', 'S', 'E', 'N', 'D', 0xFF};
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("BuildIoPacket: Enter!"));
+ //
+ // Some time in the future this should be redone so that
+ // there is a pool of packets and buffers attached to a
+ // BundleCB. This pool could be grown and shrunk as needed
+ // but some minimum number would live for the lifetime of
+ // the BundleCB.
+
+ if (pWanIoPacket->usHandleType == LINKHANDLE) {
+
+ hLink = pWanIoPacket->hHandle;
+ LINKCB_FROM_LINKH(LinkCB, hLink);
+
+ if (LinkCB == NULL) {
+ return (NDIS_STATUS_SUCCESS);
+ }
+
+ BundleCB = LinkCB->BundleCB;
+
+ if (BundleCB == NULL) {
+ return (NDIS_STATUS_SUCCESS);
+ }
+
+ } else {
+ hBundle = pWanIoPacket->hHandle;
+ BUNDLECB_FROM_BUNDLEH(BundleCB, hBundle);
+
+ if (BundleCB == NULL) {
+ return (NDIS_STATUS_SUCCESS);
+ }
+
+ LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
+
+ if (LinkCB == NULL) {
+ return (NDIS_STATUS_SUCCESS);
+ }
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ if ((LinkCB->State != LINK_UP) ||
+ (BundleCB->State != BUNDLE_UP)) {
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ return (NDIS_STATUS_SUCCESS);
+ }
+
+ //
+ // We only support ethernet headers right now so the supplied header
+ // either has to be ethernet or none at all!
+ //
+
+ //
+ //
+ // Get an NdisPacket for this send
+ //
+ NdisAllocatePacketPool(&Status,
+ &hPacketPool,
+ 1,
+ sizeof(WAN_IO_PROTOCOL_RESERVED));
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_SEND, ("BuildIoPacket: Error Allocating PacketPool!"));
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ goto RESOURCE_ERROR;
+ }
+
+ Stage++;
+
+ NdisAllocatePacket(&Status,
+ &pNdisPacket,
+ hPacketPool);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_SEND, ("BuildIoPacket: Error Allocating Packet!"));
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ goto RESOURCE_ERROR;
+ }
+
+ Stage++;
+
+ //
+ // Get an NdisBuffer for this send
+ //
+ NdisAllocateBufferPool(&Status,
+ &hBufferPool,
+ 2);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_SEND, ("BuildIoPacket: Error Allocating BufferPool!"));
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ goto RESOURCE_ERROR;
+ }
+
+ Stage++;
+
+ if (pWanIoPacket->usHeaderSize == 0) {
+ ulAllocationSize = 12;
+ }
+
+ ulAllocationSize += pWanIoPacket->usPacketSize;
+
+ NdisWanAllocateMemory(&pAllocatedMemory, ulAllocationSize);
+
+ if (pAllocatedMemory == NULL) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_SEND, ("BuildIoPacket: Error Allocating Memory! Size: %d", ulAllocationSize));
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ goto RESOURCE_ERROR;
+ }
+
+ Stage++;
+
+ NdisAllocateBuffer(&Status,
+ &pNdisBuffer,
+ hBufferPool,
+ pAllocatedMemory,
+ ulAllocationSize);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_SEND, ("BuildIoPacket: Error Allocating Buffer!"));
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ goto RESOURCE_ERROR;
+ }
+
+ Stage++;
+
+ pProtocolReserved = (PWAN_IO_PROTOCOL_RESERVED)pNdisPacket->ProtocolReserved;
+ pProtocolReserved->LinkCB = LinkCB;
+ pProtocolReserved->hPacketPool = hPacketPool;
+ pProtocolReserved->pNdisPacket = pNdisPacket;
+ pProtocolReserved->hBufferPool = hBufferPool;
+ pProtocolReserved->pNdisBuffer = pNdisBuffer;
+ pProtocolReserved->pAllocatedMemory = pAllocatedMemory;
+ pProtocolReserved->ulAllocationSize = ulAllocationSize;
+
+ pDestAddr = &pAllocatedMemory[0];
+ pSrcAddr = &pAllocatedMemory[6];
+
+ //
+ // If no header build a header
+ //
+ if (pWanIoPacket->usHeaderSize == 0) {
+
+ //
+ // Header will look like " S XXYYYY" where
+ // XX is the ProtocolCB index and YYYY is the
+ // BundleCB index. Both the Src and Dst addresses
+ // look the same.
+ //
+ NdisMoveMemory(pDestAddr,
+ SendHeader,
+ sizeof(SendHeader));
+
+ NdisMoveMemory(pSrcAddr,
+ SendHeader,
+ sizeof(SendHeader));
+
+ } else {
+ //
+ // Header supplied so go ahead and move it.
+ //
+ NdisMoveMemory(pDestAddr,
+ pWanIoPacket->PacketData,
+ pWanIoPacket->usHeaderSize);
+ }
+
+ //
+ // Fill the BundleCB Index for the Src and Dest Address
+ //
+ FillNdisWanProtocolIndex(pDestAddr, hLink);
+ FillNdisWanProtocolIndex(pSrcAddr, hLink);
+
+ //
+ // Copy the data to the buffer
+ //
+ NdisMoveMemory(&pAllocatedMemory[12],
+ &pWanIoPacket->PacketData[pWanIoPacket->usHeaderSize],
+ pWanIoPacket->usPacketSize);
+
+ //
+ // Chain buffer to ndis packet
+ //
+ NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
+
+ //
+ // Queue the packet on the bundlecb
+ //
+ ProtocolCB = BundleCB->ProtocolCBTable[0];
+
+ ASSERT(ProtocolCB != NULL);
+
+ if (SendImmediate) {
+ InsertHeadNdisPacketQueue(ProtocolCB, pNdisPacket);
+ } else {
+ InsertTailNdisPacketQueue(ProtocolCB, pNdisPacket);
+ }
+
+ //
+ // Try to send
+ //
+ // Called with lock held and returns with
+ // lock released
+ //
+ Status = SendPacketOnBundle(BundleCB);
+
+ //
+ // We don't pend I/O packets so complete
+ // as if it succeeded
+ //
+ if (Status == NDIS_STATUS_PENDING) {
+ Status = NDIS_STATUS_SUCCESS;
+ }
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+RESOURCE_ERROR:
+
+ //
+ // Free all of the allocated resources
+ //
+ switch (Stage) {
+ case 5:
+ NdisFreeBuffer(pNdisBuffer);
+
+ case 4:
+ NdisWanFreeMemory(pAllocatedMemory);
+
+ case 3:
+ NdisFreeBufferPool(hBufferPool);
+
+ case 2:
+ NdisFreePacket(pNdisPacket);
+
+ case 1:
+ NdisFreePacketPool(hPacketPool);
+
+ }
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("BuildIoPacket: Exit-Status: 0x%8.8x\n", Status));
+
+ return (Status);
+}
+
+//ULONG
+//GetNumSendingLinks(
+// PBUNDLECB BundleCB
+// )
+///*++
+//
+//Routine Name:
+//
+//Routine Description:
+//
+//Arguments:
+//
+//Return Values:
+//
+//--*/
+//{
+// ULONG LinkCount = 0;
+// PLINKCB LinkCB;
+//
+// //
+// // We need to walk through the list of links on this bundle and
+// // count how many have an open send window.
+// //
+// for (LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
+// (PVOID)LinkCB != (PVOID)&BundleCB->LinkCBList;
+// LinkCB = (PLINKCB)LinkCB->Linkage.Flink) {
+//
+// //
+// // Since we create enough sendwindow + 1 wanpackets
+// // for each link, if the send window is open we will
+// // have atleast 2 wanpackets available.
+// //
+// if (LinkCB->ulWanPacketCount > 1) {
+// LinkCount++;
+// }
+// }
+//
+// return (LinkCount);
+//}
+
+VOID
+BuildLinkHeader(
+ PHEADER_FRAMING_INFO FramingInfo,
+ PUCHAR StartBuffer
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ULONG LinkFraming = FramingInfo->FramingBits;
+ ULONG Flags = FramingInfo->Flags;
+ PUCHAR CurrentPointer = StartBuffer;
+
+ FramingInfo->HeaderLength =
+ FramingInfo->AddressControl.Length =
+ FramingInfo->Multilink.Length =
+ FramingInfo->Compression.Length =
+ FramingInfo->ProtocolID.Length = 0;
+
+ if (LinkFraming & PPP_FRAMING) {
+
+ if (!(LinkFraming & PPP_COMPRESS_ADDRESS_CONTROL)) {
+ //
+ // If there is no address/control compression
+ // we need a pointer and a length
+ //
+ FramingInfo->AddressControl.Pointer = CurrentPointer;
+ *CurrentPointer++ = 0xFF;
+ *CurrentPointer++ = 0x03;
+ FramingInfo->AddressControl.Length = 2;
+ FramingInfo->HeaderLength += FramingInfo->AddressControl.Length;
+
+ }
+
+ if (!(Flags & IO_PROTOCOLID)) {
+
+ //
+ // If this is not from our private I/O interface we will
+ // build the rest of the header.
+ //
+ if ((Flags & DO_MULTILINK) && (LinkFraming & PPP_MULTILINK_FRAMING)) {
+
+ //
+ // We are doing multilink so we need a pointer
+ // and a length
+ //
+ FramingInfo->Multilink.Pointer = CurrentPointer;
+
+ if (!(LinkFraming & PPP_COMPRESS_PROTOCOL_FIELD)) {
+ //
+ // No protocol compression
+ //
+ *CurrentPointer++ = 0x00;
+ FramingInfo->Multilink.Length++;
+ }
+
+ *CurrentPointer++ = 0x3D;
+ FramingInfo->Multilink.Length++;
+
+ if (!(LinkFraming & PPP_SHORT_SEQUENCE_HDR_FORMAT)) {
+ //
+ // We are using long sequence number
+ //
+ FramingInfo->Multilink.Length += 2;
+ CurrentPointer += 2;
+
+ }
+
+ FramingInfo->Multilink.Length += 2;
+ CurrentPointer += 2;
+
+ FramingInfo->HeaderLength += FramingInfo->Multilink.Length;
+
+ }
+
+ if (Flags & (DO_COMPRESSION | DO_ENCRYPTION)) {
+ //
+ // We are doing compression/encryption so we need
+ // a pointer and a length
+ //
+ FramingInfo->Compression.Pointer = CurrentPointer;
+
+ //
+ // It appears that legacy ras (< NT 4.0) requires that
+ // the PPP protocol field in a compressed packet not
+ // be compressed, ie has to have the leading 0x00
+ //
+ if (!(LinkFraming & PPP_COMPRESS_PROTOCOL_FIELD)) {
+ //
+ // No protocol compression
+ //
+ *CurrentPointer++ = 0x00;
+ FramingInfo->Compression.Length++;
+ }
+
+ *CurrentPointer++ = 0xFD;
+ FramingInfo->Compression.Length++;
+
+ //
+ // Add coherency bytes
+ //
+ FramingInfo->Compression.Length += 2;
+ CurrentPointer += 2;
+
+ FramingInfo->HeaderLength += FramingInfo->Compression.Length;
+ }
+
+ if (Flags & FIRST_FRAGMENT) {
+
+ FramingInfo->ProtocolID.Pointer = CurrentPointer;
+
+ if (!(LinkFraming & PPP_COMPRESS_PROTOCOL_FIELD) ||
+ (Flags & (DO_COMPRESSION | DO_ENCRYPTION))) {
+ FramingInfo->ProtocolID.Length++;
+ CurrentPointer++;
+ }
+
+ FramingInfo->ProtocolID.Length++;
+ FramingInfo->HeaderLength += FramingInfo->ProtocolID.Length;
+
+ }
+ }
+
+ } else if ((LinkFraming & RAS_FRAMING)) {
+ //
+ // If this is old ras framing:
+ //
+ // Alter the framing so that 0xFF 0x03 is not added
+ // and that the first byte is 0xFD not 0x00 0xFD
+ //
+ // So basically, a RAS compression looks like
+ // <0xFD> <2 BYTE COHERENCY> <NBF DATA FIELD>
+ //
+ // Whereas uncompressed looks like
+ // <NBF DATA FIELD> which always starts with 0xF0
+ //
+ // If this is ppp framing:
+ //
+ // A compressed frame will look like (before address/control
+ // - multilink is added)
+ // <0x00> <0xFD> <2 Byte Coherency> <Compressed Data>
+ //
+ if (Flags & (DO_COMPRESSION | DO_ENCRYPTION)) {
+ FramingInfo->Compression.Pointer = CurrentPointer;
+
+ *CurrentPointer++ = 0xFD;
+ FramingInfo->Compression.Length++;
+
+ //
+ // Coherency bytes
+ //
+ FramingInfo->Compression.Length += 2;
+ CurrentPointer += 2;
+
+ FramingInfo->HeaderLength += FramingInfo->Compression.Length;
+ }
+ }
+}
+
+VOID
+NdisWanCopyFromPacketToBuffer(
+ IN PNDIS_PACKET pNdisPacket,
+ IN ULONG Offset,
+ IN ULONG BytesToCopy,
+ OUT PUCHAR Buffer,
+ OUT PULONG BytesCopied
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ULONG NdisBufferCount;
+ PNDIS_BUFFER CurrentBuffer;
+ PVOID VirtualAddress;
+ ULONG CurrentLength, AmountToMove;
+ ULONG LocalBytesCopied = 0;
+
+ *BytesCopied = 0;
+
+ //
+ // Take care of zero byte copy
+ //
+ if (!BytesToCopy) {
+ return;
+ }
+
+ //
+ // Get the buffer count
+ //
+ NdisQueryPacket(pNdisPacket,
+ NULL,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ NULL);
+
+ //
+ // Could be a null packet
+ //
+ if (!NdisBufferCount) {
+ return;
+ }
+
+
+ NdisQueryBuffer(CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength);
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ //
+ // No more bytes left in this buffer
+ //
+ if (!CurrentLength) {
+
+ //
+ // Get the next buffer
+ //
+ NdisGetNextBuffer(CurrentBuffer,
+ &CurrentBuffer);
+
+ //
+ // End of the packet, copy what we can
+ //
+ if (CurrentBuffer == NULL) {
+ break;
+ }
+
+ //
+ //
+ //
+ NdisQueryBuffer(CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength);
+
+ continue;
+ }
+
+ //
+ // Get to the point where we can start copying
+ //
+ if (Offset) {
+
+ if (Offset > CurrentLength) {
+
+ //
+ // Not in this buffer, go to the next one
+ //
+ Offset -= CurrentLength;
+ CurrentLength = 0;
+ continue;
+
+ } else {
+
+ //
+ // At least some in this buffer
+ //
+ VirtualAddress = (PUCHAR)VirtualAddress + Offset;
+ CurrentLength -= Offset;
+ Offset = 0;
+ }
+
+ }
+
+ //
+ // We can copy some data. If we need more data than is available
+ // in this buffer we can copy what we need and go back for more.
+ //
+ AmountToMove = (CurrentLength > (BytesToCopy - LocalBytesCopied)) ?
+ (BytesToCopy - LocalBytesCopied) : CurrentLength;
+
+ NdisMoveMemory(Buffer, VirtualAddress, AmountToMove);
+
+ Buffer = (PUCHAR)Buffer + AmountToMove;
+
+ VirtualAddress = (PUCHAR)VirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+
+ CurrentLength -= AmountToMove;
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+}
+
+PNDIS_WAN_PACKET
+GetWanPacketFromLink(
+ PLINKCB LinkCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PNDIS_WAN_PACKET WanPacket;
+ ULONG PrevCount = LinkCB->ulWanPacketCount;
+
+ ASSERT(LinkCB->ulWanPacketCount);
+
+ //
+ // If the current count is greater than threshold and the
+ // new count falls below we need to decrement the sending
+ // link count.
+ //
+ if ((--LinkCB->ulWanPacketCount < 2) && (PrevCount > 1)) {
+ ((PBUNDLECB)LinkCB->BundleCB)->SendingLinks--;
+ }
+
+ WanPacket = (PNDIS_WAN_PACKET)RemoveHeadList(&LinkCB->WanPacketPool);
+
+ return (WanPacket);
+}
+
+VOID
+ReturnWanPacketToLink(
+ PLINKCB LinkCB,
+ PNDIS_WAN_PACKET WanPacket
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ULONG PrevCount = LinkCB->ulWanPacketCount;
+
+ //
+ // If the current count is below the threshold and the
+ // new count puts us over we need to increment the sending
+ // link count.
+ //
+ if ((++LinkCB->ulWanPacketCount > 1) && (PrevCount < 2)) {
+ ((PBUNDLECB)LinkCB->BundleCB)->SendingLinks++;
+ }
+
+ InsertTailList(&LinkCB->WanPacketPool, &WanPacket->WanPacketQueue);
+}
+
+VOID
+DestroyIoPacket(
+ PNDIS_PACKET NdisPacket
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PWAN_IO_PROTOCOL_RESERVED ProtocolReserved =
+ (PWAN_IO_PROTOCOL_RESERVED)NdisPacket->ProtocolReserved;
+
+ NDIS_HANDLE PacketPool = ProtocolReserved->hPacketPool;
+
+ NdisWanFreeMemory(ProtocolReserved->pAllocatedMemory);
+ NdisFreeBuffer(ProtocolReserved->pNdisBuffer);
+ NdisFreeBufferPool(ProtocolReserved->hBufferPool);
+ NdisFreePacket(NdisPacket);
+ NdisFreePacketPool(PacketPool);
+}
+
+#if DBG
+VOID
+InsertDbgPacket(
+ PDBG_SEND_CONTEXT DbgContext
+ )
+{
+ PDBG_SEND_PACKET DbgPacket;
+ PBUNDLECB BundleCB = DbgContext->BundleCB;
+ PPROTOCOLCB ProtocolCB = DbgContext->ProtocolCB;
+ PLINKCB LinkCB = DbgContext->LinkCB;
+
+ NdisWanAllocateMemory(&DbgPacket, sizeof(DBG_SEND_PACKET));
+
+ if (DbgPacket == NULL) {
+ return;
+ }
+
+ DbgPacket->Packet = DbgContext->Packet;
+ DbgPacket->PacketType = DbgContext->PacketType;
+ DbgPacket->BundleCB = BundleCB;
+ if (BundleCB) {
+ DbgPacket->BundleState = BundleCB->State;
+ DbgPacket->BundleFlags = BundleCB->Flags;
+ }
+
+ DbgPacket->ProtocolCB = ProtocolCB;
+ if (ProtocolCB) {
+ DbgPacket->ProtocolFlags = ProtocolCB->Flags;
+ }
+
+ DbgPacket->LinkCB = LinkCB;
+ if (LinkCB) {
+ DbgPacket->LinkState = LinkCB->State;
+ }
+
+ NdisAcquireSpinLock(DbgContext->ListLock);
+ InsertTailList(DbgContext->ListHead, &DbgPacket->Linkage);
+ NdisReleaseSpinLock(DbgContext->ListLock);
+}
+
+BOOLEAN
+RemoveDbgPacket(
+ PDBG_SEND_CONTEXT DbgContext
+ )
+{
+ PDBG_SEND_PACKET DbgPacket = NULL;
+ BOOLEAN Found = FALSE;
+
+ NdisAcquireSpinLock(DbgContext->ListLock);
+
+ if (!IsListEmpty(DbgContext->ListHead)) {
+ for (DbgPacket = (PDBG_SEND_PACKET)DbgContext->ListHead->Flink;
+ (PVOID)DbgPacket != (PVOID)DbgContext->ListHead;
+ DbgPacket = (PDBG_SEND_PACKET)DbgPacket->Linkage.Flink) {
+
+ if (DbgPacket->Packet == DbgContext->Packet) {
+ RemoveEntryList(&DbgPacket->Linkage);
+ NdisWanFreeMemory(DbgPacket);
+ Found = TRUE;
+ break;
+ }
+
+ }
+ }
+
+ ASSERT(Found == TRUE);
+
+ NdisReleaseSpinLock(DbgContext->ListLock);
+
+ return (Found);
+}
+
+#endif