| 1 | /* |
| 2 | * Copyright (c) 2026 Apple Inc. All rights reserved. |
| 3 | * |
| 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
| 5 | * |
| 6 | * This file contains Original Code and/or Modifications of Original Code |
| 7 | * as defined in and that are subject to the Apple Public Source License |
| 8 | * Version 2.0 (the 'License'). You may not use this file except in |
| 9 | * compliance with the License. The rights granted to you under the License |
| 10 | * may not be used to create, or enable the creation or redistribution of, |
| 11 | * unlawful or unlicensed copies of an Apple operating system, or to |
| 12 | * circumvent, violate, or enable the circumvention or violation of, any |
| 13 | * terms of an Apple operating system software license agreement. |
| 14 | * |
| 15 | * Please obtain a copy of the License at |
| 16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. |
| 17 | * |
| 18 | * The Original Code and all software distributed under the License are |
| 19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
| 20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
| 21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
| 22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
| 23 | * Please see the License for the specific language governing rights and |
| 24 | * limitations under the License. |
| 25 | * |
| 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
| 27 | */ |
| 28 | #ifndef _IPSEC_OFFLOAD_H_ |
| 29 | #define _IPSEC_OFFLOAD_H_ |
| 30 | |
| 31 | #ifdef __cplusplus |
| 32 | extern "C" { |
| 33 | #endif |
| 34 | |
| 35 | #include <stdint.h> |
| 36 | |
| 37 | /* Increase if ABI-breaking changes are added */ |
| 38 | #define IPSEC_OFFLOAD_KPI_VERSION 2 |
| 39 | |
| 40 | /* Protocol / mode */ |
| 41 | typedef enum ipsec_offload_proto { |
| 42 | 	IPSEC_OFFLOAD_PROTO_ESP = 50, |
| 43 | 	IPSEC_OFFLOAD_PROTO_AH = 51 |
| 44 | } ipsec_offload_proto_t; |
| 45 | |
| 46 | typedef enum ipsec_offload_mode { |
| 47 | 	IPSEC_OFFLOAD_MODE_TRANSPORT = 0, |
| 48 | 	IPSEC_OFFLOAD_MODE_TUNNEL = 1 |
| 49 | } ipsec_offload_mode_t; |
| 50 | |
| 51 | /* Direction type for SA and policy */ |
| 52 | typedef enum ipsec_offload_dir { |
| 53 | 	IPSEC_OFFLOAD_DIR_IN = 1, /* inbound/receive */ |
| 54 | 	IPSEC_OFFLOAD_DIR_OUT = 2, /* outbound/transmit */ |
| 55 | 	IPSEC_OFFLOAD_DIR_FWD = 3 /* forward (optional) */ |
| 56 | } ipsec_offload_dir_t; |
| 57 | |
| 58 | /* |
| 59 | * Policy action. The kernel asks the driver to install one rule per |
| 60 | * policy; this tells the driver whether to encrypt/decrypt (ALLOW) or |
| 61 | * to drop matching packets in hardware (DISCARD). The two map directly |
| 62 | * to PF_KEY's IPSEC_POLICY_IPSEC and IPSEC_POLICY_DISCARD respectively. |
| 63 | * BYPASS/NONE policies don't need driver-side state and are not |
| 64 | * offloaded. |
| 65 | */ |
| 66 | typedef enum ipsec_offload_action { |
| 67 | 	IPSEC_OFFLOAD_ACTION_ALLOW = 1, /* apply IPsec (encrypt/decrypt) */ |
| 68 | 	IPSEC_OFFLOAD_ACTION_DISCARD = 2, /* drop matching packets in HW */ |
| 69 | } ipsec_offload_action_t; |
| 70 | |
| 71 | /* Algorithm definitions taken from <net/pfkeyv2.h> */ |
| 72 | /* RFC2367 numbers - meets RFC2407 */ |
| 73 | #define IPSEC_OFFLOAD_AALG_NONE 0 |
| 74 | #define IPSEC_OFFLOAD_AALG_MD5HMAC 1 /*2*/ |
| 75 | #define IPSEC_OFFLOAD_AALG_SHA1HMAC 2 /*3*/ |
| 76 | #define IPSEC_OFFLOAD_AALG_MAX 8 |
| 77 | /* private allocations - based on RFC2407/IANA assignment */ |
| 78 | #define IPSEC_OFFLOAD_X_AALG_SHA2_256 6 /*5*/ |
| 79 | #define IPSEC_OFFLOAD_X_AALG_SHA2_384 7 /*6*/ |
| 80 | #define IPSEC_OFFLOAD_X_AALG_SHA2_512 8 /*7*/ |
| 81 | /* private allocations should use 249-255 (RFC2407) */ |
| 82 | #define IPSEC_OFFLOAD_X_AALG_MD5 3 /*249*/ /* Keyed MD5, not implemented */ |
| 83 | #define IPSEC_OFFLOAD_X_AALG_SHA 4 /*250*/ /* Keyed SHA, not implemented */ |
| 84 | #define IPSEC_OFFLOAD_X_AALG_NULL 5 /*251*/ /* null authentication */ |
| 85 | |
| 86 | /* RFC2367 numbers - meets RFC2407 */ |
| 87 | #define IPSEC_OFFLOAD_EALG_NONE 0 |
| 88 | #define IPSEC_OFFLOAD_EALG_DESCBC 1 /*2*/ |
| 89 | #define IPSEC_OFFLOAD_EALG_3DESCBC 2 /*3*/ |
| 90 | #define IPSEC_OFFLOAD_EALG_NULL 3 /*11*/ |
| 91 | #define IPSEC_OFFLOAD_EALG_MAX 12 |
| 92 | /* private allocations - based on RFC2407/IANA assignment */ |
| 93 | #define IPSEC_OFFLOAD_X_EALG_CAST128CBC 5 /*6*/ |
| 94 | #define IPSEC_OFFLOAD_X_EALG_BLOWFISHCBC 4 /*7*/ |
| 95 | #define IPSEC_OFFLOAD_X_EALG_RIJNDAELCBC 12 |
| 96 | #define IPSEC_OFFLOAD_X_EALG_AESCBC 12 |
| 97 | #define IPSEC_OFFLOAD_X_EALG_AES 12 |
| 98 | #define IPSEC_OFFLOAD_X_EALG_AES_GCM 13 |
| 99 | #define IPSEC_OFFLOAD_X_EALG_CHACHA20POLY1305 14 |
| 100 | #define IPSEC_OFFLOAD_X_EALG_AES_GMAC 15 |
| 101 | /* private allocations should use 249-255 (RFC2407) */ |
| 102 | |
| 103 | /* |
| 104 | * Keying material |
| 105 | * |
| 106 | * Keys are stored inline in fixed-size arrays. key_enc_key_len and |
| 107 | * key_auth_key_len indicate the valid bytes; unused trailing bytes |
| 108 | * are zeroed. Maximum supported key length is IPSEC_OFFLOAD_MAX_KEY_LEN. |
| 109 | * |
| 110 | * AEAD (e.g. AES-GCM, ChaCha20-Poly1305, AES-GMAC): |
| 111 | * key_aead_alg != 0; key_enc_alg = key_auth_alg = 0. |
| 112 | * key_enc_key/key_enc_key_len = AEAD key (16 or 32 bytes, excludes salt). |
| 113 | * key_auth_key/key_auth_key_len = unused (0). |
| 114 | * key_salt = per-SA AEAD salt (4 bytes, extracted from raw key material). |
| 115 | * key_icv_len = authentication tag length in bytes (e.g. 16 for AES-GCM-16); |
| 116 | * derived from algorithm, not independently configurable. |
| 117 | * |
| 118 | * Non-AEAD: |
| 119 | * key_aead_alg = 0. |
| 120 | * key_enc_alg = IPSEC_OFFLOAD_EALG_* or IPSEC_OFFLOAD_X_EALG_* (0 if AH-only). |
| 121 | * key_auth_alg = IPSEC_OFFLOAD_AALG_* or IPSEC_OFFLOAD_X_AALG_* (0 if none). |
| 122 | * key_enc_key/key_auth_key populated as applicable; key_salt typically 0. |
| 123 | * key_icv_len = MAC/ICV truncation length in bytes (0 = algorithm default); |
| 124 | * derived from algorithm, not independently configurable. |
| 125 | */ |
| 126 | #define IPSEC_OFFLOAD_MAX_KEY_LEN 64 |
| 127 | |
| 128 | typedef struct ipsec_offload_keymat { |
| 129 | 	uint16_t key_aead_alg; |
| 130 | 	uint16_t key_enc_alg; |
| 131 | 	uint16_t key_auth_alg; |
| 132 | 	uint8_t key_enc_key[IPSEC_OFFLOAD_MAX_KEY_LEN]; |
| 133 | 	uint16_t key_enc_key_len; |
| 134 | 	uint8_t key_auth_key[IPSEC_OFFLOAD_MAX_KEY_LEN]; |
| 135 | 	uint16_t key_auth_key_len; |
| 136 | 	uint8_t __reserved[2]; /* explicit padding so key_salt is |
| 137 | 	 * 4-byte aligned in the wire layout */ |
| 138 | 	uint32_t key_salt; |
| 139 | 	uint16_t key_icv_len; |
| 140 | } ipsec_offload_keymat_t; |
| 141 | |
| 142 | /* IP version */ |
| 143 | typedef enum ipsec_offload_ip_version { |
| 144 | 	IPSEC_OFFLOAD_IPV4 = 4, |
| 145 | 	IPSEC_OFFLOAD_IPV6 = 6 |
| 146 | } ipsec_offload_ip_version_t; |
| 147 | |
| 148 | /* |
| 149 | * L4 protocol values for ipsec_offload_selector.sel_transport |
| 150 | * 0 means "wildcard / no L4 match". |
| 151 | */ |
| 152 | typedef enum ipsec_offload_transport { |
| 153 | 	IPSEC_OFFLOAD_L4_ANY = 0, /* no L4 match */ |
| 154 | 	IPSEC_OFFLOAD_L4_TCP = 6, /* TCP */ |
| 155 | 	IPSEC_OFFLOAD_L4_UDP = 17, /* UDP */ |
| 156 | } ipsec_offload_transport_t; |
| 157 | |
| 158 | /* Selector for packet offload classification (inner flow) */ |
| 159 | typedef struct ipsec_offload_selector { |
| 160 | 	ipsec_offload_ip_version_t sel_ip_version; /* IP version */ |
| 161 | 	uint8_t sel_src[16]; /* source address, network order */ |
| 162 | 	uint8_t sel_dst[16]; /* destination address, network order */ |
| 163 | 	uint8_t sel_src_prefix; /* 32/128 for exact */ |
| 164 | 	uint8_t sel_dst_prefix; /* 32/128 for exact */ |
| 165 | 	ipsec_offload_transport_t sel_transport; /* transport proto */ |
| 166 | 	uint16_t sel_src_port; /* source port, network order */ |
| 167 | 	uint16_t sel_dst_port; /* destination port, network order */ |
| 168 | } ipsec_offload_selector_t; |
| 169 | |
| 170 | /* Optional outer tunnel endpoints (used if mode == TUNNEL) */ |
| 171 | typedef struct ipsec_offload_tunnel { |
| 172 | 	ipsec_offload_ip_version_t tun_ip_version; /* IP version */ |
| 173 | 	uint8_t tun_src[16]; /* outer source IP, network order */ |
| 174 | 	uint8_t tun_dst[16]; /* outer destination IP, network order */ |
| 175 | 	uint8_t tun_hop_limit; /* 0 = stack default */ |
| 176 | } ipsec_offload_tunnel_t; |
| 177 | |
| 178 | /* SA flags (bitfield) */ |
| 179 | typedef enum ipsec_offload_sa_flags { |
| 180 | 	IPSEC_OFFLOAD_SA_F_ESN = 1u << 0 /* Extended Sequence Numbers */ |
| 181 | } ipsec_offload_sa_flags_t; |
| 182 | |
| 183 | /* SA programming (used by crypto + packet offload) */ |
| 184 | typedef struct ipsec_offload_sa { |
| 185 | 	uint32_t sa_flags; /* ipsec_offload_sa_flags_t */ |
| 186 | 	uint32_t sa_spi; /* SPI (network order) */ |
| 187 | 	ipsec_offload_proto_t sa_proto; /* ESP / AH */ |
| 188 | 	ipsec_offload_mode_t sa_mode; /* Transport / Tunnel */ |
| 189 | 	ipsec_offload_dir_t sa_dir; /* IN / OUT / FWD */ |
| 190 | 	ipsec_offload_selector_t sa_selector; /* SA src/dst addresses, plus |
| 191 | 	 * optional transport proto + |
| 192 | 	 * src/dst ports. Prefix |
| 193 | 	 * lengths are 32 (IPv4) or |
| 194 | 	 * 128 (IPv6) — SAs match by |
| 195 | 	 * exact host addresses. |
| 196 | 	 * Transport / ports default |
| 197 | 	 * to ANY / 0 if userspace did |
| 198 | 	 * not specify them. */ |
| 199 | 	ipsec_offload_keymat_t sa_keys; /* Keying material */ |
| 200 | 	uint32_t sa_replay_win; /* anti-replay window size in bytes |
| 201 | 	 * (e.g. 4/8/16/32 for 32/64/128/256-bit |
| 202 | 	 * windows); 0 = disabled. |
| 203 | 	 * Driver should reject unsupported sizes. */ |
| 204 | 	uint32_t sa_reqid; /* Optional binding hint, 0 = unused */ |
| 205 | 	ipsec_offload_tunnel_t sa_tunnel; /* valid if mode == TUNNEL */ |
| 206 | } ipsec_offload_sa_t; |
| 207 | |
| 208 | /* Policy classifier (packet offload) */ |
| 209 | typedef struct ipsec_offload_policy { |
| 210 | 	ipsec_offload_dir_t pol_dir; /* IN / OUT / FWD */ |
| 211 | 	ipsec_offload_action_t pol_action; /* ALLOW = apply IPsec via the |
| 212 | 	 * bound SA; DISCARD = HW drops |
| 213 | 	 * matching packets. */ |
| 214 | 	ipsec_offload_selector_t pol_sel; /* flow match */ |
| 215 | |
| 216 | 	/* Optional binding choices (driver may use either if provided): */ |
| 217 | 	uint32_t pol_reqid; /* binding hint; 0 = unused */ |
| 218 | 	uint64_t pol_sa_handle; /* direct SA cookie; 0 = resolve via reqid/SPI/etc. */ |
| 219 | } ipsec_offload_policy_t; |
| 220 | |
| 221 | |
| 222 | #ifdef __cplusplus |
| 223 | } |
| 224 | #endif |
| 225 | #endif /* _IPSEC_OFFLOAD_H_ */ |