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