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