15b9c547cSRui Paulo /*
25b9c547cSRui Paulo * Wired Ethernet driver interface for QCA MACsec driver
35b9c547cSRui Paulo * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
45b9c547cSRui Paulo * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
55b9c547cSRui Paulo * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
6206b73d0SCy Schubert * Copyright (c) 2019, The Linux Foundation
75b9c547cSRui Paulo *
85b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license.
95b9c547cSRui Paulo * See README for more details.
105b9c547cSRui Paulo */
115b9c547cSRui Paulo
125b9c547cSRui Paulo #include "includes.h"
135b9c547cSRui Paulo #include <sys/ioctl.h>
145b9c547cSRui Paulo #include <net/if.h>
15780fb4a2SCy Schubert #include <inttypes.h>
165b9c547cSRui Paulo #ifdef __linux__
175b9c547cSRui Paulo #include <netpacket/packet.h>
185b9c547cSRui Paulo #include <net/if_arp.h>
195b9c547cSRui Paulo #include <net/if.h>
205b9c547cSRui Paulo #endif /* __linux__ */
215b9c547cSRui Paulo #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
225b9c547cSRui Paulo #include <net/if_dl.h>
235b9c547cSRui Paulo #include <net/if_media.h>
245b9c547cSRui Paulo #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
255b9c547cSRui Paulo #ifdef __sun__
265b9c547cSRui Paulo #include <sys/sockio.h>
275b9c547cSRui Paulo #endif /* __sun__ */
285b9c547cSRui Paulo
295b9c547cSRui Paulo #include "utils/common.h"
305b9c547cSRui Paulo #include "utils/eloop.h"
315b9c547cSRui Paulo #include "common/defs.h"
325b9c547cSRui Paulo #include "common/ieee802_1x_defs.h"
33206b73d0SCy Schubert #include "common/eapol_common.h"
3485732ac8SCy Schubert #include "pae/ieee802_1x_kay.h"
355b9c547cSRui Paulo #include "driver.h"
3685732ac8SCy Schubert #include "driver_wired_common.h"
375b9c547cSRui Paulo
385b9c547cSRui Paulo #include "nss_macsec_secy.h"
395b9c547cSRui Paulo #include "nss_macsec_secy_rx.h"
405b9c547cSRui Paulo #include "nss_macsec_secy_tx.h"
415b9c547cSRui Paulo
425b9c547cSRui Paulo #define MAXSC 16
435b9c547cSRui Paulo
4485732ac8SCy Schubert #define SAK_128_LEN 16
4585732ac8SCy Schubert #define SAK_256_LEN 32
4685732ac8SCy Schubert
475b9c547cSRui Paulo /* TCI field definition */
485b9c547cSRui Paulo #define TCI_ES 0x40
495b9c547cSRui Paulo #define TCI_SC 0x20
505b9c547cSRui Paulo #define TCI_SCB 0x10
515b9c547cSRui Paulo #define TCI_E 0x08
525b9c547cSRui Paulo #define TCI_C 0x04
535b9c547cSRui Paulo
545b9c547cSRui Paulo #ifdef _MSC_VER
555b9c547cSRui Paulo #pragma pack(push, 1)
565b9c547cSRui Paulo #endif /* _MSC_VER */
575b9c547cSRui Paulo
585b9c547cSRui Paulo #ifdef _MSC_VER
595b9c547cSRui Paulo #pragma pack(pop)
605b9c547cSRui Paulo #endif /* _MSC_VER */
615b9c547cSRui Paulo
6285732ac8SCy Schubert struct channel_map {
6385732ac8SCy Schubert struct ieee802_1x_mka_sci sci;
6485732ac8SCy Schubert };
655b9c547cSRui Paulo
665b9c547cSRui Paulo struct macsec_qca_data {
6785732ac8SCy Schubert struct driver_wired_common_data common;
685b9c547cSRui Paulo
69206b73d0SCy Schubert int use_pae_group_addr;
7085732ac8SCy Schubert u32 secy_id;
715b9c547cSRui Paulo
725b9c547cSRui Paulo /* shadow */
73c1d255d3SCy Schubert bool always_include_sci;
74c1d255d3SCy Schubert bool use_es;
75c1d255d3SCy Schubert bool use_scb;
76c1d255d3SCy Schubert bool protect_frames;
77c1d255d3SCy Schubert bool replay_protect;
785b9c547cSRui Paulo u32 replay_window;
7985732ac8SCy Schubert
8085732ac8SCy Schubert struct channel_map receive_channel_map[MAXSC];
8185732ac8SCy Schubert struct channel_map transmit_channel_map[MAXSC];
825b9c547cSRui Paulo };
835b9c547cSRui Paulo
845b9c547cSRui Paulo
__macsec_drv_init(struct macsec_qca_data * drv)855b9c547cSRui Paulo static void __macsec_drv_init(struct macsec_qca_data *drv)
865b9c547cSRui Paulo {
875b9c547cSRui Paulo int ret = 0;
885b9c547cSRui Paulo fal_rx_ctl_filt_t rx_ctl_filt;
895b9c547cSRui Paulo fal_tx_ctl_filt_t tx_ctl_filt;
905b9c547cSRui Paulo
915b9c547cSRui Paulo wpa_printf(MSG_INFO, "%s: secy_id=%d", __func__, drv->secy_id);
925b9c547cSRui Paulo
935b9c547cSRui Paulo /* Enable Secy and Let EAPoL bypass */
94c1d255d3SCy Schubert ret = nss_macsec_secy_en_set(drv->secy_id, true);
955b9c547cSRui Paulo if (ret)
965b9c547cSRui Paulo wpa_printf(MSG_ERROR, "nss_macsec_secy_en_set: FAIL");
975b9c547cSRui Paulo
985b9c547cSRui Paulo ret = nss_macsec_secy_sc_sa_mapping_mode_set(drv->secy_id,
995b9c547cSRui Paulo FAL_SC_SA_MAP_1_4);
1005b9c547cSRui Paulo if (ret)
1015b9c547cSRui Paulo wpa_printf(MSG_ERROR,
1025b9c547cSRui Paulo "nss_macsec_secy_sc_sa_mapping_mode_set: FAIL");
1035b9c547cSRui Paulo
1045b9c547cSRui Paulo os_memset(&rx_ctl_filt, 0, sizeof(rx_ctl_filt));
1055b9c547cSRui Paulo rx_ctl_filt.bypass = 1;
1065b9c547cSRui Paulo rx_ctl_filt.match_type = IG_CTL_COMPARE_ETHER_TYPE;
1075b9c547cSRui Paulo rx_ctl_filt.match_mask = 0xffff;
1085b9c547cSRui Paulo rx_ctl_filt.ether_type_da_range = 0x888e;
1095b9c547cSRui Paulo ret = nss_macsec_secy_rx_ctl_filt_set(drv->secy_id, 0, &rx_ctl_filt);
1105b9c547cSRui Paulo if (ret)
1115b9c547cSRui Paulo wpa_printf(MSG_ERROR, "nss_macsec_secy_rx_ctl_filt_set: FAIL");
1125b9c547cSRui Paulo
1135b9c547cSRui Paulo os_memset(&tx_ctl_filt, 0, sizeof(tx_ctl_filt));
1145b9c547cSRui Paulo tx_ctl_filt.bypass = 1;
1155b9c547cSRui Paulo tx_ctl_filt.match_type = EG_CTL_COMPARE_ETHER_TYPE;
1165b9c547cSRui Paulo tx_ctl_filt.match_mask = 0xffff;
1175b9c547cSRui Paulo tx_ctl_filt.ether_type_da_range = 0x888e;
1185b9c547cSRui Paulo ret = nss_macsec_secy_tx_ctl_filt_set(drv->secy_id, 0, &tx_ctl_filt);
1195b9c547cSRui Paulo if (ret)
1205b9c547cSRui Paulo wpa_printf(MSG_ERROR, "nss_macsec_secy_tx_ctl_filt_set: FAIL");
1215b9c547cSRui Paulo }
1225b9c547cSRui Paulo
1235b9c547cSRui Paulo
__macsec_drv_deinit(struct macsec_qca_data * drv)1245b9c547cSRui Paulo static void __macsec_drv_deinit(struct macsec_qca_data *drv)
1255b9c547cSRui Paulo {
126c1d255d3SCy Schubert nss_macsec_secy_en_set(drv->secy_id, false);
1275b9c547cSRui Paulo nss_macsec_secy_rx_sc_del_all(drv->secy_id);
1285b9c547cSRui Paulo nss_macsec_secy_tx_sc_del_all(drv->secy_id);
1295b9c547cSRui Paulo }
1305b9c547cSRui Paulo
1315b9c547cSRui Paulo
132206b73d0SCy Schubert #ifdef __linux__
133206b73d0SCy Schubert
macsec_qca_handle_data(void * ctx,unsigned char * buf,size_t len)134206b73d0SCy Schubert static void macsec_qca_handle_data(void *ctx, unsigned char *buf, size_t len)
135206b73d0SCy Schubert {
136206b73d0SCy Schubert #ifdef HOSTAPD
137206b73d0SCy Schubert struct ieee8023_hdr *hdr;
138206b73d0SCy Schubert u8 *pos, *sa;
139206b73d0SCy Schubert size_t left;
140206b73d0SCy Schubert union wpa_event_data event;
141206b73d0SCy Schubert
142206b73d0SCy Schubert /* at least 6 bytes src macaddress, 6 bytes dst macaddress
143206b73d0SCy Schubert * and 2 bytes ethertype
144206b73d0SCy Schubert */
145206b73d0SCy Schubert if (len < 14) {
146206b73d0SCy Schubert wpa_printf(MSG_MSGDUMP,
147206b73d0SCy Schubert "macsec_qca_handle_data: too short (%lu)",
148206b73d0SCy Schubert (unsigned long) len);
149206b73d0SCy Schubert return;
150206b73d0SCy Schubert }
151206b73d0SCy Schubert hdr = (struct ieee8023_hdr *) buf;
152206b73d0SCy Schubert
153206b73d0SCy Schubert switch (ntohs(hdr->ethertype)) {
154206b73d0SCy Schubert case ETH_P_PAE:
155206b73d0SCy Schubert wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
156206b73d0SCy Schubert sa = hdr->src;
157206b73d0SCy Schubert os_memset(&event, 0, sizeof(event));
158206b73d0SCy Schubert event.new_sta.addr = sa;
159206b73d0SCy Schubert wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
160206b73d0SCy Schubert
161206b73d0SCy Schubert pos = (u8 *) (hdr + 1);
162206b73d0SCy Schubert left = len - sizeof(*hdr);
163206b73d0SCy Schubert drv_event_eapol_rx(ctx, sa, pos, left);
164206b73d0SCy Schubert break;
165206b73d0SCy Schubert default:
166206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame",
167206b73d0SCy Schubert ntohs(hdr->ethertype));
168206b73d0SCy Schubert break;
169206b73d0SCy Schubert }
170206b73d0SCy Schubert #endif /* HOSTAPD */
171206b73d0SCy Schubert }
172206b73d0SCy Schubert
173206b73d0SCy Schubert
macsec_qca_handle_read(int sock,void * eloop_ctx,void * sock_ctx)174206b73d0SCy Schubert static void macsec_qca_handle_read(int sock, void *eloop_ctx, void *sock_ctx)
175206b73d0SCy Schubert {
176206b73d0SCy Schubert int len;
177206b73d0SCy Schubert unsigned char buf[3000];
178206b73d0SCy Schubert
179206b73d0SCy Schubert len = recv(sock, buf, sizeof(buf), 0);
180206b73d0SCy Schubert if (len < 0) {
181206b73d0SCy Schubert wpa_printf(MSG_ERROR, "macsec_qca: recv: %s", strerror(errno));
182206b73d0SCy Schubert return;
183206b73d0SCy Schubert }
184206b73d0SCy Schubert
185206b73d0SCy Schubert macsec_qca_handle_data(eloop_ctx, buf, len);
186206b73d0SCy Schubert }
187206b73d0SCy Schubert
188206b73d0SCy Schubert #endif /* __linux__ */
189206b73d0SCy Schubert
190206b73d0SCy Schubert
macsec_qca_init_sockets(struct macsec_qca_data * drv,u8 * own_addr)191206b73d0SCy Schubert static int macsec_qca_init_sockets(struct macsec_qca_data *drv, u8 *own_addr)
192206b73d0SCy Schubert {
193206b73d0SCy Schubert #ifdef __linux__
194206b73d0SCy Schubert struct ifreq ifr;
195206b73d0SCy Schubert struct sockaddr_ll addr;
196206b73d0SCy Schubert
197206b73d0SCy Schubert drv->common.sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
198206b73d0SCy Schubert if (drv->common.sock < 0) {
199206b73d0SCy Schubert wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
200206b73d0SCy Schubert strerror(errno));
201206b73d0SCy Schubert return -1;
202206b73d0SCy Schubert }
203206b73d0SCy Schubert
204206b73d0SCy Schubert if (eloop_register_read_sock(drv->common.sock, macsec_qca_handle_read,
205206b73d0SCy Schubert drv->common.ctx, NULL)) {
206206b73d0SCy Schubert wpa_printf(MSG_INFO, "Could not register read socket");
207206b73d0SCy Schubert return -1;
208206b73d0SCy Schubert }
209206b73d0SCy Schubert
210206b73d0SCy Schubert os_memset(&ifr, 0, sizeof(ifr));
211206b73d0SCy Schubert os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
212206b73d0SCy Schubert if (ioctl(drv->common.sock, SIOCGIFINDEX, &ifr) != 0) {
213206b73d0SCy Schubert wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
214206b73d0SCy Schubert strerror(errno));
215206b73d0SCy Schubert return -1;
216206b73d0SCy Schubert }
217206b73d0SCy Schubert
218206b73d0SCy Schubert os_memset(&addr, 0, sizeof(addr));
219206b73d0SCy Schubert addr.sll_family = AF_PACKET;
220206b73d0SCy Schubert addr.sll_ifindex = ifr.ifr_ifindex;
221206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
222206b73d0SCy Schubert addr.sll_ifindex);
223206b73d0SCy Schubert
224206b73d0SCy Schubert if (bind(drv->common.sock, (struct sockaddr *) &addr,
225206b73d0SCy Schubert sizeof(addr)) < 0) {
226206b73d0SCy Schubert wpa_printf(MSG_ERROR, "macsec_qca: bind: %s", strerror(errno));
227206b73d0SCy Schubert return -1;
228206b73d0SCy Schubert }
229206b73d0SCy Schubert
230206b73d0SCy Schubert /* filter multicast address */
231206b73d0SCy Schubert if (wired_multicast_membership(drv->common.sock, ifr.ifr_ifindex,
232206b73d0SCy Schubert pae_group_addr, 1) < 0) {
233206b73d0SCy Schubert wpa_printf(MSG_ERROR,
234206b73d0SCy Schubert "macsec_qca_init_sockets: Failed to add multicast group membership");
235206b73d0SCy Schubert return -1;
236206b73d0SCy Schubert }
237206b73d0SCy Schubert
238206b73d0SCy Schubert os_memset(&ifr, 0, sizeof(ifr));
239206b73d0SCy Schubert os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
240206b73d0SCy Schubert if (ioctl(drv->common.sock, SIOCGIFHWADDR, &ifr) != 0) {
241206b73d0SCy Schubert wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s",
242206b73d0SCy Schubert strerror(errno));
243206b73d0SCy Schubert return -1;
244206b73d0SCy Schubert }
245206b73d0SCy Schubert
246206b73d0SCy Schubert if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
247206b73d0SCy Schubert wpa_printf(MSG_INFO, "Invalid HW-addr family 0x%04x",
248206b73d0SCy Schubert ifr.ifr_hwaddr.sa_family);
249206b73d0SCy Schubert return -1;
250206b73d0SCy Schubert }
251206b73d0SCy Schubert os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
252206b73d0SCy Schubert
253206b73d0SCy Schubert return 0;
254206b73d0SCy Schubert #else /* __linux__ */
255206b73d0SCy Schubert return -1;
256206b73d0SCy Schubert #endif /* __linux__ */
257206b73d0SCy Schubert }
258206b73d0SCy Schubert
259206b73d0SCy Schubert
macsec_qca_secy_id_get(const char * ifname,u32 * secy_id)2604b72b91aSCy Schubert static int macsec_qca_secy_id_get(const char *ifname, u32 *secy_id)
2614b72b91aSCy Schubert {
2624b72b91aSCy Schubert #ifdef NSS_MACSEC_SECY_ID_GET_FUNC
2634b72b91aSCy Schubert /* Get secy id from nss macsec driver */
2644b72b91aSCy Schubert return nss_macsec_secy_id_get((u8 *) ifname, secy_id);
2654b72b91aSCy Schubert #else /* NSS_MACSEC_SECY_ID_GET_FUNC */
2664b72b91aSCy Schubert /* Board specific settings */
2674b72b91aSCy Schubert if (os_strcmp(ifname, "eth2") == 0) {
2684b72b91aSCy Schubert *secy_id = 1;
2694b72b91aSCy Schubert } else if (os_strcmp(ifname, "eth3") == 0) {
2704b72b91aSCy Schubert *secy_id = 2;
2714b72b91aSCy Schubert } else if (os_strcmp(ifname, "eth4") == 0 ||
2724b72b91aSCy Schubert os_strcmp(ifname, "eth0") == 0) {
2734b72b91aSCy Schubert *secy_id = 0;
2744b72b91aSCy Schubert } else if (os_strcmp(ifname, "eth5") == 0 ||
2754b72b91aSCy Schubert os_strcmp(ifname, "eth1") == 0) {
2764b72b91aSCy Schubert *secy_id = 1;
2774b72b91aSCy Schubert } else {
2784b72b91aSCy Schubert *secy_id = -1;
2794b72b91aSCy Schubert return -1;
2804b72b91aSCy Schubert }
2814b72b91aSCy Schubert
2824b72b91aSCy Schubert return 0;
2834b72b91aSCy Schubert #endif /* NSS_MACSEC_SECY_ID_GET_FUNC */
2844b72b91aSCy Schubert }
2854b72b91aSCy Schubert
2864b72b91aSCy Schubert
macsec_qca_init(void * ctx,const char * ifname)2875b9c547cSRui Paulo static void * macsec_qca_init(void *ctx, const char *ifname)
2885b9c547cSRui Paulo {
2895b9c547cSRui Paulo struct macsec_qca_data *drv;
2905b9c547cSRui Paulo
2915b9c547cSRui Paulo drv = os_zalloc(sizeof(*drv));
2925b9c547cSRui Paulo if (drv == NULL)
2935b9c547cSRui Paulo return NULL;
2945b9c547cSRui Paulo
2954b72b91aSCy Schubert if (macsec_qca_secy_id_get(ifname, &drv->secy_id)) {
2964b72b91aSCy Schubert wpa_printf(MSG_ERROR,
2974b72b91aSCy Schubert "macsec_qca: Failed to get secy_id for %s", ifname);
2984b72b91aSCy Schubert os_free(drv);
2994b72b91aSCy Schubert return NULL;
3004b72b91aSCy Schubert }
3015b9c547cSRui Paulo
30285732ac8SCy Schubert if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
3035b9c547cSRui Paulo os_free(drv);
3045b9c547cSRui Paulo return NULL;
3055b9c547cSRui Paulo }
3065b9c547cSRui Paulo
3075b9c547cSRui Paulo return drv;
3085b9c547cSRui Paulo }
3095b9c547cSRui Paulo
3105b9c547cSRui Paulo
macsec_qca_deinit(void * priv)3115b9c547cSRui Paulo static void macsec_qca_deinit(void *priv)
3125b9c547cSRui Paulo {
3135b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
3145b9c547cSRui Paulo
31585732ac8SCy Schubert driver_wired_deinit_common(&drv->common);
3165b9c547cSRui Paulo os_free(drv);
3175b9c547cSRui Paulo }
3185b9c547cSRui Paulo
3195b9c547cSRui Paulo
macsec_qca_hapd_init(struct hostapd_data * hapd,struct wpa_init_params * params)320206b73d0SCy Schubert static void * macsec_qca_hapd_init(struct hostapd_data *hapd,
321206b73d0SCy Schubert struct wpa_init_params *params)
322206b73d0SCy Schubert {
323206b73d0SCy Schubert struct macsec_qca_data *drv;
324206b73d0SCy Schubert
325206b73d0SCy Schubert drv = os_zalloc(sizeof(struct macsec_qca_data));
326206b73d0SCy Schubert if (!drv) {
327206b73d0SCy Schubert wpa_printf(MSG_INFO,
328206b73d0SCy Schubert "Could not allocate memory for macsec_qca driver data");
329206b73d0SCy Schubert return NULL;
330206b73d0SCy Schubert }
331206b73d0SCy Schubert
3324b72b91aSCy Schubert if (macsec_qca_secy_id_get(params->ifname, &drv->secy_id)) {
3334b72b91aSCy Schubert wpa_printf(MSG_ERROR,
3344b72b91aSCy Schubert "macsec_qca: Failed to get secy_id for %s",
3354b72b91aSCy Schubert params->ifname);
3364b72b91aSCy Schubert os_free(drv);
3374b72b91aSCy Schubert return NULL;
3384b72b91aSCy Schubert }
339206b73d0SCy Schubert
340206b73d0SCy Schubert drv->common.ctx = hapd;
341206b73d0SCy Schubert os_strlcpy(drv->common.ifname, params->ifname,
342206b73d0SCy Schubert sizeof(drv->common.ifname));
343206b73d0SCy Schubert drv->use_pae_group_addr = params->use_pae_group_addr;
344206b73d0SCy Schubert
345206b73d0SCy Schubert if (macsec_qca_init_sockets(drv, params->own_addr)) {
346206b73d0SCy Schubert os_free(drv);
347206b73d0SCy Schubert return NULL;
348206b73d0SCy Schubert }
349206b73d0SCy Schubert
350206b73d0SCy Schubert return drv;
351206b73d0SCy Schubert }
352206b73d0SCy Schubert
353206b73d0SCy Schubert
macsec_qca_hapd_deinit(void * priv)354206b73d0SCy Schubert static void macsec_qca_hapd_deinit(void *priv)
355206b73d0SCy Schubert {
356206b73d0SCy Schubert struct macsec_qca_data *drv = priv;
357206b73d0SCy Schubert
358206b73d0SCy Schubert if (drv->common.sock >= 0) {
359206b73d0SCy Schubert eloop_unregister_read_sock(drv->common.sock);
360206b73d0SCy Schubert close(drv->common.sock);
361206b73d0SCy Schubert }
362206b73d0SCy Schubert
363206b73d0SCy Schubert os_free(drv);
364206b73d0SCy Schubert }
365206b73d0SCy Schubert
366206b73d0SCy Schubert
macsec_qca_send_eapol(void * priv,const u8 * addr,const u8 * data,size_t data_len,int encrypt,const u8 * own_addr,u32 flags,int link_id)367206b73d0SCy Schubert static int macsec_qca_send_eapol(void *priv, const u8 *addr,
368206b73d0SCy Schubert const u8 *data, size_t data_len, int encrypt,
369*a90b9d01SCy Schubert const u8 *own_addr, u32 flags, int link_id)
370206b73d0SCy Schubert {
371206b73d0SCy Schubert struct macsec_qca_data *drv = priv;
372206b73d0SCy Schubert struct ieee8023_hdr *hdr;
373206b73d0SCy Schubert size_t len;
374206b73d0SCy Schubert u8 *pos;
375206b73d0SCy Schubert int res;
376206b73d0SCy Schubert
377206b73d0SCy Schubert len = sizeof(*hdr) + data_len;
378206b73d0SCy Schubert hdr = os_zalloc(len);
379206b73d0SCy Schubert if (!hdr) {
380206b73d0SCy Schubert wpa_printf(MSG_INFO,
381206b73d0SCy Schubert "malloc() failed for macsec_qca_send_eapol(len=%lu)",
382206b73d0SCy Schubert (unsigned long) len);
383206b73d0SCy Schubert return -1;
384206b73d0SCy Schubert }
385206b73d0SCy Schubert
386206b73d0SCy Schubert os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
387206b73d0SCy Schubert ETH_ALEN);
388206b73d0SCy Schubert os_memcpy(hdr->src, own_addr, ETH_ALEN);
389206b73d0SCy Schubert hdr->ethertype = htons(ETH_P_PAE);
390206b73d0SCy Schubert
391206b73d0SCy Schubert pos = (u8 *) (hdr + 1);
392206b73d0SCy Schubert os_memcpy(pos, data, data_len);
393206b73d0SCy Schubert
394206b73d0SCy Schubert res = send(drv->common.sock, (u8 *) hdr, len, 0);
395206b73d0SCy Schubert os_free(hdr);
396206b73d0SCy Schubert
397206b73d0SCy Schubert if (res < 0) {
398206b73d0SCy Schubert wpa_printf(MSG_ERROR,
399206b73d0SCy Schubert "macsec_qca_send_eapol - packet len: %lu - failed: send: %s",
400206b73d0SCy Schubert (unsigned long) len, strerror(errno));
401206b73d0SCy Schubert }
402206b73d0SCy Schubert
403206b73d0SCy Schubert return res;
404206b73d0SCy Schubert }
405206b73d0SCy Schubert
406206b73d0SCy Schubert
macsec_qca_macsec_init(void * priv,struct macsec_init_params * params)4075b9c547cSRui Paulo static int macsec_qca_macsec_init(void *priv, struct macsec_init_params *params)
4085b9c547cSRui Paulo {
4095b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
4105b9c547cSRui Paulo
4115b9c547cSRui Paulo drv->always_include_sci = params->always_include_sci;
4125b9c547cSRui Paulo drv->use_es = params->use_es;
4135b9c547cSRui Paulo drv->use_scb = params->use_scb;
4145b9c547cSRui Paulo
4155b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: es=%d, scb=%d, sci=%d",
4165b9c547cSRui Paulo __func__, drv->use_es, drv->use_scb,
4175b9c547cSRui Paulo drv->always_include_sci);
4185b9c547cSRui Paulo
4195b9c547cSRui Paulo __macsec_drv_init(drv);
4205b9c547cSRui Paulo
4215b9c547cSRui Paulo return 0;
4225b9c547cSRui Paulo }
4235b9c547cSRui Paulo
4245b9c547cSRui Paulo
macsec_qca_macsec_deinit(void * priv)4255b9c547cSRui Paulo static int macsec_qca_macsec_deinit(void *priv)
4265b9c547cSRui Paulo {
4275b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
4285b9c547cSRui Paulo
4295b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s", __func__);
4305b9c547cSRui Paulo
4315b9c547cSRui Paulo __macsec_drv_deinit(drv);
4325b9c547cSRui Paulo
4335b9c547cSRui Paulo return 0;
4345b9c547cSRui Paulo }
4355b9c547cSRui Paulo
4365b9c547cSRui Paulo
macsec_qca_get_capability(void * priv,enum macsec_cap * cap)43785732ac8SCy Schubert static int macsec_qca_get_capability(void *priv, enum macsec_cap *cap)
43885732ac8SCy Schubert {
43985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s", __func__);
44085732ac8SCy Schubert
44185732ac8SCy Schubert *cap = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
44285732ac8SCy Schubert
44385732ac8SCy Schubert return 0;
44485732ac8SCy Schubert }
44585732ac8SCy Schubert
44685732ac8SCy Schubert
macsec_qca_enable_protect_frames(void * priv,bool enabled)447c1d255d3SCy Schubert static int macsec_qca_enable_protect_frames(void *priv, bool enabled)
4485b9c547cSRui Paulo {
4495b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
4505b9c547cSRui Paulo int ret = 0;
4515b9c547cSRui Paulo
4525b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
4535b9c547cSRui Paulo
4545b9c547cSRui Paulo drv->protect_frames = enabled;
4555b9c547cSRui Paulo
4565b9c547cSRui Paulo return ret;
4575b9c547cSRui Paulo }
4585b9c547cSRui Paulo
4595b9c547cSRui Paulo
macsec_qca_set_replay_protect(void * priv,bool enabled,unsigned int window)460c1d255d3SCy Schubert static int macsec_qca_set_replay_protect(void *priv, bool enabled,
4615b9c547cSRui Paulo unsigned int window)
4625b9c547cSRui Paulo {
4635b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
4645b9c547cSRui Paulo int ret = 0;
4655b9c547cSRui Paulo
4665b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: enabled=%d, win=%u",
4675b9c547cSRui Paulo __func__, enabled, window);
4685b9c547cSRui Paulo
4695b9c547cSRui Paulo drv->replay_protect = enabled;
4705b9c547cSRui Paulo drv->replay_window = window;
4715b9c547cSRui Paulo
4725b9c547cSRui Paulo return ret;
4735b9c547cSRui Paulo }
4745b9c547cSRui Paulo
4755b9c547cSRui Paulo
macsec_qca_cs_type_get(u64 cs)47685732ac8SCy Schubert static fal_cipher_suite_e macsec_qca_cs_type_get(u64 cs)
47785732ac8SCy Schubert {
47885732ac8SCy Schubert if (cs == CS_ID_GCM_AES_128)
47985732ac8SCy Schubert return FAL_CIPHER_SUITE_AES_GCM_128;
48085732ac8SCy Schubert if (cs == CS_ID_GCM_AES_256)
48185732ac8SCy Schubert return FAL_CIPHER_SUITE_AES_GCM_256;
48285732ac8SCy Schubert return FAL_CIPHER_SUITE_MAX;
48385732ac8SCy Schubert }
48485732ac8SCy Schubert
48585732ac8SCy Schubert
macsec_qca_set_current_cipher_suite(void * priv,u64 cs)486780fb4a2SCy Schubert static int macsec_qca_set_current_cipher_suite(void *priv, u64 cs)
4875b9c547cSRui Paulo {
48885732ac8SCy Schubert struct macsec_qca_data *drv = priv;
48985732ac8SCy Schubert fal_cipher_suite_e cs_type;
49085732ac8SCy Schubert
49185732ac8SCy Schubert if (cs != CS_ID_GCM_AES_128 && cs != CS_ID_GCM_AES_256) {
492780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
493780fb4a2SCy Schubert "%s: NOT supported CipherSuite: %016" PRIx64,
494780fb4a2SCy Schubert __func__, cs);
4955b9c547cSRui Paulo return -1;
4965b9c547cSRui Paulo }
4975b9c547cSRui Paulo
49885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: CipherSuite: %016" PRIx64, __func__, cs);
4995b9c547cSRui Paulo
50085732ac8SCy Schubert cs_type = macsec_qca_cs_type_get(cs);
50185732ac8SCy Schubert return nss_macsec_secy_cipher_suite_set(drv->secy_id, cs_type);
5025b9c547cSRui Paulo }
5035b9c547cSRui Paulo
5045b9c547cSRui Paulo
macsec_qca_enable_controlled_port(void * priv,bool enabled)505c1d255d3SCy Schubert static int macsec_qca_enable_controlled_port(void *priv, bool enabled)
5065b9c547cSRui Paulo {
5075b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
5085b9c547cSRui Paulo int ret = 0;
5095b9c547cSRui Paulo
5105b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: enable=%d", __func__, enabled);
5115b9c547cSRui Paulo
5125b9c547cSRui Paulo ret += nss_macsec_secy_controlled_port_en_set(drv->secy_id, enabled);
5135b9c547cSRui Paulo
5145b9c547cSRui Paulo return ret;
5155b9c547cSRui Paulo }
5165b9c547cSRui Paulo
5175b9c547cSRui Paulo
macsec_qca_lookup_channel(struct channel_map * map,struct ieee802_1x_mka_sci * sci,u32 * channel)51885732ac8SCy Schubert static int macsec_qca_lookup_channel(struct channel_map *map,
51985732ac8SCy Schubert struct ieee802_1x_mka_sci *sci,
52085732ac8SCy Schubert u32 *channel)
52185732ac8SCy Schubert {
52285732ac8SCy Schubert u32 i;
52385732ac8SCy Schubert
52485732ac8SCy Schubert for (i = 0; i < MAXSC; i++) {
52585732ac8SCy Schubert if (os_memcmp(&map[i].sci, sci,
52685732ac8SCy Schubert sizeof(struct ieee802_1x_mka_sci)) == 0) {
52785732ac8SCy Schubert *channel = i;
52885732ac8SCy Schubert return 0;
52985732ac8SCy Schubert }
53085732ac8SCy Schubert }
53185732ac8SCy Schubert
53285732ac8SCy Schubert return -1;
53385732ac8SCy Schubert }
53485732ac8SCy Schubert
53585732ac8SCy Schubert
macsec_qca_register_channel(struct channel_map * map,struct ieee802_1x_mka_sci * sci,u32 channel)53685732ac8SCy Schubert static void macsec_qca_register_channel(struct channel_map *map,
53785732ac8SCy Schubert struct ieee802_1x_mka_sci *sci,
53885732ac8SCy Schubert u32 channel)
53985732ac8SCy Schubert {
54085732ac8SCy Schubert os_memcpy(&map[channel].sci, sci, sizeof(struct ieee802_1x_mka_sci));
54185732ac8SCy Schubert }
54285732ac8SCy Schubert
54385732ac8SCy Schubert
macsec_qca_lookup_receive_channel(struct macsec_qca_data * drv,struct receive_sc * sc,u32 * channel)54485732ac8SCy Schubert static int macsec_qca_lookup_receive_channel(struct macsec_qca_data *drv,
54585732ac8SCy Schubert struct receive_sc *sc,
54685732ac8SCy Schubert u32 *channel)
54785732ac8SCy Schubert {
54885732ac8SCy Schubert return macsec_qca_lookup_channel(drv->receive_channel_map, &sc->sci,
54985732ac8SCy Schubert channel);
55085732ac8SCy Schubert }
55185732ac8SCy Schubert
55285732ac8SCy Schubert
macsec_qca_register_receive_channel(struct macsec_qca_data * drv,struct receive_sc * sc,u32 channel)55385732ac8SCy Schubert static void macsec_qca_register_receive_channel(struct macsec_qca_data *drv,
55485732ac8SCy Schubert struct receive_sc *sc,
55585732ac8SCy Schubert u32 channel)
55685732ac8SCy Schubert {
55785732ac8SCy Schubert macsec_qca_register_channel(drv->receive_channel_map, &sc->sci,
55885732ac8SCy Schubert channel);
55985732ac8SCy Schubert }
56085732ac8SCy Schubert
56185732ac8SCy Schubert
macsec_qca_lookup_transmit_channel(struct macsec_qca_data * drv,struct transmit_sc * sc,u32 * channel)56285732ac8SCy Schubert static int macsec_qca_lookup_transmit_channel(struct macsec_qca_data *drv,
56385732ac8SCy Schubert struct transmit_sc *sc,
56485732ac8SCy Schubert u32 *channel)
56585732ac8SCy Schubert {
56685732ac8SCy Schubert return macsec_qca_lookup_channel(drv->transmit_channel_map, &sc->sci,
56785732ac8SCy Schubert channel);
56885732ac8SCy Schubert }
56985732ac8SCy Schubert
57085732ac8SCy Schubert
macsec_qca_register_transmit_channel(struct macsec_qca_data * drv,struct transmit_sc * sc,u32 channel)57185732ac8SCy Schubert static void macsec_qca_register_transmit_channel(struct macsec_qca_data *drv,
57285732ac8SCy Schubert struct transmit_sc *sc,
57385732ac8SCy Schubert u32 channel)
57485732ac8SCy Schubert {
57585732ac8SCy Schubert macsec_qca_register_channel(drv->transmit_channel_map, &sc->sci,
57685732ac8SCy Schubert channel);
57785732ac8SCy Schubert }
57885732ac8SCy Schubert
57985732ac8SCy Schubert
macsec_qca_get_receive_lowest_pn(void * priv,struct receive_sa * sa)58085732ac8SCy Schubert static int macsec_qca_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
5815b9c547cSRui Paulo {
5825b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
5835b9c547cSRui Paulo int ret = 0;
5845b9c547cSRui Paulo u32 next_pn = 0;
585c1d255d3SCy Schubert bool enabled = false;
5865b9c547cSRui Paulo u32 win;
58785732ac8SCy Schubert u32 channel;
5885b9c547cSRui Paulo
58985732ac8SCy Schubert ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
59085732ac8SCy Schubert if (ret != 0)
59185732ac8SCy Schubert return ret;
59285732ac8SCy Schubert
59385732ac8SCy Schubert ret += nss_macsec_secy_rx_sa_next_pn_get(drv->secy_id, channel, sa->an,
5945b9c547cSRui Paulo &next_pn);
5955b9c547cSRui Paulo ret += nss_macsec_secy_rx_sc_replay_protect_get(drv->secy_id, channel,
5965b9c547cSRui Paulo &enabled);
5975b9c547cSRui Paulo ret += nss_macsec_secy_rx_sc_anti_replay_window_get(drv->secy_id,
5985b9c547cSRui Paulo channel, &win);
5995b9c547cSRui Paulo
6005b9c547cSRui Paulo if (enabled)
60185732ac8SCy Schubert sa->lowest_pn = (next_pn > win) ? (next_pn - win) : 1;
6025b9c547cSRui Paulo else
60385732ac8SCy Schubert sa->lowest_pn = next_pn;
6045b9c547cSRui Paulo
60585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: lpn=0x%x", __func__, sa->lowest_pn);
6065b9c547cSRui Paulo
6075b9c547cSRui Paulo return ret;
6085b9c547cSRui Paulo }
6095b9c547cSRui Paulo
6105b9c547cSRui Paulo
macsec_qca_get_transmit_next_pn(void * priv,struct transmit_sa * sa)61185732ac8SCy Schubert static int macsec_qca_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
6125b9c547cSRui Paulo {
6135b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
6145b9c547cSRui Paulo int ret = 0;
61585732ac8SCy Schubert u32 channel;
6165b9c547cSRui Paulo
61785732ac8SCy Schubert ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
61885732ac8SCy Schubert if (ret != 0)
61985732ac8SCy Schubert return ret;
6205b9c547cSRui Paulo
62185732ac8SCy Schubert ret += nss_macsec_secy_tx_sa_next_pn_get(drv->secy_id, channel, sa->an,
62285732ac8SCy Schubert &sa->next_pn);
62385732ac8SCy Schubert
62485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: npn=0x%x", __func__, sa->next_pn);
6255b9c547cSRui Paulo
6265b9c547cSRui Paulo return ret;
6275b9c547cSRui Paulo }
6285b9c547cSRui Paulo
6295b9c547cSRui Paulo
macsec_qca_set_transmit_next_pn(void * priv,struct transmit_sa * sa)63085732ac8SCy Schubert static int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
6315b9c547cSRui Paulo {
6325b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
6335b9c547cSRui Paulo int ret = 0;
63485732ac8SCy Schubert u32 channel;
6355b9c547cSRui Paulo
63685732ac8SCy Schubert ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
63785732ac8SCy Schubert if (ret != 0)
63885732ac8SCy Schubert return ret;
6395b9c547cSRui Paulo
64085732ac8SCy Schubert ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
64185732ac8SCy Schubert sa->next_pn);
64285732ac8SCy Schubert
64385732ac8SCy Schubert wpa_printf(MSG_INFO, "%s: npn=0x%x", __func__, sa->next_pn);
6445b9c547cSRui Paulo
6455b9c547cSRui Paulo return ret;
6465b9c547cSRui Paulo }
6475b9c547cSRui Paulo
6485b9c547cSRui Paulo
macsec_qca_get_available_receive_sc(void * priv,u32 * channel)6495b9c547cSRui Paulo static int macsec_qca_get_available_receive_sc(void *priv, u32 *channel)
6505b9c547cSRui Paulo {
6515b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
6525b9c547cSRui Paulo int ret = 0;
6535b9c547cSRui Paulo u32 sc_ch = 0;
654c1d255d3SCy Schubert bool in_use = false;
6555b9c547cSRui Paulo
6565b9c547cSRui Paulo for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
6575b9c547cSRui Paulo ret = nss_macsec_secy_rx_sc_in_used_get(drv->secy_id, sc_ch,
6585b9c547cSRui Paulo &in_use);
6595b9c547cSRui Paulo if (ret)
6605b9c547cSRui Paulo continue;
6615b9c547cSRui Paulo
6625b9c547cSRui Paulo if (!in_use) {
6635b9c547cSRui Paulo *channel = sc_ch;
6645b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: channel=%d",
6655b9c547cSRui Paulo __func__, *channel);
6665b9c547cSRui Paulo return 0;
6675b9c547cSRui Paulo }
6685b9c547cSRui Paulo }
6695b9c547cSRui Paulo
6705b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: no available channel", __func__);
6715b9c547cSRui Paulo
6725b9c547cSRui Paulo return -1;
6735b9c547cSRui Paulo }
6745b9c547cSRui Paulo
6755b9c547cSRui Paulo
macsec_qca_create_receive_sc(void * priv,struct receive_sc * sc,unsigned int conf_offset,int validation)67685732ac8SCy Schubert static int macsec_qca_create_receive_sc(void *priv, struct receive_sc *sc,
6775b9c547cSRui Paulo unsigned int conf_offset,
6785b9c547cSRui Paulo int validation)
6795b9c547cSRui Paulo {
6805b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
6815b9c547cSRui Paulo int ret = 0;
6825b9c547cSRui Paulo fal_rx_prc_lut_t entry;
6835b9c547cSRui Paulo fal_rx_sc_validate_frame_e vf;
6845b9c547cSRui Paulo enum validate_frames validate_frames = validation;
68585732ac8SCy Schubert u32 channel;
68685732ac8SCy Schubert const u8 *sci_addr = sc->sci.addr;
68785732ac8SCy Schubert u16 sci_port = be_to_host16(sc->sci.port);
68885732ac8SCy Schubert
68985732ac8SCy Schubert ret = macsec_qca_get_available_receive_sc(priv, &channel);
69085732ac8SCy Schubert if (ret != 0)
69185732ac8SCy Schubert return ret;
6925b9c547cSRui Paulo
6935b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
6945b9c547cSRui Paulo
6955b9c547cSRui Paulo /* rx prc lut */
6965b9c547cSRui Paulo os_memset(&entry, 0, sizeof(entry));
6975b9c547cSRui Paulo
6985b9c547cSRui Paulo os_memcpy(entry.sci, sci_addr, ETH_ALEN);
69985732ac8SCy Schubert entry.sci[6] = (sci_port >> 8) & 0xff;
70085732ac8SCy Schubert entry.sci[7] = sci_port & 0xff;
7015b9c547cSRui Paulo entry.sci_mask = 0xf;
7025b9c547cSRui Paulo
7035b9c547cSRui Paulo entry.valid = 1;
7045b9c547cSRui Paulo entry.channel = channel;
7055b9c547cSRui Paulo entry.action = FAL_RX_PRC_ACTION_PROCESS;
7065b9c547cSRui Paulo entry.offset = conf_offset;
7075b9c547cSRui Paulo
7085b9c547cSRui Paulo /* rx validate frame */
7095b9c547cSRui Paulo if (validate_frames == Strict)
7105b9c547cSRui Paulo vf = FAL_RX_SC_VALIDATE_FRAME_STRICT;
7115b9c547cSRui Paulo else if (validate_frames == Checked)
7125b9c547cSRui Paulo vf = FAL_RX_SC_VALIDATE_FRAME_CHECK;
7135b9c547cSRui Paulo else
7145b9c547cSRui Paulo vf = FAL_RX_SC_VALIDATE_FRAME_DISABLED;
7155b9c547cSRui Paulo
7165b9c547cSRui Paulo ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
7175b9c547cSRui Paulo ret += nss_macsec_secy_rx_sc_create(drv->secy_id, channel);
7185b9c547cSRui Paulo ret += nss_macsec_secy_rx_sc_validate_frame_set(drv->secy_id, channel,
7195b9c547cSRui Paulo vf);
7205b9c547cSRui Paulo ret += nss_macsec_secy_rx_sc_replay_protect_set(drv->secy_id, channel,
7215b9c547cSRui Paulo drv->replay_protect);
7225b9c547cSRui Paulo ret += nss_macsec_secy_rx_sc_anti_replay_window_set(drv->secy_id,
7235b9c547cSRui Paulo channel,
7245b9c547cSRui Paulo drv->replay_window);
7255b9c547cSRui Paulo
72685732ac8SCy Schubert macsec_qca_register_receive_channel(drv, sc, channel);
72785732ac8SCy Schubert
7285b9c547cSRui Paulo return ret;
7295b9c547cSRui Paulo }
7305b9c547cSRui Paulo
7315b9c547cSRui Paulo
macsec_qca_delete_receive_sc(void * priv,struct receive_sc * sc)73285732ac8SCy Schubert static int macsec_qca_delete_receive_sc(void *priv, struct receive_sc *sc)
7335b9c547cSRui Paulo {
7345b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
73585732ac8SCy Schubert int ret;
7365b9c547cSRui Paulo fal_rx_prc_lut_t entry;
73785732ac8SCy Schubert u32 channel;
73885732ac8SCy Schubert
73985732ac8SCy Schubert ret = macsec_qca_lookup_receive_channel(priv, sc, &channel);
74085732ac8SCy Schubert if (ret != 0)
74185732ac8SCy Schubert return ret;
7425b9c547cSRui Paulo
7435b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
7445b9c547cSRui Paulo
7455b9c547cSRui Paulo /* rx prc lut */
7465b9c547cSRui Paulo os_memset(&entry, 0, sizeof(entry));
7475b9c547cSRui Paulo
7485b9c547cSRui Paulo ret += nss_macsec_secy_rx_sc_del(drv->secy_id, channel);
7495b9c547cSRui Paulo ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
7505b9c547cSRui Paulo
7515b9c547cSRui Paulo return ret;
7525b9c547cSRui Paulo }
7535b9c547cSRui Paulo
7545b9c547cSRui Paulo
macsec_qca_create_receive_sa(void * priv,struct receive_sa * sa)75585732ac8SCy Schubert static int macsec_qca_create_receive_sa(void *priv, struct receive_sa *sa)
7565b9c547cSRui Paulo {
7575b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
75885732ac8SCy Schubert int ret;
7595b9c547cSRui Paulo fal_rx_sak_t rx_sak;
7605b9c547cSRui Paulo int i = 0;
76185732ac8SCy Schubert u32 channel;
76285732ac8SCy Schubert fal_rx_prc_lut_t entry;
76385732ac8SCy Schubert u32 offset;
76485732ac8SCy Schubert
76585732ac8SCy Schubert ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
76685732ac8SCy Schubert if (ret != 0)
76785732ac8SCy Schubert return ret;
7685b9c547cSRui Paulo
7695b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s, channel=%d, an=%d, lpn=0x%x",
77085732ac8SCy Schubert __func__, channel, sa->an, sa->lowest_pn);
7715b9c547cSRui Paulo
7725b9c547cSRui Paulo os_memset(&rx_sak, 0, sizeof(rx_sak));
77385732ac8SCy Schubert rx_sak.sak_len = sa->pkey->key_len;
77485732ac8SCy Schubert if (sa->pkey->key_len == SAK_128_LEN) {
7755b9c547cSRui Paulo for (i = 0; i < 16; i++)
77685732ac8SCy Schubert rx_sak.sak[i] = sa->pkey->key[15 - i];
77785732ac8SCy Schubert } else if (sa->pkey->key_len == SAK_256_LEN) {
77885732ac8SCy Schubert for (i = 0; i < 16; i++) {
77985732ac8SCy Schubert rx_sak.sak1[i] = sa->pkey->key[15 - i];
78085732ac8SCy Schubert rx_sak.sak[i] = sa->pkey->key[31 - i];
78185732ac8SCy Schubert }
78285732ac8SCy Schubert } else {
78385732ac8SCy Schubert return -1;
78485732ac8SCy Schubert }
7855b9c547cSRui Paulo
78685732ac8SCy Schubert if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0)
78785732ac8SCy Schubert offset = 0;
78885732ac8SCy Schubert else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30)
78985732ac8SCy Schubert offset = 30;
79085732ac8SCy Schubert else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50)
79185732ac8SCy Schubert offset = 50;
79285732ac8SCy Schubert else
79385732ac8SCy Schubert return -1;
79485732ac8SCy Schubert ret += nss_macsec_secy_rx_prc_lut_get(drv->secy_id, channel, &entry);
79585732ac8SCy Schubert entry.offset = offset;
79685732ac8SCy Schubert ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
79785732ac8SCy Schubert ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, sa->an);
79885732ac8SCy Schubert ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, sa->an,
79985732ac8SCy Schubert &rx_sak);
8005b9c547cSRui Paulo
8015b9c547cSRui Paulo return ret;
8025b9c547cSRui Paulo }
8035b9c547cSRui Paulo
8045b9c547cSRui Paulo
macsec_qca_enable_receive_sa(void * priv,struct receive_sa * sa)80585732ac8SCy Schubert static int macsec_qca_enable_receive_sa(void *priv, struct receive_sa *sa)
8065b9c547cSRui Paulo {
8075b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
80885732ac8SCy Schubert int ret;
80985732ac8SCy Schubert u32 channel;
8105b9c547cSRui Paulo
81185732ac8SCy Schubert ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
81285732ac8SCy Schubert if (ret != 0)
81385732ac8SCy Schubert return ret;
8145b9c547cSRui Paulo
81585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
81685732ac8SCy Schubert sa->an);
81785732ac8SCy Schubert
81885732ac8SCy Schubert ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
819c1d255d3SCy Schubert true);
8205b9c547cSRui Paulo
8215b9c547cSRui Paulo return ret;
8225b9c547cSRui Paulo }
8235b9c547cSRui Paulo
8245b9c547cSRui Paulo
macsec_qca_disable_receive_sa(void * priv,struct receive_sa * sa)82585732ac8SCy Schubert static int macsec_qca_disable_receive_sa(void *priv, struct receive_sa *sa)
8265b9c547cSRui Paulo {
8275b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
82885732ac8SCy Schubert int ret;
82985732ac8SCy Schubert u32 channel;
8305b9c547cSRui Paulo
83185732ac8SCy Schubert ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
83285732ac8SCy Schubert if (ret != 0)
83385732ac8SCy Schubert return ret;
8345b9c547cSRui Paulo
83585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
83685732ac8SCy Schubert sa->an);
83785732ac8SCy Schubert
83885732ac8SCy Schubert ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
839c1d255d3SCy Schubert false);
8405b9c547cSRui Paulo
8415b9c547cSRui Paulo return ret;
8425b9c547cSRui Paulo }
8435b9c547cSRui Paulo
8445b9c547cSRui Paulo
macsec_qca_get_available_transmit_sc(void * priv,u32 * channel)8455b9c547cSRui Paulo static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel)
8465b9c547cSRui Paulo {
8475b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
8485b9c547cSRui Paulo u32 sc_ch = 0;
849c1d255d3SCy Schubert bool in_use = false;
8505b9c547cSRui Paulo
8515b9c547cSRui Paulo for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
85285732ac8SCy Schubert if (nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch,
85385732ac8SCy Schubert &in_use))
8545b9c547cSRui Paulo continue;
8555b9c547cSRui Paulo
8565b9c547cSRui Paulo if (!in_use) {
8575b9c547cSRui Paulo *channel = sc_ch;
8585b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: channel=%d",
8595b9c547cSRui Paulo __func__, *channel);
8605b9c547cSRui Paulo return 0;
8615b9c547cSRui Paulo }
8625b9c547cSRui Paulo }
8635b9c547cSRui Paulo
864*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "%s: no available channel", __func__);
8655b9c547cSRui Paulo
8665b9c547cSRui Paulo return -1;
8675b9c547cSRui Paulo }
8685b9c547cSRui Paulo
8695b9c547cSRui Paulo
macsec_qca_create_transmit_sc(void * priv,struct transmit_sc * sc,unsigned int conf_offset)87085732ac8SCy Schubert static int macsec_qca_create_transmit_sc(void *priv, struct transmit_sc *sc,
8715b9c547cSRui Paulo unsigned int conf_offset)
8725b9c547cSRui Paulo {
8735b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
87485732ac8SCy Schubert int ret;
8755b9c547cSRui Paulo fal_tx_class_lut_t entry;
8765b9c547cSRui Paulo u8 psci[ETH_ALEN + 2];
87785732ac8SCy Schubert u32 channel;
87885732ac8SCy Schubert u16 sci_port = be_to_host16(sc->sci.port);
87985732ac8SCy Schubert
88085732ac8SCy Schubert ret = macsec_qca_get_available_transmit_sc(priv, &channel);
88185732ac8SCy Schubert if (ret != 0)
88285732ac8SCy Schubert return ret;
8835b9c547cSRui Paulo
8845b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
8855b9c547cSRui Paulo
8865b9c547cSRui Paulo /* class lut */
8875b9c547cSRui Paulo os_memset(&entry, 0, sizeof(entry));
8885b9c547cSRui Paulo
8895b9c547cSRui Paulo entry.valid = 1;
8905b9c547cSRui Paulo entry.action = FAL_TX_CLASS_ACTION_FORWARD;
8915b9c547cSRui Paulo entry.channel = channel;
8925b9c547cSRui Paulo
89385732ac8SCy Schubert os_memcpy(psci, sc->sci.addr, ETH_ALEN);
89485732ac8SCy Schubert psci[6] = (sci_port >> 8) & 0xff;
89585732ac8SCy Schubert psci[7] = sci_port & 0xff;
8965b9c547cSRui Paulo
8975b9c547cSRui Paulo ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
8985b9c547cSRui Paulo ret += nss_macsec_secy_tx_sc_create(drv->secy_id, channel, psci, 8);
8995b9c547cSRui Paulo ret += nss_macsec_secy_tx_sc_protect_set(drv->secy_id, channel,
9005b9c547cSRui Paulo drv->protect_frames);
9015b9c547cSRui Paulo ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
9025b9c547cSRui Paulo channel,
9035b9c547cSRui Paulo conf_offset);
9045b9c547cSRui Paulo
90585732ac8SCy Schubert macsec_qca_register_transmit_channel(drv, sc, channel);
90685732ac8SCy Schubert
9075b9c547cSRui Paulo return ret;
9085b9c547cSRui Paulo }
9095b9c547cSRui Paulo
9105b9c547cSRui Paulo
macsec_qca_delete_transmit_sc(void * priv,struct transmit_sc * sc)91185732ac8SCy Schubert static int macsec_qca_delete_transmit_sc(void *priv, struct transmit_sc *sc)
9125b9c547cSRui Paulo {
9135b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
91485732ac8SCy Schubert int ret;
9155b9c547cSRui Paulo fal_tx_class_lut_t entry;
91685732ac8SCy Schubert u32 channel;
91785732ac8SCy Schubert
91885732ac8SCy Schubert ret = macsec_qca_lookup_transmit_channel(priv, sc, &channel);
91985732ac8SCy Schubert if (ret != 0)
92085732ac8SCy Schubert return ret;
9215b9c547cSRui Paulo
9225b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
9235b9c547cSRui Paulo
9245b9c547cSRui Paulo /* class lut */
9255b9c547cSRui Paulo os_memset(&entry, 0, sizeof(entry));
9265b9c547cSRui Paulo
9275b9c547cSRui Paulo ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
9285b9c547cSRui Paulo ret += nss_macsec_secy_tx_sc_del(drv->secy_id, channel);
9295b9c547cSRui Paulo
9305b9c547cSRui Paulo return ret;
9315b9c547cSRui Paulo }
9325b9c547cSRui Paulo
9335b9c547cSRui Paulo
macsec_qca_create_transmit_sa(void * priv,struct transmit_sa * sa)93485732ac8SCy Schubert static int macsec_qca_create_transmit_sa(void *priv, struct transmit_sa *sa)
9355b9c547cSRui Paulo {
9365b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
93785732ac8SCy Schubert int ret;
9385b9c547cSRui Paulo u8 tci = 0;
9395b9c547cSRui Paulo fal_tx_sak_t tx_sak;
9405b9c547cSRui Paulo int i;
94185732ac8SCy Schubert u32 channel;
94285732ac8SCy Schubert u32 offset;
94385732ac8SCy Schubert
94485732ac8SCy Schubert ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
94585732ac8SCy Schubert if (ret != 0)
94685732ac8SCy Schubert return ret;
9475b9c547cSRui Paulo
9485b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
9495b9c547cSRui Paulo "%s: channel=%d, an=%d, next_pn=0x%x, confidentiality=%d",
95085732ac8SCy Schubert __func__, channel, sa->an, sa->next_pn, sa->confidentiality);
9515b9c547cSRui Paulo
9525b9c547cSRui Paulo if (drv->always_include_sci)
9535b9c547cSRui Paulo tci |= TCI_SC;
9545b9c547cSRui Paulo else if (drv->use_es)
9555b9c547cSRui Paulo tci |= TCI_ES;
9565b9c547cSRui Paulo else if (drv->use_scb)
9575b9c547cSRui Paulo tci |= TCI_SCB;
9585b9c547cSRui Paulo
95985732ac8SCy Schubert if (sa->confidentiality)
9605b9c547cSRui Paulo tci |= TCI_E | TCI_C;
9615b9c547cSRui Paulo
9625b9c547cSRui Paulo os_memset(&tx_sak, 0, sizeof(tx_sak));
96385732ac8SCy Schubert tx_sak.sak_len = sa->pkey->key_len;
96485732ac8SCy Schubert if (sa->pkey->key_len == SAK_128_LEN) {
9655b9c547cSRui Paulo for (i = 0; i < 16; i++)
96685732ac8SCy Schubert tx_sak.sak[i] = sa->pkey->key[15 - i];
96785732ac8SCy Schubert } else if (sa->pkey->key_len == SAK_256_LEN) {
96885732ac8SCy Schubert for (i = 0; i < 16; i++) {
96985732ac8SCy Schubert tx_sak.sak1[i] = sa->pkey->key[15 - i];
97085732ac8SCy Schubert tx_sak.sak[i] = sa->pkey->key[31 - i];
97185732ac8SCy Schubert }
97285732ac8SCy Schubert } else {
97385732ac8SCy Schubert return -1;
97485732ac8SCy Schubert }
9755b9c547cSRui Paulo
97685732ac8SCy Schubert if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0)
97785732ac8SCy Schubert offset = 0;
97885732ac8SCy Schubert else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30)
97985732ac8SCy Schubert offset = 30;
98085732ac8SCy Schubert else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50)
98185732ac8SCy Schubert offset = 50;
98285732ac8SCy Schubert else
98385732ac8SCy Schubert return -1;
98485732ac8SCy Schubert ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
98585732ac8SCy Schubert channel,
98685732ac8SCy Schubert offset);
98785732ac8SCy Schubert ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
98885732ac8SCy Schubert sa->next_pn);
98985732ac8SCy Schubert ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, sa->an,
99085732ac8SCy Schubert &tx_sak);
9915b9c547cSRui Paulo ret += nss_macsec_secy_tx_sc_tci_7_2_set(drv->secy_id, channel,
9925b9c547cSRui Paulo (tci >> 2));
99385732ac8SCy Schubert ret += nss_macsec_secy_tx_sc_an_set(drv->secy_id, channel, sa->an);
9945b9c547cSRui Paulo
9955b9c547cSRui Paulo return ret;
9965b9c547cSRui Paulo }
9975b9c547cSRui Paulo
9985b9c547cSRui Paulo
macsec_qca_enable_transmit_sa(void * priv,struct transmit_sa * sa)99985732ac8SCy Schubert static int macsec_qca_enable_transmit_sa(void *priv, struct transmit_sa *sa)
10005b9c547cSRui Paulo {
10015b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
100285732ac8SCy Schubert int ret;
100385732ac8SCy Schubert u32 channel;
10045b9c547cSRui Paulo
100585732ac8SCy Schubert ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
100685732ac8SCy Schubert if (ret != 0)
100785732ac8SCy Schubert return ret;
10085b9c547cSRui Paulo
100985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
101085732ac8SCy Schubert sa->an);
101185732ac8SCy Schubert
101285732ac8SCy Schubert ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
1013c1d255d3SCy Schubert true);
10145b9c547cSRui Paulo
10155b9c547cSRui Paulo return ret;
10165b9c547cSRui Paulo }
10175b9c547cSRui Paulo
10185b9c547cSRui Paulo
macsec_qca_disable_transmit_sa(void * priv,struct transmit_sa * sa)101985732ac8SCy Schubert static int macsec_qca_disable_transmit_sa(void *priv, struct transmit_sa *sa)
10205b9c547cSRui Paulo {
10215b9c547cSRui Paulo struct macsec_qca_data *drv = priv;
102285732ac8SCy Schubert int ret;
102385732ac8SCy Schubert u32 channel;
10245b9c547cSRui Paulo
102585732ac8SCy Schubert ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
102685732ac8SCy Schubert if (ret != 0)
102785732ac8SCy Schubert return ret;
10285b9c547cSRui Paulo
102985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
103085732ac8SCy Schubert sa->an);
103185732ac8SCy Schubert
103285732ac8SCy Schubert ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
1033c1d255d3SCy Schubert false);
10345b9c547cSRui Paulo
10355b9c547cSRui Paulo return ret;
10365b9c547cSRui Paulo }
10375b9c547cSRui Paulo
10385b9c547cSRui Paulo
10395b9c547cSRui Paulo const struct wpa_driver_ops wpa_driver_macsec_qca_ops = {
10405b9c547cSRui Paulo .name = "macsec_qca",
10415b9c547cSRui Paulo .desc = "QCA MACsec Ethernet driver",
104285732ac8SCy Schubert .get_ssid = driver_wired_get_ssid,
104385732ac8SCy Schubert .get_bssid = driver_wired_get_bssid,
104485732ac8SCy Schubert .get_capa = driver_wired_get_capa,
10455b9c547cSRui Paulo .init = macsec_qca_init,
10465b9c547cSRui Paulo .deinit = macsec_qca_deinit,
1047206b73d0SCy Schubert .hapd_init = macsec_qca_hapd_init,
1048206b73d0SCy Schubert .hapd_deinit = macsec_qca_hapd_deinit,
1049206b73d0SCy Schubert .hapd_send_eapol = macsec_qca_send_eapol,
10505b9c547cSRui Paulo
10515b9c547cSRui Paulo .macsec_init = macsec_qca_macsec_init,
10525b9c547cSRui Paulo .macsec_deinit = macsec_qca_macsec_deinit,
105385732ac8SCy Schubert .macsec_get_capability = macsec_qca_get_capability,
10545b9c547cSRui Paulo .enable_protect_frames = macsec_qca_enable_protect_frames,
10555b9c547cSRui Paulo .set_replay_protect = macsec_qca_set_replay_protect,
10565b9c547cSRui Paulo .set_current_cipher_suite = macsec_qca_set_current_cipher_suite,
10575b9c547cSRui Paulo .enable_controlled_port = macsec_qca_enable_controlled_port,
10585b9c547cSRui Paulo .get_receive_lowest_pn = macsec_qca_get_receive_lowest_pn,
10595b9c547cSRui Paulo .get_transmit_next_pn = macsec_qca_get_transmit_next_pn,
10605b9c547cSRui Paulo .set_transmit_next_pn = macsec_qca_set_transmit_next_pn,
10615b9c547cSRui Paulo .create_receive_sc = macsec_qca_create_receive_sc,
10625b9c547cSRui Paulo .delete_receive_sc = macsec_qca_delete_receive_sc,
10635b9c547cSRui Paulo .create_receive_sa = macsec_qca_create_receive_sa,
10645b9c547cSRui Paulo .enable_receive_sa = macsec_qca_enable_receive_sa,
10655b9c547cSRui Paulo .disable_receive_sa = macsec_qca_disable_receive_sa,
10665b9c547cSRui Paulo .create_transmit_sc = macsec_qca_create_transmit_sc,
10675b9c547cSRui Paulo .delete_transmit_sc = macsec_qca_delete_transmit_sc,
10685b9c547cSRui Paulo .create_transmit_sa = macsec_qca_create_transmit_sa,
10695b9c547cSRui Paulo .enable_transmit_sa = macsec_qca_enable_transmit_sa,
10705b9c547cSRui Paulo .disable_transmit_sa = macsec_qca_disable_transmit_sa,
10715b9c547cSRui Paulo };
1072