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