driver_macsec_qca.c revision 351611
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
62struct channel_map {
63	struct ieee802_1x_mka_sci sci;
64};
65
66struct 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	Boolean always_include_sci;
74	Boolean use_es;
75	Boolean use_scb;
76	Boolean protect_frames;
77	Boolean 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
85static 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
124static 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
134static 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
174static 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
191static 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
260static void * macsec_qca_init(void *ctx, const char *ifname)
261{
262	struct macsec_qca_data *drv;
263
264	drv = os_zalloc(sizeof(*drv));
265	if (drv == NULL)
266		return NULL;
267
268	/* Board specific settings */
269	if (os_memcmp("eth2", ifname, 4) == 0)
270		drv->secy_id = 1;
271	else if (os_memcmp("eth3", ifname, 4) == 0)
272		drv->secy_id = 2;
273	else
274		drv->secy_id = -1;
275
276	if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
277		os_free(drv);
278		return NULL;
279	}
280
281	return drv;
282}
283
284
285static void macsec_qca_deinit(void *priv)
286{
287	struct macsec_qca_data *drv = priv;
288
289	driver_wired_deinit_common(&drv->common);
290	os_free(drv);
291}
292
293
294static void * macsec_qca_hapd_init(struct hostapd_data *hapd,
295				   struct wpa_init_params *params)
296{
297	struct macsec_qca_data *drv;
298
299	drv = os_zalloc(sizeof(struct macsec_qca_data));
300	if (!drv) {
301		wpa_printf(MSG_INFO,
302			   "Could not allocate memory for macsec_qca driver data");
303		return NULL;
304	}
305
306	/* Board specific settings */
307	if (os_memcmp("eth2", params->ifname, 4) == 0)
308		drv->secy_id = 1;
309	else if (os_memcmp("eth3", params->ifname, 4) == 0)
310		drv->secy_id = 2;
311	else if (os_memcmp("eth4", params->ifname, 4) == 0)
312		drv->secy_id = 0;
313	else if (os_memcmp("eth5", params->ifname, 4) == 0)
314		drv->secy_id = 1;
315	else
316		drv->secy_id = -1;
317
318	drv->common.ctx = hapd;
319	os_strlcpy(drv->common.ifname, params->ifname,
320		   sizeof(drv->common.ifname));
321	drv->use_pae_group_addr = params->use_pae_group_addr;
322
323	if (macsec_qca_init_sockets(drv, params->own_addr)) {
324		os_free(drv);
325		return NULL;
326	}
327
328	return drv;
329}
330
331
332static void macsec_qca_hapd_deinit(void *priv)
333{
334	struct macsec_qca_data *drv = priv;
335
336	if (drv->common.sock >= 0) {
337		eloop_unregister_read_sock(drv->common.sock);
338		close(drv->common.sock);
339	}
340
341	os_free(drv);
342}
343
344
345static int macsec_qca_send_eapol(void *priv, const u8 *addr,
346				 const u8 *data, size_t data_len, int encrypt,
347				 const u8 *own_addr, u32 flags)
348{
349	struct macsec_qca_data *drv = priv;
350	struct ieee8023_hdr *hdr;
351	size_t len;
352	u8 *pos;
353	int res;
354
355	len = sizeof(*hdr) + data_len;
356	hdr = os_zalloc(len);
357	if (!hdr) {
358		wpa_printf(MSG_INFO,
359			   "malloc() failed for macsec_qca_send_eapol(len=%lu)",
360			   (unsigned long) len);
361		return -1;
362	}
363
364	os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
365		  ETH_ALEN);
366	os_memcpy(hdr->src, own_addr, ETH_ALEN);
367	hdr->ethertype = htons(ETH_P_PAE);
368
369	pos = (u8 *) (hdr + 1);
370	os_memcpy(pos, data, data_len);
371
372	res = send(drv->common.sock, (u8 *) hdr, len, 0);
373	os_free(hdr);
374
375	if (res < 0) {
376		wpa_printf(MSG_ERROR,
377			   "macsec_qca_send_eapol - packet len: %lu - failed: send: %s",
378			   (unsigned long) len, strerror(errno));
379	}
380
381	return res;
382}
383
384
385static int macsec_qca_macsec_init(void *priv, struct macsec_init_params *params)
386{
387	struct macsec_qca_data *drv = priv;
388
389	drv->always_include_sci = params->always_include_sci;
390	drv->use_es = params->use_es;
391	drv->use_scb = params->use_scb;
392
393	wpa_printf(MSG_DEBUG, "%s: es=%d, scb=%d, sci=%d",
394		   __func__, drv->use_es, drv->use_scb,
395		   drv->always_include_sci);
396
397	__macsec_drv_init(drv);
398
399	return 0;
400}
401
402
403static int macsec_qca_macsec_deinit(void *priv)
404{
405	struct macsec_qca_data *drv = priv;
406
407	wpa_printf(MSG_DEBUG, "%s", __func__);
408
409	__macsec_drv_deinit(drv);
410
411	return 0;
412}
413
414
415static int macsec_qca_get_capability(void *priv, enum macsec_cap *cap)
416{
417	wpa_printf(MSG_DEBUG, "%s", __func__);
418
419	*cap = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
420
421	return 0;
422}
423
424
425static int macsec_qca_enable_protect_frames(void *priv, Boolean enabled)
426{
427	struct macsec_qca_data *drv = priv;
428	int ret = 0;
429
430	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
431
432	drv->protect_frames = enabled;
433
434	return ret;
435}
436
437
438static int macsec_qca_set_replay_protect(void *priv, Boolean enabled,
439					 unsigned int window)
440{
441	struct macsec_qca_data *drv = priv;
442	int ret = 0;
443
444	wpa_printf(MSG_DEBUG, "%s: enabled=%d, win=%u",
445		   __func__, enabled, window);
446
447	drv->replay_protect = enabled;
448	drv->replay_window = window;
449
450	return ret;
451}
452
453
454static fal_cipher_suite_e macsec_qca_cs_type_get(u64 cs)
455{
456	if (cs == CS_ID_GCM_AES_128)
457		return FAL_CIPHER_SUITE_AES_GCM_128;
458	if (cs == CS_ID_GCM_AES_256)
459		return FAL_CIPHER_SUITE_AES_GCM_256;
460	return FAL_CIPHER_SUITE_MAX;
461}
462
463
464static int macsec_qca_set_current_cipher_suite(void *priv, u64 cs)
465{
466	struct macsec_qca_data *drv = priv;
467	fal_cipher_suite_e cs_type;
468
469	if (cs != CS_ID_GCM_AES_128 && cs != CS_ID_GCM_AES_256) {
470		wpa_printf(MSG_ERROR,
471			   "%s: NOT supported CipherSuite: %016" PRIx64,
472			   __func__, cs);
473		return -1;
474	}
475
476	wpa_printf(MSG_DEBUG, "%s: CipherSuite: %016" PRIx64, __func__, cs);
477
478	cs_type = macsec_qca_cs_type_get(cs);
479	return nss_macsec_secy_cipher_suite_set(drv->secy_id, cs_type);
480}
481
482
483static int macsec_qca_enable_controlled_port(void *priv, Boolean enabled)
484{
485	struct macsec_qca_data *drv = priv;
486	int ret = 0;
487
488	wpa_printf(MSG_DEBUG, "%s: enable=%d", __func__, enabled);
489
490	ret += nss_macsec_secy_controlled_port_en_set(drv->secy_id, enabled);
491
492	return ret;
493}
494
495
496static int macsec_qca_lookup_channel(struct channel_map *map,
497				     struct ieee802_1x_mka_sci *sci,
498				     u32 *channel)
499{
500	u32 i;
501
502	for (i = 0; i < MAXSC; i++) {
503		if (os_memcmp(&map[i].sci, sci,
504			      sizeof(struct ieee802_1x_mka_sci)) == 0) {
505			*channel = i;
506			return 0;
507		}
508	}
509
510	return -1;
511}
512
513
514static void macsec_qca_register_channel(struct channel_map *map,
515					struct ieee802_1x_mka_sci *sci,
516					u32 channel)
517{
518	os_memcpy(&map[channel].sci, sci, sizeof(struct ieee802_1x_mka_sci));
519}
520
521
522static int macsec_qca_lookup_receive_channel(struct macsec_qca_data *drv,
523					     struct receive_sc *sc,
524					     u32 *channel)
525{
526	return macsec_qca_lookup_channel(drv->receive_channel_map, &sc->sci,
527					 channel);
528}
529
530
531static void macsec_qca_register_receive_channel(struct macsec_qca_data *drv,
532						struct receive_sc *sc,
533						u32 channel)
534{
535	macsec_qca_register_channel(drv->receive_channel_map, &sc->sci,
536				    channel);
537}
538
539
540static int macsec_qca_lookup_transmit_channel(struct macsec_qca_data *drv,
541					      struct transmit_sc *sc,
542					      u32 *channel)
543{
544	return macsec_qca_lookup_channel(drv->transmit_channel_map, &sc->sci,
545					 channel);
546}
547
548
549static void macsec_qca_register_transmit_channel(struct macsec_qca_data *drv,
550						 struct transmit_sc *sc,
551						 u32 channel)
552{
553	macsec_qca_register_channel(drv->transmit_channel_map, &sc->sci,
554				    channel);
555}
556
557
558static int macsec_qca_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
559{
560	struct macsec_qca_data *drv = priv;
561	int ret = 0;
562	u32 next_pn = 0;
563	bool enabled = FALSE;
564	u32 win;
565	u32 channel;
566
567	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
568	if (ret != 0)
569		return ret;
570
571	ret += nss_macsec_secy_rx_sa_next_pn_get(drv->secy_id, channel, sa->an,
572						 &next_pn);
573	ret += nss_macsec_secy_rx_sc_replay_protect_get(drv->secy_id, channel,
574							&enabled);
575	ret += nss_macsec_secy_rx_sc_anti_replay_window_get(drv->secy_id,
576							    channel, &win);
577
578	if (enabled)
579		sa->lowest_pn = (next_pn > win) ? (next_pn - win) : 1;
580	else
581		sa->lowest_pn = next_pn;
582
583	wpa_printf(MSG_DEBUG, "%s: lpn=0x%x", __func__, sa->lowest_pn);
584
585	return ret;
586}
587
588
589static int macsec_qca_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
590{
591	struct macsec_qca_data *drv = priv;
592	int ret = 0;
593	u32 channel;
594
595	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
596	if (ret != 0)
597		return ret;
598
599	ret += nss_macsec_secy_tx_sa_next_pn_get(drv->secy_id, channel, sa->an,
600						 &sa->next_pn);
601
602	wpa_printf(MSG_DEBUG, "%s: npn=0x%x", __func__, sa->next_pn);
603
604	return ret;
605}
606
607
608static int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
609{
610	struct macsec_qca_data *drv = priv;
611	int ret = 0;
612	u32 channel;
613
614	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
615	if (ret != 0)
616		return ret;
617
618	ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
619						 sa->next_pn);
620
621	wpa_printf(MSG_INFO, "%s: npn=0x%x", __func__, sa->next_pn);
622
623	return ret;
624}
625
626
627static int macsec_qca_get_available_receive_sc(void *priv, u32 *channel)
628{
629	struct macsec_qca_data *drv = priv;
630	int ret = 0;
631	u32 sc_ch = 0;
632	bool in_use = FALSE;
633
634	for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
635		ret = nss_macsec_secy_rx_sc_in_used_get(drv->secy_id, sc_ch,
636							&in_use);
637		if (ret)
638			continue;
639
640		if (!in_use) {
641			*channel = sc_ch;
642			wpa_printf(MSG_DEBUG, "%s: channel=%d",
643				   __func__, *channel);
644			return 0;
645		}
646	}
647
648	wpa_printf(MSG_DEBUG, "%s: no available channel", __func__);
649
650	return -1;
651}
652
653
654static int macsec_qca_create_receive_sc(void *priv, struct receive_sc *sc,
655					unsigned int conf_offset,
656					int validation)
657{
658	struct macsec_qca_data *drv = priv;
659	int ret = 0;
660	fal_rx_prc_lut_t entry;
661	fal_rx_sc_validate_frame_e vf;
662	enum validate_frames validate_frames = validation;
663	u32 channel;
664	const u8 *sci_addr = sc->sci.addr;
665	u16 sci_port = be_to_host16(sc->sci.port);
666
667	ret = macsec_qca_get_available_receive_sc(priv, &channel);
668	if (ret != 0)
669		return ret;
670
671	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
672
673	/* rx prc lut */
674	os_memset(&entry, 0, sizeof(entry));
675
676	os_memcpy(entry.sci, sci_addr, ETH_ALEN);
677	entry.sci[6] = (sci_port >> 8) & 0xff;
678	entry.sci[7] = sci_port & 0xff;
679	entry.sci_mask = 0xf;
680
681	entry.valid = 1;
682	entry.channel = channel;
683	entry.action = FAL_RX_PRC_ACTION_PROCESS;
684	entry.offset = conf_offset;
685
686	/* rx validate frame  */
687	if (validate_frames == Strict)
688		vf = FAL_RX_SC_VALIDATE_FRAME_STRICT;
689	else if (validate_frames == Checked)
690		vf = FAL_RX_SC_VALIDATE_FRAME_CHECK;
691	else
692		vf = FAL_RX_SC_VALIDATE_FRAME_DISABLED;
693
694	ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
695	ret += nss_macsec_secy_rx_sc_create(drv->secy_id, channel);
696	ret += nss_macsec_secy_rx_sc_validate_frame_set(drv->secy_id, channel,
697							vf);
698	ret += nss_macsec_secy_rx_sc_replay_protect_set(drv->secy_id, channel,
699							drv->replay_protect);
700	ret += nss_macsec_secy_rx_sc_anti_replay_window_set(drv->secy_id,
701							    channel,
702							    drv->replay_window);
703
704	macsec_qca_register_receive_channel(drv, sc, channel);
705
706	return ret;
707}
708
709
710static int macsec_qca_delete_receive_sc(void *priv, struct receive_sc *sc)
711{
712	struct macsec_qca_data *drv = priv;
713	int ret;
714	fal_rx_prc_lut_t entry;
715	u32 channel;
716
717	ret = macsec_qca_lookup_receive_channel(priv, sc, &channel);
718	if (ret != 0)
719		return ret;
720
721	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
722
723	/* rx prc lut */
724	os_memset(&entry, 0, sizeof(entry));
725
726	ret += nss_macsec_secy_rx_sc_del(drv->secy_id, channel);
727	ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
728
729	return ret;
730}
731
732
733static int macsec_qca_create_receive_sa(void *priv, struct receive_sa *sa)
734{
735	struct macsec_qca_data *drv = priv;
736	int ret;
737	fal_rx_sak_t rx_sak;
738	int i = 0;
739	u32 channel;
740	fal_rx_prc_lut_t entry;
741	u32 offset;
742
743	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
744	if (ret != 0)
745		return ret;
746
747	wpa_printf(MSG_DEBUG, "%s, channel=%d, an=%d, lpn=0x%x",
748		   __func__, channel, sa->an, sa->lowest_pn);
749
750	os_memset(&rx_sak, 0, sizeof(rx_sak));
751	rx_sak.sak_len = sa->pkey->key_len;
752	if (sa->pkey->key_len == SAK_128_LEN) {
753		for (i = 0; i < 16; i++)
754			rx_sak.sak[i] = sa->pkey->key[15 - i];
755	} else if (sa->pkey->key_len == SAK_256_LEN) {
756		for (i = 0; i < 16; i++) {
757			rx_sak.sak1[i] = sa->pkey->key[15 - i];
758			rx_sak.sak[i] = sa->pkey->key[31 - i];
759		}
760	} else {
761		return -1;
762	}
763
764	if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0)
765		offset = 0;
766	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30)
767		offset = 30;
768	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50)
769		offset = 50;
770	else
771		return -1;
772	ret += nss_macsec_secy_rx_prc_lut_get(drv->secy_id, channel, &entry);
773	entry.offset = offset;
774	ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
775	ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, sa->an);
776	ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, sa->an,
777					  &rx_sak);
778
779	return ret;
780}
781
782
783static int macsec_qca_enable_receive_sa(void *priv, struct receive_sa *sa)
784{
785	struct macsec_qca_data *drv = priv;
786	int ret;
787	u32 channel;
788
789	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
790	if (ret != 0)
791		return ret;
792
793	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
794		   sa->an);
795
796	ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
797					    TRUE);
798
799	return ret;
800}
801
802
803static int macsec_qca_disable_receive_sa(void *priv, struct receive_sa *sa)
804{
805	struct macsec_qca_data *drv = priv;
806	int ret;
807	u32 channel;
808
809	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
810	if (ret != 0)
811		return ret;
812
813	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
814		   sa->an);
815
816	ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
817					    FALSE);
818
819	return ret;
820}
821
822
823static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel)
824{
825	struct macsec_qca_data *drv = priv;
826	u32 sc_ch = 0;
827	bool in_use = FALSE;
828
829	for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
830		if (nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch,
831						      &in_use))
832			continue;
833
834		if (!in_use) {
835			*channel = sc_ch;
836			wpa_printf(MSG_DEBUG, "%s: channel=%d",
837				   __func__, *channel);
838			return 0;
839		}
840	}
841
842	wpa_printf(MSG_DEBUG, "%s: no avaiable channel", __func__);
843
844	return -1;
845}
846
847
848static int macsec_qca_create_transmit_sc(void *priv, struct transmit_sc *sc,
849					 unsigned int conf_offset)
850{
851	struct macsec_qca_data *drv = priv;
852	int ret;
853	fal_tx_class_lut_t entry;
854	u8 psci[ETH_ALEN + 2];
855	u32 channel;
856	u16 sci_port = be_to_host16(sc->sci.port);
857
858	ret = macsec_qca_get_available_transmit_sc(priv, &channel);
859	if (ret != 0)
860		return ret;
861
862	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
863
864	/* class lut */
865	os_memset(&entry, 0, sizeof(entry));
866
867	entry.valid = 1;
868	entry.action = FAL_TX_CLASS_ACTION_FORWARD;
869	entry.channel = channel;
870
871	os_memcpy(psci, sc->sci.addr, ETH_ALEN);
872	psci[6] = (sci_port >> 8) & 0xff;
873	psci[7] = sci_port & 0xff;
874
875	ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
876	ret += nss_macsec_secy_tx_sc_create(drv->secy_id, channel, psci, 8);
877	ret += nss_macsec_secy_tx_sc_protect_set(drv->secy_id, channel,
878						 drv->protect_frames);
879	ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
880								channel,
881								conf_offset);
882
883	macsec_qca_register_transmit_channel(drv, sc, channel);
884
885	return ret;
886}
887
888
889static int macsec_qca_delete_transmit_sc(void *priv, struct transmit_sc *sc)
890{
891	struct macsec_qca_data *drv = priv;
892	int ret;
893	fal_tx_class_lut_t entry;
894	u32 channel;
895
896	ret = macsec_qca_lookup_transmit_channel(priv, sc, &channel);
897	if (ret != 0)
898		return ret;
899
900	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
901
902	/* class lut */
903	os_memset(&entry, 0, sizeof(entry));
904
905	ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
906	ret += nss_macsec_secy_tx_sc_del(drv->secy_id, channel);
907
908	return ret;
909}
910
911
912static int macsec_qca_create_transmit_sa(void *priv, struct transmit_sa *sa)
913{
914	struct macsec_qca_data *drv = priv;
915	int ret;
916	u8 tci = 0;
917	fal_tx_sak_t tx_sak;
918	int i;
919	u32 channel;
920	u32 offset;
921
922	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
923	if (ret != 0)
924		return ret;
925
926	wpa_printf(MSG_DEBUG,
927		   "%s: channel=%d, an=%d, next_pn=0x%x, confidentiality=%d",
928		   __func__, channel, sa->an, sa->next_pn, sa->confidentiality);
929
930	if (drv->always_include_sci)
931		tci |= TCI_SC;
932	else if (drv->use_es)
933		tci |= TCI_ES;
934	else if (drv->use_scb)
935		tci |= TCI_SCB;
936
937	if (sa->confidentiality)
938		tci |= TCI_E | TCI_C;
939
940	os_memset(&tx_sak, 0, sizeof(tx_sak));
941	tx_sak.sak_len = sa->pkey->key_len;
942	if (sa->pkey->key_len == SAK_128_LEN) {
943		for (i = 0; i < 16; i++)
944			tx_sak.sak[i] = sa->pkey->key[15 - i];
945	} else if (sa->pkey->key_len == SAK_256_LEN) {
946		for (i = 0; i < 16; i++) {
947			tx_sak.sak1[i] = sa->pkey->key[15 - i];
948			tx_sak.sak[i] = sa->pkey->key[31 - i];
949		}
950	} else {
951		return -1;
952	}
953
954	if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0)
955		offset = 0;
956	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30)
957		offset = 30;
958	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50)
959		offset = 50;
960	else
961		return -1;
962	ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
963								channel,
964								offset);
965	ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
966						 sa->next_pn);
967	ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, sa->an,
968					  &tx_sak);
969	ret += nss_macsec_secy_tx_sc_tci_7_2_set(drv->secy_id, channel,
970						 (tci >> 2));
971	ret += nss_macsec_secy_tx_sc_an_set(drv->secy_id, channel, sa->an);
972
973	return ret;
974}
975
976
977static int macsec_qca_enable_transmit_sa(void *priv, struct transmit_sa *sa)
978{
979	struct macsec_qca_data *drv = priv;
980	int ret;
981	u32 channel;
982
983	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
984	if (ret != 0)
985		return ret;
986
987	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
988		   sa->an);
989
990	ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
991					    TRUE);
992
993	return ret;
994}
995
996
997static int macsec_qca_disable_transmit_sa(void *priv, struct transmit_sa *sa)
998{
999	struct macsec_qca_data *drv = priv;
1000	int ret;
1001	u32 channel;
1002
1003	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
1004	if (ret != 0)
1005		return ret;
1006
1007	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
1008		   sa->an);
1009
1010	ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
1011					    FALSE);
1012
1013	return ret;
1014}
1015
1016
1017const struct wpa_driver_ops wpa_driver_macsec_qca_ops = {
1018	.name = "macsec_qca",
1019	.desc = "QCA MACsec Ethernet driver",
1020	.get_ssid = driver_wired_get_ssid,
1021	.get_bssid = driver_wired_get_bssid,
1022	.get_capa = driver_wired_get_capa,
1023	.init = macsec_qca_init,
1024	.deinit = macsec_qca_deinit,
1025	.hapd_init = macsec_qca_hapd_init,
1026	.hapd_deinit = macsec_qca_hapd_deinit,
1027	.hapd_send_eapol = macsec_qca_send_eapol,
1028
1029	.macsec_init = macsec_qca_macsec_init,
1030	.macsec_deinit = macsec_qca_macsec_deinit,
1031	.macsec_get_capability = macsec_qca_get_capability,
1032	.enable_protect_frames = macsec_qca_enable_protect_frames,
1033	.set_replay_protect = macsec_qca_set_replay_protect,
1034	.set_current_cipher_suite = macsec_qca_set_current_cipher_suite,
1035	.enable_controlled_port = macsec_qca_enable_controlled_port,
1036	.get_receive_lowest_pn = macsec_qca_get_receive_lowest_pn,
1037	.get_transmit_next_pn = macsec_qca_get_transmit_next_pn,
1038	.set_transmit_next_pn = macsec_qca_set_transmit_next_pn,
1039	.create_receive_sc = macsec_qca_create_receive_sc,
1040	.delete_receive_sc = macsec_qca_delete_receive_sc,
1041	.create_receive_sa = macsec_qca_create_receive_sa,
1042	.enable_receive_sa = macsec_qca_enable_receive_sa,
1043	.disable_receive_sa = macsec_qca_disable_receive_sa,
1044	.create_transmit_sc = macsec_qca_create_transmit_sc,
1045	.delete_transmit_sc = macsec_qca_delete_transmit_sc,
1046	.create_transmit_sa = macsec_qca_create_transmit_sa,
1047	.enable_transmit_sa = macsec_qca_enable_transmit_sa,
1048	.disable_transmit_sa = macsec_qca_disable_transmit_sa,
1049};
1050