/*++ Copyright (c) 1989-1993 Microsoft Corporation Module Name: mac.c Abstract: This module contains code which implements Mac type dependent code for the IPX transport. Environment: Kernel mode (Actually, unimportant) Revision History: Sanjay Anand (SanjayAn) - 22-Sept-1995 BackFill optimization changes added under #if BACK_FILL --*/ #include "precomp.h" #pragma hdrstop #define TR_LENGTH_MASK 0x1F // low 5 bits in byte #define TR_DIRECTION_MASK 0x80 // returns direction bit #define TR_DEFAULT_LENGTH 0x70 // default for outgoing #define TR_MAX_SIZE_MASK 0x70 #define TR_PREAMBLE_AC 0x10 #define TR_PREAMBLE_FC 0x40 #define FDDI_HEADER_BYTE 0x57 static UCHAR AllRouteSourceRouting[2] = { 0x82, TR_DEFAULT_LENGTH }; static UCHAR SingleRouteSourceRouting[2] = { 0xc2, TR_DEFAULT_LENGTH }; #define ROUTE_EQUAL(_A,_B) { \ (*(UNALIGNED USHORT *)(_A) == *(UNALIGNED USHORT *)(_B)) \ } // // For back-fillable packets, chains the back-fill space as a MAC header // to the packet and sets the header pointer. // // // We dont need to test for IDENTIFIER_IPX since it will always be // true for the mediumframe specific send handlers. // #define BACK_FILL_HEADER(_header, _reserved, _headerlength, _packet) \ if ((_reserved)->Identifier == IDENTIFIER_IPX) { \ if((_reserved)->BackFill) { \ CTEAssert ((_reserved)->HeaderBuffer); \ CTEAssert ((_reserved)->HeaderBuffer->MdlFlags & MDL_NETWORK_HEADER); \ _header = (PCHAR)(_reserved)->HeaderBuffer->MappedSystemVa - (_headerlength); \ (_reserved)->HeaderBuffer->MappedSystemVa = (PCHAR)(_reserved)->HeaderBuffer->MappedSystemVa - (_headerlength); \ (_reserved)->HeaderBuffer->ByteOffset -= (_headerlength); \ ASSERT((LONG)(_reserved)->HeaderBuffer->ByteOffset >= 0); \ NdisChainBufferAtFront(_packet,(PNDIS_BUFFER)(_reserved)->HeaderBuffer); \ } \ } // // In case of back-fillable packets, the adjusted length should include // the prev. bytecount of the headerbuffer. // #define BACK_FILL_ADJUST_BUFFER_LENGTH(_reserved, _headerlength) \ if((_reserved)->BackFill){ \ NdisAdjustBufferLength ((_reserved)->HeaderBuffer, _headerlength+(_reserved)->HeaderBuffer->ByteCount); \ IPX_DEBUG(SEND,("mac user mdl %x\n", (_reserved)->HeaderBuffer)); \ } else { \ NdisAdjustBufferLength ((_reserved)->HeaderBuffer, _headerlength); \ } // // This is the interpretation of the length bits in // the 802.5 source-routing information. // ULONG SR802_5Lengths[8] = { 516, 1500, 2052, 4472, 8144, 11407, 17800, 17800 }; VOID MacInitializeBindingInfo( IN struct _BINDING * Binding, IN struct _ADAPTER * Adapter ) /*++ Routine Description: Fills in the binding info based on the adapter's MacInfo and the frame type of the binding. Arguments: Binding - The newly created binding. Adapter - The adapter. Return Value: None. --*/ { ULONG MaxUserData; Binding->DefHeaderSize = Adapter->DefHeaderSizes[Binding->FrameType]; Binding->BcMcHeaderSize = Adapter->BcMcHeaderSizes[Binding->FrameType]; MacReturnMaxDataSize( &Adapter->MacInfo, NULL, 0, Binding->MaxSendPacketSize, &MaxUserData); Binding->MaxLookaheadData = Adapter->MaxReceivePacketSize - sizeof(IPX_HEADER) - (Binding->DefHeaderSize - Adapter->MacInfo.MinHeaderLength); Binding->AnnouncedMaxDatagramSize = MaxUserData - sizeof(IPX_HEADER) - (Binding->DefHeaderSize - Adapter->MacInfo.MinHeaderLength); Binding->RealMaxDatagramSize = Binding->MaxSendPacketSize - Adapter->MacInfo.MaxHeaderLength - sizeof(IPX_HEADER) - (Binding->DefHeaderSize - Adapter->MacInfo.MinHeaderLength); } /* MacInitializeBindingInfo */ VOID MacInitializeMacInfo( IN NDIS_MEDIUM MacType, OUT PNDIS_INFORMATION MacInfo ) /*++ Routine Description: Fills in the MacInfo table based on MacType. Arguments: MacType - The MAC type we wish to decode. MacInfo - The MacInfo structure to fill in. Return Value: None. --*/ { switch (MacType) { case NdisMedium802_3: MacInfo->SourceRouting = FALSE; MacInfo->MediumAsync = FALSE; MacInfo->BroadcastMask = 0x01; MacInfo->MaxHeaderLength = 14; MacInfo->MinHeaderLength = 14; MacInfo->MediumType = NdisMedium802_3; break; case NdisMedium802_5: MacInfo->SourceRouting = TRUE; MacInfo->MediumAsync = FALSE; MacInfo->BroadcastMask = 0x80; MacInfo->MaxHeaderLength = 32; MacInfo->MinHeaderLength = 14; MacInfo->MediumType = NdisMedium802_5; break; case NdisMediumFddi: MacInfo->SourceRouting = FALSE; MacInfo->MediumAsync = FALSE; MacInfo->BroadcastMask = 0x01; MacInfo->MaxHeaderLength = 13; MacInfo->MinHeaderLength = 13; MacInfo->MediumType = NdisMediumFddi; break; case NdisMediumArcnet878_2: MacInfo->SourceRouting = FALSE; MacInfo->MediumAsync = FALSE; MacInfo->BroadcastMask = 0x00; MacInfo->MaxHeaderLength = 3; MacInfo->MinHeaderLength = 3; MacInfo->MediumType = NdisMediumArcnet878_2; break; case NdisMediumWan: MacInfo->SourceRouting = FALSE; MacInfo->MediumAsync = TRUE; MacInfo->BroadcastMask = 0x01; MacInfo->MaxHeaderLength = 14; MacInfo->MinHeaderLength = 14; MacInfo->MediumType = NdisMedium802_3; break; default: CTEAssert(FALSE); } MacInfo->RealMediumType = MacType; } /* MacInitializeMacInfo */ VOID MacMapFrameType( IN NDIS_MEDIUM MacType, IN ULONG FrameType, OUT ULONG * MappedFrameType ) /*++ Routine Description: Maps the specified frame type to a value which is valid for the medium. Arguments: MacType - The MAC type we wish to map for. FrameType - The frame type in question. MappedFrameType - Returns the mapped frame type. Return Value: --*/ { switch (MacType) { // // Ethernet accepts all values, the default is 802.2. // case NdisMedium802_3: if (FrameType >= ISN_FRAME_TYPE_MAX) { *MappedFrameType = ISN_FRAME_TYPE_802_2; } else { *MappedFrameType = FrameType; } break; // // Token-ring supports SNAP and 802.2 only. // case NdisMedium802_5: if (FrameType == ISN_FRAME_TYPE_SNAP) { *MappedFrameType = ISN_FRAME_TYPE_SNAP; } else { *MappedFrameType = ISN_FRAME_TYPE_802_2; } break; // // FDDI supports SNAP, 802.2, and 802.3 only. // case NdisMediumFddi: if ((FrameType == ISN_FRAME_TYPE_SNAP) || (FrameType == ISN_FRAME_TYPE_802_3)) { *MappedFrameType = FrameType; } else { *MappedFrameType = ISN_FRAME_TYPE_802_2; } break; // // On arcnet there is only one frame type, use 802.3 // (it doesn't matter what we use). // case NdisMediumArcnet878_2: *MappedFrameType = ISN_FRAME_TYPE_802_3; break; // // WAN uses ethernet II because it includes the ethertype. // case NdisMediumWan: *MappedFrameType = ISN_FRAME_TYPE_ETHERNET_II; break; default: CTEAssert(FALSE); } } /* MacMapFrameType */ // // use symbols instead of hardcoded values for mac header lengths // --pradeepb // VOID MacReturnMaxDataSize( IN PNDIS_INFORMATION MacInfo, IN PUCHAR SourceRouting, IN UINT SourceRoutingLength, IN UINT DeviceMaxFrameSize, OUT PUINT MaxFrameSize ) /*++ Routine Description: This routine returns the space available for user data in a MAC packet. This will be the available space after the MAC header; all headers headers will be included in this space. Arguments: MacInfo - Describes the MAC we wish to decode. SourceRouting - If we are concerned about a reply to a specific frame, then this information is used. SourceRouting - The length of SourceRouting. MaxFrameSize - The maximum frame size as returned by the adapter. MaxDataSize - The maximum data size computed. Return Value: None. --*/ { switch (MacInfo->MediumType) { case NdisMedium802_3: // // For 802.3, we always have a 14-byte MAC header. // *MaxFrameSize = DeviceMaxFrameSize - 14; break; case NdisMedium802_5: // // For 802.5, if we have source routing information then // use that, otherwise assume the worst. // if (SourceRouting && SourceRoutingLength >= 2) { UINT SRLength; SRLength = SR802_5Lengths[(SourceRouting[1] & TR_MAX_SIZE_MASK) >> 4]; DeviceMaxFrameSize -= (SourceRoutingLength + 14); if (DeviceMaxFrameSize < SRLength) { *MaxFrameSize = DeviceMaxFrameSize; } else { *MaxFrameSize = SRLength; } } else { #if 0 if (DeviceMaxFrameSize < 608) { *MaxFrameSize = DeviceMaxFrameSize - 32; } else { *MaxFrameSize = 576; } #endif // // bug # 6192. There is no point in assuming the worst. It only // leads to lower throughput. Packets can get dropped by an // an intermediate router for both cases (this one and the one // above where 576 is chosen). In the above case, they will // get dropped if two ethernet machines are communicating via // a token ring. In this case, they will if two token ring // machines with a frame size > max ethernet frame size are // going over an ethernet. To fix the packet drop case, one // should adjust the MaxPktSize Parameter of the card. // *MaxFrameSize = DeviceMaxFrameSize - 32; } break; case NdisMediumFddi: // // For FDDI, we always have a 13-byte MAC header. // *MaxFrameSize = DeviceMaxFrameSize - 13; break; case NdisMediumArcnet878_2: // // For Arcnet, we always have a 3-byte MAC header. // *MaxFrameSize = DeviceMaxFrameSize - 3; break; } } /* MacReturnMaxDataSize */ VOID IpxUpdateWanInactivityCounter( IN PBINDING Binding, IN IPX_HEADER UNALIGNED * IpxHeader, IN ULONG IncludedHeaderLength, IN PNDIS_PACKET Packet, IN ULONG PacketLength ) /*++ Routine Description: This routine is called when a frame is being sent on a WAN line. It updates the inactivity counter for this binding unless: - The frame is from the RIP socket - The frame is from the SAP socket - The frame is a netbios keep alive - The frame is an NCP keep alive Take the identifier as a parameter to optimize. Arguments: Binding - The binding the frame is sent on. IpxHeader - May contain the first bytes of the packet. IncludedHeaderLength - The number of packet bytes at IpxHeader. Packet - The full NDIS packet. PacketLength - The length of the packet. Return Value: None, but in some cases we return without resetting the inactivity counter. Comments: Improve the instruction count here - pradeepb --*/ { USHORT SourceSocket; PNDIS_BUFFER DataBuffer = NULL; PUCHAR DataBufferData; UINT DataBufferLength; // // First get the source socket. // SourceSocket = IpxHeader->SourceSocket; if ((SourceSocket == RIP_SOCKET) || (SourceSocket == SAP_SOCKET)) { return; } if (SourceSocket == NB_SOCKET) { UCHAR ConnectionControlFlag; UCHAR DataStreamType; USHORT TotalDataLength; // // ConnectionControlFlag and DataStreamType will always follow // IpxHeader // ConnectionControlFlag = ((PUCHAR)(IpxHeader+1))[0]; DataStreamType = ((PUCHAR)(IpxHeader+1))[1]; // // If this is a SYS packet with or without a request for ACK and // has session data in it. // if (((ConnectionControlFlag == 0x80) || (ConnectionControlFlag == 0xc0)) && (DataStreamType == 0x06)) { // // TotalDataLength is in the same buffer. // TotalDataLength = ((USHORT UNALIGNED *)(IpxHeader+1))[4]; // // No need to update the WAN activity counter // if (TotalDataLength == 0) { return; } } } else { UCHAR KeepAliveSignature; // // Now see if it is an NCP keep alive. It can be from rip or from // NCP on this machine // // NOTE: We cannot come here for an SMB packet - [IsaacHe - 12/15]. // if (PacketLength == sizeof(IPX_HEADER) + 2) { // // Get the client data buffer // NdisQueryPacket(Packet, NULL, NULL, &DataBuffer, NULL); // // If the included header length is 0, it is from rip // if (IncludedHeaderLength == 0) { // // Get the second buffer in the packet. The second buffer // contains the IPX header + other stuff // DataBuffer = NDIS_BUFFER_LINKAGE(DataBuffer); } else { // // Get the third buffer in the packet. // DataBuffer = NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(DataBuffer)); } NdisQueryBufferSafe (DataBuffer, (PVOID *)&DataBufferData, &DataBufferLength, NormalPagePriority); if (DataBufferData == NULL) { return; } if (IncludedHeaderLength == 0) { KeepAliveSignature = DataBufferData[sizeof(IPX_HEADER) + 1]; } else { KeepAliveSignature = DataBufferData[1]; } if ((KeepAliveSignature == '?') || (KeepAliveSignature == 'Y')) { return; } } } // // This was a normal packet, so reset this. // Binding->WanInactivityCounter = 0; } /* IpxUpdateWanInactivityCounter */ #if DBG ULONG IpxPadCount = 0; #endif NDIS_STATUS IpxSendFramePreFwd( IN PIPX_LOCAL_TARGET LocalTarget, IN PNDIS_PACKET Packet, IN ULONG PacketLength, IN ULONG IncludedHeaderLength ) /*++ Routine Description: This routine is called by NB/SPX to send a frame. Arguments: LocalTarget - The local target of the send - NB will have the LocalTarget in the Send_Reserved part of the packet; SPX will not now, but will later. Packet - The NDIS packet. PacketLength - The length of the packet, starting at the IPX header. IncludedHeaderLength - The length of the header included in the first buffer that needs to be moved if it does not wind up MacHeaderOffset bytes into the packet. Return Value: Return of IpxSendFrame --*/ { PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved); PUCHAR Header; PNDIS_BUFFER HeaderBuffer; PUCHAR IpxHeader; PUCHAR EthernetHeader; PIPX_HEADER pIpxHeader; UINT TempHeaderBufferLength; PDEVICE Device = IpxDevice; PIPX_HEADER TempHeader; NTSTATUS ret; BOOLEAN fIterate=FALSE; PBINDING pBinding = NULL; // // Figure out the IpxHeader - it is always at the top of the second MDL. // NdisQueryPacket (Packet, NULL, NULL, &HeaderBuffer, NULL); NdisQueryBufferSafe (HeaderBuffer, &EthernetHeader, &TempHeaderBufferLength, HighPagePriority); NdisQueryBufferSafe (NDIS_BUFFER_LINKAGE(HeaderBuffer), &IpxHeader, &TempHeaderBufferLength, HighPagePriority); if (EthernetHeader == NULL || IpxHeader == NULL) { return NDIS_STATUS_FAILURE; } // // Set this now, will change later // Reserved->CurrentNicId = 0; // // Copy the LocalTarget into the send reserved area of the packet. // Reserved->LocalTarget = *LocalTarget; // // If the NicId in the handle is ITERATIVE_NIC_ID, then this could be a send // over all NICs in the case of NB/SPX. // if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)ITERATIVE_NIC_ID) { CTEAssert(Reserved->Identifier == IDENTIFIER_NB || Reserved->Identifier == IDENTIFIER_SPX); // // If there are no real adapters, send on loopback and then quit. if (Device->RealAdapters) { // // Start with the first REAL NIC // Reserved->CurrentNicId = FIRST_REAL_BINDING; FILL_LOCAL_TARGET(&Reserved->LocalTarget, FIRST_REAL_BINDING); } else { // // Use loopback // Reserved->CurrentNicId = LOOPBACK_NIC_ID; FILL_LOCAL_TARGET(&Reserved->LocalTarget, LOOPBACK_NIC_ID); } IPX_DEBUG(SEND, ("Iteration over NICs started, reserved: %lx\n", Reserved)); Reserved->Net0SendSucceeded = FALSE; Reserved->PacketLength = PacketLength; fIterate = TRUE; } // // If the Forwarder is installed, send the packet out for filtering // if (Device->ForwarderBound) { #ifdef SUNDOWN ULONG_PTR FwdAdapterContext = INVALID_CONTEXT_VALUE; #else ULONG FwdAdapterContext = INVALID_CONTEXT_VALUE; #endif PBINDING Binding; // // Figure out the FwdAdapterContext; if the NicId is 0 // then no NicId is specified (since we never return a // NicId of 0 in a FindRoute). // // // We need to fix the following problems with respect to type 20 iterative bcasts : // 1. IPX will not bcast on a down WAN line (thus the Fwd cannot bring up a demand-dial line). // 2. IPX bcasts on every Nic (since it is not any wiser about selecting relevant Nics). // 3. If the first bcast fails, the whole send fails. // // All the above (except 3.) occur because the Fwd knows more about the Nics than IPX does; hence // we let the Fwd decide which lines he wants to send a bcast on. Thus, for Type20 pkts, we pass // up the invalid Fwd context so the Fwd decides the next Nic to send on. // if (!((((PIPX_HEADER)IpxHeader)->PacketType == 0x14) && fIterate) && Reserved->LocalTarget.NicId && (Binding = NIC_ID_TO_BINDING(Device, Reserved->LocalTarget.NicId)) && (GET_LONG_VALUE(Binding->ReferenceCount) == 2)) { // // If proper NicId specified, and the adapter has been opened by // the forwarder, set the FwdAdapterContext. // FwdAdapterContext = Binding->FwdAdapterContext; } #if DBG else { if (((PIPX_HEADER)IpxHeader)->PacketType == 0x14) { IPX_DEBUG(SEND, ("SendComplete: IpxHeader has Type20: %lx\n", IpxHeader)); } } #endif // // Call the InternalSend to filter the packet and get to know // the correct adapter context // ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)( &Reserved->LocalTarget, FwdAdapterContext, Packet, IpxHeader, IpxHeader+sizeof(IPX_HEADER), // the data starts after the IPX Header. PacketLength, fIterate); // // The FWD might not yet know of the Nics going away [109160]. // if (NULL == NIC_ID_TO_BINDING(Device, Reserved->LocalTarget.NicId)) { ret = STATUS_DROP_SILENTLY; } if (ret == STATUS_SUCCESS) { // // The adapter could have gone away and we have indicated to the Forwarder // but the Forwarder has not yet closed the adapter. // [ZZ] adapters do not go away now. // // what if the binding is NULL here? Can we trust the Forwarder to // give us a non-NULL binding? // if (GET_LONG_VALUE(NIC_ID_TO_BINDING(Device, Reserved->LocalTarget.NicId)->ReferenceCount) == 1) { IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned SUCCESS, Ref count is 1\n")); return NDIS_STATUS_SUCCESS; } else { // // Fill up the changed LocalTarget for the client except in the ITERATE case. // if (!fIterate) { *LocalTarget = Reserved->LocalTarget; } IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned SUCCESS, sending out on wire\n")); goto SendPkt; } } else if (ret == STATUS_PENDING) { // // LocalTarget will get filled up in InternalSendComplete // IPX_DEBUG(SEND, ("SendFramePreFwd: FWD returned PENDING\n")); return NDIS_STATUS_PENDING; } else if (ret == STATUS_DROP_SILENTLY) { // // This was a keepalive which the router is spoofing. Drop it silently. // IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned STATUS_DROP_SILENTLY - dropping pkt.\n")); return NDIS_STATUS_SUCCESS; } // // else DISCARD - this means that either the packet failed the send // or that the preferred NicId was not good. // return STATUS_NETWORK_UNREACHABLE; } else { // // Work around NdisMBlahX bug. // Check if this is a self-directed packet and loop it back. // SendPkt: pIpxHeader = (PIPX_HEADER) IpxHeader; if ((IPX_NODE_EQUAL(pIpxHeader->SourceNode, pIpxHeader->DestinationNode)) && (*(UNALIGNED ULONG *)pIpxHeader->SourceNetwork == *(UNALIGNED ULONG *)pIpxHeader->DestinationNetwork)) { IPX_DEBUG(TEMP, ("Source Net: %lx + Source Address: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n", *(UNALIGNED ULONG *)pIpxHeader->SourceNetwork, pIpxHeader->SourceNode[0], pIpxHeader->SourceNode[1], pIpxHeader->SourceNode[2], pIpxHeader->SourceNode[3], pIpxHeader->SourceNode[4], pIpxHeader->SourceNode[5])); IPX_DEBUG(TEMP, ("Dest Net: %lx + DestinationAddress: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x \n", *(UNALIGNED ULONG *)pIpxHeader->DestinationNetwork, pIpxHeader->DestinationNode[0], pIpxHeader->DestinationNode[1], pIpxHeader->DestinationNode[2], pIpxHeader->DestinationNode[3], pIpxHeader->DestinationNode[4], pIpxHeader->DestinationNode[5] )); IPX_DEBUG(TEMP, ("Well, It is self-directed. Loop it back ourselves\n")); FILL_LOCAL_TARGET(LocalTarget, LOOPBACK_NIC_ID); } else { pBinding = NIC_ID_TO_BINDING(Device, Reserved->LocalTarget.NicId); if (pBinding) { if (IPX_NODE_EQUAL(Reserved->LocalTarget.MacAddress, pBinding->LocalAddress.NodeAddress)) { IPX_DEBUG(TEMP, ("Source Net:%lx, Source Address: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n", *(UNALIGNED ULONG *)pIpxHeader->SourceNetwork, pIpxHeader->SourceNode[0], pIpxHeader->SourceNode[1], pIpxHeader->SourceNode[2], pIpxHeader->SourceNode[3], pIpxHeader->SourceNode[4], pIpxHeader->SourceNode[5])); IPX_DEBUG(TEMP, ("Dest Net:%lx, DestAddress: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x \n", *(UNALIGNED ULONG *)pIpxHeader->DestinationNetwork, pIpxHeader->DestinationNode[0], pIpxHeader->DestinationNode[1], pIpxHeader->DestinationNode[2], pIpxHeader->DestinationNode[3], pIpxHeader->DestinationNode[4], pIpxHeader->DestinationNode[5] )); IPX_DEBUG(TEMP, ("Well, It is self-directed. Loop it back ourselves (NIC_HANDLE is the same!)\n")); FILL_LOCAL_TARGET(LocalTarget, LOOPBACK_NIC_ID); } } else { IPX_DEBUG(TEMP, ("Source Net:%lx, Source Address: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n", *(UNALIGNED ULONG *)pIpxHeader->SourceNetwork, pIpxHeader->SourceNode[0], pIpxHeader->SourceNode[1], pIpxHeader->SourceNode[2], pIpxHeader->SourceNode[3], pIpxHeader->SourceNode[4], pIpxHeader->SourceNode[5])); IPX_DEBUG(TEMP, ("Dest Net: %lx, LocalAddress: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x \n", *(UNALIGNED ULONG *)pIpxHeader->DestinationNetwork, pIpxHeader->DestinationNode[0], pIpxHeader->DestinationNode[1], pIpxHeader->DestinationNode[2], pIpxHeader->DestinationNode[3], pIpxHeader->DestinationNode[4], pIpxHeader->DestinationNode[5] )); } } if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID) { // // Enque this packet to the LoopbackQueue on the binding. // If the LoopbackRtn is not already scheduled, schedule it. // IPX_DEBUG(LOOPB, ("Mac.c: Packet: %x\n", Packet)); // // Recalculate packet counts here. // Assume an 802_3802_2 header and use that length. // Adjust the MAC header's length to the right value // NdisAdjustBufferLength (HeaderBuffer, 17); NdisRecalculatePacketCounts (Packet); IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, LOOPBACK_NIC_ID)->Adapter); // // The upper driver waits for the SendComplete. // return STATUS_PENDING; } return IpxSendFrame ( &Reserved->LocalTarget, Packet, PacketLength, IncludedHeaderLength); } } NDIS_STATUS IpxSendFrame( IN PIPX_LOCAL_TARGET LocalTarget, IN PNDIS_PACKET Packet, IN ULONG PacketLength, IN ULONG IncludedHeaderLength ) /*++ Routine Description: This routine constructs a MAC header in a packet and submits it to the appropriate NDIS driver. It is assumed that the first buffer in the packet contains an IPX header at an offset based on the media type. This IPX header is moved around if needed. Check that Binding is not NULL. Arguments: LocalTarget - The local target of the send. Packet - The NDIS packet. PacketLength - The length of the packet, starting at the IPX header. IncludedHeaderLength - The length of the header included in the first buffer that needs to be moved if it does not wind up MacHeaderOffset bytes into the packet. Return Value: None. --*/ { PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved); PDEVICE Device = IpxDevice; PUCHAR Header; PBINDING Binding, MasterBinding; PADAPTER Adapter; ULONG TwoBytes; PNDIS_BUFFER HeaderBuffer; UINT TempHeaderBufferLength; ULONG HeaderLength=0; UCHAR SourceRoutingBuffer[18]; PUCHAR SourceRouting; ULONG SourceRoutingLength; NDIS_STATUS Status; ULONG BufferLength; UCHAR DestinationType; UCHAR SourceRoutingIdentifier; ULONG HeaderSizeRequired; PIPX_HEADER TempHeader; USHORT PktLength; IPX_DEFINE_LOCK_HANDLE(LockHandle1) IPX_DEFINE_LOCK_HANDLE(LockHandle) #ifdef SNMP // // This should not include the forwarded packets; on host side, it is 0. // On router, the AdvSysForwPackets are subtracted in the sub-agent code. // ++IPX_MIB_ENTRY(Device, SysOutRequests); #endif SNMP // // Get the lock on the binding array // IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1); Binding = NIC_HANDLE_TO_BINDING(Device, &LocalTarget->NicHandle); if (Binding == NULL) { IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1); IPX_DEBUG(PNP, ("Invalid NIC handle: %lx\n", LocalTarget->NicHandle)); // // Return a unique error that NB/SPX see and re-query the NicId. // #ifdef SNMP ++IPX_MIB_ENTRY(Device, SysOutMalformedRequests); #endif SNMP return STATUS_DEVICE_DOES_NOT_EXIST; } IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS); Adapter = Binding->Adapter; IpxReferenceAdapter(Adapter); // // Release the lock // IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1); // // For IPX and other protocols that are guaranteed to have allocated // the header from non-paged pool, use the buffer directly. For others, // query the packet for the pointer to the MDL. // if (Reserved->Identifier >= IDENTIFIER_IPX) { HeaderBuffer = Reserved->HeaderBuffer; Header = Reserved->Header; } else { NdisQueryPacket (Packet, NULL, NULL, &HeaderBuffer, NULL); NdisQueryBufferSafe(HeaderBuffer, &Header, &TempHeaderBufferLength, HighPagePriority); if (Header == NULL) { return NDIS_STATUS_FAILURE; } } CTEAssert (Reserved->PaddingBuffer == NULL); // // First move the packet around if needed. // if (Reserved->Identifier < IDENTIFIER_IPX) { // // Only RIP will have IncludedHeaderLength as 0. I don't know // why we have the comment about RIP inside this if statement. // if (IncludedHeaderLength > 0) { // // Spx can handle a virtual net as long as it is // not 0. Netbios always needs to use the real address. // We need to hack the ipx source address for packets // which are sent by spx if we have a fake virtual // net, and packets sent by netbios unless we are // bound to only one card. // // // We handle binding sets as follows, based on who // sent the frame to us: // // RIP: Since we only tell RIP about the masters at // bind time, and hide slaves on indications, it should // never be sending on a slave binding. Since RIP knows // the real net and node of every binding we don't // need to modify the packet at all. // // NB: For broadcasts we want to put the first card's // address in the IPX source but round-robin the // actual sends over all cards (broadcasts shouldn't // be passed in with a slave's NIC ID). For directed // packets, which may come in on a slave, we should // put the slave's address in the IPX source. // // SPX: SPX does not send broadcasts. For directed // frames we want to use the slave's net and node // in the IPX source. // if (Reserved->Identifier == IDENTIFIER_NB) { CTEAssert (IncludedHeaderLength >= sizeof(IPX_HEADER)); // // Get the packet length from the ipx header. Compare with // the max. allowed datagram size. // TempHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]); PktLength = ((TempHeader->PacketLength[0] << 8) | (TempHeader->PacketLength[1])); // // Not the most efficient way to do this. NWLNKNB should do this. // Doing it in ipx means doing it for all packets (even those sent on // connections). Will remove this later when nwlnknb change has been // tested. // if (PktLength > (Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER))) { IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n", PktLength, Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER))); // // Dereference the binding and adapter // IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS); IpxDereferenceAdapter(Adapter); #ifdef SNMP ++IPX_MIB_ENTRY(Device, SysOutMalformedRequests); #endif SNMP return STATUS_INVALID_BUFFER_SIZE; } if (Device->ValidBindings > 1) { // // Store this now, since even if we round-robin the // actual send we want the binding set master's net // and node in the IPX source address. // *(UNALIGNED ULONG *)TempHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress; RtlCopyMemory (TempHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6); if (Binding->BindingSetMember) { if (IPX_NODE_BROADCAST(LocalTarget->MacAddress)) { // // This is a broadcast, so we round-robin the // sends through the binding set. // // // We dont have a lock here - the masterbinding could be bogus // IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS); IpxDereferenceAdapter(Adapter); MasterBinding = Binding->MasterBinding; Binding = MasterBinding->CurrentSendBinding; MasterBinding->CurrentSendBinding = Binding->NextBinding; Adapter = Binding->Adapter; IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS); IpxReferenceAdapter(Adapter); } } } // // [STEFANS]: Replace all source addresses with the virtualnet# to allow for sends // on 0 network number WAN lines (typically between routers). // if (Device->VirtualNetwork) { *(UNALIGNED ULONG *)TempHeader->SourceNetwork = Device->SourceAddress.NetworkAddress; RtlCopyMemory (TempHeader->SourceNode, Device->SourceAddress.NodeAddress, 6); } } else if (Reserved->Identifier == IDENTIFIER_SPX) { // // Need to update this if we have multiple cards but // a zero virtual net. // if (Device->MultiCardZeroVirtual) { CTEAssert (IncludedHeaderLength >= sizeof(IPX_HEADER)); TempHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]); *(UNALIGNED ULONG *)TempHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress; RtlCopyMemory (TempHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6); } } else { // // For a rip packet it should not be in a binding set, // or if it is it should be the master. // #if DBG CTEAssert ((!Binding->BindingSetMember) || (Binding->CurrentSendBinding)); #endif } #if 0 // // There is a header included, we need to adjust it. // The header will be at Device->IncludedHeaderOffset. // if (LocalTarget->MacAddress[0] & Adapter->MacInfo.BroadcastMask) { HeaderSizeRequired = Adapter->BcMcHeaderSizes[Binding->FrameType]; } else { HeaderSizeRequired = Adapter->DefHeaderSizes[Binding->FrameType]; } if (HeaderSizeRequired != Device->IncludedHeaderOffset) { RtlMoveMemory( &Header[HeaderSizeRequired], &Header[Device->IncludedHeaderOffset], IncludedHeaderLength); } #endif } } IPX_GET_LOCK (&Adapter->Lock, &LockHandle); if (Adapter->State != ADAPTER_STATE_STOPPING) { IpxReferenceAdapter1(Adapter,ADAP_REF_SEND); IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } else { IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS); IpxDereferenceAdapter(Adapter); IPX_FREE_LOCK (&Adapter->Lock, LockHandle); return NDIS_STATUS_FAILURE; } switch (Adapter->MacInfo.MediumType) { case NdisMedium802_3: // // [FW] This will allow both LINE_UP and LINE_CONFIG states // if (!Binding->LineUp) { // // Bug #17273 return proper error message // // return STATUS_DEVICE_DOES_NOT_EXIST; // Make this a separate switch that generally falls through? // // Derefernce the binding and adapter // IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS); IpxDereferenceAdapter(Adapter); IpxDereferenceAdapter1(Adapter,ADAP_REF_SEND); #ifdef SNMP ++IPX_MIB_ENTRY(Device, SysOutDiscards); #endif SNMP return STATUS_NETWORK_UNREACHABLE; } if (Adapter->MacInfo.MediumAsync) { IPX_HEADER UNALIGNED * IpxHeader; PNDIS_BUFFER IpxNdisBuff; UINT IpxHeaderLen; #if 0 // // The header should have been moved here. // CTEAssert(Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] == Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II]); IpxHeader = (IPX_HEADER UNALIGNED *) (&Header[Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II]]); #endif // // The Ipx header is always the second ndis buffer in the mdl // chain. Get it and then query the va of the same. // IpxNdisBuff = NDIS_BUFFER_LINKAGE(HeaderBuffer); NdisQueryBufferSafe (IpxNdisBuff, (PVOID *)&IpxHeader, &IpxHeaderLen, HighPagePriority); if (IpxHeader == NULL) { return NDIS_STATUS_FAILURE; } // IpxHeader = (IPX_HEADER UNALIGNED *) (&Header[MAC_HEADER_SIZE]); // // If this is a type 20 name frame from Netbios and we are // on a dialin WAN line, drop it if configured to. // // The 0x01 bit of DisableDialinNetbios controls // internal->WAN packets, which we handle here. // // // // SS# 33592: In case of iterative sends, the IncludedHeaderLength is not set properly // since we dont keep track of the length that came in the first time (we track the PacketLength // however). The included length field is used here for checking for NB_NAME_FRAMES, but elsewhere // used only to distinguish between whether RIP or NB/SPX sent the packet (IncludedHeaderLen ==0 for RIP) // The ideal solution here is to do way with this field altogether, but for the beta we will just use the // PacketLength field for comparison here since we are assured that this will be equal to the InclHeaderLen // for any type 0x14 packet that comes down from NB. // // Remove the IncludedHeaderLength field. // // // [FW] do this only if the forwarder is not bound // if (!Device->ForwarderBound && (!Binding->DialOutAsync) && (Reserved->Identifier == IDENTIFIER_NB) && // (IncludedHeaderLength == sizeof(IPX_HEADER) + 50) && // 50 == sizeof(NB_NAME_FRAME) (PacketLength == sizeof(IPX_HEADER) + 50) && // 50 == sizeof(NB_NAME_FRAME) ((Device->DisableDialinNetbios & 0x01) != 0) && (IpxHeader->PacketType == 0x14)) { // // Derefernce the binding and adapter // IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS); IpxDereferenceAdapter(Adapter); IpxDereferenceAdapter1(Adapter,ADAP_REF_SEND); return STATUS_SUCCESS; } // // We do checks to see if we should reset the inactivity // counter. We normally need to check for netbios // session alives, packets from rip, packets from // sap, and ncp keep alives. In fact sap and ncp // packets don't come through here. // IpxUpdateWanInactivityCounter( Binding, IpxHeader, IncludedHeaderLength, Packet, PacketLength); // // In order for loopback to work properly, we need to put the local MAC address for locally destined // pkts so NdisWAN can loop them back. // if (IPX_NODE_EQUAL(LocalTarget->MacAddress, Binding->LocalAddress.NodeAddress)) { RtlCopyMemory (Header, Binding->LocalMacAddress.Address, 6); } else { RtlCopyMemory (Header, Binding->RemoteMacAddress.Address, 6); } } else { RtlCopyMemory (Header, LocalTarget->MacAddress, 6); } RtlCopyMemory (Header+6, Binding->LocalMacAddress.Address, 6); switch (Binding->FrameType) { case ISN_FRAME_TYPE_802_2: TwoBytes = PacketLength + 3; Header[14] = 0xe0; Header[15] = 0xe0; Header[16] = 0x03; HeaderLength = 17; break; case ISN_FRAME_TYPE_802_3: TwoBytes = PacketLength; HeaderLength = 14; break; case ISN_FRAME_TYPE_ETHERNET_II: TwoBytes = Adapter->BindSap; HeaderLength = 14; break; case ISN_FRAME_TYPE_SNAP: TwoBytes = PacketLength + 8; Header[14] = 0xaa; Header[15] = 0xaa; Header[16] = 0x03; Header[17] = 0x00; Header[18] = 0x00; Header[19] = 0x00; *(UNALIGNED USHORT *)(&Header[20]) = Adapter->BindSapNetworkOrder; HeaderLength = 22; break; } Header[12] = (UCHAR)(TwoBytes / 256); Header[13] = (UCHAR)(TwoBytes % 256); //BufferLength = IncludedHeaderLength + HeaderLength; BufferLength = HeaderLength; // // Pad odd-length packets if needed. // if ((((PacketLength + HeaderLength) & 1) != 0) && (Device->EthernetPadToEven) && (!Adapter->MacInfo.MediumAsync)) { PNDIS_BUFFER CurBuffer; PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer; UINT Offset; UINT LastBufferLength; // // Find the tail of the current packet. // CurBuffer = HeaderBuffer; while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) { CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer); } // // If the last byte of the last NDIS_BUFFER is not at the end of // the page, then we can simply increase the NDIS_BUFFER ByteCount // by one. // Otherwise, we must use the global padding buffer. // NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength ); if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) { if ( CurBuffer == HeaderBuffer ) { BufferLength++; // Just bump this length } else { NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) ); Reserved->PreviousTail = NULL; Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer; IPX_DEBUG(TEMP,("IpxSendFrame:Set PaddingBuffer for %p\n", Packet)); } } else { CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL); Reserved->PreviousTail = CurBuffer; NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer; Reserved->PaddingBuffer = PaddingBuffer; IPX_DEBUG(TEMP,("IpxSendFrame:Set PaddingBuffer for %p\n", Packet)); } if (TwoBytes != Adapter->BindSap) { CTEAssert(TwoBytes & 1); TwoBytes += 1; Header[12] = (UCHAR)(TwoBytes / 256); Header[13] = (UCHAR)(TwoBytes % 256); } #if DBG ++IpxPadCount; #endif } break; case NdisMedium802_5: if (Reserved->Identifier >= IDENTIFIER_IPX) { DestinationType = Reserved->DestinationType; SourceRoutingIdentifier = IDENTIFIER_IPX; } else { if (LocalTarget->MacAddress[0] & 0x80) { if (*(UNALIGNED ULONG *)(&LocalTarget->MacAddress[2]) != 0xffffffff) { DestinationType = DESTINATION_MCAST; } else { DestinationType = DESTINATION_BCAST; } } else { DestinationType = DESTINATION_DEF; } SourceRoutingIdentifier = Reserved->Identifier; } if (DestinationType == DESTINATION_DEF) { MacLookupSourceRouting( SourceRoutingIdentifier, Binding, LocalTarget->MacAddress, SourceRoutingBuffer, &SourceRoutingLength); if (SourceRoutingLength != 0) { // PUCHAR IpxHeader = Header + Binding->DefHeaderSize; PUCHAR IpxHeader = Header + MAC_HEADER_SIZE; // // Need to slide the header down to accomodate the SR. // SourceRouting = SourceRoutingBuffer; // RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength); } } else { // // For these packets we assume that the header is in the // right place. // if (!Adapter->SourceRouting) { SourceRoutingLength = 0; } else { if (DestinationType == DESTINATION_BCAST) { if (Binding->AllRouteBroadcast) { SourceRouting = AllRouteSourceRouting; } else { SourceRouting = SingleRouteSourceRouting; } SourceRoutingLength = 2; } else { CTEAssert (DestinationType == DESTINATION_MCAST); if (Binding->AllRouteMulticast) { SourceRouting = AllRouteSourceRouting; } else { SourceRouting = SingleRouteSourceRouting; } SourceRoutingLength = 2; } } #if 0 if (SourceRoutingLength != 0) { // PUCHAR IpxHeader = Header + Binding->BcMcHeaderSize; PUCHAR IpxHeader = Header + MAC_HEADER_SIZE; // // Need to slide the header down to accomodate the SR. // RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength); } #endif } Header[0] = TR_PREAMBLE_AC; Header[1] = TR_PREAMBLE_FC; RtlCopyMemory (Header+2, LocalTarget->MacAddress, 6); RtlCopyMemory (Header+8, Binding->LocalMacAddress.Address, 6); if (SourceRoutingLength != 0) { Header[8] |= TR_SOURCE_ROUTE_FLAG; RtlCopyMemory (Header+14, SourceRouting, SourceRoutingLength); } Header += (14 + SourceRoutingLength); switch (Binding->FrameType) { case ISN_FRAME_TYPE_802_2: case ISN_FRAME_TYPE_802_3: case ISN_FRAME_TYPE_ETHERNET_II: Header[0] = 0xe0; Header[1] = 0xe0; Header[2] = 0x03; HeaderLength = 17; break; case ISN_FRAME_TYPE_SNAP: Header[0] = 0xaa; Header[1] = 0xaa; Header[2] = 0x03; Header[3] = 0x00; Header[4] = 0x00; Header[5] = 0x00; *(UNALIGNED USHORT *)(&Header[6]) = Adapter->BindSapNetworkOrder; HeaderLength = 22; break; } // BufferLength = IncludedHeaderLength + HeaderLength + SourceRoutingLength; BufferLength = HeaderLength + SourceRoutingLength; break; case NdisMediumFddi: Header[0] = FDDI_HEADER_BYTE; RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6); RtlCopyMemory (Header+7, Binding->LocalMacAddress.Address, 6); switch (Binding->FrameType) { case ISN_FRAME_TYPE_802_3: HeaderLength = 13; break; case ISN_FRAME_TYPE_802_2: case ISN_FRAME_TYPE_ETHERNET_II: Header[13] = 0xe0; Header[14] = 0xe0; Header[15] = 0x03; HeaderLength = 16; break; case ISN_FRAME_TYPE_SNAP: Header[13] = 0xaa; Header[14] = 0xaa; Header[15] = 0x03; Header[16] = 0x00; Header[17] = 0x00; Header[18] = 0x00; *(UNALIGNED USHORT *)(&Header[19]) = Adapter->BindSapNetworkOrder; HeaderLength = 21; break; } // BufferLength = IncludedHeaderLength + HeaderLength; BufferLength = HeaderLength; break; case NdisMediumArcnet878_2: // // Convert broadcast address to 0 (the arcnet broadcast). // Header[0] = Binding->LocalMacAddress.Address[5]; if (LocalTarget->MacAddress[5] == 0xff) { Header[1] = 0x00; } else { Header[1] = LocalTarget->MacAddress[5]; } Header[2] = ARCNET_PROTOCOL_ID; // // Binding->FrameType is not used. // HeaderLength = 3; // BufferLength = IncludedHeaderLength + HeaderLength; BufferLength = HeaderLength; break; } // // Adjust the MAC header's length to the right value // NdisAdjustBufferLength (HeaderBuffer, BufferLength); NdisRecalculatePacketCounts (Packet); #if 0 { PMDL mdl; mdl = (PMDL)NDIS_BUFFER_LINKAGE(HeaderBuffer); if (mdl) { KdPrint(("**Bytecount %x %x\n",mdl->ByteCount, mdl)); if ((LONG)mdl->ByteCount < 0) { DbgBreakPoint(); } } } #endif #if DBG { ULONG SendFlag; ULONG Temp; PNDIS_BUFFER FirstPacketBuffer; PNDIS_BUFFER SecondPacketBuffer; IPX_HEADER DumpHeader; UCHAR DumpData[14]; NdisQueryPacket (Packet, NULL, NULL, &FirstPacketBuffer, NULL); SecondPacketBuffer = NDIS_BUFFER_LINKAGE(FirstPacketBuffer); TdiCopyMdlToBuffer(SecondPacketBuffer, 0, &DumpHeader, 0, sizeof(IPX_HEADER), &Temp); if (Reserved->Identifier == IDENTIFIER_NB) { SendFlag = IPX_PACKET_LOG_SEND_NB; } else if (Reserved->Identifier == IDENTIFIER_SPX) { SendFlag = IPX_PACKET_LOG_SEND_SPX; } else if (Reserved->Identifier == IDENTIFIER_RIP) { SendFlag = IPX_PACKET_LOG_SEND_RIP; } else { if (DumpHeader.SourceSocket == IpxPacketLogSocket) { SendFlag = IPX_PACKET_LOG_SEND_SOCKET | IPX_PACKET_LOG_SEND_OTHER; } else { SendFlag = IPX_PACKET_LOG_SEND_OTHER; } } #if 0 if (PACKET_LOG(SendFlag)) { TdiCopyMdlToBuffer(SecondPacketBuffer, sizeof(IPX_HEADER), &DumpData, 0, 14, &Temp); IpxLogPacket( TRUE, LocalTarget->MacAddress, Binding->LocalMacAddress.Address, (USHORT)PacketLength, &DumpHeader, DumpData); } #endif } #endif ++Device->Statistics.PacketsSent; NdisSend( &Status, Adapter->NdisBindingHandle, Packet); IpxDereferenceAdapter1(Adapter,ADAP_REF_SEND); if (Status != STATUS_PENDING) { IPX_DEBUG(TEMP,("Status is not pending (%ld). Reserved (%p)\n",Status,Reserved)); if (Reserved->PaddingBuffer) { IPX_DEBUG(TEMP,("Padding buffer is not null. \n")); // // Remove padding if it was done. // if ( Reserved->PreviousTail ) { NDIS_BUFFER_LINKAGE (Reserved->PreviousTail) = (PNDIS_BUFFER)NULL; } else { PNDIS_BUFFER LastBuffer = (PNDIS_BUFFER)Reserved->PaddingBuffer; UINT LastBufferLength; NdisQueryBuffer( LastBuffer, NULL, &LastBufferLength ); NdisAdjustBufferLength( LastBuffer, (LastBufferLength - 1) ); #if DBG if ((Reserved->Identifier == IDENTIFIER_RIP) && (LastBufferLength == 1500)) { DbgPrint("Packet: %lx\n", Packet); DbgBreakPoint(); } #endif DBG } Reserved->PaddingBuffer = NULL; IPX_DEBUG(TEMP,("IpxSendFrame:Cleared PaddingBuffer for %p\n", Packet)); if (Reserved->Identifier < IDENTIFIER_IPX) { NdisRecalculatePacketCounts (Packet); } } // // If this was an NB/SPX packet, and there was an // iterative send going on, then call the SendComplete // handler. // if ((Reserved->Identifier == IDENTIFIER_NB || Reserved->Identifier == IDENTIFIER_SPX) && (Reserved->CurrentNicId)) { IpxSendComplete( (NDIS_HANDLE)Binding->Adapter, Packet, Status); Status = STATUS_PENDING; } } // // Derefernce the binding and adapter // IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS); IpxDereferenceAdapter(Adapter); return Status; } /* IpxSendFrame */ NDIS_STATUS IpxSendFrame802_3802_3( IN PADAPTER Adapter, IN PIPX_LOCAL_TARGET LocalTarget, IN PNDIS_PACKET Packet, IN ULONG PacketLength, IN ULONG IncludedHeaderLength ) /*++ Routine Description: This routine constructs a MAC header in a packet and submits it to the appropriate NDIS driver. It is assumed that the first buffer in the packet contains an IPX header at an offset based on the media type. This IPX header is moved around if needed. THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN THE ISN_FRAME_TYPE_802_3 FORMAT. Arguments: Adapter - The adapter on which we are sending. LocalTarget - The local target of the send. Packet - The NDIS packet. PacketLength - The length of the packet, starting at the IPX header. IncludedHeaderLength - The length of the header included in the first buffer that needs to be moved if it does not wind up MacHeaderOffset bytes into the packet. // // Remove the IncludedHeaderLength parameter from here // Return Value: None. --*/ { PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved); PUCHAR Header; NDIS_STATUS Status; LONG HeaderLength; IPX_DEFINE_LOCK_HANDLE(LockHandle) IPX_GET_LOCK (&Adapter->Lock, &LockHandle); if (Adapter->State != ADAPTER_STATE_STOPPING) { IpxReferenceAdapter1(Adapter,ADAP_REF_SEND); IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } else { IPX_FREE_LOCK (&Adapter->Lock, LockHandle); return NDIS_STATUS_FAILURE; } Header = Reserved->Header; #if BACK_FILL BACK_FILL_HEADER(Header, Reserved, 14, Packet); IPX_DEBUG(SEND,("Backfill request 802_3802_3!! %x %x %x\n", Packet, Reserved, Reserved->HeaderBuffer)); #endif RtlCopyMemory (Header, LocalTarget->MacAddress, 6); RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6); // // Pad odd-length packets if needed. // if (((PacketLength & 1) != 0) && (IpxDevice->EthernetPadToEven)) { PNDIS_BUFFER CurBuffer; PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer; UINT Offset; UINT LastBufferLength; // // Find the tail of the current packet. // CurBuffer = Reserved->HeaderBuffer; while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) { CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer); } // // If the last byte of the last NDIS_BUFFER is not at the end of // the page, then we can simply increase the NDIS_BUFFER ByteCount // by one. // Otherwise, we must use the global padding buffer. // NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength ); if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) { #if BACK_FILL if (0) { #else if ( CurBuffer == Reserved->HeaderBuffer ) { IncludedHeaderLength++; // Just bump this length #endif } else { NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) ); Reserved->PreviousTail = NULL; Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer; } } else { CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL); Reserved->PreviousTail = CurBuffer; NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer; Reserved->PaddingBuffer = PaddingBuffer; } ++PacketLength; #if DBG ++IpxPadCount; #endif } Header[12] = (UCHAR)(PacketLength / 256); Header[13] = (UCHAR)(PacketLength % 256); //NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 14); #if BACK_FILL BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 14); #else NdisAdjustBufferLength (Reserved->HeaderBuffer, 14); #endif NdisRecalculatePacketCounts (Packet); NdisSend( &Status, Adapter->NdisBindingHandle, Packet); IpxDereferenceAdapter1(Adapter,ADAP_REF_SEND); return Status; } /* IpxSendFrame802_3802_3 */ NDIS_STATUS IpxSendFrame802_3802_2( IN PADAPTER Adapter, IN PIPX_LOCAL_TARGET LocalTarget, IN PNDIS_PACKET Packet, IN ULONG PacketLength, IN ULONG IncludedHeaderLength ) /*++ Routine Description: This routine constructs a MAC header in a packet and submits it to the appropriate NDIS driver. It is assumed that the first buffer in the packet contains an IPX header at an offset based on the media type. This IPX header is moved around if needed. THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN THE ISN_FRAME_TYPE_802_2 FORMAT. Arguments: Adapter - The adapter on which we are sending. LocalTarget - The local target of the send. Packet - The NDIS packet. PacketLength - The length of the packet, starting at the IPX header. IncludedHeaderLength - The length of the header included in the first buffer that needs to be moved if it does not wind up MacHeaderOffset bytes into the packet. Return Value: None. --*/ { PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved); PUCHAR Header; ULONG TwoBytes; NDIS_STATUS Status; IPX_DEFINE_LOCK_HANDLE(LockHandle) IPX_GET_LOCK (&Adapter->Lock, &LockHandle); if (Adapter->State != ADAPTER_STATE_STOPPING) { IpxReferenceAdapter1(Adapter,ADAP_REF_SEND); IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } else { IPX_FREE_LOCK (&Adapter->Lock, LockHandle); return NDIS_STATUS_FAILURE; } Header = Reserved->Header; #if BACK_FILL BACK_FILL_HEADER(Header, Reserved, 17, Packet); IPX_DEBUG(SEND, ("Backfill request 802_3802_3!! %x %x %x\n", Packet, Reserved, Reserved->HeaderBuffer)); IPX_DEBUG(SEND, ("packet=%x, usermdl %x\n",Packet,Reserved->HeaderBuffer)); #endif RtlCopyMemory (Header, LocalTarget->MacAddress, 6); RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6); TwoBytes = PacketLength + 3; Header[14] = 0xe0; Header[15] = 0xe0; Header[16] = 0x03; // // Pad odd-length packets if needed. // if (((PacketLength & 1) == 0) && (IpxDevice->EthernetPadToEven)) { PNDIS_BUFFER CurBuffer; PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer; UINT Offset; UINT LastBufferLength; // // Find the tail of the current packet. // CurBuffer = Reserved->HeaderBuffer; while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) { CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer); } // // If the last byte of the last NDIS_BUFFER is not at the end of // the page, then we can simply increase the NDIS_BUFFER ByteCount // by one. // Otherwise, we must use the global padding buffer. // NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength ); if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0 ) { #if BACK_FILL if (0) { #else if ( CurBuffer == Reserved->HeaderBuffer ) { IncludedHeaderLength++; // Just bump this length #endif } else { NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) ); Reserved->PreviousTail = NULL; Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer; IPX_DEBUG(TEMP,("IpxSendFrame802_3802_2:Set PaddingBuffer for %p\n", Packet)); } } else { CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL); Reserved->PreviousTail = CurBuffer; NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer; Reserved->PaddingBuffer = PaddingBuffer; IPX_DEBUG(TEMP,("IpxSendFrame802_3802_:Set PaddingBuffer for %p\n", Packet)); } ++TwoBytes; #if DBG ++IpxPadCount; #endif } Header[12] = (UCHAR)(TwoBytes / 256); Header[13] = (UCHAR)(TwoBytes % 256); // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 17); #if BACK_FILL BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 17); #else NdisAdjustBufferLength (Reserved->HeaderBuffer, 17); #endif NdisRecalculatePacketCounts (Packet); NdisSend( &Status, Adapter->NdisBindingHandle, Packet); IpxDereferenceAdapter1(Adapter,ADAP_REF_SEND); return Status; } /* IpxSendFrame802_3802_2 */ NDIS_STATUS IpxSendFrame802_3EthernetII( IN PADAPTER Adapter, IN PIPX_LOCAL_TARGET LocalTarget, IN PNDIS_PACKET Packet, IN ULONG PacketLength, IN ULONG IncludedHeaderLength ) /*++ Routine Description: This routine constructs a MAC header in a packet and submits it to the appropriate NDIS driver. It is assumed that the first buffer in the packet contains an IPX header at an offset based on the media type. This IPX header is moved around if needed. THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN THE ISN_FRAME_TYPE_ETHERNET_II FORMAT. Arguments: Adapter - The adapter on which we are sending. LocalTarget - The local target of the send. Packet - The NDIS packet. PacketLength - The length of the packet, starting at the IPX header. IncludedHeaderLength - The length of the header included in the first buffer that needs to be moved if it does not wind up MacHeaderOffset bytes into the packet. Return Value: None. --*/ { PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved); PUCHAR Header; NDIS_STATUS Status; IPX_DEFINE_LOCK_HANDLE(LockHandle) IPX_GET_LOCK (&Adapter->Lock, &LockHandle); if (Adapter->State != ADAPTER_STATE_STOPPING) { IpxReferenceAdapter1(Adapter,ADAP_REF_SEND); IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } else { IPX_FREE_LOCK (&Adapter->Lock, LockHandle); return NDIS_STATUS_FAILURE; } Header = Reserved->Header; #if BACK_FILL BACK_FILL_HEADER(Header, Reserved, 14, Packet); #endif BACK_FILL RtlCopyMemory (Header, LocalTarget->MacAddress, 6); RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6); *(UNALIGNED USHORT *)(&Header[12]) = Adapter->BindSapNetworkOrder; // // Pad odd-length packets if needed. // if (((PacketLength & 1) != 0) && (IpxDevice->EthernetPadToEven)) { PNDIS_BUFFER CurBuffer; PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer; UINT Offset; UINT LastBufferLength; // // Find the tail of the current packet. // CurBuffer = Reserved->HeaderBuffer; while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) { CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer); } // // If the last byte of the last NDIS_BUFFER is not at the end of // the page, then we can simply increase the NDIS_BUFFER ByteCount // by one. // Otherwise, we must use the global padding buffer. // NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength ); if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) { #if BACK_FILL if (0) { #else if ( CurBuffer == Reserved->HeaderBuffer ) { IncludedHeaderLength++; // Just bump this length #endif } else { NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) ); Reserved->PreviousTail = NULL; Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer; } } else { CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL); Reserved->PreviousTail = CurBuffer; NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer; Reserved->PaddingBuffer = PaddingBuffer; } #if DBG ++IpxPadCount; #endif } // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 14); #if BACK_FILL BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 14); #else NdisAdjustBufferLength (Reserved->HeaderBuffer, 14); #endif NdisRecalculatePacketCounts (Packet); NdisSend( &Status, Adapter->NdisBindingHandle, Packet); IpxDereferenceAdapter1(Adapter,ADAP_REF_SEND); return Status; } /* IpxSendFrame802_3EthernetII */ NDIS_STATUS IpxSendFrame802_3Snap( IN PADAPTER Adapter, IN PIPX_LOCAL_TARGET LocalTarget, IN PNDIS_PACKET Packet, IN ULONG PacketLength, IN ULONG IncludedHeaderLength ) /*++ Routine Description: This routine constructs a MAC header in a packet and submits it to the appropriate NDIS driver. It is assumed that the first buffer in the packet contains an IPX header at an offset based on the media type. This IPX header is moved around if needed. THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN THE ISN_FRAME_TYPE_SNAP FORMAT. Arguments: Adapter - The adapter on which we are sending. LocalTarget - The local target of the send. Packet - The NDIS packet. PacketLength - The length of the packet, starting at the IPX header. IncludedHeaderLength - The length of the header included in the first buffer that needs to be moved if it does not wind up MacHeaderOffset bytes into the packet. Return Value: None. --*/ { PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved); PUCHAR Header; ULONG TwoBytes; NDIS_STATUS Status; IPX_DEFINE_LOCK_HANDLE(LockHandle) IPX_GET_LOCK (&Adapter->Lock, &LockHandle); if (Adapter->State != ADAPTER_STATE_STOPPING) { IpxReferenceAdapter1(Adapter,ADAP_REF_SEND); IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } else { IPX_FREE_LOCK (&Adapter->Lock, LockHandle); return NDIS_STATUS_FAILURE; } Header = Reserved->Header; #if BACK_FILL BACK_FILL_HEADER(Header, Reserved, 22, Packet); #endif BACK_FILL RtlCopyMemory (Header, LocalTarget->MacAddress, 6); RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6); TwoBytes = PacketLength + 8; Header[14] = 0xaa; Header[15] = 0xaa; Header[16] = 0x03; Header[17] = 0x00; Header[18] = 0x00; Header[19] = 0x00; *(UNALIGNED USHORT *)(&Header[20]) = Adapter->BindSapNetworkOrder; // // Pad odd-length packets if needed. // if (((PacketLength & 1) == 0) && (IpxDevice->EthernetPadToEven)) { PNDIS_BUFFER CurBuffer; PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer; UINT Offset; UINT LastBufferLength; // // Find the tail of the current packet. // CurBuffer = Reserved->HeaderBuffer; while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) { CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer); } // // If the last byte of the last NDIS_BUFFER is not at the end of // the page, then we can simply increase the NDIS_BUFFER ByteCount // by one. // Otherwise, we must use the global padding buffer. // NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength ); if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) { #if BACK_FILL if (0) { #else if ( CurBuffer == Reserved->HeaderBuffer ) { IncludedHeaderLength++; // Just bump this length #endif } else { NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) ); Reserved->PreviousTail = NULL; Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer; } } else { CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL); Reserved->PreviousTail = CurBuffer; NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer; Reserved->PaddingBuffer = PaddingBuffer; } ++TwoBytes; #if DBG ++IpxPadCount; #endif } Header[12] = (UCHAR)(TwoBytes / 256); Header[13] = (UCHAR)(TwoBytes % 256); // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 22); #if BACK_FILL BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 22); #else NdisAdjustBufferLength (Reserved->HeaderBuffer, 22); #endif NdisRecalculatePacketCounts (Packet); NdisSend( &Status, Adapter->NdisBindingHandle, Packet); IpxDereferenceAdapter1(Adapter,ADAP_REF_SEND); return Status; } /* IpxSendFrame802_3Snap */ NDIS_STATUS IpxSendFrame802_5802_2( IN PADAPTER Adapter, IN PIPX_LOCAL_TARGET LocalTarget, IN PNDIS_PACKET Packet, IN ULONG PacketLength, IN ULONG IncludedHeaderLength ) /*++ Routine Description: This routine constructs a MAC header in a packet and submits it to the appropriate NDIS driver. It is assumed that the first buffer in the packet contains an IPX header at an offset based on the media type. This IPX header is moved around if needed. THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_5 FRAMES IN THE ISN_FRAME_TYPE_802_2 FORMAT. Arguments: Adapter - The adapter on which we are sending. LocalTarget - The local target of the send. Packet - The NDIS packet. PacketLength - The length of the packet, starting at the IPX header. IncludedHeaderLength - The length of the header included in the first buffer that needs to be moved if it does not wind up MacHeaderOffset bytes into the packet. Return Value: None. --*/ { PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved); PBINDING Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2]; PUCHAR Header; ULONG HeaderLength; UCHAR SourceRoutingBuffer[18]; PUCHAR SourceRouting; ULONG SourceRoutingLength; NDIS_STATUS Status; ULONG BufferLength; UCHAR DestinationType; IPX_DEFINE_LOCK_HANDLE(LockHandle) IPX_GET_LOCK (&Adapter->Lock, &LockHandle); if (Adapter->State != ADAPTER_STATE_STOPPING) { IpxReferenceAdapter1(Adapter,ADAP_REF_SEND); IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } else { IPX_FREE_LOCK (&Adapter->Lock, LockHandle); return NDIS_STATUS_FAILURE; } Header = Reserved->Header; #if BACK_FILL BACK_FILL_HEADER(Header, Reserved, 17, Packet); #endif BACK_FILL DestinationType = Reserved->DestinationType; if (DestinationType == DESTINATION_DEF) { MacLookupSourceRouting( Reserved->Identifier, Binding, LocalTarget->MacAddress, SourceRoutingBuffer, &SourceRoutingLength); if (SourceRoutingLength != 0) { //PUCHAR IpxHeader = Header + Binding->DefHeaderSize; PUCHAR IpxHeader = Header + MAC_HEADER_SIZE; // // Need to slide the header down to accomodate the SR. // SourceRouting = SourceRoutingBuffer; // RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength); } } else { // // For these packets we assume that the header is in the // right place. // if (!Adapter->SourceRouting) { SourceRoutingLength = 0; } else { if (DestinationType == DESTINATION_BCAST) { if (Binding->AllRouteBroadcast) { SourceRouting = AllRouteSourceRouting; } else { SourceRouting = SingleRouteSourceRouting; } SourceRoutingLength = 2; } else { CTEAssert (DestinationType == DESTINATION_MCAST); if (Binding->AllRouteMulticast) { SourceRouting = AllRouteSourceRouting; } else { SourceRouting = SingleRouteSourceRouting; } SourceRoutingLength = 2; } } #if 0 if (SourceRoutingLength != 0) { PUCHAR IpxHeader = Header + Binding->BcMcHeaderSize; // // Need to slide the header down to accomodate the SR. // RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength); } #endif } Header[0] = TR_PREAMBLE_AC; Header[1] = TR_PREAMBLE_FC; RtlCopyMemory (Header+2, LocalTarget->MacAddress, 6); RtlCopyMemory (Header+8, Adapter->LocalMacAddress.Address, 6); if (SourceRoutingLength != 0) { Header[8] |= TR_SOURCE_ROUTE_FLAG; RtlCopyMemory (Header+14, SourceRouting, SourceRoutingLength); } Header += (14 + SourceRoutingLength); Header[0] = 0xe0; Header[1] = 0xe0; Header[2] = 0x03; HeaderLength = 17; //BufferLength = IncludedHeaderLength + HeaderLength + SourceRoutingLength; BufferLength = HeaderLength + SourceRoutingLength; #if BACK_FILL BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, BufferLength); #else NdisAdjustBufferLength (Reserved->HeaderBuffer, BufferLength); #endif NdisRecalculatePacketCounts (Packet); NdisSend( &Status, Adapter->NdisBindingHandle, Packet); IpxDereferenceAdapter1(Adapter,ADAP_REF_SEND); return Status; } /* IpxSendFrame802_5802_2 */ NDIS_STATUS IpxSendFrame802_5Snap( IN PADAPTER Adapter, IN PIPX_LOCAL_TARGET LocalTarget, IN PNDIS_PACKET Packet, IN ULONG PacketLength, IN ULONG IncludedHeaderLength ) /*++ Routine Description: This routine constructs a MAC header in a packet and submits it to the appropriate NDIS driver. It is assumed that the first buffer in the packet contains an IPX header at an offset based on the media type. This IPX header is moved around if needed. THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_5 FRAMES IN THE ISN_FRAME_TYPE_SNAP FORMAT. Arguments: Adapter - The adapter on which we are sending. LocalTarget - The local target of the send. Packet - The NDIS packet. PacketLength - The length of the packet, starting at the IPX header. IncludedHeaderLength - The length of the header included in the first buffer that needs to be moved if it does not wind up MacHeaderOffset bytes into the packet. Return Value: None. --*/ { PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved); PBINDING Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP]; PUCHAR Header; ULONG HeaderLength; UCHAR SourceRoutingBuffer[18]; PUCHAR SourceRouting; ULONG SourceRoutingLength; NDIS_STATUS Status; ULONG BufferLength; UCHAR DestinationType; IPX_DEFINE_LOCK_HANDLE(LockHandle) IPX_GET_LOCK (&Adapter->Lock, &LockHandle); if (Adapter->State != ADAPTER_STATE_STOPPING) { IpxReferenceAdapter1(Adapter,ADAP_REF_SEND); IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } else { IPX_FREE_LOCK (&Adapter->Lock, LockHandle); return NDIS_STATUS_FAILURE; } Header = Reserved->Header; #if BACK_FILL BACK_FILL_HEADER(Header, Reserved, 22, Packet); #endif BACK_FILL DestinationType = Reserved->DestinationType; if (DestinationType == DESTINATION_DEF) { MacLookupSourceRouting( Reserved->Identifier, Binding, LocalTarget->MacAddress, SourceRoutingBuffer, &SourceRoutingLength); if (SourceRoutingLength != 0) { // PUCHAR IpxHeader = Header + Binding->DefHeaderSize; // // Need to slide the header down to accomodate the SR. // SourceRouting = SourceRoutingBuffer; // RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength); } } else { // // For these packets we assume that the header is in the // right place. // if (!Adapter->SourceRouting) { SourceRoutingLength = 0; } else { if (DestinationType == DESTINATION_BCAST) { if (Binding->AllRouteBroadcast) { SourceRouting = AllRouteSourceRouting; } else { SourceRouting = SingleRouteSourceRouting; } SourceRoutingLength = 2; } else { CTEAssert (DestinationType == DESTINATION_MCAST); if (Binding->AllRouteMulticast) { SourceRouting = AllRouteSourceRouting; } else { SourceRouting = SingleRouteSourceRouting; } SourceRoutingLength = 2; } if (SourceRoutingLength != 0) { // PUCHAR IpxHeader = Header + Binding->BcMcHeaderSize; // // Need to slide the header down to accomodate the SR. // // RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength); } } } Header[0] = TR_PREAMBLE_AC; Header[1] = TR_PREAMBLE_FC; RtlCopyMemory (Header+2, LocalTarget->MacAddress, 6); RtlCopyMemory (Header+8, Adapter->LocalMacAddress.Address, 6); if (SourceRoutingLength != 0) { Header[8] |= TR_SOURCE_ROUTE_FLAG; RtlCopyMemory (Header+14, SourceRouting, SourceRoutingLength); } Header += (14 + SourceRoutingLength); Header[0] = 0xaa; Header[1] = 0xaa; Header[2] = 0x03; Header[3] = 0x00; Header[4] = 0x00; Header[5] = 0x00; *(UNALIGNED USHORT *)(&Header[6]) = Adapter->BindSapNetworkOrder; HeaderLength = 22; //BufferLength = IncludedHeaderLength + HeaderLength + SourceRoutingLength; BufferLength = HeaderLength + SourceRoutingLength; #if BACK_FILL BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, BufferLength); #else NdisAdjustBufferLength (Reserved->HeaderBuffer, BufferLength); #endif NdisRecalculatePacketCounts (Packet); NdisSend( &Status, Adapter->NdisBindingHandle, Packet); IpxDereferenceAdapter1(Adapter,ADAP_REF_SEND); return Status; } /* IpxSendFrame802_5Snap */ NDIS_STATUS IpxSendFrameFddi802_3( IN PADAPTER Adapter, IN PIPX_LOCAL_TARGET LocalTarget, IN PNDIS_PACKET Packet, IN ULONG PacketLength, IN ULONG IncludedHeaderLength ) /*++ Routine Description: This routine constructs a MAC header in a packet and submits it to the appropriate NDIS driver. It is assumed that the first buffer in the packet contains an IPX header at an offset based on the media type. This IPX header is moved around if needed. THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMFDDI FRAMES IN THE ISN_FRAME_TYPE_802_3 FORMAT. Arguments: Adapter - The adapter on which we are sending. LocalTarget - The local target of the send. Packet - The NDIS packet. PacketLength - The length of the packet, starting at the IPX header. IncludedHeaderLength - The length of the header included in the first buffer that needs to be moved if it does not wind up MacHeaderOffset bytes into the packet. Return Value: None. --*/ { PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved); PUCHAR Header; NDIS_STATUS Status; IPX_DEFINE_LOCK_HANDLE(LockHandle) IPX_GET_LOCK (&Adapter->Lock, &LockHandle); if (Adapter->State != ADAPTER_STATE_STOPPING) { IpxReferenceAdapter1(Adapter,ADAP_REF_SEND); IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } else { IPX_FREE_LOCK (&Adapter->Lock, LockHandle); return NDIS_STATUS_FAILURE; } Header = Reserved->Header; #if BACK_FILL BACK_FILL_HEADER(Header, Reserved, 13, Packet); #endif BACK_FILL Header[0] = FDDI_HEADER_BYTE; RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6); RtlCopyMemory (Header+7, Adapter->LocalMacAddress.Address, 6); // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 13); #if BACK_FILL BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 13); #else NdisAdjustBufferLength (Reserved->HeaderBuffer, 13); #endif NdisRecalculatePacketCounts (Packet); NdisSend( &Status, Adapter->NdisBindingHandle, Packet); IpxDereferenceAdapter1(Adapter,ADAP_REF_SEND); return Status; } /* IpxSendFrameFddi802_3 */ NDIS_STATUS IpxSendFrameFddi802_2( IN PADAPTER Adapter, IN PIPX_LOCAL_TARGET LocalTarget, IN PNDIS_PACKET Packet, IN ULONG PacketLength, IN ULONG IncludedHeaderLength ) /*++ Routine Description: This routine constructs a MAC header in a packet and submits it to the appropriate NDIS driver. It is assumed that the first buffer in the packet contains an IPX header at an offset based on the media type. This IPX header is moved around if needed. THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMFDDI FRAMES IN THE ISN_FRAME_TYPE_802_2 FORMAT. Arguments: Adapter - The adapter on which we are sending. LocalTarget - The local target of the send. Packet - The NDIS packet. PacketLength - The length of the packet, starting at the IPX header. IncludedHeaderLength - The length of the header included in the first buffer that needs to be moved if it does not wind up MacHeaderOffset bytes into the packet. Return Value: None. --*/ { PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved); PUCHAR Header; NDIS_STATUS Status; IPX_DEFINE_LOCK_HANDLE(LockHandle) IPX_GET_LOCK (&Adapter->Lock, &LockHandle); if (Adapter->State != ADAPTER_STATE_STOPPING) { IpxReferenceAdapter1(Adapter,ADAP_REF_SEND); IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } else { IPX_FREE_LOCK (&Adapter->Lock, LockHandle); return NDIS_STATUS_FAILURE; } Header = Reserved->Header; #if BACK_FILL BACK_FILL_HEADER(Header, Reserved, 16, Packet); #endif BACK_FILL Header[0] = FDDI_HEADER_BYTE; RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6); RtlCopyMemory (Header+7, Adapter->LocalMacAddress.Address, 6); Header[13] = 0xe0; Header[14] = 0xe0; Header[15] = 0x03; // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 16); #if BACK_FILL BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 16); #else NdisAdjustBufferLength (Reserved->HeaderBuffer, 16); #endif NdisRecalculatePacketCounts (Packet); NdisSend( &Status, Adapter->NdisBindingHandle, Packet); IpxDereferenceAdapter1(Adapter,ADAP_REF_SEND); return Status; } /* IpxSendFrameFddi802_2 */ NDIS_STATUS IpxSendFrameFddiSnap( IN PADAPTER Adapter, IN PIPX_LOCAL_TARGET LocalTarget, IN PNDIS_PACKET Packet, IN ULONG PacketLength, IN ULONG IncludedHeaderLength ) /*++ Routine Description: This routine constructs a MAC header in a packet and submits it to the appropriate NDIS driver. It is assumed that the first buffer in the packet contains an IPX header at an offset based on the media type. This IPX header is moved around if needed. THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMFDDI FRAMES IN THE ISN_FRAME_TYPE_SNAP FORMAT. Arguments: Adapter - The adapter on which we are sending. LocalTarget - The local target of the send. Packet - The NDIS packet. PacketLength - The length of the packet, starting at the IPX header. IncludedHeaderLength - The length of the header included in the first buffer that needs to be moved if it does not wind up MacHeaderOffset bytes into the packet. Return Value: None. --*/ { PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved); PUCHAR Header; NDIS_STATUS Status; IPX_DEFINE_LOCK_HANDLE(LockHandle) IPX_GET_LOCK (&Adapter->Lock, &LockHandle); if (Adapter->State != ADAPTER_STATE_STOPPING) { IpxReferenceAdapter1(Adapter,ADAP_REF_SEND); IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } else { IPX_FREE_LOCK (&Adapter->Lock, LockHandle); return NDIS_STATUS_FAILURE; } Header = Reserved->Header; #if BACK_FILL BACK_FILL_HEADER(Header, Reserved, 21, Packet); #endif BACK_FILL Header[0] = FDDI_HEADER_BYTE; RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6); RtlCopyMemory (Header+7, Adapter->LocalMacAddress.Address, 6); Header[13] = 0xaa; Header[14] = 0xaa; Header[15] = 0x03; Header[16] = 0x00; Header[17] = 0x00; Header[18] = 0x00; *(UNALIGNED USHORT *)(&Header[19]) = Adapter->BindSapNetworkOrder; // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 21); #if BACK_FILL BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 21); #else NdisAdjustBufferLength (Reserved->HeaderBuffer, 21); #endif NdisRecalculatePacketCounts (Packet); NdisSend( &Status, Adapter->NdisBindingHandle, Packet); IpxDereferenceAdapter1(Adapter,ADAP_REF_SEND); return Status; } /* IpxSendFrameFddiSnap */ NDIS_STATUS IpxSendFrameArcnet878_2( IN PADAPTER Adapter, IN PIPX_LOCAL_TARGET LocalTarget, IN PNDIS_PACKET Packet, IN ULONG PacketLength, IN ULONG IncludedHeaderLength ) /*++ Routine Description: This routine constructs a MAC header in a packet and submits it to the appropriate NDIS driver. It is assumed that the first buffer in the packet contains an IPX header at an offset based on the media type. This IPX header is moved around if needed. THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMARCNET878_2 FRAMES IN THE ISN_FRAME_TYPE_802_2 FORMAT. Arguments: Adapter - The adapter on which we are sending. LocalTarget - The local target of the send. Packet - The NDIS packet. PacketLength - The length of the packet, starting at the IPX header. IncludedHeaderLength - The length of the header included in the first buffer that needs to be moved if it does not wind up MacHeaderOffset bytes into the packet. Return Value: None. --*/ { PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved); PUCHAR Header; NDIS_STATUS Status; IPX_DEFINE_LOCK_HANDLE(LockHandle) IPX_GET_LOCK (&Adapter->Lock, &LockHandle); if (Adapter->State != ADAPTER_STATE_STOPPING) { IpxReferenceAdapter1(Adapter,ADAP_REF_SEND); IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } else { IPX_FREE_LOCK (&Adapter->Lock, LockHandle); return NDIS_STATUS_FAILURE; } Header = Reserved->Header; #if BACK_FILL BACK_FILL_HEADER(Header, Reserved, 3, Packet); #endif BACK_FILL // // Convert broadcast address to 0 (the arcnet broadcast). // Header[0] = Adapter->LocalMacAddress.Address[5]; if (LocalTarget->MacAddress[5] == 0xff) { Header[1] = 0x00; } else { Header[1] = LocalTarget->MacAddress[5]; } Header[2] = ARCNET_PROTOCOL_ID; // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 3); #if BACK_FILL BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 3); #else NdisAdjustBufferLength (Reserved->HeaderBuffer, 3); #endif NdisRecalculatePacketCounts (Packet); NdisSend( &Status, Adapter->NdisBindingHandle, Packet); IpxDereferenceAdapter1(Adapter,ADAP_REF_SEND); return Status; } /* IpxSendFrameFddiArcnet878_2 */ NDIS_STATUS IpxSendFrameWanEthernetII( IN PADAPTER Adapter, IN PIPX_LOCAL_TARGET LocalTarget, IN PNDIS_PACKET Packet, IN ULONG PacketLength, IN ULONG IncludedHeaderLength ) /*++ Routine Description: This routine constructs a MAC header in a packet and submits it to the appropriate NDIS driver. It is assumed that the first buffer in the packet contains an IPX header at an offset based on the media type. This IPX header is moved around if needed. THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMWAN FRAMES IN THE ISN_FRAME_TYPE_ETHERNET_II FORMAT. Arguments: Adapter - The adapter on which we are sending. LocalTarget - The local target of the send. Packet - The NDIS packet. PacketLength - The length of the packet, starting at the IPX header. IncludedHeaderLength - The length of the header included in the first buffer that needs to be moved if it does not wind up MacHeaderOffset bytes into the packet. Return Value: None. --*/ { PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved); PUCHAR Header; NDIS_STATUS Status; PBINDING Binding; IPX_DEFINE_LOCK_HANDLE(LockHandle1) IPX_GET_LOCK1(&IpxDevice->BindAccessLock, &LockHandle1); Binding = NIC_ID_TO_BINDING(IpxDevice, NIC_FROM_LOCAL_TARGET(LocalTarget)); IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS); IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1); // // [FW] This will allow both LINE_UP and LINE_CONFIG states // if (Binding->LineUp) { IPX_DEFINE_LOCK_HANDLE(LockHandle) IPX_GET_LOCK (&Adapter->Lock, &LockHandle); if (Adapter->State != ADAPTER_STATE_STOPPING) { IpxReferenceAdapter1(Adapter,ADAP_REF_SEND); IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } else { IPX_FREE_LOCK (&Adapter->Lock, LockHandle); IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS); return NDIS_STATUS_FAILURE; } Header = Reserved->Header; #if BACK_FILL BACK_FILL_HEADER(Header, Reserved, 14, Packet); // // Call UpdateWanInactivity only if this is not a backfill packet, since // SMB server does not do KeepAlives. In case, of backfilled packets, reset // the counter regardless. // if (!Reserved->BackFill) { IpxUpdateWanInactivityCounter( Binding, (IPX_HEADER UNALIGNED *)(Header + IpxDevice->IncludedHeaderOffset), IncludedHeaderLength, Packet, PacketLength); } else { Binding->WanInactivityCounter = 0; } #else // // We do checks to see if we should reset the inactivity // counter. We normally need to check for netbios // session alives, packets from rip, packets from // sap, and ncp keep alives. In fact netbios packets // and rip packets don't come through here. // IpxUpdateWanInactivityCounter( Binding, (IPX_HEADER UNALIGNED *)(Header + IpxDevice->IncludedHeaderOffset), IncludedHeaderLength, Packet, PacketLength); #endif BACK_FILL // // In order for loopback to work properly, we need to put the local MAC address for locally destined // pkts so NdisWAN can loop them back. // if (IPX_NODE_EQUAL(LocalTarget->MacAddress, Binding->LocalAddress.NodeAddress)) { RtlCopyMemory (Header, Binding->LocalMacAddress.Address, 6); } else { RtlCopyMemory (Header, Binding->RemoteMacAddress.Address, 6); } // RtlCopyMemory (Header, Binding->RemoteMacAddress.Address, 6); RtlCopyMemory (Header+6, Binding->LocalMacAddress.Address, 6); *(UNALIGNED USHORT *)(&Header[12]) = Adapter->BindSapNetworkOrder; // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 14); #if BACK_FILL BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 14); #else NdisAdjustBufferLength (Reserved->HeaderBuffer, 14); #endif NdisRecalculatePacketCounts (Packet); NdisSend( &Status, Adapter->NdisBindingHandle, Packet); IpxDereferenceAdapter1(Adapter,ADAP_REF_SEND); IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS); return Status; } else { // // Bug #17273 return proper error message // // return STATUS_DEVICE_DOES_NOT_EXIST; IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS); return STATUS_NETWORK_UNREACHABLE; } } /* IpxSendFrameWanEthernetII */ VOID MacUpdateSourceRouting( IN ULONG Database, IN PADAPTER Adapter, IN PUCHAR MacHeader, IN ULONG MacHeaderLength ) /*++ Routine Description: This routine is called when a valid IPX frame is received from a remote. It gives the source routing database a change to update itself to include information about this remote. Arguments: Database - The "database" to use (IPX, SPX, NB, RIP). Adapter - The adapter the frame was received on. MacHeader - The MAC header of the received frame. MacHeaderLength - The length of the MAC header. Return Value: None. --*/ { PSOURCE_ROUTE Current; ULONG Hash; LONG Result; IPX_DEFINE_LOCK_HANDLE (LockHandle) CTEAssert (((LONG)Database >= 0) && (Database <= 3)); // // If this adapter is configured for no source routing, don't // need to do anything. // if (!Adapter->SourceRouting) { return; } // // See if this source routing is relevant. We don't // care about two-byte source routing since that // indicates it did not cross a router. If there // is nothing in the database, then don't add // this if it is minimal (if it is not, we need // to add it so we will find it on sending). // if ((Adapter->SourceRoutingEmpty[Database]) && (MacHeaderLength <= 16)) { return; } IPX_GET_LOCK (&Adapter->Lock, &LockHandle); // // Try to find this address in the database. // Hash = MacSourceRoutingHash (MacHeader+8); Current = Adapter->SourceRoutingHeads[Database][Hash]; while (Current != (PSOURCE_ROUTE)NULL) { IPX_NODE_COMPARE (MacHeader+8, Current->MacAddress, &Result); if (Result == 0) { // // We found routing for this node. If the data is the // same as what we have, update the time since used to // prevent aging. // if ((Current->SourceRoutingLength == MacHeaderLength-14) && (RtlEqualMemory (Current->SourceRouting, MacHeader+14, MacHeaderLength-14))) { Current->TimeSinceUsed = 0; } IPX_FREE_LOCK (&Adapter->Lock, LockHandle); return; } else { Current = Current->Next; } } // // Not found, insert a new node at the front of the list. // Current = (PSOURCE_ROUTE)IpxAllocateMemory (SOURCE_ROUTE_SIZE(MacHeaderLength-14), MEMORY_SOURCE_ROUTE, "SourceRouting"); if (Current == (PSOURCE_ROUTE)NULL) { IPX_FREE_LOCK (&Adapter->Lock, LockHandle); return; } Current->Next = Adapter->SourceRoutingHeads[Database][Hash]; Adapter->SourceRoutingHeads[Database][Hash] = Current; Adapter->SourceRoutingEmpty[Database] = FALSE; RtlCopyMemory (Current->MacAddress, MacHeader+8, 6); Current->MacAddress[0] &= 0x7f; Current->SourceRoutingLength = (UCHAR)(MacHeaderLength - 14); RtlCopyMemory (Current->SourceRouting, MacHeader+14, MacHeaderLength - 14); Current->TimeSinceUsed = 0; IPX_DEBUG (SOURCE_ROUTE, ("Adding source route %lx for %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n", Current, Current->MacAddress[0], Current->MacAddress[1], Current->MacAddress[2], Current->MacAddress[3], Current->MacAddress[4], Current->MacAddress[5])); IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } /* MacUpdateSourceRouting */ VOID MacLookupSourceRouting( IN ULONG Database, IN PBINDING Binding, IN UCHAR MacAddress[6], IN OUT UCHAR SourceRouting[18], OUT PULONG SourceRoutingLength ) /*++ Routine Description: This routine looks up a target address in the adapter's source routing database to see if source routing information needs to be added to the frame. Arguments: Database - The "database" to use (IPX, SPX, NB, RIP). Binding - The binding the frame is being sent on. MacAddress - The destination address. SourceRouting - Buffer to hold the returned source routing info. SourceRoutingLength - The returned source routing length. Return Value: None. --*/ { PSOURCE_ROUTE Current; PADAPTER Adapter = Binding->Adapter; ULONG Hash; LONG Result; IPX_DEFINE_LOCK_HANDLE (LockHandle) // // If this adapter is configured for no source routing, don't // insert any. // if (!Adapter->SourceRouting) { *SourceRoutingLength = 0; return; } // // See if source routing has not been important so far. // // This is wrong because we may be sending a directed // packet to somebody on the other side of a router, without // ever having received a routed packet. We fix this for the // moment by only setting SourceRoutingEmpty for netbios // which uses broadcasts for discovery. // if (Adapter->SourceRoutingEmpty[Database]) { *SourceRoutingLength = 0; return; } Hash = MacSourceRoutingHash (MacAddress); IPX_GET_LOCK (&Adapter->Lock, &LockHandle); Current = Adapter->SourceRoutingHeads[Database][Hash]; while (Current != (PSOURCE_ROUTE)NULL) { IPX_NODE_COMPARE (MacAddress, Current->MacAddress, &Result); if (Result == 0) { // // We found routing for this node. // if (Current->SourceRoutingLength <= 2) { *SourceRoutingLength = 0; } else { RtlCopyMemory (SourceRouting, Current->SourceRouting, Current->SourceRoutingLength); SourceRouting[0] = (SourceRouting[0] & TR_LENGTH_MASK); SourceRouting[1] = (SourceRouting[1] ^ TR_DIRECTION_MASK); *SourceRoutingLength = Current->SourceRoutingLength; } IPX_FREE_LOCK (&Adapter->Lock, LockHandle); return; } else { Current = Current->Next; } } IPX_FREE_LOCK (&Adapter->Lock, LockHandle); // // We did not find this node, use the default. // if (Binding->AllRouteDirected) { RtlCopyMemory (SourceRouting, AllRouteSourceRouting, 2); } else { RtlCopyMemory (SourceRouting, SingleRouteSourceRouting, 2); } *SourceRoutingLength = 2; } /* MacLookupSourceRouting */ VOID MacSourceRoutingTimeout( CTEEvent * Event, PVOID Context ) /*++ Routine Description: This routine is called when the source routing timer expires. It is called every minute. Arguments: Event - The event used to queue the timer. Context - The context, which is the device pointer. Return Value: None. --*/ { PDEVICE Device = (PDEVICE)Context; PADAPTER Adapter; PBINDING Binding; PSOURCE_ROUTE Current, OldCurrent, Previous; UINT i, j, k; IPX_DEFINE_LOCK_HANDLE (LockHandle) IPX_DEFINE_LOCK_HANDLE(LockHandle1) // // Get a lock on the access path. // IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1); ++Device->SourceRoutingTime; { ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings); for (i = FIRST_REAL_BINDING; i <= Index; i++) { if (Binding = NIC_ID_TO_BINDING(Device, i)) { Adapter = Binding->Adapter; if (Adapter->LastSourceRoutingTime != Device->SourceRoutingTime) { // // We need to scan this adapter's source routing // tree for stale routes. To simplify the scan we // only delete entries that have at least one // child that is NULL. // Adapter->LastSourceRoutingTime = Device->SourceRoutingTime; for (j = 0; j < IDENTIFIER_TOTAL; j++) { for (k = 0; k < SOURCE_ROUTE_HASH_SIZE; k++) { if (Adapter->SourceRoutingHeads[j][k] == (PSOURCE_ROUTE)NULL) { continue; } IPX_GET_LOCK (&Adapter->Lock, &LockHandle); Current = Adapter->SourceRoutingHeads[j][k]; Previous = (PSOURCE_ROUTE)NULL; while (Current != (PSOURCE_ROUTE)NULL) { ++Current->TimeSinceUsed; if (Current->TimeSinceUsed >= Device->SourceRouteUsageTime) { // // A stale entry needs to be aged. // if (Previous) { Previous->Next = Current->Next; } else { Adapter->SourceRoutingHeads[j][k] = Current->Next; } OldCurrent = Current; Current = Current->Next; IPX_DEBUG (SOURCE_ROUTE, ("Aging out source-route entry %lx\n", OldCurrent)); IpxFreeMemory (OldCurrent, SOURCE_ROUTE_SIZE (OldCurrent->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting"); } else { Previous = Current; Current = Current->Next; } } IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } // for loop through the database's hash list } // for loop through the adapter's four databases } // if adapter's database needs to be checked } // if binding exists } // for loop through every binding } IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1); // // Now restart the timer unless we should not (which means // we are being unloaded). // if (Device->SourceRoutingUsed) { CTEStartTimer( &Device->SourceRoutingTimer, 60000, // one minute timeout MacSourceRoutingTimeout, (PVOID)Device); } else { IpxDereferenceDevice (Device, DREF_SR_TIMER); } } /* MacSourceRoutingTimeout */ VOID MacSourceRoutingRemove( IN PBINDING Binding, IN UCHAR MacAddress[6] ) /*++ Routine Description: This routine is called by the IPX action handler when an IPXROUTE use has specified that source routing for a given MAC address should be removed. Arguments: Binding - The binding to modify. MacAddress - The MAC address to remove. Return Value: None. --*/ { PSOURCE_ROUTE Current, Previous; PADAPTER Adapter = Binding->Adapter; ULONG Hash; ULONG Database; LONG Result; IPX_DEFINE_LOCK_HANDLE (LockHandle) // // Scan through to find the matching entry in each database. // Hash = MacSourceRoutingHash (MacAddress); IPX_GET_LOCK (&Adapter->Lock, &LockHandle); for (Database = 0; Database < IDENTIFIER_TOTAL; Database++) { Current = Adapter->SourceRoutingHeads[Database][Hash]; Previous = NULL; while (Current != (PSOURCE_ROUTE)NULL) { IPX_NODE_COMPARE (MacAddress, Current->MacAddress, &Result); if (Result == 0) { if (Previous) { Previous->Next = Current->Next; } else { Adapter->SourceRoutingHeads[Database][Hash] = Current->Next; } IPX_DEBUG (SOURCE_ROUTE, ("IPXROUTE freeing source-route entry %lx\n", Current)); IpxFreeMemory (Current, SOURCE_ROUTE_SIZE (Current->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting"); break; } else { Previous = Current; Current = Current->Next; } } } IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } /* MacSourceRoutingRemove */ VOID MacSourceRoutingClear( IN PBINDING Binding ) /*++ Routine Description: This routine is called by the IPX action handler when an IPXROUTE use has specified that source routing for a given binding should be cleared entirely. Arguments: Binding - The binding to be cleared. MacAddress - The MAC address to remove. Return Value: None. --*/ { PSOURCE_ROUTE Current; PADAPTER Adapter = Binding->Adapter; ULONG Database, Hash; IPX_DEFINE_LOCK_HANDLE (LockHandle) // // Scan through and remove every entry in the database. // IPX_GET_LOCK (&Adapter->Lock, &LockHandle); for (Database = 0; Database < IDENTIFIER_TOTAL; Database++) { for (Hash = 0; Hash < SOURCE_ROUTE_HASH_SIZE; Hash++) { while (Adapter->SourceRoutingHeads[Database][Hash]) { Current = Adapter->SourceRoutingHeads[Database][Hash]; Adapter->SourceRoutingHeads[Database][Hash] = Current->Next; IpxFreeMemory (Current, SOURCE_ROUTE_SIZE (Current->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting"); } } } IPX_FREE_LOCK (&Adapter->Lock, LockHandle); } /* MacSourceRoutingClear */