]> git.ipfire.org Git - thirdparty/hostap.git/blob - src/drivers/driver_macsec_qca.c
mka: Pass full structures down to macsec drivers' receive SC 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, struct receive_sc *sc,
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 u32 channel = sc->channel;
614 const u8 *sci_addr = sc->sci.addr;
615 u16 sci_port = be_to_host16(sc->sci.port);
616
617 wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
618
619 /* rx prc lut */
620 os_memset(&entry, 0, sizeof(entry));
621
622 os_memcpy(entry.sci, sci_addr, ETH_ALEN);
623 entry.sci[6] = (sci_port >> 8) & 0xf;
624 entry.sci[7] = sci_port & 0xf;
625 entry.sci_mask = 0xf;
626
627 entry.valid = 1;
628 entry.channel = channel;
629 entry.action = FAL_RX_PRC_ACTION_PROCESS;
630 entry.offset = conf_offset;
631
632 /* rx validate frame */
633 if (validate_frames == Strict)
634 vf = FAL_RX_SC_VALIDATE_FRAME_STRICT;
635 else if (validate_frames == Checked)
636 vf = FAL_RX_SC_VALIDATE_FRAME_CHECK;
637 else
638 vf = FAL_RX_SC_VALIDATE_FRAME_DISABLED;
639
640 ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
641 ret += nss_macsec_secy_rx_sc_create(drv->secy_id, channel);
642 ret += nss_macsec_secy_rx_sc_validate_frame_set(drv->secy_id, channel,
643 vf);
644 ret += nss_macsec_secy_rx_sc_replay_protect_set(drv->secy_id, channel,
645 drv->replay_protect);
646 ret += nss_macsec_secy_rx_sc_anti_replay_window_set(drv->secy_id,
647 channel,
648 drv->replay_window);
649
650 return ret;
651 }
652
653
654 static int macsec_qca_delete_receive_sc(void *priv, struct receive_sc *sc)
655 {
656 struct macsec_qca_data *drv = priv;
657 int ret = 0;
658 fal_rx_prc_lut_t entry;
659 u32 channel = sc->channel;
660
661 wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
662
663 /* rx prc lut */
664 os_memset(&entry, 0, sizeof(entry));
665
666 ret += nss_macsec_secy_rx_sc_del(drv->secy_id, channel);
667 ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
668
669 return ret;
670 }
671
672
673 static int macsec_qca_create_receive_sa(void *priv, struct receive_sa *sa)
674 {
675 struct macsec_qca_data *drv = priv;
676 int ret = 0;
677 fal_rx_sak_t rx_sak;
678 int i = 0;
679 u32 channel = sa->sc->channel;
680
681 wpa_printf(MSG_DEBUG, "%s, channel=%d, an=%d, lpn=0x%x",
682 __func__, channel, sa->an, sa->lowest_pn);
683
684 os_memset(&rx_sak, 0, sizeof(rx_sak));
685 for (i = 0; i < 16; i++)
686 rx_sak.sak[i] = sa->pkey->key[15 - i];
687
688 ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, sa->an);
689 ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, sa->an,
690 &rx_sak);
691
692 return ret;
693 }
694
695
696 static int macsec_qca_enable_receive_sa(void *priv, struct receive_sa *sa)
697 {
698 struct macsec_qca_data *drv = priv;
699 int ret = 0;
700 u32 channel = sa->sc->channel;
701
702
703 wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
704 sa->an);
705
706 ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
707 TRUE);
708
709 return ret;
710 }
711
712
713 static int macsec_qca_disable_receive_sa(void *priv, struct receive_sa *sa)
714 {
715 struct macsec_qca_data *drv = priv;
716 int ret = 0;
717 u32 channel = sa->sc->channel;
718
719 wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
720 sa->an);
721
722 ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
723 FALSE);
724
725 return ret;
726 }
727
728
729 static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel)
730 {
731 struct macsec_qca_data *drv = priv;
732 int ret = 0;
733 u32 sc_ch = 0;
734 bool in_use = FALSE;
735
736 for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
737 ret = nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch,
738 &in_use);
739 if (ret)
740 continue;
741
742 if (!in_use) {
743 *channel = sc_ch;
744 wpa_printf(MSG_DEBUG, "%s: channel=%d",
745 __func__, *channel);
746 return 0;
747 }
748 }
749
750 wpa_printf(MSG_DEBUG, "%s: no avaiable channel", __func__);
751
752 return -1;
753 }
754
755
756 static int macsec_qca_create_transmit_sc(void *priv, struct transmit_sc *sc,
757 unsigned int conf_offset)
758 {
759 struct macsec_qca_data *drv = priv;
760 int ret = 0;
761 fal_tx_class_lut_t entry;
762 u8 psci[ETH_ALEN + 2];
763 u32 channel = sc->channel;
764
765 wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
766
767 /* class lut */
768 os_memset(&entry, 0, sizeof(entry));
769
770 entry.valid = 1;
771 entry.action = FAL_TX_CLASS_ACTION_FORWARD;
772 entry.channel = channel;
773
774 os_memcpy(psci, sc->sci.addr, ETH_ALEN);
775 psci[6] = (sc->sci.port >> 8) & 0xf;
776 psci[7] = sc->sci.port & 0xf;
777
778 ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
779 ret += nss_macsec_secy_tx_sc_create(drv->secy_id, channel, psci, 8);
780 ret += nss_macsec_secy_tx_sc_protect_set(drv->secy_id, channel,
781 drv->protect_frames);
782 ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
783 channel,
784 conf_offset);
785
786 return ret;
787 }
788
789
790 static int macsec_qca_delete_transmit_sc(void *priv, struct transmit_sc *sc)
791 {
792 struct macsec_qca_data *drv = priv;
793 int ret = 0;
794 fal_tx_class_lut_t entry;
795 u32 channel = sc->channel;
796
797 wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
798
799 /* class lut */
800 os_memset(&entry, 0, sizeof(entry));
801
802 ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
803 ret += nss_macsec_secy_tx_sc_del(drv->secy_id, channel);
804
805 return ret;
806 }
807
808
809 static int macsec_qca_create_transmit_sa(void *priv, struct transmit_sa *sa)
810 {
811 struct macsec_qca_data *drv = priv;
812 int ret = 0;
813 u8 tci = 0;
814 fal_tx_sak_t tx_sak;
815 int i;
816 u32 channel = sa->sc->channel;
817
818 wpa_printf(MSG_DEBUG,
819 "%s: channel=%d, an=%d, next_pn=0x%x, confidentiality=%d",
820 __func__, channel, sa->an, sa->next_pn, sa->confidentiality);
821
822 if (drv->always_include_sci)
823 tci |= TCI_SC;
824 else if (drv->use_es)
825 tci |= TCI_ES;
826 else if (drv->use_scb)
827 tci |= TCI_SCB;
828
829 if (sa->confidentiality)
830 tci |= TCI_E | TCI_C;
831
832 os_memset(&tx_sak, 0, sizeof(tx_sak));
833 for (i = 0; i < 16; i++)
834 tx_sak.sak[i] = sa->pkey->key[15 - i];
835
836 ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
837 sa->next_pn);
838 ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, sa->an,
839 &tx_sak);
840 ret += nss_macsec_secy_tx_sc_tci_7_2_set(drv->secy_id, channel,
841 (tci >> 2));
842 ret += nss_macsec_secy_tx_sc_an_set(drv->secy_id, channel, sa->an);
843
844 return ret;
845 }
846
847
848 static int macsec_qca_enable_transmit_sa(void *priv, struct transmit_sa *sa)
849 {
850 struct macsec_qca_data *drv = priv;
851 int ret = 0;
852 u32 channel = sa->sc->channel;
853
854
855 wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
856 sa->an);
857
858 ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
859 TRUE);
860
861 return ret;
862 }
863
864
865 static int macsec_qca_disable_transmit_sa(void *priv, struct transmit_sa *sa)
866 {
867 struct macsec_qca_data *drv = priv;
868 int ret = 0;
869 u32 channel = sa->sc->channel;
870
871 wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
872 sa->an);
873
874 ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
875 FALSE);
876
877 return ret;
878 }
879
880
881 const struct wpa_driver_ops wpa_driver_macsec_qca_ops = {
882 .name = "macsec_qca",
883 .desc = "QCA MACsec Ethernet driver",
884 .get_ssid = macsec_qca_get_ssid,
885 .get_bssid = macsec_qca_get_bssid,
886 .get_capa = macsec_qca_get_capa,
887 .init = macsec_qca_init,
888 .deinit = macsec_qca_deinit,
889
890 .macsec_init = macsec_qca_macsec_init,
891 .macsec_deinit = macsec_qca_macsec_deinit,
892 .enable_protect_frames = macsec_qca_enable_protect_frames,
893 .set_replay_protect = macsec_qca_set_replay_protect,
894 .set_current_cipher_suite = macsec_qca_set_current_cipher_suite,
895 .enable_controlled_port = macsec_qca_enable_controlled_port,
896 .get_receive_lowest_pn = macsec_qca_get_receive_lowest_pn,
897 .get_transmit_next_pn = macsec_qca_get_transmit_next_pn,
898 .set_transmit_next_pn = macsec_qca_set_transmit_next_pn,
899 .get_available_receive_sc = macsec_qca_get_available_receive_sc,
900 .create_receive_sc = macsec_qca_create_receive_sc,
901 .delete_receive_sc = macsec_qca_delete_receive_sc,
902 .create_receive_sa = macsec_qca_create_receive_sa,
903 .enable_receive_sa = macsec_qca_enable_receive_sa,
904 .disable_receive_sa = macsec_qca_disable_receive_sa,
905 .get_available_transmit_sc = macsec_qca_get_available_transmit_sc,
906 .create_transmit_sc = macsec_qca_create_transmit_sc,
907 .delete_transmit_sc = macsec_qca_delete_transmit_sc,
908 .create_transmit_sa = macsec_qca_create_transmit_sa,
909 .enable_transmit_sa = macsec_qca_enable_transmit_sa,
910 .disable_transmit_sa = macsec_qca_disable_transmit_sa,
911 };