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