/*++ Copyright (c) 1989-1993 Microsoft Corporation Module Name: spxpkt.c Abstract: This module contains code that builds various spx packets. Author: Nikhil Kamkolkar (nikhilk) 11-November-1993 Environment: Kernel mode Revision History: --*/ #include "precomp.h" #pragma hdrstop // Define module number for event logging entries #define FILENUM SPXPKT VOID SpxPktBuildCr( IN PSPX_CONN_FILE pSpxConnFile, IN PSPX_ADDR pSpxAddr, IN OUT PNDIS_PACKET * ppPkt, IN USHORT State, IN BOOLEAN fSpx2 ) /*++ Routine Description: NOTE: If *ppPkt is NULL, we allocate a packet. If not, we just recreate the data and don't update the packet's state. Arguments: Return Value: --*/ { PNDIS_PACKET pCrPkt; PSPX_SEND_RESD pSendResd; NDIS_STATUS ndisStatus; PIPXSPX_HDR pIpxSpxHdr; PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr; if (*ppPkt == NULL) { SpxAllocSendPacket(SpxDevice, &pCrPkt, &ndisStatus); if (ndisStatus != NDIS_STATUS_SUCCESS) { DBGPRINT(CONNECT, ERR, ("SpxConnHandleConnReq: Could not allocate ndis packet\n")); return; } } else { pCrPkt = *ppPkt; } pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pCrPkt + NDIS_PACKET_SIZE + sizeof(SPX_SEND_RESD) + IpxInclHdrOffset); NdisQueryPacket(pCrPkt, NULL, NULL, &pNdisMacHdr, NULL); pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr); if (!fSpx2) { NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE); } SpxBuildIpxHdr( pIpxSpxHdr, MIN_IPXSPX_HDRSIZE, pSpxConnFile->scf_RemAddr, pSpxAddr->sa_Socket); // Build SPX Header. pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_ACK | (fSpx2 ? (SPX_CC_SPX2 | SPX_CC_NEG) : 0)); pIpxSpxHdr->hdr_DataType = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SrcConnId, pSpxConnFile->scf_LocalConnId); pIpxSpxHdr->hdr_DestConnId = 0xFFFF; pIpxSpxHdr->hdr_SeqNum = 0; pIpxSpxHdr->hdr_AckNum = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AllocNum, pSpxConnFile->scf_SentAllocNum); // Initialize if (*ppPkt == NULL) { pSendResd = (PSPX_SEND_RESD)(pCrPkt->ProtocolReserved); pSendResd->sr_Id = IDENTIFIER_SPX; pSendResd->sr_Type = SPX_TYPE_CR; pSendResd->sr_Reserved1 = NULL; pSendResd->sr_Reserved2 = NULL; pSendResd->sr_State = State; pSendResd->sr_ConnFile = pSpxConnFile; pSendResd->sr_Request = NULL; pSendResd->sr_Next = NULL; pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX_HDRSIZE; *ppPkt = pCrPkt; } return; } VOID SpxPktBuildCrAck( IN PSPX_CONN_FILE pSpxConnFile, IN PSPX_ADDR pSpxAddr, OUT PNDIS_PACKET * ppPkt, IN USHORT State, IN BOOLEAN fNeg, IN BOOLEAN fSpx2 ) /*++ Routine Description: Arguments: Return Value: --*/ { PNDIS_PACKET pCrAckPkt; PSPX_SEND_RESD pSendResd; PIPXSPX_HDR pIpxSpxHdr; NDIS_STATUS ndisStatus; USHORT hdrLen; PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr; *ppPkt = NULL; SpxAllocSendPacket(SpxDevice, &pCrAckPkt, &ndisStatus); if (ndisStatus != NDIS_STATUS_SUCCESS) { DBGPRINT(CONNECT, ERR, ("SpxConnHandleConnReq: Could not allocate ndis packet\n")); return; } pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pCrAckPkt + NDIS_PACKET_SIZE + sizeof(SPX_SEND_RESD) + IpxInclHdrOffset); hdrLen = (SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE); NdisQueryPacket(pCrAckPkt, NULL, NULL, &pNdisMacHdr, NULL); pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr); if (!SPX2_CONN(pSpxConnFile)) { NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE); } SpxBuildIpxHdr( pIpxSpxHdr, hdrLen, pSpxConnFile->scf_RemAddr, pSpxAddr->sa_Socket); pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | (fSpx2 ? SPX_CC_SPX2 : 0) | (fNeg ? SPX_CC_NEG : 0)); pIpxSpxHdr->hdr_DataType = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SrcConnId, pSpxConnFile->scf_LocalConnId); pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId; pIpxSpxHdr->hdr_SeqNum = 0; pIpxSpxHdr->hdr_AckNum = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AllocNum, pSpxConnFile->scf_SentAllocNum); if (SPX2_CONN(pSpxConnFile)) { DBGPRINT(CONNECT, DBG, ("SpxConnBuildCrAck: Spx2 packet size %d.%lx\n", pSpxConnFile->scf_MaxPktSize)); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_NegSize, pSpxConnFile->scf_MaxPktSize); } pSendResd = (PSPX_SEND_RESD)(pCrAckPkt->ProtocolReserved); pSendResd->sr_Id = IDENTIFIER_SPX; pSendResd->sr_Type = SPX_TYPE_CRACK; pSendResd->sr_Reserved1 = NULL; pSendResd->sr_Reserved2 = NULL; pSendResd->sr_State = State; pSendResd->sr_ConnFile = pSpxConnFile; pSendResd->sr_Request = NULL; pSendResd->sr_Next = NULL; pSendResd->sr_Len = pSendResd->sr_HdrLen = hdrLen; *ppPkt = pCrAckPkt; return; } VOID SpxPktBuildSn( IN PSPX_CONN_FILE pSpxConnFile, OUT PNDIS_PACKET * ppPkt, IN USHORT State ) /*++ Routine Description: Arguments: Return Value: --*/ { PNDIS_PACKET pPkt; PSPX_SEND_RESD pSendResd; PNDIS_BUFFER pBuf; NDIS_STATUS ndisStatus; PIPXSPX_HDR pIpxSpxHdr; PBYTE pData; do { *ppPkt = NULL; // Allocate a ndis packet for the cr. SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } CTEAssert(pSpxConnFile->scf_MaxPktSize != 0); DBGPRINT(SEND, DBG, ("SpxPktBuildSn: Data size %lx\n", pSpxConnFile->scf_MaxPktSize)); if ((pData = SpxAllocateMemory( pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE)) == NULL) { SpxPktSendRelease(pPkt); break; } // Build ndis buffer desc NdisAllocateBuffer( &ndisStatus, &pBuf, SpxDevice->dev_NdisBufferPoolHandle, pData, pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE); if (ndisStatus != NDIS_STATUS_SUCCESS) { SpxPktSendRelease(pPkt); SpxFreeMemory(pData); break; } // Chain at back. NdisChainBufferAtBack( pPkt, pBuf); pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt + NDIS_PACKET_SIZE + sizeof(SPX_SEND_RESD) + IpxInclHdrOffset); SpxBuildIpxHdr( pIpxSpxHdr, pSpxConnFile->scf_MaxPktSize, pSpxConnFile->scf_RemAddr, pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket); // Build SPX Header. pIpxSpxHdr->hdr_ConnCtrl = ( SPX_CC_SYS | SPX_CC_ACK | SPX_CC_NEG | SPX_CC_SPX2); pIpxSpxHdr->hdr_DataType = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SrcConnId, pSpxConnFile->scf_LocalConnId); pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId; pIpxSpxHdr->hdr_SeqNum = 0; pIpxSpxHdr->hdr_AckNum = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AllocNum, pSpxConnFile->scf_SentAllocNum); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_NegSize, pSpxConnFile->scf_MaxPktSize); // Init the data part to indicate no neg values *(UNALIGNED ULONG *)pData = 0; pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved); pSendResd->sr_Id = IDENTIFIER_SPX; pSendResd->sr_Type = SPX_TYPE_SN; pSendResd->sr_Reserved1 = NULL; pSendResd->sr_Reserved2 = NULL; pSendResd->sr_State = (State | SPX_SENDPKT_FREEDATA); pSendResd->sr_ConnFile = pSpxConnFile; pSendResd->sr_Request = NULL; pSendResd->sr_Next = NULL; pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE; pSendResd->sr_Len = pSpxConnFile->scf_MaxPktSize; *ppPkt = pPkt; } while (FALSE); return; } VOID SpxPktBuildSnAck( IN PSPX_CONN_FILE pSpxConnFile, OUT PNDIS_PACKET * ppPkt, IN USHORT State ) /*++ Routine Description: Arguments: Return Value: --*/ { PNDIS_PACKET pPkt; NDIS_STATUS ndisStatus; PIPXSPX_HDR pIpxSpxHdr; PSPX_SEND_RESD pSendResd; do { *ppPkt = NULL; // Allocate a ndis packet for the cr. SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt + NDIS_PACKET_SIZE + sizeof(SPX_SEND_RESD) + IpxInclHdrOffset); SpxBuildIpxHdr( pIpxSpxHdr, MIN_IPXSPX2_HDRSIZE, pSpxConnFile->scf_RemAddr, pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket); // Build SPX Header. pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2); pIpxSpxHdr->hdr_DataType = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SrcConnId, pSpxConnFile->scf_LocalConnId); pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId; pIpxSpxHdr->hdr_SeqNum = 0; pIpxSpxHdr->hdr_AckNum = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AllocNum, pSpxConnFile->scf_SentAllocNum); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_NegSize, pSpxConnFile->scf_MaxPktSize); pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved); pSendResd->sr_Id = IDENTIFIER_SPX; pSendResd->sr_Type = SPX_TYPE_SNACK; pSendResd->sr_Reserved1 = NULL; pSendResd->sr_Reserved2 = NULL; pSendResd->sr_State = State; pSendResd->sr_ConnFile = pSpxConnFile; pSendResd->sr_Request = NULL; pSendResd->sr_Next = NULL; pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE; *ppPkt = pPkt; } while (FALSE); return; } VOID SpxPktBuildSs( IN PSPX_CONN_FILE pSpxConnFile, OUT PNDIS_PACKET * ppPkt, IN USHORT State ) /*++ Routine Description: Arguments: Return Value: --*/ { PNDIS_PACKET pPkt; PSPX_SEND_RESD pSendResd; PNDIS_BUFFER pBuf; NDIS_STATUS ndisStatus; PIPXSPX_HDR pIpxSpxHdr; PBYTE pData; do { *ppPkt = NULL; // Allocate a ndis packet for the cr. SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } CTEAssert(pSpxConnFile->scf_MaxPktSize != 0); DBGPRINT(SEND, DBG, ("SpxPktBuildSs: Data size %lx\n", pSpxConnFile->scf_MaxPktSize)); if ((pData = SpxAllocateMemory( pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE)) == NULL) { SpxPktSendRelease(pPkt); break; } // Build ndis buffer desc NdisAllocateBuffer( &ndisStatus, &pBuf, SpxDevice->dev_NdisBufferPoolHandle, pData, pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE); if (ndisStatus != NDIS_STATUS_SUCCESS) { SpxPktSendRelease(pPkt); SpxFreeMemory(pData); break; } // Chain at back. NdisChainBufferAtBack( pPkt, pBuf); pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt + NDIS_PACKET_SIZE + sizeof(SPX_SEND_RESD) + IpxInclHdrOffset); SpxBuildIpxHdr( pIpxSpxHdr, pSpxConnFile->scf_MaxPktSize, pSpxConnFile->scf_RemAddr, pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket); // Build SPX Header. pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_ACK | SPX_CC_SPX2 | ((pSpxConnFile->scf_Flags & SPX_CONNFILE_NEG) ? SPX_CC_NEG : 0)); pIpxSpxHdr->hdr_DataType = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SrcConnId, pSpxConnFile->scf_LocalConnId); pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId; pIpxSpxHdr->hdr_SeqNum = 0; pIpxSpxHdr->hdr_AckNum = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AllocNum, pSpxConnFile->scf_SentAllocNum); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_NegSize, pSpxConnFile->scf_MaxPktSize); // Init the data part to indicate no neg values *(UNALIGNED ULONG *)pData = 0; pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved); pSendResd->sr_Id = IDENTIFIER_SPX; pSendResd->sr_Type = SPX_TYPE_SS; pSendResd->sr_Reserved1 = NULL; pSendResd->sr_Reserved2 = NULL; pSendResd->sr_State = (State | SPX_SENDPKT_FREEDATA); pSendResd->sr_ConnFile = pSpxConnFile; pSendResd->sr_Request = NULL; pSendResd->sr_Next = NULL; pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE; pSendResd->sr_Len = pSpxConnFile->scf_MaxPktSize; *ppPkt = pPkt; } while (FALSE); return; } VOID SpxPktBuildSsAck( IN PSPX_CONN_FILE pSpxConnFile, OUT PNDIS_PACKET * ppPkt, IN USHORT State ) /*++ Routine Description: Arguments: Return Value: --*/ { PNDIS_PACKET pPkt; NDIS_STATUS ndisStatus; PIPXSPX_HDR pIpxSpxHdr; PSPX_SEND_RESD pSendResd; do { *ppPkt = NULL; // Allocate a ndis packet for the cr. SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt + NDIS_PACKET_SIZE + sizeof(SPX_SEND_RESD) + IpxInclHdrOffset); SpxBuildIpxHdr( pIpxSpxHdr, MIN_IPXSPX2_HDRSIZE, pSpxConnFile->scf_RemAddr, pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket); // Build SPX Header. pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_SPX2 | ((pSpxConnFile->scf_Flags & SPX_CONNFILE_NEG) ? SPX_CC_NEG : 0)); pIpxSpxHdr->hdr_DataType = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SrcConnId, pSpxConnFile->scf_LocalConnId); pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId; pIpxSpxHdr->hdr_SeqNum = 0; pIpxSpxHdr->hdr_AckNum = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AllocNum, pSpxConnFile->scf_SentAllocNum); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_NegSize, pSpxConnFile->scf_MaxPktSize); pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved); pSendResd->sr_Id = IDENTIFIER_SPX; pSendResd->sr_Type = SPX_TYPE_SSACK; pSendResd->sr_Reserved1 = NULL; pSendResd->sr_Reserved2 = NULL; pSendResd->sr_State = State; pSendResd->sr_ConnFile = pSpxConnFile; pSendResd->sr_Request = NULL; pSendResd->sr_Next = NULL; pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE; *ppPkt = pPkt; } while (FALSE); return; } VOID SpxPktBuildRr( IN PSPX_CONN_FILE pSpxConnFile, OUT PNDIS_PACKET * ppPkt, IN USHORT SeqNum, IN USHORT State ) /*++ Routine Description: Arguments: Return Value: --*/ { PNDIS_PACKET pPkt; PSPX_SEND_RESD pSendResd; PNDIS_BUFFER pBuf; NDIS_STATUS ndisStatus; PIPXSPX_HDR pIpxSpxHdr; PBYTE pData; do { *ppPkt = NULL; // Allocate a ndis packet for the cr. SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } if ((pData = SpxAllocateMemory( pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE)) == NULL) { SpxPktSendRelease(pPkt); break; } // Build ndis buffer desc NdisAllocateBuffer( &ndisStatus, &pBuf, SpxDevice->dev_NdisBufferPoolHandle, pData, pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE); if (ndisStatus != NDIS_STATUS_SUCCESS) { SpxPktSendRelease(pPkt); SpxFreeMemory(pData); break; } // Chain at back. NdisChainBufferAtBack( pPkt, pBuf); pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt + NDIS_PACKET_SIZE + sizeof(SPX_SEND_RESD) + IpxInclHdrOffset); SpxBuildIpxHdr( pIpxSpxHdr, pSpxConnFile->scf_MaxPktSize, pSpxConnFile->scf_RemAddr, pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket); // Build SPX Header. pIpxSpxHdr->hdr_ConnCtrl = ( SPX_CC_SYS | SPX_CC_ACK | SPX_CC_NEG | SPX_CC_SPX2); pIpxSpxHdr->hdr_DataType = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SrcConnId, pSpxConnFile->scf_LocalConnId); pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId; // For a renegotiate request, we use the sequence number of // the first waiting data packet. Passed in. PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SeqNum, SeqNum); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AckNum, pSpxConnFile->scf_RecvSeqNum); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AllocNum, pSpxConnFile->scf_SentAllocNum); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_NegSize, pSpxConnFile->scf_MaxPktSize); // Init the data part to indicate no neg values *(UNALIGNED ULONG *)pData = 0; pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved); pSendResd->sr_Id = IDENTIFIER_SPX; pSendResd->sr_Type = SPX_TYPE_RR; pSendResd->sr_Reserved1 = NULL; pSendResd->sr_Reserved2 = NULL; pSendResd->sr_State = (State | SPX_SENDPKT_FREEDATA); pSendResd->sr_ConnFile = pSpxConnFile; pSendResd->sr_Request = NULL; pSendResd->sr_Next = NULL; pSendResd->sr_SeqNum = SeqNum; pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE; pSendResd->sr_Len = pSpxConnFile->scf_MaxPktSize; *ppPkt = pPkt; } while (FALSE); return; } VOID SpxPktBuildRrAck( IN PSPX_CONN_FILE pSpxConnFile, OUT PNDIS_PACKET * ppPkt, IN USHORT State, IN USHORT MaxPktSize ) /*++ Routine Description: Arguments: Return Value: --*/ { PNDIS_PACKET pPkt; NDIS_STATUS ndisStatus; PIPXSPX_HDR pIpxSpxHdr; PSPX_SEND_RESD pSendResd; do { *ppPkt = NULL; // Allocate a ndis packet for the cr. SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt + NDIS_PACKET_SIZE + sizeof(SPX_SEND_RESD) + IpxInclHdrOffset); SpxBuildIpxHdr( pIpxSpxHdr, MIN_IPXSPX2_HDRSIZE, pSpxConnFile->scf_RemAckAddr, pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket); // Build SPX Header. pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2); pIpxSpxHdr->hdr_DataType = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SrcConnId, pSpxConnFile->scf_LocalConnId); pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SeqNum, pSpxConnFile->scf_SendSeqNum); // For the RrAck, ack number will be the appropriate number // for the last data packet received. PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AckNum, pSpxConnFile->scf_RenegAckAckNum); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AllocNum, pSpxConnFile->scf_SentAllocNum); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_NegSize, MaxPktSize); DBGPRINT(SEND, DBG3, ("SpxPktBuildRrAck: SEQ %lx ACKNUM %lx ALLOCNUM %lx MAXPKT %lx\n", pSpxConnFile->scf_SendSeqNum, pSpxConnFile->scf_RenegAckAckNum, pSpxConnFile->scf_SentAllocNum, MaxPktSize)); pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved); pSendResd->sr_Id = IDENTIFIER_SPX; pSendResd->sr_Type = SPX_TYPE_RRACK; pSendResd->sr_Reserved1 = NULL; pSendResd->sr_Reserved2 = NULL; pSendResd->sr_State = State; pSendResd->sr_ConnFile = pSpxConnFile; pSendResd->sr_Request = NULL; pSendResd->sr_Next = NULL; pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE; *ppPkt = pPkt; } while (FALSE); return; } VOID SpxPktBuildDisc( IN PSPX_CONN_FILE pSpxConnFile, IN PREQUEST pRequest, OUT PNDIS_PACKET * ppPkt, IN USHORT State, IN UCHAR DataType ) /*++ Routine Description: Arguments: Return Value: --*/ { PSPX_SEND_RESD pSendResd; PNDIS_PACKET pDiscPkt; NDIS_STATUS ndisStatus; PIPXSPX_HDR pIpxSpxHdr; USHORT hdrLen; PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr; *ppPkt = NULL; SpxAllocSendPacket(SpxDevice, &pDiscPkt, &ndisStatus); if (ndisStatus == NDIS_STATUS_SUCCESS) { pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pDiscPkt + NDIS_PACKET_SIZE + sizeof(SPX_SEND_RESD) + IpxInclHdrOffset); hdrLen = SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE; NdisQueryPacket(pDiscPkt, NULL, NULL, &pNdisMacHdr, NULL); pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr); if (!SPX2_CONN(pSpxConnFile)) { NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE); } SpxBuildIpxHdr( pIpxSpxHdr, hdrLen, pSpxConnFile->scf_RemAddr, pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket); // Build SPX Header. pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_ACK | (SPX2_CONN(pSpxConnFile) ? SPX_CC_SPX2 : 0) | ((DataType == SPX2_DT_IDISC) ? 0 : SPX_CC_EOM)); pIpxSpxHdr->hdr_DataType = DataType; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SrcConnId, pSpxConnFile->scf_LocalConnId); pIpxSpxHdr->hdr_DestConnId = *((UNALIGNED USHORT *)&pSpxConnFile->scf_RemConnId); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SeqNum, pSpxConnFile->scf_SendSeqNum); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AckNum, pSpxConnFile->scf_RecvSeqNum); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AllocNum, pSpxConnFile->scf_SentAllocNum); if (SPX2_CONN(pSpxConnFile)) { PUTSHORT2SHORT( &pIpxSpxHdr->hdr_NegSize, pSpxConnFile->scf_MaxPktSize); } pSendResd = (PSPX_SEND_RESD)(pDiscPkt->ProtocolReserved); pSendResd->sr_Id = IDENTIFIER_SPX; pSendResd->sr_State = State; pSendResd->sr_Reserved1 = NULL; pSendResd->sr_Reserved2 = NULL; pSendResd->sr_Type = ((DataType == SPX2_DT_IDISC) ? SPX_TYPE_IDISC : SPX_TYPE_ORDREL); pSendResd->sr_Next = NULL; pSendResd->sr_Request = pRequest; pSendResd->sr_ConnFile = pSpxConnFile; pSendResd->sr_Offset = 0; pSendResd->sr_SeqNum = pSpxConnFile->scf_SendSeqNum; pSendResd->sr_Len = pSendResd->sr_HdrLen = hdrLen; *ppPkt = pDiscPkt; } return; } VOID SpxPktBuildProbe( IN PSPX_CONN_FILE pSpxConnFile, OUT PNDIS_PACKET * ppPkt, IN USHORT State, IN BOOLEAN fSpx2 ) /*++ Routine Description: Arguments: Return Value: --*/ { PSPX_SEND_RESD pSendResd; PNDIS_PACKET pProbe; NDIS_STATUS ndisStatus; PIPXSPX_HDR pIpxSpxHdr; USHORT hdrLen; PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr; *ppPkt = NULL; SpxAllocSendPacket(SpxDevice, &pProbe, &ndisStatus); if (ndisStatus == NDIS_STATUS_SUCCESS) { pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pProbe + NDIS_PACKET_SIZE + sizeof(SPX_SEND_RESD) + IpxInclHdrOffset); hdrLen = (fSpx2 ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE); NdisQueryPacket(pProbe, NULL, NULL, &pNdisMacHdr, NULL); pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr); if (!fSpx2) { NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE); } SpxBuildIpxHdr( pIpxSpxHdr, hdrLen, pSpxConnFile->scf_RemAddr, pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket); // Build SPX Header. pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_ACK | (fSpx2 ? SPX_CC_SPX2 : 0)); pIpxSpxHdr->hdr_DataType = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SrcConnId, pSpxConnFile->scf_LocalConnId); pIpxSpxHdr->hdr_DestConnId = *((UNALIGNED USHORT *)&pSpxConnFile->scf_RemConnId); if (fSpx2) { pIpxSpxHdr->hdr_SeqNum = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_NegSize, pSpxConnFile->scf_MaxPktSize); } else { PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SeqNum, pSpxConnFile->scf_SendSeqNum); } PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AckNum, pSpxConnFile->scf_RecvSeqNum); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AllocNum, pSpxConnFile->scf_SentAllocNum); pSendResd = (PSPX_SEND_RESD)(pProbe->ProtocolReserved); pSendResd->sr_Id = IDENTIFIER_SPX; pSendResd->sr_Type = SPX_TYPE_PROBE; pSendResd->sr_Reserved1 = NULL; pSendResd->sr_Reserved2 = NULL; pSendResd->sr_State = State; pSendResd->sr_Next = NULL; pSendResd->sr_Request = NULL; pSendResd->sr_ConnFile = pSpxConnFile; pSendResd->sr_Len = pSendResd->sr_HdrLen = (fSpx2 ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE); *ppPkt = pProbe; } return; } VOID SpxPktBuildData( IN PSPX_CONN_FILE pSpxConnFile, OUT PNDIS_PACKET * ppPkt, IN USHORT State, IN USHORT Length ) /*++ Routine Description: Handles zero length sends. Arguments: Return Value: --*/ { PNDIS_BUFFER pNdisBuffer; PSPX_SEND_RESD pSendResd; PNDIS_PACKET pDataPkt; NDIS_STATUS ndisStatus; PIPXSPX_HDR pIpxSpxHdr; USHORT hdrLen; PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr; *ppPkt = NULL; SpxAllocSendPacket(SpxDevice, &pDataPkt, &ndisStatus); if (ndisStatus == NDIS_STATUS_SUCCESS) { // Make a ndis buffer descriptor for the data if present. if (Length > 0) { SpxCopyBufferChain( &ndisStatus, &pNdisBuffer, SpxDevice->dev_NdisBufferPoolHandle, REQUEST_TDI_BUFFER(pSpxConnFile->scf_ReqPkt), pSpxConnFile->scf_ReqPktOffset, Length); if (ndisStatus != NDIS_STATUS_SUCCESS) { // Free the send packet SpxPktSendRelease(pDataPkt); return; } // Chain this in the packet NdisChainBufferAtBack(pDataPkt, pNdisBuffer); } pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pDataPkt + NDIS_PACKET_SIZE + sizeof(SPX_SEND_RESD) + IpxInclHdrOffset); hdrLen = SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE; Length += hdrLen; NdisQueryPacket(pDataPkt, NULL, NULL, &pNdisMacHdr, NULL); pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr); if (!SPX2_CONN(pSpxConnFile)) { NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE); } SpxBuildIpxHdr( pIpxSpxHdr, Length, pSpxConnFile->scf_RemAddr, pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket); // Build SPX Header. pIpxSpxHdr->hdr_ConnCtrl = (((State & SPX_SENDPKT_ACKREQ) ? SPX_CC_ACK : 0) | ((State & SPX_SENDPKT_EOM) ? SPX_CC_EOM : 0) | (SPX2_CONN(pSpxConnFile) ? SPX_CC_SPX2 : 0)); pIpxSpxHdr->hdr_DataType = (UCHAR)REQUEST_PARAMETERS(pSpxConnFile->scf_ReqPkt)->Others.Argument3; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SrcConnId, pSpxConnFile->scf_LocalConnId); pIpxSpxHdr->hdr_DestConnId = *((UNALIGNED USHORT *)&pSpxConnFile->scf_RemConnId); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SeqNum, pSpxConnFile->scf_SendSeqNum); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AckNum, pSpxConnFile->scf_RecvSeqNum); PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AllocNum, pSpxConnFile->scf_SentAllocNum); if (SPX2_CONN(pSpxConnFile)) { PUTSHORT2SHORT( &pIpxSpxHdr->hdr_NegSize, pSpxConnFile->scf_MaxPktSize); } pSendResd = (PSPX_SEND_RESD)(pDataPkt->ProtocolReserved); pSendResd->sr_Id = IDENTIFIER_SPX; pSendResd->sr_State = State; pSendResd->sr_Reserved1 = NULL; pSendResd->sr_Reserved2 = NULL; pSendResd->sr_Type = SPX_TYPE_DATA; pSendResd->sr_Next = NULL; pSendResd->sr_Request = pSpxConnFile->scf_ReqPkt; pSendResd->sr_Offset = pSpxConnFile->scf_ReqPktOffset; pSendResd->sr_ConnFile = pSpxConnFile; pSendResd->sr_SeqNum = pSpxConnFile->scf_SendSeqNum; pSendResd->sr_Len = Length; pSendResd->sr_HdrLen = hdrLen; if (State & SPX_SENDPKT_ACKREQ) { KeQuerySystemTime((PLARGE_INTEGER)&pSendResd->sr_SentTime); } CTEAssert(pSendResd->sr_Len <= pSpxConnFile->scf_MaxPktSize); *ppPkt = pDataPkt; // Ok, allocation succeeded. Increment send seq. pSpxConnFile->scf_SendSeqNum++; } return; } VOID SpxCopyBufferChain( OUT PNDIS_STATUS Status, OUT PNDIS_BUFFER * TargetChain, IN NDIS_HANDLE PoolHandle, IN PNDIS_BUFFER SourceChain, IN UINT Offset, IN UINT Length ) /*++ Routine Description: Creates a TargetBufferChain from the SourceBufferChain. The copy begins at the 'Offset' location in the source chain. It copies 'Length' bytes. It also handles Length = 0. If we run out of source chain before copying length amount of bytes or run out of memory to create any more buffers for the target chain, we clean up the partial chain created so far. Arguments: Status - Status of the request. TargetChain - Pointer to the allocated buffer descriptor. PoolHandle - Handle that is used to specify the pool. SourceChain - Pointer to the descriptor of the source memory. Offset - The Offset in the sources memory from which the copy is to begin Length - Number of Bytes to copy. Return Value: None. --*/ { UINT BytesBeforeCurBuffer = 0; PNDIS_BUFFER CurBuffer = SourceChain; UINT BytesLeft; UINT AvailableBytes; PNDIS_BUFFER NewNdisBuffer, StartTargetChain; CTEAssert( SourceChain ); // First of all find the source buffer that contains data that starts at // Offset. NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes ); while ( BytesBeforeCurBuffer + AvailableBytes <= Offset ) { BytesBeforeCurBuffer += AvailableBytes; CurBuffer = CurBuffer->Next; if ( CurBuffer ) { NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes ); } else { break; } } if ( ! CurBuffer ) { *Status = STATUS_UNSUCCESSFUL; return; } // // Copy the first buffer. This takes care of Length = 0. // BytesLeft = Length; // // ( Offset - BytesBeforeCurBuffer ) gives us the offset within this buffer. // AvailableBytes -= ( Offset - BytesBeforeCurBuffer ); if ( AvailableBytes > BytesLeft ) { AvailableBytes = BytesLeft; } NdisCopyBuffer( Status, &NewNdisBuffer, PoolHandle, CurBuffer, Offset - BytesBeforeCurBuffer, AvailableBytes); if ( *Status != NDIS_STATUS_SUCCESS ) { return; } StartTargetChain = NewNdisBuffer; BytesLeft -= AvailableBytes; // // Did the first buffer have enough data. If so, we r done. // if ( ! BytesLeft ) { *TargetChain = StartTargetChain; return; } // // Now follow the Mdl chain and copy more buffers. // CurBuffer = CurBuffer->Next; NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes ); while ( CurBuffer ) { if ( AvailableBytes > BytesLeft ) { AvailableBytes = BytesLeft; } NdisCopyBuffer( Status, &(NDIS_BUFFER_LINKAGE(NewNdisBuffer)), PoolHandle, CurBuffer, 0, AvailableBytes); if ( *Status != NDIS_STATUS_SUCCESS ) { // // ran out of resources. put back what we've used in this call and // return the error. // while ( StartTargetChain != NULL) { NewNdisBuffer = NDIS_BUFFER_LINKAGE( StartTargetChain ); NdisFreeBuffer ( StartTargetChain ); StartTargetChain = NewNdisBuffer; } return; } NewNdisBuffer = NDIS_BUFFER_LINKAGE(NewNdisBuffer); BytesLeft -= AvailableBytes; if ( ! BytesLeft ) { *TargetChain = StartTargetChain; return; } CurBuffer = CurBuffer->Next; NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes ); } // // Ran out of source chain. This should not happen. // CTEAssert( FALSE ); // For Retail build we clean up anyways. while ( StartTargetChain != NULL) { NewNdisBuffer = NDIS_BUFFER_LINKAGE( StartTargetChain ); NdisFreeBuffer ( StartTargetChain ); StartTargetChain = NewNdisBuffer; } *Status = STATUS_UNSUCCESSFUL; return; } VOID SpxPktBuildAck( IN PSPX_CONN_FILE pSpxConnFile, OUT PNDIS_PACKET * ppPkt, IN USHORT State, IN BOOLEAN fBuildNack, IN USHORT NumToResend ) /*++ Routine Description: Arguments: Return Value: --*/ { PNDIS_PACKET pPkt; PSPX_SEND_RESD pSendResd; PIPXSPX_HDR pIpxSpxHdr; NDIS_STATUS ndisStatus; USHORT hdrLen; PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr; BOOLEAN fSpx2 = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2); *ppPkt = NULL; SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus); if (ndisStatus != NDIS_STATUS_SUCCESS) { DBGPRINT(SEND, ERR, ("SpxPktBuildAck: Could not allocate ndis packet\n")); return; } pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt + NDIS_PACKET_SIZE + sizeof(SPX_SEND_RESD) + IpxInclHdrOffset); hdrLen = SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE; NdisQueryPacket(pPkt, NULL, NULL, &pNdisMacHdr, NULL); pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr); if (!fSpx2) { NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE); } // Send where data came from SpxBuildIpxHdr( pIpxSpxHdr, hdrLen, pSpxConnFile->scf_RemAckAddr, pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket); pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | (fSpx2 ? SPX_CC_SPX2 : 0)); pIpxSpxHdr->hdr_DataType = 0; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SrcConnId, pSpxConnFile->scf_LocalConnId); pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId; PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AckNum, pSpxConnFile->scf_RecvSeqNum); if (fSpx2) { pIpxSpxHdr->hdr_SeqNum = 0; if (fBuildNack) { PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SeqNum, NumToResend); } PUTSHORT2SHORT( &pIpxSpxHdr->hdr_NegSize, pSpxConnFile->scf_MaxPktSize); } else { // Put current send seq number in packet for spx1 PUTSHORT2SHORT( &pIpxSpxHdr->hdr_SeqNum, pSpxConnFile->scf_SendSeqNum); } PUTSHORT2SHORT( &pIpxSpxHdr->hdr_AllocNum, pSpxConnFile->scf_SentAllocNum); pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved); pSendResd->sr_Id = IDENTIFIER_SPX; pSendResd->sr_Type = (fBuildNack ? SPX_TYPE_DATANACK : SPX_TYPE_DATAACK); pSendResd->sr_Reserved1 = NULL; pSendResd->sr_Reserved2 = NULL; pSendResd->sr_State = State; pSendResd->sr_ConnFile = pSpxConnFile; pSendResd->sr_Request = NULL; pSendResd->sr_Next = NULL; pSendResd->sr_Len = pSendResd->sr_HdrLen = hdrLen; *ppPkt = pPkt; return; } VOID SpxPktRecvRelease( IN PNDIS_PACKET pPkt ) { ((PSPX_RECV_RESD)(pPkt->ProtocolReserved))->rr_State = SPX_RECVPKT_IDLE; SpxFreeRecvPacket(SpxDevice, pPkt); return; } VOID SpxPktSendRelease( IN PNDIS_PACKET pPkt ) { PNDIS_BUFFER pBuf, pIpxSpxBuf, pFreeBuf; UINT bufCount; CTEAssert((((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_State & SPX_SENDPKT_IPXOWNS) == 0); NdisQueryPacket(pPkt, NULL, &bufCount, &pBuf, NULL); // BufCount == 1 for only the header. That's ok, we just reset the length // and free the packet to the buffer pools. Else we need to free user buffers // before that. NdisUnchainBufferAtFront( pPkt, &pBuf); NdisUnchainBufferAtFront( pPkt, &pIpxSpxBuf); // // Set the header length to the max. that can be needed. // NdisAdjustBufferLength(pIpxSpxBuf, MIN_IPXSPX2_HDRSIZE); while (bufCount-- > 2) { PBYTE pData; ULONG dataLen; NdisUnchainBufferAtBack( pPkt, &pFreeBuf); // See if we free data associated with the buffer if ((((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_State & SPX_SENDPKT_FREEDATA) != 0) { NdisQueryBuffer(pFreeBuf, &pData, &dataLen); CTEAssert(pData != NULL); SpxFreeMemory(pData); } CTEAssert(pFreeBuf != NULL); NdisFreeBuffer(pFreeBuf); } NdisReinitializePacket(pPkt); // Initialize elements of the protocol reserved structure. ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_Id = IDENTIFIER_SPX; ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_State = SPX_SENDPKT_IDLE; ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_Reserved1= NULL; ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_Reserved2= NULL; NdisChainBufferAtFront( pPkt, pBuf); NdisChainBufferAtBack( pPkt, pIpxSpxBuf); SpxFreeSendPacket(SpxDevice, pPkt); return; }