Home | History | Annotate | Download | only in drivers
      1 /*
      2  * Wired Ethernet driver interface for QCA MACsec driver
      3  * Copyright (c) 2005-2009, Jouni Malinen <j (at) w1.fi>
      4  * Copyright (c) 2004, Gunter Burchardt <tira (at) isx.de>
      5  * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
      6  *
      7  * This software may be distributed under the terms of the BSD license.
      8  * See README for more details.
      9  */
     10 
     11 #include "includes.h"
     12 #include <sys/ioctl.h>
     13 #include <net/if.h>
     14 #include <inttypes.h>
     15 #ifdef __linux__
     16 #include <netpacket/packet.h>
     17 #include <net/if_arp.h>
     18 #include <net/if.h>
     19 #endif /* __linux__ */
     20 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
     21 #include <net/if_dl.h>
     22 #include <net/if_media.h>
     23 #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
     24 #ifdef __sun__
     25 #include <sys/sockio.h>
     26 #endif /* __sun__ */
     27 
     28 #include "utils/common.h"
     29 #include "utils/eloop.h"
     30 #include "common/defs.h"
     31 #include "common/ieee802_1x_defs.h"
     32 #include "pae/ieee802_1x_kay.h"
     33 #include "driver.h"
     34 #include "driver_wired_common.h"
     35 
     36 #include "nss_macsec_secy.h"
     37 #include "nss_macsec_secy_rx.h"
     38 #include "nss_macsec_secy_tx.h"
     39 
     40 #define MAXSC 16
     41 
     42 /* TCI field definition */
     43 #define TCI_ES                0x40
     44 #define TCI_SC                0x20
     45 #define TCI_SCB               0x10
     46 #define TCI_E                 0x08
     47 #define TCI_C                 0x04
     48 
     49 #ifdef _MSC_VER
     50 #pragma pack(push, 1)
     51 #endif /* _MSC_VER */
     52 
     53 #ifdef _MSC_VER
     54 #pragma pack(pop)
     55 #endif /* _MSC_VER */
     56 
     57 struct channel_map {
     58 	struct ieee802_1x_mka_sci sci;
     59 };
     60 
     61 struct macsec_qca_data {
     62 	struct driver_wired_common_data common;
     63 
     64 	u32 secy_id;
     65 
     66 	/* shadow */
     67 	Boolean always_include_sci;
     68 	Boolean use_es;
     69 	Boolean use_scb;
     70 	Boolean protect_frames;
     71 	Boolean replay_protect;
     72 	u32 replay_window;
     73 
     74 	struct channel_map receive_channel_map[MAXSC];
     75 	struct channel_map transmit_channel_map[MAXSC];
     76 };
     77 
     78 
     79 static void __macsec_drv_init(struct macsec_qca_data *drv)
     80 {
     81 	int ret = 0;
     82 	fal_rx_ctl_filt_t rx_ctl_filt;
     83 	fal_tx_ctl_filt_t tx_ctl_filt;
     84 
     85 	wpa_printf(MSG_INFO, "%s: secy_id=%d", __func__, drv->secy_id);
     86 
     87 	/* Enable Secy and Let EAPoL bypass */
     88 	ret = nss_macsec_secy_en_set(drv->secy_id, TRUE);
     89 	if (ret)
     90 		wpa_printf(MSG_ERROR, "nss_macsec_secy_en_set: FAIL");
     91 
     92 	ret = nss_macsec_secy_sc_sa_mapping_mode_set(drv->secy_id,
     93 						     FAL_SC_SA_MAP_1_4);
     94 	if (ret)
     95 		wpa_printf(MSG_ERROR,
     96 			   "nss_macsec_secy_sc_sa_mapping_mode_set: FAIL");
     97 
     98 	os_memset(&rx_ctl_filt, 0, sizeof(rx_ctl_filt));
     99 	rx_ctl_filt.bypass = 1;
    100 	rx_ctl_filt.match_type = IG_CTL_COMPARE_ETHER_TYPE;
    101 	rx_ctl_filt.match_mask = 0xffff;
    102 	rx_ctl_filt.ether_type_da_range = 0x888e;
    103 	ret = nss_macsec_secy_rx_ctl_filt_set(drv->secy_id, 0, &rx_ctl_filt);
    104 	if (ret)
    105 		wpa_printf(MSG_ERROR, "nss_macsec_secy_rx_ctl_filt_set: FAIL");
    106 
    107 	os_memset(&tx_ctl_filt, 0, sizeof(tx_ctl_filt));
    108 	tx_ctl_filt.bypass = 1;
    109 	tx_ctl_filt.match_type = EG_CTL_COMPARE_ETHER_TYPE;
    110 	tx_ctl_filt.match_mask = 0xffff;
    111 	tx_ctl_filt.ether_type_da_range = 0x888e;
    112 	ret = nss_macsec_secy_tx_ctl_filt_set(drv->secy_id, 0, &tx_ctl_filt);
    113 	if (ret)
    114 		wpa_printf(MSG_ERROR, "nss_macsec_secy_tx_ctl_filt_set: FAIL");
    115 }
    116 
    117 
    118 static void __macsec_drv_deinit(struct macsec_qca_data *drv)
    119 {
    120 	nss_macsec_secy_en_set(drv->secy_id, FALSE);
    121 	nss_macsec_secy_rx_sc_del_all(drv->secy_id);
    122 	nss_macsec_secy_tx_sc_del_all(drv->secy_id);
    123 }
    124 
    125 
    126 static void * macsec_qca_init(void *ctx, const char *ifname)
    127 {
    128 	struct macsec_qca_data *drv;
    129 
    130 	drv = os_zalloc(sizeof(*drv));
    131 	if (drv == NULL)
    132 		return NULL;
    133 
    134 	/* Board specific settings */
    135 	if (os_memcmp("eth2", ifname, 4) == 0)
    136 		drv->secy_id = 1;
    137 	else if (os_memcmp("eth3", ifname, 4) == 0)
    138 		drv->secy_id = 2;
    139 	else
    140 		drv->secy_id = -1;
    141 
    142 	if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
    143 		os_free(drv);
    144 		return NULL;
    145 	}
    146 
    147 	return drv;
    148 }
    149 
    150 
    151 static void macsec_qca_deinit(void *priv)
    152 {
    153 	struct macsec_qca_data *drv = priv;
    154 
    155 	driver_wired_deinit_common(&drv->common);
    156 	os_free(drv);
    157 }
    158 
    159 
    160 static int macsec_qca_macsec_init(void *priv, struct macsec_init_params *params)
    161 {
    162 	struct macsec_qca_data *drv = priv;
    163 
    164 	drv->always_include_sci = params->always_include_sci;
    165 	drv->use_es = params->use_es;
    166 	drv->use_scb = params->use_scb;
    167 
    168 	wpa_printf(MSG_DEBUG, "%s: es=%d, scb=%d, sci=%d",
    169 		   __func__, drv->use_es, drv->use_scb,
    170 		   drv->always_include_sci);
    171 
    172 	__macsec_drv_init(drv);
    173 
    174 	return 0;
    175 }
    176 
    177 
    178 static int macsec_qca_macsec_deinit(void *priv)
    179 {
    180 	struct macsec_qca_data *drv = priv;
    181 
    182 	wpa_printf(MSG_DEBUG, "%s", __func__);
    183 
    184 	__macsec_drv_deinit(drv);
    185 
    186 	return 0;
    187 }
    188 
    189 
    190 static int macsec_qca_get_capability(void *priv, enum macsec_cap *cap)
    191 {
    192 	wpa_printf(MSG_DEBUG, "%s", __func__);
    193 
    194 	*cap = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
    195 
    196 	return 0;
    197 }
    198 
    199 
    200 static int macsec_qca_enable_protect_frames(void *priv, Boolean enabled)
    201 {
    202 	struct macsec_qca_data *drv = priv;
    203 	int ret = 0;
    204 
    205 	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
    206 
    207 	drv->protect_frames = enabled;
    208 
    209 	return ret;
    210 }
    211 
    212 
    213 static int macsec_qca_set_replay_protect(void *priv, Boolean enabled,
    214 					 unsigned int window)
    215 {
    216 	struct macsec_qca_data *drv = priv;
    217 	int ret = 0;
    218 
    219 	wpa_printf(MSG_DEBUG, "%s: enabled=%d, win=%u",
    220 		   __func__, enabled, window);
    221 
    222 	drv->replay_protect = enabled;
    223 	drv->replay_window = window;
    224 
    225 	return ret;
    226 }
    227 
    228 
    229 static int macsec_qca_set_current_cipher_suite(void *priv, u64 cs)
    230 {
    231 	if (cs != CS_ID_GCM_AES_128) {
    232 		wpa_printf(MSG_ERROR,
    233 			   "%s: NOT supported CipherSuite: %016" PRIx64,
    234 			   __func__, cs);
    235 		return -1;
    236 	}
    237 
    238 	/* Support default Cipher Suite 0080020001000001 (GCM-AES-128) */
    239 	wpa_printf(MSG_DEBUG, "%s: default support aes-gcm-128", __func__);
    240 
    241 	return 0;
    242 }
    243 
    244 
    245 static int macsec_qca_enable_controlled_port(void *priv, Boolean enabled)
    246 {
    247 	struct macsec_qca_data *drv = priv;
    248 	int ret = 0;
    249 
    250 	wpa_printf(MSG_DEBUG, "%s: enable=%d", __func__, enabled);
    251 
    252 	ret += nss_macsec_secy_controlled_port_en_set(drv->secy_id, enabled);
    253 
    254 	return ret;
    255 }
    256 
    257 
    258 static int macsec_qca_lookup_channel(struct channel_map *map,
    259 				     struct ieee802_1x_mka_sci *sci,
    260 				     u32 *channel)
    261 {
    262 	u32 i;
    263 
    264 	for (i = 0; i < MAXSC; i++) {
    265 		if (os_memcmp(&map[i].sci, sci,
    266 			      sizeof(struct ieee802_1x_mka_sci)) == 0) {
    267 			*channel = i;
    268 			return 0;
    269 		}
    270 	}
    271 
    272 	return -1;
    273 }
    274 
    275 
    276 static void macsec_qca_register_channel(struct channel_map *map,
    277 					struct ieee802_1x_mka_sci *sci,
    278 					u32 channel)
    279 {
    280 	os_memcpy(&map[channel].sci, sci, sizeof(struct ieee802_1x_mka_sci));
    281 }
    282 
    283 
    284 static int macsec_qca_lookup_receive_channel(struct macsec_qca_data *drv,
    285 					     struct receive_sc *sc,
    286 					     u32 *channel)
    287 {
    288 	return macsec_qca_lookup_channel(drv->receive_channel_map, &sc->sci,
    289 					 channel);
    290 }
    291 
    292 
    293 static void macsec_qca_register_receive_channel(struct macsec_qca_data *drv,
    294 						struct receive_sc *sc,
    295 						u32 channel)
    296 {
    297 	macsec_qca_register_channel(drv->receive_channel_map, &sc->sci,
    298 				    channel);
    299 }
    300 
    301 
    302 static int macsec_qca_lookup_transmit_channel(struct macsec_qca_data *drv,
    303 					      struct transmit_sc *sc,
    304 					      u32 *channel)
    305 {
    306 	return macsec_qca_lookup_channel(drv->transmit_channel_map, &sc->sci,
    307 					 channel);
    308 }
    309 
    310 
    311 static void macsec_qca_register_transmit_channel(struct macsec_qca_data *drv,
    312 						 struct transmit_sc *sc,
    313 						 u32 channel)
    314 {
    315 	macsec_qca_register_channel(drv->transmit_channel_map, &sc->sci,
    316 				    channel);
    317 }
    318 
    319 
    320 static int macsec_qca_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
    321 {
    322 	struct macsec_qca_data *drv = priv;
    323 	int ret = 0;
    324 	u32 next_pn = 0;
    325 	bool enabled = FALSE;
    326 	u32 win;
    327 	u32 channel;
    328 
    329 	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
    330 	if (ret != 0)
    331 		return ret;
    332 
    333 	ret += nss_macsec_secy_rx_sa_next_pn_get(drv->secy_id, channel, sa->an,
    334 						 &next_pn);
    335 	ret += nss_macsec_secy_rx_sc_replay_protect_get(drv->secy_id, channel,
    336 							&enabled);
    337 	ret += nss_macsec_secy_rx_sc_anti_replay_window_get(drv->secy_id,
    338 							    channel, &win);
    339 
    340 	if (enabled)
    341 		sa->lowest_pn = (next_pn > win) ? (next_pn - win) : 1;
    342 	else
    343 		sa->lowest_pn = next_pn;
    344 
    345 	wpa_printf(MSG_DEBUG, "%s: lpn=0x%x", __func__, sa->lowest_pn);
    346 
    347 	return ret;
    348 }
    349 
    350 
    351 static int macsec_qca_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
    352 {
    353 	struct macsec_qca_data *drv = priv;
    354 	int ret = 0;
    355 	u32 channel;
    356 
    357 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
    358 	if (ret != 0)
    359 		return ret;
    360 
    361 	ret += nss_macsec_secy_tx_sa_next_pn_get(drv->secy_id, channel, sa->an,
    362 						 &sa->next_pn);
    363 
    364 	wpa_printf(MSG_DEBUG, "%s: npn=0x%x", __func__, sa->next_pn);
    365 
    366 	return ret;
    367 }
    368 
    369 
    370 int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
    371 {
    372 	struct macsec_qca_data *drv = priv;
    373 	int ret = 0;
    374 	u32 channel;
    375 
    376 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
    377 	if (ret != 0)
    378 		return ret;
    379 
    380 	ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
    381 						 sa->next_pn);
    382 
    383 	wpa_printf(MSG_INFO, "%s: npn=0x%x", __func__, sa->next_pn);
    384 
    385 	return ret;
    386 }
    387 
    388 
    389 static int macsec_qca_get_available_receive_sc(void *priv, u32 *channel)
    390 {
    391 	struct macsec_qca_data *drv = priv;
    392 	int ret = 0;
    393 	u32 sc_ch = 0;
    394 	bool in_use = FALSE;
    395 
    396 	for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
    397 		ret = nss_macsec_secy_rx_sc_in_used_get(drv->secy_id, sc_ch,
    398 							&in_use);
    399 		if (ret)
    400 			continue;
    401 
    402 		if (!in_use) {
    403 			*channel = sc_ch;
    404 			wpa_printf(MSG_DEBUG, "%s: channel=%d",
    405 				   __func__, *channel);
    406 			return 0;
    407 		}
    408 	}
    409 
    410 	wpa_printf(MSG_DEBUG, "%s: no available channel", __func__);
    411 
    412 	return -1;
    413 }
    414 
    415 
    416 static int macsec_qca_create_receive_sc(void *priv, struct receive_sc *sc,
    417 					unsigned int conf_offset,
    418 					int validation)
    419 {
    420 	struct macsec_qca_data *drv = priv;
    421 	int ret = 0;
    422 	fal_rx_prc_lut_t entry;
    423 	fal_rx_sc_validate_frame_e vf;
    424 	enum validate_frames validate_frames = validation;
    425 	u32 channel;
    426 	const u8 *sci_addr = sc->sci.addr;
    427 	u16 sci_port = be_to_host16(sc->sci.port);
    428 
    429 	ret = macsec_qca_get_available_receive_sc(priv, &channel);
    430 	if (ret != 0)
    431 		return ret;
    432 
    433 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
    434 
    435 	/* rx prc lut */
    436 	os_memset(&entry, 0, sizeof(entry));
    437 
    438 	os_memcpy(entry.sci, sci_addr, ETH_ALEN);
    439 	entry.sci[6] = (sci_port >> 8) & 0xf;
    440 	entry.sci[7] = sci_port & 0xf;
    441 	entry.sci_mask = 0xf;
    442 
    443 	entry.valid = 1;
    444 	entry.channel = channel;
    445 	entry.action = FAL_RX_PRC_ACTION_PROCESS;
    446 	entry.offset = conf_offset;
    447 
    448 	/* rx validate frame  */
    449 	if (validate_frames == Strict)
    450 		vf = FAL_RX_SC_VALIDATE_FRAME_STRICT;
    451 	else if (validate_frames == Checked)
    452 		vf = FAL_RX_SC_VALIDATE_FRAME_CHECK;
    453 	else
    454 		vf = FAL_RX_SC_VALIDATE_FRAME_DISABLED;
    455 
    456 	ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
    457 	ret += nss_macsec_secy_rx_sc_create(drv->secy_id, channel);
    458 	ret += nss_macsec_secy_rx_sc_validate_frame_set(drv->secy_id, channel,
    459 							vf);
    460 	ret += nss_macsec_secy_rx_sc_replay_protect_set(drv->secy_id, channel,
    461 							drv->replay_protect);
    462 	ret += nss_macsec_secy_rx_sc_anti_replay_window_set(drv->secy_id,
    463 							    channel,
    464 							    drv->replay_window);
    465 
    466 	macsec_qca_register_receive_channel(drv, sc, channel);
    467 
    468 	return ret;
    469 }
    470 
    471 
    472 static int macsec_qca_delete_receive_sc(void *priv, struct receive_sc *sc)
    473 {
    474 	struct macsec_qca_data *drv = priv;
    475 	int ret;
    476 	fal_rx_prc_lut_t entry;
    477 	u32 channel;
    478 
    479 	ret = macsec_qca_lookup_receive_channel(priv, sc, &channel);
    480 	if (ret != 0)
    481 		return ret;
    482 
    483 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
    484 
    485 	/* rx prc lut */
    486 	os_memset(&entry, 0, sizeof(entry));
    487 
    488 	ret += nss_macsec_secy_rx_sc_del(drv->secy_id, channel);
    489 	ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
    490 
    491 	return ret;
    492 }
    493 
    494 
    495 static int macsec_qca_create_receive_sa(void *priv, struct receive_sa *sa)
    496 {
    497 	struct macsec_qca_data *drv = priv;
    498 	int ret;
    499 	fal_rx_sak_t rx_sak;
    500 	int i = 0;
    501 	u32 channel;
    502 
    503 	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
    504 	if (ret != 0)
    505 		return ret;
    506 
    507 	wpa_printf(MSG_DEBUG, "%s, channel=%d, an=%d, lpn=0x%x",
    508 		   __func__, channel, sa->an, sa->lowest_pn);
    509 
    510 	os_memset(&rx_sak, 0, sizeof(rx_sak));
    511 	for (i = 0; i < 16; i++)
    512 		rx_sak.sak[i] = sa->pkey->key[15 - i];
    513 
    514 	ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, sa->an);
    515 	ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, sa->an,
    516 					  &rx_sak);
    517 
    518 	return ret;
    519 }
    520 
    521 
    522 static int macsec_qca_enable_receive_sa(void *priv, struct receive_sa *sa)
    523 {
    524 	struct macsec_qca_data *drv = priv;
    525 	int ret;
    526 	u32 channel;
    527 
    528 	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
    529 	if (ret != 0)
    530 		return ret;
    531 
    532 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
    533 		   sa->an);
    534 
    535 	ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
    536 					    TRUE);
    537 
    538 	return ret;
    539 }
    540 
    541 
    542 static int macsec_qca_disable_receive_sa(void *priv, struct receive_sa *sa)
    543 {
    544 	struct macsec_qca_data *drv = priv;
    545 	int ret;
    546 	u32 channel;
    547 
    548 	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
    549 	if (ret != 0)
    550 		return ret;
    551 
    552 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
    553 		   sa->an);
    554 
    555 	ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
    556 					    FALSE);
    557 
    558 	return ret;
    559 }
    560 
    561 
    562 static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel)
    563 {
    564 	struct macsec_qca_data *drv = priv;
    565 	u32 sc_ch = 0;
    566 	bool in_use = FALSE;
    567 
    568 	for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
    569 		if (nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch,
    570 						      &in_use))
    571 			continue;
    572 
    573 		if (!in_use) {
    574 			*channel = sc_ch;
    575 			wpa_printf(MSG_DEBUG, "%s: channel=%d",
    576 				   __func__, *channel);
    577 			return 0;
    578 		}
    579 	}
    580 
    581 	wpa_printf(MSG_DEBUG, "%s: no avaiable channel", __func__);
    582 
    583 	return -1;
    584 }
    585 
    586 
    587 static int macsec_qca_create_transmit_sc(void *priv, struct transmit_sc *sc,
    588 					 unsigned int conf_offset)
    589 {
    590 	struct macsec_qca_data *drv = priv;
    591 	int ret;
    592 	fal_tx_class_lut_t entry;
    593 	u8 psci[ETH_ALEN + 2];
    594 	u32 channel;
    595 
    596 	ret = macsec_qca_get_available_transmit_sc(priv, &channel);
    597 	if (ret != 0)
    598 		return ret;
    599 
    600 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
    601 
    602 	/* class lut */
    603 	os_memset(&entry, 0, sizeof(entry));
    604 
    605 	entry.valid = 1;
    606 	entry.action = FAL_TX_CLASS_ACTION_FORWARD;
    607 	entry.channel = channel;
    608 
    609 	os_memcpy(psci, sc->sci.addr, ETH_ALEN);
    610 	psci[6] = (sc->sci.port >> 8) & 0xf;
    611 	psci[7] = sc->sci.port & 0xf;
    612 
    613 	ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
    614 	ret += nss_macsec_secy_tx_sc_create(drv->secy_id, channel, psci, 8);
    615 	ret += nss_macsec_secy_tx_sc_protect_set(drv->secy_id, channel,
    616 						 drv->protect_frames);
    617 	ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
    618 								channel,
    619 								conf_offset);
    620 
    621 	macsec_qca_register_transmit_channel(drv, sc, channel);
    622 
    623 	return ret;
    624 }
    625 
    626 
    627 static int macsec_qca_delete_transmit_sc(void *priv, struct transmit_sc *sc)
    628 {
    629 	struct macsec_qca_data *drv = priv;
    630 	int ret;
    631 	fal_tx_class_lut_t entry;
    632 	u32 channel;
    633 
    634 	ret = macsec_qca_lookup_transmit_channel(priv, sc, &channel);
    635 	if (ret != 0)
    636 		return ret;
    637 
    638 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
    639 
    640 	/* class lut */
    641 	os_memset(&entry, 0, sizeof(entry));
    642 
    643 	ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
    644 	ret += nss_macsec_secy_tx_sc_del(drv->secy_id, channel);
    645 
    646 	return ret;
    647 }
    648 
    649 
    650 static int macsec_qca_create_transmit_sa(void *priv, struct transmit_sa *sa)
    651 {
    652 	struct macsec_qca_data *drv = priv;
    653 	int ret;
    654 	u8 tci = 0;
    655 	fal_tx_sak_t tx_sak;
    656 	int i;
    657 	u32 channel;
    658 
    659 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
    660 	if (ret != 0)
    661 		return ret;
    662 
    663 	wpa_printf(MSG_DEBUG,
    664 		   "%s: channel=%d, an=%d, next_pn=0x%x, confidentiality=%d",
    665 		   __func__, channel, sa->an, sa->next_pn, sa->confidentiality);
    666 
    667 	if (drv->always_include_sci)
    668 		tci |= TCI_SC;
    669 	else if (drv->use_es)
    670 		tci |= TCI_ES;
    671 	else if (drv->use_scb)
    672 		tci |= TCI_SCB;
    673 
    674 	if (sa->confidentiality)
    675 		tci |= TCI_E | TCI_C;
    676 
    677 	os_memset(&tx_sak, 0, sizeof(tx_sak));
    678 	for (i = 0; i < 16; i++)
    679 		tx_sak.sak[i] = sa->pkey->key[15 - i];
    680 
    681 	ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
    682 						 sa->next_pn);
    683 	ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, sa->an,
    684 					  &tx_sak);
    685 	ret += nss_macsec_secy_tx_sc_tci_7_2_set(drv->secy_id, channel,
    686 						 (tci >> 2));
    687 	ret += nss_macsec_secy_tx_sc_an_set(drv->secy_id, channel, sa->an);
    688 
    689 	return ret;
    690 }
    691 
    692 
    693 static int macsec_qca_enable_transmit_sa(void *priv, struct transmit_sa *sa)
    694 {
    695 	struct macsec_qca_data *drv = priv;
    696 	int ret;
    697 	u32 channel;
    698 
    699 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
    700 	if (ret != 0)
    701 		return ret;
    702 
    703 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
    704 		   sa->an);
    705 
    706 	ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
    707 					    TRUE);
    708 
    709 	return ret;
    710 }
    711 
    712 
    713 static int macsec_qca_disable_transmit_sa(void *priv, struct transmit_sa *sa)
    714 {
    715 	struct macsec_qca_data *drv = priv;
    716 	int ret;
    717 	u32 channel;
    718 
    719 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
    720 	if (ret != 0)
    721 		return ret;
    722 
    723 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
    724 		   sa->an);
    725 
    726 	ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
    727 					    FALSE);
    728 
    729 	return ret;
    730 }
    731 
    732 
    733 const struct wpa_driver_ops wpa_driver_macsec_qca_ops = {
    734 	.name = "macsec_qca",
    735 	.desc = "QCA MACsec Ethernet driver",
    736 	.get_ssid = driver_wired_get_ssid,
    737 	.get_bssid = driver_wired_get_bssid,
    738 	.get_capa = driver_wired_get_capa,
    739 	.init = macsec_qca_init,
    740 	.deinit = macsec_qca_deinit,
    741 
    742 	.macsec_init = macsec_qca_macsec_init,
    743 	.macsec_deinit = macsec_qca_macsec_deinit,
    744 	.macsec_get_capability = macsec_qca_get_capability,
    745 	.enable_protect_frames = macsec_qca_enable_protect_frames,
    746 	.set_replay_protect = macsec_qca_set_replay_protect,
    747 	.set_current_cipher_suite = macsec_qca_set_current_cipher_suite,
    748 	.enable_controlled_port = macsec_qca_enable_controlled_port,
    749 	.get_receive_lowest_pn = macsec_qca_get_receive_lowest_pn,
    750 	.get_transmit_next_pn = macsec_qca_get_transmit_next_pn,
    751 	.set_transmit_next_pn = macsec_qca_set_transmit_next_pn,
    752 	.create_receive_sc = macsec_qca_create_receive_sc,
    753 	.delete_receive_sc = macsec_qca_delete_receive_sc,
    754 	.create_receive_sa = macsec_qca_create_receive_sa,
    755 	.enable_receive_sa = macsec_qca_enable_receive_sa,
    756 	.disable_receive_sa = macsec_qca_disable_receive_sa,
    757 	.create_transmit_sc = macsec_qca_create_transmit_sc,
    758 	.delete_transmit_sc = macsec_qca_delete_transmit_sc,
    759 	.create_transmit_sa = macsec_qca_create_transmit_sa,
    760 	.enable_transmit_sa = macsec_qca_enable_transmit_sa,
    761 	.disable_transmit_sa = macsec_qca_disable_transmit_sa,
    762 };
    763