xref: /freebsd/contrib/wpa/src/drivers/driver_macsec_qca.c (revision 85732ac8bccbc0adcf5a261ea1ffec8ca7b3a92d)
15b9c547cSRui Paulo /*
25b9c547cSRui Paulo  * Wired Ethernet driver interface for QCA MACsec driver
35b9c547cSRui Paulo  * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
45b9c547cSRui Paulo  * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
55b9c547cSRui Paulo  * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
65b9c547cSRui Paulo  *
75b9c547cSRui Paulo  * This software may be distributed under the terms of the BSD license.
85b9c547cSRui Paulo  * See README for more details.
95b9c547cSRui Paulo  */
105b9c547cSRui Paulo 
115b9c547cSRui Paulo #include "includes.h"
125b9c547cSRui Paulo #include <sys/ioctl.h>
135b9c547cSRui Paulo #include <net/if.h>
14780fb4a2SCy Schubert #include <inttypes.h>
155b9c547cSRui Paulo #ifdef __linux__
165b9c547cSRui Paulo #include <netpacket/packet.h>
175b9c547cSRui Paulo #include <net/if_arp.h>
185b9c547cSRui Paulo #include <net/if.h>
195b9c547cSRui Paulo #endif /* __linux__ */
205b9c547cSRui Paulo #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
215b9c547cSRui Paulo #include <net/if_dl.h>
225b9c547cSRui Paulo #include <net/if_media.h>
235b9c547cSRui Paulo #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
245b9c547cSRui Paulo #ifdef __sun__
255b9c547cSRui Paulo #include <sys/sockio.h>
265b9c547cSRui Paulo #endif /* __sun__ */
275b9c547cSRui Paulo 
285b9c547cSRui Paulo #include "utils/common.h"
295b9c547cSRui Paulo #include "utils/eloop.h"
305b9c547cSRui Paulo #include "common/defs.h"
315b9c547cSRui Paulo #include "common/ieee802_1x_defs.h"
32*85732ac8SCy Schubert #include "pae/ieee802_1x_kay.h"
335b9c547cSRui Paulo #include "driver.h"
34*85732ac8SCy Schubert #include "driver_wired_common.h"
355b9c547cSRui Paulo 
365b9c547cSRui Paulo #include "nss_macsec_secy.h"
375b9c547cSRui Paulo #include "nss_macsec_secy_rx.h"
385b9c547cSRui Paulo #include "nss_macsec_secy_tx.h"
395b9c547cSRui Paulo 
405b9c547cSRui Paulo #define MAXSC 16
415b9c547cSRui Paulo 
42*85732ac8SCy Schubert #define SAK_128_LEN	16
43*85732ac8SCy Schubert #define SAK_256_LEN	32
44*85732ac8SCy Schubert 
455b9c547cSRui Paulo /* TCI field definition */
465b9c547cSRui Paulo #define TCI_ES                0x40
475b9c547cSRui Paulo #define TCI_SC                0x20
485b9c547cSRui Paulo #define TCI_SCB               0x10
495b9c547cSRui Paulo #define TCI_E                 0x08
505b9c547cSRui Paulo #define TCI_C                 0x04
515b9c547cSRui Paulo 
525b9c547cSRui Paulo #ifdef _MSC_VER
535b9c547cSRui Paulo #pragma pack(push, 1)
545b9c547cSRui Paulo #endif /* _MSC_VER */
555b9c547cSRui Paulo 
565b9c547cSRui Paulo #ifdef _MSC_VER
575b9c547cSRui Paulo #pragma pack(pop)
585b9c547cSRui Paulo #endif /* _MSC_VER */
595b9c547cSRui Paulo 
60*85732ac8SCy Schubert struct channel_map {
61*85732ac8SCy Schubert 	struct ieee802_1x_mka_sci sci;
62*85732ac8SCy Schubert };
635b9c547cSRui Paulo 
645b9c547cSRui Paulo struct macsec_qca_data {
65*85732ac8SCy Schubert 	struct driver_wired_common_data common;
665b9c547cSRui Paulo 
67*85732ac8SCy Schubert 	u32 secy_id;
685b9c547cSRui Paulo 
695b9c547cSRui Paulo 	/* shadow */
705b9c547cSRui Paulo 	Boolean always_include_sci;
715b9c547cSRui Paulo 	Boolean use_es;
725b9c547cSRui Paulo 	Boolean use_scb;
735b9c547cSRui Paulo 	Boolean protect_frames;
745b9c547cSRui Paulo 	Boolean replay_protect;
755b9c547cSRui Paulo 	u32 replay_window;
76*85732ac8SCy Schubert 
77*85732ac8SCy Schubert 	struct channel_map receive_channel_map[MAXSC];
78*85732ac8SCy Schubert 	struct channel_map transmit_channel_map[MAXSC];
795b9c547cSRui Paulo };
805b9c547cSRui Paulo 
815b9c547cSRui Paulo 
825b9c547cSRui Paulo static void __macsec_drv_init(struct macsec_qca_data *drv)
835b9c547cSRui Paulo {
845b9c547cSRui Paulo 	int ret = 0;
855b9c547cSRui Paulo 	fal_rx_ctl_filt_t rx_ctl_filt;
865b9c547cSRui Paulo 	fal_tx_ctl_filt_t tx_ctl_filt;
875b9c547cSRui Paulo 
885b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "%s: secy_id=%d", __func__, drv->secy_id);
895b9c547cSRui Paulo 
905b9c547cSRui Paulo 	/* Enable Secy and Let EAPoL bypass */
915b9c547cSRui Paulo 	ret = nss_macsec_secy_en_set(drv->secy_id, TRUE);
925b9c547cSRui Paulo 	if (ret)
935b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "nss_macsec_secy_en_set: FAIL");
945b9c547cSRui Paulo 
955b9c547cSRui Paulo 	ret = nss_macsec_secy_sc_sa_mapping_mode_set(drv->secy_id,
965b9c547cSRui Paulo 						     FAL_SC_SA_MAP_1_4);
975b9c547cSRui Paulo 	if (ret)
985b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
995b9c547cSRui Paulo 			   "nss_macsec_secy_sc_sa_mapping_mode_set: FAIL");
1005b9c547cSRui Paulo 
1015b9c547cSRui Paulo 	os_memset(&rx_ctl_filt, 0, sizeof(rx_ctl_filt));
1025b9c547cSRui Paulo 	rx_ctl_filt.bypass = 1;
1035b9c547cSRui Paulo 	rx_ctl_filt.match_type = IG_CTL_COMPARE_ETHER_TYPE;
1045b9c547cSRui Paulo 	rx_ctl_filt.match_mask = 0xffff;
1055b9c547cSRui Paulo 	rx_ctl_filt.ether_type_da_range = 0x888e;
1065b9c547cSRui Paulo 	ret = nss_macsec_secy_rx_ctl_filt_set(drv->secy_id, 0, &rx_ctl_filt);
1075b9c547cSRui Paulo 	if (ret)
1085b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "nss_macsec_secy_rx_ctl_filt_set: FAIL");
1095b9c547cSRui Paulo 
1105b9c547cSRui Paulo 	os_memset(&tx_ctl_filt, 0, sizeof(tx_ctl_filt));
1115b9c547cSRui Paulo 	tx_ctl_filt.bypass = 1;
1125b9c547cSRui Paulo 	tx_ctl_filt.match_type = EG_CTL_COMPARE_ETHER_TYPE;
1135b9c547cSRui Paulo 	tx_ctl_filt.match_mask = 0xffff;
1145b9c547cSRui Paulo 	tx_ctl_filt.ether_type_da_range = 0x888e;
1155b9c547cSRui Paulo 	ret = nss_macsec_secy_tx_ctl_filt_set(drv->secy_id, 0, &tx_ctl_filt);
1165b9c547cSRui Paulo 	if (ret)
1175b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "nss_macsec_secy_tx_ctl_filt_set: FAIL");
1185b9c547cSRui Paulo }
1195b9c547cSRui Paulo 
1205b9c547cSRui Paulo 
1215b9c547cSRui Paulo static void __macsec_drv_deinit(struct macsec_qca_data *drv)
1225b9c547cSRui Paulo {
1235b9c547cSRui Paulo 	nss_macsec_secy_en_set(drv->secy_id, FALSE);
1245b9c547cSRui Paulo 	nss_macsec_secy_rx_sc_del_all(drv->secy_id);
1255b9c547cSRui Paulo 	nss_macsec_secy_tx_sc_del_all(drv->secy_id);
1265b9c547cSRui Paulo }
1275b9c547cSRui Paulo 
1285b9c547cSRui Paulo 
1295b9c547cSRui Paulo static void * macsec_qca_init(void *ctx, const char *ifname)
1305b9c547cSRui Paulo {
1315b9c547cSRui Paulo 	struct macsec_qca_data *drv;
1325b9c547cSRui Paulo 
1335b9c547cSRui Paulo 	drv = os_zalloc(sizeof(*drv));
1345b9c547cSRui Paulo 	if (drv == NULL)
1355b9c547cSRui Paulo 		return NULL;
1365b9c547cSRui Paulo 
1375b9c547cSRui Paulo 	/* Board specific settings */
138*85732ac8SCy Schubert 	if (os_memcmp("eth2", ifname, 4) == 0)
1395b9c547cSRui Paulo 		drv->secy_id = 1;
140*85732ac8SCy Schubert 	else if (os_memcmp("eth3", ifname, 4) == 0)
1415b9c547cSRui Paulo 		drv->secy_id = 2;
1425b9c547cSRui Paulo 	else
1435b9c547cSRui Paulo 		drv->secy_id = -1;
1445b9c547cSRui Paulo 
145*85732ac8SCy Schubert 	if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
1465b9c547cSRui Paulo 		os_free(drv);
1475b9c547cSRui Paulo 		return NULL;
1485b9c547cSRui Paulo 	}
1495b9c547cSRui Paulo 
1505b9c547cSRui Paulo 	return drv;
1515b9c547cSRui Paulo }
1525b9c547cSRui Paulo 
1535b9c547cSRui Paulo 
1545b9c547cSRui Paulo static void macsec_qca_deinit(void *priv)
1555b9c547cSRui Paulo {
1565b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
1575b9c547cSRui Paulo 
158*85732ac8SCy Schubert 	driver_wired_deinit_common(&drv->common);
1595b9c547cSRui Paulo 	os_free(drv);
1605b9c547cSRui Paulo }
1615b9c547cSRui Paulo 
1625b9c547cSRui Paulo 
1635b9c547cSRui Paulo static int macsec_qca_macsec_init(void *priv, struct macsec_init_params *params)
1645b9c547cSRui Paulo {
1655b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
1665b9c547cSRui Paulo 
1675b9c547cSRui Paulo 	drv->always_include_sci = params->always_include_sci;
1685b9c547cSRui Paulo 	drv->use_es = params->use_es;
1695b9c547cSRui Paulo 	drv->use_scb = params->use_scb;
1705b9c547cSRui Paulo 
1715b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "%s: es=%d, scb=%d, sci=%d",
1725b9c547cSRui Paulo 		   __func__, drv->use_es, drv->use_scb,
1735b9c547cSRui Paulo 		   drv->always_include_sci);
1745b9c547cSRui Paulo 
1755b9c547cSRui Paulo 	__macsec_drv_init(drv);
1765b9c547cSRui Paulo 
1775b9c547cSRui Paulo 	return 0;
1785b9c547cSRui Paulo }
1795b9c547cSRui Paulo 
1805b9c547cSRui Paulo 
1815b9c547cSRui Paulo static int macsec_qca_macsec_deinit(void *priv)
1825b9c547cSRui Paulo {
1835b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
1845b9c547cSRui Paulo 
1855b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "%s", __func__);
1865b9c547cSRui Paulo 
1875b9c547cSRui Paulo 	__macsec_drv_deinit(drv);
1885b9c547cSRui Paulo 
1895b9c547cSRui Paulo 	return 0;
1905b9c547cSRui Paulo }
1915b9c547cSRui Paulo 
1925b9c547cSRui Paulo 
193*85732ac8SCy Schubert static int macsec_qca_get_capability(void *priv, enum macsec_cap *cap)
194*85732ac8SCy Schubert {
195*85732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "%s", __func__);
196*85732ac8SCy Schubert 
197*85732ac8SCy Schubert 	*cap = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
198*85732ac8SCy Schubert 
199*85732ac8SCy Schubert 	return 0;
200*85732ac8SCy Schubert }
201*85732ac8SCy Schubert 
202*85732ac8SCy Schubert 
2035b9c547cSRui Paulo static int macsec_qca_enable_protect_frames(void *priv, Boolean enabled)
2045b9c547cSRui Paulo {
2055b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
2065b9c547cSRui Paulo 	int ret = 0;
2075b9c547cSRui Paulo 
2085b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
2095b9c547cSRui Paulo 
2105b9c547cSRui Paulo 	drv->protect_frames = enabled;
2115b9c547cSRui Paulo 
2125b9c547cSRui Paulo 	return ret;
2135b9c547cSRui Paulo }
2145b9c547cSRui Paulo 
2155b9c547cSRui Paulo 
2165b9c547cSRui Paulo static int macsec_qca_set_replay_protect(void *priv, Boolean enabled,
2175b9c547cSRui Paulo 					 unsigned int window)
2185b9c547cSRui Paulo {
2195b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
2205b9c547cSRui Paulo 	int ret = 0;
2215b9c547cSRui Paulo 
2225b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "%s: enabled=%d, win=%u",
2235b9c547cSRui Paulo 		   __func__, enabled, window);
2245b9c547cSRui Paulo 
2255b9c547cSRui Paulo 	drv->replay_protect = enabled;
2265b9c547cSRui Paulo 	drv->replay_window = window;
2275b9c547cSRui Paulo 
2285b9c547cSRui Paulo 	return ret;
2295b9c547cSRui Paulo }
2305b9c547cSRui Paulo 
2315b9c547cSRui Paulo 
232*85732ac8SCy Schubert static fal_cipher_suite_e macsec_qca_cs_type_get(u64 cs)
233*85732ac8SCy Schubert {
234*85732ac8SCy Schubert 	if (cs == CS_ID_GCM_AES_128)
235*85732ac8SCy Schubert 		return FAL_CIPHER_SUITE_AES_GCM_128;
236*85732ac8SCy Schubert 	if (cs == CS_ID_GCM_AES_256)
237*85732ac8SCy Schubert 		return FAL_CIPHER_SUITE_AES_GCM_256;
238*85732ac8SCy Schubert 	return FAL_CIPHER_SUITE_MAX;
239*85732ac8SCy Schubert }
240*85732ac8SCy Schubert 
241*85732ac8SCy Schubert 
242780fb4a2SCy Schubert static int macsec_qca_set_current_cipher_suite(void *priv, u64 cs)
2435b9c547cSRui Paulo {
244*85732ac8SCy Schubert 	struct macsec_qca_data *drv = priv;
245*85732ac8SCy Schubert 	fal_cipher_suite_e cs_type;
246*85732ac8SCy Schubert 
247*85732ac8SCy Schubert 	if (cs != CS_ID_GCM_AES_128 && cs != CS_ID_GCM_AES_256) {
248780fb4a2SCy Schubert 		wpa_printf(MSG_ERROR,
249780fb4a2SCy Schubert 			   "%s: NOT supported CipherSuite: %016" PRIx64,
250780fb4a2SCy Schubert 			   __func__, cs);
2515b9c547cSRui Paulo 		return -1;
2525b9c547cSRui Paulo 	}
2535b9c547cSRui Paulo 
254*85732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: CipherSuite: %016" PRIx64, __func__, cs);
2555b9c547cSRui Paulo 
256*85732ac8SCy Schubert 	cs_type = macsec_qca_cs_type_get(cs);
257*85732ac8SCy Schubert 	return nss_macsec_secy_cipher_suite_set(drv->secy_id, cs_type);
2585b9c547cSRui Paulo }
2595b9c547cSRui Paulo 
2605b9c547cSRui Paulo 
2615b9c547cSRui Paulo static int macsec_qca_enable_controlled_port(void *priv, Boolean enabled)
2625b9c547cSRui Paulo {
2635b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
2645b9c547cSRui Paulo 	int ret = 0;
2655b9c547cSRui Paulo 
2665b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "%s: enable=%d", __func__, enabled);
2675b9c547cSRui Paulo 
2685b9c547cSRui Paulo 	ret += nss_macsec_secy_controlled_port_en_set(drv->secy_id, enabled);
2695b9c547cSRui Paulo 
2705b9c547cSRui Paulo 	return ret;
2715b9c547cSRui Paulo }
2725b9c547cSRui Paulo 
2735b9c547cSRui Paulo 
274*85732ac8SCy Schubert static int macsec_qca_lookup_channel(struct channel_map *map,
275*85732ac8SCy Schubert 				     struct ieee802_1x_mka_sci *sci,
276*85732ac8SCy Schubert 				     u32 *channel)
277*85732ac8SCy Schubert {
278*85732ac8SCy Schubert 	u32 i;
279*85732ac8SCy Schubert 
280*85732ac8SCy Schubert 	for (i = 0; i < MAXSC; i++) {
281*85732ac8SCy Schubert 		if (os_memcmp(&map[i].sci, sci,
282*85732ac8SCy Schubert 			      sizeof(struct ieee802_1x_mka_sci)) == 0) {
283*85732ac8SCy Schubert 			*channel = i;
284*85732ac8SCy Schubert 			return 0;
285*85732ac8SCy Schubert 		}
286*85732ac8SCy Schubert 	}
287*85732ac8SCy Schubert 
288*85732ac8SCy Schubert 	return -1;
289*85732ac8SCy Schubert }
290*85732ac8SCy Schubert 
291*85732ac8SCy Schubert 
292*85732ac8SCy Schubert static void macsec_qca_register_channel(struct channel_map *map,
293*85732ac8SCy Schubert 					struct ieee802_1x_mka_sci *sci,
294*85732ac8SCy Schubert 					u32 channel)
295*85732ac8SCy Schubert {
296*85732ac8SCy Schubert 	os_memcpy(&map[channel].sci, sci, sizeof(struct ieee802_1x_mka_sci));
297*85732ac8SCy Schubert }
298*85732ac8SCy Schubert 
299*85732ac8SCy Schubert 
300*85732ac8SCy Schubert static int macsec_qca_lookup_receive_channel(struct macsec_qca_data *drv,
301*85732ac8SCy Schubert 					     struct receive_sc *sc,
302*85732ac8SCy Schubert 					     u32 *channel)
303*85732ac8SCy Schubert {
304*85732ac8SCy Schubert 	return macsec_qca_lookup_channel(drv->receive_channel_map, &sc->sci,
305*85732ac8SCy Schubert 					 channel);
306*85732ac8SCy Schubert }
307*85732ac8SCy Schubert 
308*85732ac8SCy Schubert 
309*85732ac8SCy Schubert static void macsec_qca_register_receive_channel(struct macsec_qca_data *drv,
310*85732ac8SCy Schubert 						struct receive_sc *sc,
311*85732ac8SCy Schubert 						u32 channel)
312*85732ac8SCy Schubert {
313*85732ac8SCy Schubert 	macsec_qca_register_channel(drv->receive_channel_map, &sc->sci,
314*85732ac8SCy Schubert 				    channel);
315*85732ac8SCy Schubert }
316*85732ac8SCy Schubert 
317*85732ac8SCy Schubert 
318*85732ac8SCy Schubert static int macsec_qca_lookup_transmit_channel(struct macsec_qca_data *drv,
319*85732ac8SCy Schubert 					      struct transmit_sc *sc,
320*85732ac8SCy Schubert 					      u32 *channel)
321*85732ac8SCy Schubert {
322*85732ac8SCy Schubert 	return macsec_qca_lookup_channel(drv->transmit_channel_map, &sc->sci,
323*85732ac8SCy Schubert 					 channel);
324*85732ac8SCy Schubert }
325*85732ac8SCy Schubert 
326*85732ac8SCy Schubert 
327*85732ac8SCy Schubert static void macsec_qca_register_transmit_channel(struct macsec_qca_data *drv,
328*85732ac8SCy Schubert 						 struct transmit_sc *sc,
329*85732ac8SCy Schubert 						 u32 channel)
330*85732ac8SCy Schubert {
331*85732ac8SCy Schubert 	macsec_qca_register_channel(drv->transmit_channel_map, &sc->sci,
332*85732ac8SCy Schubert 				    channel);
333*85732ac8SCy Schubert }
334*85732ac8SCy Schubert 
335*85732ac8SCy Schubert 
336*85732ac8SCy Schubert static int macsec_qca_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
3375b9c547cSRui Paulo {
3385b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
3395b9c547cSRui Paulo 	int ret = 0;
3405b9c547cSRui Paulo 	u32 next_pn = 0;
3415b9c547cSRui Paulo 	bool enabled = FALSE;
3425b9c547cSRui Paulo 	u32 win;
343*85732ac8SCy Schubert 	u32 channel;
3445b9c547cSRui Paulo 
345*85732ac8SCy Schubert 	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
346*85732ac8SCy Schubert 	if (ret != 0)
347*85732ac8SCy Schubert 		return ret;
348*85732ac8SCy Schubert 
349*85732ac8SCy Schubert 	ret += nss_macsec_secy_rx_sa_next_pn_get(drv->secy_id, channel, sa->an,
3505b9c547cSRui Paulo 						 &next_pn);
3515b9c547cSRui Paulo 	ret += nss_macsec_secy_rx_sc_replay_protect_get(drv->secy_id, channel,
3525b9c547cSRui Paulo 							&enabled);
3535b9c547cSRui Paulo 	ret += nss_macsec_secy_rx_sc_anti_replay_window_get(drv->secy_id,
3545b9c547cSRui Paulo 							    channel, &win);
3555b9c547cSRui Paulo 
3565b9c547cSRui Paulo 	if (enabled)
357*85732ac8SCy Schubert 		sa->lowest_pn = (next_pn > win) ? (next_pn - win) : 1;
3585b9c547cSRui Paulo 	else
359*85732ac8SCy Schubert 		sa->lowest_pn = next_pn;
3605b9c547cSRui Paulo 
361*85732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: lpn=0x%x", __func__, sa->lowest_pn);
3625b9c547cSRui Paulo 
3635b9c547cSRui Paulo 	return ret;
3645b9c547cSRui Paulo }
3655b9c547cSRui Paulo 
3665b9c547cSRui Paulo 
367*85732ac8SCy Schubert static int macsec_qca_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
3685b9c547cSRui Paulo {
3695b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
3705b9c547cSRui Paulo 	int ret = 0;
371*85732ac8SCy Schubert 	u32 channel;
3725b9c547cSRui Paulo 
373*85732ac8SCy Schubert 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
374*85732ac8SCy Schubert 	if (ret != 0)
375*85732ac8SCy Schubert 		return ret;
3765b9c547cSRui Paulo 
377*85732ac8SCy Schubert 	ret += nss_macsec_secy_tx_sa_next_pn_get(drv->secy_id, channel, sa->an,
378*85732ac8SCy Schubert 						 &sa->next_pn);
379*85732ac8SCy Schubert 
380*85732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: npn=0x%x", __func__, sa->next_pn);
3815b9c547cSRui Paulo 
3825b9c547cSRui Paulo 	return ret;
3835b9c547cSRui Paulo }
3845b9c547cSRui Paulo 
3855b9c547cSRui Paulo 
386*85732ac8SCy Schubert static int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
3875b9c547cSRui Paulo {
3885b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
3895b9c547cSRui Paulo 	int ret = 0;
390*85732ac8SCy Schubert 	u32 channel;
3915b9c547cSRui Paulo 
392*85732ac8SCy Schubert 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
393*85732ac8SCy Schubert 	if (ret != 0)
394*85732ac8SCy Schubert 		return ret;
3955b9c547cSRui Paulo 
396*85732ac8SCy Schubert 	ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
397*85732ac8SCy Schubert 						 sa->next_pn);
398*85732ac8SCy Schubert 
399*85732ac8SCy Schubert 	wpa_printf(MSG_INFO, "%s: npn=0x%x", __func__, sa->next_pn);
4005b9c547cSRui Paulo 
4015b9c547cSRui Paulo 	return ret;
4025b9c547cSRui Paulo }
4035b9c547cSRui Paulo 
4045b9c547cSRui Paulo 
4055b9c547cSRui Paulo static int macsec_qca_get_available_receive_sc(void *priv, u32 *channel)
4065b9c547cSRui Paulo {
4075b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
4085b9c547cSRui Paulo 	int ret = 0;
4095b9c547cSRui Paulo 	u32 sc_ch = 0;
4105b9c547cSRui Paulo 	bool in_use = FALSE;
4115b9c547cSRui Paulo 
4125b9c547cSRui Paulo 	for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
4135b9c547cSRui Paulo 		ret = nss_macsec_secy_rx_sc_in_used_get(drv->secy_id, sc_ch,
4145b9c547cSRui Paulo 							&in_use);
4155b9c547cSRui Paulo 		if (ret)
4165b9c547cSRui Paulo 			continue;
4175b9c547cSRui Paulo 
4185b9c547cSRui Paulo 		if (!in_use) {
4195b9c547cSRui Paulo 			*channel = sc_ch;
4205b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "%s: channel=%d",
4215b9c547cSRui Paulo 				   __func__, *channel);
4225b9c547cSRui Paulo 			return 0;
4235b9c547cSRui Paulo 		}
4245b9c547cSRui Paulo 	}
4255b9c547cSRui Paulo 
4265b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "%s: no available channel", __func__);
4275b9c547cSRui Paulo 
4285b9c547cSRui Paulo 	return -1;
4295b9c547cSRui Paulo }
4305b9c547cSRui Paulo 
4315b9c547cSRui Paulo 
432*85732ac8SCy Schubert static int macsec_qca_create_receive_sc(void *priv, struct receive_sc *sc,
4335b9c547cSRui Paulo 					unsigned int conf_offset,
4345b9c547cSRui Paulo 					int validation)
4355b9c547cSRui Paulo {
4365b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
4375b9c547cSRui Paulo 	int ret = 0;
4385b9c547cSRui Paulo 	fal_rx_prc_lut_t entry;
4395b9c547cSRui Paulo 	fal_rx_sc_validate_frame_e vf;
4405b9c547cSRui Paulo 	enum validate_frames validate_frames = validation;
441*85732ac8SCy Schubert 	u32 channel;
442*85732ac8SCy Schubert 	const u8 *sci_addr = sc->sci.addr;
443*85732ac8SCy Schubert 	u16 sci_port = be_to_host16(sc->sci.port);
444*85732ac8SCy Schubert 
445*85732ac8SCy Schubert 	ret = macsec_qca_get_available_receive_sc(priv, &channel);
446*85732ac8SCy Schubert 	if (ret != 0)
447*85732ac8SCy Schubert 		return ret;
4485b9c547cSRui Paulo 
4495b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
4505b9c547cSRui Paulo 
4515b9c547cSRui Paulo 	/* rx prc lut */
4525b9c547cSRui Paulo 	os_memset(&entry, 0, sizeof(entry));
4535b9c547cSRui Paulo 
4545b9c547cSRui Paulo 	os_memcpy(entry.sci, sci_addr, ETH_ALEN);
455*85732ac8SCy Schubert 	entry.sci[6] = (sci_port >> 8) & 0xff;
456*85732ac8SCy Schubert 	entry.sci[7] = sci_port & 0xff;
4575b9c547cSRui Paulo 	entry.sci_mask = 0xf;
4585b9c547cSRui Paulo 
4595b9c547cSRui Paulo 	entry.valid = 1;
4605b9c547cSRui Paulo 	entry.channel = channel;
4615b9c547cSRui Paulo 	entry.action = FAL_RX_PRC_ACTION_PROCESS;
4625b9c547cSRui Paulo 	entry.offset = conf_offset;
4635b9c547cSRui Paulo 
4645b9c547cSRui Paulo 	/* rx validate frame  */
4655b9c547cSRui Paulo 	if (validate_frames == Strict)
4665b9c547cSRui Paulo 		vf = FAL_RX_SC_VALIDATE_FRAME_STRICT;
4675b9c547cSRui Paulo 	else if (validate_frames == Checked)
4685b9c547cSRui Paulo 		vf = FAL_RX_SC_VALIDATE_FRAME_CHECK;
4695b9c547cSRui Paulo 	else
4705b9c547cSRui Paulo 		vf = FAL_RX_SC_VALIDATE_FRAME_DISABLED;
4715b9c547cSRui Paulo 
4725b9c547cSRui Paulo 	ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
4735b9c547cSRui Paulo 	ret += nss_macsec_secy_rx_sc_create(drv->secy_id, channel);
4745b9c547cSRui Paulo 	ret += nss_macsec_secy_rx_sc_validate_frame_set(drv->secy_id, channel,
4755b9c547cSRui Paulo 							vf);
4765b9c547cSRui Paulo 	ret += nss_macsec_secy_rx_sc_replay_protect_set(drv->secy_id, channel,
4775b9c547cSRui Paulo 							drv->replay_protect);
4785b9c547cSRui Paulo 	ret += nss_macsec_secy_rx_sc_anti_replay_window_set(drv->secy_id,
4795b9c547cSRui Paulo 							    channel,
4805b9c547cSRui Paulo 							    drv->replay_window);
4815b9c547cSRui Paulo 
482*85732ac8SCy Schubert 	macsec_qca_register_receive_channel(drv, sc, channel);
483*85732ac8SCy Schubert 
4845b9c547cSRui Paulo 	return ret;
4855b9c547cSRui Paulo }
4865b9c547cSRui Paulo 
4875b9c547cSRui Paulo 
488*85732ac8SCy Schubert static int macsec_qca_delete_receive_sc(void *priv, struct receive_sc *sc)
4895b9c547cSRui Paulo {
4905b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
491*85732ac8SCy Schubert 	int ret;
4925b9c547cSRui Paulo 	fal_rx_prc_lut_t entry;
493*85732ac8SCy Schubert 	u32 channel;
494*85732ac8SCy Schubert 
495*85732ac8SCy Schubert 	ret = macsec_qca_lookup_receive_channel(priv, sc, &channel);
496*85732ac8SCy Schubert 	if (ret != 0)
497*85732ac8SCy Schubert 		return ret;
4985b9c547cSRui Paulo 
4995b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
5005b9c547cSRui Paulo 
5015b9c547cSRui Paulo 	/* rx prc lut */
5025b9c547cSRui Paulo 	os_memset(&entry, 0, sizeof(entry));
5035b9c547cSRui Paulo 
5045b9c547cSRui Paulo 	ret += nss_macsec_secy_rx_sc_del(drv->secy_id, channel);
5055b9c547cSRui Paulo 	ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
5065b9c547cSRui Paulo 
5075b9c547cSRui Paulo 	return ret;
5085b9c547cSRui Paulo }
5095b9c547cSRui Paulo 
5105b9c547cSRui Paulo 
511*85732ac8SCy Schubert static int macsec_qca_create_receive_sa(void *priv, struct receive_sa *sa)
5125b9c547cSRui Paulo {
5135b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
514*85732ac8SCy Schubert 	int ret;
5155b9c547cSRui Paulo 	fal_rx_sak_t rx_sak;
5165b9c547cSRui Paulo 	int i = 0;
517*85732ac8SCy Schubert 	u32 channel;
518*85732ac8SCy Schubert 	fal_rx_prc_lut_t entry;
519*85732ac8SCy Schubert 	u32 offset;
520*85732ac8SCy Schubert 
521*85732ac8SCy Schubert 	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
522*85732ac8SCy Schubert 	if (ret != 0)
523*85732ac8SCy Schubert 		return ret;
5245b9c547cSRui Paulo 
5255b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "%s, channel=%d, an=%d, lpn=0x%x",
526*85732ac8SCy Schubert 		   __func__, channel, sa->an, sa->lowest_pn);
5275b9c547cSRui Paulo 
5285b9c547cSRui Paulo 	os_memset(&rx_sak, 0, sizeof(rx_sak));
529*85732ac8SCy Schubert 	rx_sak.sak_len = sa->pkey->key_len;
530*85732ac8SCy Schubert 	if (sa->pkey->key_len == SAK_128_LEN) {
5315b9c547cSRui Paulo 		for (i = 0; i < 16; i++)
532*85732ac8SCy Schubert 			rx_sak.sak[i] = sa->pkey->key[15 - i];
533*85732ac8SCy Schubert 	} else if (sa->pkey->key_len == SAK_256_LEN) {
534*85732ac8SCy Schubert 		for (i = 0; i < 16; i++) {
535*85732ac8SCy Schubert 			rx_sak.sak1[i] = sa->pkey->key[15 - i];
536*85732ac8SCy Schubert 			rx_sak.sak[i] = sa->pkey->key[31 - i];
537*85732ac8SCy Schubert 		}
538*85732ac8SCy Schubert 	} else {
539*85732ac8SCy Schubert 		return -1;
540*85732ac8SCy Schubert 	}
5415b9c547cSRui Paulo 
542*85732ac8SCy Schubert 	if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0)
543*85732ac8SCy Schubert 		offset = 0;
544*85732ac8SCy Schubert 	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30)
545*85732ac8SCy Schubert 		offset = 30;
546*85732ac8SCy Schubert 	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50)
547*85732ac8SCy Schubert 		offset = 50;
548*85732ac8SCy Schubert 	else
549*85732ac8SCy Schubert 		return -1;
550*85732ac8SCy Schubert 	ret += nss_macsec_secy_rx_prc_lut_get(drv->secy_id, channel, &entry);
551*85732ac8SCy Schubert 	entry.offset = offset;
552*85732ac8SCy Schubert 	ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
553*85732ac8SCy Schubert 	ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, sa->an);
554*85732ac8SCy Schubert 	ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, sa->an,
555*85732ac8SCy Schubert 					  &rx_sak);
5565b9c547cSRui Paulo 
5575b9c547cSRui Paulo 	return ret;
5585b9c547cSRui Paulo }
5595b9c547cSRui Paulo 
5605b9c547cSRui Paulo 
561*85732ac8SCy Schubert static int macsec_qca_enable_receive_sa(void *priv, struct receive_sa *sa)
5625b9c547cSRui Paulo {
5635b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
564*85732ac8SCy Schubert 	int ret;
565*85732ac8SCy Schubert 	u32 channel;
5665b9c547cSRui Paulo 
567*85732ac8SCy Schubert 	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
568*85732ac8SCy Schubert 	if (ret != 0)
569*85732ac8SCy Schubert 		return ret;
5705b9c547cSRui Paulo 
571*85732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
572*85732ac8SCy Schubert 		   sa->an);
573*85732ac8SCy Schubert 
574*85732ac8SCy Schubert 	ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
575*85732ac8SCy Schubert 					    TRUE);
5765b9c547cSRui Paulo 
5775b9c547cSRui Paulo 	return ret;
5785b9c547cSRui Paulo }
5795b9c547cSRui Paulo 
5805b9c547cSRui Paulo 
581*85732ac8SCy Schubert static int macsec_qca_disable_receive_sa(void *priv, struct receive_sa *sa)
5825b9c547cSRui Paulo {
5835b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
584*85732ac8SCy Schubert 	int ret;
585*85732ac8SCy Schubert 	u32 channel;
5865b9c547cSRui Paulo 
587*85732ac8SCy Schubert 	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
588*85732ac8SCy Schubert 	if (ret != 0)
589*85732ac8SCy Schubert 		return ret;
5905b9c547cSRui Paulo 
591*85732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
592*85732ac8SCy Schubert 		   sa->an);
593*85732ac8SCy Schubert 
594*85732ac8SCy Schubert 	ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
595*85732ac8SCy Schubert 					    FALSE);
5965b9c547cSRui Paulo 
5975b9c547cSRui Paulo 	return ret;
5985b9c547cSRui Paulo }
5995b9c547cSRui Paulo 
6005b9c547cSRui Paulo 
6015b9c547cSRui Paulo static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel)
6025b9c547cSRui Paulo {
6035b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
6045b9c547cSRui Paulo 	u32 sc_ch = 0;
6055b9c547cSRui Paulo 	bool in_use = FALSE;
6065b9c547cSRui Paulo 
6075b9c547cSRui Paulo 	for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
608*85732ac8SCy Schubert 		if (nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch,
609*85732ac8SCy Schubert 						      &in_use))
6105b9c547cSRui Paulo 			continue;
6115b9c547cSRui Paulo 
6125b9c547cSRui Paulo 		if (!in_use) {
6135b9c547cSRui Paulo 			*channel = sc_ch;
6145b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "%s: channel=%d",
6155b9c547cSRui Paulo 				   __func__, *channel);
6165b9c547cSRui Paulo 			return 0;
6175b9c547cSRui Paulo 		}
6185b9c547cSRui Paulo 	}
6195b9c547cSRui Paulo 
6205b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "%s: no avaiable channel", __func__);
6215b9c547cSRui Paulo 
6225b9c547cSRui Paulo 	return -1;
6235b9c547cSRui Paulo }
6245b9c547cSRui Paulo 
6255b9c547cSRui Paulo 
626*85732ac8SCy Schubert static int macsec_qca_create_transmit_sc(void *priv, struct transmit_sc *sc,
6275b9c547cSRui Paulo 					 unsigned int conf_offset)
6285b9c547cSRui Paulo {
6295b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
630*85732ac8SCy Schubert 	int ret;
6315b9c547cSRui Paulo 	fal_tx_class_lut_t entry;
6325b9c547cSRui Paulo 	u8 psci[ETH_ALEN + 2];
633*85732ac8SCy Schubert 	u32 channel;
634*85732ac8SCy Schubert 	u16 sci_port = be_to_host16(sc->sci.port);
635*85732ac8SCy Schubert 
636*85732ac8SCy Schubert 	ret = macsec_qca_get_available_transmit_sc(priv, &channel);
637*85732ac8SCy Schubert 	if (ret != 0)
638*85732ac8SCy Schubert 		return ret;
6395b9c547cSRui Paulo 
6405b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
6415b9c547cSRui Paulo 
6425b9c547cSRui Paulo 	/* class lut */
6435b9c547cSRui Paulo 	os_memset(&entry, 0, sizeof(entry));
6445b9c547cSRui Paulo 
6455b9c547cSRui Paulo 	entry.valid = 1;
6465b9c547cSRui Paulo 	entry.action = FAL_TX_CLASS_ACTION_FORWARD;
6475b9c547cSRui Paulo 	entry.channel = channel;
6485b9c547cSRui Paulo 
649*85732ac8SCy Schubert 	os_memcpy(psci, sc->sci.addr, ETH_ALEN);
650*85732ac8SCy Schubert 	psci[6] = (sci_port >> 8) & 0xff;
651*85732ac8SCy Schubert 	psci[7] = sci_port & 0xff;
6525b9c547cSRui Paulo 
6535b9c547cSRui Paulo 	ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
6545b9c547cSRui Paulo 	ret += nss_macsec_secy_tx_sc_create(drv->secy_id, channel, psci, 8);
6555b9c547cSRui Paulo 	ret += nss_macsec_secy_tx_sc_protect_set(drv->secy_id, channel,
6565b9c547cSRui Paulo 						 drv->protect_frames);
6575b9c547cSRui Paulo 	ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
6585b9c547cSRui Paulo 								channel,
6595b9c547cSRui Paulo 								conf_offset);
6605b9c547cSRui Paulo 
661*85732ac8SCy Schubert 	macsec_qca_register_transmit_channel(drv, sc, channel);
662*85732ac8SCy Schubert 
6635b9c547cSRui Paulo 	return ret;
6645b9c547cSRui Paulo }
6655b9c547cSRui Paulo 
6665b9c547cSRui Paulo 
667*85732ac8SCy Schubert static int macsec_qca_delete_transmit_sc(void *priv, struct transmit_sc *sc)
6685b9c547cSRui Paulo {
6695b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
670*85732ac8SCy Schubert 	int ret;
6715b9c547cSRui Paulo 	fal_tx_class_lut_t entry;
672*85732ac8SCy Schubert 	u32 channel;
673*85732ac8SCy Schubert 
674*85732ac8SCy Schubert 	ret = macsec_qca_lookup_transmit_channel(priv, sc, &channel);
675*85732ac8SCy Schubert 	if (ret != 0)
676*85732ac8SCy Schubert 		return ret;
6775b9c547cSRui Paulo 
6785b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
6795b9c547cSRui Paulo 
6805b9c547cSRui Paulo 	/* class lut */
6815b9c547cSRui Paulo 	os_memset(&entry, 0, sizeof(entry));
6825b9c547cSRui Paulo 
6835b9c547cSRui Paulo 	ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
6845b9c547cSRui Paulo 	ret += nss_macsec_secy_tx_sc_del(drv->secy_id, channel);
6855b9c547cSRui Paulo 
6865b9c547cSRui Paulo 	return ret;
6875b9c547cSRui Paulo }
6885b9c547cSRui Paulo 
6895b9c547cSRui Paulo 
690*85732ac8SCy Schubert static int macsec_qca_create_transmit_sa(void *priv, struct transmit_sa *sa)
6915b9c547cSRui Paulo {
6925b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
693*85732ac8SCy Schubert 	int ret;
6945b9c547cSRui Paulo 	u8 tci = 0;
6955b9c547cSRui Paulo 	fal_tx_sak_t tx_sak;
6965b9c547cSRui Paulo 	int i;
697*85732ac8SCy Schubert 	u32 channel;
698*85732ac8SCy Schubert 	u32 offset;
699*85732ac8SCy Schubert 
700*85732ac8SCy Schubert 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
701*85732ac8SCy Schubert 	if (ret != 0)
702*85732ac8SCy Schubert 		return ret;
7035b9c547cSRui Paulo 
7045b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG,
7055b9c547cSRui Paulo 		   "%s: channel=%d, an=%d, next_pn=0x%x, confidentiality=%d",
706*85732ac8SCy Schubert 		   __func__, channel, sa->an, sa->next_pn, sa->confidentiality);
7075b9c547cSRui Paulo 
7085b9c547cSRui Paulo 	if (drv->always_include_sci)
7095b9c547cSRui Paulo 		tci |= TCI_SC;
7105b9c547cSRui Paulo 	else if (drv->use_es)
7115b9c547cSRui Paulo 		tci |= TCI_ES;
7125b9c547cSRui Paulo 	else if (drv->use_scb)
7135b9c547cSRui Paulo 		tci |= TCI_SCB;
7145b9c547cSRui Paulo 
715*85732ac8SCy Schubert 	if (sa->confidentiality)
7165b9c547cSRui Paulo 		tci |= TCI_E | TCI_C;
7175b9c547cSRui Paulo 
7185b9c547cSRui Paulo 	os_memset(&tx_sak, 0, sizeof(tx_sak));
719*85732ac8SCy Schubert 	tx_sak.sak_len = sa->pkey->key_len;
720*85732ac8SCy Schubert 	if (sa->pkey->key_len == SAK_128_LEN) {
7215b9c547cSRui Paulo 		for (i = 0; i < 16; i++)
722*85732ac8SCy Schubert 			tx_sak.sak[i] = sa->pkey->key[15 - i];
723*85732ac8SCy Schubert 	} else if (sa->pkey->key_len == SAK_256_LEN) {
724*85732ac8SCy Schubert 		for (i = 0; i < 16; i++) {
725*85732ac8SCy Schubert 			tx_sak.sak1[i] = sa->pkey->key[15 - i];
726*85732ac8SCy Schubert 			tx_sak.sak[i] = sa->pkey->key[31 - i];
727*85732ac8SCy Schubert 		}
728*85732ac8SCy Schubert 	} else {
729*85732ac8SCy Schubert 		return -1;
730*85732ac8SCy Schubert 	}
7315b9c547cSRui Paulo 
732*85732ac8SCy Schubert 	if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0)
733*85732ac8SCy Schubert 		offset = 0;
734*85732ac8SCy Schubert 	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30)
735*85732ac8SCy Schubert 		offset = 30;
736*85732ac8SCy Schubert 	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50)
737*85732ac8SCy Schubert 		offset = 50;
738*85732ac8SCy Schubert 	else
739*85732ac8SCy Schubert 		return -1;
740*85732ac8SCy Schubert 	ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
741*85732ac8SCy Schubert 								channel,
742*85732ac8SCy Schubert 								offset);
743*85732ac8SCy Schubert 	ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
744*85732ac8SCy Schubert 						 sa->next_pn);
745*85732ac8SCy Schubert 	ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, sa->an,
746*85732ac8SCy Schubert 					  &tx_sak);
7475b9c547cSRui Paulo 	ret += nss_macsec_secy_tx_sc_tci_7_2_set(drv->secy_id, channel,
7485b9c547cSRui Paulo 						 (tci >> 2));
749*85732ac8SCy Schubert 	ret += nss_macsec_secy_tx_sc_an_set(drv->secy_id, channel, sa->an);
7505b9c547cSRui Paulo 
7515b9c547cSRui Paulo 	return ret;
7525b9c547cSRui Paulo }
7535b9c547cSRui Paulo 
7545b9c547cSRui Paulo 
755*85732ac8SCy Schubert static int macsec_qca_enable_transmit_sa(void *priv, struct transmit_sa *sa)
7565b9c547cSRui Paulo {
7575b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
758*85732ac8SCy Schubert 	int ret;
759*85732ac8SCy Schubert 	u32 channel;
7605b9c547cSRui Paulo 
761*85732ac8SCy Schubert 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
762*85732ac8SCy Schubert 	if (ret != 0)
763*85732ac8SCy Schubert 		return ret;
7645b9c547cSRui Paulo 
765*85732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
766*85732ac8SCy Schubert 		   sa->an);
767*85732ac8SCy Schubert 
768*85732ac8SCy Schubert 	ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
769*85732ac8SCy Schubert 					    TRUE);
7705b9c547cSRui Paulo 
7715b9c547cSRui Paulo 	return ret;
7725b9c547cSRui Paulo }
7735b9c547cSRui Paulo 
7745b9c547cSRui Paulo 
775*85732ac8SCy Schubert static int macsec_qca_disable_transmit_sa(void *priv, struct transmit_sa *sa)
7765b9c547cSRui Paulo {
7775b9c547cSRui Paulo 	struct macsec_qca_data *drv = priv;
778*85732ac8SCy Schubert 	int ret;
779*85732ac8SCy Schubert 	u32 channel;
7805b9c547cSRui Paulo 
781*85732ac8SCy Schubert 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
782*85732ac8SCy Schubert 	if (ret != 0)
783*85732ac8SCy Schubert 		return ret;
7845b9c547cSRui Paulo 
785*85732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
786*85732ac8SCy Schubert 		   sa->an);
787*85732ac8SCy Schubert 
788*85732ac8SCy Schubert 	ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
789*85732ac8SCy Schubert 					    FALSE);
7905b9c547cSRui Paulo 
7915b9c547cSRui Paulo 	return ret;
7925b9c547cSRui Paulo }
7935b9c547cSRui Paulo 
7945b9c547cSRui Paulo 
7955b9c547cSRui Paulo const struct wpa_driver_ops wpa_driver_macsec_qca_ops = {
7965b9c547cSRui Paulo 	.name = "macsec_qca",
7975b9c547cSRui Paulo 	.desc = "QCA MACsec Ethernet driver",
798*85732ac8SCy Schubert 	.get_ssid = driver_wired_get_ssid,
799*85732ac8SCy Schubert 	.get_bssid = driver_wired_get_bssid,
800*85732ac8SCy Schubert 	.get_capa = driver_wired_get_capa,
8015b9c547cSRui Paulo 	.init = macsec_qca_init,
8025b9c547cSRui Paulo 	.deinit = macsec_qca_deinit,
8035b9c547cSRui Paulo 
8045b9c547cSRui Paulo 	.macsec_init = macsec_qca_macsec_init,
8055b9c547cSRui Paulo 	.macsec_deinit = macsec_qca_macsec_deinit,
806*85732ac8SCy Schubert 	.macsec_get_capability = macsec_qca_get_capability,
8075b9c547cSRui Paulo 	.enable_protect_frames = macsec_qca_enable_protect_frames,
8085b9c547cSRui Paulo 	.set_replay_protect = macsec_qca_set_replay_protect,
8095b9c547cSRui Paulo 	.set_current_cipher_suite = macsec_qca_set_current_cipher_suite,
8105b9c547cSRui Paulo 	.enable_controlled_port = macsec_qca_enable_controlled_port,
8115b9c547cSRui Paulo 	.get_receive_lowest_pn = macsec_qca_get_receive_lowest_pn,
8125b9c547cSRui Paulo 	.get_transmit_next_pn = macsec_qca_get_transmit_next_pn,
8135b9c547cSRui Paulo 	.set_transmit_next_pn = macsec_qca_set_transmit_next_pn,
8145b9c547cSRui Paulo 	.create_receive_sc = macsec_qca_create_receive_sc,
8155b9c547cSRui Paulo 	.delete_receive_sc = macsec_qca_delete_receive_sc,
8165b9c547cSRui Paulo 	.create_receive_sa = macsec_qca_create_receive_sa,
8175b9c547cSRui Paulo 	.enable_receive_sa = macsec_qca_enable_receive_sa,
8185b9c547cSRui Paulo 	.disable_receive_sa = macsec_qca_disable_receive_sa,
8195b9c547cSRui Paulo 	.create_transmit_sc = macsec_qca_create_transmit_sc,
8205b9c547cSRui Paulo 	.delete_transmit_sc = macsec_qca_delete_transmit_sc,
8215b9c547cSRui Paulo 	.create_transmit_sa = macsec_qca_create_transmit_sa,
8225b9c547cSRui Paulo 	.enable_transmit_sa = macsec_qca_enable_transmit_sa,
8235b9c547cSRui Paulo 	.disable_transmit_sa = macsec_qca_disable_transmit_sa,
8245b9c547cSRui Paulo };
825