Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1383 lines
45 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 ((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. return FALSE;
  366. }
  367. /* At this point, TcpBuf, TCPH and TcpLen contain the proper values */
  368. // Get the port numbers out.
  369. SrcPort = net_short(TCPH->tcp_src);
  370. DstPort = net_short(TCPH->tcp_dest);
  371. *pSrcPort = SrcPort;
  372. *pDstPort = DstPort;
  373. // If the packet is here, it means: The link on which it is being sent is <= MAX_LINK_SPEED_FOR_DRR.
  374. // So, it is OK to adjust the Window size if we are on an ICS box.
  375. // Note that, we only do this on WAN adapters, which do not have the checksum offload
  376. // capability. So, we are fine with changing the checksum.
  377. if(gEnableWindowAdjustment)
  378. {
  379. USHORT _old, _new;
  380. ULONG _sum;
  381. _old = (TCPH)->tcp_window;
  382. _new = 1460*6;
  383. if( net_short( _old) < _new)
  384. return TRUE;
  385. _new = net_short( _new );
  386. (TCPH)->tcp_window = _new;
  387. _sum = ((~(TCPH)->tcp_xsum) & 0xffff) + ((~_old) & 0xffff) + _new;
  388. _sum = (_sum & 0xffff) + (_sum >> 16);
  389. _sum += (_sum >> 16);
  390. (TCPH)->tcp_xsum = (ushort) ((~_sum) & 0xffff);
  391. }
  392. return TRUE;
  393. case IPPROTO_UDP:
  394. if (IpLen > IpHdrLen)
  395. {
  396. // We have more than the IP Header in this MDL //
  397. UDPH = (UDPHeader *) ((PUCHAR)IPH + IpHdrLen);
  398. UdpLen = IpLen - IpHdrLen;
  399. UdpBuf = IpBuf;
  400. }
  401. else
  402. {
  403. return FALSE;
  404. }
  405. /* At this point, UdpBuf, UDPH and UdpLen contain the proper values */
  406. SrcPort = net_short(UDPH->uh_src);
  407. DstPort = net_short(UDPH->uh_dest);
  408. *pSrcPort = SrcPort;
  409. *pDstPort = DstPort;
  410. return TRUE;
  411. default:
  412. ;
  413. }
  414. return FALSE;
  415. }
  416. //
  417. // This where we get called for each Send
  418. //
  419. NTSTATUS
  420. MpSend(
  421. IN NDIS_HANDLE MiniportAdapterContext,
  422. IN PNDIS_PACKET TheirPacket,
  423. IN UINT Flags
  424. )
  425. /*++
  426. Routine Description:
  427. Received a xmit request from a legacy transport.
  428. Arguments:
  429. See the DDK...
  430. Return Values:
  431. None
  432. --*/
  433. {
  434. PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
  435. NDIS_STATUS Status;
  436. PNDIS_PACKET OurPacket;
  437. PPS_SEND_PACKET_CONTEXT PktContext;
  438. PGPC_CLIENT_VC BeVc, Vc = NULL;
  439. PETH_HEADER pAddr;
  440. PNDIS_BUFFER pNdisBuf1;
  441. UINT Len;
  442. PUSHORT id;
  443. PPS_WAN_LINK WanLink;
  444. PsStructAssert(Adapter);
  445. //
  446. // If the device is shutting down, we cannot accept any more sends.
  447. //
  448. if(IsDeviceStateOn(Adapter) == FALSE)
  449. {
  450. return NDIS_STATUS_FAILURE;
  451. }
  452. if(Adapter->MediaType == NdisMediumWan)
  453. {
  454. if(Adapter->ProtocolType == ARP_ETYPE_IP)
  455. {
  456. //
  457. // We should not be getting non-ip packets in the NDISWAN-IP binding.
  458. //
  459. PsAssert(NDIS_GET_PACKET_PROTOCOL_TYPE(TheirPacket) == NDIS_PROTOCOL_ID_TCP_IP);
  460. pNdisBuf1 = TheirPacket->Private.Head;
  461. NdisQueryBuffer(pNdisBuf1, &pAddr, &Len);
  462. if(Len < sizeof(ETH_HEADER))
  463. {
  464. //
  465. // Packet is too small. we have to fail this bogus packet.
  466. //
  467. return NDIS_STATUS_FAILURE;
  468. }
  469. //
  470. // Get to the wanlink using the remote address from the packet.
  471. //
  472. id = (PUSHORT) &pAddr->DestAddr[0];
  473. PS_LOCK(&Adapter->Lock);
  474. WanLink = (PPS_WAN_LINK)(g_WanLinkTable[*id]);
  475. if(WanLink == 0)
  476. {
  477. //
  478. // We received a packet for a wanlink that has already gone down.
  479. //
  480. PS_UNLOCK(&Adapter->Lock);
  481. return NDIS_STATUS_FAILURE;
  482. }
  483. if(WanLink->State != WanStateOpen)
  484. {
  485. //
  486. // We received a packet for a wanlink that has already gone down.
  487. //
  488. PS_UNLOCK(&Adapter->Lock);
  489. return NDIS_STATUS_FAILURE;
  490. }
  491. //
  492. // When we get a StatusIndication for a new WAN link, NDISWAN puts context in the remote address
  493. // When psched intercepts the LineUp, it overwrites NDISWAN's context with its own context. Psched
  494. // uses this context to get to the WanLink from the packet. (see above)
  495. //
  496. // But, when it passes the packet down to NDISWAN, it needs to plumb NDISWAN's context into the packet,
  497. // so that NDISWAN can see the context that it sent to us, as opposed to the context that we sent up to
  498. // wanarp.
  499. //
  500. NdisMoveMemory(pAddr,
  501. &WanLink->SendHeader,
  502. FIELD_OFFSET(ETH_HEADER, Type));
  503. //
  504. // We optimize psched to bypass the scheduling components when there are no flows. There are a set of
  505. // scheduling components per WanLink, so to be truly optimal, we need to check the FLowCount on a specific
  506. // WanLink.
  507. //
  508. if( (WanLink->LinkSpeed > MAX_LINK_SPEED_FOR_DRR) && (!WanLink->CfInfosInstalled) )
  509. {
  510. // Bypass scheduling components, since there are no flows created on this
  511. // wanlink. Note that the UserPriority is never used over wanlinks, so we can set it to 0.
  512. PS_UNLOCK(&Adapter->Lock);
  513. SEND_PACKET_OVER_NIC(Adapter,
  514. TheirPacket,
  515. 0,
  516. Status);
  517. }
  518. //
  519. // Now, we are going to do either (1) DiffServ Or (2) IntServ. If the packet does not belong to either
  520. // of these categories, we will just hash it into one of the BeVcs we have and do simple DRR.
  521. //
  522. else
  523. {
  524. //
  525. // There is at least one flow. we need to classify this packet. Since the flow is going
  526. // via the scheduling components, we have to allocate memory for the per-packet info
  527. // (if the packet-stack APIs are used) or a new packet descriptor, which will include the
  528. // per-packet info (if the old NDIS APIs are used) The packet that has been passed to us is
  529. // 'TheirPacket'. If the packet-stack APIs are used, then TheirPacket == OurPacket
  530. // if the non packet-stack APIs are used, then OurPacket == Newly Allocated Packet.
  531. //
  532. // In both cases, the code after this point will just use 'OurPacket' and the right thing will happen.
  533. //
  534. if((Status = PsDupPacketContext(Adapter, TheirPacket, &OurPacket, &PktContext)) != NDIS_STATUS_SUCCESS)
  535. {
  536. PS_UNLOCK(&Adapter->Lock);
  537. return Status;
  538. }
  539. if (1)
  540. {
  541. USHORT SrcPort=0, DstPort=0;
  542. //
  543. // We are in RSVP mode, and we need to go to the GPC to classify the packet.
  544. // We already have a pointer to our WanLink. But, the wanlink could go away
  545. // when we release the lock and try to classify the packet. So, we take
  546. // a ref on the BestEffortVc for the WanLink.
  547. //
  548. if( (WanLink->LinkSpeed <= MAX_LINK_SPEED_FOR_DRR) &&
  549. (GetPortNos( TheirPacket, Adapter->IPHeaderOffset, &SrcPort, &DstPort)))
  550. BeVc = GetVcForPacket( WanLink, SrcPort, DstPort);
  551. else
  552. BeVc = &WanLink->BestEffortVc;
  553. InterlockedIncrement(&BeVc->RefCount);
  554. PS_UNLOCK(&Adapter->Lock);
  555. if( WanLink->CfInfosInstalled )
  556. Vc = GetVcByClassifyingPacket(Adapter, &WanLink->InterfaceID, OurPacket);
  557. if(!Vc)
  558. {
  559. Vc = BeVc;
  560. }
  561. else
  562. {
  563. DerefClVc(BeVc);
  564. }
  565. FILL_PKT_FOR_SCHED(Adapter,
  566. PktContext,
  567. Vc,
  568. OurPacket,
  569. Vc->IPPrecedenceNonConforming,
  570. Vc->UserPriorityConforming,
  571. Vc->UserPriorityNonConforming,
  572. NULL);
  573. }
  574. //
  575. // There is at least one flow - We need to send this packet via the scheduling
  576. // components.
  577. //
  578. if((Vc->ClVcState == CL_CALL_COMPLETE) ||
  579. (Vc->ClVcState == CL_MODIFY_PENDING) ||
  580. (Vc->ClVcState == CL_INTERNAL_CALL_COMPLETE))
  581. {
  582. SEND_PACKET_VIA_SCHEDULER(PktContext, Vc, Adapter, OurPacket);
  583. }
  584. else
  585. {
  586. //
  587. // Deref the ref that was added by the GPC.
  588. //
  589. DerefClVc(Vc);
  590. PsDbgSend(DBG_FAILURE, DBG_SEND, MP_SEND, NOT_READY, Adapter, Vc, TheirPacket, OurPacket);
  591. if(PktContext->OriginalPacket)
  592. {
  593. NdisFreePacket(OurPacket);
  594. }
  595. else
  596. {
  597. NdisFreeToBlockPool((PUCHAR)PktContext);
  598. }
  599. return(NDIS_STATUS_FAILURE);
  600. }
  601. }
  602. }
  603. //
  604. // Forget about it. It's a Non-IP packet
  605. //
  606. else
  607. {
  608. //
  609. // For non IP adapters, we just send over the NIC. Note that we don't create a best effort
  610. // Vc for such adapters. The only thing that we lose here is the ability to mark 802.1p on
  611. // such packets (we don't have a Vc, so we cannot supply a UserPriority value to the below
  612. // macro. But that is okay, since 802.1p is meaningful only in non LAN adapters.
  613. //
  614. SEND_PACKET_OVER_NIC(Adapter,
  615. TheirPacket,
  616. 0,
  617. Status);
  618. }
  619. }
  620. else
  621. {
  622. //
  623. // We have received a send at our non WAN binding.
  624. //
  625. if(!Adapter->CfInfosInstalled &&
  626. Adapter->BestEffortLimit == UNSPECIFIED_RATE )
  627. {
  628. // There is no point in trying to classify if there are no flows installed
  629. Vc = &Adapter->BestEffortVc;
  630. PsAssert(Vc->ClVcState == CL_CALL_COMPLETE);
  631. //
  632. // Bypass scheduling components.
  633. //
  634. SEND_PACKET_OVER_NIC(Adapter,
  635. TheirPacket,
  636. Vc->UserPriorityConforming,
  637. Status);
  638. }
  639. else
  640. {
  641. //
  642. // There is at least one flow, or we are in LimitedBestEffort mode. Let's try to classify the Vc.
  643. // In this case, the packet will have to go via the scheduling components.
  644. //
  645. //
  646. // Since the flow is going via the scheduling components, we have to allocate the per-packet info.
  647. // (if the new NDIS APIs are used) or a new packet descriptor, which will include the per-packet info
  648. // (if the old NDIS APIs are used)
  649. //
  650. if(1)
  651. {
  652. // We are in RSVP mode. Let's classify with the GPC.
  653. Vc = GetVcByClassifyingPacket(Adapter, &Adapter->InterfaceID, TheirPacket);
  654. if( !Vc)
  655. {
  656. if( Adapter->MaxOutstandingSends == 0xffffffff)
  657. {
  658. Vc = &Adapter->BestEffortVc;
  659. PsAssert(Vc->ClVcState == CL_CALL_COMPLETE);
  660. //
  661. // Bypass scheduling components.
  662. //
  663. SEND_PACKET_OVER_NIC(Adapter,
  664. TheirPacket,
  665. Vc->UserPriorityConforming,
  666. Status);
  667. }
  668. // We will be doing DRR on this adapter; so send pkt on BeVc
  669. Vc = &Adapter->BestEffortVc;
  670. InterlockedIncrement(&Vc->RefCount);
  671. }
  672. if((Status = PsDupPacketContext(Adapter, TheirPacket, &OurPacket, &PktContext)) != NDIS_STATUS_SUCCESS)
  673. {
  674. return Status;
  675. }
  676. FILL_PKT_FOR_SCHED(Adapter,
  677. PktContext,
  678. Vc,
  679. OurPacket,
  680. Vc->IPPrecedenceNonConforming,
  681. Vc->UserPriorityConforming,
  682. Vc->UserPriorityNonConforming,
  683. NULL);
  684. }
  685. if((Vc->ClVcState == CL_CALL_COMPLETE) ||
  686. (Vc->ClVcState == CL_MODIFY_PENDING) ||
  687. (Vc->ClVcState == CL_INTERNAL_CALL_COMPLETE))
  688. {
  689. SEND_PACKET_VIA_SCHEDULER(PktContext, Vc, Adapter, OurPacket);
  690. }
  691. else
  692. {
  693. //
  694. // Deref the ref that was added by the GPC.
  695. //
  696. DerefClVc(Vc);
  697. PsDbgSend(DBG_FAILURE, DBG_SEND, MP_SEND, NOT_READY, Adapter, Vc, TheirPacket, OurPacket);
  698. if(PktContext->OriginalPacket)
  699. {
  700. NdisFreePacket(OurPacket);
  701. }
  702. else
  703. {
  704. NdisFreeToBlockPool((PUCHAR)PktContext);
  705. }
  706. return(NDIS_STATUS_FAILURE);
  707. }
  708. }
  709. }
  710. }
  711. VOID
  712. ClSendComplete(
  713. IN NDIS_HANDLE ProtocolBindingContext,
  714. IN PNDIS_PACKET Packet,
  715. IN NDIS_STATUS Status
  716. )
  717. /*++
  718. Routine Description:
  719. Completion routine for NdisSendPackets.
  720. Does most of the work for cleaning up after a send.
  721. If necessary, call the PSA's send packet complete function
  722. Arguments:
  723. See the DDK...
  724. Return Values:
  725. None
  726. --*/
  727. {
  728. PGPC_CLIENT_VC Vc;
  729. PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
  730. PPS_SEND_PACKET_CONTEXT PktContext;
  731. PNDIS_PACKET XportPacket;
  732. HANDLE PoolHandle;
  733. //
  734. // Determine if the packet we are completing is the one we allocated. If so, get
  735. // the original packet from the reserved area and free the allocated packet. If this
  736. // is the packet that was sent down to us then just complete the packet.
  737. //
  738. PoolHandle = NdisGetPoolFromPacket(Packet);
  739. if(PoolHandle != Adapter->SendPacketPool)
  740. {
  741. PNDIS_PACKET_STACK PacketStack;
  742. BOOLEAN Remaining;
  743. PacketStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
  744. PsAssert(Remaining != 0);
  745. PktContext = (PPS_SEND_PACKET_CONTEXT) PacketStack->IMReserved[0];
  746. if(PktContext != 0)
  747. {
  748. //
  749. // This packet went via the scheduling components.
  750. //
  751. PsAssert(PktContext->Vc);
  752. Vc = PktContext->Vc;
  753. PsDbgSend(DBG_INFO, DBG_SEND, CL_SEND_COMPLETE, ENTER, Adapter, Vc, Packet, 0);
  754. PsAssert(Vc->Adapter == Adapter);
  755. if(Vc->SendComplete)
  756. (*Vc->SendComplete)(Vc->SendCompletePipeContext, Packet);
  757. DerefClVc(Vc);
  758. NdisFreeToBlockPool((PUCHAR)PktContext);
  759. }
  760. NdisMSendComplete(Adapter->PsNdisHandle,
  761. Packet,
  762. Status);
  763. }
  764. else
  765. {
  766. //
  767. // get the pointer to the upper layer's packet. Reinit the packet struct and
  768. // push it back on the adapter's packet SList. Remove the reference incurred
  769. // when the packet was handled by MpSend
  770. //
  771. PktContext = PS_SEND_PACKET_CONTEXT_FROM_PACKET(Packet);
  772. //
  773. // Call the scheduler if necessary
  774. //
  775. if(PktContext->Vc)
  776. {
  777. //
  778. // Some packets never went through the scheduler.
  779. //
  780. Vc = PktContext->Vc;
  781. PsDbgSend(DBG_INFO, DBG_SEND, CL_SEND_COMPLETE, ENTER, Adapter, Vc, Packet, 0);
  782. PsAssert(Vc->Adapter == Adapter);
  783. if(Vc->SendComplete)
  784. {
  785. (*Vc->SendComplete)(Vc->SendCompletePipeContext, Packet);
  786. }
  787. //
  788. // We have taken a ref on the VCs when we sent the packets
  789. // through the scheduling components. Now is the time to
  790. // Deref them
  791. //
  792. DerefClVc(Vc);
  793. }
  794. else
  795. {
  796. PsDbgSend(DBG_INFO, DBG_SEND, CL_SEND_COMPLETE, ENTER, Adapter, 0, Packet, 0);
  797. }
  798. XportPacket = PktContext->OriginalPacket;
  799. NdisIMCopySendCompletePerPacketInfo(XportPacket, Packet);
  800. NdisFreePacket(Packet);
  801. NdisMSendComplete(Adapter->PsNdisHandle,
  802. XportPacket,
  803. Status);
  804. }
  805. } // ClSendComplete
  806. VOID
  807. DropPacket(
  808. IN HANDLE PipeContext,
  809. IN HANDLE FlowContext,
  810. IN PNDIS_PACKET Packet,
  811. IN NDIS_STATUS Status
  812. )
  813. /*++
  814. Routine Description:
  815. Drop a packet after it was queued by the scheduler.
  816. Arguments:
  817. PipeContext - Pipe context (adapter)
  818. FlowContext - Flow context (adapter VC)
  819. Packet - Packet to drop
  820. Status - Return code to return to NDIS
  821. Return Values:
  822. None
  823. --*/
  824. {
  825. PGPC_CLIENT_VC Vc = (PGPC_CLIENT_VC)FlowContext;
  826. PADAPTER Adapter = (PADAPTER)PipeContext;
  827. PPS_SEND_PACKET_CONTEXT PktContext;
  828. PNDIS_PACKET XportPacket;
  829. HANDLE PoolHandle;
  830. //
  831. // Determine if the packet we are completing is the one we allocated. If so, get
  832. // the original packet from the reserved area and free the allocated packet. If this
  833. // is the packet that was sent down to us then just complete the packet.
  834. //
  835. PoolHandle = NdisGetPoolFromPacket(Packet);
  836. if(PoolHandle != Adapter->SendPacketPool)
  837. {
  838. PNDIS_PACKET_STACK PacketStack;
  839. BOOLEAN Remaining;
  840. PacketStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
  841. PsAssert(Remaining != 0);
  842. PktContext = (PPS_SEND_PACKET_CONTEXT) PacketStack->IMReserved[0];
  843. PsAssert(PktContext != 0);
  844. PsAssert(Vc == PktContext->Vc);
  845. PsAssert(Adapter == Vc->Adapter);
  846. NdisFreeToBlockPool((PUCHAR)PktContext);
  847. NdisMSendComplete(Adapter->PsNdisHandle,
  848. Packet,
  849. Status);
  850. }
  851. else
  852. {
  853. PktContext = PS_SEND_PACKET_CONTEXT_FROM_PACKET(Packet);
  854. PsAssert(PktContext != 0);
  855. PsAssert(Vc == PktContext->Vc);
  856. PsAssert(Adapter == Vc->Adapter);
  857. XportPacket = PktContext->OriginalPacket;
  858. NdisFreePacket(Packet);
  859. NdisMSendComplete(Adapter->PsNdisHandle,
  860. XportPacket,
  861. Status);
  862. }
  863. Vc->Stats.DroppedPackets ++;
  864. PsDbgSend(DBG_INFO, DBG_SEND, DROP_PACKET, ENTER, Adapter, Vc, Packet, 0);
  865. DerefClVc(Vc);
  866. } // DropPacket
  867. char*
  868. ReturnByteAtOffset( PNDIS_PACKET pNdisPacket, ULONG Offset)
  869. {
  870. PVOID VA;
  871. PNDIS_BUFFER pNdisBuf1, pNdisBuf2;
  872. UINT Len;
  873. pNdisBuf1 = pNdisPacket->Private.Head;
  874. NdisQueryBuffer(pNdisBuf1, &VA, &Len);
  875. while(Len <= Offset)
  876. {
  877. Offset -= Len;
  878. NdisGetNextBuffer(pNdisBuf1, &pNdisBuf2);
  879. NdisQueryBuffer(pNdisBuf2, &VA, &Len);
  880. pNdisBuf1 = pNdisBuf2;
  881. }
  882. return (char*)(((char*)VA) + Offset);
  883. }
  884. PGPC_CLIENT_VC FASTCALL
  885. GetVcByClassifyingPacket(
  886. PADAPTER Adapter,
  887. PTC_INTERFACE_ID pInterfaceID,
  888. PNDIS_PACKET OurPacket
  889. )
  890. /*+++
  891. ---*/
  892. {
  893. CLASSIFICATION_HANDLE ClassificationHandle;
  894. PGPC_CLIENT_VC Vc = NULL;
  895. NDIS_STATUS Status;
  896. ULONG ProtocolType;
  897. //
  898. // Let's act based on the ClassificationType we read from the registry key.
  899. // This is specific to debug version only.
  900. // case 0: (default): Use preclassification information, classify otherwise
  901. // case 1: Use prelcassification information ONLY
  902. // case 2: Use classification information ONLY
  903. //
  904. ClassificationHandle = (CLASSIFICATION_HANDLE)
  905. PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(OurPacket, ClassificationHandlePacketInfo));
  906. #if DBG
  907. if (ClassificationType == 2) {
  908. ClassificationHandle = 0;
  909. }
  910. #endif
  911. if (ClassificationHandle)
  912. {
  913. PsAssert(GpcEntries.GpcGetCfInfoClientContextHandler);
  914. Vc = GpcEntries.GpcGetCfInfoClientContextWithRefHandler(GpcQosClientHandle,
  915. ClassificationHandle,
  916. FIELD_OFFSET(GPC_CLIENT_VC, RefCount));
  917. //
  918. // If we got a Vc that was not destined for this adapter, we have to reject it.
  919. //
  920. if(Vc)
  921. {
  922. if(Vc->Adapter != Adapter)
  923. {
  924. DerefClVc(Vc);
  925. }
  926. else
  927. return Vc;
  928. }
  929. }
  930. #if DBG
  931. if (ClassificationType == 1) {
  932. return NULL;
  933. }
  934. #endif
  935. //
  936. // Let's classify this packet since we did not get a Classification ID or a proper Vc.
  937. //
  938. PsAssert(GpcEntries.GpcClassifyPacketHandler);
  939. switch(NDIS_GET_PACKET_PROTOCOL_TYPE(OurPacket))
  940. {
  941. case NDIS_PROTOCOL_ID_TCP_IP:
  942. ProtocolType = GPC_PROTOCOL_TEMPLATE_IP;
  943. break;
  944. case NDIS_PROTOCOL_ID_IPX:
  945. ProtocolType = GPC_PROTOCOL_TEMPLATE_IPX;
  946. break;
  947. default:
  948. ProtocolType = GPC_PROTOCOL_TEMPLATE_NOT_SPECIFIED;
  949. break;
  950. }
  951. //
  952. // If the adapter type is 802.5 (Token Ring), then the MAC header can be of variable size.
  953. // The format of the MAC header is as follows:
  954. // +---------------------+-------------+----------+-----------
  955. // | 2 + 6 (DA) + 6 (SA) | Optional RI | 8 (SNAP) | IP
  956. // +---------------------+-------------+----------+-----------
  957. // Optional RI is present if and only if RI bit as part of SA is set.
  958. // When RI is present, its length is give by the lower 5 bits of the 15th byte.
  959. // 1. Get the VA for the 9th and the 15th bytes.
  960. // 2. If RI if not present, Offset = 14 + 6.
  961. // 3. If present, Offset = 14 + 6 + RI-Size.
  962. if(Adapter->MediaType == NdisMedium802_5)
  963. {
  964. PNDIS_BUFFER pTempNdisBuffer;
  965. PUCHAR pHeaderBuffer;
  966. ULONG BufferLength;
  967. ULONG TotalLength;
  968. ULONG IpOffset;
  969. NdisGetFirstBufferFromPacket( OurPacket,
  970. &pTempNdisBuffer,
  971. &pHeaderBuffer,
  972. &BufferLength,
  973. &TotalLength);
  974. ASSERT( BufferLength >= 15);
  975. if( (*(ReturnByteAtOffset(OurPacket, 8)) & 0x80) == 0)
  976. IpOffset = 14 + 8;
  977. else
  978. IpOffset = 14 + 8 + (*(ReturnByteAtOffset(OurPacket, 14)) & 0x1f);
  979. Status = GpcEntries.GpcClassifyPacketHandler(
  980. GpcQosClientHandle,
  981. ProtocolType,
  982. OurPacket,
  983. IpOffset,
  984. pInterfaceID,
  985. (PGPC_CLIENT_HANDLE)&Vc,
  986. &ClassificationHandle);
  987. }
  988. else
  989. {
  990. PNDIS_BUFFER pTempNdisBuffer;
  991. PUCHAR pHeaderBuffer;
  992. ULONG BufferLength;
  993. ULONG TotalLength;
  994. ULONG IpOffset;
  995. PVOID VA;
  996. PNDIS_BUFFER pNdisBuf1, pNdisBuf2;
  997. UINT Len;
  998. ENetHeader UNALIGNED * EHdr;
  999. pNdisBuf1 = OurPacket->Private.Head;
  1000. NdisQueryBuffer(pNdisBuf1, &VA, &Len);
  1001. EHdr = (ENetHeader UNALIGNED *)VA;
  1002. if (EHdr == NULL)
  1003. return NULL;
  1004. // We don't want to do any fancy parsing other than this. If the frame
  1005. // is not of standard ethernet type, bail out.
  1006. if ((Adapter->MediaType == NdisMedium802_3) && (net_short(EHdr->eh_type) >= MIN_ETYPE))
  1007. {
  1008. ULONG FrameOffset;
  1009. // The conditional is basically to cover up a bug in wandrv.sys, which gives
  1010. // bogus frame header sizes. We look at the IP Header offset supplied
  1011. // by the protocol above for IP packets only, as we are saving only
  1012. // those for the time being.
  1013. if ((NDIS_GET_PACKET_PROTOCOL_TYPE(OurPacket) == NDIS_PROTOCOL_ID_TCP_IP) &&
  1014. (Adapter->IPHeaderOffset)) {
  1015. FrameOffset = Adapter->IPHeaderOffset;
  1016. } else {
  1017. FrameOffset = Adapter->HeaderSize;
  1018. }
  1019. Status = GpcEntries.GpcClassifyPacketHandler(
  1020. GpcQosClientHandle,
  1021. ProtocolType,
  1022. OurPacket,
  1023. FrameOffset,
  1024. pInterfaceID,
  1025. (PGPC_CLIENT_HANDLE)&Vc,
  1026. &ClassificationHandle);
  1027. } else {
  1028. return NULL;
  1029. }
  1030. }
  1031. if(Status == GPC_STATUS_SUCCESS)
  1032. {
  1033. //
  1034. // If we have succeeded, we must get a Classification Handle
  1035. //
  1036. PsAssert(ClassificationHandle != 0);
  1037. //
  1038. // The Classification succeeded. If we found a ClassificationHandle
  1039. // then we must write it in the packet so that anyone below us can use
  1040. // it. The very fact that we are here indicates that we did not start
  1041. // with a Classification handle or we got a bad one. So, we need not
  1042. // worry about over writing the classification handle in the packet.
  1043. //
  1044. NDIS_PER_PACKET_INFO_FROM_PACKET(OurPacket, ClassificationHandlePacketInfo) =
  1045. UlongToPtr(ClassificationHandle);
  1046. Vc = GpcEntries.GpcGetCfInfoClientContextWithRefHandler(
  1047. GpcQosClientHandle,
  1048. ClassificationHandle,
  1049. FIELD_OFFSET(GPC_CLIENT_VC, RefCount));
  1050. }
  1051. if(Vc && Vc->Adapter != Adapter)
  1052. {
  1053. //
  1054. // We have used the GPC APIs that return a Vc with a ref. We have to
  1055. // deref here, because we got a wrong Vc for this adapter.
  1056. //
  1057. DerefClVc(Vc);
  1058. return NULL;
  1059. }
  1060. return Vc;
  1061. }
  1062. VOID
  1063. ClCoSendComplete(
  1064. IN NDIS_STATUS Status,
  1065. IN NDIS_HANDLE ProtocolVcContext,
  1066. IN PNDIS_PACKET Packet
  1067. )
  1068. {
  1069. PGPC_CLIENT_VC Vc = (PGPC_CLIENT_VC) ProtocolVcContext;
  1070. ClSendComplete(Vc->Adapter,
  1071. Packet,
  1072. Status);
  1073. } // ClCoSendComplete
  1074. /* end send.c */