1// SPDX-License-Identifier: GPL-2.0
2
3#include <net/macsec.h>
4#include "netdevsim.h"
5
6static int nsim_macsec_find_secy(struct netdevsim *ns, sci_t sci)
7{
8	int i;
9
10	for (i = 0; i < NSIM_MACSEC_MAX_SECY_COUNT; i++) {
11		if (ns->macsec.nsim_secy[i].sci == sci)
12			return i;
13	}
14
15	return -1;
16}
17
18static int nsim_macsec_find_rxsc(struct nsim_secy *ns_secy, sci_t sci)
19{
20	int i;
21
22	for (i = 0; i < NSIM_MACSEC_MAX_RXSC_COUNT; i++) {
23		if (ns_secy->nsim_rxsc[i].sci == sci)
24			return i;
25	}
26
27	return -1;
28}
29
30static int nsim_macsec_add_secy(struct macsec_context *ctx)
31{
32	struct netdevsim *ns = netdev_priv(ctx->netdev);
33	int idx;
34
35	if (ns->macsec.nsim_secy_count == NSIM_MACSEC_MAX_SECY_COUNT)
36		return -ENOSPC;
37
38	for (idx = 0; idx < NSIM_MACSEC_MAX_SECY_COUNT; idx++) {
39		if (!ns->macsec.nsim_secy[idx].used)
40			break;
41	}
42
43	if (idx == NSIM_MACSEC_MAX_SECY_COUNT) {
44		netdev_err(ctx->netdev, "%s: nsim_secy_count not full but all SecYs used\n",
45			   __func__);
46		return -ENOSPC;
47	}
48
49	netdev_dbg(ctx->netdev, "%s: adding new secy with sci %08llx at index %d\n",
50		   __func__, sci_to_cpu(ctx->secy->sci), idx);
51	ns->macsec.nsim_secy[idx].used = true;
52	ns->macsec.nsim_secy[idx].nsim_rxsc_count = 0;
53	ns->macsec.nsim_secy[idx].sci = ctx->secy->sci;
54	ns->macsec.nsim_secy_count++;
55
56	return 0;
57}
58
59static int nsim_macsec_upd_secy(struct macsec_context *ctx)
60{
61	struct netdevsim *ns = netdev_priv(ctx->netdev);
62	int idx;
63
64	idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
65	if (idx < 0) {
66		netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
67			   __func__, sci_to_cpu(ctx->secy->sci));
68		return -ENOENT;
69	}
70
71	netdev_dbg(ctx->netdev, "%s: updating secy with sci %08llx at index %d\n",
72		   __func__, sci_to_cpu(ctx->secy->sci), idx);
73
74	return 0;
75}
76
77static int nsim_macsec_del_secy(struct macsec_context *ctx)
78{
79	struct netdevsim *ns = netdev_priv(ctx->netdev);
80	int idx;
81
82	idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
83	if (idx < 0) {
84		netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
85			   __func__, sci_to_cpu(ctx->secy->sci));
86		return -ENOENT;
87	}
88
89	netdev_dbg(ctx->netdev, "%s: removing SecY with SCI %08llx at index %d\n",
90		   __func__, sci_to_cpu(ctx->secy->sci), idx);
91
92	ns->macsec.nsim_secy[idx].used = false;
93	memset(&ns->macsec.nsim_secy[idx], 0, sizeof(ns->macsec.nsim_secy[idx]));
94	ns->macsec.nsim_secy_count--;
95
96	return 0;
97}
98
99static int nsim_macsec_add_rxsc(struct macsec_context *ctx)
100{
101	struct netdevsim *ns = netdev_priv(ctx->netdev);
102	struct nsim_secy *secy;
103	int idx;
104
105	idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
106	if (idx < 0) {
107		netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
108			   __func__, sci_to_cpu(ctx->secy->sci));
109		return -ENOENT;
110	}
111	secy = &ns->macsec.nsim_secy[idx];
112
113	if (secy->nsim_rxsc_count == NSIM_MACSEC_MAX_RXSC_COUNT)
114		return -ENOSPC;
115
116	for (idx = 0; idx < NSIM_MACSEC_MAX_RXSC_COUNT; idx++) {
117		if (!secy->nsim_rxsc[idx].used)
118			break;
119	}
120
121	if (idx == NSIM_MACSEC_MAX_RXSC_COUNT)
122		netdev_err(ctx->netdev, "%s: nsim_rxsc_count not full but all RXSCs used\n",
123			   __func__);
124
125	netdev_dbg(ctx->netdev, "%s: adding new rxsc with sci %08llx at index %d\n",
126		   __func__, sci_to_cpu(ctx->rx_sc->sci), idx);
127	secy->nsim_rxsc[idx].used = true;
128	secy->nsim_rxsc[idx].sci = ctx->rx_sc->sci;
129	secy->nsim_rxsc_count++;
130
131	return 0;
132}
133
134static int nsim_macsec_upd_rxsc(struct macsec_context *ctx)
135{
136	struct netdevsim *ns = netdev_priv(ctx->netdev);
137	struct nsim_secy *secy;
138	int idx;
139
140	idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
141	if (idx < 0) {
142		netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
143			   __func__, sci_to_cpu(ctx->secy->sci));
144		return -ENOENT;
145	}
146	secy = &ns->macsec.nsim_secy[idx];
147
148	idx = nsim_macsec_find_rxsc(secy, ctx->rx_sc->sci);
149	if (idx < 0) {
150		netdev_err(ctx->netdev, "%s: sci %08llx not found in RXSC table\n",
151			   __func__, sci_to_cpu(ctx->rx_sc->sci));
152		return -ENOENT;
153	}
154
155	netdev_dbg(ctx->netdev, "%s: updating RXSC with sci %08llx at index %d\n",
156		   __func__, sci_to_cpu(ctx->rx_sc->sci), idx);
157
158	return 0;
159}
160
161static int nsim_macsec_del_rxsc(struct macsec_context *ctx)
162{
163	struct netdevsim *ns = netdev_priv(ctx->netdev);
164	struct nsim_secy *secy;
165	int idx;
166
167	idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
168	if (idx < 0) {
169		netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
170			   __func__, sci_to_cpu(ctx->secy->sci));
171		return -ENOENT;
172	}
173	secy = &ns->macsec.nsim_secy[idx];
174
175	idx = nsim_macsec_find_rxsc(secy, ctx->rx_sc->sci);
176	if (idx < 0) {
177		netdev_err(ctx->netdev, "%s: sci %08llx not found in RXSC table\n",
178			   __func__, sci_to_cpu(ctx->rx_sc->sci));
179		return -ENOENT;
180	}
181
182	netdev_dbg(ctx->netdev, "%s: removing RXSC with sci %08llx at index %d\n",
183		   __func__, sci_to_cpu(ctx->rx_sc->sci), idx);
184
185	secy->nsim_rxsc[idx].used = false;
186	memset(&secy->nsim_rxsc[idx], 0, sizeof(secy->nsim_rxsc[idx]));
187	secy->nsim_rxsc_count--;
188
189	return 0;
190}
191
192static int nsim_macsec_add_rxsa(struct macsec_context *ctx)
193{
194	struct netdevsim *ns = netdev_priv(ctx->netdev);
195	struct nsim_secy *secy;
196	int idx;
197
198	idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
199	if (idx < 0) {
200		netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
201			   __func__, sci_to_cpu(ctx->secy->sci));
202		return -ENOENT;
203	}
204	secy = &ns->macsec.nsim_secy[idx];
205
206	idx = nsim_macsec_find_rxsc(secy, ctx->sa.rx_sa->sc->sci);
207	if (idx < 0) {
208		netdev_err(ctx->netdev, "%s: sci %08llx not found in RXSC table\n",
209			   __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci));
210		return -ENOENT;
211	}
212
213	netdev_dbg(ctx->netdev, "%s: RXSC with sci %08llx, AN %u\n",
214		   __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci), ctx->sa.assoc_num);
215
216	return 0;
217}
218
219static int nsim_macsec_upd_rxsa(struct macsec_context *ctx)
220{
221	struct netdevsim *ns = netdev_priv(ctx->netdev);
222	struct nsim_secy *secy;
223	int idx;
224
225	idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
226	if (idx < 0) {
227		netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
228			   __func__, sci_to_cpu(ctx->secy->sci));
229		return -ENOENT;
230	}
231	secy = &ns->macsec.nsim_secy[idx];
232
233	idx = nsim_macsec_find_rxsc(secy, ctx->sa.rx_sa->sc->sci);
234	if (idx < 0) {
235		netdev_err(ctx->netdev, "%s: sci %08llx not found in RXSC table\n",
236			   __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci));
237		return -ENOENT;
238	}
239
240	netdev_dbg(ctx->netdev, "%s: RXSC with sci %08llx, AN %u\n",
241		   __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci), ctx->sa.assoc_num);
242
243	return 0;
244}
245
246static int nsim_macsec_del_rxsa(struct macsec_context *ctx)
247{
248	struct netdevsim *ns = netdev_priv(ctx->netdev);
249	struct nsim_secy *secy;
250	int idx;
251
252	idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
253	if (idx < 0) {
254		netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
255			   __func__, sci_to_cpu(ctx->secy->sci));
256		return -ENOENT;
257	}
258	secy = &ns->macsec.nsim_secy[idx];
259
260	idx = nsim_macsec_find_rxsc(secy, ctx->sa.rx_sa->sc->sci);
261	if (idx < 0) {
262		netdev_err(ctx->netdev, "%s: sci %08llx not found in RXSC table\n",
263			   __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci));
264		return -ENOENT;
265	}
266
267	netdev_dbg(ctx->netdev, "%s: RXSC with sci %08llx, AN %u\n",
268		   __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci), ctx->sa.assoc_num);
269
270	return 0;
271}
272
273static int nsim_macsec_add_txsa(struct macsec_context *ctx)
274{
275	struct netdevsim *ns = netdev_priv(ctx->netdev);
276	int idx;
277
278	idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
279	if (idx < 0) {
280		netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
281			   __func__, sci_to_cpu(ctx->secy->sci));
282		return -ENOENT;
283	}
284
285	netdev_dbg(ctx->netdev, "%s: SECY with sci %08llx, AN %u\n",
286		   __func__, sci_to_cpu(ctx->secy->sci), ctx->sa.assoc_num);
287
288	return 0;
289}
290
291static int nsim_macsec_upd_txsa(struct macsec_context *ctx)
292{
293	struct netdevsim *ns = netdev_priv(ctx->netdev);
294	int idx;
295
296	idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
297	if (idx < 0) {
298		netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
299			   __func__, sci_to_cpu(ctx->secy->sci));
300		return -ENOENT;
301	}
302
303	netdev_dbg(ctx->netdev, "%s: SECY with sci %08llx, AN %u\n",
304		   __func__, sci_to_cpu(ctx->secy->sci), ctx->sa.assoc_num);
305
306	return 0;
307}
308
309static int nsim_macsec_del_txsa(struct macsec_context *ctx)
310{
311	struct netdevsim *ns = netdev_priv(ctx->netdev);
312	int idx;
313
314	idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
315	if (idx < 0) {
316		netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
317			   __func__, sci_to_cpu(ctx->secy->sci));
318		return -ENOENT;
319	}
320
321	netdev_dbg(ctx->netdev, "%s: SECY with sci %08llx, AN %u\n",
322		   __func__, sci_to_cpu(ctx->secy->sci), ctx->sa.assoc_num);
323
324	return 0;
325}
326
327static const struct macsec_ops nsim_macsec_ops = {
328	.mdo_add_secy = nsim_macsec_add_secy,
329	.mdo_upd_secy = nsim_macsec_upd_secy,
330	.mdo_del_secy = nsim_macsec_del_secy,
331	.mdo_add_rxsc = nsim_macsec_add_rxsc,
332	.mdo_upd_rxsc = nsim_macsec_upd_rxsc,
333	.mdo_del_rxsc = nsim_macsec_del_rxsc,
334	.mdo_add_rxsa = nsim_macsec_add_rxsa,
335	.mdo_upd_rxsa = nsim_macsec_upd_rxsa,
336	.mdo_del_rxsa = nsim_macsec_del_rxsa,
337	.mdo_add_txsa = nsim_macsec_add_txsa,
338	.mdo_upd_txsa = nsim_macsec_upd_txsa,
339	.mdo_del_txsa = nsim_macsec_del_txsa,
340};
341
342void nsim_macsec_init(struct netdevsim *ns)
343{
344	ns->netdev->macsec_ops = &nsim_macsec_ops;
345	ns->netdev->features |= NETIF_F_HW_MACSEC;
346	memset(&ns->macsec, 0, sizeof(ns->macsec));
347}
348
349void nsim_macsec_teardown(struct netdevsim *ns)
350{
351}
352