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