1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2018 Oracle and/or its affiliates. All rights reserved. */
4 #include <crypto/aead.h>
5 #include <linux/debugfs.h>
10 #define NSIM_IPSEC_AUTH_BITS 128
12 static ssize_t
nsim_dbg_netdev_ops_read(struct file
*filp
,
14 size_t count
, loff_t
*ppos
)
16 struct netdevsim
*ns
= filp
->private_data
;
17 struct nsim_ipsec
*ipsec
= &ns
->ipsec
;
23 /* the buffer needed is
24 * (num SAs * 3 lines each * ~60 bytes per line) + one more line
26 bufsize
= (ipsec
->count
* 4 * 60) + 60;
27 buf
= kzalloc(bufsize
, GFP_KERNEL
);
32 p
+= scnprintf(p
, bufsize
- (p
- buf
),
33 "SA count=%u tx=%u\n",
34 ipsec
->count
, ipsec
->tx
);
36 for (i
= 0; i
< NSIM_IPSEC_MAX_SA_COUNT
; i
++) {
37 struct nsim_sa
*sap
= &ipsec
->sa
[i
];
42 if (sap
->xs
->props
.family
== AF_INET6
)
43 p
+= scnprintf(p
, bufsize
- (p
- buf
),
44 "sa[%i] %cx ipaddr=%pI6c\n",
45 i
, (sap
->rx
? 'r' : 't'), &sap
->ipaddr
);
47 p
+= scnprintf(p
, bufsize
- (p
- buf
),
48 "sa[%i] %cx ipaddr=%pI4\n",
49 i
, (sap
->rx
? 'r' : 't'), &sap
->ipaddr
[3]);
50 p
+= scnprintf(p
, bufsize
- (p
- buf
),
51 "sa[%i] spi=0x%08x proto=0x%x salt=0x%08x crypt=%d\n",
52 i
, be32_to_cpu(sap
->xs
->id
.spi
),
53 sap
->xs
->id
.proto
, sap
->salt
, sap
->crypt
);
54 p
+= scnprintf(p
, bufsize
- (p
- buf
),
55 "sa[%i] key=0x%08x %08x %08x %08x\n",
56 i
, sap
->key
[0], sap
->key
[1],
57 sap
->key
[2], sap
->key
[3]);
60 len
= simple_read_from_buffer(buffer
, count
, ppos
, buf
, p
- buf
);
66 static const struct file_operations ipsec_dbg_fops
= {
69 .read
= nsim_dbg_netdev_ops_read
,
72 static int nsim_ipsec_find_empty_idx(struct nsim_ipsec
*ipsec
)
76 if (ipsec
->count
== NSIM_IPSEC_MAX_SA_COUNT
)
80 for (i
= 0; i
< NSIM_IPSEC_MAX_SA_COUNT
; i
++) {
81 if (!ipsec
->sa
[i
].used
)
88 static int nsim_ipsec_parse_proto_keys(struct xfrm_state
*xs
,
89 u32
*mykey
, u32
*mysalt
)
91 const char aes_gcm_name
[] = "rfc4106(gcm(aes))";
92 struct net_device
*dev
= xs
->xso
.real_dev
;
93 unsigned char *key_data
;
94 char *alg_name
= NULL
;
98 netdev_err(dev
, "Unsupported IPsec algorithm\n");
102 if (xs
->aead
->alg_icv_len
!= NSIM_IPSEC_AUTH_BITS
) {
103 netdev_err(dev
, "IPsec offload requires %d bit authentication\n",
104 NSIM_IPSEC_AUTH_BITS
);
108 key_data
= &xs
->aead
->alg_key
[0];
109 key_len
= xs
->aead
->alg_key_len
;
110 alg_name
= xs
->aead
->alg_name
;
112 if (strcmp(alg_name
, aes_gcm_name
)) {
113 netdev_err(dev
, "Unsupported IPsec algorithm - please use %s\n",
118 /* 160 accounts for 16 byte key and 4 byte salt */
119 if (key_len
> NSIM_IPSEC_AUTH_BITS
) {
120 *mysalt
= ((u32
*)key_data
)[4];
121 } else if (key_len
== NSIM_IPSEC_AUTH_BITS
) {
124 netdev_err(dev
, "IPsec hw offload only supports 128 bit keys with optional 32 bit salt\n");
127 memcpy(mykey
, key_data
, 16);
132 static int nsim_ipsec_add_sa(struct xfrm_state
*xs
,
133 struct netlink_ext_ack
*extack
)
135 struct nsim_ipsec
*ipsec
;
136 struct net_device
*dev
;
137 struct netdevsim
*ns
;
142 dev
= xs
->xso
.real_dev
;
143 ns
= netdev_priv(dev
);
146 if (xs
->id
.proto
!= IPPROTO_ESP
&& xs
->id
.proto
!= IPPROTO_AH
) {
147 NL_SET_ERR_MSG_MOD(extack
, "Unsupported protocol for ipsec offload");
152 NL_SET_ERR_MSG_MOD(extack
, "Compression offload not supported");
156 if (xs
->xso
.type
!= XFRM_DEV_OFFLOAD_CRYPTO
) {
157 NL_SET_ERR_MSG_MOD(extack
, "Unsupported ipsec offload type");
161 /* find the first unused index */
162 ret
= nsim_ipsec_find_empty_idx(ipsec
);
164 NL_SET_ERR_MSG_MOD(extack
, "No space for SA in Rx table!");
169 memset(&sa
, 0, sizeof(sa
));
173 if (sa
.xs
->id
.proto
& IPPROTO_ESP
)
174 sa
.crypt
= xs
->ealg
|| xs
->aead
;
176 /* get the key and salt */
177 ret
= nsim_ipsec_parse_proto_keys(xs
, sa
.key
, &sa
.salt
);
179 NL_SET_ERR_MSG_MOD(extack
, "Failed to get key data for SA table");
183 if (xs
->xso
.dir
== XFRM_DEV_OFFLOAD_IN
)
186 if (xs
->props
.family
== AF_INET6
)
187 memcpy(sa
.ipaddr
, &xs
->id
.daddr
.a6
, 16);
189 memcpy(&sa
.ipaddr
[3], &xs
->id
.daddr
.a4
, 4);
191 /* the preparations worked, so save the info */
192 memcpy(&ipsec
->sa
[sa_idx
], &sa
, sizeof(sa
));
194 /* the XFRM stack doesn't like offload_handle == 0,
195 * so add a bitflag in case our array index is 0
197 xs
->xso
.offload_handle
= sa_idx
| NSIM_IPSEC_VALID
;
203 static void nsim_ipsec_del_sa(struct xfrm_state
*xs
)
205 struct netdevsim
*ns
= netdev_priv(xs
->xso
.real_dev
);
206 struct nsim_ipsec
*ipsec
= &ns
->ipsec
;
209 sa_idx
= xs
->xso
.offload_handle
& ~NSIM_IPSEC_VALID
;
210 if (!ipsec
->sa
[sa_idx
].used
) {
211 netdev_err(ns
->netdev
, "Invalid SA for delete sa_idx=%d\n",
216 memset(&ipsec
->sa
[sa_idx
], 0, sizeof(struct nsim_sa
));
220 static bool nsim_ipsec_offload_ok(struct sk_buff
*skb
, struct xfrm_state
*xs
)
222 struct netdevsim
*ns
= netdev_priv(xs
->xso
.real_dev
);
223 struct nsim_ipsec
*ipsec
= &ns
->ipsec
;
230 static const struct xfrmdev_ops nsim_xfrmdev_ops
= {
231 .xdo_dev_state_add
= nsim_ipsec_add_sa
,
232 .xdo_dev_state_delete
= nsim_ipsec_del_sa
,
233 .xdo_dev_offload_ok
= nsim_ipsec_offload_ok
,
236 bool nsim_ipsec_tx(struct netdevsim
*ns
, struct sk_buff
*skb
)
238 struct sec_path
*sp
= skb_sec_path(skb
);
239 struct nsim_ipsec
*ipsec
= &ns
->ipsec
;
240 struct xfrm_state
*xs
;
244 /* do we even need to check this packet? */
248 if (unlikely(!sp
->len
)) {
249 netdev_err(ns
->netdev
, "no xfrm state len = %d\n",
254 xs
= xfrm_input_state(skb
);
256 netdev_err(ns
->netdev
, "no xfrm_input_state() xs = %p\n", xs
);
260 sa_idx
= xs
->xso
.offload_handle
& ~NSIM_IPSEC_VALID
;
261 if (unlikely(sa_idx
>= NSIM_IPSEC_MAX_SA_COUNT
)) {
262 netdev_err(ns
->netdev
, "bad sa_idx=%d max=%d\n",
263 sa_idx
, NSIM_IPSEC_MAX_SA_COUNT
);
267 tsa
= &ipsec
->sa
[sa_idx
];
268 if (unlikely(!tsa
->used
)) {
269 netdev_err(ns
->netdev
, "unused sa_idx=%d\n", sa_idx
);
273 if (xs
->id
.proto
!= IPPROTO_ESP
&& xs
->id
.proto
!= IPPROTO_AH
) {
274 netdev_err(ns
->netdev
, "unexpected proto=%d\n", xs
->id
.proto
);
283 void nsim_ipsec_init(struct netdevsim
*ns
)
285 ns
->netdev
->xfrmdev_ops
= &nsim_xfrmdev_ops
;
287 #define NSIM_ESP_FEATURES (NETIF_F_HW_ESP | \
288 NETIF_F_HW_ESP_TX_CSUM | \
291 ns
->netdev
->features
|= NSIM_ESP_FEATURES
;
292 ns
->netdev
->hw_enc_features
|= NSIM_ESP_FEATURES
;
294 ns
->ipsec
.pfile
= debugfs_create_file("ipsec", 0400,
295 ns
->nsim_dev_port
->ddir
, ns
,
299 void nsim_ipsec_teardown(struct netdevsim
*ns
)
301 struct nsim_ipsec
*ipsec
= &ns
->ipsec
;
304 netdev_err(ns
->netdev
, "tearing down IPsec offload with %d SAs left\n",
306 debugfs_remove_recursive(ipsec
->pfile
);