Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1612 lines
55 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. send.c
  5. Abstract:
  6. routines for sending packets
  7. Author:
  8. Charlie Wickham (charlwi) 07-May-1996
  9. Yoram Bernet (yoramb)
  10. Rajesh Sundaram (rajeshsu) 01-Aug-1998.
  11. Environment:
  12. Kernel Mode
  13. Revision History:
  14. --*/
  15. #include "psched.h"
  16. #pragma hdrstop
  17. /* External */
  18. /* Static */
  19. /* Forwad */
  20. #define SEND_PACKET_VIA_SCHEDULER(_pktcontext, _vc, _adapter, _ourpacket) \
  21. { \
  22. PsAssert((_pktcontext)->Vc != 0); \
  23. (_vc)->Stats.PacketsScheduled++; \
  24. (_vc)->Stats.BytesScheduled.QuadPart += (_pktcontext)->Info.PacketLength; \
  25. if(!(*(_vc)->PsComponent->SubmitPacket)( \
  26. (_vc)->PsPipeContext, \
  27. (_vc)->PsFlowContext, \
  28. (_pktcontext)->Info.ClassMapContext, \
  29. &(_pktcontext)->Info)) { \
  30. \
  31. DropPacket((_adapter), (_vc), (_ourpacket), NDIS_STATUS_FAILURE); \
  32. } \
  33. return NDIS_STATUS_PENDING; \
  34. }
  35. #define FILL_PKT_FOR_NIC(OPacket, UserC) \
  36. { \
  37. NDIS_PACKET_8021Q_INFO VlanPriInfo; \
  38. \
  39. VlanPriInfo.Value = NDIS_PER_PACKET_INFO_FROM_PACKET(OPacket, Ieee8021QInfo);\
  40. VlanPriInfo.TagHeader.UserPriority = (UserC); \
  41. NDIS_PER_PACKET_INFO_FROM_PACKET(OPacket, Ieee8021QInfo) = VlanPriInfo.Value;\
  42. }
  43. #define FILL_PKT_FOR_SCHED(Adapter, PktContext, Vc, OPacket, TOSNC, UserC, UserNC, \
  44. _IPHdr) \
  45. { \
  46. ULONG _PacketLength; \
  47. FILL_PKT_FOR_NIC(OPacket, UserC); \
  48. NdisQueryPacket((OPacket), NULL, NULL, NULL, &(_PacketLength)); \
  49. (PktContext)->Info.PacketLength = (_PacketLength) - (Adapter)->HeaderSize; \
  50. (PktContext)->Info.ConformanceTime.QuadPart = 0; \
  51. (PktContext)->Info.ClassMapContext = 0; \
  52. (PktContext)->Info.UserPriorityNonConforming = (UserNC); \
  53. (PktContext)->Info.TOSNonConforming = (TOSNC); \
  54. (PktContext)->Info.IPHdr = (_IPHdr); \
  55. (PktContext)->Info.IPHeaderOffset = (Adapter)->IPHeaderOffset; \
  56. (PktContext)->Vc = (Vc); \
  57. }
  58. #define SEND_PACKET_OVER_NIC(Adapter, Packet, UserC, Status) \
  59. { \
  60. PPS_SEND_PACKET_CONTEXT _PktContext; \
  61. PNDIS_PACKET _OurPacket; \
  62. if((Status = PsDupPacketNoContext(Adapter, Packet, &_OurPacket, &_PktContext)) == NDIS_STATUS_SUCCESS) \
  63. { \
  64. FILL_PKT_FOR_NIC(_OurPacket, UserC); \
  65. NdisSend(&Status, Adapter->LowerMpHandle, _OurPacket); \
  66. if(Status != NDIS_STATUS_PENDING) { \
  67. if(_PktContext) { \
  68. PsAssert((_PktContext)->Vc == 0); \
  69. NdisIMCopySendCompletePerPacketInfo(_PktContext->OriginalPacket, _OurPacket); \
  70. NdisFreePacket(_OurPacket); \
  71. } \
  72. } \
  73. } \
  74. return Status; \
  75. }
  76. NDIS_STATUS
  77. PsAllocateAndCopyPacket(
  78. PADAPTER Adapter,
  79. PNDIS_PACKET Packet,
  80. PPNDIS_PACKET OurPacket,
  81. PPS_SEND_PACKET_CONTEXT *PktContext)
  82. {
  83. PNDIS_PACKET_OOB_DATA OurOOBData;
  84. PNDIS_PACKET_OOB_DATA XportOOBData;
  85. PMEDIA_SPECIFIC_INFORMATION OurMediaArea;
  86. PVOID MediaSpecificInfo = NULL;
  87. UINT MediaSpecificInfoSize = 0;
  88. NDIS_STATUS Status;
  89. //
  90. // At this point, we know that there are no packet stacks remaining in the packet.
  91. // we proceed to allocate an NDIS packet using NdisAllocatePacket. Note that here
  92. // we do not have to allocate our per-packet area, since NdisAllocatePacket already
  93. // did this for us.
  94. //
  95. if(!Adapter->SendPacketPool)
  96. {
  97. PS_LOCK(&Adapter->Lock);
  98. if(!Adapter->SendPacketPool)
  99. {
  100. NDIS_HANDLE PoolHandle = (void *) NDIS_PACKET_POOL_TAG_FOR_PSCHED;
  101. NdisAllocatePacketPoolEx(&Status,
  102. &PoolHandle,
  103. MIN_PACKET_POOL_SIZE,
  104. MAX_PACKET_POOL_SIZE,
  105. Adapter->PacketContextLength);
  106. if(Status != NDIS_STATUS_SUCCESS)
  107. {
  108. Adapter->Stats.OutOfPackets ++;
  109. PS_UNLOCK(&Adapter->Lock);
  110. return Status;
  111. }
  112. //
  113. // We successfully allocated a packet pool. We can now free the Fixed Size Block pool for the packet-stack API
  114. //
  115. Adapter->SendPacketPool = PoolHandle;
  116. }
  117. PS_UNLOCK(&Adapter->Lock);
  118. }
  119. NdisAllocatePacket(&Status,
  120. OurPacket,
  121. Adapter->SendPacketPool);
  122. if(Status != NDIS_STATUS_SUCCESS)
  123. {
  124. //
  125. // mark as out of resources. Ndis will resubmit.
  126. //
  127. Adapter->Stats.OutOfPackets ++;
  128. return(NDIS_STATUS_RESOURCES);
  129. }
  130. #if DBG
  131. PsAssert((*OurPacket)->Private.Head == NULL);
  132. if(Packet->Private.TotalLength){
  133. PsAssert(Packet->Private.Head);
  134. }
  135. #endif // DBG
  136. //
  137. // chain the buffers from the upper layer packet to the newly allocated packet.
  138. //
  139. (*OurPacket)->Private.Head = Packet->Private.Head;
  140. (*OurPacket)->Private.Tail = Packet->Private.Tail;
  141. //
  142. // Copy the Packet Flags from the Packet to OldPacket. Since we handle loopback in the
  143. // QueryInformation handlers, we don't set the NDIS_FLAGS_DONT_LOOPBACK
  144. //
  145. NdisGetPacketFlags(*OurPacket) = NdisGetPacketFlags(Packet);
  146. //
  147. // Copy the OOB Offset from the original packet to the new packet.
  148. //
  149. XportOOBData = NDIS_OOB_DATA_FROM_PACKET(Packet);
  150. OurOOBData = NDIS_OOB_DATA_FROM_PACKET(*OurPacket);
  151. NdisMoveMemory(OurOOBData,
  152. XportOOBData,
  153. sizeof(NDIS_PACKET_OOB_DATA));
  154. //
  155. // Copy the per packet info into the new packet
  156. //
  157. NdisIMCopySendPerPacketInfo(*OurPacket, Packet);
  158. //
  159. // Copy the Media specific information
  160. //
  161. NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
  162. &MediaSpecificInfo,
  163. &MediaSpecificInfoSize);
  164. if(MediaSpecificInfo || MediaSpecificInfoSize){
  165. NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(*OurPacket,
  166. MediaSpecificInfo,
  167. MediaSpecificInfoSize);
  168. }
  169. //
  170. // Remember the original packet so that we can complete it properly.
  171. //
  172. *PktContext = PS_SEND_PACKET_CONTEXT_FROM_PACKET(*OurPacket);
  173. (*PktContext)->OriginalPacket = Packet;
  174. (*PktContext)->Vc = 0;
  175. (*PktContext)->Info.NdisPacket = *OurPacket;
  176. return Status;
  177. }
  178. NDIS_STATUS
  179. PsDupPacketNoContext(
  180. PADAPTER Adapter,
  181. PNDIS_PACKET Packet,
  182. PPNDIS_PACKET OurPacket,
  183. PPS_SEND_PACKET_CONTEXT *PktContext)
  184. {
  185. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  186. BOOLEAN Remaining;
  187. PNDIS_PACKET_STACK PacketStack;
  188. //
  189. // NDIS provides 2 ways for IMs to indicate packets. If the IM can allocate a packet stack, it should use it as
  190. // it is the optimal approach. In this case, we do not have to do any per-packet copying since we don't allocate
  191. // a new packet.
  192. //
  193. PacketStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
  194. if(Remaining != 0)
  195. {
  196. //
  197. // The packet stack has space only for 2 DWORDs. Since we are using more than 2, we need to allocate our own
  198. // memory for the per-packet block. Note that we *DONT* do this when we use the NdisAllocatePacket APIs, because
  199. // we initialized the packet pool to already include the space for the per-packet region.
  200. //
  201. *OurPacket = Packet;
  202. *PktContext = 0;
  203. PacketStack->IMReserved[0] = 0;
  204. }
  205. else
  206. {
  207. Status = PsAllocateAndCopyPacket(Adapter,
  208. Packet,
  209. OurPacket,
  210. PktContext);
  211. }
  212. return Status;
  213. }
  214. NDIS_STATUS
  215. PsDupPacketContext(
  216. PADAPTER Adapter,
  217. PNDIS_PACKET Packet,
  218. PPNDIS_PACKET OurPacket,
  219. PPS_SEND_PACKET_CONTEXT *PktContext)
  220. {
  221. NDIS_STATUS Status;
  222. BOOLEAN Remaining;
  223. PNDIS_PACKET_STACK PacketStack;
  224. //
  225. // NDIS provides 2 ways for IMs to indicate packets. If the IM can allocate a packet stack, it should use it as
  226. // it is the optimal approach. In this case, we do not have to do any per-packet copying since we don't allocate
  227. // a new packet.
  228. //
  229. PacketStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
  230. if(Remaining != 0)
  231. {
  232. //
  233. // The packet stack has space only for 2 DWORDs. Since we are using more than 2, we need to allocate our own
  234. // memory for the per-packet block. Note that we *DONT* do this when we use the NdisAllocatePacket APIs, because
  235. // we initialized the packet pool to already include the space for the per-packet region.
  236. //
  237. *OurPacket = Packet;
  238. *PktContext = (PPS_SEND_PACKET_CONTEXT) (ULONG_PTR)NdisAllocateFromBlockPool(Adapter->SendBlockPool);
  239. PacketStack->IMReserved[0] = (ULONG_PTR)*PktContext;
  240. if(!*PktContext)
  241. {
  242. Adapter->Stats.OutOfPackets ++;
  243. return NDIS_STATUS_RESOURCES;
  244. }
  245. else {
  246. (*PktContext)->Info.NdisPacket = Packet;
  247. (*PktContext)->OriginalPacket = 0;
  248. return NDIS_STATUS_SUCCESS;
  249. }
  250. }
  251. else
  252. {
  253. Status = PsAllocateAndCopyPacket(Adapter,
  254. Packet,
  255. OurPacket,
  256. PktContext);
  257. }
  258. return Status;
  259. }
  260. //
  261. // Tries to classify this packet based on the port numbers. If not found, will add it to one of the flows (in Round
  262. // Robin fashion) and returns a pointer to that Vc
  263. //
  264. PGPC_CLIENT_VC
  265. GetVcForPacket( PPS_WAN_LINK WanLink,
  266. USHORT SrcPort,
  267. USHORT DstPort)
  268. {
  269. PGPC_CLIENT_VC pVc, pVc1;
  270. int i, j;
  271. for( j = 0; j < BEVC_LIST_LEN; j++)
  272. {
  273. pVc = &WanLink->BeVcList[j];
  274. // Let's look at the 2 VCs we have now:
  275. for( i = 0; i < PORT_LIST_LEN; i++)
  276. {
  277. if( (pVc->SrcPort[i] == SrcPort) && (pVc->DstPort[i] == DstPort))
  278. return pVc;
  279. }
  280. }
  281. // Did not find in any of the VCs. Need to choose the Next VC for insertion and insert these valuse..
  282. pVc = &WanLink->BeVcList[WanLink->NextVc];
  283. WanLink->NextVc = ((WanLink->NextVc + 1) % BEVC_LIST_LEN);
  284. pVc->SrcPort[pVc->NextSlot] = SrcPort;
  285. pVc->DstPort[pVc->NextSlot] = DstPort;
  286. pVc->NextSlot = ((pVc->NextSlot + 1)% PORT_LIST_LEN );
  287. return pVc;
  288. }
  289. //
  290. // This routine returns the Src and Dst Port numbers
  291. BOOLEAN
  292. GetPortNos(
  293. IN PNDIS_PACKET Packet ,
  294. IN ULONG TransportHeaderOffset,
  295. IN OUT PUSHORT pSrcPort,
  296. IN OUT PUSHORT pDstPort
  297. )
  298. {
  299. PNDIS_BUFFER ArpBuf , IpBuf , TcpBuf, UdpBuf, DataBuf;
  300. ULONG ArpLen , IpLen , IpHdrLen , TcpLen , UdpLen, DataLen , TotalLen , TcpHeaderOffset;
  301. VOID *ArpH;
  302. IPHeader UNALIGNED *IPH;
  303. TCPHeader UNALIGNED *TCPH;
  304. UDPHeader UNALIGNED *UDPH;
  305. IPAddr Src, Dst;
  306. BOOLEAN bFragment;
  307. USHORT SrcPort , DstPort , IPID, FragOffset ,Size;
  308. PVOID GeneralVA , Data;
  309. ULONG i, Ret;
  310. IpBuf = NULL;
  311. // Steps
  312. // Parse the IP Packet.
  313. // Look for the appropriate ports.
  314. // Look for the data portion and put in the Time & length there.
  315. if(1)
  316. {
  317. PVOID pAddr;
  318. PNDIS_BUFFER pNdisBuf1, pNdisBuf2;
  319. UINT Len;
  320. NdisGetFirstBufferFromPacket( Packet,
  321. &ArpBuf,
  322. &ArpH,
  323. &ArpLen,
  324. &TotalLen
  325. );
  326. pNdisBuf1 = Packet->Private.Head;
  327. NdisQueryBuffer(pNdisBuf1, &pAddr, &Len);
  328. while(Len <= TransportHeaderOffset)
  329. {
  330. TransportHeaderOffset -= Len;
  331. NdisGetNextBuffer(pNdisBuf1, &pNdisBuf2);
  332. NdisQueryBuffer(pNdisBuf2, &pAddr, &Len);
  333. pNdisBuf1 = pNdisBuf2;
  334. }
  335. /* Buffer Descriptor corresponding to Ip Packet */
  336. IpBuf = pNdisBuf1;
  337. /* Length of this Buffer (IP buffer) */
  338. IpLen = Len - TransportHeaderOffset;
  339. /* Starting Virtual Address for this buffer */
  340. GeneralVA = pAddr;
  341. /* Virtual Address of the IP Header */
  342. IPH = (IPHeader *)(((PUCHAR)pAddr) + TransportHeaderOffset);
  343. }
  344. if(!IpBuf)
  345. return FALSE;
  346. IpHdrLen = ((IPH->iph_verlen & (uchar)~IP_VER_FLAG) << 2);
  347. FragOffset = IPH->iph_offset & IP_OFFSET_MASK;
  348. FragOffset = net_short(FragOffset) * 8;
  349. bFragment = (IPH->iph_offset & IP_MF_FLAG) || (FragOffset > 0);
  350. // Don't want to deal with Fragmented packets right now..//
  351. if ( bFragment )
  352. return FALSE;
  353. switch (IPH->iph_protocol)
  354. {
  355. case IPPROTO_TCP :
  356. if (IPH && ((USHORT)IpLen > IpHdrLen))
  357. {
  358. // We have more than the IP Header in this MDL //
  359. TCPH = (TCPHeader *) ((PUCHAR)IPH + IpHdrLen);
  360. TcpLen = IpLen - IpHdrLen;
  361. TcpBuf = IpBuf;
  362. }
  363. else
  364. {
  365. // TCP Header is in the next MDL //
  366. NdisGetNextBuffer(IpBuf, &TcpBuf);
  367. if(!TcpBuf)
  368. return FALSE;
  369. GeneralVA = NULL;
  370. NdisQueryBuffer(TcpBuf,
  371. &GeneralVA,
  372. &TcpLen
  373. );
  374. TCPH = (TCPHeader *) GeneralVA;
  375. }
  376. /* At this point, TcpBuf, TCPH and TcpLen contain the proper values */
  377. // Get the port numbers out.
  378. SrcPort = net_short(TCPH->tcp_src);
  379. DstPort = net_short(TCPH->tcp_dest);
  380. *pSrcPort = SrcPort;
  381. *pDstPort = DstPort;
  382. // If the packet is here, it means: The link on which it is being sent is <= MAX_LINK_SPEED_FOR_DRR.
  383. // So, it is OK to adjust the Window size if we are on an ICS box.
  384. if(gEnableWindowAdjustment)
  385. {
  386. USHORT _old, _new;
  387. ULONG _sum;
  388. _old = (TCPH)->tcp_window;
  389. _new = 1460*6;
  390. if( net_short( _old) < _new)
  391. return TRUE;
  392. _new = net_short( _new );
  393. (TCPH)->tcp_window = _new;
  394. _sum = ((~(TCPH)->tcp_xsum) & 0xffff) + ((~_old) & 0xffff) + _new;
  395. _sum = (_sum & 0xffff) + (_sum >> 16);
  396. _sum += (_sum >> 16);
  397. (TCPH)->tcp_xsum = (ushort) ((~_sum) & 0xffff);
  398. }
  399. return TRUE;
  400. case IPPROTO_UDP:
  401. if (IpLen > IpHdrLen)
  402. {
  403. // We have more than the IP Header in this MDL //
  404. UDPH = (UDPHeader *) ((PUCHAR)IPH + IpHdrLen);
  405. UdpLen = IpLen - IpHdrLen;
  406. UdpBuf = IpBuf;
  407. }
  408. else
  409. {
  410. // UDP Header is in the next MDL //
  411. NdisGetNextBuffer(IpBuf, &UdpBuf);
  412. if(!UdpBuf)
  413. return FALSE;
  414. GeneralVA = NULL;
  415. NdisQueryBuffer(UdpBuf,
  416. &GeneralVA,
  417. &UdpLen
  418. );
  419. UDPH = (UDPHeader *) GeneralVA;
  420. }
  421. /* At this point, UdpBuf, UDPH and UdpLen contain the proper values */
  422. SrcPort = net_short(UDPH->uh_src);
  423. DstPort = net_short(UDPH->uh_dest);
  424. *pSrcPort = SrcPort;
  425. *pDstPort = DstPort;
  426. return TRUE;
  427. default:
  428. ;
  429. }
  430. return FALSE;
  431. }
  432. //
  433. // This where we get called for each Send
  434. //
  435. NTSTATUS
  436. MpSend(
  437. IN NDIS_HANDLE MiniportAdapterContext,
  438. IN PNDIS_PACKET TheirPacket,
  439. IN UINT Flags
  440. )
  441. /*++
  442. Routine Description:
  443. Received a xmit request from a legacy transport.
  444. Arguments:
  445. See the DDK...
  446. Return Values:
  447. None
  448. --*/
  449. {
  450. PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
  451. NDIS_STATUS Status;
  452. PNDIS_PACKET OurPacket;
  453. PPS_SEND_PACKET_CONTEXT PktContext;
  454. PGPC_CLIENT_VC BeVc, Vc = NULL;
  455. PETH_HEADER pAddr;
  456. PNDIS_BUFFER pNdisBuf1;
  457. UINT Len;
  458. PUSHORT id;
  459. PPS_WAN_LINK WanLink;
  460. PsStructAssert(Adapter);
  461. //
  462. // If the device is shutting down, we cannot accept any more sends.
  463. //
  464. if(IsDeviceStateOn(Adapter) == FALSE)
  465. {
  466. return NDIS_STATUS_FAILURE;
  467. }
  468. if(Adapter->MediaType == NdisMediumWan)
  469. {
  470. if(Adapter->ProtocolType == ARP_ETYPE_IP)
  471. {
  472. //
  473. // We should not be getting non-ip packets in the NDISWAN-IP binding.
  474. //
  475. PsAssert(NDIS_GET_PACKET_PROTOCOL_TYPE(TheirPacket) == NDIS_PROTOCOL_ID_TCP_IP);
  476. pNdisBuf1 = TheirPacket->Private.Head;
  477. NdisQueryBuffer(pNdisBuf1, &pAddr, &Len);
  478. if(Len < sizeof(ETH_HEADER))
  479. {
  480. //
  481. // Packet is too small. we have to fail this bogus packet.
  482. //
  483. return NDIS_STATUS_FAILURE;
  484. }
  485. //
  486. // Get to the wanlink using the remote address from the packet.
  487. //
  488. id = (PUSHORT) &pAddr->DestAddr[0];
  489. PS_LOCK(&Adapter->Lock);
  490. WanLink = (PPS_WAN_LINK)(g_WanLinkTable[*id]);
  491. if(WanLink == 0)
  492. {
  493. //
  494. // We received a packet for a wanlink that has already gone down.
  495. //
  496. PS_UNLOCK(&Adapter->Lock);
  497. return NDIS_STATUS_FAILURE;
  498. }
  499. if(WanLink->State != WanStateOpen)
  500. {
  501. //
  502. // We received a packet for a wanlink that has already gone down.
  503. //
  504. PS_UNLOCK(&Adapter->Lock);
  505. return NDIS_STATUS_FAILURE;
  506. }
  507. //
  508. // When we get a StatusIndication for a new WAN link, NDISWAN puts context in the remote address
  509. // When psched intercepts the LineUp, it overwrites NDISWAN's context with its own context. Psched
  510. // uses this context to get to the WanLink from the packet. (see above)
  511. //
  512. // But, when it passes the packet down to NDISWAN, it needs to plumb NDISWAN's context into the packet,
  513. // so that NDISWAN can see the context that it sent to us, as opposed to the context that we sent up to
  514. // wanarp.
  515. //
  516. NdisMoveMemory(pAddr,
  517. &WanLink->SendHeader,
  518. FIELD_OFFSET(ETH_HEADER, Type));
  519. //
  520. // We optimize psched to bypass the scheduling components when there are no flows. There are a set of
  521. // scheduling components per WanLink, so to be truly optimal, we need to check the FLowCount on a specific
  522. // WanLink.
  523. //
  524. if( (WanLink->LinkSpeed > MAX_LINK_SPEED_FOR_DRR) && (!WanLink->CfInfosInstalled) )
  525. {
  526. // Bypass scheduling components, since there are no flows created on this
  527. // wanlink. Note that the UserPriority is never used over wanlinks, so we can set it to 0.
  528. PS_UNLOCK(&Adapter->Lock);
  529. SEND_PACKET_OVER_NIC(Adapter,
  530. TheirPacket,
  531. 0,
  532. Status);
  533. }
  534. //
  535. // Now, we are going to do either (1) DiffServ Or (2) IntServ. If the packet does not belong to either
  536. // of these categories, we will just hash it into one of the BeVcs we have and do simple DRR.
  537. //
  538. else
  539. {
  540. //
  541. // There is at least one flow. we need to classify this packet. Since the flow is going
  542. // via the scheduling components, we have to allocate memory for the per-packet info
  543. // (if the packet-stack APIs are used) or a new packet descriptor, which will include the
  544. // per-packet info (if the old NDIS APIs are used) The packet that has been passed to us is
  545. // 'TheirPacket'. If the packet-stack APIs are used, then TheirPacket == OurPacket
  546. // if the non packet-stack APIs are used, then OurPacket == Newly Allocated Packet.
  547. //
  548. // In both cases, the code after this point will just use 'OurPacket' and the right thing will happen.
  549. //
  550. if((Status = PsDupPacketContext(Adapter, TheirPacket, &OurPacket, &PktContext)) != NDIS_STATUS_SUCCESS)
  551. {
  552. PS_UNLOCK(&Adapter->Lock);
  553. return Status;
  554. }
  555. // Case 1. DiffServMode //
  556. if(WanLink->AdapterMode == AdapterModeDiffservFlow)
  557. {
  558. //
  559. // If we are in Diffserv mode, we classify the packet based on the DSCP in the IP header.
  560. //
  561. // Is there atleast ONE DiffServ Flow?
  562. if(Adapter->IPHeaderOffset && WanLink->pDiffServMapping)
  563. {
  564. IPHeader *pIpHdr;
  565. UCHAR tos;
  566. pIpHdr = GetIpHeader(Adapter->IPHeaderOffset, OurPacket);
  567. tos = pIpHdr->iph_tos >> 2;
  568. if((Vc = WanLink->pDiffServMapping[tos].Vc))
  569. {
  570. //
  571. // We found a VC for this packet.
  572. //
  573. PsAssert(Vc->Adapter == Adapter);
  574. PsAssert(Vc->WanLink == WanLink);
  575. InterlockedIncrement(&Vc->RefCount);
  576. SET_TOS_XSUM(OurPacket,
  577. pIpHdr,
  578. (WanLink->pDiffServMapping[tos].ConformingOutboundDSField));
  579. FILL_PKT_FOR_SCHED(Adapter,
  580. PktContext,
  581. Vc,
  582. OurPacket,
  583. (WanLink->pDiffServMapping[tos].NonConformingOutboundDSField),
  584. WanLink->pDiffServMapping[tos].ConformingUserPriority,
  585. WanLink->pDiffServMapping[tos].NonConformingUserPriority,
  586. pIpHdr);
  587. }
  588. // Could not classify packets to ANY of the DiffServ Flows. So, let's just do DRR across the BeVcs.
  589. else
  590. {
  591. //
  592. // There are Diffserv flows installed, but not for this DSCP. Lets use the BEVCS.
  593. //
  594. USHORT SrcPort, DstPort;
  595. if( (WanLink->LinkSpeed <= MAX_LINK_SPEED_FOR_DRR) &&
  596. (GetPortNos( TheirPacket, Adapter->IPHeaderOffset, &SrcPort, &DstPort)))
  597. Vc = GetVcForPacket( WanLink, SrcPort, DstPort);
  598. else
  599. Vc = &WanLink->BestEffortVc;
  600. InterlockedIncrement(&Vc->RefCount);
  601. FILL_PKT_FOR_SCHED(Adapter,
  602. PktContext,
  603. Vc,
  604. OurPacket,
  605. Vc->IPPrecedenceNonConforming,
  606. Vc->UserPriorityConforming,
  607. Vc->UserPriorityNonConforming,
  608. pIpHdr);
  609. }
  610. }
  611. // No, there is not One, let's just do DRR across the BeVcs.
  612. else
  613. {
  614. //
  615. // We are in Diffserv mode, but no Diffserv flows are created as yet. Let's use the BEVCS.
  616. //
  617. USHORT SrcPort, DstPort;
  618. if( (WanLink->LinkSpeed <= MAX_LINK_SPEED_FOR_DRR) &&
  619. (GetPortNos( TheirPacket, Adapter->IPHeaderOffset, &SrcPort, &DstPort)))
  620. Vc = GetVcForPacket( WanLink, SrcPort, DstPort);
  621. else
  622. Vc = &WanLink->BestEffortVc;
  623. InterlockedIncrement(&Vc->RefCount);
  624. FILL_PKT_FOR_SCHED(Adapter,
  625. PktContext,
  626. Vc,
  627. OurPacket,
  628. Vc->IPPrecedenceNonConforming,
  629. Vc->UserPriorityConforming,
  630. Vc->UserPriorityNonConforming,
  631. NULL);
  632. }
  633. PS_UNLOCK(&Adapter->Lock);
  634. }
  635. // Case 2. IntServMode
  636. else
  637. {
  638. USHORT SrcPort=0, DstPort=0;
  639. //
  640. // We are in RSVP mode, and we need to go to the GPC to classify the packet.
  641. // We already have a pointer to our WanLink. But, the wanlink could go away
  642. // when we release the lock and try to classify the packet. So, we take
  643. // a ref on the BestEffortVc for the WanLink.
  644. //
  645. if( (WanLink->LinkSpeed <= MAX_LINK_SPEED_FOR_DRR) &&
  646. (GetPortNos( TheirPacket, Adapter->IPHeaderOffset, &SrcPort, &DstPort)))
  647. BeVc = GetVcForPacket( WanLink, SrcPort, DstPort);
  648. else
  649. BeVc = &WanLink->BestEffortVc;
  650. InterlockedIncrement(&BeVc->RefCount);
  651. PS_UNLOCK(&Adapter->Lock);
  652. if( WanLink->CfInfosInstalled )
  653. Vc = GetVcByClassifyingPacket(Adapter, &WanLink->InterfaceID, OurPacket);
  654. if(!Vc)
  655. {
  656. Vc = BeVc;
  657. }
  658. else
  659. {
  660. DerefClVc(BeVc);
  661. }
  662. FILL_PKT_FOR_SCHED(Adapter,
  663. PktContext,
  664. Vc,
  665. OurPacket,
  666. Vc->IPPrecedenceNonConforming,
  667. Vc->UserPriorityConforming,
  668. Vc->UserPriorityNonConforming,
  669. NULL);
  670. }
  671. //
  672. // There is at least one flow - We need to send this packet via the scheduling
  673. // components.
  674. //
  675. if((Vc->ClVcState == CL_CALL_COMPLETE) ||
  676. (Vc->ClVcState == CL_MODIFY_PENDING))
  677. {
  678. SEND_PACKET_VIA_SCHEDULER(PktContext, Vc, Adapter, OurPacket);
  679. }
  680. else
  681. {
  682. //
  683. // Deref the ref that was added by the GPC.
  684. //
  685. DerefClVc(Vc);
  686. PsDbgSend(DBG_FAILURE, DBG_SEND, MP_SEND, NOT_READY, Adapter, Vc, TheirPacket, OurPacket);
  687. if(PktContext->OriginalPacket)
  688. {
  689. NdisFreePacket(OurPacket);
  690. }
  691. else
  692. {
  693. NdisFreeToBlockPool((PUCHAR)PktContext);
  694. }
  695. return(NDIS_STATUS_FAILURE);
  696. }
  697. }
  698. }
  699. //
  700. // Forget about it. It's a Non-IP packet
  701. //
  702. else
  703. {
  704. //
  705. // For non IP adapters, we just send over the NIC. Note that we don't create a best effort
  706. // Vc for such adapters. The only thing that we lose here is the ability to mark 802.1p on
  707. // such packets (we don't have a Vc, so we cannot supply a UserPriority value to the below
  708. // macro. But that is okay, since 802.1p is meaningful only in non LAN adapters.
  709. //
  710. SEND_PACKET_OVER_NIC(Adapter,
  711. TheirPacket,
  712. 0,
  713. Status);
  714. }
  715. }
  716. else
  717. {
  718. //
  719. // We have received a send at our non WAN binding.
  720. //
  721. if(!Adapter->CfInfosInstalled &&
  722. Adapter->BestEffortLimit == UNSPECIFIED_RATE &&
  723. TsCount == 0 )
  724. {
  725. // There is no point in trying to classify if there are no flows installed
  726. Vc = &Adapter->BestEffortVc;
  727. PsAssert(Vc->ClVcState == CL_CALL_COMPLETE);
  728. //
  729. // Bypass scheduling components.
  730. //
  731. SEND_PACKET_OVER_NIC(Adapter,
  732. TheirPacket,
  733. Vc->UserPriorityConforming,
  734. Status);
  735. }
  736. else
  737. {
  738. //
  739. // There is at least one flow, or we are in LimitedBestEffort mode. Let's try to classify the Vc.
  740. // In this case, the packet will have to go via the scheduling components.
  741. //
  742. //
  743. // Since the flow is going via the scheduling components, we have to allocate the per-packet info.
  744. // (if the new NDIS APIs are used) or a new packet descriptor, which will include the per-packet info
  745. // (if the old NDIS APIs are used)
  746. //
  747. if(Adapter->AdapterMode == AdapterModeDiffservFlow)
  748. {
  749. //
  750. // We are in the diffserv mode. We don't have to use the GPC to classify packets.
  751. // For all IP packets, classify on the TOS byte.
  752. //
  753. PS_LOCK(&Adapter->Lock);
  754. if(NDIS_GET_PACKET_PROTOCOL_TYPE(TheirPacket) == NDIS_PROTOCOL_ID_TCP_IP &&
  755. Adapter->IPHeaderOffset &&
  756. Adapter->pDiffServMapping)
  757. {
  758. UCHAR tos;
  759. IPHeader *pIpHdr = 0;
  760. pIpHdr = GetIpHeader(Adapter->IPHeaderOffset, TheirPacket);
  761. tos = pIpHdr->iph_tos >> 2;
  762. if((Vc = Adapter->pDiffServMapping[tos].Vc))
  763. {
  764. PsAssert(Vc->Adapter == Adapter);
  765. if((Status = PsDupPacketContext(Adapter,
  766. TheirPacket,
  767. &OurPacket,
  768. &PktContext)) != NDIS_STATUS_SUCCESS)
  769. {
  770. PS_UNLOCK(&Adapter->Lock);
  771. return Status;
  772. }
  773. InterlockedIncrement(&Vc->RefCount);
  774. SET_TOS_XSUM(OurPacket,
  775. pIpHdr,
  776. (Adapter->pDiffServMapping[tos].ConformingOutboundDSField));
  777. FILL_PKT_FOR_SCHED(Adapter,
  778. PktContext,
  779. Vc,
  780. OurPacket,
  781. (Adapter->pDiffServMapping[tos].NonConformingOutboundDSField),
  782. Adapter->pDiffServMapping[tos].ConformingUserPriority,
  783. Adapter->pDiffServMapping[tos].NonConformingUserPriority,
  784. pIpHdr);
  785. }
  786. else
  787. {
  788. if( ( Adapter->MaxOutstandingSends == 0xffffffff) &&
  789. ( TsCount == 0))
  790. {
  791. Vc = &Adapter->BestEffortVc;
  792. PsAssert(Vc->ClVcState == CL_CALL_COMPLETE);
  793. //
  794. // Bypass scheduling components.
  795. //
  796. PS_UNLOCK(&Adapter->Lock);
  797. SEND_PACKET_OVER_NIC(Adapter,
  798. TheirPacket,
  799. Vc->UserPriorityConforming,
  800. Status);
  801. }
  802. Vc = &Adapter->BestEffortVc;
  803. if((Status = PsDupPacketContext(Adapter,
  804. TheirPacket,
  805. &OurPacket,
  806. &PktContext)) != NDIS_STATUS_SUCCESS)
  807. {
  808. PS_UNLOCK(&Adapter->Lock);
  809. return Status;
  810. }
  811. InterlockedIncrement(&Vc->RefCount);
  812. FILL_PKT_FOR_SCHED(Adapter,
  813. PktContext,
  814. Vc,
  815. OurPacket,
  816. Vc->IPPrecedenceNonConforming,
  817. Vc->UserPriorityConforming,
  818. Vc->UserPriorityNonConforming,
  819. NULL);
  820. }
  821. }
  822. else
  823. {
  824. //
  825. // We are in Diffserv mode, but there are no DiffServ Vcs, or it's not an IP
  826. // packet. Send over the Adapter's BE Vc.
  827. //
  828. Vc = &Adapter->BestEffortVc;
  829. if((Status = PsDupPacketContext( Adapter,
  830. TheirPacket,
  831. &OurPacket,
  832. &PktContext)) != NDIS_STATUS_SUCCESS)
  833. {
  834. PS_UNLOCK(&Adapter->Lock);
  835. return Status;
  836. }
  837. InterlockedIncrement(&Vc->RefCount);
  838. FILL_PKT_FOR_SCHED(Adapter,
  839. PktContext,
  840. Vc,
  841. OurPacket,
  842. Vc->IPPrecedenceNonConforming,
  843. Vc->UserPriorityConforming,
  844. Vc->UserPriorityNonConforming,
  845. NULL);
  846. }
  847. PS_UNLOCK(&Adapter->Lock);
  848. }
  849. else
  850. {
  851. // We are in RSVP mode. Let's classify with the GPC.
  852. Vc = GetVcByClassifyingPacket(Adapter, &Adapter->InterfaceID, TheirPacket);
  853. if( !Vc)
  854. {
  855. if( (Adapter->MaxOutstandingSends == 0xffffffff) &&
  856. (TsCount == 0))
  857. {
  858. Vc = &Adapter->BestEffortVc;
  859. PsAssert(Vc->ClVcState == CL_CALL_COMPLETE);
  860. //
  861. // Bypass scheduling components.
  862. //
  863. SEND_PACKET_OVER_NIC(Adapter,
  864. TheirPacket,
  865. Vc->UserPriorityConforming,
  866. Status);
  867. }
  868. // We will be doing DRR on this adapter; so send pkt on BeVc
  869. Vc = &Adapter->BestEffortVc;
  870. InterlockedIncrement(&Vc->RefCount);
  871. }
  872. if((Status = PsDupPacketContext(Adapter, TheirPacket, &OurPacket, &PktContext)) != NDIS_STATUS_SUCCESS)
  873. {
  874. return Status;
  875. }
  876. FILL_PKT_FOR_SCHED(Adapter,
  877. PktContext,
  878. Vc,
  879. OurPacket,
  880. Vc->IPPrecedenceNonConforming,
  881. Vc->UserPriorityConforming,
  882. Vc->UserPriorityNonConforming,
  883. NULL);
  884. }
  885. if((Vc->ClVcState == CL_CALL_COMPLETE) ||
  886. (Vc->ClVcState == CL_MODIFY_PENDING) ||
  887. (Vc->ClVcState == CL_INTERNAL_CALL_COMPLETE))
  888. {
  889. SEND_PACKET_VIA_SCHEDULER(PktContext, Vc, Adapter, OurPacket);
  890. }
  891. else
  892. {
  893. //
  894. // Deref the ref that was added by the GPC.
  895. //
  896. DerefClVc(Vc);
  897. PsDbgSend(DBG_FAILURE, DBG_SEND, MP_SEND, NOT_READY, Adapter, Vc, TheirPacket, OurPacket);
  898. if(PktContext->OriginalPacket)
  899. {
  900. NdisFreePacket(OurPacket);
  901. }
  902. else
  903. {
  904. NdisFreeToBlockPool((PUCHAR)PktContext);
  905. }
  906. return(NDIS_STATUS_FAILURE);
  907. }
  908. }
  909. }
  910. }
  911. VOID
  912. ClSendComplete(
  913. IN NDIS_HANDLE ProtocolBindingContext,
  914. IN PNDIS_PACKET Packet,
  915. IN NDIS_STATUS Status
  916. )
  917. /*++
  918. Routine Description:
  919. Completion routine for NdisSendPackets.
  920. Does most of the work for cleaning up after a send.
  921. If necessary, call the PSA's send packet complete function
  922. Arguments:
  923. See the DDK...
  924. Return Values:
  925. None
  926. --*/
  927. {
  928. PGPC_CLIENT_VC Vc;
  929. PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
  930. PPS_SEND_PACKET_CONTEXT PktContext;
  931. PNDIS_PACKET XportPacket;
  932. HANDLE PoolHandle;
  933. //
  934. // Determine if the packet we are completing is the one we allocated. If so, get
  935. // the original packet from the reserved area and free the allocated packet. If this
  936. // is the packet that was sent down to us then just complete the packet.
  937. //
  938. PoolHandle = NdisGetPoolFromPacket(Packet);
  939. if(PoolHandle != Adapter->SendPacketPool)
  940. {
  941. PNDIS_PACKET_STACK PacketStack;
  942. BOOLEAN Remaining;
  943. PacketStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
  944. PsAssert(Remaining != 0);
  945. PktContext = (PPS_SEND_PACKET_CONTEXT) PacketStack->IMReserved[0];
  946. if(PktContext != 0)
  947. {
  948. //
  949. // This packet went via the scheduling components.
  950. //
  951. PsAssert(PktContext->Vc);
  952. Vc = PktContext->Vc;
  953. PsDbgSend(DBG_INFO, DBG_SEND, CL_SEND_COMPLETE, ENTER, Adapter, Vc, Packet, 0);
  954. PsAssert(Vc->Adapter == Adapter);
  955. if(Vc->SendComplete)
  956. (*Vc->SendComplete)(Vc->SendCompletePipeContext, Packet);
  957. DerefClVc(Vc);
  958. NdisFreeToBlockPool((PUCHAR)PktContext);
  959. }
  960. NdisMSendComplete(Adapter->PsNdisHandle,
  961. Packet,
  962. Status);
  963. }
  964. else
  965. {
  966. //
  967. // get the pointer to the upper layer's packet. Reinit the packet struct and
  968. // push it back on the adapter's packet SList. Remove the reference incurred
  969. // when the packet was handled by MpSend
  970. //
  971. PktContext = PS_SEND_PACKET_CONTEXT_FROM_PACKET(Packet);
  972. //
  973. // Call the scheduler if necessary
  974. //
  975. if(PktContext->Vc)
  976. {
  977. //
  978. // Some packets never went through the scheduler.
  979. //
  980. Vc = PktContext->Vc;
  981. PsDbgSend(DBG_INFO, DBG_SEND, CL_SEND_COMPLETE, ENTER, Adapter, Vc, Packet, 0);
  982. PsAssert(Vc->Adapter == Adapter);
  983. if(Vc->SendComplete)
  984. {
  985. (*Vc->SendComplete)(Vc->SendCompletePipeContext, Packet);
  986. }
  987. //
  988. // We have taken a ref on the VCs when we sent the packets
  989. // through the scheduling components. Now is the time to
  990. // Deref them
  991. //
  992. DerefClVc(Vc);
  993. }
  994. else
  995. {
  996. PsDbgSend(DBG_INFO, DBG_SEND, CL_SEND_COMPLETE, ENTER, Adapter, 0, Packet, 0);
  997. }
  998. XportPacket = PktContext->OriginalPacket;
  999. NdisIMCopySendCompletePerPacketInfo(XportPacket, Packet);
  1000. NdisFreePacket(Packet);
  1001. NdisMSendComplete(Adapter->PsNdisHandle,
  1002. XportPacket,
  1003. Status);
  1004. }
  1005. } // ClSendComplete
  1006. VOID
  1007. DropPacket(
  1008. IN HANDLE PipeContext,
  1009. IN HANDLE FlowContext,
  1010. IN PNDIS_PACKET Packet,
  1011. IN NDIS_STATUS Status
  1012. )
  1013. /*++
  1014. Routine Description:
  1015. Drop a packet after it was queued by the scheduler.
  1016. Arguments:
  1017. PipeContext - Pipe context (adapter)
  1018. FlowContext - Flow context (adapter VC)
  1019. Packet - Packet to drop
  1020. Status - Return code to return to NDIS
  1021. Return Values:
  1022. None
  1023. --*/
  1024. {
  1025. PGPC_CLIENT_VC Vc = (PGPC_CLIENT_VC)FlowContext;
  1026. PADAPTER Adapter = (PADAPTER)PipeContext;
  1027. PPS_SEND_PACKET_CONTEXT PktContext;
  1028. PNDIS_PACKET XportPacket;
  1029. HANDLE PoolHandle;
  1030. //
  1031. // Determine if the packet we are completing is the one we allocated. If so, get
  1032. // the original packet from the reserved area and free the allocated packet. If this
  1033. // is the packet that was sent down to us then just complete the packet.
  1034. //
  1035. PoolHandle = NdisGetPoolFromPacket(Packet);
  1036. if(PoolHandle != Adapter->SendPacketPool)
  1037. {
  1038. PNDIS_PACKET_STACK PacketStack;
  1039. BOOLEAN Remaining;
  1040. PacketStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
  1041. PsAssert(Remaining != 0);
  1042. PktContext = (PPS_SEND_PACKET_CONTEXT) PacketStack->IMReserved[0];
  1043. PsAssert(PktContext != 0);
  1044. PsAssert(Vc == PktContext->Vc);
  1045. PsAssert(Adapter == Vc->Adapter);
  1046. NdisFreeToBlockPool((PUCHAR)PktContext);
  1047. NdisMSendComplete(Adapter->PsNdisHandle,
  1048. Packet,
  1049. Status);
  1050. }
  1051. else
  1052. {
  1053. PktContext = PS_SEND_PACKET_CONTEXT_FROM_PACKET(Packet);
  1054. PsAssert(PktContext != 0);
  1055. PsAssert(Vc == PktContext->Vc);
  1056. PsAssert(Adapter == Vc->Adapter);
  1057. XportPacket = PktContext->OriginalPacket;
  1058. NdisFreePacket(Packet);
  1059. NdisMSendComplete(Adapter->PsNdisHandle,
  1060. XportPacket,
  1061. Status);
  1062. }
  1063. Vc->Stats.DroppedPackets ++;
  1064. PsDbgSend(DBG_INFO, DBG_SEND, DROP_PACKET, ENTER, Adapter, Vc, Packet, 0);
  1065. DerefClVc(Vc);
  1066. } // DropPacket
  1067. char*
  1068. ReturnByteAtOffset( PNDIS_PACKET pNdisPacket, ULONG Offset)
  1069. {
  1070. PVOID VA;
  1071. PNDIS_BUFFER pNdisBuf1, pNdisBuf2;
  1072. UINT Len;
  1073. pNdisBuf1 = pNdisPacket->Private.Head;
  1074. NdisQueryBuffer(pNdisBuf1, &VA, &Len);
  1075. while(Len <= Offset)
  1076. {
  1077. Offset -= Len;
  1078. NdisGetNextBuffer(pNdisBuf1, &pNdisBuf2);
  1079. NdisQueryBuffer(pNdisBuf2, &VA, &Len);
  1080. pNdisBuf1 = pNdisBuf2;
  1081. }
  1082. return (char*)(((char*)VA) + Offset);
  1083. }
  1084. PGPC_CLIENT_VC FASTCALL
  1085. GetVcByClassifyingPacket(
  1086. PADAPTER Adapter,
  1087. PTC_INTERFACE_ID pInterfaceID,
  1088. PNDIS_PACKET OurPacket
  1089. )
  1090. /*+++
  1091. ---*/
  1092. {
  1093. CLASSIFICATION_HANDLE ClassificationHandle;
  1094. PGPC_CLIENT_VC Vc = NULL;
  1095. #if CBQ
  1096. PCLASS_MAP_CONTEXT_BLK pClBlk = NULL;
  1097. #endif
  1098. NDIS_STATUS Status;
  1099. ULONG ProtocolType;
  1100. //
  1101. // We are in RSVP mode - Use the GPC to classify the packet. If the GPC wants to return a Vc, it will
  1102. // return with a ref.
  1103. //
  1104. ClassificationHandle = (CLASSIFICATION_HANDLE)
  1105. PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(OurPacket, ClassificationHandlePacketInfo));
  1106. if (ClassificationHandle)
  1107. {
  1108. PsAssert(GpcEntries.GpcGetCfInfoClientContextHandler);
  1109. Vc = GpcEntries.GpcGetCfInfoClientContextWithRefHandler(GpcQosClientHandle,
  1110. ClassificationHandle,
  1111. FIELD_OFFSET(GPC_CLIENT_VC, RefCount));
  1112. #if CBQ
  1113. pClBlk = NULL;
  1114. Status = GpcEntries.GpcGetCfInfoClientContextHandler(GpcClassMapClientHandle,
  1115. ClassificationHandle,
  1116. &pClBlk);
  1117. if(pClBlk)
  1118. {
  1119. PktContext->Info.ClassMapContext = pClBlk->ComponentContext;
  1120. }
  1121. #endif
  1122. //
  1123. // If we got a Vc that was not destined for this adapter, we have to reject it.
  1124. //
  1125. if(Vc)
  1126. {
  1127. if(Vc->Adapter != Adapter)
  1128. {
  1129. DerefClVc(Vc);
  1130. }
  1131. else
  1132. return Vc;
  1133. }
  1134. }
  1135. //
  1136. // Let's classify this packet since we did not get a Classification ID or a proper Vc.
  1137. //
  1138. PsAssert(GpcEntries.GpcClassifyPacketHandler);
  1139. switch(NDIS_GET_PACKET_PROTOCOL_TYPE(OurPacket))
  1140. {
  1141. case NDIS_PROTOCOL_ID_TCP_IP:
  1142. ProtocolType = GPC_PROTOCOL_TEMPLATE_IP;
  1143. break;
  1144. case NDIS_PROTOCOL_ID_IPX:
  1145. ProtocolType = GPC_PROTOCOL_TEMPLATE_IPX;
  1146. break;
  1147. default:
  1148. ProtocolType = GPC_PROTOCOL_TEMPLATE_NOT_SPECIFIED;
  1149. break;
  1150. }
  1151. //
  1152. // If the adapter type is 802.5 (Token Ring), then the MAC header can be of variable size.
  1153. // The format of the MAC header is as follows:
  1154. // +---------------------+-------------+----------+-----------
  1155. // | 2 + 6 (DA) + 6 (SA) | Optional RI | 8 (SNAP) | IP
  1156. // +---------------------+-------------+----------+-----------
  1157. // Optional RI is present if and only if RI bit as part of SA is set.
  1158. // When RI is present, its length is give by the lower 5 bits of the 15th byte.
  1159. // 1. Get the VA for the 9th and the 15th bytes.
  1160. // 2. If RI if not present, Offset = 14 + 6.
  1161. // 3. If present, Offset = 14 + 6 + RI-Size.
  1162. if(Adapter->MediaType == NdisMedium802_5)
  1163. {
  1164. PNDIS_BUFFER pTempNdisBuffer;
  1165. PUCHAR pHeaderBuffer;
  1166. ULONG BufferLength;
  1167. ULONG TotalLength;
  1168. ULONG IpOffset;
  1169. NdisGetFirstBufferFromPacket( OurPacket,
  1170. &pTempNdisBuffer,
  1171. &pHeaderBuffer,
  1172. &BufferLength,
  1173. &TotalLength);
  1174. ASSERT( BufferLength >= 15);
  1175. if( (*(ReturnByteAtOffset(OurPacket, 8)) & 0x80) == 0)
  1176. IpOffset = 14 + 8;
  1177. else
  1178. IpOffset = 14 + 8 + (*(ReturnByteAtOffset(OurPacket, 14)) & 0x1f);
  1179. Status = GpcEntries.GpcClassifyPacketHandler(
  1180. GpcQosClientHandle,
  1181. ProtocolType,
  1182. OurPacket,
  1183. IpOffset,
  1184. pInterfaceID,
  1185. (PGPC_CLIENT_HANDLE)&Vc,
  1186. &ClassificationHandle);
  1187. }
  1188. else
  1189. {
  1190. Status = GpcEntries.GpcClassifyPacketHandler(
  1191. GpcQosClientHandle,
  1192. ProtocolType,
  1193. OurPacket,
  1194. // This is basically to cover up a bug in wandrv.sys, which gives bogus frame header sizes. We look at the
  1195. // Ip Header offset supplied by the protocol above for IP packets only, as we are saving only those for the
  1196. // time being.
  1197. ((NDIS_GET_PACKET_PROTOCOL_TYPE(OurPacket) == NDIS_PROTOCOL_ID_TCP_IP) && (Adapter->IPHeaderOffset))
  1198. ? (Adapter->IPHeaderOffset)
  1199. : Adapter->HeaderSize,
  1200. pInterfaceID,
  1201. (PGPC_CLIENT_HANDLE)&Vc,
  1202. &ClassificationHandle);
  1203. }
  1204. if(Status == GPC_STATUS_SUCCESS)
  1205. {
  1206. //
  1207. // If we have succeeded, we must get a Classification Handle
  1208. //
  1209. PsAssert(ClassificationHandle != 0);
  1210. //
  1211. // The Classification succeeded. If we found a ClassificationHandle
  1212. // then we must write it in the packet so that anyone below us can use
  1213. // it. The very fact that we are here indicates that we did not start
  1214. // with a Classification handle or we got a bad one. So, we need not
  1215. // worry about over writing the classification handle in the packet.
  1216. //
  1217. NDIS_PER_PACKET_INFO_FROM_PACKET(OurPacket, ClassificationHandlePacketInfo) = UlongToPtr(ClassificationHandle);
  1218. Vc = GpcEntries.GpcGetCfInfoClientContextWithRefHandler(GpcQosClientHandle,
  1219. ClassificationHandle,
  1220. FIELD_OFFSET(GPC_CLIENT_VC, RefCount));
  1221. #if CBQ
  1222. //
  1223. // Get the CBQ class map context & store it in the
  1224. // packet. No point doing this if the first classification
  1225. // failed.
  1226. //
  1227. pClBlk = NULL;
  1228. Status = GpcEntries.GpcGetCfInfoClientContextHandler(GpcClassMapClientHandle,
  1229. ClassificationHandle,
  1230. &pClBlk);
  1231. if(pClBlk)
  1232. {
  1233. PktContext->Info.ClassMapContext = pClBlk->ComponentContext;
  1234. }
  1235. #endif
  1236. }
  1237. if(Vc && Vc->Adapter != Adapter)
  1238. {
  1239. //
  1240. // We have used the GPC APIs that return a Vc with a ref. We have to deref here, because we got a wrong Vc
  1241. // for this adapter.
  1242. //
  1243. DerefClVc(Vc);
  1244. return NULL;
  1245. }
  1246. return Vc;
  1247. }
  1248. VOID
  1249. ClCoSendComplete(
  1250. IN NDIS_STATUS Status,
  1251. IN NDIS_HANDLE ProtocolVcContext,
  1252. IN PNDIS_PACKET Packet
  1253. )
  1254. {
  1255. PGPC_CLIENT_VC Vc = (PGPC_CLIENT_VC) ProtocolVcContext;
  1256. ClSendComplete(Vc->Adapter,
  1257. Packet,
  1258. Status);
  1259. } // ClCoSendComplete
  1260. /* end send.c */