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