15b9c547cSRui Paulo /* 25b9c547cSRui Paulo * Wired Ethernet driver interface for QCA MACsec driver 35b9c547cSRui Paulo * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> 45b9c547cSRui Paulo * Copyright (c) 2004, Gunter Burchardt <tira@isx.de> 55b9c547cSRui Paulo * Copyright (c) 2013-2014, Qualcomm Atheros, Inc. 6*206b73d0SCy Schubert * Copyright (c) 2019, The Linux Foundation 75b9c547cSRui Paulo * 85b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license. 95b9c547cSRui Paulo * See README for more details. 105b9c547cSRui Paulo */ 115b9c547cSRui Paulo 125b9c547cSRui Paulo #include "includes.h" 135b9c547cSRui Paulo #include <sys/ioctl.h> 145b9c547cSRui Paulo #include <net/if.h> 15780fb4a2SCy Schubert #include <inttypes.h> 165b9c547cSRui Paulo #ifdef __linux__ 175b9c547cSRui Paulo #include <netpacket/packet.h> 185b9c547cSRui Paulo #include <net/if_arp.h> 195b9c547cSRui Paulo #include <net/if.h> 205b9c547cSRui Paulo #endif /* __linux__ */ 215b9c547cSRui Paulo #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) 225b9c547cSRui Paulo #include <net/if_dl.h> 235b9c547cSRui Paulo #include <net/if_media.h> 245b9c547cSRui Paulo #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */ 255b9c547cSRui Paulo #ifdef __sun__ 265b9c547cSRui Paulo #include <sys/sockio.h> 275b9c547cSRui Paulo #endif /* __sun__ */ 285b9c547cSRui Paulo 295b9c547cSRui Paulo #include "utils/common.h" 305b9c547cSRui Paulo #include "utils/eloop.h" 315b9c547cSRui Paulo #include "common/defs.h" 325b9c547cSRui Paulo #include "common/ieee802_1x_defs.h" 33*206b73d0SCy Schubert #include "common/eapol_common.h" 3485732ac8SCy Schubert #include "pae/ieee802_1x_kay.h" 355b9c547cSRui Paulo #include "driver.h" 3685732ac8SCy Schubert #include "driver_wired_common.h" 375b9c547cSRui Paulo 385b9c547cSRui Paulo #include "nss_macsec_secy.h" 395b9c547cSRui Paulo #include "nss_macsec_secy_rx.h" 405b9c547cSRui Paulo #include "nss_macsec_secy_tx.h" 415b9c547cSRui Paulo 425b9c547cSRui Paulo #define MAXSC 16 435b9c547cSRui Paulo 4485732ac8SCy Schubert #define SAK_128_LEN 16 4585732ac8SCy Schubert #define SAK_256_LEN 32 4685732ac8SCy Schubert 475b9c547cSRui Paulo /* TCI field definition */ 485b9c547cSRui Paulo #define TCI_ES 0x40 495b9c547cSRui Paulo #define TCI_SC 0x20 505b9c547cSRui Paulo #define TCI_SCB 0x10 515b9c547cSRui Paulo #define TCI_E 0x08 525b9c547cSRui Paulo #define TCI_C 0x04 535b9c547cSRui Paulo 545b9c547cSRui Paulo #ifdef _MSC_VER 555b9c547cSRui Paulo #pragma pack(push, 1) 565b9c547cSRui Paulo #endif /* _MSC_VER */ 575b9c547cSRui Paulo 585b9c547cSRui Paulo #ifdef _MSC_VER 595b9c547cSRui Paulo #pragma pack(pop) 605b9c547cSRui Paulo #endif /* _MSC_VER */ 615b9c547cSRui Paulo 6285732ac8SCy Schubert struct channel_map { 6385732ac8SCy Schubert struct ieee802_1x_mka_sci sci; 6485732ac8SCy Schubert }; 655b9c547cSRui Paulo 665b9c547cSRui Paulo struct macsec_qca_data { 6785732ac8SCy Schubert struct driver_wired_common_data common; 685b9c547cSRui Paulo 69*206b73d0SCy Schubert int use_pae_group_addr; 7085732ac8SCy Schubert u32 secy_id; 715b9c547cSRui Paulo 725b9c547cSRui Paulo /* shadow */ 735b9c547cSRui Paulo Boolean always_include_sci; 745b9c547cSRui Paulo Boolean use_es; 755b9c547cSRui Paulo Boolean use_scb; 765b9c547cSRui Paulo Boolean protect_frames; 775b9c547cSRui Paulo Boolean replay_protect; 785b9c547cSRui Paulo u32 replay_window; 7985732ac8SCy Schubert 8085732ac8SCy Schubert struct channel_map receive_channel_map[MAXSC]; 8185732ac8SCy Schubert struct channel_map transmit_channel_map[MAXSC]; 825b9c547cSRui Paulo }; 835b9c547cSRui Paulo 845b9c547cSRui Paulo 855b9c547cSRui Paulo static void __macsec_drv_init(struct macsec_qca_data *drv) 865b9c547cSRui Paulo { 875b9c547cSRui Paulo int ret = 0; 885b9c547cSRui Paulo fal_rx_ctl_filt_t rx_ctl_filt; 895b9c547cSRui Paulo fal_tx_ctl_filt_t tx_ctl_filt; 905b9c547cSRui Paulo 915b9c547cSRui Paulo wpa_printf(MSG_INFO, "%s: secy_id=%d", __func__, drv->secy_id); 925b9c547cSRui Paulo 935b9c547cSRui Paulo /* Enable Secy and Let EAPoL bypass */ 945b9c547cSRui Paulo ret = nss_macsec_secy_en_set(drv->secy_id, TRUE); 955b9c547cSRui Paulo if (ret) 965b9c547cSRui Paulo wpa_printf(MSG_ERROR, "nss_macsec_secy_en_set: FAIL"); 975b9c547cSRui Paulo 985b9c547cSRui Paulo ret = nss_macsec_secy_sc_sa_mapping_mode_set(drv->secy_id, 995b9c547cSRui Paulo FAL_SC_SA_MAP_1_4); 1005b9c547cSRui Paulo if (ret) 1015b9c547cSRui Paulo wpa_printf(MSG_ERROR, 1025b9c547cSRui Paulo "nss_macsec_secy_sc_sa_mapping_mode_set: FAIL"); 1035b9c547cSRui Paulo 1045b9c547cSRui Paulo os_memset(&rx_ctl_filt, 0, sizeof(rx_ctl_filt)); 1055b9c547cSRui Paulo rx_ctl_filt.bypass = 1; 1065b9c547cSRui Paulo rx_ctl_filt.match_type = IG_CTL_COMPARE_ETHER_TYPE; 1075b9c547cSRui Paulo rx_ctl_filt.match_mask = 0xffff; 1085b9c547cSRui Paulo rx_ctl_filt.ether_type_da_range = 0x888e; 1095b9c547cSRui Paulo ret = nss_macsec_secy_rx_ctl_filt_set(drv->secy_id, 0, &rx_ctl_filt); 1105b9c547cSRui Paulo if (ret) 1115b9c547cSRui Paulo wpa_printf(MSG_ERROR, "nss_macsec_secy_rx_ctl_filt_set: FAIL"); 1125b9c547cSRui Paulo 1135b9c547cSRui Paulo os_memset(&tx_ctl_filt, 0, sizeof(tx_ctl_filt)); 1145b9c547cSRui Paulo tx_ctl_filt.bypass = 1; 1155b9c547cSRui Paulo tx_ctl_filt.match_type = EG_CTL_COMPARE_ETHER_TYPE; 1165b9c547cSRui Paulo tx_ctl_filt.match_mask = 0xffff; 1175b9c547cSRui Paulo tx_ctl_filt.ether_type_da_range = 0x888e; 1185b9c547cSRui Paulo ret = nss_macsec_secy_tx_ctl_filt_set(drv->secy_id, 0, &tx_ctl_filt); 1195b9c547cSRui Paulo if (ret) 1205b9c547cSRui Paulo wpa_printf(MSG_ERROR, "nss_macsec_secy_tx_ctl_filt_set: FAIL"); 1215b9c547cSRui Paulo } 1225b9c547cSRui Paulo 1235b9c547cSRui Paulo 1245b9c547cSRui Paulo static void __macsec_drv_deinit(struct macsec_qca_data *drv) 1255b9c547cSRui Paulo { 1265b9c547cSRui Paulo nss_macsec_secy_en_set(drv->secy_id, FALSE); 1275b9c547cSRui Paulo nss_macsec_secy_rx_sc_del_all(drv->secy_id); 1285b9c547cSRui Paulo nss_macsec_secy_tx_sc_del_all(drv->secy_id); 1295b9c547cSRui Paulo } 1305b9c547cSRui Paulo 1315b9c547cSRui Paulo 132*206b73d0SCy Schubert #ifdef __linux__ 133*206b73d0SCy Schubert 134*206b73d0SCy Schubert static void macsec_qca_handle_data(void *ctx, unsigned char *buf, size_t len) 135*206b73d0SCy Schubert { 136*206b73d0SCy Schubert #ifdef HOSTAPD 137*206b73d0SCy Schubert struct ieee8023_hdr *hdr; 138*206b73d0SCy Schubert u8 *pos, *sa; 139*206b73d0SCy Schubert size_t left; 140*206b73d0SCy Schubert union wpa_event_data event; 141*206b73d0SCy Schubert 142*206b73d0SCy Schubert /* at least 6 bytes src macaddress, 6 bytes dst macaddress 143*206b73d0SCy Schubert * and 2 bytes ethertype 144*206b73d0SCy Schubert */ 145*206b73d0SCy Schubert if (len < 14) { 146*206b73d0SCy Schubert wpa_printf(MSG_MSGDUMP, 147*206b73d0SCy Schubert "macsec_qca_handle_data: too short (%lu)", 148*206b73d0SCy Schubert (unsigned long) len); 149*206b73d0SCy Schubert return; 150*206b73d0SCy Schubert } 151*206b73d0SCy Schubert hdr = (struct ieee8023_hdr *) buf; 152*206b73d0SCy Schubert 153*206b73d0SCy Schubert switch (ntohs(hdr->ethertype)) { 154*206b73d0SCy Schubert case ETH_P_PAE: 155*206b73d0SCy Schubert wpa_printf(MSG_MSGDUMP, "Received EAPOL packet"); 156*206b73d0SCy Schubert sa = hdr->src; 157*206b73d0SCy Schubert os_memset(&event, 0, sizeof(event)); 158*206b73d0SCy Schubert event.new_sta.addr = sa; 159*206b73d0SCy Schubert wpa_supplicant_event(ctx, EVENT_NEW_STA, &event); 160*206b73d0SCy Schubert 161*206b73d0SCy Schubert pos = (u8 *) (hdr + 1); 162*206b73d0SCy Schubert left = len - sizeof(*hdr); 163*206b73d0SCy Schubert drv_event_eapol_rx(ctx, sa, pos, left); 164*206b73d0SCy Schubert break; 165*206b73d0SCy Schubert default: 166*206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame", 167*206b73d0SCy Schubert ntohs(hdr->ethertype)); 168*206b73d0SCy Schubert break; 169*206b73d0SCy Schubert } 170*206b73d0SCy Schubert #endif /* HOSTAPD */ 171*206b73d0SCy Schubert } 172*206b73d0SCy Schubert 173*206b73d0SCy Schubert 174*206b73d0SCy Schubert static void macsec_qca_handle_read(int sock, void *eloop_ctx, void *sock_ctx) 175*206b73d0SCy Schubert { 176*206b73d0SCy Schubert int len; 177*206b73d0SCy Schubert unsigned char buf[3000]; 178*206b73d0SCy Schubert 179*206b73d0SCy Schubert len = recv(sock, buf, sizeof(buf), 0); 180*206b73d0SCy Schubert if (len < 0) { 181*206b73d0SCy Schubert wpa_printf(MSG_ERROR, "macsec_qca: recv: %s", strerror(errno)); 182*206b73d0SCy Schubert return; 183*206b73d0SCy Schubert } 184*206b73d0SCy Schubert 185*206b73d0SCy Schubert macsec_qca_handle_data(eloop_ctx, buf, len); 186*206b73d0SCy Schubert } 187*206b73d0SCy Schubert 188*206b73d0SCy Schubert #endif /* __linux__ */ 189*206b73d0SCy Schubert 190*206b73d0SCy Schubert 191*206b73d0SCy Schubert static int macsec_qca_init_sockets(struct macsec_qca_data *drv, u8 *own_addr) 192*206b73d0SCy Schubert { 193*206b73d0SCy Schubert #ifdef __linux__ 194*206b73d0SCy Schubert struct ifreq ifr; 195*206b73d0SCy Schubert struct sockaddr_ll addr; 196*206b73d0SCy Schubert 197*206b73d0SCy Schubert drv->common.sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE)); 198*206b73d0SCy Schubert if (drv->common.sock < 0) { 199*206b73d0SCy Schubert wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s", 200*206b73d0SCy Schubert strerror(errno)); 201*206b73d0SCy Schubert return -1; 202*206b73d0SCy Schubert } 203*206b73d0SCy Schubert 204*206b73d0SCy Schubert if (eloop_register_read_sock(drv->common.sock, macsec_qca_handle_read, 205*206b73d0SCy Schubert drv->common.ctx, NULL)) { 206*206b73d0SCy Schubert wpa_printf(MSG_INFO, "Could not register read socket"); 207*206b73d0SCy Schubert return -1; 208*206b73d0SCy Schubert } 209*206b73d0SCy Schubert 210*206b73d0SCy Schubert os_memset(&ifr, 0, sizeof(ifr)); 211*206b73d0SCy Schubert os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name)); 212*206b73d0SCy Schubert if (ioctl(drv->common.sock, SIOCGIFINDEX, &ifr) != 0) { 213*206b73d0SCy Schubert wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s", 214*206b73d0SCy Schubert strerror(errno)); 215*206b73d0SCy Schubert return -1; 216*206b73d0SCy Schubert } 217*206b73d0SCy Schubert 218*206b73d0SCy Schubert os_memset(&addr, 0, sizeof(addr)); 219*206b73d0SCy Schubert addr.sll_family = AF_PACKET; 220*206b73d0SCy Schubert addr.sll_ifindex = ifr.ifr_ifindex; 221*206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", 222*206b73d0SCy Schubert addr.sll_ifindex); 223*206b73d0SCy Schubert 224*206b73d0SCy Schubert if (bind(drv->common.sock, (struct sockaddr *) &addr, 225*206b73d0SCy Schubert sizeof(addr)) < 0) { 226*206b73d0SCy Schubert wpa_printf(MSG_ERROR, "macsec_qca: bind: %s", strerror(errno)); 227*206b73d0SCy Schubert return -1; 228*206b73d0SCy Schubert } 229*206b73d0SCy Schubert 230*206b73d0SCy Schubert /* filter multicast address */ 231*206b73d0SCy Schubert if (wired_multicast_membership(drv->common.sock, ifr.ifr_ifindex, 232*206b73d0SCy Schubert pae_group_addr, 1) < 0) { 233*206b73d0SCy Schubert wpa_printf(MSG_ERROR, 234*206b73d0SCy Schubert "macsec_qca_init_sockets: Failed to add multicast group membership"); 235*206b73d0SCy Schubert return -1; 236*206b73d0SCy Schubert } 237*206b73d0SCy Schubert 238*206b73d0SCy Schubert os_memset(&ifr, 0, sizeof(ifr)); 239*206b73d0SCy Schubert os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name)); 240*206b73d0SCy Schubert if (ioctl(drv->common.sock, SIOCGIFHWADDR, &ifr) != 0) { 241*206b73d0SCy Schubert wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s", 242*206b73d0SCy Schubert strerror(errno)); 243*206b73d0SCy Schubert return -1; 244*206b73d0SCy Schubert } 245*206b73d0SCy Schubert 246*206b73d0SCy Schubert if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { 247*206b73d0SCy Schubert wpa_printf(MSG_INFO, "Invalid HW-addr family 0x%04x", 248*206b73d0SCy Schubert ifr.ifr_hwaddr.sa_family); 249*206b73d0SCy Schubert return -1; 250*206b73d0SCy Schubert } 251*206b73d0SCy Schubert os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); 252*206b73d0SCy Schubert 253*206b73d0SCy Schubert return 0; 254*206b73d0SCy Schubert #else /* __linux__ */ 255*206b73d0SCy Schubert return -1; 256*206b73d0SCy Schubert #endif /* __linux__ */ 257*206b73d0SCy Schubert } 258*206b73d0SCy Schubert 259*206b73d0SCy Schubert 2605b9c547cSRui Paulo static void * macsec_qca_init(void *ctx, const char *ifname) 2615b9c547cSRui Paulo { 2625b9c547cSRui Paulo struct macsec_qca_data *drv; 2635b9c547cSRui Paulo 2645b9c547cSRui Paulo drv = os_zalloc(sizeof(*drv)); 2655b9c547cSRui Paulo if (drv == NULL) 2665b9c547cSRui Paulo return NULL; 2675b9c547cSRui Paulo 2685b9c547cSRui Paulo /* Board specific settings */ 26985732ac8SCy Schubert if (os_memcmp("eth2", ifname, 4) == 0) 2705b9c547cSRui Paulo drv->secy_id = 1; 27185732ac8SCy Schubert else if (os_memcmp("eth3", ifname, 4) == 0) 2725b9c547cSRui Paulo drv->secy_id = 2; 2735b9c547cSRui Paulo else 2745b9c547cSRui Paulo drv->secy_id = -1; 2755b9c547cSRui Paulo 27685732ac8SCy Schubert if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) { 2775b9c547cSRui Paulo os_free(drv); 2785b9c547cSRui Paulo return NULL; 2795b9c547cSRui Paulo } 2805b9c547cSRui Paulo 2815b9c547cSRui Paulo return drv; 2825b9c547cSRui Paulo } 2835b9c547cSRui Paulo 2845b9c547cSRui Paulo 2855b9c547cSRui Paulo static void macsec_qca_deinit(void *priv) 2865b9c547cSRui Paulo { 2875b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 2885b9c547cSRui Paulo 28985732ac8SCy Schubert driver_wired_deinit_common(&drv->common); 2905b9c547cSRui Paulo os_free(drv); 2915b9c547cSRui Paulo } 2925b9c547cSRui Paulo 2935b9c547cSRui Paulo 294*206b73d0SCy Schubert static void * macsec_qca_hapd_init(struct hostapd_data *hapd, 295*206b73d0SCy Schubert struct wpa_init_params *params) 296*206b73d0SCy Schubert { 297*206b73d0SCy Schubert struct macsec_qca_data *drv; 298*206b73d0SCy Schubert 299*206b73d0SCy Schubert drv = os_zalloc(sizeof(struct macsec_qca_data)); 300*206b73d0SCy Schubert if (!drv) { 301*206b73d0SCy Schubert wpa_printf(MSG_INFO, 302*206b73d0SCy Schubert "Could not allocate memory for macsec_qca driver data"); 303*206b73d0SCy Schubert return NULL; 304*206b73d0SCy Schubert } 305*206b73d0SCy Schubert 306*206b73d0SCy Schubert /* Board specific settings */ 307*206b73d0SCy Schubert if (os_memcmp("eth2", params->ifname, 4) == 0) 308*206b73d0SCy Schubert drv->secy_id = 1; 309*206b73d0SCy Schubert else if (os_memcmp("eth3", params->ifname, 4) == 0) 310*206b73d0SCy Schubert drv->secy_id = 2; 311*206b73d0SCy Schubert else if (os_memcmp("eth4", params->ifname, 4) == 0) 312*206b73d0SCy Schubert drv->secy_id = 0; 313*206b73d0SCy Schubert else if (os_memcmp("eth5", params->ifname, 4) == 0) 314*206b73d0SCy Schubert drv->secy_id = 1; 315*206b73d0SCy Schubert else 316*206b73d0SCy Schubert drv->secy_id = -1; 317*206b73d0SCy Schubert 318*206b73d0SCy Schubert drv->common.ctx = hapd; 319*206b73d0SCy Schubert os_strlcpy(drv->common.ifname, params->ifname, 320*206b73d0SCy Schubert sizeof(drv->common.ifname)); 321*206b73d0SCy Schubert drv->use_pae_group_addr = params->use_pae_group_addr; 322*206b73d0SCy Schubert 323*206b73d0SCy Schubert if (macsec_qca_init_sockets(drv, params->own_addr)) { 324*206b73d0SCy Schubert os_free(drv); 325*206b73d0SCy Schubert return NULL; 326*206b73d0SCy Schubert } 327*206b73d0SCy Schubert 328*206b73d0SCy Schubert return drv; 329*206b73d0SCy Schubert } 330*206b73d0SCy Schubert 331*206b73d0SCy Schubert 332*206b73d0SCy Schubert static void macsec_qca_hapd_deinit(void *priv) 333*206b73d0SCy Schubert { 334*206b73d0SCy Schubert struct macsec_qca_data *drv = priv; 335*206b73d0SCy Schubert 336*206b73d0SCy Schubert if (drv->common.sock >= 0) { 337*206b73d0SCy Schubert eloop_unregister_read_sock(drv->common.sock); 338*206b73d0SCy Schubert close(drv->common.sock); 339*206b73d0SCy Schubert } 340*206b73d0SCy Schubert 341*206b73d0SCy Schubert os_free(drv); 342*206b73d0SCy Schubert } 343*206b73d0SCy Schubert 344*206b73d0SCy Schubert 345*206b73d0SCy Schubert static int macsec_qca_send_eapol(void *priv, const u8 *addr, 346*206b73d0SCy Schubert const u8 *data, size_t data_len, int encrypt, 347*206b73d0SCy Schubert const u8 *own_addr, u32 flags) 348*206b73d0SCy Schubert { 349*206b73d0SCy Schubert struct macsec_qca_data *drv = priv; 350*206b73d0SCy Schubert struct ieee8023_hdr *hdr; 351*206b73d0SCy Schubert size_t len; 352*206b73d0SCy Schubert u8 *pos; 353*206b73d0SCy Schubert int res; 354*206b73d0SCy Schubert 355*206b73d0SCy Schubert len = sizeof(*hdr) + data_len; 356*206b73d0SCy Schubert hdr = os_zalloc(len); 357*206b73d0SCy Schubert if (!hdr) { 358*206b73d0SCy Schubert wpa_printf(MSG_INFO, 359*206b73d0SCy Schubert "malloc() failed for macsec_qca_send_eapol(len=%lu)", 360*206b73d0SCy Schubert (unsigned long) len); 361*206b73d0SCy Schubert return -1; 362*206b73d0SCy Schubert } 363*206b73d0SCy Schubert 364*206b73d0SCy Schubert os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr, 365*206b73d0SCy Schubert ETH_ALEN); 366*206b73d0SCy Schubert os_memcpy(hdr->src, own_addr, ETH_ALEN); 367*206b73d0SCy Schubert hdr->ethertype = htons(ETH_P_PAE); 368*206b73d0SCy Schubert 369*206b73d0SCy Schubert pos = (u8 *) (hdr + 1); 370*206b73d0SCy Schubert os_memcpy(pos, data, data_len); 371*206b73d0SCy Schubert 372*206b73d0SCy Schubert res = send(drv->common.sock, (u8 *) hdr, len, 0); 373*206b73d0SCy Schubert os_free(hdr); 374*206b73d0SCy Schubert 375*206b73d0SCy Schubert if (res < 0) { 376*206b73d0SCy Schubert wpa_printf(MSG_ERROR, 377*206b73d0SCy Schubert "macsec_qca_send_eapol - packet len: %lu - failed: send: %s", 378*206b73d0SCy Schubert (unsigned long) len, strerror(errno)); 379*206b73d0SCy Schubert } 380*206b73d0SCy Schubert 381*206b73d0SCy Schubert return res; 382*206b73d0SCy Schubert } 383*206b73d0SCy Schubert 384*206b73d0SCy Schubert 3855b9c547cSRui Paulo static int macsec_qca_macsec_init(void *priv, struct macsec_init_params *params) 3865b9c547cSRui Paulo { 3875b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 3885b9c547cSRui Paulo 3895b9c547cSRui Paulo drv->always_include_sci = params->always_include_sci; 3905b9c547cSRui Paulo drv->use_es = params->use_es; 3915b9c547cSRui Paulo drv->use_scb = params->use_scb; 3925b9c547cSRui Paulo 3935b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: es=%d, scb=%d, sci=%d", 3945b9c547cSRui Paulo __func__, drv->use_es, drv->use_scb, 3955b9c547cSRui Paulo drv->always_include_sci); 3965b9c547cSRui Paulo 3975b9c547cSRui Paulo __macsec_drv_init(drv); 3985b9c547cSRui Paulo 3995b9c547cSRui Paulo return 0; 4005b9c547cSRui Paulo } 4015b9c547cSRui Paulo 4025b9c547cSRui Paulo 4035b9c547cSRui Paulo static int macsec_qca_macsec_deinit(void *priv) 4045b9c547cSRui Paulo { 4055b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 4065b9c547cSRui Paulo 4075b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s", __func__); 4085b9c547cSRui Paulo 4095b9c547cSRui Paulo __macsec_drv_deinit(drv); 4105b9c547cSRui Paulo 4115b9c547cSRui Paulo return 0; 4125b9c547cSRui Paulo } 4135b9c547cSRui Paulo 4145b9c547cSRui Paulo 41585732ac8SCy Schubert static int macsec_qca_get_capability(void *priv, enum macsec_cap *cap) 41685732ac8SCy Schubert { 41785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s", __func__); 41885732ac8SCy Schubert 41985732ac8SCy Schubert *cap = MACSEC_CAP_INTEG_AND_CONF_0_30_50; 42085732ac8SCy Schubert 42185732ac8SCy Schubert return 0; 42285732ac8SCy Schubert } 42385732ac8SCy Schubert 42485732ac8SCy Schubert 4255b9c547cSRui Paulo static int macsec_qca_enable_protect_frames(void *priv, Boolean enabled) 4265b9c547cSRui Paulo { 4275b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 4285b9c547cSRui Paulo int ret = 0; 4295b9c547cSRui Paulo 4305b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); 4315b9c547cSRui Paulo 4325b9c547cSRui Paulo drv->protect_frames = enabled; 4335b9c547cSRui Paulo 4345b9c547cSRui Paulo return ret; 4355b9c547cSRui Paulo } 4365b9c547cSRui Paulo 4375b9c547cSRui Paulo 4385b9c547cSRui Paulo static int macsec_qca_set_replay_protect(void *priv, Boolean enabled, 4395b9c547cSRui Paulo unsigned int window) 4405b9c547cSRui Paulo { 4415b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 4425b9c547cSRui Paulo int ret = 0; 4435b9c547cSRui Paulo 4445b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: enabled=%d, win=%u", 4455b9c547cSRui Paulo __func__, enabled, window); 4465b9c547cSRui Paulo 4475b9c547cSRui Paulo drv->replay_protect = enabled; 4485b9c547cSRui Paulo drv->replay_window = window; 4495b9c547cSRui Paulo 4505b9c547cSRui Paulo return ret; 4515b9c547cSRui Paulo } 4525b9c547cSRui Paulo 4535b9c547cSRui Paulo 45485732ac8SCy Schubert static fal_cipher_suite_e macsec_qca_cs_type_get(u64 cs) 45585732ac8SCy Schubert { 45685732ac8SCy Schubert if (cs == CS_ID_GCM_AES_128) 45785732ac8SCy Schubert return FAL_CIPHER_SUITE_AES_GCM_128; 45885732ac8SCy Schubert if (cs == CS_ID_GCM_AES_256) 45985732ac8SCy Schubert return FAL_CIPHER_SUITE_AES_GCM_256; 46085732ac8SCy Schubert return FAL_CIPHER_SUITE_MAX; 46185732ac8SCy Schubert } 46285732ac8SCy Schubert 46385732ac8SCy Schubert 464780fb4a2SCy Schubert static int macsec_qca_set_current_cipher_suite(void *priv, u64 cs) 4655b9c547cSRui Paulo { 46685732ac8SCy Schubert struct macsec_qca_data *drv = priv; 46785732ac8SCy Schubert fal_cipher_suite_e cs_type; 46885732ac8SCy Schubert 46985732ac8SCy Schubert if (cs != CS_ID_GCM_AES_128 && cs != CS_ID_GCM_AES_256) { 470780fb4a2SCy Schubert wpa_printf(MSG_ERROR, 471780fb4a2SCy Schubert "%s: NOT supported CipherSuite: %016" PRIx64, 472780fb4a2SCy Schubert __func__, cs); 4735b9c547cSRui Paulo return -1; 4745b9c547cSRui Paulo } 4755b9c547cSRui Paulo 47685732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: CipherSuite: %016" PRIx64, __func__, cs); 4775b9c547cSRui Paulo 47885732ac8SCy Schubert cs_type = macsec_qca_cs_type_get(cs); 47985732ac8SCy Schubert return nss_macsec_secy_cipher_suite_set(drv->secy_id, cs_type); 4805b9c547cSRui Paulo } 4815b9c547cSRui Paulo 4825b9c547cSRui Paulo 4835b9c547cSRui Paulo static int macsec_qca_enable_controlled_port(void *priv, Boolean enabled) 4845b9c547cSRui Paulo { 4855b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 4865b9c547cSRui Paulo int ret = 0; 4875b9c547cSRui Paulo 4885b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: enable=%d", __func__, enabled); 4895b9c547cSRui Paulo 4905b9c547cSRui Paulo ret += nss_macsec_secy_controlled_port_en_set(drv->secy_id, enabled); 4915b9c547cSRui Paulo 4925b9c547cSRui Paulo return ret; 4935b9c547cSRui Paulo } 4945b9c547cSRui Paulo 4955b9c547cSRui Paulo 49685732ac8SCy Schubert static int macsec_qca_lookup_channel(struct channel_map *map, 49785732ac8SCy Schubert struct ieee802_1x_mka_sci *sci, 49885732ac8SCy Schubert u32 *channel) 49985732ac8SCy Schubert { 50085732ac8SCy Schubert u32 i; 50185732ac8SCy Schubert 50285732ac8SCy Schubert for (i = 0; i < MAXSC; i++) { 50385732ac8SCy Schubert if (os_memcmp(&map[i].sci, sci, 50485732ac8SCy Schubert sizeof(struct ieee802_1x_mka_sci)) == 0) { 50585732ac8SCy Schubert *channel = i; 50685732ac8SCy Schubert return 0; 50785732ac8SCy Schubert } 50885732ac8SCy Schubert } 50985732ac8SCy Schubert 51085732ac8SCy Schubert return -1; 51185732ac8SCy Schubert } 51285732ac8SCy Schubert 51385732ac8SCy Schubert 51485732ac8SCy Schubert static void macsec_qca_register_channel(struct channel_map *map, 51585732ac8SCy Schubert struct ieee802_1x_mka_sci *sci, 51685732ac8SCy Schubert u32 channel) 51785732ac8SCy Schubert { 51885732ac8SCy Schubert os_memcpy(&map[channel].sci, sci, sizeof(struct ieee802_1x_mka_sci)); 51985732ac8SCy Schubert } 52085732ac8SCy Schubert 52185732ac8SCy Schubert 52285732ac8SCy Schubert static int macsec_qca_lookup_receive_channel(struct macsec_qca_data *drv, 52385732ac8SCy Schubert struct receive_sc *sc, 52485732ac8SCy Schubert u32 *channel) 52585732ac8SCy Schubert { 52685732ac8SCy Schubert return macsec_qca_lookup_channel(drv->receive_channel_map, &sc->sci, 52785732ac8SCy Schubert channel); 52885732ac8SCy Schubert } 52985732ac8SCy Schubert 53085732ac8SCy Schubert 53185732ac8SCy Schubert static void macsec_qca_register_receive_channel(struct macsec_qca_data *drv, 53285732ac8SCy Schubert struct receive_sc *sc, 53385732ac8SCy Schubert u32 channel) 53485732ac8SCy Schubert { 53585732ac8SCy Schubert macsec_qca_register_channel(drv->receive_channel_map, &sc->sci, 53685732ac8SCy Schubert channel); 53785732ac8SCy Schubert } 53885732ac8SCy Schubert 53985732ac8SCy Schubert 54085732ac8SCy Schubert static int macsec_qca_lookup_transmit_channel(struct macsec_qca_data *drv, 54185732ac8SCy Schubert struct transmit_sc *sc, 54285732ac8SCy Schubert u32 *channel) 54385732ac8SCy Schubert { 54485732ac8SCy Schubert return macsec_qca_lookup_channel(drv->transmit_channel_map, &sc->sci, 54585732ac8SCy Schubert channel); 54685732ac8SCy Schubert } 54785732ac8SCy Schubert 54885732ac8SCy Schubert 54985732ac8SCy Schubert static void macsec_qca_register_transmit_channel(struct macsec_qca_data *drv, 55085732ac8SCy Schubert struct transmit_sc *sc, 55185732ac8SCy Schubert u32 channel) 55285732ac8SCy Schubert { 55385732ac8SCy Schubert macsec_qca_register_channel(drv->transmit_channel_map, &sc->sci, 55485732ac8SCy Schubert channel); 55585732ac8SCy Schubert } 55685732ac8SCy Schubert 55785732ac8SCy Schubert 55885732ac8SCy Schubert static int macsec_qca_get_receive_lowest_pn(void *priv, struct receive_sa *sa) 5595b9c547cSRui Paulo { 5605b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 5615b9c547cSRui Paulo int ret = 0; 5625b9c547cSRui Paulo u32 next_pn = 0; 5635b9c547cSRui Paulo bool enabled = FALSE; 5645b9c547cSRui Paulo u32 win; 56585732ac8SCy Schubert u32 channel; 5665b9c547cSRui Paulo 56785732ac8SCy Schubert ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel); 56885732ac8SCy Schubert if (ret != 0) 56985732ac8SCy Schubert return ret; 57085732ac8SCy Schubert 57185732ac8SCy Schubert ret += nss_macsec_secy_rx_sa_next_pn_get(drv->secy_id, channel, sa->an, 5725b9c547cSRui Paulo &next_pn); 5735b9c547cSRui Paulo ret += nss_macsec_secy_rx_sc_replay_protect_get(drv->secy_id, channel, 5745b9c547cSRui Paulo &enabled); 5755b9c547cSRui Paulo ret += nss_macsec_secy_rx_sc_anti_replay_window_get(drv->secy_id, 5765b9c547cSRui Paulo channel, &win); 5775b9c547cSRui Paulo 5785b9c547cSRui Paulo if (enabled) 57985732ac8SCy Schubert sa->lowest_pn = (next_pn > win) ? (next_pn - win) : 1; 5805b9c547cSRui Paulo else 58185732ac8SCy Schubert sa->lowest_pn = next_pn; 5825b9c547cSRui Paulo 58385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: lpn=0x%x", __func__, sa->lowest_pn); 5845b9c547cSRui Paulo 5855b9c547cSRui Paulo return ret; 5865b9c547cSRui Paulo } 5875b9c547cSRui Paulo 5885b9c547cSRui Paulo 58985732ac8SCy Schubert static int macsec_qca_get_transmit_next_pn(void *priv, struct transmit_sa *sa) 5905b9c547cSRui Paulo { 5915b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 5925b9c547cSRui Paulo int ret = 0; 59385732ac8SCy Schubert u32 channel; 5945b9c547cSRui Paulo 59585732ac8SCy Schubert ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel); 59685732ac8SCy Schubert if (ret != 0) 59785732ac8SCy Schubert return ret; 5985b9c547cSRui Paulo 59985732ac8SCy Schubert ret += nss_macsec_secy_tx_sa_next_pn_get(drv->secy_id, channel, sa->an, 60085732ac8SCy Schubert &sa->next_pn); 60185732ac8SCy Schubert 60285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: npn=0x%x", __func__, sa->next_pn); 6035b9c547cSRui Paulo 6045b9c547cSRui Paulo return ret; 6055b9c547cSRui Paulo } 6065b9c547cSRui Paulo 6075b9c547cSRui Paulo 60885732ac8SCy Schubert static int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa) 6095b9c547cSRui Paulo { 6105b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 6115b9c547cSRui Paulo int ret = 0; 61285732ac8SCy Schubert u32 channel; 6135b9c547cSRui Paulo 61485732ac8SCy Schubert ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel); 61585732ac8SCy Schubert if (ret != 0) 61685732ac8SCy Schubert return ret; 6175b9c547cSRui Paulo 61885732ac8SCy Schubert ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an, 61985732ac8SCy Schubert sa->next_pn); 62085732ac8SCy Schubert 62185732ac8SCy Schubert wpa_printf(MSG_INFO, "%s: npn=0x%x", __func__, sa->next_pn); 6225b9c547cSRui Paulo 6235b9c547cSRui Paulo return ret; 6245b9c547cSRui Paulo } 6255b9c547cSRui Paulo 6265b9c547cSRui Paulo 6275b9c547cSRui Paulo static int macsec_qca_get_available_receive_sc(void *priv, u32 *channel) 6285b9c547cSRui Paulo { 6295b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 6305b9c547cSRui Paulo int ret = 0; 6315b9c547cSRui Paulo u32 sc_ch = 0; 6325b9c547cSRui Paulo bool in_use = FALSE; 6335b9c547cSRui Paulo 6345b9c547cSRui Paulo for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) { 6355b9c547cSRui Paulo ret = nss_macsec_secy_rx_sc_in_used_get(drv->secy_id, sc_ch, 6365b9c547cSRui Paulo &in_use); 6375b9c547cSRui Paulo if (ret) 6385b9c547cSRui Paulo continue; 6395b9c547cSRui Paulo 6405b9c547cSRui Paulo if (!in_use) { 6415b9c547cSRui Paulo *channel = sc_ch; 6425b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: channel=%d", 6435b9c547cSRui Paulo __func__, *channel); 6445b9c547cSRui Paulo return 0; 6455b9c547cSRui Paulo } 6465b9c547cSRui Paulo } 6475b9c547cSRui Paulo 6485b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: no available channel", __func__); 6495b9c547cSRui Paulo 6505b9c547cSRui Paulo return -1; 6515b9c547cSRui Paulo } 6525b9c547cSRui Paulo 6535b9c547cSRui Paulo 65485732ac8SCy Schubert static int macsec_qca_create_receive_sc(void *priv, struct receive_sc *sc, 6555b9c547cSRui Paulo unsigned int conf_offset, 6565b9c547cSRui Paulo int validation) 6575b9c547cSRui Paulo { 6585b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 6595b9c547cSRui Paulo int ret = 0; 6605b9c547cSRui Paulo fal_rx_prc_lut_t entry; 6615b9c547cSRui Paulo fal_rx_sc_validate_frame_e vf; 6625b9c547cSRui Paulo enum validate_frames validate_frames = validation; 66385732ac8SCy Schubert u32 channel; 66485732ac8SCy Schubert const u8 *sci_addr = sc->sci.addr; 66585732ac8SCy Schubert u16 sci_port = be_to_host16(sc->sci.port); 66685732ac8SCy Schubert 66785732ac8SCy Schubert ret = macsec_qca_get_available_receive_sc(priv, &channel); 66885732ac8SCy Schubert if (ret != 0) 66985732ac8SCy Schubert return ret; 6705b9c547cSRui Paulo 6715b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel); 6725b9c547cSRui Paulo 6735b9c547cSRui Paulo /* rx prc lut */ 6745b9c547cSRui Paulo os_memset(&entry, 0, sizeof(entry)); 6755b9c547cSRui Paulo 6765b9c547cSRui Paulo os_memcpy(entry.sci, sci_addr, ETH_ALEN); 67785732ac8SCy Schubert entry.sci[6] = (sci_port >> 8) & 0xff; 67885732ac8SCy Schubert entry.sci[7] = sci_port & 0xff; 6795b9c547cSRui Paulo entry.sci_mask = 0xf; 6805b9c547cSRui Paulo 6815b9c547cSRui Paulo entry.valid = 1; 6825b9c547cSRui Paulo entry.channel = channel; 6835b9c547cSRui Paulo entry.action = FAL_RX_PRC_ACTION_PROCESS; 6845b9c547cSRui Paulo entry.offset = conf_offset; 6855b9c547cSRui Paulo 6865b9c547cSRui Paulo /* rx validate frame */ 6875b9c547cSRui Paulo if (validate_frames == Strict) 6885b9c547cSRui Paulo vf = FAL_RX_SC_VALIDATE_FRAME_STRICT; 6895b9c547cSRui Paulo else if (validate_frames == Checked) 6905b9c547cSRui Paulo vf = FAL_RX_SC_VALIDATE_FRAME_CHECK; 6915b9c547cSRui Paulo else 6925b9c547cSRui Paulo vf = FAL_RX_SC_VALIDATE_FRAME_DISABLED; 6935b9c547cSRui Paulo 6945b9c547cSRui Paulo ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry); 6955b9c547cSRui Paulo ret += nss_macsec_secy_rx_sc_create(drv->secy_id, channel); 6965b9c547cSRui Paulo ret += nss_macsec_secy_rx_sc_validate_frame_set(drv->secy_id, channel, 6975b9c547cSRui Paulo vf); 6985b9c547cSRui Paulo ret += nss_macsec_secy_rx_sc_replay_protect_set(drv->secy_id, channel, 6995b9c547cSRui Paulo drv->replay_protect); 7005b9c547cSRui Paulo ret += nss_macsec_secy_rx_sc_anti_replay_window_set(drv->secy_id, 7015b9c547cSRui Paulo channel, 7025b9c547cSRui Paulo drv->replay_window); 7035b9c547cSRui Paulo 70485732ac8SCy Schubert macsec_qca_register_receive_channel(drv, sc, channel); 70585732ac8SCy Schubert 7065b9c547cSRui Paulo return ret; 7075b9c547cSRui Paulo } 7085b9c547cSRui Paulo 7095b9c547cSRui Paulo 71085732ac8SCy Schubert static int macsec_qca_delete_receive_sc(void *priv, struct receive_sc *sc) 7115b9c547cSRui Paulo { 7125b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 71385732ac8SCy Schubert int ret; 7145b9c547cSRui Paulo fal_rx_prc_lut_t entry; 71585732ac8SCy Schubert u32 channel; 71685732ac8SCy Schubert 71785732ac8SCy Schubert ret = macsec_qca_lookup_receive_channel(priv, sc, &channel); 71885732ac8SCy Schubert if (ret != 0) 71985732ac8SCy Schubert return ret; 7205b9c547cSRui Paulo 7215b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel); 7225b9c547cSRui Paulo 7235b9c547cSRui Paulo /* rx prc lut */ 7245b9c547cSRui Paulo os_memset(&entry, 0, sizeof(entry)); 7255b9c547cSRui Paulo 7265b9c547cSRui Paulo ret += nss_macsec_secy_rx_sc_del(drv->secy_id, channel); 7275b9c547cSRui Paulo ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry); 7285b9c547cSRui Paulo 7295b9c547cSRui Paulo return ret; 7305b9c547cSRui Paulo } 7315b9c547cSRui Paulo 7325b9c547cSRui Paulo 73385732ac8SCy Schubert static int macsec_qca_create_receive_sa(void *priv, struct receive_sa *sa) 7345b9c547cSRui Paulo { 7355b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 73685732ac8SCy Schubert int ret; 7375b9c547cSRui Paulo fal_rx_sak_t rx_sak; 7385b9c547cSRui Paulo int i = 0; 73985732ac8SCy Schubert u32 channel; 74085732ac8SCy Schubert fal_rx_prc_lut_t entry; 74185732ac8SCy Schubert u32 offset; 74285732ac8SCy Schubert 74385732ac8SCy Schubert ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel); 74485732ac8SCy Schubert if (ret != 0) 74585732ac8SCy Schubert return ret; 7465b9c547cSRui Paulo 7475b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s, channel=%d, an=%d, lpn=0x%x", 74885732ac8SCy Schubert __func__, channel, sa->an, sa->lowest_pn); 7495b9c547cSRui Paulo 7505b9c547cSRui Paulo os_memset(&rx_sak, 0, sizeof(rx_sak)); 75185732ac8SCy Schubert rx_sak.sak_len = sa->pkey->key_len; 75285732ac8SCy Schubert if (sa->pkey->key_len == SAK_128_LEN) { 7535b9c547cSRui Paulo for (i = 0; i < 16; i++) 75485732ac8SCy Schubert rx_sak.sak[i] = sa->pkey->key[15 - i]; 75585732ac8SCy Schubert } else if (sa->pkey->key_len == SAK_256_LEN) { 75685732ac8SCy Schubert for (i = 0; i < 16; i++) { 75785732ac8SCy Schubert rx_sak.sak1[i] = sa->pkey->key[15 - i]; 75885732ac8SCy Schubert rx_sak.sak[i] = sa->pkey->key[31 - i]; 75985732ac8SCy Schubert } 76085732ac8SCy Schubert } else { 76185732ac8SCy Schubert return -1; 76285732ac8SCy Schubert } 7635b9c547cSRui Paulo 76485732ac8SCy Schubert if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0) 76585732ac8SCy Schubert offset = 0; 76685732ac8SCy Schubert else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30) 76785732ac8SCy Schubert offset = 30; 76885732ac8SCy Schubert else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50) 76985732ac8SCy Schubert offset = 50; 77085732ac8SCy Schubert else 77185732ac8SCy Schubert return -1; 77285732ac8SCy Schubert ret += nss_macsec_secy_rx_prc_lut_get(drv->secy_id, channel, &entry); 77385732ac8SCy Schubert entry.offset = offset; 77485732ac8SCy Schubert ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry); 77585732ac8SCy Schubert ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, sa->an); 77685732ac8SCy Schubert ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, sa->an, 77785732ac8SCy Schubert &rx_sak); 7785b9c547cSRui Paulo 7795b9c547cSRui Paulo return ret; 7805b9c547cSRui Paulo } 7815b9c547cSRui Paulo 7825b9c547cSRui Paulo 78385732ac8SCy Schubert static int macsec_qca_enable_receive_sa(void *priv, struct receive_sa *sa) 7845b9c547cSRui Paulo { 7855b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 78685732ac8SCy Schubert int ret; 78785732ac8SCy Schubert u32 channel; 7885b9c547cSRui Paulo 78985732ac8SCy Schubert ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel); 79085732ac8SCy Schubert if (ret != 0) 79185732ac8SCy Schubert return ret; 7925b9c547cSRui Paulo 79385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, 79485732ac8SCy Schubert sa->an); 79585732ac8SCy Schubert 79685732ac8SCy Schubert ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an, 79785732ac8SCy Schubert TRUE); 7985b9c547cSRui Paulo 7995b9c547cSRui Paulo return ret; 8005b9c547cSRui Paulo } 8015b9c547cSRui Paulo 8025b9c547cSRui Paulo 80385732ac8SCy Schubert static int macsec_qca_disable_receive_sa(void *priv, struct receive_sa *sa) 8045b9c547cSRui Paulo { 8055b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 80685732ac8SCy Schubert int ret; 80785732ac8SCy Schubert u32 channel; 8085b9c547cSRui Paulo 80985732ac8SCy Schubert ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel); 81085732ac8SCy Schubert if (ret != 0) 81185732ac8SCy Schubert return ret; 8125b9c547cSRui Paulo 81385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, 81485732ac8SCy Schubert sa->an); 81585732ac8SCy Schubert 81685732ac8SCy Schubert ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an, 81785732ac8SCy Schubert FALSE); 8185b9c547cSRui Paulo 8195b9c547cSRui Paulo return ret; 8205b9c547cSRui Paulo } 8215b9c547cSRui Paulo 8225b9c547cSRui Paulo 8235b9c547cSRui Paulo static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel) 8245b9c547cSRui Paulo { 8255b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 8265b9c547cSRui Paulo u32 sc_ch = 0; 8275b9c547cSRui Paulo bool in_use = FALSE; 8285b9c547cSRui Paulo 8295b9c547cSRui Paulo for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) { 83085732ac8SCy Schubert if (nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch, 83185732ac8SCy Schubert &in_use)) 8325b9c547cSRui Paulo continue; 8335b9c547cSRui Paulo 8345b9c547cSRui Paulo if (!in_use) { 8355b9c547cSRui Paulo *channel = sc_ch; 8365b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: channel=%d", 8375b9c547cSRui Paulo __func__, *channel); 8385b9c547cSRui Paulo return 0; 8395b9c547cSRui Paulo } 8405b9c547cSRui Paulo } 8415b9c547cSRui Paulo 8425b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: no avaiable channel", __func__); 8435b9c547cSRui Paulo 8445b9c547cSRui Paulo return -1; 8455b9c547cSRui Paulo } 8465b9c547cSRui Paulo 8475b9c547cSRui Paulo 84885732ac8SCy Schubert static int macsec_qca_create_transmit_sc(void *priv, struct transmit_sc *sc, 8495b9c547cSRui Paulo unsigned int conf_offset) 8505b9c547cSRui Paulo { 8515b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 85285732ac8SCy Schubert int ret; 8535b9c547cSRui Paulo fal_tx_class_lut_t entry; 8545b9c547cSRui Paulo u8 psci[ETH_ALEN + 2]; 85585732ac8SCy Schubert u32 channel; 85685732ac8SCy Schubert u16 sci_port = be_to_host16(sc->sci.port); 85785732ac8SCy Schubert 85885732ac8SCy Schubert ret = macsec_qca_get_available_transmit_sc(priv, &channel); 85985732ac8SCy Schubert if (ret != 0) 86085732ac8SCy Schubert return ret; 8615b9c547cSRui Paulo 8625b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel); 8635b9c547cSRui Paulo 8645b9c547cSRui Paulo /* class lut */ 8655b9c547cSRui Paulo os_memset(&entry, 0, sizeof(entry)); 8665b9c547cSRui Paulo 8675b9c547cSRui Paulo entry.valid = 1; 8685b9c547cSRui Paulo entry.action = FAL_TX_CLASS_ACTION_FORWARD; 8695b9c547cSRui Paulo entry.channel = channel; 8705b9c547cSRui Paulo 87185732ac8SCy Schubert os_memcpy(psci, sc->sci.addr, ETH_ALEN); 87285732ac8SCy Schubert psci[6] = (sci_port >> 8) & 0xff; 87385732ac8SCy Schubert psci[7] = sci_port & 0xff; 8745b9c547cSRui Paulo 8755b9c547cSRui Paulo ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry); 8765b9c547cSRui Paulo ret += nss_macsec_secy_tx_sc_create(drv->secy_id, channel, psci, 8); 8775b9c547cSRui Paulo ret += nss_macsec_secy_tx_sc_protect_set(drv->secy_id, channel, 8785b9c547cSRui Paulo drv->protect_frames); 8795b9c547cSRui Paulo ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id, 8805b9c547cSRui Paulo channel, 8815b9c547cSRui Paulo conf_offset); 8825b9c547cSRui Paulo 88385732ac8SCy Schubert macsec_qca_register_transmit_channel(drv, sc, channel); 88485732ac8SCy Schubert 8855b9c547cSRui Paulo return ret; 8865b9c547cSRui Paulo } 8875b9c547cSRui Paulo 8885b9c547cSRui Paulo 88985732ac8SCy Schubert static int macsec_qca_delete_transmit_sc(void *priv, struct transmit_sc *sc) 8905b9c547cSRui Paulo { 8915b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 89285732ac8SCy Schubert int ret; 8935b9c547cSRui Paulo fal_tx_class_lut_t entry; 89485732ac8SCy Schubert u32 channel; 89585732ac8SCy Schubert 89685732ac8SCy Schubert ret = macsec_qca_lookup_transmit_channel(priv, sc, &channel); 89785732ac8SCy Schubert if (ret != 0) 89885732ac8SCy Schubert return ret; 8995b9c547cSRui Paulo 9005b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel); 9015b9c547cSRui Paulo 9025b9c547cSRui Paulo /* class lut */ 9035b9c547cSRui Paulo os_memset(&entry, 0, sizeof(entry)); 9045b9c547cSRui Paulo 9055b9c547cSRui Paulo ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry); 9065b9c547cSRui Paulo ret += nss_macsec_secy_tx_sc_del(drv->secy_id, channel); 9075b9c547cSRui Paulo 9085b9c547cSRui Paulo return ret; 9095b9c547cSRui Paulo } 9105b9c547cSRui Paulo 9115b9c547cSRui Paulo 91285732ac8SCy Schubert static int macsec_qca_create_transmit_sa(void *priv, struct transmit_sa *sa) 9135b9c547cSRui Paulo { 9145b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 91585732ac8SCy Schubert int ret; 9165b9c547cSRui Paulo u8 tci = 0; 9175b9c547cSRui Paulo fal_tx_sak_t tx_sak; 9185b9c547cSRui Paulo int i; 91985732ac8SCy Schubert u32 channel; 92085732ac8SCy Schubert u32 offset; 92185732ac8SCy Schubert 92285732ac8SCy Schubert ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel); 92385732ac8SCy Schubert if (ret != 0) 92485732ac8SCy Schubert return ret; 9255b9c547cSRui Paulo 9265b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 9275b9c547cSRui Paulo "%s: channel=%d, an=%d, next_pn=0x%x, confidentiality=%d", 92885732ac8SCy Schubert __func__, channel, sa->an, sa->next_pn, sa->confidentiality); 9295b9c547cSRui Paulo 9305b9c547cSRui Paulo if (drv->always_include_sci) 9315b9c547cSRui Paulo tci |= TCI_SC; 9325b9c547cSRui Paulo else if (drv->use_es) 9335b9c547cSRui Paulo tci |= TCI_ES; 9345b9c547cSRui Paulo else if (drv->use_scb) 9355b9c547cSRui Paulo tci |= TCI_SCB; 9365b9c547cSRui Paulo 93785732ac8SCy Schubert if (sa->confidentiality) 9385b9c547cSRui Paulo tci |= TCI_E | TCI_C; 9395b9c547cSRui Paulo 9405b9c547cSRui Paulo os_memset(&tx_sak, 0, sizeof(tx_sak)); 94185732ac8SCy Schubert tx_sak.sak_len = sa->pkey->key_len; 94285732ac8SCy Schubert if (sa->pkey->key_len == SAK_128_LEN) { 9435b9c547cSRui Paulo for (i = 0; i < 16; i++) 94485732ac8SCy Schubert tx_sak.sak[i] = sa->pkey->key[15 - i]; 94585732ac8SCy Schubert } else if (sa->pkey->key_len == SAK_256_LEN) { 94685732ac8SCy Schubert for (i = 0; i < 16; i++) { 94785732ac8SCy Schubert tx_sak.sak1[i] = sa->pkey->key[15 - i]; 94885732ac8SCy Schubert tx_sak.sak[i] = sa->pkey->key[31 - i]; 94985732ac8SCy Schubert } 95085732ac8SCy Schubert } else { 95185732ac8SCy Schubert return -1; 95285732ac8SCy Schubert } 9535b9c547cSRui Paulo 95485732ac8SCy Schubert if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0) 95585732ac8SCy Schubert offset = 0; 95685732ac8SCy Schubert else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30) 95785732ac8SCy Schubert offset = 30; 95885732ac8SCy Schubert else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50) 95985732ac8SCy Schubert offset = 50; 96085732ac8SCy Schubert else 96185732ac8SCy Schubert return -1; 96285732ac8SCy Schubert ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id, 96385732ac8SCy Schubert channel, 96485732ac8SCy Schubert offset); 96585732ac8SCy Schubert ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an, 96685732ac8SCy Schubert sa->next_pn); 96785732ac8SCy Schubert ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, sa->an, 96885732ac8SCy Schubert &tx_sak); 9695b9c547cSRui Paulo ret += nss_macsec_secy_tx_sc_tci_7_2_set(drv->secy_id, channel, 9705b9c547cSRui Paulo (tci >> 2)); 97185732ac8SCy Schubert ret += nss_macsec_secy_tx_sc_an_set(drv->secy_id, channel, sa->an); 9725b9c547cSRui Paulo 9735b9c547cSRui Paulo return ret; 9745b9c547cSRui Paulo } 9755b9c547cSRui Paulo 9765b9c547cSRui Paulo 97785732ac8SCy Schubert static int macsec_qca_enable_transmit_sa(void *priv, struct transmit_sa *sa) 9785b9c547cSRui Paulo { 9795b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 98085732ac8SCy Schubert int ret; 98185732ac8SCy Schubert u32 channel; 9825b9c547cSRui Paulo 98385732ac8SCy Schubert ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel); 98485732ac8SCy Schubert if (ret != 0) 98585732ac8SCy Schubert return ret; 9865b9c547cSRui Paulo 98785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, 98885732ac8SCy Schubert sa->an); 98985732ac8SCy Schubert 99085732ac8SCy Schubert ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an, 99185732ac8SCy Schubert TRUE); 9925b9c547cSRui Paulo 9935b9c547cSRui Paulo return ret; 9945b9c547cSRui Paulo } 9955b9c547cSRui Paulo 9965b9c547cSRui Paulo 99785732ac8SCy Schubert static int macsec_qca_disable_transmit_sa(void *priv, struct transmit_sa *sa) 9985b9c547cSRui Paulo { 9995b9c547cSRui Paulo struct macsec_qca_data *drv = priv; 100085732ac8SCy Schubert int ret; 100185732ac8SCy Schubert u32 channel; 10025b9c547cSRui Paulo 100385732ac8SCy Schubert ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel); 100485732ac8SCy Schubert if (ret != 0) 100585732ac8SCy Schubert return ret; 10065b9c547cSRui Paulo 100785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, 100885732ac8SCy Schubert sa->an); 100985732ac8SCy Schubert 101085732ac8SCy Schubert ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an, 101185732ac8SCy Schubert FALSE); 10125b9c547cSRui Paulo 10135b9c547cSRui Paulo return ret; 10145b9c547cSRui Paulo } 10155b9c547cSRui Paulo 10165b9c547cSRui Paulo 10175b9c547cSRui Paulo const struct wpa_driver_ops wpa_driver_macsec_qca_ops = { 10185b9c547cSRui Paulo .name = "macsec_qca", 10195b9c547cSRui Paulo .desc = "QCA MACsec Ethernet driver", 102085732ac8SCy Schubert .get_ssid = driver_wired_get_ssid, 102185732ac8SCy Schubert .get_bssid = driver_wired_get_bssid, 102285732ac8SCy Schubert .get_capa = driver_wired_get_capa, 10235b9c547cSRui Paulo .init = macsec_qca_init, 10245b9c547cSRui Paulo .deinit = macsec_qca_deinit, 1025*206b73d0SCy Schubert .hapd_init = macsec_qca_hapd_init, 1026*206b73d0SCy Schubert .hapd_deinit = macsec_qca_hapd_deinit, 1027*206b73d0SCy Schubert .hapd_send_eapol = macsec_qca_send_eapol, 10285b9c547cSRui Paulo 10295b9c547cSRui Paulo .macsec_init = macsec_qca_macsec_init, 10305b9c547cSRui Paulo .macsec_deinit = macsec_qca_macsec_deinit, 103185732ac8SCy Schubert .macsec_get_capability = macsec_qca_get_capability, 10325b9c547cSRui Paulo .enable_protect_frames = macsec_qca_enable_protect_frames, 10335b9c547cSRui Paulo .set_replay_protect = macsec_qca_set_replay_protect, 10345b9c547cSRui Paulo .set_current_cipher_suite = macsec_qca_set_current_cipher_suite, 10355b9c547cSRui Paulo .enable_controlled_port = macsec_qca_enable_controlled_port, 10365b9c547cSRui Paulo .get_receive_lowest_pn = macsec_qca_get_receive_lowest_pn, 10375b9c547cSRui Paulo .get_transmit_next_pn = macsec_qca_get_transmit_next_pn, 10385b9c547cSRui Paulo .set_transmit_next_pn = macsec_qca_set_transmit_next_pn, 10395b9c547cSRui Paulo .create_receive_sc = macsec_qca_create_receive_sc, 10405b9c547cSRui Paulo .delete_receive_sc = macsec_qca_delete_receive_sc, 10415b9c547cSRui Paulo .create_receive_sa = macsec_qca_create_receive_sa, 10425b9c547cSRui Paulo .enable_receive_sa = macsec_qca_enable_receive_sa, 10435b9c547cSRui Paulo .disable_receive_sa = macsec_qca_disable_receive_sa, 10445b9c547cSRui Paulo .create_transmit_sc = macsec_qca_create_transmit_sc, 10455b9c547cSRui Paulo .delete_transmit_sc = macsec_qca_delete_transmit_sc, 10465b9c547cSRui Paulo .create_transmit_sa = macsec_qca_create_transmit_sa, 10475b9c547cSRui Paulo .enable_transmit_sa = macsec_qca_enable_transmit_sa, 10485b9c547cSRui Paulo .disable_transmit_sa = macsec_qca_disable_transmit_sa, 10495b9c547cSRui Paulo }; 1050