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.

1259 lines
35 KiB

  1. /*++
  2. Copyright (c) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. offload.c
  5. Abstract:
  6. This module contains the code that handles offload.
  7. Author:
  8. ChunYe
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. VOID
  15. IPSecFillHwAddSA(
  16. IN PSA_TABLE_ENTRY pSA,
  17. IN PUCHAR Buf,
  18. IN ULONG Len
  19. )
  20. /*++
  21. Routine Description:
  22. Fills in the ADD_SA hw request from pSA
  23. Arguments:
  24. pSA - the SA
  25. Buf - buffer to set info
  26. Len - length
  27. Return Value:
  28. status of the operation
  29. --*/
  30. {
  31. POFFLOAD_IPSEC_ADD_SA pAddSA = (POFFLOAD_IPSEC_ADD_SA)Buf;
  32. POFFLOAD_SECURITY_ASSOCIATION pSAInfo;
  33. LONG Index;
  34. ULONG Offset = 0;
  35. pAddSA->NumSAs = (SHORT)pSA->sa_NumOps;
  36. pAddSA->SrcAddr = pSA->SA_SRC_ADDR;
  37. pAddSA->SrcMask = pSA->SA_SRC_MASK;
  38. pAddSA->DestAddr = pSA->SA_DEST_ADDR;
  39. pAddSA->DestMask = pSA->SA_DEST_MASK;
  40. pAddSA->Protocol = pSA->SA_PROTO;
  41. pAddSA->SrcPort = SA_SRC_PORT(pSA);
  42. pAddSA->DestPort = SA_DEST_PORT(pSA);
  43. if (pSA->sa_Flags & FLAGS_SA_OUTBOUND) {
  44. pAddSA->Flags |= OFFLOAD_OUTBOUND_SA;
  45. } else {
  46. pAddSA->Flags |= OFFLOAD_INBOUND_SA;
  47. }
  48. if (pSA->sa_Flags & FLAGS_SA_TUNNEL) {
  49. pAddSA->DestTunnelAddr = pSA->sa_TunnelAddr;
  50. pAddSA->SrcTunnelAddr = pSA->sa_SrcTunnelAddr;
  51. }
  52. for (Index = 0; Index < pSA->sa_NumOps; Index++) {
  53. pSAInfo = &pAddSA->SecAssoc[Index];
  54. pSAInfo->Operation = pSA->sa_Operation[Index];
  55. pSAInfo->SPI = pSA->sa_OtherSPIs[Index];
  56. pSAInfo->EXT_INT_ALGO = pSA->INT_ALGO(Index);
  57. pSAInfo->EXT_INT_KEYLEN = pSA->INT_KEYLEN(Index);
  58. pSAInfo->EXT_INT_ROUNDS = pSA->INT_ROUNDS(Index);
  59. pSAInfo->EXT_CONF_ALGO = pSA->CONF_ALGO(Index);
  60. pSAInfo->EXT_CONF_KEYLEN = pSA->CONF_KEYLEN(Index);
  61. pSAInfo->EXT_CONF_ROUNDS = pSA->CONF_ROUNDS(Index);
  62. //
  63. // now get the keys in
  64. //
  65. ASSERT(Len >= sizeof(OFFLOAD_IPSEC_ADD_SA) + pSA->INT_KEYLEN(Index) + pSA->CONF_KEYLEN(Index));
  66. RtlCopyMemory( pAddSA->KeyMat + Offset,
  67. pSA->CONF_KEY(Index),
  68. pSA->CONF_KEYLEN(Index));
  69. RtlCopyMemory( pAddSA->KeyMat + Offset + pSA->CONF_KEYLEN(Index),
  70. pSA->INT_KEY(Index),
  71. pSA->INT_KEYLEN(Index));
  72. Offset = pSA->INT_KEYLEN(Index) + pSA->CONF_KEYLEN(Index);
  73. pAddSA->KeyLen += Offset;
  74. IPSEC_DEBUG(HW, ("pAddSA: %lx, keylen: %lx, KeyMat: %lx\n", pAddSA, pAddSA->KeyLen, pAddSA->KeyMat));
  75. }
  76. }
  77. NDIS_STATUS
  78. IPSecPlumbHw(
  79. IN PVOID DestIF,
  80. IN PVOID Buf,
  81. IN ULONG Len,
  82. IN NDIS_OID Oid
  83. )
  84. /*++
  85. Routine Description:
  86. Plumbs the input outbound and its corresponding inbound SA
  87. into the hw accelerator.
  88. Arguments:
  89. DestIF - the IP Interface
  90. Buf - buffer to set info
  91. Len - length
  92. Return Value:
  93. status of the operation
  94. --*/
  95. {
  96. #if DBG
  97. NTSTATUS status;
  98. if (Oid == OID_TCP_TASK_IPSEC_ADD_SA) {
  99. IPSEC_INCREMENT(NumAddSA);
  100. }
  101. if (Oid == OID_TCP_TASK_IPSEC_DELETE_SA) {
  102. IPSEC_INCREMENT(NumDelSA);
  103. }
  104. status = TCPIP_NDIS_REQUEST(DestIF,
  105. NdisRequestSetInformation,
  106. Oid,
  107. Buf,
  108. Len,
  109. NULL);
  110. if (status == STATUS_SUCCESS) {
  111. if (Oid == OID_TCP_TASK_IPSEC_ADD_SA) {
  112. IPSEC_INCREMENT(NumAddSU);
  113. }
  114. if (Oid == OID_TCP_TASK_IPSEC_DELETE_SA) {
  115. IPSEC_INCREMENT(NumDelSU);
  116. }
  117. } else {
  118. if (Oid == OID_TCP_TASK_IPSEC_ADD_SA) {
  119. IPSEC_INCREMENT(NumAddFA);
  120. }
  121. if (Oid == OID_TCP_TASK_IPSEC_DELETE_SA) {
  122. IPSEC_INCREMENT(NumDelFA);
  123. }
  124. }
  125. return status;
  126. #else
  127. return TCPIP_NDIS_REQUEST( DestIF,
  128. NdisRequestSetInformation,
  129. Oid,
  130. Buf,
  131. Len,
  132. NULL);
  133. #endif
  134. }
  135. NTSTATUS
  136. IPSecSendOffload(
  137. IN IPHeader UNALIGNED *pIPHeader,
  138. IN PNDIS_PACKET Packet,
  139. IN Interface *DestIF,
  140. IN PSA_TABLE_ENTRY pSA,
  141. IN PSA_TABLE_ENTRY pNextSA,
  142. IN PVOID *ppSCContext,
  143. IN BOOLEAN *pfCryptoOnly
  144. )
  145. {
  146. KIRQL kIrql;
  147. BOOLEAN fRefBumped = FALSE;
  148. NTSTATUS status = STATUS_UNSUCCESSFUL;
  149. PSA_TABLE_ENTRY pSaveSA = NULL;
  150. PIPSEC_SEND_COMPLETE_CONTEXT pContext = NULL;
  151. PNDIS_IPSEC_PACKET_INFO IPSecPktInfo = NULL;
  152. PNDIS_PACKET_EXTENSION PktExt = NDIS_PACKET_EXTENSION_FROM_PACKET(Packet);
  153. IPSEC_DEBUG(HW, ("IPSecSendOffload: DestIF: %lx, DestIF->Flags: %lx\n", DestIF, DestIF->if_OffloadFlags));
  154. *pfCryptoOnly = FALSE;
  155. //
  156. // See if options are supported.
  157. //
  158. if (((pIPHeader->iph_verlen & (UCHAR)~IP_VER_FLAG) << 2) > sizeof(IPHeader) &&
  159. !(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_V4_OPTIONS)) {
  160. status = STATUS_UNSUCCESSFUL;
  161. IPSEC_DEBUG(HW, ("Options present - not offloading the packet. HdrLen %d\n",
  162. ((pIPHeader->iph_verlen & (UCHAR)~IP_VER_FLAG) << 2)));
  163. return (status);
  164. }
  165. AcquireWriteLock(&g_ipsec.SADBLock, &kIrql);
  166. do {
  167. if ((pSA->sa_Flags & FLAGS_SA_HW_PLUMBED) &&
  168. pSA->sa_IPIF == DestIF) {
  169. if (*ppSCContext == NULL) {
  170. pContext = IPSecAllocateSendCompleteCtx(IPSEC_TAG_HW);
  171. if (!pContext) {
  172. IPSEC_DEBUG(HW, ("Failed to alloc. SendCtx\n"));
  173. status = STATUS_INSUFFICIENT_RESOURCES;
  174. IPSecFreePktInfo(IPSecPktInfo);
  175. *ppSCContext = NULL;
  176. break;
  177. }
  178. IPSEC_INCREMENT(g_ipsec.NumSends);
  179. IPSecZeroMemory(pContext, sizeof(IPSEC_SEND_COMPLETE_CONTEXT));
  180. #if DBG
  181. RtlCopyMemory(pContext->Signature, "ISC5", 4);
  182. #endif
  183. *ppSCContext = pContext;
  184. } else {
  185. pContext = *ppSCContext;
  186. }
  187. if (IPSecPktInfo == NULL) {
  188. if (IPSecPktInfo = IPSecAllocatePktInfo(IPSEC_TAG_HW_PKTINFO)) {
  189. IPSecZeroMemory(IPSecPktInfo, sizeof(NDIS_IPSEC_PACKET_INFO));
  190. pContext->Flags |= SCF_PKTINFO;
  191. pContext->PktInfo = IPSecPktInfo;
  192. } else {
  193. IPSEC_DEBUG(HW, ("Failed to alloc. PktInfo\n"));
  194. status = STATUS_UNSUCCESSFUL;
  195. break;
  196. }
  197. }
  198. PktExt->NdisPacketInfo[IpSecPacketInfo] = IPSecPktInfo;
  199. //
  200. // if this is the nextOperationSA
  201. //
  202. if (fRefBumped) {
  203. IPSEC_DEBUG(HW, ("Offloading... pSA: %lx, NextOffloadHandle %lx\n", pSA, pSA->sa_OffloadHandle));
  204. IPSecPktInfo->Transmit.NextOffloadHandle = pSA->sa_OffloadHandle;
  205. } else {
  206. IPSEC_DEBUG(HW, ("Offloading... pSA: %lx, OffloadHandle %lx\n", pSA, pSA->sa_OffloadHandle));
  207. IPSecPktInfo->Transmit.OffloadHandle = pSA->sa_OffloadHandle;
  208. }
  209. *pfCryptoOnly = TRUE;
  210. IPSEC_DEBUG(HW, ("Using Hw for SA->handle: %lx on IF: %lx IPSecPktInfo: %lx *pfCryptoOnly %d\n", pSA->sa_OffloadHandle, DestIF, IPSecPktInfo, *pfCryptoOnly));
  211. status = STATUS_SUCCESS;
  212. } else if (!(pSA->sa_Flags & FLAGS_SA_HW_PLUMB_FAILED) && !pSA->sa_IPIF) {
  213. PUCHAR outBuf;
  214. ULONG outLen;
  215. LONG Index;
  216. pSA->sa_Flags |= FLAGS_SA_HW_PLUMB_FAILED;
  217. //
  218. // See if CryptoOnly mode is supported.
  219. //
  220. if (!(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_CRYPTO_ONLY)) {
  221. status = STATUS_UNSUCCESSFUL;
  222. break;
  223. }
  224. //
  225. // See if transport over tunnel mode is supported.
  226. //
  227. if (pNextSA &&
  228. !(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_TPT_TUNNEL)) {
  229. status = STATUS_UNSUCCESSFUL;
  230. break;
  231. }
  232. //
  233. // No need to offload soft SAs.
  234. //
  235. if (pSA->sa_Operation[0] == None) {
  236. status = STATUS_UNSUCCESSFUL;
  237. break;
  238. }
  239. //
  240. // Tunnel required, but not supported, don't plumb.
  241. //
  242. if ((pSA->sa_Flags & FLAGS_SA_TUNNEL) &&
  243. ((IS_AH_SA(pSA) &&
  244. !(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_AH_TUNNEL)) ||
  245. (IS_ESP_SA(pSA) &&
  246. !(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_ESP_TUNNEL)))) {
  247. status = STATUS_UNSUCCESSFUL;
  248. break;
  249. }
  250. //
  251. // AH + ESP required, but not supported, don't plumb.
  252. //
  253. if (pSA->sa_NumOps > 1 &&
  254. !(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_AH_ESP)) {
  255. status = STATUS_UNSUCCESSFUL;
  256. break;
  257. }
  258. //
  259. // Check XMT capabilities.
  260. //
  261. if ((IS_AH_SA(pSA) &&
  262. !(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_AH_XMT)) ||
  263. (IS_ESP_SA(pSA) &&
  264. !(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_ESP_XMT))) {
  265. status = STATUS_UNSUCCESSFUL;
  266. break;
  267. }
  268. outLen = sizeof(OFFLOAD_IPSEC_ADD_SA);
  269. for (Index = 0; Index < pSA->sa_NumOps; Index++) {
  270. //
  271. // Check offload capability bits with those in the SA.
  272. //
  273. if ((pSA->INT_ALGO(Index) == IPSEC_AH_MD5) &&
  274. (!(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_AH_MD5)) ||
  275. ((pSA->INT_ALGO(Index) == IPSEC_AH_SHA) &&
  276. (!(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_AH_SHA_1))) ||
  277. ((pSA->CONF_ALGO(Index) == IPSEC_ESP_NONE) &&
  278. (!(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_ESP_NONE))) ||
  279. ((pSA->CONF_ALGO(Index) == IPSEC_ESP_DES) &&
  280. (!(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_ESP_DES))) ||
  281. ((pSA->CONF_ALGO(Index) == IPSEC_ESP_3_DES) &&
  282. (!(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_ESP_3_DES)))) {
  283. status = STATUS_UNSUCCESSFUL;
  284. goto out;
  285. }
  286. outLen += pSA->INT_KEYLEN(Index) + pSA->CONF_KEYLEN(Index);
  287. }
  288. //
  289. // This SA can be offloaded.
  290. //
  291. pSA->sa_Flags |= FLAGS_SA_OFFLOADABLE;
  292. IPSEC_DEBUG(HW, ("outLen: %lx\n", outLen));
  293. outBuf = IPSecAllocateMemory(outLen, IPSEC_TAG_HW_ADDSA);
  294. if (outBuf) {
  295. IPSecZeroMemory(outBuf, outLen);
  296. IPSecFillHwAddSA(pSA, outBuf, outLen);
  297. //
  298. // Bump the SA reference count to make sure they won't
  299. // go away during the processing of the work item.
  300. //
  301. IPSecRefSA(pSA);
  302. //
  303. // Plumb the SA by scheduling a work item; the SA will
  304. // not be used for offload until plumbing succeeds.
  305. //
  306. IPSecBufferPlumbSA( DestIF,
  307. pSA,
  308. outBuf,
  309. outLen);
  310. //
  311. // Return failure here so the caller does it in software.
  312. //
  313. status = STATUS_UNSUCCESSFUL;
  314. break;
  315. } else {
  316. IPSEC_DEBUG(HW, ("Memory: Failed to plumb outboundSA: %lx on IF: %lx\n", pSA, DestIF));
  317. status = STATUS_UNSUCCESSFUL;
  318. break;
  319. }
  320. } else {
  321. status = STATUS_UNSUCCESSFUL;
  322. break;
  323. }
  324. if (pNextSA && !fRefBumped) {
  325. IPSEC_DEBUG(HW, ("RefBumped on SA: %lx\n", pSA));
  326. pSaveSA = pSA;
  327. pSA = pNextSA;
  328. fRefBumped = TRUE;
  329. } else {
  330. break;
  331. }
  332. } while (TRUE);
  333. out:
  334. if (status == STATUS_SUCCESS && (*pfCryptoOnly)) {
  335. ASSERT(pContext);
  336. ASSERT(pContext->Flags & SCF_PKTINFO);
  337. if (fRefBumped) {
  338. IPSecRefSA(pSaveSA);
  339. IPSecRefSA(pNextSA);
  340. IPSEC_INCREMENT(pSaveSA->sa_NumSends);
  341. IPSEC_INCREMENT(pNextSA->sa_NumSends);
  342. pContext->pSA = pSaveSA;
  343. pContext->pNextSA = pNextSA;
  344. } else {
  345. IPSecRefSA(pSA);
  346. IPSEC_INCREMENT(pSA->sa_NumSends);
  347. pContext->pSA = pSA;
  348. }
  349. } else {
  350. if (IPSecPktInfo) {
  351. ASSERT(pContext);
  352. ASSERT(pContext->Flags & SCF_PKTINFO);
  353. IPSecFreePktInfo(pContext->PktInfo);
  354. pContext->Flags &= ~SCF_PKTINFO;
  355. pContext->PktInfo = NULL;
  356. PktExt->NdisPacketInfo[IpSecPacketInfo] = NULL;
  357. }
  358. status = STATUS_UNSUCCESSFUL;
  359. *pfCryptoOnly = FALSE;
  360. }
  361. ReleaseWriteLock(&g_ipsec.SADBLock, kIrql);
  362. return status;
  363. }
  364. NTSTATUS
  365. IPSecRecvOffload(
  366. IN IPHeader UNALIGNED *pIPHeader,
  367. IN Interface *DestIF,
  368. IN PSA_TABLE_ENTRY pSA
  369. )
  370. {
  371. KIRQL kIrql;
  372. NTSTATUS status = STATUS_UNSUCCESSFUL;
  373. IPSEC_DEBUG(HW, ("IPSecRecvOffload: DestIF: %lx, DestIF->Flags: %lx\n", DestIF, DestIF->if_OffloadFlags));
  374. AcquireWriteLock(&g_ipsec.SADBLock, &kIrql);
  375. if (!(pSA->sa_Flags & FLAGS_SA_HW_PLUMB_FAILED) &&
  376. !(pSA->sa_Flags & FLAGS_SA_HW_PLUMBED) &&
  377. !pSA->sa_IPIF) {
  378. PUCHAR inBuf;
  379. ULONG inLen;
  380. LONG Index;
  381. pSA->sa_Flags |= FLAGS_SA_HW_PLUMB_FAILED;
  382. //
  383. // See if CryptoOnly mode is supported.
  384. //
  385. if (!(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_CRYPTO_ONLY)) {
  386. status = STATUS_UNSUCCESSFUL;
  387. goto out;
  388. }
  389. //
  390. // No need to offload soft SAs.
  391. //
  392. if (pSA->sa_Operation[0] == None) {
  393. status = STATUS_UNSUCCESSFUL;
  394. goto out;
  395. }
  396. //
  397. // Tunnel required, but not supported, don't plumb.
  398. //
  399. if ((pSA->sa_Flags & FLAGS_SA_TUNNEL) &&
  400. ((IS_AH_SA(pSA) &&
  401. !(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_AH_TUNNEL)) ||
  402. (IS_ESP_SA(pSA) &&
  403. !(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_ESP_TUNNEL)))) {
  404. status = STATUS_UNSUCCESSFUL;
  405. goto out;
  406. }
  407. //
  408. // AH + ESP required, but not supported, don't plumb.
  409. //
  410. if (pSA->sa_NumOps > 1 &&
  411. !(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_AH_ESP)) {
  412. status = STATUS_UNSUCCESSFUL;
  413. goto out;
  414. }
  415. //
  416. // Check RCV capabilities.
  417. //
  418. if ((IS_AH_SA(pSA) &&
  419. !(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_AH_RCV)) ||
  420. (IS_ESP_SA(pSA) &&
  421. !(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_ESP_RCV))) {
  422. status = STATUS_UNSUCCESSFUL;
  423. goto out;
  424. }
  425. inLen = sizeof(OFFLOAD_IPSEC_ADD_SA);
  426. for (Index = 0; Index < pSA->sa_NumOps; Index++) {
  427. //
  428. // Check offload capability bits with those in the SA
  429. //
  430. if ((pSA->INT_ALGO(Index) == IPSEC_AH_MD5) &&
  431. (!(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_AH_MD5)) ||
  432. ((pSA->INT_ALGO(Index) == IPSEC_AH_SHA) &&
  433. (!(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_AH_SHA_1))) ||
  434. ((pSA->CONF_ALGO(Index) == IPSEC_ESP_NONE) &&
  435. (!(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_ESP_NONE))) ||
  436. ((pSA->CONF_ALGO(Index) == IPSEC_ESP_DES) &&
  437. (!(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_ESP_DES))) ||
  438. ((pSA->CONF_ALGO(Index) == IPSEC_ESP_3_DES) &&
  439. (!(DestIF->if_OffloadFlags & IPSEC_OFFLOAD_ESP_3_DES)))) {
  440. status = STATUS_UNSUCCESSFUL;
  441. goto out;
  442. }
  443. inLen += pSA->INT_KEYLEN(Index) + pSA->CONF_KEYLEN(Index);
  444. }
  445. IPSEC_DEBUG(HW, ("inLen: %lx\n", inLen));
  446. inBuf = IPSecAllocateMemory(inLen, IPSEC_TAG_HW_ADDSA);
  447. if (inBuf) {
  448. IPSecZeroMemory(inBuf, inLen);
  449. IPSecFillHwAddSA(pSA, inBuf, inLen);
  450. //
  451. // Bump the SA reference count to make sure they won't
  452. // go away during the processing of the work item.
  453. //
  454. IPSecRefSA(pSA);
  455. //
  456. // Plumb the SA by scheduling a work item; the SA will
  457. // not be used for offload until plumbing succeeds.
  458. //
  459. status = IPSecBufferPlumbSA(DestIF,
  460. pSA,
  461. inBuf,
  462. inLen);
  463. //
  464. // Return failure here so the caller does it in software.
  465. //
  466. status = STATUS_UNSUCCESSFUL;
  467. goto out;
  468. } else {
  469. IPSEC_DEBUG(HW, ("Memory: Failed to plumb inboundSA: %lx on IF: %lx\n", pSA, DestIF));
  470. status = STATUS_UNSUCCESSFUL;
  471. goto out;
  472. }
  473. }
  474. out:
  475. ReleaseWriteLock(&g_ipsec.SADBLock, kIrql);
  476. return status;
  477. }
  478. NTSTATUS
  479. IPSecDelHWSA(
  480. IN PSA_TABLE_ENTRY pSA
  481. )
  482. {
  483. NTSTATUS status = STATUS_SUCCESS;
  484. ASSERT(pSA->sa_Flags & FLAGS_SA_HW_PLUMBED);
  485. pSA->sa_Flags &= ~FLAGS_SA_HW_PLUMBED;
  486. pSA->sa_Flags |= FLAGS_SA_HW_PLUMB_FAILED;
  487. if ((pSA->sa_Flags & FLAGS_SA_OUTBOUND) &&
  488. IPSEC_GET_VALUE(pSA->sa_NumSends) > 0) {
  489. pSA->sa_Flags |= FLAGS_SA_HW_DELETE_SA;
  490. return STATUS_PENDING;
  491. }
  492. pSA->sa_Flags &= ~FLAGS_SA_HW_DELETE_SA;
  493. pSA->sa_Flags |= FLAGS_SA_HW_DELETE_QUEUED;
  494. ASSERT(pSA->sa_IPIF);
  495. if (pSA->sa_IPIF) {
  496. status = IPSecPlumbHw( pSA->sa_IPIF,
  497. &pSA->sa_OffloadHandle,
  498. sizeof(OFFLOAD_IPSEC_DELETE_SA),
  499. OID_TCP_TASK_IPSEC_DELETE_SA);
  500. IPSEC_DEBUG(HWAPI, ("DelHWSA %s: %lx, handle: %lx, status: %lx\n",
  501. (pSA->sa_Flags & FLAGS_SA_OUTBOUND)? "outbound": "inbound",
  502. pSA,
  503. pSA->sa_OffloadHandle,
  504. status));
  505. IPSEC_DEC_STATISTIC(dwNumOffloadedSAs);
  506. IPSecDerefSA(pSA);
  507. }
  508. return status;
  509. }
  510. NTSTATUS
  511. IPSecDelHWSAAtDpc(
  512. IN PSA_TABLE_ENTRY pSA
  513. )
  514. {
  515. ASSERT(pSA->sa_Flags & (FLAGS_SA_HW_PLUMBED | FLAGS_SA_HW_DELETE_SA));
  516. pSA->sa_Flags &= ~FLAGS_SA_HW_PLUMBED;
  517. pSA->sa_Flags |= FLAGS_SA_HW_PLUMB_FAILED;
  518. if ((pSA->sa_Flags & FLAGS_SA_OUTBOUND) &&
  519. IPSEC_GET_VALUE(pSA->sa_NumSends) > 0) {
  520. pSA->sa_Flags |= FLAGS_SA_HW_DELETE_SA;
  521. return STATUS_PENDING;
  522. }
  523. pSA->sa_Flags &= ~FLAGS_SA_HW_DELETE_SA;
  524. pSA->sa_Flags |= FLAGS_SA_HW_DELETE_QUEUED;
  525. ASSERT(pSA->sa_IPIF);
  526. ExInitializeWorkItem( &pSA->sa_QueueItem,
  527. IPSecProcessDeleteSA,
  528. (PVOID)pSA);
  529. ExQueueWorkItem(&pSA->sa_QueueItem, DelayedWorkQueue);
  530. IPSEC_INCREMENT(g_ipsec.NumWorkers);
  531. return STATUS_SUCCESS;
  532. }
  533. NTSTATUS
  534. IPSecBufferPlumbSA(
  535. IN Interface *DestIF,
  536. IN PSA_TABLE_ENTRY pSA,
  537. IN PUCHAR Buf,
  538. IN ULONG Len
  539. )
  540. {
  541. PIPSEC_PLUMB_SA pPlumbSA;
  542. pPlumbSA = IPSecAllocateMemory(sizeof(IPSEC_PLUMB_SA), IPSEC_TAG_HW_PLUMB);
  543. if (pPlumbSA == NULL) {
  544. IPSecFreeMemory(Buf);
  545. if (pSA) {
  546. IPSecDerefSA(pSA);
  547. }
  548. return STATUS_INSUFFICIENT_RESOURCES;
  549. }
  550. pPlumbSA->pSA = pSA;
  551. pPlumbSA->DestIF = DestIF;
  552. pPlumbSA->Buf = Buf;
  553. pPlumbSA->Len = Len;
  554. ExInitializeWorkItem( &pPlumbSA->PlumbQueueItem,
  555. IPSecProcessPlumbSA,
  556. (PVOID)pPlumbSA);
  557. ExQueueWorkItem(&pPlumbSA->PlumbQueueItem, DelayedWorkQueue);
  558. IPSEC_INCREMENT(g_ipsec.NumWorkers);
  559. return STATUS_SUCCESS;
  560. }
  561. NTSTATUS
  562. IPSecProcessPlumbSA(
  563. IN PVOID Context
  564. )
  565. {
  566. PIPSEC_PLUMB_SA pPlumbSA = (PIPSEC_PLUMB_SA)Context;
  567. NTSTATUS status = STATUS_SUCCESS;
  568. KIRQL kIrql;
  569. Interface *DestIF = pPlumbSA->DestIF;
  570. PSA_TABLE_ENTRY pSA = pPlumbSA->pSA;
  571. PUCHAR Buf = pPlumbSA->Buf;
  572. ULONG Len = pPlumbSA->Len;
  573. //
  574. // Plumb this SA into the hw if acceleration is enabled
  575. // on this card and it has not been plumbed already.
  576. //
  577. if (pSA) {
  578. IPSEC_DEBUG(HW, ("About to plumb outbound\n"));
  579. status = IPSecPlumbHw( DestIF,
  580. Buf,
  581. Len,
  582. OID_TCP_TASK_IPSEC_ADD_SA);
  583. IPSEC_DEBUG(HWAPI, ("AddHWSA %s: %lx, handle: %lx, status: %lx\n",
  584. (pSA->sa_Flags & FLAGS_SA_OUTBOUND)? "outbound": "inbound",
  585. pSA,
  586. ((POFFLOAD_IPSEC_ADD_SA)Buf)->OffloadHandle,
  587. status));
  588. AcquireWriteLock(&g_ipsec.SADBLock, &kIrql);
  589. pSA->sa_IPIF = DestIF;
  590. if (status != STATUS_SUCCESS) {
  591. IPSEC_DEBUG(HW, ("Failed to plumb SA: %lx on IF: %lx, status: %lx\n", pSA, DestIF, status));
  592. pSA->sa_Flags |= FLAGS_SA_HW_PLUMB_FAILED;
  593. IPSecDerefSA(pSA);
  594. } else {
  595. pSA->sa_OffloadHandle = ((POFFLOAD_IPSEC_ADD_SA)Buf)->OffloadHandle;
  596. IPSEC_DEBUG(HW, ("Success plumb SA: %lx, pSA->sa_OffloadHandle %lx\n", pSA, pSA->sa_OffloadHandle));
  597. pSA->sa_Flags |= FLAGS_SA_HW_PLUMBED;
  598. pSA->sa_Flags &= ~FLAGS_SA_HW_PLUMB_FAILED;
  599. IPSEC_INC_STATISTIC(dwNumOffloadedSAs);
  600. }
  601. if (status == STATUS_SUCCESS &&
  602. !(pSA->sa_State == STATE_SA_ACTIVE &&
  603. (pSA->sa_Flags & FLAGS_SA_ON_FILTER_LIST) &&
  604. pSA->sa_AssociatedSA)) {
  605. //
  606. // SA got deleted before we plumb, call DelHWSA now since
  607. // HW_PLUMBED wasn't set when the SA was deleted.
  608. //
  609. IPSecDelHWSAAtDpc(pSA);
  610. }
  611. ReleaseWriteLock(&g_ipsec.SADBLock, kIrql);
  612. }
  613. IPSecFreeMemory(Buf);
  614. IPSecFreeMemory(pPlumbSA);
  615. IPSEC_DECREMENT(g_ipsec.NumWorkers);
  616. return status;
  617. }
  618. NTSTATUS
  619. IPSecProcessDeleteSA(
  620. IN PVOID Context
  621. )
  622. {
  623. PSA_TABLE_ENTRY pSA = (PSA_TABLE_ENTRY)Context;
  624. NTSTATUS status;
  625. ASSERT(IPSEC_GET_VALUE(pSA->sa_NumSends) == 0);
  626. status = IPSecPlumbHw( pSA->sa_IPIF,
  627. &pSA->sa_OffloadHandle,
  628. sizeof(OFFLOAD_IPSEC_DELETE_SA),
  629. OID_TCP_TASK_IPSEC_DELETE_SA);
  630. IPSEC_DEBUG(HWAPI, ("ProcessDeleteSA %s: %lx, handle: %lx, status: %lx\n",
  631. (pSA->sa_Flags & FLAGS_SA_OUTBOUND)? "outbound": "inbound",
  632. pSA,
  633. pSA->sa_OffloadHandle,
  634. status));
  635. IPSEC_DEC_STATISTIC(dwNumOffloadedSAs);
  636. IPSecDerefSA(pSA);
  637. IPSEC_DECREMENT(g_ipsec.NumWorkers);
  638. return status;
  639. }
  640. NTSTATUS
  641. IPSecNdisStatus(
  642. IN PVOID IPContext,
  643. IN UINT Status
  644. )
  645. /*++
  646. Routine Description:
  647. Notify Interface has a NDIS status change.
  648. Arguments:
  649. IPContext - This is the Interface notified of status change.
  650. Return Value:
  651. --*/
  652. {
  653. IPSEC_DEBUG(HWAPI, ("IPSecNdisStatus %lx called for interface %lx\n", Status, IPContext));
  654. switch (Status) {
  655. case NDIS_STATUS_NETWORK_UNREACHABLE:
  656. IPSecDeleteIF(IPContext);
  657. break;
  658. case NDIS_STATUS_RESET_START:
  659. IPSecResetStart(IPContext);
  660. break;
  661. case NDIS_STATUS_RESET_END:
  662. IPSecResetEnd(IPContext);
  663. break;
  664. case NDIS_STATUS_INTERFACE_UP:
  665. IPSecWakeUp(IPContext);
  666. break;
  667. default:
  668. ASSERT(FALSE);
  669. break;
  670. }
  671. return STATUS_SUCCESS;
  672. }
  673. VOID
  674. IPSecDeleteIF(
  675. IN PVOID IPContext
  676. )
  677. /*++
  678. Routine Description:
  679. Notify Interface is deleted so need to clean up SA's that are offloaded
  680. on the deleted interface.
  681. Arguments:
  682. IPContext - This is the Interface being deleted.
  683. Return Value:
  684. --*/
  685. {
  686. Interface *DestIF = (Interface *)IPContext;
  687. PLIST_ENTRY pFilterEntry;
  688. PLIST_ENTRY pSAEntry;
  689. PFILTER pFilter;
  690. PSA_TABLE_ENTRY pSA;
  691. KIRQL kIrql;
  692. LONG Index;
  693. LONG SAIndex;
  694. IPSEC_DEBUG(HWAPI, ("IPSecDeleteIF called for interface %lx\n", DestIF));
  695. //
  696. // Go through all SA's and unmark the offload bits.
  697. //
  698. AcquireWriteLock(&g_ipsec.SADBLock, &kIrql);
  699. for ( Index = MIN_FILTER;
  700. Index <= MAX_FILTER;
  701. Index++) {
  702. for ( pFilterEntry = g_ipsec.FilterList[Index].Flink;
  703. pFilterEntry != &g_ipsec.FilterList[Index];
  704. pFilterEntry = pFilterEntry->Flink) {
  705. pFilter = CONTAINING_RECORD(pFilterEntry,
  706. FILTER,
  707. MaskedLinkage);
  708. for ( SAIndex = 0;
  709. SAIndex < pFilter->SAChainSize;
  710. SAIndex++) {
  711. for ( pSAEntry = pFilter->SAChain[SAIndex].Flink;
  712. pSAEntry != &pFilter->SAChain[SAIndex];
  713. pSAEntry = pSAEntry->Flink) {
  714. pSA = CONTAINING_RECORD(pSAEntry,
  715. SA_TABLE_ENTRY,
  716. sa_FilterLinkage);
  717. if ((pSA->sa_Flags & FLAGS_SA_HW_PLUMBED) &&
  718. (DestIF == pSA->sa_IPIF)) {
  719. pSA->sa_Flags &= ~FLAGS_SA_HW_PLUMBED;
  720. pSA->sa_Flags |= FLAGS_SA_HW_PLUMB_FAILED;
  721. pSA->sa_Flags &= ~FLAGS_SA_HW_DELETE_SA;
  722. IPSEC_DEC_STATISTIC(dwNumOffloadedSAs);
  723. #if DBG
  724. NumReset++;
  725. #endif
  726. IPSecDerefSA(pSA);
  727. }
  728. }
  729. }
  730. }
  731. }
  732. ReleaseWriteLock(&g_ipsec.SADBLock, kIrql);
  733. }
  734. VOID
  735. IPSecResetStart(
  736. IN PVOID IPContext
  737. )
  738. /*++
  739. Routine Description:
  740. Notify Interface is being reset.
  741. Arguments:
  742. IPContext - This is the Interface being reset.
  743. Return Value:
  744. --*/
  745. {
  746. Interface *DestIF = (Interface *)IPContext;
  747. PLIST_ENTRY pFilterEntry;
  748. PLIST_ENTRY pSAEntry;
  749. PFILTER pFilter;
  750. PSA_TABLE_ENTRY pSA;
  751. KIRQL kIrql;
  752. LONG Index;
  753. LONG SAIndex;
  754. IPSEC_DEBUG(HWAPI, ("IPSecResetStart called for interface %lx\n", DestIF));
  755. //
  756. // Go through all SA's and unmark the offload bits.
  757. //
  758. AcquireWriteLock(&g_ipsec.SADBLock, &kIrql);
  759. for ( Index = MIN_FILTER;
  760. Index <= MAX_FILTER;
  761. Index++) {
  762. for ( pFilterEntry = g_ipsec.FilterList[Index].Flink;
  763. pFilterEntry != &g_ipsec.FilterList[Index];
  764. pFilterEntry = pFilterEntry->Flink) {
  765. pFilter = CONTAINING_RECORD(pFilterEntry,
  766. FILTER,
  767. MaskedLinkage);
  768. for ( SAIndex = 0;
  769. SAIndex < pFilter->SAChainSize;
  770. SAIndex++) {
  771. for ( pSAEntry = pFilter->SAChain[SAIndex].Flink;
  772. pSAEntry != &pFilter->SAChain[SAIndex];
  773. pSAEntry = pSAEntry->Flink) {
  774. pSA = CONTAINING_RECORD(pSAEntry,
  775. SA_TABLE_ENTRY,
  776. sa_FilterLinkage);
  777. if ((pSA->sa_Flags & FLAGS_SA_HW_PLUMBED) &&
  778. (DestIF == pSA->sa_IPIF)) {
  779. pSA->sa_Flags &= ~FLAGS_SA_HW_PLUMBED;
  780. pSA->sa_Flags |= FLAGS_SA_HW_PLUMB_FAILED;
  781. pSA->sa_Flags &= ~FLAGS_SA_HW_DELETE_SA;
  782. pSA->sa_Flags |= FLAGS_SA_HW_RESET;
  783. IPSEC_DEC_STATISTIC(dwNumOffloadedSAs);
  784. #if DBG
  785. NumReset++;
  786. #endif
  787. IPSecDerefSA(pSA);
  788. }
  789. }
  790. }
  791. }
  792. }
  793. IPSecNumResets++;
  794. ReleaseWriteLock(&g_ipsec.SADBLock, kIrql);
  795. }
  796. VOID
  797. IPSecResetEnd(
  798. IN PVOID IPContext
  799. )
  800. /*++
  801. Routine Description:
  802. Notify Interface reset is completed.
  803. Arguments:
  804. IPContext - This is the Interface being reset.
  805. Return Value:
  806. --*/
  807. {
  808. Interface *DestIF = (Interface *)IPContext;
  809. PLIST_ENTRY pFilterEntry;
  810. PLIST_ENTRY pSAEntry;
  811. PFILTER pFilter;
  812. PSA_TABLE_ENTRY pSA;
  813. KIRQL kIrql;
  814. LONG Index;
  815. LONG SAIndex;
  816. IPSEC_DEBUG(HWAPI, ("IPSecResetEnd called for interface %lx\n", DestIF));
  817. //
  818. // Go through all SA's and unmark the offload bits.
  819. //
  820. AcquireWriteLock(&g_ipsec.SADBLock, &kIrql);
  821. for ( Index = MIN_FILTER;
  822. Index <= MAX_FILTER;
  823. Index++) {
  824. for ( pFilterEntry = g_ipsec.FilterList[Index].Flink;
  825. pFilterEntry != &g_ipsec.FilterList[Index];
  826. pFilterEntry = pFilterEntry->Flink) {
  827. pFilter = CONTAINING_RECORD(pFilterEntry,
  828. FILTER,
  829. MaskedLinkage);
  830. for ( SAIndex = 0;
  831. SAIndex < pFilter->SAChainSize;
  832. SAIndex++) {
  833. for ( pSAEntry = pFilter->SAChain[SAIndex].Flink;
  834. pSAEntry != &pFilter->SAChain[SAIndex];
  835. pSAEntry = pSAEntry->Flink) {
  836. pSA = CONTAINING_RECORD(pSAEntry,
  837. SA_TABLE_ENTRY,
  838. sa_FilterLinkage);
  839. if ((pSA->sa_Flags & FLAGS_SA_HW_PLUMB_FAILED) &&
  840. !(pSA->sa_Flags & FLAGS_SA_HW_DELETE_QUEUED) &&
  841. (DestIF == pSA->sa_IPIF)) {
  842. pSA->sa_Flags &= ~FLAGS_SA_HW_PLUMB_FAILED;
  843. pSA->sa_IPIF = NULL;
  844. }
  845. }
  846. }
  847. }
  848. }
  849. ReleaseWriteLock(&g_ipsec.SADBLock, kIrql);
  850. }
  851. VOID
  852. IPSecWakeUp(
  853. IN PVOID IPContext
  854. )
  855. /*++
  856. Routine Description:
  857. Notify Interface has waken up from hibernate.
  858. Arguments:
  859. IPContext - This is the Interface that wakes up.
  860. Return Value:
  861. --*/
  862. {
  863. Interface *DestIF = (Interface *)IPContext;
  864. PLIST_ENTRY pFilterEntry;
  865. PLIST_ENTRY pSAEntry;
  866. PFILTER pFilter;
  867. PSA_TABLE_ENTRY pSA;
  868. KIRQL kIrql;
  869. LONG Index;
  870. LONG SAIndex;
  871. IPSEC_DEBUG(HWAPI, ("IPSecWakeUp called for interface %lx\n", DestIF));
  872. //
  873. // Go through all SA's and unmark the offload bits.
  874. //
  875. AcquireWriteLock(&g_ipsec.SADBLock, &kIrql);
  876. for ( Index = MIN_FILTER;
  877. Index <= MAX_FILTER;
  878. Index++) {
  879. for ( pFilterEntry = g_ipsec.FilterList[Index].Flink;
  880. pFilterEntry != &g_ipsec.FilterList[Index];
  881. pFilterEntry = pFilterEntry->Flink) {
  882. pFilter = CONTAINING_RECORD(pFilterEntry,
  883. FILTER,
  884. MaskedLinkage);
  885. for ( SAIndex = 0;
  886. SAIndex < pFilter->SAChainSize;
  887. SAIndex++) {
  888. for ( pSAEntry = pFilter->SAChain[SAIndex].Flink;
  889. pSAEntry != &pFilter->SAChain[SAIndex];
  890. pSAEntry = pSAEntry->Flink) {
  891. pSA = CONTAINING_RECORD(pSAEntry,
  892. SA_TABLE_ENTRY,
  893. sa_FilterLinkage);
  894. if ((pSA->sa_Flags & FLAGS_SA_HW_PLUMBED) &&
  895. (DestIF == pSA->sa_IPIF)) {
  896. pSA->sa_Flags &= ~FLAGS_SA_HW_PLUMBED;
  897. pSA->sa_IPIF = NULL;
  898. pSA->sa_Flags |= FLAGS_SA_HIBERNATED;
  899. IPSEC_DEC_STATISTIC(dwNumOffloadedSAs);
  900. IPSecDerefSA(pSA);
  901. }
  902. }
  903. }
  904. }
  905. }
  906. ReleaseWriteLock(&g_ipsec.SADBLock, kIrql);
  907. }
  908. VOID
  909. IPSecBufferOffloadEvent(
  910. IN IPHeader UNALIGNED *pIPH,
  911. IN PNDIS_IPSEC_PACKET_INFO IPSecPktInfo
  912. )
  913. /*++
  914. Routine Description:
  915. Log an event for offload failures.
  916. Arguments:
  917. pIPH - The IP header of the problem packet.
  918. IPSecPktInfo - The per-packet IPSec offload info.
  919. Return Value:
  920. None
  921. --*/
  922. {
  923. switch (IPSecPktInfo->Receive.CryptoStatus) {
  924. case CRYPTO_TRANSPORT_AH_AUTH_FAILED:
  925. IPSEC_INC_STATISTIC(dwNumPacketsNotAuthenticated);
  926. IPSecBufferEvent( pIPH->iph_src,
  927. EVENT_IPSEC_AUTH_FAILURE,
  928. 3,
  929. TRUE);
  930. break;
  931. case CRYPTO_TRANSPORT_ESP_AUTH_FAILED:
  932. IPSEC_INC_STATISTIC(dwNumPacketsNotAuthenticated);
  933. IPSecBufferEvent( pIPH->iph_src,
  934. EVENT_IPSEC_AUTH_FAILURE,
  935. 4,
  936. TRUE);
  937. break;
  938. case CRYPTO_TUNNEL_AH_AUTH_FAILED:
  939. IPSEC_INC_STATISTIC(dwNumPacketsNotAuthenticated);
  940. IPSecBufferEvent( pIPH->iph_src,
  941. EVENT_IPSEC_AUTH_FAILURE,
  942. 5,
  943. TRUE);
  944. break;
  945. case CRYPTO_TUNNEL_ESP_AUTH_FAILED:
  946. IPSEC_INC_STATISTIC(dwNumPacketsNotAuthenticated);
  947. IPSecBufferEvent( pIPH->iph_src,
  948. EVENT_IPSEC_AUTH_FAILURE,
  949. 6,
  950. TRUE);
  951. break;
  952. case CRYPTO_INVALID_PACKET_SYNTAX:
  953. IPSecBufferEvent( pIPH->iph_src,
  954. EVENT_IPSEC_BAD_PACKET_SYNTAX,
  955. 1,
  956. TRUE);
  957. break;
  958. case CRYPTO_INVALID_PROTOCOL:
  959. IPSecBufferEvent( pIPH->iph_src,
  960. EVENT_IPSEC_BAD_PROTOCOL_RECEIVED,
  961. 3,
  962. TRUE);
  963. break;
  964. case CRYPTO_GENERIC_ERROR:
  965. default:
  966. IPSecBufferEvent( pIPH->iph_src,
  967. EVENT_IPSEC_GENERIC_FAILURE,
  968. 1,
  969. TRUE);
  970. break;
  971. }
  972. }