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