xref: /freebsd/contrib/wpa/src/drivers/driver_macsec_qca.c (revision 2008043f386721d58158e37e0d7e50df8095942d)
1 /*
2  * Wired Ethernet driver interface for QCA MACsec driver
3  * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
4  * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
5  * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
6  * Copyright (c) 2019, The Linux Foundation
7  *
8  * This software may be distributed under the terms of the BSD license.
9  * See README for more details.
10  */
11 
12 #include "includes.h"
13 #include <sys/ioctl.h>
14 #include <net/if.h>
15 #include <inttypes.h>
16 #ifdef __linux__
17 #include <netpacket/packet.h>
18 #include <net/if_arp.h>
19 #include <net/if.h>
20 #endif /* __linux__ */
21 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
22 #include <net/if_dl.h>
23 #include <net/if_media.h>
24 #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
25 #ifdef __sun__
26 #include <sys/sockio.h>
27 #endif /* __sun__ */
28 
29 #include "utils/common.h"
30 #include "utils/eloop.h"
31 #include "common/defs.h"
32 #include "common/ieee802_1x_defs.h"
33 #include "common/eapol_common.h"
34 #include "pae/ieee802_1x_kay.h"
35 #include "driver.h"
36 #include "driver_wired_common.h"
37 
38 #include "nss_macsec_secy.h"
39 #include "nss_macsec_secy_rx.h"
40 #include "nss_macsec_secy_tx.h"
41 
42 #define MAXSC 16
43 
44 #define SAK_128_LEN	16
45 #define SAK_256_LEN	32
46 
47 /* TCI field definition */
48 #define TCI_ES                0x40
49 #define TCI_SC                0x20
50 #define TCI_SCB               0x10
51 #define TCI_E                 0x08
52 #define TCI_C                 0x04
53 
54 #ifdef _MSC_VER
55 #pragma pack(push, 1)
56 #endif /* _MSC_VER */
57 
58 #ifdef _MSC_VER
59 #pragma pack(pop)
60 #endif /* _MSC_VER */
61 
62 struct channel_map {
63 	struct ieee802_1x_mka_sci sci;
64 };
65 
66 struct macsec_qca_data {
67 	struct driver_wired_common_data common;
68 
69 	int use_pae_group_addr;
70 	u32 secy_id;
71 
72 	/* shadow */
73 	bool always_include_sci;
74 	bool use_es;
75 	bool use_scb;
76 	bool protect_frames;
77 	bool replay_protect;
78 	u32 replay_window;
79 
80 	struct channel_map receive_channel_map[MAXSC];
81 	struct channel_map transmit_channel_map[MAXSC];
82 };
83 
84 
85 static void __macsec_drv_init(struct macsec_qca_data *drv)
86 {
87 	int ret = 0;
88 	fal_rx_ctl_filt_t rx_ctl_filt;
89 	fal_tx_ctl_filt_t tx_ctl_filt;
90 
91 	wpa_printf(MSG_INFO, "%s: secy_id=%d", __func__, drv->secy_id);
92 
93 	/* Enable Secy and Let EAPoL bypass */
94 	ret = nss_macsec_secy_en_set(drv->secy_id, true);
95 	if (ret)
96 		wpa_printf(MSG_ERROR, "nss_macsec_secy_en_set: FAIL");
97 
98 	ret = nss_macsec_secy_sc_sa_mapping_mode_set(drv->secy_id,
99 						     FAL_SC_SA_MAP_1_4);
100 	if (ret)
101 		wpa_printf(MSG_ERROR,
102 			   "nss_macsec_secy_sc_sa_mapping_mode_set: FAIL");
103 
104 	os_memset(&rx_ctl_filt, 0, sizeof(rx_ctl_filt));
105 	rx_ctl_filt.bypass = 1;
106 	rx_ctl_filt.match_type = IG_CTL_COMPARE_ETHER_TYPE;
107 	rx_ctl_filt.match_mask = 0xffff;
108 	rx_ctl_filt.ether_type_da_range = 0x888e;
109 	ret = nss_macsec_secy_rx_ctl_filt_set(drv->secy_id, 0, &rx_ctl_filt);
110 	if (ret)
111 		wpa_printf(MSG_ERROR, "nss_macsec_secy_rx_ctl_filt_set: FAIL");
112 
113 	os_memset(&tx_ctl_filt, 0, sizeof(tx_ctl_filt));
114 	tx_ctl_filt.bypass = 1;
115 	tx_ctl_filt.match_type = EG_CTL_COMPARE_ETHER_TYPE;
116 	tx_ctl_filt.match_mask = 0xffff;
117 	tx_ctl_filt.ether_type_da_range = 0x888e;
118 	ret = nss_macsec_secy_tx_ctl_filt_set(drv->secy_id, 0, &tx_ctl_filt);
119 	if (ret)
120 		wpa_printf(MSG_ERROR, "nss_macsec_secy_tx_ctl_filt_set: FAIL");
121 }
122 
123 
124 static void __macsec_drv_deinit(struct macsec_qca_data *drv)
125 {
126 	nss_macsec_secy_en_set(drv->secy_id, false);
127 	nss_macsec_secy_rx_sc_del_all(drv->secy_id);
128 	nss_macsec_secy_tx_sc_del_all(drv->secy_id);
129 }
130 
131 
132 #ifdef __linux__
133 
134 static void macsec_qca_handle_data(void *ctx, unsigned char *buf, size_t len)
135 {
136 #ifdef HOSTAPD
137 	struct ieee8023_hdr *hdr;
138 	u8 *pos, *sa;
139 	size_t left;
140 	union wpa_event_data event;
141 
142 	/* at least 6 bytes src macaddress, 6 bytes dst macaddress
143 	 * and 2 bytes ethertype
144 	*/
145 	if (len < 14) {
146 		wpa_printf(MSG_MSGDUMP,
147 			   "macsec_qca_handle_data: too short (%lu)",
148 			   (unsigned long) len);
149 		return;
150 	}
151 	hdr = (struct ieee8023_hdr *) buf;
152 
153 	switch (ntohs(hdr->ethertype)) {
154 	case ETH_P_PAE:
155 		wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
156 		sa = hdr->src;
157 		os_memset(&event, 0, sizeof(event));
158 		event.new_sta.addr = sa;
159 		wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
160 
161 		pos = (u8 *) (hdr + 1);
162 		left = len - sizeof(*hdr);
163 		drv_event_eapol_rx(ctx, sa, pos, left);
164 		break;
165 	default:
166 		wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame",
167 			   ntohs(hdr->ethertype));
168 		break;
169 	}
170 #endif /* HOSTAPD */
171 }
172 
173 
174 static void macsec_qca_handle_read(int sock, void *eloop_ctx, void *sock_ctx)
175 {
176 	int len;
177 	unsigned char buf[3000];
178 
179 	len = recv(sock, buf, sizeof(buf), 0);
180 	if (len < 0) {
181 		wpa_printf(MSG_ERROR, "macsec_qca: recv: %s", strerror(errno));
182 		return;
183 	}
184 
185 	macsec_qca_handle_data(eloop_ctx, buf, len);
186 }
187 
188 #endif /* __linux__ */
189 
190 
191 static int macsec_qca_init_sockets(struct macsec_qca_data *drv, u8 *own_addr)
192 {
193 #ifdef __linux__
194 	struct ifreq ifr;
195 	struct sockaddr_ll addr;
196 
197 	drv->common.sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
198 	if (drv->common.sock < 0) {
199 		wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
200 			   strerror(errno));
201 		return -1;
202 	}
203 
204 	if (eloop_register_read_sock(drv->common.sock, macsec_qca_handle_read,
205 				     drv->common.ctx, NULL)) {
206 		wpa_printf(MSG_INFO, "Could not register read socket");
207 		return -1;
208 	}
209 
210 	os_memset(&ifr, 0, sizeof(ifr));
211 	os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
212 	if (ioctl(drv->common.sock, SIOCGIFINDEX, &ifr) != 0) {
213 		wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
214 			   strerror(errno));
215 		return -1;
216 	}
217 
218 	os_memset(&addr, 0, sizeof(addr));
219 	addr.sll_family = AF_PACKET;
220 	addr.sll_ifindex = ifr.ifr_ifindex;
221 	wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
222 		   addr.sll_ifindex);
223 
224 	if (bind(drv->common.sock, (struct sockaddr *) &addr,
225 		 sizeof(addr)) < 0) {
226 		wpa_printf(MSG_ERROR, "macsec_qca: bind: %s", strerror(errno));
227 		return -1;
228 	}
229 
230 	/* filter multicast address */
231 	if (wired_multicast_membership(drv->common.sock, ifr.ifr_ifindex,
232 				       pae_group_addr, 1) < 0) {
233 		wpa_printf(MSG_ERROR,
234 			"macsec_qca_init_sockets: Failed to add multicast group membership");
235 		return -1;
236 	}
237 
238 	os_memset(&ifr, 0, sizeof(ifr));
239 	os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
240 	if (ioctl(drv->common.sock, SIOCGIFHWADDR, &ifr) != 0) {
241 		wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s",
242 			   strerror(errno));
243 		return -1;
244 	}
245 
246 	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
247 		wpa_printf(MSG_INFO, "Invalid HW-addr family 0x%04x",
248 			   ifr.ifr_hwaddr.sa_family);
249 		return -1;
250 	}
251 	os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
252 
253 	return 0;
254 #else /* __linux__ */
255 	return -1;
256 #endif /* __linux__ */
257 }
258 
259 
260 static int macsec_qca_secy_id_get(const char *ifname, u32 *secy_id)
261 {
262 #ifdef NSS_MACSEC_SECY_ID_GET_FUNC
263 	/* Get secy id from nss macsec driver */
264 	return nss_macsec_secy_id_get((u8 *) ifname, secy_id);
265 #else /* NSS_MACSEC_SECY_ID_GET_FUNC */
266 	/* Board specific settings */
267 	if (os_strcmp(ifname, "eth2") == 0) {
268 		*secy_id = 1;
269 	} else if (os_strcmp(ifname, "eth3") == 0) {
270 		*secy_id = 2;
271 	} else if (os_strcmp(ifname, "eth4") == 0 ||
272 		   os_strcmp(ifname, "eth0") == 0) {
273 		*secy_id = 0;
274 	} else if (os_strcmp(ifname, "eth5") == 0 ||
275 		   os_strcmp(ifname, "eth1") == 0) {
276 		*secy_id = 1;
277 	} else {
278 		*secy_id = -1;
279 		return -1;
280 	}
281 
282 	return 0;
283 #endif /* NSS_MACSEC_SECY_ID_GET_FUNC */
284 }
285 
286 
287 static void * macsec_qca_init(void *ctx, const char *ifname)
288 {
289 	struct macsec_qca_data *drv;
290 
291 	drv = os_zalloc(sizeof(*drv));
292 	if (drv == NULL)
293 		return NULL;
294 
295 	if (macsec_qca_secy_id_get(ifname, &drv->secy_id)) {
296 		wpa_printf(MSG_ERROR,
297 			   "macsec_qca: Failed to get secy_id for %s", ifname);
298 		os_free(drv);
299 		return NULL;
300 	}
301 
302 	if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
303 		os_free(drv);
304 		return NULL;
305 	}
306 
307 	return drv;
308 }
309 
310 
311 static void macsec_qca_deinit(void *priv)
312 {
313 	struct macsec_qca_data *drv = priv;
314 
315 	driver_wired_deinit_common(&drv->common);
316 	os_free(drv);
317 }
318 
319 
320 static void * macsec_qca_hapd_init(struct hostapd_data *hapd,
321 				   struct wpa_init_params *params)
322 {
323 	struct macsec_qca_data *drv;
324 
325 	drv = os_zalloc(sizeof(struct macsec_qca_data));
326 	if (!drv) {
327 		wpa_printf(MSG_INFO,
328 			   "Could not allocate memory for macsec_qca driver data");
329 		return NULL;
330 	}
331 
332 	if (macsec_qca_secy_id_get(params->ifname, &drv->secy_id)) {
333 		wpa_printf(MSG_ERROR,
334 			   "macsec_qca: Failed to get secy_id for %s",
335 			   params->ifname);
336 		os_free(drv);
337 		return NULL;
338 	}
339 
340 	drv->common.ctx = hapd;
341 	os_strlcpy(drv->common.ifname, params->ifname,
342 		   sizeof(drv->common.ifname));
343 	drv->use_pae_group_addr = params->use_pae_group_addr;
344 
345 	if (macsec_qca_init_sockets(drv, params->own_addr)) {
346 		os_free(drv);
347 		return NULL;
348 	}
349 
350 	return drv;
351 }
352 
353 
354 static void macsec_qca_hapd_deinit(void *priv)
355 {
356 	struct macsec_qca_data *drv = priv;
357 
358 	if (drv->common.sock >= 0) {
359 		eloop_unregister_read_sock(drv->common.sock);
360 		close(drv->common.sock);
361 	}
362 
363 	os_free(drv);
364 }
365 
366 
367 static int macsec_qca_send_eapol(void *priv, const u8 *addr,
368 				 const u8 *data, size_t data_len, int encrypt,
369 				 const u8 *own_addr, u32 flags)
370 {
371 	struct macsec_qca_data *drv = priv;
372 	struct ieee8023_hdr *hdr;
373 	size_t len;
374 	u8 *pos;
375 	int res;
376 
377 	len = sizeof(*hdr) + data_len;
378 	hdr = os_zalloc(len);
379 	if (!hdr) {
380 		wpa_printf(MSG_INFO,
381 			   "malloc() failed for macsec_qca_send_eapol(len=%lu)",
382 			   (unsigned long) len);
383 		return -1;
384 	}
385 
386 	os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
387 		  ETH_ALEN);
388 	os_memcpy(hdr->src, own_addr, ETH_ALEN);
389 	hdr->ethertype = htons(ETH_P_PAE);
390 
391 	pos = (u8 *) (hdr + 1);
392 	os_memcpy(pos, data, data_len);
393 
394 	res = send(drv->common.sock, (u8 *) hdr, len, 0);
395 	os_free(hdr);
396 
397 	if (res < 0) {
398 		wpa_printf(MSG_ERROR,
399 			   "macsec_qca_send_eapol - packet len: %lu - failed: send: %s",
400 			   (unsigned long) len, strerror(errno));
401 	}
402 
403 	return res;
404 }
405 
406 
407 static int macsec_qca_macsec_init(void *priv, struct macsec_init_params *params)
408 {
409 	struct macsec_qca_data *drv = priv;
410 
411 	drv->always_include_sci = params->always_include_sci;
412 	drv->use_es = params->use_es;
413 	drv->use_scb = params->use_scb;
414 
415 	wpa_printf(MSG_DEBUG, "%s: es=%d, scb=%d, sci=%d",
416 		   __func__, drv->use_es, drv->use_scb,
417 		   drv->always_include_sci);
418 
419 	__macsec_drv_init(drv);
420 
421 	return 0;
422 }
423 
424 
425 static int macsec_qca_macsec_deinit(void *priv)
426 {
427 	struct macsec_qca_data *drv = priv;
428 
429 	wpa_printf(MSG_DEBUG, "%s", __func__);
430 
431 	__macsec_drv_deinit(drv);
432 
433 	return 0;
434 }
435 
436 
437 static int macsec_qca_get_capability(void *priv, enum macsec_cap *cap)
438 {
439 	wpa_printf(MSG_DEBUG, "%s", __func__);
440 
441 	*cap = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
442 
443 	return 0;
444 }
445 
446 
447 static int macsec_qca_enable_protect_frames(void *priv, bool enabled)
448 {
449 	struct macsec_qca_data *drv = priv;
450 	int ret = 0;
451 
452 	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
453 
454 	drv->protect_frames = enabled;
455 
456 	return ret;
457 }
458 
459 
460 static int macsec_qca_set_replay_protect(void *priv, bool enabled,
461 					 unsigned int window)
462 {
463 	struct macsec_qca_data *drv = priv;
464 	int ret = 0;
465 
466 	wpa_printf(MSG_DEBUG, "%s: enabled=%d, win=%u",
467 		   __func__, enabled, window);
468 
469 	drv->replay_protect = enabled;
470 	drv->replay_window = window;
471 
472 	return ret;
473 }
474 
475 
476 static fal_cipher_suite_e macsec_qca_cs_type_get(u64 cs)
477 {
478 	if (cs == CS_ID_GCM_AES_128)
479 		return FAL_CIPHER_SUITE_AES_GCM_128;
480 	if (cs == CS_ID_GCM_AES_256)
481 		return FAL_CIPHER_SUITE_AES_GCM_256;
482 	return FAL_CIPHER_SUITE_MAX;
483 }
484 
485 
486 static int macsec_qca_set_current_cipher_suite(void *priv, u64 cs)
487 {
488 	struct macsec_qca_data *drv = priv;
489 	fal_cipher_suite_e cs_type;
490 
491 	if (cs != CS_ID_GCM_AES_128 && cs != CS_ID_GCM_AES_256) {
492 		wpa_printf(MSG_ERROR,
493 			   "%s: NOT supported CipherSuite: %016" PRIx64,
494 			   __func__, cs);
495 		return -1;
496 	}
497 
498 	wpa_printf(MSG_DEBUG, "%s: CipherSuite: %016" PRIx64, __func__, cs);
499 
500 	cs_type = macsec_qca_cs_type_get(cs);
501 	return nss_macsec_secy_cipher_suite_set(drv->secy_id, cs_type);
502 }
503 
504 
505 static int macsec_qca_enable_controlled_port(void *priv, bool enabled)
506 {
507 	struct macsec_qca_data *drv = priv;
508 	int ret = 0;
509 
510 	wpa_printf(MSG_DEBUG, "%s: enable=%d", __func__, enabled);
511 
512 	ret += nss_macsec_secy_controlled_port_en_set(drv->secy_id, enabled);
513 
514 	return ret;
515 }
516 
517 
518 static int macsec_qca_lookup_channel(struct channel_map *map,
519 				     struct ieee802_1x_mka_sci *sci,
520 				     u32 *channel)
521 {
522 	u32 i;
523 
524 	for (i = 0; i < MAXSC; i++) {
525 		if (os_memcmp(&map[i].sci, sci,
526 			      sizeof(struct ieee802_1x_mka_sci)) == 0) {
527 			*channel = i;
528 			return 0;
529 		}
530 	}
531 
532 	return -1;
533 }
534 
535 
536 static void macsec_qca_register_channel(struct channel_map *map,
537 					struct ieee802_1x_mka_sci *sci,
538 					u32 channel)
539 {
540 	os_memcpy(&map[channel].sci, sci, sizeof(struct ieee802_1x_mka_sci));
541 }
542 
543 
544 static int macsec_qca_lookup_receive_channel(struct macsec_qca_data *drv,
545 					     struct receive_sc *sc,
546 					     u32 *channel)
547 {
548 	return macsec_qca_lookup_channel(drv->receive_channel_map, &sc->sci,
549 					 channel);
550 }
551 
552 
553 static void macsec_qca_register_receive_channel(struct macsec_qca_data *drv,
554 						struct receive_sc *sc,
555 						u32 channel)
556 {
557 	macsec_qca_register_channel(drv->receive_channel_map, &sc->sci,
558 				    channel);
559 }
560 
561 
562 static int macsec_qca_lookup_transmit_channel(struct macsec_qca_data *drv,
563 					      struct transmit_sc *sc,
564 					      u32 *channel)
565 {
566 	return macsec_qca_lookup_channel(drv->transmit_channel_map, &sc->sci,
567 					 channel);
568 }
569 
570 
571 static void macsec_qca_register_transmit_channel(struct macsec_qca_data *drv,
572 						 struct transmit_sc *sc,
573 						 u32 channel)
574 {
575 	macsec_qca_register_channel(drv->transmit_channel_map, &sc->sci,
576 				    channel);
577 }
578 
579 
580 static int macsec_qca_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
581 {
582 	struct macsec_qca_data *drv = priv;
583 	int ret = 0;
584 	u32 next_pn = 0;
585 	bool enabled = false;
586 	u32 win;
587 	u32 channel;
588 
589 	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
590 	if (ret != 0)
591 		return ret;
592 
593 	ret += nss_macsec_secy_rx_sa_next_pn_get(drv->secy_id, channel, sa->an,
594 						 &next_pn);
595 	ret += nss_macsec_secy_rx_sc_replay_protect_get(drv->secy_id, channel,
596 							&enabled);
597 	ret += nss_macsec_secy_rx_sc_anti_replay_window_get(drv->secy_id,
598 							    channel, &win);
599 
600 	if (enabled)
601 		sa->lowest_pn = (next_pn > win) ? (next_pn - win) : 1;
602 	else
603 		sa->lowest_pn = next_pn;
604 
605 	wpa_printf(MSG_DEBUG, "%s: lpn=0x%x", __func__, sa->lowest_pn);
606 
607 	return ret;
608 }
609 
610 
611 static int macsec_qca_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
612 {
613 	struct macsec_qca_data *drv = priv;
614 	int ret = 0;
615 	u32 channel;
616 
617 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
618 	if (ret != 0)
619 		return ret;
620 
621 	ret += nss_macsec_secy_tx_sa_next_pn_get(drv->secy_id, channel, sa->an,
622 						 &sa->next_pn);
623 
624 	wpa_printf(MSG_DEBUG, "%s: npn=0x%x", __func__, sa->next_pn);
625 
626 	return ret;
627 }
628 
629 
630 static int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
631 {
632 	struct macsec_qca_data *drv = priv;
633 	int ret = 0;
634 	u32 channel;
635 
636 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
637 	if (ret != 0)
638 		return ret;
639 
640 	ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
641 						 sa->next_pn);
642 
643 	wpa_printf(MSG_INFO, "%s: npn=0x%x", __func__, sa->next_pn);
644 
645 	return ret;
646 }
647 
648 
649 static int macsec_qca_get_available_receive_sc(void *priv, u32 *channel)
650 {
651 	struct macsec_qca_data *drv = priv;
652 	int ret = 0;
653 	u32 sc_ch = 0;
654 	bool in_use = false;
655 
656 	for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
657 		ret = nss_macsec_secy_rx_sc_in_used_get(drv->secy_id, sc_ch,
658 							&in_use);
659 		if (ret)
660 			continue;
661 
662 		if (!in_use) {
663 			*channel = sc_ch;
664 			wpa_printf(MSG_DEBUG, "%s: channel=%d",
665 				   __func__, *channel);
666 			return 0;
667 		}
668 	}
669 
670 	wpa_printf(MSG_DEBUG, "%s: no available channel", __func__);
671 
672 	return -1;
673 }
674 
675 
676 static int macsec_qca_create_receive_sc(void *priv, struct receive_sc *sc,
677 					unsigned int conf_offset,
678 					int validation)
679 {
680 	struct macsec_qca_data *drv = priv;
681 	int ret = 0;
682 	fal_rx_prc_lut_t entry;
683 	fal_rx_sc_validate_frame_e vf;
684 	enum validate_frames validate_frames = validation;
685 	u32 channel;
686 	const u8 *sci_addr = sc->sci.addr;
687 	u16 sci_port = be_to_host16(sc->sci.port);
688 
689 	ret = macsec_qca_get_available_receive_sc(priv, &channel);
690 	if (ret != 0)
691 		return ret;
692 
693 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
694 
695 	/* rx prc lut */
696 	os_memset(&entry, 0, sizeof(entry));
697 
698 	os_memcpy(entry.sci, sci_addr, ETH_ALEN);
699 	entry.sci[6] = (sci_port >> 8) & 0xff;
700 	entry.sci[7] = sci_port & 0xff;
701 	entry.sci_mask = 0xf;
702 
703 	entry.valid = 1;
704 	entry.channel = channel;
705 	entry.action = FAL_RX_PRC_ACTION_PROCESS;
706 	entry.offset = conf_offset;
707 
708 	/* rx validate frame  */
709 	if (validate_frames == Strict)
710 		vf = FAL_RX_SC_VALIDATE_FRAME_STRICT;
711 	else if (validate_frames == Checked)
712 		vf = FAL_RX_SC_VALIDATE_FRAME_CHECK;
713 	else
714 		vf = FAL_RX_SC_VALIDATE_FRAME_DISABLED;
715 
716 	ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
717 	ret += nss_macsec_secy_rx_sc_create(drv->secy_id, channel);
718 	ret += nss_macsec_secy_rx_sc_validate_frame_set(drv->secy_id, channel,
719 							vf);
720 	ret += nss_macsec_secy_rx_sc_replay_protect_set(drv->secy_id, channel,
721 							drv->replay_protect);
722 	ret += nss_macsec_secy_rx_sc_anti_replay_window_set(drv->secy_id,
723 							    channel,
724 							    drv->replay_window);
725 
726 	macsec_qca_register_receive_channel(drv, sc, channel);
727 
728 	return ret;
729 }
730 
731 
732 static int macsec_qca_delete_receive_sc(void *priv, struct receive_sc *sc)
733 {
734 	struct macsec_qca_data *drv = priv;
735 	int ret;
736 	fal_rx_prc_lut_t entry;
737 	u32 channel;
738 
739 	ret = macsec_qca_lookup_receive_channel(priv, sc, &channel);
740 	if (ret != 0)
741 		return ret;
742 
743 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
744 
745 	/* rx prc lut */
746 	os_memset(&entry, 0, sizeof(entry));
747 
748 	ret += nss_macsec_secy_rx_sc_del(drv->secy_id, channel);
749 	ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
750 
751 	return ret;
752 }
753 
754 
755 static int macsec_qca_create_receive_sa(void *priv, struct receive_sa *sa)
756 {
757 	struct macsec_qca_data *drv = priv;
758 	int ret;
759 	fal_rx_sak_t rx_sak;
760 	int i = 0;
761 	u32 channel;
762 	fal_rx_prc_lut_t entry;
763 	u32 offset;
764 
765 	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
766 	if (ret != 0)
767 		return ret;
768 
769 	wpa_printf(MSG_DEBUG, "%s, channel=%d, an=%d, lpn=0x%x",
770 		   __func__, channel, sa->an, sa->lowest_pn);
771 
772 	os_memset(&rx_sak, 0, sizeof(rx_sak));
773 	rx_sak.sak_len = sa->pkey->key_len;
774 	if (sa->pkey->key_len == SAK_128_LEN) {
775 		for (i = 0; i < 16; i++)
776 			rx_sak.sak[i] = sa->pkey->key[15 - i];
777 	} else if (sa->pkey->key_len == SAK_256_LEN) {
778 		for (i = 0; i < 16; i++) {
779 			rx_sak.sak1[i] = sa->pkey->key[15 - i];
780 			rx_sak.sak[i] = sa->pkey->key[31 - i];
781 		}
782 	} else {
783 		return -1;
784 	}
785 
786 	if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0)
787 		offset = 0;
788 	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30)
789 		offset = 30;
790 	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50)
791 		offset = 50;
792 	else
793 		return -1;
794 	ret += nss_macsec_secy_rx_prc_lut_get(drv->secy_id, channel, &entry);
795 	entry.offset = offset;
796 	ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
797 	ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, sa->an);
798 	ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, sa->an,
799 					  &rx_sak);
800 
801 	return ret;
802 }
803 
804 
805 static int macsec_qca_enable_receive_sa(void *priv, struct receive_sa *sa)
806 {
807 	struct macsec_qca_data *drv = priv;
808 	int ret;
809 	u32 channel;
810 
811 	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
812 	if (ret != 0)
813 		return ret;
814 
815 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
816 		   sa->an);
817 
818 	ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
819 					    true);
820 
821 	return ret;
822 }
823 
824 
825 static int macsec_qca_disable_receive_sa(void *priv, struct receive_sa *sa)
826 {
827 	struct macsec_qca_data *drv = priv;
828 	int ret;
829 	u32 channel;
830 
831 	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
832 	if (ret != 0)
833 		return ret;
834 
835 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
836 		   sa->an);
837 
838 	ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
839 					    false);
840 
841 	return ret;
842 }
843 
844 
845 static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel)
846 {
847 	struct macsec_qca_data *drv = priv;
848 	u32 sc_ch = 0;
849 	bool in_use = false;
850 
851 	for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
852 		if (nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch,
853 						      &in_use))
854 			continue;
855 
856 		if (!in_use) {
857 			*channel = sc_ch;
858 			wpa_printf(MSG_DEBUG, "%s: channel=%d",
859 				   __func__, *channel);
860 			return 0;
861 		}
862 	}
863 
864 	wpa_printf(MSG_DEBUG, "%s: no avaiable channel", __func__);
865 
866 	return -1;
867 }
868 
869 
870 static int macsec_qca_create_transmit_sc(void *priv, struct transmit_sc *sc,
871 					 unsigned int conf_offset)
872 {
873 	struct macsec_qca_data *drv = priv;
874 	int ret;
875 	fal_tx_class_lut_t entry;
876 	u8 psci[ETH_ALEN + 2];
877 	u32 channel;
878 	u16 sci_port = be_to_host16(sc->sci.port);
879 
880 	ret = macsec_qca_get_available_transmit_sc(priv, &channel);
881 	if (ret != 0)
882 		return ret;
883 
884 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
885 
886 	/* class lut */
887 	os_memset(&entry, 0, sizeof(entry));
888 
889 	entry.valid = 1;
890 	entry.action = FAL_TX_CLASS_ACTION_FORWARD;
891 	entry.channel = channel;
892 
893 	os_memcpy(psci, sc->sci.addr, ETH_ALEN);
894 	psci[6] = (sci_port >> 8) & 0xff;
895 	psci[7] = sci_port & 0xff;
896 
897 	ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
898 	ret += nss_macsec_secy_tx_sc_create(drv->secy_id, channel, psci, 8);
899 	ret += nss_macsec_secy_tx_sc_protect_set(drv->secy_id, channel,
900 						 drv->protect_frames);
901 	ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
902 								channel,
903 								conf_offset);
904 
905 	macsec_qca_register_transmit_channel(drv, sc, channel);
906 
907 	return ret;
908 }
909 
910 
911 static int macsec_qca_delete_transmit_sc(void *priv, struct transmit_sc *sc)
912 {
913 	struct macsec_qca_data *drv = priv;
914 	int ret;
915 	fal_tx_class_lut_t entry;
916 	u32 channel;
917 
918 	ret = macsec_qca_lookup_transmit_channel(priv, sc, &channel);
919 	if (ret != 0)
920 		return ret;
921 
922 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
923 
924 	/* class lut */
925 	os_memset(&entry, 0, sizeof(entry));
926 
927 	ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
928 	ret += nss_macsec_secy_tx_sc_del(drv->secy_id, channel);
929 
930 	return ret;
931 }
932 
933 
934 static int macsec_qca_create_transmit_sa(void *priv, struct transmit_sa *sa)
935 {
936 	struct macsec_qca_data *drv = priv;
937 	int ret;
938 	u8 tci = 0;
939 	fal_tx_sak_t tx_sak;
940 	int i;
941 	u32 channel;
942 	u32 offset;
943 
944 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
945 	if (ret != 0)
946 		return ret;
947 
948 	wpa_printf(MSG_DEBUG,
949 		   "%s: channel=%d, an=%d, next_pn=0x%x, confidentiality=%d",
950 		   __func__, channel, sa->an, sa->next_pn, sa->confidentiality);
951 
952 	if (drv->always_include_sci)
953 		tci |= TCI_SC;
954 	else if (drv->use_es)
955 		tci |= TCI_ES;
956 	else if (drv->use_scb)
957 		tci |= TCI_SCB;
958 
959 	if (sa->confidentiality)
960 		tci |= TCI_E | TCI_C;
961 
962 	os_memset(&tx_sak, 0, sizeof(tx_sak));
963 	tx_sak.sak_len = sa->pkey->key_len;
964 	if (sa->pkey->key_len == SAK_128_LEN) {
965 		for (i = 0; i < 16; i++)
966 			tx_sak.sak[i] = sa->pkey->key[15 - i];
967 	} else if (sa->pkey->key_len == SAK_256_LEN) {
968 		for (i = 0; i < 16; i++) {
969 			tx_sak.sak1[i] = sa->pkey->key[15 - i];
970 			tx_sak.sak[i] = sa->pkey->key[31 - i];
971 		}
972 	} else {
973 		return -1;
974 	}
975 
976 	if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0)
977 		offset = 0;
978 	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30)
979 		offset = 30;
980 	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50)
981 		offset = 50;
982 	else
983 		return -1;
984 	ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
985 								channel,
986 								offset);
987 	ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
988 						 sa->next_pn);
989 	ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, sa->an,
990 					  &tx_sak);
991 	ret += nss_macsec_secy_tx_sc_tci_7_2_set(drv->secy_id, channel,
992 						 (tci >> 2));
993 	ret += nss_macsec_secy_tx_sc_an_set(drv->secy_id, channel, sa->an);
994 
995 	return ret;
996 }
997 
998 
999 static int macsec_qca_enable_transmit_sa(void *priv, struct transmit_sa *sa)
1000 {
1001 	struct macsec_qca_data *drv = priv;
1002 	int ret;
1003 	u32 channel;
1004 
1005 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
1006 	if (ret != 0)
1007 		return ret;
1008 
1009 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
1010 		   sa->an);
1011 
1012 	ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
1013 					    true);
1014 
1015 	return ret;
1016 }
1017 
1018 
1019 static int macsec_qca_disable_transmit_sa(void *priv, struct transmit_sa *sa)
1020 {
1021 	struct macsec_qca_data *drv = priv;
1022 	int ret;
1023 	u32 channel;
1024 
1025 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
1026 	if (ret != 0)
1027 		return ret;
1028 
1029 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
1030 		   sa->an);
1031 
1032 	ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
1033 					    false);
1034 
1035 	return ret;
1036 }
1037 
1038 
1039 const struct wpa_driver_ops wpa_driver_macsec_qca_ops = {
1040 	.name = "macsec_qca",
1041 	.desc = "QCA MACsec Ethernet driver",
1042 	.get_ssid = driver_wired_get_ssid,
1043 	.get_bssid = driver_wired_get_bssid,
1044 	.get_capa = driver_wired_get_capa,
1045 	.init = macsec_qca_init,
1046 	.deinit = macsec_qca_deinit,
1047 	.hapd_init = macsec_qca_hapd_init,
1048 	.hapd_deinit = macsec_qca_hapd_deinit,
1049 	.hapd_send_eapol = macsec_qca_send_eapol,
1050 
1051 	.macsec_init = macsec_qca_macsec_init,
1052 	.macsec_deinit = macsec_qca_macsec_deinit,
1053 	.macsec_get_capability = macsec_qca_get_capability,
1054 	.enable_protect_frames = macsec_qca_enable_protect_frames,
1055 	.set_replay_protect = macsec_qca_set_replay_protect,
1056 	.set_current_cipher_suite = macsec_qca_set_current_cipher_suite,
1057 	.enable_controlled_port = macsec_qca_enable_controlled_port,
1058 	.get_receive_lowest_pn = macsec_qca_get_receive_lowest_pn,
1059 	.get_transmit_next_pn = macsec_qca_get_transmit_next_pn,
1060 	.set_transmit_next_pn = macsec_qca_set_transmit_next_pn,
1061 	.create_receive_sc = macsec_qca_create_receive_sc,
1062 	.delete_receive_sc = macsec_qca_delete_receive_sc,
1063 	.create_receive_sa = macsec_qca_create_receive_sa,
1064 	.enable_receive_sa = macsec_qca_enable_receive_sa,
1065 	.disable_receive_sa = macsec_qca_disable_receive_sa,
1066 	.create_transmit_sc = macsec_qca_create_transmit_sc,
1067 	.delete_transmit_sc = macsec_qca_delete_transmit_sc,
1068 	.create_transmit_sa = macsec_qca_create_transmit_sa,
1069 	.enable_transmit_sa = macsec_qca_enable_transmit_sa,
1070 	.disable_transmit_sa = macsec_qca_disable_transmit_sa,
1071 };
1072