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