]> git.ipfire.org Git - thirdparty/hostap.git/blob - src/drivers/driver_macsec_qca.c
mka: Add driver op to get macsec capabilities
[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_get_capability(void *priv, enum macsec_cap *cap)
462 {
463 wpa_printf(MSG_DEBUG, "%s", __func__);
464
465 *cap = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
466
467 return 0;
468 }
469
470
471 static int macsec_qca_enable_protect_frames(void *priv, Boolean enabled)
472 {
473 struct macsec_qca_data *drv = priv;
474 int ret = 0;
475
476 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
477
478 drv->protect_frames = enabled;
479
480 return ret;
481 }
482
483
484 static int macsec_qca_set_replay_protect(void *priv, Boolean enabled,
485 unsigned int window)
486 {
487 struct macsec_qca_data *drv = priv;
488 int ret = 0;
489
490 wpa_printf(MSG_DEBUG, "%s: enabled=%d, win=%u",
491 __func__, enabled, window);
492
493 drv->replay_protect = enabled;
494 drv->replay_window = window;
495
496 return ret;
497 }
498
499
500 static int macsec_qca_set_current_cipher_suite(void *priv, u64 cs)
501 {
502 if (cs != CS_ID_GCM_AES_128) {
503 wpa_printf(MSG_ERROR,
504 "%s: NOT supported CipherSuite: %016" PRIx64,
505 __func__, cs);
506 return -1;
507 }
508
509 /* Support default Cipher Suite 0080020001000001 (GCM-AES-128) */
510 wpa_printf(MSG_DEBUG, "%s: default support aes-gcm-128", __func__);
511
512 return 0;
513 }
514
515
516 static int macsec_qca_enable_controlled_port(void *priv, Boolean enabled)
517 {
518 struct macsec_qca_data *drv = priv;
519 int ret = 0;
520
521 wpa_printf(MSG_DEBUG, "%s: enable=%d", __func__, enabled);
522
523 ret += nss_macsec_secy_controlled_port_en_set(drv->secy_id, enabled);
524
525 return ret;
526 }
527
528
529 static int macsec_qca_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
530 {
531 struct macsec_qca_data *drv = priv;
532 int ret = 0;
533 u32 next_pn = 0;
534 bool enabled = FALSE;
535 u32 win;
536 u32 channel = sa->sc->channel;
537
538 ret += nss_macsec_secy_rx_sa_next_pn_get(drv->secy_id, channel, sa->an,
539 &next_pn);
540 ret += nss_macsec_secy_rx_sc_replay_protect_get(drv->secy_id, channel,
541 &enabled);
542 ret += nss_macsec_secy_rx_sc_anti_replay_window_get(drv->secy_id,
543 channel, &win);
544
545 if (enabled)
546 sa->lowest_pn = (next_pn > win) ? (next_pn - win) : 1;
547 else
548 sa->lowest_pn = next_pn;
549
550 wpa_printf(MSG_DEBUG, "%s: lpn=0x%x", __func__, sa->lowest_pn);
551
552 return ret;
553 }
554
555
556 static int macsec_qca_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
557 {
558 struct macsec_qca_data *drv = priv;
559 int ret = 0;
560 u32 channel = sa->sc->channel;
561
562 ret += nss_macsec_secy_tx_sa_next_pn_get(drv->secy_id, channel, sa->an,
563 &sa->next_pn);
564
565 wpa_printf(MSG_DEBUG, "%s: npn=0x%x", __func__, sa->next_pn);
566
567 return ret;
568 }
569
570
571 int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
572 {
573 struct macsec_qca_data *drv = priv;
574 int ret = 0;
575 u32 channel = sa->sc->channel;
576
577
578 ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
579 sa->next_pn);
580
581 wpa_printf(MSG_INFO, "%s: npn=0x%x", __func__, sa->next_pn);
582
583 return ret;
584 }
585
586
587 static int macsec_qca_get_available_receive_sc(void *priv, u32 *channel)
588 {
589 struct macsec_qca_data *drv = priv;
590 int ret = 0;
591 u32 sc_ch = 0;
592 bool in_use = FALSE;
593
594 for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
595 ret = nss_macsec_secy_rx_sc_in_used_get(drv->secy_id, sc_ch,
596 &in_use);
597 if (ret)
598 continue;
599
600 if (!in_use) {
601 *channel = sc_ch;
602 wpa_printf(MSG_DEBUG, "%s: channel=%d",
603 __func__, *channel);
604 return 0;
605 }
606 }
607
608 wpa_printf(MSG_DEBUG, "%s: no available channel", __func__);
609
610 return -1;
611 }
612
613
614 static int macsec_qca_create_receive_sc(void *priv, struct receive_sc *sc,
615 unsigned int conf_offset,
616 int validation)
617 {
618 struct macsec_qca_data *drv = priv;
619 int ret = 0;
620 fal_rx_prc_lut_t entry;
621 fal_rx_sc_validate_frame_e vf;
622 enum validate_frames validate_frames = validation;
623 u32 channel = sc->channel;
624 const u8 *sci_addr = sc->sci.addr;
625 u16 sci_port = be_to_host16(sc->sci.port);
626
627 wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
628
629 /* rx prc lut */
630 os_memset(&entry, 0, sizeof(entry));
631
632 os_memcpy(entry.sci, sci_addr, ETH_ALEN);
633 entry.sci[6] = (sci_port >> 8) & 0xf;
634 entry.sci[7] = sci_port & 0xf;
635 entry.sci_mask = 0xf;
636
637 entry.valid = 1;
638 entry.channel = channel;
639 entry.action = FAL_RX_PRC_ACTION_PROCESS;
640 entry.offset = conf_offset;
641
642 /* rx validate frame */
643 if (validate_frames == Strict)
644 vf = FAL_RX_SC_VALIDATE_FRAME_STRICT;
645 else if (validate_frames == Checked)
646 vf = FAL_RX_SC_VALIDATE_FRAME_CHECK;
647 else
648 vf = FAL_RX_SC_VALIDATE_FRAME_DISABLED;
649
650 ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
651 ret += nss_macsec_secy_rx_sc_create(drv->secy_id, channel);
652 ret += nss_macsec_secy_rx_sc_validate_frame_set(drv->secy_id, channel,
653 vf);
654 ret += nss_macsec_secy_rx_sc_replay_protect_set(drv->secy_id, channel,
655 drv->replay_protect);
656 ret += nss_macsec_secy_rx_sc_anti_replay_window_set(drv->secy_id,
657 channel,
658 drv->replay_window);
659
660 return ret;
661 }
662
663
664 static int macsec_qca_delete_receive_sc(void *priv, struct receive_sc *sc)
665 {
666 struct macsec_qca_data *drv = priv;
667 int ret = 0;
668 fal_rx_prc_lut_t entry;
669 u32 channel = sc->channel;
670
671 wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
672
673 /* rx prc lut */
674 os_memset(&entry, 0, sizeof(entry));
675
676 ret += nss_macsec_secy_rx_sc_del(drv->secy_id, channel);
677 ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
678
679 return ret;
680 }
681
682
683 static int macsec_qca_create_receive_sa(void *priv, struct receive_sa *sa)
684 {
685 struct macsec_qca_data *drv = priv;
686 int ret = 0;
687 fal_rx_sak_t rx_sak;
688 int i = 0;
689 u32 channel = sa->sc->channel;
690
691 wpa_printf(MSG_DEBUG, "%s, channel=%d, an=%d, lpn=0x%x",
692 __func__, channel, sa->an, sa->lowest_pn);
693
694 os_memset(&rx_sak, 0, sizeof(rx_sak));
695 for (i = 0; i < 16; i++)
696 rx_sak.sak[i] = sa->pkey->key[15 - i];
697
698 ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, sa->an);
699 ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, sa->an,
700 &rx_sak);
701
702 return ret;
703 }
704
705
706 static int macsec_qca_enable_receive_sa(void *priv, struct receive_sa *sa)
707 {
708 struct macsec_qca_data *drv = priv;
709 int ret = 0;
710 u32 channel = sa->sc->channel;
711
712
713 wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
714 sa->an);
715
716 ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
717 TRUE);
718
719 return ret;
720 }
721
722
723 static int macsec_qca_disable_receive_sa(void *priv, struct receive_sa *sa)
724 {
725 struct macsec_qca_data *drv = priv;
726 int ret = 0;
727 u32 channel = sa->sc->channel;
728
729 wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
730 sa->an);
731
732 ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
733 FALSE);
734
735 return ret;
736 }
737
738
739 static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel)
740 {
741 struct macsec_qca_data *drv = priv;
742 int ret = 0;
743 u32 sc_ch = 0;
744 bool in_use = FALSE;
745
746 for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
747 ret = nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch,
748 &in_use);
749 if (ret)
750 continue;
751
752 if (!in_use) {
753 *channel = sc_ch;
754 wpa_printf(MSG_DEBUG, "%s: channel=%d",
755 __func__, *channel);
756 return 0;
757 }
758 }
759
760 wpa_printf(MSG_DEBUG, "%s: no avaiable channel", __func__);
761
762 return -1;
763 }
764
765
766 static int macsec_qca_create_transmit_sc(void *priv, struct transmit_sc *sc,
767 unsigned int conf_offset)
768 {
769 struct macsec_qca_data *drv = priv;
770 int ret = 0;
771 fal_tx_class_lut_t entry;
772 u8 psci[ETH_ALEN + 2];
773 u32 channel = sc->channel;
774
775 wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
776
777 /* class lut */
778 os_memset(&entry, 0, sizeof(entry));
779
780 entry.valid = 1;
781 entry.action = FAL_TX_CLASS_ACTION_FORWARD;
782 entry.channel = channel;
783
784 os_memcpy(psci, sc->sci.addr, ETH_ALEN);
785 psci[6] = (sc->sci.port >> 8) & 0xf;
786 psci[7] = sc->sci.port & 0xf;
787
788 ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
789 ret += nss_macsec_secy_tx_sc_create(drv->secy_id, channel, psci, 8);
790 ret += nss_macsec_secy_tx_sc_protect_set(drv->secy_id, channel,
791 drv->protect_frames);
792 ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
793 channel,
794 conf_offset);
795
796 return ret;
797 }
798
799
800 static int macsec_qca_delete_transmit_sc(void *priv, struct transmit_sc *sc)
801 {
802 struct macsec_qca_data *drv = priv;
803 int ret = 0;
804 fal_tx_class_lut_t entry;
805 u32 channel = sc->channel;
806
807 wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
808
809 /* class lut */
810 os_memset(&entry, 0, sizeof(entry));
811
812 ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
813 ret += nss_macsec_secy_tx_sc_del(drv->secy_id, channel);
814
815 return ret;
816 }
817
818
819 static int macsec_qca_create_transmit_sa(void *priv, struct transmit_sa *sa)
820 {
821 struct macsec_qca_data *drv = priv;
822 int ret = 0;
823 u8 tci = 0;
824 fal_tx_sak_t tx_sak;
825 int i;
826 u32 channel = sa->sc->channel;
827
828 wpa_printf(MSG_DEBUG,
829 "%s: channel=%d, an=%d, next_pn=0x%x, confidentiality=%d",
830 __func__, channel, sa->an, sa->next_pn, sa->confidentiality);
831
832 if (drv->always_include_sci)
833 tci |= TCI_SC;
834 else if (drv->use_es)
835 tci |= TCI_ES;
836 else if (drv->use_scb)
837 tci |= TCI_SCB;
838
839 if (sa->confidentiality)
840 tci |= TCI_E | TCI_C;
841
842 os_memset(&tx_sak, 0, sizeof(tx_sak));
843 for (i = 0; i < 16; i++)
844 tx_sak.sak[i] = sa->pkey->key[15 - i];
845
846 ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
847 sa->next_pn);
848 ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, sa->an,
849 &tx_sak);
850 ret += nss_macsec_secy_tx_sc_tci_7_2_set(drv->secy_id, channel,
851 (tci >> 2));
852 ret += nss_macsec_secy_tx_sc_an_set(drv->secy_id, channel, sa->an);
853
854 return ret;
855 }
856
857
858 static int macsec_qca_enable_transmit_sa(void *priv, struct transmit_sa *sa)
859 {
860 struct macsec_qca_data *drv = priv;
861 int ret = 0;
862 u32 channel = sa->sc->channel;
863
864
865 wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
866 sa->an);
867
868 ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
869 TRUE);
870
871 return ret;
872 }
873
874
875 static int macsec_qca_disable_transmit_sa(void *priv, struct transmit_sa *sa)
876 {
877 struct macsec_qca_data *drv = priv;
878 int ret = 0;
879 u32 channel = sa->sc->channel;
880
881 wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
882 sa->an);
883
884 ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
885 FALSE);
886
887 return ret;
888 }
889
890
891 const struct wpa_driver_ops wpa_driver_macsec_qca_ops = {
892 .name = "macsec_qca",
893 .desc = "QCA MACsec Ethernet driver",
894 .get_ssid = macsec_qca_get_ssid,
895 .get_bssid = macsec_qca_get_bssid,
896 .get_capa = macsec_qca_get_capa,
897 .init = macsec_qca_init,
898 .deinit = macsec_qca_deinit,
899
900 .macsec_init = macsec_qca_macsec_init,
901 .macsec_deinit = macsec_qca_macsec_deinit,
902 .macsec_get_capability = macsec_qca_get_capability,
903 .enable_protect_frames = macsec_qca_enable_protect_frames,
904 .set_replay_protect = macsec_qca_set_replay_protect,
905 .set_current_cipher_suite = macsec_qca_set_current_cipher_suite,
906 .enable_controlled_port = macsec_qca_enable_controlled_port,
907 .get_receive_lowest_pn = macsec_qca_get_receive_lowest_pn,
908 .get_transmit_next_pn = macsec_qca_get_transmit_next_pn,
909 .set_transmit_next_pn = macsec_qca_set_transmit_next_pn,
910 .get_available_receive_sc = macsec_qca_get_available_receive_sc,
911 .create_receive_sc = macsec_qca_create_receive_sc,
912 .delete_receive_sc = macsec_qca_delete_receive_sc,
913 .create_receive_sa = macsec_qca_create_receive_sa,
914 .enable_receive_sa = macsec_qca_enable_receive_sa,
915 .disable_receive_sa = macsec_qca_disable_receive_sa,
916 .get_available_transmit_sc = macsec_qca_get_available_transmit_sc,
917 .create_transmit_sc = macsec_qca_create_transmit_sc,
918 .delete_transmit_sc = macsec_qca_delete_transmit_sc,
919 .create_transmit_sa = macsec_qca_create_transmit_sa,
920 .enable_transmit_sa = macsec_qca_enable_transmit_sa,
921 .disable_transmit_sa = macsec_qca_disable_transmit_sa,
922 };