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 #include "driver_wired_common.h"
35
36 #include "nss_macsec_secy.h"
37 #include "nss_macsec_secy_rx.h"
38 #include "nss_macsec_secy_tx.h"
39
40 #define MAXSC 16
41
42 /* TCI field definition */
43 #define TCI_ES 0x40
44 #define TCI_SC 0x20
45 #define TCI_SCB 0x10
46 #define TCI_E 0x08
47 #define TCI_C 0x04
48
49 #ifdef _MSC_VER
50 #pragma pack(push, 1)
51 #endif /* _MSC_VER */
52
53 #ifdef _MSC_VER
54 #pragma pack(pop)
55 #endif /* _MSC_VER */
56
57 struct channel_map {
58 struct ieee802_1x_mka_sci sci;
59 };
60
61 struct macsec_qca_data {
62 struct driver_wired_common_data common;
63
64 u32 secy_id;
65
66 /* shadow */
67 Boolean always_include_sci;
68 Boolean use_es;
69 Boolean use_scb;
70 Boolean protect_frames;
71 Boolean replay_protect;
72 u32 replay_window;
73
74 struct channel_map receive_channel_map[MAXSC];
75 struct channel_map transmit_channel_map[MAXSC];
76 };
77
78
__macsec_drv_init(struct macsec_qca_data * drv)79 static void __macsec_drv_init(struct macsec_qca_data *drv)
80 {
81 int ret = 0;
82 fal_rx_ctl_filt_t rx_ctl_filt;
83 fal_tx_ctl_filt_t tx_ctl_filt;
84
85 wpa_printf(MSG_INFO, "%s: secy_id=%d", __func__, drv->secy_id);
86
87 /* Enable Secy and Let EAPoL bypass */
88 ret = nss_macsec_secy_en_set(drv->secy_id, TRUE);
89 if (ret)
90 wpa_printf(MSG_ERROR, "nss_macsec_secy_en_set: FAIL");
91
92 ret = nss_macsec_secy_sc_sa_mapping_mode_set(drv->secy_id,
93 FAL_SC_SA_MAP_1_4);
94 if (ret)
95 wpa_printf(MSG_ERROR,
96 "nss_macsec_secy_sc_sa_mapping_mode_set: FAIL");
97
98 os_memset(&rx_ctl_filt, 0, sizeof(rx_ctl_filt));
99 rx_ctl_filt.bypass = 1;
100 rx_ctl_filt.match_type = IG_CTL_COMPARE_ETHER_TYPE;
101 rx_ctl_filt.match_mask = 0xffff;
102 rx_ctl_filt.ether_type_da_range = 0x888e;
103 ret = nss_macsec_secy_rx_ctl_filt_set(drv->secy_id, 0, &rx_ctl_filt);
104 if (ret)
105 wpa_printf(MSG_ERROR, "nss_macsec_secy_rx_ctl_filt_set: FAIL");
106
107 os_memset(&tx_ctl_filt, 0, sizeof(tx_ctl_filt));
108 tx_ctl_filt.bypass = 1;
109 tx_ctl_filt.match_type = EG_CTL_COMPARE_ETHER_TYPE;
110 tx_ctl_filt.match_mask = 0xffff;
111 tx_ctl_filt.ether_type_da_range = 0x888e;
112 ret = nss_macsec_secy_tx_ctl_filt_set(drv->secy_id, 0, &tx_ctl_filt);
113 if (ret)
114 wpa_printf(MSG_ERROR, "nss_macsec_secy_tx_ctl_filt_set: FAIL");
115 }
116
117
__macsec_drv_deinit(struct macsec_qca_data * drv)118 static void __macsec_drv_deinit(struct macsec_qca_data *drv)
119 {
120 nss_macsec_secy_en_set(drv->secy_id, FALSE);
121 nss_macsec_secy_rx_sc_del_all(drv->secy_id);
122 nss_macsec_secy_tx_sc_del_all(drv->secy_id);
123 }
124
125
macsec_qca_init(void * ctx,const char * ifname)126 static void * macsec_qca_init(void *ctx, const char *ifname)
127 {
128 struct macsec_qca_data *drv;
129
130 drv = os_zalloc(sizeof(*drv));
131 if (drv == NULL)
132 return NULL;
133
134 /* Board specific settings */
135 if (os_memcmp("eth2", ifname, 4) == 0)
136 drv->secy_id = 1;
137 else if (os_memcmp("eth3", ifname, 4) == 0)
138 drv->secy_id = 2;
139 else
140 drv->secy_id = -1;
141
142 if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
143 os_free(drv);
144 return NULL;
145 }
146
147 return drv;
148 }
149
150
macsec_qca_deinit(void * priv)151 static void macsec_qca_deinit(void *priv)
152 {
153 struct macsec_qca_data *drv = priv;
154
155 driver_wired_deinit_common(&drv->common);
156 os_free(drv);
157 }
158
159
macsec_qca_macsec_init(void * priv,struct macsec_init_params * params)160 static int macsec_qca_macsec_init(void *priv, struct macsec_init_params *params)
161 {
162 struct macsec_qca_data *drv = priv;
163
164 drv->always_include_sci = params->always_include_sci;
165 drv->use_es = params->use_es;
166 drv->use_scb = params->use_scb;
167
168 wpa_printf(MSG_DEBUG, "%s: es=%d, scb=%d, sci=%d",
169 __func__, drv->use_es, drv->use_scb,
170 drv->always_include_sci);
171
172 __macsec_drv_init(drv);
173
174 return 0;
175 }
176
177
macsec_qca_macsec_deinit(void * priv)178 static int macsec_qca_macsec_deinit(void *priv)
179 {
180 struct macsec_qca_data *drv = priv;
181
182 wpa_printf(MSG_DEBUG, "%s", __func__);
183
184 __macsec_drv_deinit(drv);
185
186 return 0;
187 }
188
189
macsec_qca_get_capability(void * priv,enum macsec_cap * cap)190 static int macsec_qca_get_capability(void *priv, enum macsec_cap *cap)
191 {
192 wpa_printf(MSG_DEBUG, "%s", __func__);
193
194 *cap = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
195
196 return 0;
197 }
198
199
macsec_qca_enable_protect_frames(void * priv,Boolean enabled)200 static int macsec_qca_enable_protect_frames(void *priv, Boolean enabled)
201 {
202 struct macsec_qca_data *drv = priv;
203 int ret = 0;
204
205 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
206
207 drv->protect_frames = enabled;
208
209 return ret;
210 }
211
212
macsec_qca_set_replay_protect(void * priv,Boolean enabled,unsigned int window)213 static int macsec_qca_set_replay_protect(void *priv, Boolean enabled,
214 unsigned int window)
215 {
216 struct macsec_qca_data *drv = priv;
217 int ret = 0;
218
219 wpa_printf(MSG_DEBUG, "%s: enabled=%d, win=%u",
220 __func__, enabled, window);
221
222 drv->replay_protect = enabled;
223 drv->replay_window = window;
224
225 return ret;
226 }
227
228
macsec_qca_set_current_cipher_suite(void * priv,u64 cs)229 static int macsec_qca_set_current_cipher_suite(void *priv, u64 cs)
230 {
231 if (cs != CS_ID_GCM_AES_128) {
232 wpa_printf(MSG_ERROR,
233 "%s: NOT supported CipherSuite: %016" PRIx64,
234 __func__, cs);
235 return -1;
236 }
237
238 /* Support default Cipher Suite 0080020001000001 (GCM-AES-128) */
239 wpa_printf(MSG_DEBUG, "%s: default support aes-gcm-128", __func__);
240
241 return 0;
242 }
243
244
macsec_qca_enable_controlled_port(void * priv,Boolean enabled)245 static int macsec_qca_enable_controlled_port(void *priv, Boolean enabled)
246 {
247 struct macsec_qca_data *drv = priv;
248 int ret = 0;
249
250 wpa_printf(MSG_DEBUG, "%s: enable=%d", __func__, enabled);
251
252 ret += nss_macsec_secy_controlled_port_en_set(drv->secy_id, enabled);
253
254 return ret;
255 }
256
257
macsec_qca_lookup_channel(struct channel_map * map,struct ieee802_1x_mka_sci * sci,u32 * channel)258 static int macsec_qca_lookup_channel(struct channel_map *map,
259 struct ieee802_1x_mka_sci *sci,
260 u32 *channel)
261 {
262 u32 i;
263
264 for (i = 0; i < MAXSC; i++) {
265 if (os_memcmp(&map[i].sci, sci,
266 sizeof(struct ieee802_1x_mka_sci)) == 0) {
267 *channel = i;
268 return 0;
269 }
270 }
271
272 return -1;
273 }
274
275
macsec_qca_register_channel(struct channel_map * map,struct ieee802_1x_mka_sci * sci,u32 channel)276 static void macsec_qca_register_channel(struct channel_map *map,
277 struct ieee802_1x_mka_sci *sci,
278 u32 channel)
279 {
280 os_memcpy(&map[channel].sci, sci, sizeof(struct ieee802_1x_mka_sci));
281 }
282
283
macsec_qca_lookup_receive_channel(struct macsec_qca_data * drv,struct receive_sc * sc,u32 * channel)284 static int macsec_qca_lookup_receive_channel(struct macsec_qca_data *drv,
285 struct receive_sc *sc,
286 u32 *channel)
287 {
288 return macsec_qca_lookup_channel(drv->receive_channel_map, &sc->sci,
289 channel);
290 }
291
292
macsec_qca_register_receive_channel(struct macsec_qca_data * drv,struct receive_sc * sc,u32 channel)293 static void macsec_qca_register_receive_channel(struct macsec_qca_data *drv,
294 struct receive_sc *sc,
295 u32 channel)
296 {
297 macsec_qca_register_channel(drv->receive_channel_map, &sc->sci,
298 channel);
299 }
300
301
macsec_qca_lookup_transmit_channel(struct macsec_qca_data * drv,struct transmit_sc * sc,u32 * channel)302 static int macsec_qca_lookup_transmit_channel(struct macsec_qca_data *drv,
303 struct transmit_sc *sc,
304 u32 *channel)
305 {
306 return macsec_qca_lookup_channel(drv->transmit_channel_map, &sc->sci,
307 channel);
308 }
309
310
macsec_qca_register_transmit_channel(struct macsec_qca_data * drv,struct transmit_sc * sc,u32 channel)311 static void macsec_qca_register_transmit_channel(struct macsec_qca_data *drv,
312 struct transmit_sc *sc,
313 u32 channel)
314 {
315 macsec_qca_register_channel(drv->transmit_channel_map, &sc->sci,
316 channel);
317 }
318
319
macsec_qca_get_receive_lowest_pn(void * priv,struct receive_sa * sa)320 static int macsec_qca_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
321 {
322 struct macsec_qca_data *drv = priv;
323 int ret = 0;
324 u32 next_pn = 0;
325 bool enabled = FALSE;
326 u32 win;
327 u32 channel;
328
329 ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
330 if (ret != 0)
331 return ret;
332
333 ret += nss_macsec_secy_rx_sa_next_pn_get(drv->secy_id, channel, sa->an,
334 &next_pn);
335 ret += nss_macsec_secy_rx_sc_replay_protect_get(drv->secy_id, channel,
336 &enabled);
337 ret += nss_macsec_secy_rx_sc_anti_replay_window_get(drv->secy_id,
338 channel, &win);
339
340 if (enabled)
341 sa->lowest_pn = (next_pn > win) ? (next_pn - win) : 1;
342 else
343 sa->lowest_pn = next_pn;
344
345 wpa_printf(MSG_DEBUG, "%s: lpn=0x%x", __func__, sa->lowest_pn);
346
347 return ret;
348 }
349
350
macsec_qca_get_transmit_next_pn(void * priv,struct transmit_sa * sa)351 static int macsec_qca_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
352 {
353 struct macsec_qca_data *drv = priv;
354 int ret = 0;
355 u32 channel;
356
357 ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
358 if (ret != 0)
359 return ret;
360
361 ret += nss_macsec_secy_tx_sa_next_pn_get(drv->secy_id, channel, sa->an,
362 &sa->next_pn);
363
364 wpa_printf(MSG_DEBUG, "%s: npn=0x%x", __func__, sa->next_pn);
365
366 return ret;
367 }
368
369
macsec_qca_set_transmit_next_pn(void * priv,struct transmit_sa * sa)370 int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
371 {
372 struct macsec_qca_data *drv = priv;
373 int ret = 0;
374 u32 channel;
375
376 ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
377 if (ret != 0)
378 return ret;
379
380 ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
381 sa->next_pn);
382
383 wpa_printf(MSG_INFO, "%s: npn=0x%x", __func__, sa->next_pn);
384
385 return ret;
386 }
387
388
macsec_qca_get_available_receive_sc(void * priv,u32 * channel)389 static int macsec_qca_get_available_receive_sc(void *priv, u32 *channel)
390 {
391 struct macsec_qca_data *drv = priv;
392 int ret = 0;
393 u32 sc_ch = 0;
394 bool in_use = FALSE;
395
396 for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
397 ret = nss_macsec_secy_rx_sc_in_used_get(drv->secy_id, sc_ch,
398 &in_use);
399 if (ret)
400 continue;
401
402 if (!in_use) {
403 *channel = sc_ch;
404 wpa_printf(MSG_DEBUG, "%s: channel=%d",
405 __func__, *channel);
406 return 0;
407 }
408 }
409
410 wpa_printf(MSG_DEBUG, "%s: no available channel", __func__);
411
412 return -1;
413 }
414
415
macsec_qca_create_receive_sc(void * priv,struct receive_sc * sc,unsigned int conf_offset,int validation)416 static int macsec_qca_create_receive_sc(void *priv, struct receive_sc *sc,
417 unsigned int conf_offset,
418 int validation)
419 {
420 struct macsec_qca_data *drv = priv;
421 int ret = 0;
422 fal_rx_prc_lut_t entry;
423 fal_rx_sc_validate_frame_e vf;
424 enum validate_frames validate_frames = validation;
425 u32 channel;
426 const u8 *sci_addr = sc->sci.addr;
427 u16 sci_port = be_to_host16(sc->sci.port);
428
429 ret = macsec_qca_get_available_receive_sc(priv, &channel);
430 if (ret != 0)
431 return ret;
432
433 wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
434
435 /* rx prc lut */
436 os_memset(&entry, 0, sizeof(entry));
437
438 os_memcpy(entry.sci, sci_addr, ETH_ALEN);
439 entry.sci[6] = (sci_port >> 8) & 0xf;
440 entry.sci[7] = sci_port & 0xf;
441 entry.sci_mask = 0xf;
442
443 entry.valid = 1;
444 entry.channel = channel;
445 entry.action = FAL_RX_PRC_ACTION_PROCESS;
446 entry.offset = conf_offset;
447
448 /* rx validate frame */
449 if (validate_frames == Strict)
450 vf = FAL_RX_SC_VALIDATE_FRAME_STRICT;
451 else if (validate_frames == Checked)
452 vf = FAL_RX_SC_VALIDATE_FRAME_CHECK;
453 else
454 vf = FAL_RX_SC_VALIDATE_FRAME_DISABLED;
455
456 ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
457 ret += nss_macsec_secy_rx_sc_create(drv->secy_id, channel);
458 ret += nss_macsec_secy_rx_sc_validate_frame_set(drv->secy_id, channel,
459 vf);
460 ret += nss_macsec_secy_rx_sc_replay_protect_set(drv->secy_id, channel,
461 drv->replay_protect);
462 ret += nss_macsec_secy_rx_sc_anti_replay_window_set(drv->secy_id,
463 channel,
464 drv->replay_window);
465
466 macsec_qca_register_receive_channel(drv, sc, channel);
467
468 return ret;
469 }
470
471
macsec_qca_delete_receive_sc(void * priv,struct receive_sc * sc)472 static int macsec_qca_delete_receive_sc(void *priv, struct receive_sc *sc)
473 {
474 struct macsec_qca_data *drv = priv;
475 int ret;
476 fal_rx_prc_lut_t entry;
477 u32 channel;
478
479 ret = macsec_qca_lookup_receive_channel(priv, sc, &channel);
480 if (ret != 0)
481 return ret;
482
483 wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
484
485 /* rx prc lut */
486 os_memset(&entry, 0, sizeof(entry));
487
488 ret += nss_macsec_secy_rx_sc_del(drv->secy_id, channel);
489 ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
490
491 return ret;
492 }
493
494
macsec_qca_create_receive_sa(void * priv,struct receive_sa * sa)495 static int macsec_qca_create_receive_sa(void *priv, struct receive_sa *sa)
496 {
497 struct macsec_qca_data *drv = priv;
498 int ret;
499 fal_rx_sak_t rx_sak;
500 int i = 0;
501 u32 channel;
502
503 ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
504 if (ret != 0)
505 return ret;
506
507 wpa_printf(MSG_DEBUG, "%s, channel=%d, an=%d, lpn=0x%x",
508 __func__, channel, sa->an, sa->lowest_pn);
509
510 os_memset(&rx_sak, 0, sizeof(rx_sak));
511 for (i = 0; i < 16; i++)
512 rx_sak.sak[i] = sa->pkey->key[15 - i];
513
514 ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, sa->an);
515 ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, sa->an,
516 &rx_sak);
517
518 return ret;
519 }
520
521
macsec_qca_enable_receive_sa(void * priv,struct receive_sa * sa)522 static int macsec_qca_enable_receive_sa(void *priv, struct receive_sa *sa)
523 {
524 struct macsec_qca_data *drv = priv;
525 int ret;
526 u32 channel;
527
528 ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
529 if (ret != 0)
530 return ret;
531
532 wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
533 sa->an);
534
535 ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
536 TRUE);
537
538 return ret;
539 }
540
541
macsec_qca_disable_receive_sa(void * priv,struct receive_sa * sa)542 static int macsec_qca_disable_receive_sa(void *priv, struct receive_sa *sa)
543 {
544 struct macsec_qca_data *drv = priv;
545 int ret;
546 u32 channel;
547
548 ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
549 if (ret != 0)
550 return ret;
551
552 wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
553 sa->an);
554
555 ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
556 FALSE);
557
558 return ret;
559 }
560
561
macsec_qca_get_available_transmit_sc(void * priv,u32 * channel)562 static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel)
563 {
564 struct macsec_qca_data *drv = priv;
565 u32 sc_ch = 0;
566 bool in_use = FALSE;
567
568 for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
569 if (nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch,
570 &in_use))
571 continue;
572
573 if (!in_use) {
574 *channel = sc_ch;
575 wpa_printf(MSG_DEBUG, "%s: channel=%d",
576 __func__, *channel);
577 return 0;
578 }
579 }
580
581 wpa_printf(MSG_DEBUG, "%s: no avaiable channel", __func__);
582
583 return -1;
584 }
585
586
macsec_qca_create_transmit_sc(void * priv,struct transmit_sc * sc,unsigned int conf_offset)587 static int macsec_qca_create_transmit_sc(void *priv, struct transmit_sc *sc,
588 unsigned int conf_offset)
589 {
590 struct macsec_qca_data *drv = priv;
591 int ret;
592 fal_tx_class_lut_t entry;
593 u8 psci[ETH_ALEN + 2];
594 u32 channel;
595
596 ret = macsec_qca_get_available_transmit_sc(priv, &channel);
597 if (ret != 0)
598 return ret;
599
600 wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
601
602 /* class lut */
603 os_memset(&entry, 0, sizeof(entry));
604
605 entry.valid = 1;
606 entry.action = FAL_TX_CLASS_ACTION_FORWARD;
607 entry.channel = channel;
608
609 os_memcpy(psci, sc->sci.addr, ETH_ALEN);
610 psci[6] = (sc->sci.port >> 8) & 0xf;
611 psci[7] = sc->sci.port & 0xf;
612
613 ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
614 ret += nss_macsec_secy_tx_sc_create(drv->secy_id, channel, psci, 8);
615 ret += nss_macsec_secy_tx_sc_protect_set(drv->secy_id, channel,
616 drv->protect_frames);
617 ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
618 channel,
619 conf_offset);
620
621 macsec_qca_register_transmit_channel(drv, sc, channel);
622
623 return ret;
624 }
625
626
macsec_qca_delete_transmit_sc(void * priv,struct transmit_sc * sc)627 static int macsec_qca_delete_transmit_sc(void *priv, struct transmit_sc *sc)
628 {
629 struct macsec_qca_data *drv = priv;
630 int ret;
631 fal_tx_class_lut_t entry;
632 u32 channel;
633
634 ret = macsec_qca_lookup_transmit_channel(priv, sc, &channel);
635 if (ret != 0)
636 return ret;
637
638 wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
639
640 /* class lut */
641 os_memset(&entry, 0, sizeof(entry));
642
643 ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
644 ret += nss_macsec_secy_tx_sc_del(drv->secy_id, channel);
645
646 return ret;
647 }
648
649
macsec_qca_create_transmit_sa(void * priv,struct transmit_sa * sa)650 static int macsec_qca_create_transmit_sa(void *priv, struct transmit_sa *sa)
651 {
652 struct macsec_qca_data *drv = priv;
653 int ret;
654 u8 tci = 0;
655 fal_tx_sak_t tx_sak;
656 int i;
657 u32 channel;
658
659 ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
660 if (ret != 0)
661 return ret;
662
663 wpa_printf(MSG_DEBUG,
664 "%s: channel=%d, an=%d, next_pn=0x%x, confidentiality=%d",
665 __func__, channel, sa->an, sa->next_pn, sa->confidentiality);
666
667 if (drv->always_include_sci)
668 tci |= TCI_SC;
669 else if (drv->use_es)
670 tci |= TCI_ES;
671 else if (drv->use_scb)
672 tci |= TCI_SCB;
673
674 if (sa->confidentiality)
675 tci |= TCI_E | TCI_C;
676
677 os_memset(&tx_sak, 0, sizeof(tx_sak));
678 for (i = 0; i < 16; i++)
679 tx_sak.sak[i] = sa->pkey->key[15 - i];
680
681 ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
682 sa->next_pn);
683 ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, sa->an,
684 &tx_sak);
685 ret += nss_macsec_secy_tx_sc_tci_7_2_set(drv->secy_id, channel,
686 (tci >> 2));
687 ret += nss_macsec_secy_tx_sc_an_set(drv->secy_id, channel, sa->an);
688
689 return ret;
690 }
691
692
macsec_qca_enable_transmit_sa(void * priv,struct transmit_sa * sa)693 static int macsec_qca_enable_transmit_sa(void *priv, struct transmit_sa *sa)
694 {
695 struct macsec_qca_data *drv = priv;
696 int ret;
697 u32 channel;
698
699 ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
700 if (ret != 0)
701 return ret;
702
703 wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
704 sa->an);
705
706 ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
707 TRUE);
708
709 return ret;
710 }
711
712
macsec_qca_disable_transmit_sa(void * priv,struct transmit_sa * sa)713 static int macsec_qca_disable_transmit_sa(void *priv, struct transmit_sa *sa)
714 {
715 struct macsec_qca_data *drv = priv;
716 int ret;
717 u32 channel;
718
719 ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
720 if (ret != 0)
721 return ret;
722
723 wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
724 sa->an);
725
726 ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
727 FALSE);
728
729 return ret;
730 }
731
732
733 const struct wpa_driver_ops wpa_driver_macsec_qca_ops = {
734 .name = "macsec_qca",
735 .desc = "QCA MACsec Ethernet driver",
736 .get_ssid = driver_wired_get_ssid,
737 .get_bssid = driver_wired_get_bssid,
738 .get_capa = driver_wired_get_capa,
739 .init = macsec_qca_init,
740 .deinit = macsec_qca_deinit,
741
742 .macsec_init = macsec_qca_macsec_init,
743 .macsec_deinit = macsec_qca_macsec_deinit,
744 .macsec_get_capability = macsec_qca_get_capability,
745 .enable_protect_frames = macsec_qca_enable_protect_frames,
746 .set_replay_protect = macsec_qca_set_replay_protect,
747 .set_current_cipher_suite = macsec_qca_set_current_cipher_suite,
748 .enable_controlled_port = macsec_qca_enable_controlled_port,
749 .get_receive_lowest_pn = macsec_qca_get_receive_lowest_pn,
750 .get_transmit_next_pn = macsec_qca_get_transmit_next_pn,
751 .set_transmit_next_pn = macsec_qca_set_transmit_next_pn,
752 .create_receive_sc = macsec_qca_create_receive_sc,
753 .delete_receive_sc = macsec_qca_delete_receive_sc,
754 .create_receive_sa = macsec_qca_create_receive_sa,
755 .enable_receive_sa = macsec_qca_enable_receive_sa,
756 .disable_receive_sa = macsec_qca_disable_receive_sa,
757 .create_transmit_sc = macsec_qca_create_transmit_sc,
758 .delete_transmit_sc = macsec_qca_delete_transmit_sc,
759 .create_transmit_sa = macsec_qca_create_transmit_sa,
760 .enable_transmit_sa = macsec_qca_enable_transmit_sa,
761 .disable_transmit_sa = macsec_qca_disable_transmit_sa,
762 };
763