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