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 #ifdef __linux__
     15 #include <netpacket/packet.h>
     16 #include <net/if_arp.h>
     17 #include <net/if.h>
     18 #endif /* __linux__ */
     19 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
     20 #include <net/if_dl.h>
     21 #include <net/if_media.h>
     22 #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
     23 #ifdef __sun__
     24 #include <sys/sockio.h>
     25 #endif /* __sun__ */
     26 
     27 #include "utils/common.h"
     28 #include "utils/eloop.h"
     29 #include "common/defs.h"
     30 #include "common/ieee802_1x_defs.h"
     31 #include "driver.h"
     32 
     33 #include "nss_macsec_secy.h"
     34 #include "nss_macsec_secy_rx.h"
     35 #include "nss_macsec_secy_tx.h"
     36 
     37 #define MAXSC 16
     38 
     39 /* TCI field definition */
     40 #define TCI_ES                0x40
     41 #define TCI_SC                0x20
     42 #define TCI_SCB               0x10
     43 #define TCI_E                 0x08
     44 #define TCI_C                 0x04
     45 
     46 #ifdef _MSC_VER
     47 #pragma pack(push, 1)
     48 #endif /* _MSC_VER */
     49 
     50 #ifdef _MSC_VER
     51 #pragma pack(pop)
     52 #endif /* _MSC_VER */
     53 
     54 static const u8 pae_group_addr[ETH_ALEN] =
     55 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
     56 
     57 struct macsec_qca_data {
     58 	char ifname[IFNAMSIZ + 1];
     59 	u32 secy_id;
     60 	void *ctx;
     61 
     62 	int sock; /* raw packet socket for driver access */
     63 	int pf_sock;
     64 	int membership, multi, iff_allmulti, iff_up;
     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 
     75 
     76 static int macsec_qca_multicast_membership(int sock, int ifindex,
     77 					   const u8 *addr, int add)
     78 {
     79 #ifdef __linux__
     80 	struct packet_mreq mreq;
     81 
     82 	if (sock < 0)
     83 		return -1;
     84 
     85 	os_memset(&mreq, 0, sizeof(mreq));
     86 	mreq.mr_ifindex = ifindex;
     87 	mreq.mr_type = PACKET_MR_MULTICAST;
     88 	mreq.mr_alen = ETH_ALEN;
     89 	os_memcpy(mreq.mr_address, addr, ETH_ALEN);
     90 
     91 	if (setsockopt(sock, SOL_PACKET,
     92 		       add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
     93 		       &mreq, sizeof(mreq)) < 0) {
     94 		perror("setsockopt");
     95 		return -1;
     96 	}
     97 	return 0;
     98 #else /* __linux__ */
     99 	return -1;
    100 #endif /* __linux__ */
    101 }
    102 
    103 
    104 static int macsec_qca_get_ssid(void *priv, u8 *ssid)
    105 {
    106 	ssid[0] = 0;
    107 	return 0;
    108 }
    109 
    110 
    111 static int macsec_qca_get_bssid(void *priv, u8 *bssid)
    112 {
    113 	/* Report PAE group address as the "BSSID" for macsec connection. */
    114 	os_memcpy(bssid, pae_group_addr, ETH_ALEN);
    115 	return 0;
    116 }
    117 
    118 
    119 static int macsec_qca_get_capa(void *priv, struct wpa_driver_capa *capa)
    120 {
    121 	os_memset(capa, 0, sizeof(*capa));
    122 	capa->flags = WPA_DRIVER_FLAGS_WIRED;
    123 	return 0;
    124 }
    125 
    126 
    127 static int macsec_qca_get_ifflags(const char *ifname, int *flags)
    128 {
    129 	struct ifreq ifr;
    130 	int s;
    131 
    132 	s = socket(PF_INET, SOCK_DGRAM, 0);
    133 	if (s < 0) {
    134 		perror("socket");
    135 		return -1;
    136 	}
    137 
    138 	os_memset(&ifr, 0, sizeof(ifr));
    139 	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
    140 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
    141 		perror("ioctl[SIOCGIFFLAGS]");
    142 		close(s);
    143 		return -1;
    144 	}
    145 	close(s);
    146 	*flags = ifr.ifr_flags & 0xffff;
    147 	return 0;
    148 }
    149 
    150 
    151 static int macsec_qca_set_ifflags(const char *ifname, int flags)
    152 {
    153 	struct ifreq ifr;
    154 	int s;
    155 
    156 	s = socket(PF_INET, SOCK_DGRAM, 0);
    157 	if (s < 0) {
    158 		perror("socket");
    159 		return -1;
    160 	}
    161 
    162 	os_memset(&ifr, 0, sizeof(ifr));
    163 	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
    164 	ifr.ifr_flags = flags & 0xffff;
    165 	if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
    166 		perror("ioctl[SIOCSIFFLAGS]");
    167 		close(s);
    168 		return -1;
    169 	}
    170 	close(s);
    171 	return 0;
    172 }
    173 
    174 
    175 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
    176 static int macsec_qca_get_ifstatus(const char *ifname, int *status)
    177 {
    178 	struct ifmediareq ifmr;
    179 	int s;
    180 
    181 	s = socket(PF_INET, SOCK_DGRAM, 0);
    182 	if (s < 0) {
    183 		perror("socket");
    184 		return -1;
    185 	}
    186 
    187 	os_memset(&ifmr, 0, sizeof(ifmr));
    188 	os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
    189 	if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
    190 		perror("ioctl[SIOCGIFMEDIA]");
    191 		close(s);
    192 		return -1;
    193 	}
    194 	close(s);
    195 	*status = (ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) ==
    196 		(IFM_ACTIVE | IFM_AVALID);
    197 
    198 	return 0;
    199 }
    200 #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
    201 
    202 
    203 static int macsec_qca_multi(const char *ifname, const u8 *addr, int add)
    204 {
    205 	struct ifreq ifr;
    206 	int s;
    207 
    208 #ifdef __sun__
    209 	return -1;
    210 #endif /* __sun__ */
    211 
    212 	s = socket(PF_INET, SOCK_DGRAM, 0);
    213 	if (s < 0) {
    214 		perror("socket");
    215 		return -1;
    216 	}
    217 
    218 	os_memset(&ifr, 0, sizeof(ifr));
    219 	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
    220 #ifdef __linux__
    221 	ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
    222 	os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
    223 #endif /* __linux__ */
    224 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
    225 	{
    226 		struct sockaddr_dl *dlp;
    227 		dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
    228 		dlp->sdl_len = sizeof(struct sockaddr_dl);
    229 		dlp->sdl_family = AF_LINK;
    230 		dlp->sdl_index = 0;
    231 		dlp->sdl_nlen = 0;
    232 		dlp->sdl_alen = ETH_ALEN;
    233 		dlp->sdl_slen = 0;
    234 		os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
    235 	}
    236 #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
    237 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
    238 	{
    239 		struct sockaddr *sap;
    240 		sap = (struct sockaddr *) &ifr.ifr_addr;
    241 		sap->sa_len = sizeof(struct sockaddr);
    242 		sap->sa_family = AF_UNSPEC;
    243 		os_memcpy(sap->sa_data, addr, ETH_ALEN);
    244 	}
    245 #endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
    246 
    247 	if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
    248 		perror("ioctl[SIOC{ADD/DEL}MULTI]");
    249 		close(s);
    250 		return -1;
    251 	}
    252 	close(s);
    253 	return 0;
    254 }
    255 
    256 
    257 static void __macsec_drv_init(struct macsec_qca_data *drv)
    258 {
    259 	int ret = 0;
    260 	fal_rx_ctl_filt_t rx_ctl_filt;
    261 	fal_tx_ctl_filt_t tx_ctl_filt;
    262 
    263 	wpa_printf(MSG_INFO, "%s: secy_id=%d", __func__, drv->secy_id);
    264 
    265 	/* Enable Secy and Let EAPoL bypass */
    266 	ret = nss_macsec_secy_en_set(drv->secy_id, TRUE);
    267 	if (ret)
    268 		wpa_printf(MSG_ERROR, "nss_macsec_secy_en_set: FAIL");
    269 
    270 	ret = nss_macsec_secy_sc_sa_mapping_mode_set(drv->secy_id,
    271 						     FAL_SC_SA_MAP_1_4);
    272 	if (ret)
    273 		wpa_printf(MSG_ERROR,
    274 			   "nss_macsec_secy_sc_sa_mapping_mode_set: FAIL");
    275 
    276 	os_memset(&rx_ctl_filt, 0, sizeof(rx_ctl_filt));
    277 	rx_ctl_filt.bypass = 1;
    278 	rx_ctl_filt.match_type = IG_CTL_COMPARE_ETHER_TYPE;
    279 	rx_ctl_filt.match_mask = 0xffff;
    280 	rx_ctl_filt.ether_type_da_range = 0x888e;
    281 	ret = nss_macsec_secy_rx_ctl_filt_set(drv->secy_id, 0, &rx_ctl_filt);
    282 	if (ret)
    283 		wpa_printf(MSG_ERROR, "nss_macsec_secy_rx_ctl_filt_set: FAIL");
    284 
    285 	os_memset(&tx_ctl_filt, 0, sizeof(tx_ctl_filt));
    286 	tx_ctl_filt.bypass = 1;
    287 	tx_ctl_filt.match_type = EG_CTL_COMPARE_ETHER_TYPE;
    288 	tx_ctl_filt.match_mask = 0xffff;
    289 	tx_ctl_filt.ether_type_da_range = 0x888e;
    290 	ret = nss_macsec_secy_tx_ctl_filt_set(drv->secy_id, 0, &tx_ctl_filt);
    291 	if (ret)
    292 		wpa_printf(MSG_ERROR, "nss_macsec_secy_tx_ctl_filt_set: FAIL");
    293 }
    294 
    295 
    296 static void __macsec_drv_deinit(struct macsec_qca_data *drv)
    297 {
    298 	nss_macsec_secy_en_set(drv->secy_id, FALSE);
    299 	nss_macsec_secy_rx_sc_del_all(drv->secy_id);
    300 	nss_macsec_secy_tx_sc_del_all(drv->secy_id);
    301 }
    302 
    303 
    304 static void * macsec_qca_init(void *ctx, const char *ifname)
    305 {
    306 	struct macsec_qca_data *drv;
    307 	int flags;
    308 
    309 	drv = os_zalloc(sizeof(*drv));
    310 	if (drv == NULL)
    311 		return NULL;
    312 	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
    313 	drv->ctx = ctx;
    314 
    315 	/* Board specific settings */
    316 	if (os_memcmp("eth2", drv->ifname, 4) == 0)
    317 		drv->secy_id = 1;
    318 	else if (os_memcmp("eth3", drv->ifname, 4) == 0)
    319 		drv->secy_id = 2;
    320 	else
    321 		drv->secy_id = -1;
    322 
    323 #ifdef __linux__
    324 	drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
    325 	if (drv->pf_sock < 0)
    326 		perror("socket(PF_PACKET)");
    327 #else /* __linux__ */
    328 	drv->pf_sock = -1;
    329 #endif /* __linux__ */
    330 
    331 	if (macsec_qca_get_ifflags(ifname, &flags) == 0 &&
    332 	    !(flags & IFF_UP) &&
    333 	    macsec_qca_set_ifflags(ifname, flags | IFF_UP) == 0) {
    334 		drv->iff_up = 1;
    335 	}
    336 
    337 	if (macsec_qca_multicast_membership(drv->pf_sock,
    338 					    if_nametoindex(drv->ifname),
    339 					    pae_group_addr, 1) == 0) {
    340 		wpa_printf(MSG_DEBUG,
    341 			   "%s: Added multicast membership with packet socket",
    342 			   __func__);
    343 		drv->membership = 1;
    344 	} else if (macsec_qca_multi(ifname, pae_group_addr, 1) == 0) {
    345 		wpa_printf(MSG_DEBUG,
    346 			   "%s: Added multicast membership with SIOCADDMULTI",
    347 			   __func__);
    348 		drv->multi = 1;
    349 	} else if (macsec_qca_get_ifflags(ifname, &flags) < 0) {
    350 		wpa_printf(MSG_INFO, "%s: Could not get interface flags",
    351 			   __func__);
    352 		os_free(drv);
    353 		return NULL;
    354 	} else if (flags & IFF_ALLMULTI) {
    355 		wpa_printf(MSG_DEBUG,
    356 			   "%s: Interface is already configured for multicast",
    357 			   __func__);
    358 	} else if (macsec_qca_set_ifflags(ifname, flags | IFF_ALLMULTI) < 0) {
    359 		wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
    360 			   __func__);
    361 		os_free(drv);
    362 		return NULL;
    363 	} else {
    364 		wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode", __func__);
    365 		drv->iff_allmulti = 1;
    366 	}
    367 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
    368 	{
    369 		int status;
    370 		wpa_printf(MSG_DEBUG, "%s: waiting for link to become active",
    371 			   __func__);
    372 		while (macsec_qca_get_ifstatus(ifname, &status) == 0 &&
    373 		       status == 0)
    374 			sleep(1);
    375 	}
    376 #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
    377 
    378 	return drv;
    379 }
    380 
    381 
    382 static void macsec_qca_deinit(void *priv)
    383 {
    384 	struct macsec_qca_data *drv = priv;
    385 	int flags;
    386 
    387 	if (drv->membership &&
    388 	    macsec_qca_multicast_membership(drv->pf_sock,
    389 					    if_nametoindex(drv->ifname),
    390 					    pae_group_addr, 0) < 0) {
    391 		wpa_printf(MSG_DEBUG,
    392 			   "%s: Failed to remove PAE multicast group (PACKET)",
    393 			   __func__);
    394 	}
    395 
    396 	if (drv->multi &&
    397 	    macsec_qca_multi(drv->ifname, pae_group_addr, 0) < 0) {
    398 		wpa_printf(MSG_DEBUG,
    399 			   "%s: Failed to remove PAE multicast group (SIOCDELMULTI)",
    400 			   __func__);
    401 	}
    402 
    403 	if (drv->iff_allmulti &&
    404 	    (macsec_qca_get_ifflags(drv->ifname, &flags) < 0 ||
    405 	     macsec_qca_set_ifflags(drv->ifname, flags & ~IFF_ALLMULTI) < 0)) {
    406 		wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
    407 			   __func__);
    408 	}
    409 
    410 	if (drv->iff_up &&
    411 	    macsec_qca_get_ifflags(drv->ifname, &flags) == 0 &&
    412 	    (flags & IFF_UP) &&
    413 	    macsec_qca_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
    414 		wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
    415 			   __func__);
    416 	}
    417 
    418 	if (drv->pf_sock != -1)
    419 		close(drv->pf_sock);
    420 
    421 	os_free(drv);
    422 }
    423 
    424 
    425 static int macsec_qca_macsec_init(void *priv, struct macsec_init_params *params)
    426 {
    427 	struct macsec_qca_data *drv = priv;
    428 
    429 	drv->always_include_sci = params->always_include_sci;
    430 	drv->use_es = params->use_es;
    431 	drv->use_scb = params->use_scb;
    432 
    433 	wpa_printf(MSG_DEBUG, "%s: es=%d, scb=%d, sci=%d",
    434 		   __func__, drv->use_es, drv->use_scb,
    435 		   drv->always_include_sci);
    436 
    437 	__macsec_drv_init(drv);
    438 
    439 	return 0;
    440 }
    441 
    442 
    443 static int macsec_qca_macsec_deinit(void *priv)
    444 {
    445 	struct macsec_qca_data *drv = priv;
    446 
    447 	wpa_printf(MSG_DEBUG, "%s", __func__);
    448 
    449 	__macsec_drv_deinit(drv);
    450 
    451 	return 0;
    452 }
    453 
    454 
    455 static int macsec_qca_enable_protect_frames(void *priv, Boolean enabled)
    456 {
    457 	struct macsec_qca_data *drv = priv;
    458 	int ret = 0;
    459 
    460 	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
    461 
    462 	drv->protect_frames = enabled;
    463 
    464 	return ret;
    465 }
    466 
    467 
    468 static int macsec_qca_set_replay_protect(void *priv, Boolean enabled,
    469 					 unsigned int window)
    470 {
    471 	struct macsec_qca_data *drv = priv;
    472 	int ret = 0;
    473 
    474 	wpa_printf(MSG_DEBUG, "%s: enabled=%d, win=%u",
    475 		   __func__, enabled, window);
    476 
    477 	drv->replay_protect = enabled;
    478 	drv->replay_window = window;
    479 
    480 	return ret;
    481 }
    482 
    483 
    484 static int macsec_qca_set_current_cipher_suite(void *priv, const u8 *cs,
    485 					       size_t cs_len)
    486 {
    487 	u8 default_cs_id[] = CS_ID_GCM_AES_128;
    488 
    489 	if (cs_len != CS_ID_LEN ||
    490 	    os_memcmp(cs, default_cs_id, cs_len) != 0) {
    491 		wpa_hexdump(MSG_ERROR, "macsec: NOT supported CipherSuite",
    492 			    cs, cs_len);
    493 		return -1;
    494 	}
    495 
    496 	/* Support default Cipher Suite 0080020001000001 (GCM-AES-128) */
    497 	wpa_printf(MSG_DEBUG, "%s: default support aes-gcm-128", __func__);
    498 
    499 	return 0;
    500 }
    501 
    502 
    503 static int macsec_qca_enable_controlled_port(void *priv, Boolean enabled)
    504 {
    505 	struct macsec_qca_data *drv = priv;
    506 	int ret = 0;
    507 
    508 	wpa_printf(MSG_DEBUG, "%s: enable=%d", __func__, enabled);
    509 
    510 	ret += nss_macsec_secy_controlled_port_en_set(drv->secy_id, enabled);
    511 
    512 	return ret;
    513 }
    514 
    515 
    516 static int macsec_qca_get_receive_lowest_pn(void *priv, u32 channel, u8 an,
    517 					    u32 *lowest_pn)
    518 {
    519 	struct macsec_qca_data *drv = priv;
    520 	int ret = 0;
    521 	u32 next_pn = 0;
    522 	bool enabled = FALSE;
    523 	u32 win;
    524 
    525 	ret += nss_macsec_secy_rx_sa_next_pn_get(drv->secy_id, channel, an,
    526 						 &next_pn);
    527 	ret += nss_macsec_secy_rx_sc_replay_protect_get(drv->secy_id, channel,
    528 							&enabled);
    529 	ret += nss_macsec_secy_rx_sc_anti_replay_window_get(drv->secy_id,
    530 							    channel, &win);
    531 
    532 	if (enabled)
    533 		*lowest_pn = (next_pn > win) ? (next_pn - win) : 1;
    534 	else
    535 		*lowest_pn = next_pn;
    536 
    537 	wpa_printf(MSG_DEBUG, "%s: lpn=0x%x", __func__, *lowest_pn);
    538 
    539 	return ret;
    540 }
    541 
    542 
    543 static int macsec_qca_get_transmit_next_pn(void *priv, u32 channel, u8 an,
    544 					   u32 *next_pn)
    545 {
    546 	struct macsec_qca_data *drv = priv;
    547 	int ret = 0;
    548 
    549 	ret += nss_macsec_secy_tx_sa_next_pn_get(drv->secy_id, channel, an,
    550 						 next_pn);
    551 
    552 	wpa_printf(MSG_DEBUG, "%s: npn=0x%x", __func__, *next_pn);
    553 
    554 	return ret;
    555 }
    556 
    557 
    558 int macsec_qca_set_transmit_next_pn(void *priv, u32 channel, u8 an, u32 next_pn)
    559 {
    560 	struct macsec_qca_data *drv = priv;
    561 	int ret = 0;
    562 
    563 	ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, an,
    564 						 next_pn);
    565 
    566 	wpa_printf(MSG_INFO, "%s: npn=0x%x", __func__, next_pn);
    567 
    568 	return ret;
    569 }
    570 
    571 
    572 static int macsec_qca_get_available_receive_sc(void *priv, u32 *channel)
    573 {
    574 	struct macsec_qca_data *drv = priv;
    575 	int ret = 0;
    576 	u32 sc_ch = 0;
    577 	bool in_use = FALSE;
    578 
    579 	for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
    580 		ret = nss_macsec_secy_rx_sc_in_used_get(drv->secy_id, sc_ch,
    581 							&in_use);
    582 		if (ret)
    583 			continue;
    584 
    585 		if (!in_use) {
    586 			*channel = sc_ch;
    587 			wpa_printf(MSG_DEBUG, "%s: channel=%d",
    588 				   __func__, *channel);
    589 			return 0;
    590 		}
    591 	}
    592 
    593 	wpa_printf(MSG_DEBUG, "%s: no available channel", __func__);
    594 
    595 	return -1;
    596 }
    597 
    598 
    599 static int macsec_qca_create_receive_sc(void *priv, u32 channel,
    600 					const u8 *sci_addr, u16 sci_port,
    601 					unsigned int conf_offset,
    602 					int validation)
    603 {
    604 	struct macsec_qca_data *drv = priv;
    605 	int ret = 0;
    606 	fal_rx_prc_lut_t entry;
    607 	fal_rx_sc_validate_frame_e vf;
    608 	enum validate_frames validate_frames = validation;
    609 
    610 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
    611 
    612 	/* rx prc lut */
    613 	os_memset(&entry, 0, sizeof(entry));
    614 
    615 	os_memcpy(entry.sci, sci_addr, ETH_ALEN);
    616 	entry.sci[6] = (sci_port >> 8) & 0xf;
    617 	entry.sci[7] = sci_port & 0xf;
    618 	entry.sci_mask = 0xf;
    619 
    620 	entry.valid = 1;
    621 	entry.channel = channel;
    622 	entry.action = FAL_RX_PRC_ACTION_PROCESS;
    623 	entry.offset = conf_offset;
    624 
    625 	/* rx validate frame  */
    626 	if (validate_frames == Strict)
    627 		vf = FAL_RX_SC_VALIDATE_FRAME_STRICT;
    628 	else if (validate_frames == Checked)
    629 		vf = FAL_RX_SC_VALIDATE_FRAME_CHECK;
    630 	else
    631 		vf = FAL_RX_SC_VALIDATE_FRAME_DISABLED;
    632 
    633 	ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
    634 	ret += nss_macsec_secy_rx_sc_create(drv->secy_id, channel);
    635 	ret += nss_macsec_secy_rx_sc_validate_frame_set(drv->secy_id, channel,
    636 							vf);
    637 	ret += nss_macsec_secy_rx_sc_replay_protect_set(drv->secy_id, channel,
    638 							drv->replay_protect);
    639 	ret += nss_macsec_secy_rx_sc_anti_replay_window_set(drv->secy_id,
    640 							    channel,
    641 							    drv->replay_window);
    642 
    643 	return ret;
    644 }
    645 
    646 
    647 static int macsec_qca_delete_receive_sc(void *priv, u32 channel)
    648 {
    649 	struct macsec_qca_data *drv = priv;
    650 	int ret = 0;
    651 	fal_rx_prc_lut_t entry;
    652 
    653 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
    654 
    655 	/* rx prc lut */
    656 	os_memset(&entry, 0, sizeof(entry));
    657 
    658 	ret += nss_macsec_secy_rx_sc_del(drv->secy_id, channel);
    659 	ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
    660 
    661 	return ret;
    662 }
    663 
    664 
    665 static int macsec_qca_create_receive_sa(void *priv, u32 channel, u8 an,
    666 					u32 lowest_pn, const u8 *sak)
    667 {
    668 	struct macsec_qca_data *drv = priv;
    669 	int ret = 0;
    670 	fal_rx_sak_t rx_sak;
    671 	int i = 0;
    672 
    673 	wpa_printf(MSG_DEBUG, "%s, channel=%d, an=%d, lpn=0x%x",
    674 		   __func__, channel, an, lowest_pn);
    675 
    676 	os_memset(&rx_sak, 0, sizeof(rx_sak));
    677 	for (i = 0; i < 16; i++)
    678 		rx_sak.sak[i] = sak[15 - i];
    679 
    680 	ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, an);
    681 	ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, an, &rx_sak);
    682 
    683 	return ret;
    684 }
    685 
    686 
    687 static int macsec_qca_enable_receive_sa(void *priv, u32 channel, u8 an)
    688 {
    689 	struct macsec_qca_data *drv = priv;
    690 	int ret = 0;
    691 
    692 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
    693 
    694 	ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, an, TRUE);
    695 
    696 	return ret;
    697 }
    698 
    699 
    700 static int macsec_qca_disable_receive_sa(void *priv, u32 channel, u8 an)
    701 {
    702 	struct macsec_qca_data *drv = priv;
    703 	int ret = 0;
    704 
    705 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
    706 
    707 	ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, an, FALSE);
    708 
    709 	return ret;
    710 }
    711 
    712 
    713 static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel)
    714 {
    715 	struct macsec_qca_data *drv = priv;
    716 	int ret = 0;
    717 	u32 sc_ch = 0;
    718 	bool in_use = FALSE;
    719 
    720 	for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
    721 		ret = nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch,
    722 							&in_use);
    723 		if (ret)
    724 			continue;
    725 
    726 		if (!in_use) {
    727 			*channel = sc_ch;
    728 			wpa_printf(MSG_DEBUG, "%s: channel=%d",
    729 				   __func__, *channel);
    730 			return 0;
    731 		}
    732 	}
    733 
    734 	wpa_printf(MSG_DEBUG, "%s: no avaiable channel", __func__);
    735 
    736 	return -1;
    737 }
    738 
    739 
    740 static int macsec_qca_create_transmit_sc(void *priv, u32 channel,
    741 					 const u8 *sci_addr, u16 sci_port,
    742 					 unsigned int conf_offset)
    743 {
    744 	struct macsec_qca_data *drv = priv;
    745 	int ret = 0;
    746 	fal_tx_class_lut_t entry;
    747 	u8 psci[ETH_ALEN + 2];
    748 
    749 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
    750 
    751 	/* class lut */
    752 	os_memset(&entry, 0, sizeof(entry));
    753 
    754 	entry.valid = 1;
    755 	entry.action = FAL_TX_CLASS_ACTION_FORWARD;
    756 	entry.channel = channel;
    757 
    758 	os_memcpy(psci, sci_addr, ETH_ALEN);
    759 	psci[6] = (sci_port >> 8) & 0xf;
    760 	psci[7] = sci_port & 0xf;
    761 
    762 	ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
    763 	ret += nss_macsec_secy_tx_sc_create(drv->secy_id, channel, psci, 8);
    764 	ret += nss_macsec_secy_tx_sc_protect_set(drv->secy_id, channel,
    765 						 drv->protect_frames);
    766 	ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
    767 								channel,
    768 								conf_offset);
    769 
    770 	return ret;
    771 }
    772 
    773 
    774 static int macsec_qca_delete_transmit_sc(void *priv, u32 channel)
    775 {
    776 	struct macsec_qca_data *drv = priv;
    777 	int ret = 0;
    778 	fal_tx_class_lut_t entry;
    779 
    780 	wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
    781 
    782 	/* class lut */
    783 	os_memset(&entry, 0, sizeof(entry));
    784 
    785 	ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
    786 	ret += nss_macsec_secy_tx_sc_del(drv->secy_id, channel);
    787 
    788 	return ret;
    789 }
    790 
    791 
    792 static int macsec_qca_create_transmit_sa(void *priv, u32 channel, u8 an,
    793 					 u32 next_pn, Boolean confidentiality,
    794 					 const u8 *sak)
    795 {
    796 	struct macsec_qca_data *drv = priv;
    797 	int ret = 0;
    798 	u8 tci = 0;
    799 	fal_tx_sak_t tx_sak;
    800 	int i;
    801 
    802 	wpa_printf(MSG_DEBUG,
    803 		   "%s: channel=%d, an=%d, next_pn=0x%x, confidentiality=%d",
    804 		   __func__, channel, an, next_pn, confidentiality);
    805 
    806 	if (drv->always_include_sci)
    807 		tci |= TCI_SC;
    808 	else if (drv->use_es)
    809 		tci |= TCI_ES;
    810 	else if (drv->use_scb)
    811 		tci |= TCI_SCB;
    812 
    813 	if (confidentiality)
    814 		tci |= TCI_E | TCI_C;
    815 
    816 	os_memset(&tx_sak, 0, sizeof(tx_sak));
    817 	for (i = 0; i < 16; i++)
    818 		tx_sak.sak[i] = sak[15 - i];
    819 
    820 	ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, an,
    821 						 next_pn);
    822 	ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, an, &tx_sak);
    823 	ret += nss_macsec_secy_tx_sc_tci_7_2_set(drv->secy_id, channel,
    824 						 (tci >> 2));
    825 	ret += nss_macsec_secy_tx_sc_an_set(drv->secy_id, channel, an);
    826 
    827 	return ret;
    828 }
    829 
    830 
    831 static int macsec_qca_enable_transmit_sa(void *priv, u32 channel, u8 an)
    832 {
    833 	struct macsec_qca_data *drv = priv;
    834 	int ret = 0;
    835 
    836 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
    837 
    838 	ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, an, TRUE);
    839 
    840 	return ret;
    841 }
    842 
    843 
    844 static int macsec_qca_disable_transmit_sa(void *priv, u32 channel, u8 an)
    845 {
    846 	struct macsec_qca_data *drv = priv;
    847 	int ret = 0;
    848 
    849 	wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
    850 
    851 	ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, an, FALSE);
    852 
    853 	return ret;
    854 }
    855 
    856 
    857 const struct wpa_driver_ops wpa_driver_macsec_qca_ops = {
    858 	.name = "macsec_qca",
    859 	.desc = "QCA MACsec Ethernet driver",
    860 	.get_ssid = macsec_qca_get_ssid,
    861 	.get_bssid = macsec_qca_get_bssid,
    862 	.get_capa = macsec_qca_get_capa,
    863 	.init = macsec_qca_init,
    864 	.deinit = macsec_qca_deinit,
    865 
    866 	.macsec_init = macsec_qca_macsec_init,
    867 	.macsec_deinit = macsec_qca_macsec_deinit,
    868 	.enable_protect_frames = macsec_qca_enable_protect_frames,
    869 	.set_replay_protect = macsec_qca_set_replay_protect,
    870 	.set_current_cipher_suite = macsec_qca_set_current_cipher_suite,
    871 	.enable_controlled_port = macsec_qca_enable_controlled_port,
    872 	.get_receive_lowest_pn = macsec_qca_get_receive_lowest_pn,
    873 	.get_transmit_next_pn = macsec_qca_get_transmit_next_pn,
    874 	.set_transmit_next_pn = macsec_qca_set_transmit_next_pn,
    875 	.get_available_receive_sc = macsec_qca_get_available_receive_sc,
    876 	.create_receive_sc = macsec_qca_create_receive_sc,
    877 	.delete_receive_sc = macsec_qca_delete_receive_sc,
    878 	.create_receive_sa = macsec_qca_create_receive_sa,
    879 	.enable_receive_sa = macsec_qca_enable_receive_sa,
    880 	.disable_receive_sa = macsec_qca_disable_receive_sa,
    881 	.get_available_transmit_sc = macsec_qca_get_available_transmit_sc,
    882 	.create_transmit_sc = macsec_qca_create_transmit_sc,
    883 	.delete_transmit_sc = macsec_qca_delete_transmit_sc,
    884 	.create_transmit_sa = macsec_qca_create_transmit_sa,
    885 	.enable_transmit_sa = macsec_qca_enable_transmit_sa,
    886 	.disable_transmit_sa = macsec_qca_disable_transmit_sa,
    887 };
    888