185732ac8SCy Schubert /*
285732ac8SCy Schubert * Driver interaction with Linux MACsec kernel module
385732ac8SCy Schubert * Copyright (c) 2016, Sabrina Dubroca <sd@queasysnail.net> and Red Hat, Inc.
4206b73d0SCy Schubert * Copyright (c) 2019, The Linux Foundation
585732ac8SCy Schubert *
685732ac8SCy Schubert * This software may be distributed under the terms of the BSD license.
785732ac8SCy Schubert * See README for more details.
885732ac8SCy Schubert */
985732ac8SCy Schubert
1085732ac8SCy Schubert #include "includes.h"
1185732ac8SCy Schubert #include <sys/ioctl.h>
1285732ac8SCy Schubert #include <net/if.h>
1385732ac8SCy Schubert #include <netpacket/packet.h>
1485732ac8SCy Schubert #include <net/if_arp.h>
1585732ac8SCy Schubert #include <net/if.h>
1685732ac8SCy Schubert #include <netlink/netlink.h>
1785732ac8SCy Schubert #include <netlink/genl/genl.h>
1885732ac8SCy Schubert #include <netlink/genl/ctrl.h>
1985732ac8SCy Schubert #include <netlink/route/link.h>
2085732ac8SCy Schubert #include <netlink/route/link/macsec.h>
2185732ac8SCy Schubert #include <linux/if_macsec.h>
2285732ac8SCy Schubert #include <inttypes.h>
2385732ac8SCy Schubert
2485732ac8SCy Schubert #include "utils/common.h"
2585732ac8SCy Schubert #include "utils/eloop.h"
26206b73d0SCy Schubert #include "common/eapol_common.h"
2785732ac8SCy Schubert #include "pae/ieee802_1x_kay.h"
2885732ac8SCy Schubert #include "driver.h"
2985732ac8SCy Schubert #include "driver_wired_common.h"
3085732ac8SCy Schubert
3185732ac8SCy Schubert #define DRV_PREFIX "macsec_linux: "
3285732ac8SCy Schubert
3385732ac8SCy Schubert #define UNUSED_SCI 0xffffffffffffffff
3485732ac8SCy Schubert
35*a90b9d01SCy Schubert #if LIBNL_VER_NUM >= LIBNL_VER(3, 6)
36*a90b9d01SCy Schubert #define LIBNL_HAS_OFFLOAD
37*a90b9d01SCy Schubert #endif
38*a90b9d01SCy Schubert
3985732ac8SCy Schubert struct cb_arg {
4085732ac8SCy Schubert struct macsec_drv_data *drv;
4185732ac8SCy Schubert u32 *pn;
4285732ac8SCy Schubert int ifindex;
4385732ac8SCy Schubert u8 txsa;
4485732ac8SCy Schubert u8 rxsa;
4585732ac8SCy Schubert u64 rxsci;
4685732ac8SCy Schubert };
4785732ac8SCy Schubert
4885732ac8SCy Schubert struct macsec_genl_ctx {
4985732ac8SCy Schubert struct nl_sock *sk;
5085732ac8SCy Schubert int macsec_genl_id;
5185732ac8SCy Schubert struct cb_arg cb_arg;
5285732ac8SCy Schubert };
5385732ac8SCy Schubert
5485732ac8SCy Schubert struct macsec_drv_data {
5585732ac8SCy Schubert struct driver_wired_common_data common;
5685732ac8SCy Schubert struct rtnl_link *link;
5785732ac8SCy Schubert struct nl_cache *link_cache;
5885732ac8SCy Schubert struct nl_sock *sk;
5985732ac8SCy Schubert struct macsec_genl_ctx ctx;
6085732ac8SCy Schubert
6185732ac8SCy Schubert char ifname[IFNAMSIZ + 1];
6285732ac8SCy Schubert int ifi;
6385732ac8SCy Schubert int parent_ifi;
64206b73d0SCy Schubert int use_pae_group_addr;
6585732ac8SCy Schubert
66c1d255d3SCy Schubert bool created_link;
6785732ac8SCy Schubert
68c1d255d3SCy Schubert bool controlled_port_enabled;
69c1d255d3SCy Schubert bool controlled_port_enabled_set;
7085732ac8SCy Schubert
71c1d255d3SCy Schubert bool protect_frames;
72c1d255d3SCy Schubert bool protect_frames_set;
7385732ac8SCy Schubert
74c1d255d3SCy Schubert bool encrypt;
75c1d255d3SCy Schubert bool encrypt_set;
7685732ac8SCy Schubert
77c1d255d3SCy Schubert bool replay_protect;
78c1d255d3SCy Schubert bool replay_protect_set;
7985732ac8SCy Schubert
80*a90b9d01SCy Schubert #ifdef LIBNL_HAS_OFFLOAD
81*a90b9d01SCy Schubert enum macsec_offload offload;
82*a90b9d01SCy Schubert bool offload_set;
83*a90b9d01SCy Schubert #endif /* LIBNL_HAS_OFFLOAD */
84*a90b9d01SCy Schubert
8585732ac8SCy Schubert u32 replay_window;
8685732ac8SCy Schubert
8785732ac8SCy Schubert u8 encoding_sa;
88c1d255d3SCy Schubert bool encoding_sa_set;
89*a90b9d01SCy Schubert
90*a90b9d01SCy Schubert u64 cipher_suite;
91*a90b9d01SCy Schubert bool cipher_suite_set;
9285732ac8SCy Schubert };
9385732ac8SCy Schubert
9485732ac8SCy Schubert
9585732ac8SCy Schubert static int dump_callback(struct nl_msg *msg, void *argp);
9685732ac8SCy Schubert
9785732ac8SCy Schubert
msg_prepare(enum macsec_nl_commands cmd,const struct macsec_genl_ctx * ctx,unsigned int ifindex)9885732ac8SCy Schubert static struct nl_msg * msg_prepare(enum macsec_nl_commands cmd,
9985732ac8SCy Schubert const struct macsec_genl_ctx *ctx,
10085732ac8SCy Schubert unsigned int ifindex)
10185732ac8SCy Schubert {
10285732ac8SCy Schubert struct nl_msg *msg;
10385732ac8SCy Schubert
10485732ac8SCy Schubert msg = nlmsg_alloc();
10585732ac8SCy Schubert if (!msg) {
10685732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc message");
10785732ac8SCy Schubert return NULL;
10885732ac8SCy Schubert }
10985732ac8SCy Schubert
11085732ac8SCy Schubert if (!genlmsg_put(msg, 0, 0, ctx->macsec_genl_id, 0, 0, cmd, 0)) {
11185732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "failed to put header");
11285732ac8SCy Schubert goto nla_put_failure;
11385732ac8SCy Schubert }
11485732ac8SCy Schubert
11585732ac8SCy Schubert NLA_PUT_U32(msg, MACSEC_ATTR_IFINDEX, ifindex);
11685732ac8SCy Schubert
11785732ac8SCy Schubert return msg;
11885732ac8SCy Schubert
11985732ac8SCy Schubert nla_put_failure:
12085732ac8SCy Schubert nlmsg_free(msg);
12185732ac8SCy Schubert return NULL;
12285732ac8SCy Schubert }
12385732ac8SCy Schubert
12485732ac8SCy Schubert
nla_put_rxsc_config(struct nl_msg * msg,u64 sci)12585732ac8SCy Schubert static int nla_put_rxsc_config(struct nl_msg *msg, u64 sci)
12685732ac8SCy Schubert {
12785732ac8SCy Schubert struct nlattr *nest = nla_nest_start(msg, MACSEC_ATTR_RXSC_CONFIG);
12885732ac8SCy Schubert
12985732ac8SCy Schubert if (!nest)
13085732ac8SCy Schubert return -1;
13185732ac8SCy Schubert
13285732ac8SCy Schubert NLA_PUT_U64(msg, MACSEC_RXSC_ATTR_SCI, sci);
13385732ac8SCy Schubert
13485732ac8SCy Schubert nla_nest_end(msg, nest);
13585732ac8SCy Schubert
13685732ac8SCy Schubert return 0;
13785732ac8SCy Schubert
13885732ac8SCy Schubert nla_put_failure:
13985732ac8SCy Schubert return -1;
14085732ac8SCy Schubert }
14185732ac8SCy Schubert
14285732ac8SCy Schubert
init_genl_ctx(struct macsec_drv_data * drv)14385732ac8SCy Schubert static int init_genl_ctx(struct macsec_drv_data *drv)
14485732ac8SCy Schubert {
14585732ac8SCy Schubert struct macsec_genl_ctx *ctx = &drv->ctx;
14685732ac8SCy Schubert
14785732ac8SCy Schubert ctx->sk = nl_socket_alloc();
14885732ac8SCy Schubert if (!ctx->sk) {
14985732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc genl socket");
15085732ac8SCy Schubert return -1;
15185732ac8SCy Schubert }
15285732ac8SCy Schubert
15385732ac8SCy Schubert if (genl_connect(ctx->sk) < 0) {
15485732ac8SCy Schubert wpa_printf(MSG_ERROR,
15585732ac8SCy Schubert DRV_PREFIX "connection to genl socket failed");
15685732ac8SCy Schubert goto out_free;
15785732ac8SCy Schubert }
15885732ac8SCy Schubert
15985732ac8SCy Schubert ctx->macsec_genl_id = genl_ctrl_resolve(ctx->sk, "macsec");
16085732ac8SCy Schubert if (ctx->macsec_genl_id < 0) {
16185732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "genl resolve failed");
16285732ac8SCy Schubert goto out_free;
16385732ac8SCy Schubert }
16485732ac8SCy Schubert
16585732ac8SCy Schubert memset(&ctx->cb_arg, 0, sizeof(ctx->cb_arg));
16685732ac8SCy Schubert ctx->cb_arg.drv = drv;
16785732ac8SCy Schubert
16885732ac8SCy Schubert nl_socket_modify_cb(ctx->sk, NL_CB_VALID, NL_CB_CUSTOM, dump_callback,
16985732ac8SCy Schubert &ctx->cb_arg);
17085732ac8SCy Schubert
17185732ac8SCy Schubert return 0;
17285732ac8SCy Schubert
17385732ac8SCy Schubert out_free:
17485732ac8SCy Schubert nl_socket_free(ctx->sk);
17585732ac8SCy Schubert ctx->sk = NULL;
17685732ac8SCy Schubert return -1;
17785732ac8SCy Schubert }
17885732ac8SCy Schubert
17985732ac8SCy Schubert
try_commit(struct macsec_drv_data * drv)18085732ac8SCy Schubert static int try_commit(struct macsec_drv_data *drv)
18185732ac8SCy Schubert {
18285732ac8SCy Schubert int err;
18385732ac8SCy Schubert
18485732ac8SCy Schubert if (!drv->sk)
18585732ac8SCy Schubert return 0;
18685732ac8SCy Schubert
18785732ac8SCy Schubert if (!drv->link)
18885732ac8SCy Schubert return 0;
18985732ac8SCy Schubert
19085732ac8SCy Schubert if (drv->controlled_port_enabled_set) {
19185732ac8SCy Schubert struct rtnl_link *change = rtnl_link_alloc();
19285732ac8SCy Schubert
1934bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX
1944bc52338SCy Schubert "%s: try_commit controlled_port_enabled=%d",
1954bc52338SCy Schubert drv->ifname, drv->controlled_port_enabled);
19685732ac8SCy Schubert if (!change)
19785732ac8SCy Schubert return -1;
19885732ac8SCy Schubert
19985732ac8SCy Schubert rtnl_link_set_name(change, drv->ifname);
20085732ac8SCy Schubert
20185732ac8SCy Schubert if (drv->controlled_port_enabled)
20285732ac8SCy Schubert rtnl_link_set_flags(change, IFF_UP);
20385732ac8SCy Schubert else
20485732ac8SCy Schubert rtnl_link_unset_flags(change, IFF_UP);
20585732ac8SCy Schubert
20685732ac8SCy Schubert err = rtnl_link_change(drv->sk, change, change, 0);
20785732ac8SCy Schubert if (err < 0)
20885732ac8SCy Schubert return err;
20985732ac8SCy Schubert
21085732ac8SCy Schubert rtnl_link_put(change);
21185732ac8SCy Schubert
212c1d255d3SCy Schubert drv->controlled_port_enabled_set = false;
21385732ac8SCy Schubert }
21485732ac8SCy Schubert
2154bc52338SCy Schubert if (drv->protect_frames_set) {
2164bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX
2174bc52338SCy Schubert "%s: try_commit protect_frames=%d",
2184bc52338SCy Schubert drv->ifname, drv->protect_frames);
21985732ac8SCy Schubert rtnl_link_macsec_set_protect(drv->link, drv->protect_frames);
2204bc52338SCy Schubert }
22185732ac8SCy Schubert
2224bc52338SCy Schubert if (drv->encrypt_set) {
2234bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: try_commit encrypt=%d",
2244bc52338SCy Schubert drv->ifname, drv->encrypt);
22585732ac8SCy Schubert rtnl_link_macsec_set_encrypt(drv->link, drv->encrypt);
2264bc52338SCy Schubert }
22785732ac8SCy Schubert
22885732ac8SCy Schubert if (drv->replay_protect_set) {
2294bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX
2304bc52338SCy Schubert "%s: try_commit replay_protect=%d replay_window=%d",
2314bc52338SCy Schubert drv->ifname, drv->replay_protect,
2324bc52338SCy Schubert drv->replay_window);
23385732ac8SCy Schubert rtnl_link_macsec_set_replay_protect(drv->link,
23485732ac8SCy Schubert drv->replay_protect);
23585732ac8SCy Schubert if (drv->replay_protect)
23685732ac8SCy Schubert rtnl_link_macsec_set_window(drv->link,
23785732ac8SCy Schubert drv->replay_window);
23885732ac8SCy Schubert }
23985732ac8SCy Schubert
240*a90b9d01SCy Schubert #ifdef LIBNL_HAS_OFFLOAD
241*a90b9d01SCy Schubert if (drv->offload_set) {
242*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX
243*a90b9d01SCy Schubert "%s: try_commit offload=%d",
244*a90b9d01SCy Schubert drv->ifname, drv->offload);
245*a90b9d01SCy Schubert rtnl_link_macsec_set_offload(drv->link, drv->offload);
246*a90b9d01SCy Schubert }
247*a90b9d01SCy Schubert #endif /* LIBNL_HAS_OFFLOAD */
248*a90b9d01SCy Schubert
2494bc52338SCy Schubert if (drv->encoding_sa_set) {
2504bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX
2514bc52338SCy Schubert "%s: try_commit encoding_sa=%d",
2524bc52338SCy Schubert drv->ifname, drv->encoding_sa);
25385732ac8SCy Schubert rtnl_link_macsec_set_encoding_sa(drv->link, drv->encoding_sa);
2544bc52338SCy Schubert }
25585732ac8SCy Schubert
25685732ac8SCy Schubert err = rtnl_link_add(drv->sk, drv->link, 0);
25785732ac8SCy Schubert if (err < 0)
25885732ac8SCy Schubert return err;
25985732ac8SCy Schubert
260c1d255d3SCy Schubert drv->protect_frames_set = false;
261c1d255d3SCy Schubert drv->encrypt_set = false;
262c1d255d3SCy Schubert drv->replay_protect_set = false;
26385732ac8SCy Schubert
26485732ac8SCy Schubert return 0;
26585732ac8SCy Schubert }
26685732ac8SCy Schubert
26785732ac8SCy Schubert
macsec_drv_wpa_deinit(void * priv)26885732ac8SCy Schubert static void macsec_drv_wpa_deinit(void *priv)
26985732ac8SCy Schubert {
27085732ac8SCy Schubert struct macsec_drv_data *drv = priv;
27185732ac8SCy Schubert
27285732ac8SCy Schubert driver_wired_deinit_common(&drv->common);
27385732ac8SCy Schubert os_free(drv);
27485732ac8SCy Schubert }
27585732ac8SCy Schubert
27685732ac8SCy Schubert
macsec_check_macsec(void)27785732ac8SCy Schubert static int macsec_check_macsec(void)
27885732ac8SCy Schubert {
27985732ac8SCy Schubert struct nl_sock *sk;
28085732ac8SCy Schubert int err = -1;
28185732ac8SCy Schubert
28285732ac8SCy Schubert sk = nl_socket_alloc();
28385732ac8SCy Schubert if (!sk) {
28485732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc genl socket");
28585732ac8SCy Schubert return -1;
28685732ac8SCy Schubert }
28785732ac8SCy Schubert
28885732ac8SCy Schubert if (genl_connect(sk) < 0) {
28985732ac8SCy Schubert wpa_printf(MSG_ERROR,
29085732ac8SCy Schubert DRV_PREFIX "connection to genl socket failed");
29185732ac8SCy Schubert goto out_free;
29285732ac8SCy Schubert }
29385732ac8SCy Schubert
29485732ac8SCy Schubert if (genl_ctrl_resolve(sk, "macsec") < 0) {
29585732ac8SCy Schubert wpa_printf(MSG_ERROR,
29685732ac8SCy Schubert DRV_PREFIX "genl resolve failed - macsec kernel module not present?");
29785732ac8SCy Schubert goto out_free;
29885732ac8SCy Schubert }
29985732ac8SCy Schubert
30085732ac8SCy Schubert err = 0;
30185732ac8SCy Schubert
30285732ac8SCy Schubert out_free:
30385732ac8SCy Schubert nl_socket_free(sk);
30485732ac8SCy Schubert return err;
30585732ac8SCy Schubert }
30685732ac8SCy Schubert
30785732ac8SCy Schubert
macsec_drv_wpa_init(void * ctx,const char * ifname)30885732ac8SCy Schubert static void * macsec_drv_wpa_init(void *ctx, const char *ifname)
30985732ac8SCy Schubert {
31085732ac8SCy Schubert struct macsec_drv_data *drv;
31185732ac8SCy Schubert
31285732ac8SCy Schubert if (macsec_check_macsec() < 0)
31385732ac8SCy Schubert return NULL;
31485732ac8SCy Schubert
31585732ac8SCy Schubert drv = os_zalloc(sizeof(*drv));
31685732ac8SCy Schubert if (!drv)
31785732ac8SCy Schubert return NULL;
31885732ac8SCy Schubert
31985732ac8SCy Schubert if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
32085732ac8SCy Schubert os_free(drv);
32185732ac8SCy Schubert return NULL;
32285732ac8SCy Schubert }
32385732ac8SCy Schubert
32485732ac8SCy Schubert return drv;
32585732ac8SCy Schubert }
32685732ac8SCy Schubert
32785732ac8SCy Schubert
macsec_drv_macsec_init(void * priv,struct macsec_init_params * params)32885732ac8SCy Schubert static int macsec_drv_macsec_init(void *priv, struct macsec_init_params *params)
32985732ac8SCy Schubert {
33085732ac8SCy Schubert struct macsec_drv_data *drv = priv;
33185732ac8SCy Schubert int err;
33285732ac8SCy Schubert
33385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s", __func__);
33485732ac8SCy Schubert
33585732ac8SCy Schubert drv->sk = nl_socket_alloc();
33685732ac8SCy Schubert if (!drv->sk)
33785732ac8SCy Schubert return -1;
33885732ac8SCy Schubert
33985732ac8SCy Schubert err = nl_connect(drv->sk, NETLINK_ROUTE);
34085732ac8SCy Schubert if (err < 0) {
34185732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX
34285732ac8SCy Schubert "Unable to connect NETLINK_ROUTE socket: %s",
343c1d255d3SCy Schubert nl_geterror(err));
34485732ac8SCy Schubert goto sock;
34585732ac8SCy Schubert }
34685732ac8SCy Schubert
34785732ac8SCy Schubert err = rtnl_link_alloc_cache(drv->sk, AF_UNSPEC, &drv->link_cache);
34885732ac8SCy Schubert if (err < 0) {
34985732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "Unable to get link cache: %s",
350c1d255d3SCy Schubert nl_geterror(err));
35185732ac8SCy Schubert goto sock;
35285732ac8SCy Schubert }
35385732ac8SCy Schubert
35485732ac8SCy Schubert drv->parent_ifi = rtnl_link_name2i(drv->link_cache, drv->common.ifname);
35585732ac8SCy Schubert if (drv->parent_ifi == 0) {
35685732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX
35785732ac8SCy Schubert "couldn't find ifindex for interface %s",
35885732ac8SCy Schubert drv->common.ifname);
35985732ac8SCy Schubert goto cache;
36085732ac8SCy Schubert }
3614bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX "ifname=%s parent_ifi=%d",
3624bc52338SCy Schubert drv->common.ifname, drv->parent_ifi);
36385732ac8SCy Schubert
36485732ac8SCy Schubert err = init_genl_ctx(drv);
36585732ac8SCy Schubert if (err < 0)
36685732ac8SCy Schubert goto cache;
36785732ac8SCy Schubert
36885732ac8SCy Schubert return 0;
36985732ac8SCy Schubert
37085732ac8SCy Schubert cache:
37185732ac8SCy Schubert nl_cache_free(drv->link_cache);
37285732ac8SCy Schubert drv->link_cache = NULL;
37385732ac8SCy Schubert sock:
37485732ac8SCy Schubert nl_socket_free(drv->sk);
37585732ac8SCy Schubert drv->sk = NULL;
37685732ac8SCy Schubert return -1;
37785732ac8SCy Schubert }
37885732ac8SCy Schubert
37985732ac8SCy Schubert
macsec_drv_macsec_deinit(void * priv)38085732ac8SCy Schubert static int macsec_drv_macsec_deinit(void *priv)
38185732ac8SCy Schubert {
38285732ac8SCy Schubert struct macsec_drv_data *drv = priv;
38385732ac8SCy Schubert
38485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s", __func__);
38585732ac8SCy Schubert
38685732ac8SCy Schubert if (drv->sk)
38785732ac8SCy Schubert nl_socket_free(drv->sk);
38885732ac8SCy Schubert drv->sk = NULL;
38985732ac8SCy Schubert
39085732ac8SCy Schubert if (drv->link_cache)
39185732ac8SCy Schubert nl_cache_free(drv->link_cache);
39285732ac8SCy Schubert drv->link_cache = NULL;
39385732ac8SCy Schubert
39485732ac8SCy Schubert if (drv->ctx.sk)
39585732ac8SCy Schubert nl_socket_free(drv->ctx.sk);
39685732ac8SCy Schubert
39785732ac8SCy Schubert return 0;
39885732ac8SCy Schubert }
39985732ac8SCy Schubert
40085732ac8SCy Schubert
macsec_drv_get_capability(void * priv,enum macsec_cap * cap)40185732ac8SCy Schubert static int macsec_drv_get_capability(void *priv, enum macsec_cap *cap)
40285732ac8SCy Schubert {
40385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s", __func__);
40485732ac8SCy Schubert
40585732ac8SCy Schubert *cap = MACSEC_CAP_INTEG_AND_CONF;
40685732ac8SCy Schubert
40785732ac8SCy Schubert return 0;
40885732ac8SCy Schubert }
40985732ac8SCy Schubert
41085732ac8SCy Schubert
41185732ac8SCy Schubert /**
41285732ac8SCy Schubert * macsec_drv_enable_protect_frames - Set protect frames status
41385732ac8SCy Schubert * @priv: Private driver interface data
414c1d255d3SCy Schubert * @enabled: true = protect frames enabled
415c1d255d3SCy Schubert * false = protect frames disabled
41685732ac8SCy Schubert * Returns: 0 on success, -1 on failure (or if not supported)
41785732ac8SCy Schubert */
macsec_drv_enable_protect_frames(void * priv,bool enabled)418c1d255d3SCy Schubert static int macsec_drv_enable_protect_frames(void *priv, bool enabled)
41985732ac8SCy Schubert {
42085732ac8SCy Schubert struct macsec_drv_data *drv = priv;
42185732ac8SCy Schubert
42285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
42385732ac8SCy Schubert
424c1d255d3SCy Schubert drv->protect_frames_set = true;
42585732ac8SCy Schubert drv->protect_frames = enabled;
42685732ac8SCy Schubert
42785732ac8SCy Schubert return try_commit(drv);
42885732ac8SCy Schubert }
42985732ac8SCy Schubert
43085732ac8SCy Schubert
43185732ac8SCy Schubert /**
43285732ac8SCy Schubert * macsec_drv_enable_encrypt - Set protect frames status
43385732ac8SCy Schubert * @priv: Private driver interface data
434c1d255d3SCy Schubert * @enabled: true = protect frames enabled
435c1d255d3SCy Schubert * false = protect frames disabled
43685732ac8SCy Schubert * Returns: 0 on success, -1 on failure (or if not supported)
43785732ac8SCy Schubert */
macsec_drv_enable_encrypt(void * priv,bool enabled)438c1d255d3SCy Schubert static int macsec_drv_enable_encrypt(void *priv, bool enabled)
43985732ac8SCy Schubert {
44085732ac8SCy Schubert struct macsec_drv_data *drv = priv;
44185732ac8SCy Schubert
44285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
44385732ac8SCy Schubert
444c1d255d3SCy Schubert drv->encrypt_set = true;
44585732ac8SCy Schubert drv->encrypt = enabled;
44685732ac8SCy Schubert
44785732ac8SCy Schubert return try_commit(drv);
44885732ac8SCy Schubert }
44985732ac8SCy Schubert
45085732ac8SCy Schubert
45185732ac8SCy Schubert /**
45285732ac8SCy Schubert * macsec_drv_set_replay_protect - Set replay protect status and window size
45385732ac8SCy Schubert * @priv: Private driver interface data
454c1d255d3SCy Schubert * @enabled: true = replay protect enabled
455c1d255d3SCy Schubert * false = replay protect disabled
45685732ac8SCy Schubert * @window: replay window size, valid only when replay protect enabled
45785732ac8SCy Schubert * Returns: 0 on success, -1 on failure (or if not supported)
45885732ac8SCy Schubert */
macsec_drv_set_replay_protect(void * priv,bool enabled,u32 window)459c1d255d3SCy Schubert static int macsec_drv_set_replay_protect(void *priv, bool enabled,
46085732ac8SCy Schubert u32 window)
46185732ac8SCy Schubert {
46285732ac8SCy Schubert struct macsec_drv_data *drv = priv;
46385732ac8SCy Schubert
46485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s -> %s, %u", __func__,
46585732ac8SCy Schubert enabled ? "TRUE" : "FALSE", window);
46685732ac8SCy Schubert
467c1d255d3SCy Schubert drv->replay_protect_set = true;
46885732ac8SCy Schubert drv->replay_protect = enabled;
46985732ac8SCy Schubert if (enabled)
47085732ac8SCy Schubert drv->replay_window = window;
47185732ac8SCy Schubert
47285732ac8SCy Schubert return try_commit(drv);
47385732ac8SCy Schubert }
47485732ac8SCy Schubert
47585732ac8SCy Schubert
47685732ac8SCy Schubert /**
477*a90b9d01SCy Schubert * macsec_drv_set_offload - Set offload status
478*a90b9d01SCy Schubert * @priv: Private driver interface data
479*a90b9d01SCy Schubert * @offload: 0 = MACSEC_OFFLOAD_OFF
480*a90b9d01SCy Schubert * 1 = MACSEC_OFFLOAD_PHY
481*a90b9d01SCy Schubert * 2 = MACSEC_OFFLOAD_MAC
482*a90b9d01SCy Schubert * Returns: 0 on success, -1 on failure (or if not supported)
483*a90b9d01SCy Schubert */
macsec_drv_set_offload(void * priv,u8 offload)484*a90b9d01SCy Schubert static int macsec_drv_set_offload(void *priv, u8 offload)
485*a90b9d01SCy Schubert {
486*a90b9d01SCy Schubert #ifdef LIBNL_HAS_OFFLOAD
487*a90b9d01SCy Schubert struct macsec_drv_data *drv = priv;
488*a90b9d01SCy Schubert
489*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "%s -> %02" PRIx8, __func__, offload);
490*a90b9d01SCy Schubert
491*a90b9d01SCy Schubert drv->offload_set = true;
492*a90b9d01SCy Schubert drv->offload = offload;
493*a90b9d01SCy Schubert
494*a90b9d01SCy Schubert return try_commit(drv);
495*a90b9d01SCy Schubert #else /* LIBNL_HAS_OFFLOAD */
496*a90b9d01SCy Schubert if (offload == 0)
497*a90b9d01SCy Schubert return 0;
498*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
499*a90b9d01SCy Schubert "%s: libnl version does not include support for MACsec offload",
500*a90b9d01SCy Schubert __func__);
501*a90b9d01SCy Schubert return -1;
502*a90b9d01SCy Schubert #endif /* LIBNL_HAS_OFFLOAD */
503*a90b9d01SCy Schubert }
504*a90b9d01SCy Schubert
505*a90b9d01SCy Schubert
506*a90b9d01SCy Schubert /**
50785732ac8SCy Schubert * macsec_drv_set_current_cipher_suite - Set current cipher suite
50885732ac8SCy Schubert * @priv: Private driver interface data
50985732ac8SCy Schubert * @cs: EUI64 identifier
51085732ac8SCy Schubert * Returns: 0 on success, -1 on failure (or if not supported)
51185732ac8SCy Schubert */
macsec_drv_set_current_cipher_suite(void * priv,u64 cs)51285732ac8SCy Schubert static int macsec_drv_set_current_cipher_suite(void *priv, u64 cs)
51385732ac8SCy Schubert {
514*a90b9d01SCy Schubert struct macsec_drv_data *drv = priv;
515*a90b9d01SCy Schubert
51685732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s -> %016" PRIx64, __func__, cs);
517*a90b9d01SCy Schubert
518*a90b9d01SCy Schubert drv->cipher_suite_set = true;
519*a90b9d01SCy Schubert drv->cipher_suite = cs;
520*a90b9d01SCy Schubert
521*a90b9d01SCy Schubert return try_commit(drv);
52285732ac8SCy Schubert }
52385732ac8SCy Schubert
52485732ac8SCy Schubert
52585732ac8SCy Schubert /**
52685732ac8SCy Schubert * macsec_drv_enable_controlled_port - Set controlled port status
52785732ac8SCy Schubert * @priv: Private driver interface data
528c1d255d3SCy Schubert * @enabled: true = controlled port enabled
529c1d255d3SCy Schubert * false = controlled port disabled
53085732ac8SCy Schubert * Returns: 0 on success, -1 on failure (or if not supported)
53185732ac8SCy Schubert */
macsec_drv_enable_controlled_port(void * priv,bool enabled)532c1d255d3SCy Schubert static int macsec_drv_enable_controlled_port(void *priv, bool enabled)
53385732ac8SCy Schubert {
53485732ac8SCy Schubert struct macsec_drv_data *drv = priv;
53585732ac8SCy Schubert
53685732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
53785732ac8SCy Schubert
53885732ac8SCy Schubert drv->controlled_port_enabled = enabled;
539c1d255d3SCy Schubert drv->controlled_port_enabled_set = true;
54085732ac8SCy Schubert
54185732ac8SCy Schubert return try_commit(drv);
54285732ac8SCy Schubert }
54385732ac8SCy Schubert
54485732ac8SCy Schubert
54585732ac8SCy Schubert static struct nla_policy sa_policy[MACSEC_SA_ATTR_MAX + 1] = {
54685732ac8SCy Schubert [MACSEC_SA_ATTR_AN] = { .type = NLA_U8 },
54785732ac8SCy Schubert [MACSEC_SA_ATTR_ACTIVE] = { .type = NLA_U8 },
54885732ac8SCy Schubert [MACSEC_SA_ATTR_PN] = { .type = NLA_U32 },
54985732ac8SCy Schubert [MACSEC_SA_ATTR_KEYID] = { .type = NLA_BINARY },
55085732ac8SCy Schubert };
55185732ac8SCy Schubert
55285732ac8SCy Schubert static struct nla_policy sc_policy[MACSEC_RXSC_ATTR_MAX + 1] = {
55385732ac8SCy Schubert [MACSEC_RXSC_ATTR_SCI] = { .type = NLA_U64 },
55485732ac8SCy Schubert [MACSEC_RXSC_ATTR_ACTIVE] = { .type = NLA_U8 },
55585732ac8SCy Schubert [MACSEC_RXSC_ATTR_SA_LIST] = { .type = NLA_NESTED },
55685732ac8SCy Schubert };
55785732ac8SCy Schubert
55885732ac8SCy Schubert static struct nla_policy main_policy[MACSEC_ATTR_MAX + 1] = {
55985732ac8SCy Schubert [MACSEC_ATTR_IFINDEX] = { .type = NLA_U32 },
56085732ac8SCy Schubert [MACSEC_ATTR_SECY] = { .type = NLA_NESTED },
56185732ac8SCy Schubert [MACSEC_ATTR_TXSA_LIST] = { .type = NLA_NESTED },
56285732ac8SCy Schubert [MACSEC_ATTR_RXSC_LIST] = { .type = NLA_NESTED },
56385732ac8SCy Schubert };
56485732ac8SCy Schubert
dump_callback(struct nl_msg * msg,void * argp)56585732ac8SCy Schubert static int dump_callback(struct nl_msg *msg, void *argp)
56685732ac8SCy Schubert {
56785732ac8SCy Schubert struct nlmsghdr *ret_hdr = nlmsg_hdr(msg);
56885732ac8SCy Schubert struct nlattr *tb_msg[MACSEC_ATTR_MAX + 1];
56985732ac8SCy Schubert struct cb_arg *arg = (struct cb_arg *) argp;
57085732ac8SCy Schubert struct genlmsghdr *gnlh = (struct genlmsghdr *) nlmsg_data(ret_hdr);
57185732ac8SCy Schubert int err;
57285732ac8SCy Schubert
57385732ac8SCy Schubert if (ret_hdr->nlmsg_type != arg->drv->ctx.macsec_genl_id)
57485732ac8SCy Schubert return 0;
57585732ac8SCy Schubert
57685732ac8SCy Schubert err = nla_parse(tb_msg, MACSEC_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
57785732ac8SCy Schubert genlmsg_attrlen(gnlh, 0), main_policy);
57885732ac8SCy Schubert if (err < 0)
57985732ac8SCy Schubert return 0;
58085732ac8SCy Schubert
58185732ac8SCy Schubert if (!tb_msg[MACSEC_ATTR_IFINDEX])
58285732ac8SCy Schubert return 0;
58385732ac8SCy Schubert
58485732ac8SCy Schubert if (nla_get_u32(tb_msg[MACSEC_ATTR_IFINDEX]) != (u32) arg->ifindex)
58585732ac8SCy Schubert return 0;
58685732ac8SCy Schubert
58785732ac8SCy Schubert if (arg->txsa < 4 && !tb_msg[MACSEC_ATTR_TXSA_LIST]) {
58885732ac8SCy Schubert return 0;
58985732ac8SCy Schubert } else if (arg->txsa < 4) {
59085732ac8SCy Schubert struct nlattr *nla;
59185732ac8SCy Schubert int rem;
59285732ac8SCy Schubert
59385732ac8SCy Schubert nla_for_each_nested(nla, tb_msg[MACSEC_ATTR_TXSA_LIST], rem) {
59485732ac8SCy Schubert struct nlattr *tb[MACSEC_SA_ATTR_MAX + 1];
59585732ac8SCy Schubert
59685732ac8SCy Schubert err = nla_parse_nested(tb, MACSEC_SA_ATTR_MAX, nla,
59785732ac8SCy Schubert sa_policy);
59885732ac8SCy Schubert if (err < 0)
59985732ac8SCy Schubert continue;
60085732ac8SCy Schubert if (!tb[MACSEC_SA_ATTR_AN])
60185732ac8SCy Schubert continue;
60285732ac8SCy Schubert if (nla_get_u8(tb[MACSEC_SA_ATTR_AN]) != arg->txsa)
60385732ac8SCy Schubert continue;
60485732ac8SCy Schubert if (!tb[MACSEC_SA_ATTR_PN])
60585732ac8SCy Schubert return 0;
60685732ac8SCy Schubert *arg->pn = nla_get_u32(tb[MACSEC_SA_ATTR_PN]);
60785732ac8SCy Schubert return 0;
60885732ac8SCy Schubert }
60985732ac8SCy Schubert
61085732ac8SCy Schubert return 0;
61185732ac8SCy Schubert }
61285732ac8SCy Schubert
61385732ac8SCy Schubert if (arg->rxsci == UNUSED_SCI)
61485732ac8SCy Schubert return 0;
61585732ac8SCy Schubert
61685732ac8SCy Schubert if (tb_msg[MACSEC_ATTR_RXSC_LIST]) {
61785732ac8SCy Schubert struct nlattr *nla;
61885732ac8SCy Schubert int rem;
61985732ac8SCy Schubert
62085732ac8SCy Schubert nla_for_each_nested(nla, tb_msg[MACSEC_ATTR_RXSC_LIST], rem) {
62185732ac8SCy Schubert struct nlattr *tb[MACSEC_RXSC_ATTR_MAX + 1];
62285732ac8SCy Schubert
62385732ac8SCy Schubert err = nla_parse_nested(tb, MACSEC_RXSC_ATTR_MAX, nla,
62485732ac8SCy Schubert sc_policy);
62585732ac8SCy Schubert if (err < 0)
62685732ac8SCy Schubert return 0;
62785732ac8SCy Schubert if (!tb[MACSEC_RXSC_ATTR_SCI])
62885732ac8SCy Schubert continue;
62985732ac8SCy Schubert if (nla_get_u64(tb[MACSEC_RXSC_ATTR_SCI]) != arg->rxsci)
63085732ac8SCy Schubert continue;
63185732ac8SCy Schubert if (!tb[MACSEC_RXSC_ATTR_SA_LIST])
63285732ac8SCy Schubert return 0;
63385732ac8SCy Schubert
63485732ac8SCy Schubert nla_for_each_nested(nla, tb[MACSEC_RXSC_ATTR_SA_LIST],
63585732ac8SCy Schubert rem) {
63685732ac8SCy Schubert struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
63785732ac8SCy Schubert
63885732ac8SCy Schubert err = nla_parse_nested(tb_sa,
63985732ac8SCy Schubert MACSEC_SA_ATTR_MAX, nla,
64085732ac8SCy Schubert sa_policy);
64185732ac8SCy Schubert if (err < 0)
64285732ac8SCy Schubert continue;
64385732ac8SCy Schubert if (!tb_sa[MACSEC_SA_ATTR_AN])
64485732ac8SCy Schubert continue;
64585732ac8SCy Schubert if (nla_get_u8(tb_sa[MACSEC_SA_ATTR_AN]) !=
64685732ac8SCy Schubert arg->rxsa)
64785732ac8SCy Schubert continue;
64885732ac8SCy Schubert if (!tb_sa[MACSEC_SA_ATTR_PN])
64985732ac8SCy Schubert return 0;
65085732ac8SCy Schubert *arg->pn =
65185732ac8SCy Schubert nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
65285732ac8SCy Schubert
65385732ac8SCy Schubert return 0;
65485732ac8SCy Schubert }
65585732ac8SCy Schubert
65685732ac8SCy Schubert return 0;
65785732ac8SCy Schubert }
65885732ac8SCy Schubert
65985732ac8SCy Schubert return 0;
66085732ac8SCy Schubert }
66185732ac8SCy Schubert
66285732ac8SCy Schubert return 0;
66385732ac8SCy Schubert }
66485732ac8SCy Schubert
66585732ac8SCy Schubert
nl_send_recv(struct nl_sock * sk,struct nl_msg * msg)66685732ac8SCy Schubert static int nl_send_recv(struct nl_sock *sk, struct nl_msg *msg)
66785732ac8SCy Schubert {
66885732ac8SCy Schubert int ret;
66985732ac8SCy Schubert
67085732ac8SCy Schubert ret = nl_send_auto_complete(sk, msg);
67185732ac8SCy Schubert if (ret < 0) {
67285732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to send: %d (%s)",
67385732ac8SCy Schubert __func__, ret, nl_geterror(-ret));
67485732ac8SCy Schubert return ret;
67585732ac8SCy Schubert }
67685732ac8SCy Schubert
67785732ac8SCy Schubert ret = nl_recvmsgs_default(sk);
67885732ac8SCy Schubert if (ret < 0) {
67985732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to recv: %d (%s)",
68085732ac8SCy Schubert __func__, ret, nl_geterror(-ret));
68185732ac8SCy Schubert }
68285732ac8SCy Schubert
68385732ac8SCy Schubert return ret;
68485732ac8SCy Schubert }
68585732ac8SCy Schubert
68685732ac8SCy Schubert
do_dump(struct macsec_drv_data * drv,u8 txsa,u64 rxsci,u8 rxsa,u32 * pn)68785732ac8SCy Schubert static int do_dump(struct macsec_drv_data *drv, u8 txsa, u64 rxsci, u8 rxsa,
68885732ac8SCy Schubert u32 *pn)
68985732ac8SCy Schubert {
69085732ac8SCy Schubert struct macsec_genl_ctx *ctx = &drv->ctx;
69185732ac8SCy Schubert struct nl_msg *msg;
69285732ac8SCy Schubert int ret = 1;
69385732ac8SCy Schubert
69485732ac8SCy Schubert ctx->cb_arg.ifindex = drv->ifi;
69585732ac8SCy Schubert ctx->cb_arg.rxsci = rxsci;
69685732ac8SCy Schubert ctx->cb_arg.rxsa = rxsa;
69785732ac8SCy Schubert ctx->cb_arg.txsa = txsa;
69885732ac8SCy Schubert ctx->cb_arg.pn = pn;
69985732ac8SCy Schubert
70085732ac8SCy Schubert msg = nlmsg_alloc();
70185732ac8SCy Schubert if (!msg) {
70285732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to alloc message",
70385732ac8SCy Schubert __func__);
70485732ac8SCy Schubert return 1;
70585732ac8SCy Schubert }
70685732ac8SCy Schubert
70785732ac8SCy Schubert if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ctx->macsec_genl_id, 0,
70885732ac8SCy Schubert NLM_F_DUMP, MACSEC_CMD_GET_TXSC, 0)) {
70985732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to put header",
71085732ac8SCy Schubert __func__);
71185732ac8SCy Schubert goto out_free_msg;
71285732ac8SCy Schubert }
71385732ac8SCy Schubert
71485732ac8SCy Schubert ret = nl_send_recv(ctx->sk, msg);
71585732ac8SCy Schubert if (ret < 0)
71685732ac8SCy Schubert wpa_printf(MSG_ERROR,
71785732ac8SCy Schubert DRV_PREFIX "failed to communicate: %d (%s)",
71885732ac8SCy Schubert ret, nl_geterror(-ret));
71985732ac8SCy Schubert
72085732ac8SCy Schubert ctx->cb_arg.pn = NULL;
72185732ac8SCy Schubert
72285732ac8SCy Schubert out_free_msg:
72385732ac8SCy Schubert nlmsg_free(msg);
72485732ac8SCy Schubert return ret;
72585732ac8SCy Schubert }
72685732ac8SCy Schubert
72785732ac8SCy Schubert
72885732ac8SCy Schubert /**
72985732ac8SCy Schubert * macsec_drv_get_receive_lowest_pn - Get receive lowest PN
73085732ac8SCy Schubert * @priv: Private driver interface data
73185732ac8SCy Schubert * @sa: secure association
73285732ac8SCy Schubert * Returns: 0 on success, -1 on failure (or if not supported)
73385732ac8SCy Schubert */
macsec_drv_get_receive_lowest_pn(void * priv,struct receive_sa * sa)73485732ac8SCy Schubert static int macsec_drv_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
73585732ac8SCy Schubert {
73685732ac8SCy Schubert struct macsec_drv_data *drv = priv;
73785732ac8SCy Schubert int err;
73885732ac8SCy Schubert
73985732ac8SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX "%s", __func__);
74085732ac8SCy Schubert
74185732ac8SCy Schubert err = do_dump(drv, 0xff, mka_sci_u64(&sa->sc->sci), sa->an,
74285732ac8SCy Schubert &sa->lowest_pn);
74385732ac8SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: result %d", __func__,
74485732ac8SCy Schubert sa->lowest_pn);
74585732ac8SCy Schubert
74685732ac8SCy Schubert return err;
74785732ac8SCy Schubert }
74885732ac8SCy Schubert
74985732ac8SCy Schubert
75085732ac8SCy Schubert /**
7514bc52338SCy Schubert * macsec_drv_set_receive_lowest_pn - Set receive lowest PN
7524bc52338SCy Schubert * @priv: Private driver interface data
7534bc52338SCy Schubert * @sa: secure association
7544bc52338SCy Schubert * Returns: 0 on success, -1 on failure (or if not supported)
7554bc52338SCy Schubert */
macsec_drv_set_receive_lowest_pn(void * priv,struct receive_sa * sa)7564bc52338SCy Schubert static int macsec_drv_set_receive_lowest_pn(void *priv, struct receive_sa *sa)
7574bc52338SCy Schubert {
7584bc52338SCy Schubert struct macsec_drv_data *drv = priv;
7594bc52338SCy Schubert struct macsec_genl_ctx *ctx = &drv->ctx;
7604bc52338SCy Schubert struct nl_msg *msg;
7614bc52338SCy Schubert struct nlattr *nest;
7624bc52338SCy Schubert int ret = -1;
7634bc52338SCy Schubert
7644bc52338SCy Schubert wpa_printf(MSG_DEBUG,
7654bc52338SCy Schubert DRV_PREFIX "%s: set_receive_lowest_pn -> %d: %d",
7664bc52338SCy Schubert drv->ifname, sa->an, sa->next_pn);
7674bc52338SCy Schubert
7684bc52338SCy Schubert msg = msg_prepare(MACSEC_CMD_UPD_RXSA, ctx, drv->ifi);
7694bc52338SCy Schubert if (!msg)
7704bc52338SCy Schubert return ret;
7714bc52338SCy Schubert
772c1d255d3SCy Schubert if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci)))
773c1d255d3SCy Schubert goto nla_put_failure;
774c1d255d3SCy Schubert
7754bc52338SCy Schubert nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
7764bc52338SCy Schubert if (!nest)
7774bc52338SCy Schubert goto nla_put_failure;
7784bc52338SCy Schubert
7794bc52338SCy Schubert NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
7804bc52338SCy Schubert NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
7814bc52338SCy Schubert
7824bc52338SCy Schubert nla_nest_end(msg, nest);
7834bc52338SCy Schubert
7844bc52338SCy Schubert ret = nl_send_recv(ctx->sk, msg);
7854bc52338SCy Schubert if (ret < 0) {
7864bc52338SCy Schubert wpa_printf(MSG_ERROR,
7874bc52338SCy Schubert DRV_PREFIX "failed to communicate: %d (%s)",
7884bc52338SCy Schubert ret, nl_geterror(-ret));
7894bc52338SCy Schubert }
7904bc52338SCy Schubert
7914bc52338SCy Schubert nla_put_failure:
7924bc52338SCy Schubert nlmsg_free(msg);
7934bc52338SCy Schubert return ret;
7944bc52338SCy Schubert }
7954bc52338SCy Schubert
7964bc52338SCy Schubert
7974bc52338SCy Schubert /**
79885732ac8SCy Schubert * macsec_drv_get_transmit_next_pn - Get transmit next PN
79985732ac8SCy Schubert * @priv: Private driver interface data
80085732ac8SCy Schubert * @sa: secure association
80185732ac8SCy Schubert * Returns: 0 on success, -1 on failure (or if not supported)
80285732ac8SCy Schubert */
macsec_drv_get_transmit_next_pn(void * priv,struct transmit_sa * sa)80385732ac8SCy Schubert static int macsec_drv_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
80485732ac8SCy Schubert {
80585732ac8SCy Schubert struct macsec_drv_data *drv = priv;
80685732ac8SCy Schubert int err;
80785732ac8SCy Schubert
80885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s", __func__);
80985732ac8SCy Schubert
81085732ac8SCy Schubert err = do_dump(drv, sa->an, UNUSED_SCI, 0xff, &sa->next_pn);
81185732ac8SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: err %d result %d", __func__, err,
81285732ac8SCy Schubert sa->next_pn);
81385732ac8SCy Schubert return err;
81485732ac8SCy Schubert }
81585732ac8SCy Schubert
81685732ac8SCy Schubert
81785732ac8SCy Schubert /**
81885732ac8SCy Schubert * macsec_drv_set_transmit_next_pn - Set transmit next pn
81985732ac8SCy Schubert * @priv: Private driver interface data
82085732ac8SCy Schubert * @sa: secure association
82185732ac8SCy Schubert * Returns: 0 on success, -1 on failure (or if not supported)
82285732ac8SCy Schubert */
macsec_drv_set_transmit_next_pn(void * priv,struct transmit_sa * sa)82385732ac8SCy Schubert static int macsec_drv_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
82485732ac8SCy Schubert {
82585732ac8SCy Schubert struct macsec_drv_data *drv = priv;
82685732ac8SCy Schubert struct macsec_genl_ctx *ctx = &drv->ctx;
82785732ac8SCy Schubert struct nl_msg *msg;
82885732ac8SCy Schubert struct nlattr *nest;
82985732ac8SCy Schubert int ret = -1;
83085732ac8SCy Schubert
83185732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s -> %d: %d", __func__, sa->an, sa->next_pn);
83285732ac8SCy Schubert
83385732ac8SCy Schubert msg = msg_prepare(MACSEC_CMD_UPD_TXSA, ctx, drv->ifi);
83485732ac8SCy Schubert if (!msg)
83585732ac8SCy Schubert return ret;
83685732ac8SCy Schubert
83785732ac8SCy Schubert nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
83885732ac8SCy Schubert if (!nest)
83985732ac8SCy Schubert goto nla_put_failure;
84085732ac8SCy Schubert
84185732ac8SCy Schubert NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
84285732ac8SCy Schubert NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
84385732ac8SCy Schubert
84485732ac8SCy Schubert nla_nest_end(msg, nest);
84585732ac8SCy Schubert
84685732ac8SCy Schubert ret = nl_send_recv(ctx->sk, msg);
84785732ac8SCy Schubert if (ret < 0) {
84885732ac8SCy Schubert wpa_printf(MSG_ERROR,
84985732ac8SCy Schubert DRV_PREFIX "failed to communicate: %d (%s)",
85085732ac8SCy Schubert ret, nl_geterror(-ret));
85185732ac8SCy Schubert }
85285732ac8SCy Schubert
85385732ac8SCy Schubert nla_put_failure:
85485732ac8SCy Schubert nlmsg_free(msg);
85585732ac8SCy Schubert return ret;
85685732ac8SCy Schubert }
85785732ac8SCy Schubert
85885732ac8SCy Schubert
85985732ac8SCy Schubert #define SCISTR MACSTR "::%hx"
86085732ac8SCy Schubert #define SCI2STR(addr, port) MAC2STR(addr), htons(port)
86185732ac8SCy Schubert
86285732ac8SCy Schubert /**
86385732ac8SCy Schubert * macsec_drv_create_receive_sc - Create secure channel for receiving
86485732ac8SCy Schubert * @priv: Private driver interface data
86585732ac8SCy Schubert * @sc: secure channel
86685732ac8SCy Schubert * @sci_addr: secure channel identifier - address
86785732ac8SCy Schubert * @sci_port: secure channel identifier - port
86885732ac8SCy Schubert * @conf_offset: confidentiality offset (0, 30, or 50)
86985732ac8SCy Schubert * @validation: frame validation policy (0 = Disabled, 1 = Checked,
87085732ac8SCy Schubert * 2 = Strict)
87185732ac8SCy Schubert * Returns: 0 on success, -1 on failure (or if not supported)
87285732ac8SCy Schubert */
macsec_drv_create_receive_sc(void * priv,struct receive_sc * sc,unsigned int conf_offset,int validation)87385732ac8SCy Schubert static int macsec_drv_create_receive_sc(void *priv, struct receive_sc *sc,
87485732ac8SCy Schubert unsigned int conf_offset,
87585732ac8SCy Schubert int validation)
87685732ac8SCy Schubert {
87785732ac8SCy Schubert struct macsec_drv_data *drv = priv;
87885732ac8SCy Schubert struct macsec_genl_ctx *ctx = &drv->ctx;
87985732ac8SCy Schubert struct nl_msg *msg;
88085732ac8SCy Schubert int ret = -1;
88185732ac8SCy Schubert
8824bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: create_receive_sc -> " SCISTR
8834bc52338SCy Schubert " (conf_offset=%u validation=%d)",
8844bc52338SCy Schubert drv->ifname, SCI2STR(sc->sci.addr, sc->sci.port),
8854bc52338SCy Schubert conf_offset, validation);
88685732ac8SCy Schubert
88785732ac8SCy Schubert msg = msg_prepare(MACSEC_CMD_ADD_RXSC, ctx, drv->ifi);
88885732ac8SCy Schubert if (!msg)
88985732ac8SCy Schubert return ret;
89085732ac8SCy Schubert
89185732ac8SCy Schubert if (nla_put_rxsc_config(msg, mka_sci_u64(&sc->sci)))
89285732ac8SCy Schubert goto nla_put_failure;
89385732ac8SCy Schubert
89485732ac8SCy Schubert ret = nl_send_recv(ctx->sk, msg);
89585732ac8SCy Schubert if (ret < 0) {
89685732ac8SCy Schubert wpa_printf(MSG_ERROR,
89785732ac8SCy Schubert DRV_PREFIX "%s: failed to communicate: %d (%s)",
89885732ac8SCy Schubert __func__, ret, nl_geterror(-ret));
89985732ac8SCy Schubert }
90085732ac8SCy Schubert
90185732ac8SCy Schubert nla_put_failure:
90285732ac8SCy Schubert nlmsg_free(msg);
90385732ac8SCy Schubert return ret;
90485732ac8SCy Schubert }
90585732ac8SCy Schubert
90685732ac8SCy Schubert
90785732ac8SCy Schubert /**
90885732ac8SCy Schubert * macsec_drv_delete_receive_sc - Delete secure connection for receiving
90985732ac8SCy Schubert * @priv: private driver interface data from init()
91085732ac8SCy Schubert * @sc: secure channel
91185732ac8SCy Schubert * Returns: 0 on success, -1 on failure
91285732ac8SCy Schubert */
macsec_drv_delete_receive_sc(void * priv,struct receive_sc * sc)91385732ac8SCy Schubert static int macsec_drv_delete_receive_sc(void *priv, struct receive_sc *sc)
91485732ac8SCy Schubert {
91585732ac8SCy Schubert struct macsec_drv_data *drv = priv;
91685732ac8SCy Schubert struct macsec_genl_ctx *ctx = &drv->ctx;
91785732ac8SCy Schubert struct nl_msg *msg;
91885732ac8SCy Schubert int ret = -1;
91985732ac8SCy Schubert
9204bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_receive_sc -> " SCISTR,
9214bc52338SCy Schubert drv->ifname, SCI2STR(sc->sci.addr, sc->sci.port));
92285732ac8SCy Schubert
92385732ac8SCy Schubert msg = msg_prepare(MACSEC_CMD_DEL_RXSC, ctx, drv->ifi);
92485732ac8SCy Schubert if (!msg)
92585732ac8SCy Schubert return ret;
92685732ac8SCy Schubert
92785732ac8SCy Schubert if (nla_put_rxsc_config(msg, mka_sci_u64(&sc->sci)))
92885732ac8SCy Schubert goto nla_put_failure;
92985732ac8SCy Schubert
93085732ac8SCy Schubert ret = nl_send_recv(ctx->sk, msg);
93185732ac8SCy Schubert if (ret < 0) {
93285732ac8SCy Schubert wpa_printf(MSG_ERROR,
93385732ac8SCy Schubert DRV_PREFIX "%s: failed to communicate: %d (%s)",
93485732ac8SCy Schubert __func__, ret, nl_geterror(-ret));
93585732ac8SCy Schubert }
93685732ac8SCy Schubert
93785732ac8SCy Schubert nla_put_failure:
93885732ac8SCy Schubert nlmsg_free(msg);
93985732ac8SCy Schubert return ret;
94085732ac8SCy Schubert }
94185732ac8SCy Schubert
94285732ac8SCy Schubert
94385732ac8SCy Schubert /**
94485732ac8SCy Schubert * macsec_drv_create_receive_sa - Create secure association for receive
94585732ac8SCy Schubert * @priv: private driver interface data from init()
94685732ac8SCy Schubert * @sa: secure association
94785732ac8SCy Schubert * Returns: 0 on success, -1 on failure
94885732ac8SCy Schubert */
macsec_drv_create_receive_sa(void * priv,struct receive_sa * sa)94985732ac8SCy Schubert static int macsec_drv_create_receive_sa(void *priv, struct receive_sa *sa)
95085732ac8SCy Schubert {
95185732ac8SCy Schubert struct macsec_drv_data *drv = priv;
95285732ac8SCy Schubert struct macsec_genl_ctx *ctx = &drv->ctx;
95385732ac8SCy Schubert struct nl_msg *msg;
95485732ac8SCy Schubert struct nlattr *nest;
95585732ac8SCy Schubert int ret = -1;
95685732ac8SCy Schubert
9574bc52338SCy Schubert wpa_printf(MSG_DEBUG,
9584bc52338SCy Schubert DRV_PREFIX "%s: create_receive_sa -> %d on " SCISTR
9594bc52338SCy Schubert " (enable_receive=%d next_pn=%u)",
9604bc52338SCy Schubert drv->ifname, sa->an,
9614bc52338SCy Schubert SCI2STR(sa->sc->sci.addr, sa->sc->sci.port),
9624bc52338SCy Schubert sa->enable_receive, sa->next_pn);
9634bc52338SCy Schubert wpa_hexdump(MSG_DEBUG, DRV_PREFIX "SA keyid",
9644bc52338SCy Schubert &sa->pkey->key_identifier,
9654bc52338SCy Schubert sizeof(sa->pkey->key_identifier));
9664bc52338SCy Schubert wpa_hexdump_key(MSG_DEBUG, DRV_PREFIX "SA key",
9674bc52338SCy Schubert sa->pkey->key, sa->pkey->key_len);
96885732ac8SCy Schubert
96985732ac8SCy Schubert msg = msg_prepare(MACSEC_CMD_ADD_RXSA, ctx, drv->ifi);
97085732ac8SCy Schubert if (!msg)
97185732ac8SCy Schubert return ret;
97285732ac8SCy Schubert
97385732ac8SCy Schubert if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci)))
97485732ac8SCy Schubert goto nla_put_failure;
97585732ac8SCy Schubert
97685732ac8SCy Schubert nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
97785732ac8SCy Schubert if (!nest)
97885732ac8SCy Schubert goto nla_put_failure;
97985732ac8SCy Schubert
98085732ac8SCy Schubert NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
98185732ac8SCy Schubert NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, sa->enable_receive);
98285732ac8SCy Schubert NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
98385732ac8SCy Schubert NLA_PUT(msg, MACSEC_SA_ATTR_KEYID, sizeof(sa->pkey->key_identifier),
98485732ac8SCy Schubert &sa->pkey->key_identifier);
98585732ac8SCy Schubert NLA_PUT(msg, MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
98685732ac8SCy Schubert
98785732ac8SCy Schubert nla_nest_end(msg, nest);
98885732ac8SCy Schubert
98985732ac8SCy Schubert ret = nl_send_recv(ctx->sk, msg);
99085732ac8SCy Schubert if (ret < 0) {
99185732ac8SCy Schubert wpa_printf(MSG_ERROR,
99285732ac8SCy Schubert DRV_PREFIX "%s: failed to communicate: %d (%s)",
99385732ac8SCy Schubert __func__, ret, nl_geterror(-ret));
99485732ac8SCy Schubert }
99585732ac8SCy Schubert
99685732ac8SCy Schubert nla_put_failure:
99785732ac8SCy Schubert nlmsg_free(msg);
99885732ac8SCy Schubert return ret;
99985732ac8SCy Schubert }
100085732ac8SCy Schubert
100185732ac8SCy Schubert
100285732ac8SCy Schubert /**
100385732ac8SCy Schubert * macsec_drv_delete_receive_sa - Delete secure association for receive
100485732ac8SCy Schubert * @priv: private driver interface data from init()
100585732ac8SCy Schubert * @sa: secure association
100685732ac8SCy Schubert * Returns: 0 on success, -1 on failure
100785732ac8SCy Schubert */
macsec_drv_delete_receive_sa(void * priv,struct receive_sa * sa)100885732ac8SCy Schubert static int macsec_drv_delete_receive_sa(void *priv, struct receive_sa *sa)
100985732ac8SCy Schubert {
101085732ac8SCy Schubert struct macsec_drv_data *drv = priv;
101185732ac8SCy Schubert struct macsec_genl_ctx *ctx = &drv->ctx;
101285732ac8SCy Schubert struct nl_msg *msg;
101385732ac8SCy Schubert struct nlattr *nest;
101485732ac8SCy Schubert int ret = -1;
101585732ac8SCy Schubert
10164bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_receive_sa -> %d on "
10174bc52338SCy Schubert SCISTR, drv->ifname, sa->an,
101885732ac8SCy Schubert SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
101985732ac8SCy Schubert
102085732ac8SCy Schubert msg = msg_prepare(MACSEC_CMD_DEL_RXSA, ctx, drv->ifi);
102185732ac8SCy Schubert if (!msg)
102285732ac8SCy Schubert return ret;
102385732ac8SCy Schubert
102485732ac8SCy Schubert if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci)))
102585732ac8SCy Schubert goto nla_put_failure;
102685732ac8SCy Schubert
102785732ac8SCy Schubert nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
102885732ac8SCy Schubert if (!nest)
102985732ac8SCy Schubert goto nla_put_failure;
103085732ac8SCy Schubert
103185732ac8SCy Schubert NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
103285732ac8SCy Schubert
103385732ac8SCy Schubert nla_nest_end(msg, nest);
103485732ac8SCy Schubert
103585732ac8SCy Schubert ret = nl_send_recv(ctx->sk, msg);
103685732ac8SCy Schubert if (ret < 0) {
103785732ac8SCy Schubert wpa_printf(MSG_ERROR,
103885732ac8SCy Schubert DRV_PREFIX "%s: failed to communicate: %d (%s)",
103985732ac8SCy Schubert __func__, ret, nl_geterror(-ret));
104085732ac8SCy Schubert }
104185732ac8SCy Schubert
104285732ac8SCy Schubert nla_put_failure:
104385732ac8SCy Schubert nlmsg_free(msg);
104485732ac8SCy Schubert return ret;
104585732ac8SCy Schubert }
104685732ac8SCy Schubert
104785732ac8SCy Schubert
set_active_rx_sa(const struct macsec_genl_ctx * ctx,int ifindex,u64 sci,unsigned char an,bool state)104885732ac8SCy Schubert static int set_active_rx_sa(const struct macsec_genl_ctx *ctx, int ifindex,
1049c1d255d3SCy Schubert u64 sci, unsigned char an, bool state)
105085732ac8SCy Schubert {
105185732ac8SCy Schubert struct nl_msg *msg;
105285732ac8SCy Schubert struct nlattr *nest;
105385732ac8SCy Schubert int ret = -1;
105485732ac8SCy Schubert
105585732ac8SCy Schubert msg = msg_prepare(MACSEC_CMD_UPD_RXSA, ctx, ifindex);
105685732ac8SCy Schubert if (!msg)
105785732ac8SCy Schubert return ret;
105885732ac8SCy Schubert
105985732ac8SCy Schubert if (nla_put_rxsc_config(msg, sci))
106085732ac8SCy Schubert goto nla_put_failure;
106185732ac8SCy Schubert
106285732ac8SCy Schubert nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
106385732ac8SCy Schubert if (!nest)
106485732ac8SCy Schubert goto nla_put_failure;
106585732ac8SCy Schubert
106685732ac8SCy Schubert NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, an);
106785732ac8SCy Schubert NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, !!state);
106885732ac8SCy Schubert
106985732ac8SCy Schubert nla_nest_end(msg, nest);
107085732ac8SCy Schubert
107185732ac8SCy Schubert ret = nl_send_recv(ctx->sk, msg);
107285732ac8SCy Schubert if (ret < 0)
107385732ac8SCy Schubert wpa_printf(MSG_ERROR,
107485732ac8SCy Schubert DRV_PREFIX "%s: failed to communicate: %d (%s)",
107585732ac8SCy Schubert __func__, ret, nl_geterror(-ret));
107685732ac8SCy Schubert
107785732ac8SCy Schubert nla_put_failure:
107885732ac8SCy Schubert nlmsg_free(msg);
107985732ac8SCy Schubert return ret;
108085732ac8SCy Schubert }
108185732ac8SCy Schubert
108285732ac8SCy Schubert
108385732ac8SCy Schubert /**
108485732ac8SCy Schubert * macsec_drv_enable_receive_sa - Enable the SA for receive
108585732ac8SCy Schubert * @priv: private driver interface data from init()
108685732ac8SCy Schubert * @sa: secure association
108785732ac8SCy Schubert * Returns: 0 on success, -1 on failure
108885732ac8SCy Schubert */
macsec_drv_enable_receive_sa(void * priv,struct receive_sa * sa)108985732ac8SCy Schubert static int macsec_drv_enable_receive_sa(void *priv, struct receive_sa *sa)
109085732ac8SCy Schubert {
109185732ac8SCy Schubert struct macsec_drv_data *drv = priv;
109285732ac8SCy Schubert struct macsec_genl_ctx *ctx = &drv->ctx;
109385732ac8SCy Schubert
10944bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: enable_receive_sa -> %d on "
10954bc52338SCy Schubert SCISTR, drv->ifname, sa->an,
109685732ac8SCy Schubert SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
109785732ac8SCy Schubert
109885732ac8SCy Schubert return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
1099c1d255d3SCy Schubert sa->an, true);
110085732ac8SCy Schubert }
110185732ac8SCy Schubert
110285732ac8SCy Schubert
110385732ac8SCy Schubert /**
110485732ac8SCy Schubert * macsec_drv_disable_receive_sa - Disable SA for receive
110585732ac8SCy Schubert * @priv: private driver interface data from init()
110685732ac8SCy Schubert * @sa: secure association
110785732ac8SCy Schubert * Returns: 0 on success, -1 on failure
110885732ac8SCy Schubert */
macsec_drv_disable_receive_sa(void * priv,struct receive_sa * sa)110985732ac8SCy Schubert static int macsec_drv_disable_receive_sa(void *priv, struct receive_sa *sa)
111085732ac8SCy Schubert {
111185732ac8SCy Schubert struct macsec_drv_data *drv = priv;
111285732ac8SCy Schubert struct macsec_genl_ctx *ctx = &drv->ctx;
111385732ac8SCy Schubert
11144bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: disable_receive_sa -> %d on "
11154bc52338SCy Schubert SCISTR, drv->ifname, sa->an,
111685732ac8SCy Schubert SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
111785732ac8SCy Schubert
111885732ac8SCy Schubert return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
1119c1d255d3SCy Schubert sa->an, false);
112085732ac8SCy Schubert }
112185732ac8SCy Schubert
112285732ac8SCy Schubert
lookup_sc(struct nl_cache * cache,int parent,u64 sci,u64 cs)1123*a90b9d01SCy Schubert static struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci,
1124*a90b9d01SCy Schubert u64 cs)
112585732ac8SCy Schubert {
112685732ac8SCy Schubert struct rtnl_link *needle;
112785732ac8SCy Schubert void *match;
112885732ac8SCy Schubert
112985732ac8SCy Schubert needle = rtnl_link_macsec_alloc();
113085732ac8SCy Schubert if (!needle)
113185732ac8SCy Schubert return NULL;
113285732ac8SCy Schubert
113385732ac8SCy Schubert rtnl_link_set_link(needle, parent);
113485732ac8SCy Schubert rtnl_link_macsec_set_sci(needle, sci);
1135*a90b9d01SCy Schubert if (cs)
1136*a90b9d01SCy Schubert rtnl_link_macsec_set_cipher_suite(needle, cs);
113785732ac8SCy Schubert
113885732ac8SCy Schubert match = nl_cache_find(cache, (struct nl_object *) needle);
113985732ac8SCy Schubert rtnl_link_put(needle);
114085732ac8SCy Schubert
114185732ac8SCy Schubert return (struct rtnl_link *) match;
114285732ac8SCy Schubert }
114385732ac8SCy Schubert
114485732ac8SCy Schubert
114585732ac8SCy Schubert /**
114685732ac8SCy Schubert * macsec_drv_create_transmit_sc - Create secure connection for transmit
114785732ac8SCy Schubert * @priv: private driver interface data from init()
114885732ac8SCy Schubert * @sc: secure channel
114985732ac8SCy Schubert * @conf_offset: confidentiality offset
115085732ac8SCy Schubert * Returns: 0 on success, -1 on failure
115185732ac8SCy Schubert */
macsec_drv_create_transmit_sc(void * priv,struct transmit_sc * sc,unsigned int conf_offset)115285732ac8SCy Schubert static int macsec_drv_create_transmit_sc(
115385732ac8SCy Schubert void *priv, struct transmit_sc *sc,
115485732ac8SCy Schubert unsigned int conf_offset)
115585732ac8SCy Schubert {
115685732ac8SCy Schubert struct macsec_drv_data *drv = priv;
115785732ac8SCy Schubert struct rtnl_link *link;
115885732ac8SCy Schubert char *ifname;
115985732ac8SCy Schubert u64 sci;
116085732ac8SCy Schubert int err;
1161*a90b9d01SCy Schubert u64 cs = 0;
116285732ac8SCy Schubert
11634bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX
11644bc52338SCy Schubert "%s: create_transmit_sc -> " SCISTR " (conf_offset=%d)",
11654bc52338SCy Schubert drv->common.ifname, SCI2STR(sc->sci.addr, sc->sci.port),
11664bc52338SCy Schubert conf_offset);
116785732ac8SCy Schubert
116885732ac8SCy Schubert if (!drv->sk) {
116985732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "NULL rtnl socket");
117085732ac8SCy Schubert return -1;
117185732ac8SCy Schubert }
117285732ac8SCy Schubert
117385732ac8SCy Schubert link = rtnl_link_macsec_alloc();
117485732ac8SCy Schubert if (!link) {
117585732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't allocate link");
117685732ac8SCy Schubert return -1;
117785732ac8SCy Schubert }
117885732ac8SCy Schubert
117985732ac8SCy Schubert rtnl_link_set_link(link, drv->parent_ifi);
118085732ac8SCy Schubert
118185732ac8SCy Schubert sci = mka_sci_u64(&sc->sci);
118285732ac8SCy Schubert rtnl_link_macsec_set_sci(link, sci);
118385732ac8SCy Schubert
1184c1d255d3SCy Schubert drv->created_link = true;
118585732ac8SCy Schubert
1186*a90b9d01SCy Schubert if (drv->cipher_suite_set) {
1187*a90b9d01SCy Schubert cs = drv->cipher_suite;
1188*a90b9d01SCy Schubert drv->cipher_suite_set = false;
1189*a90b9d01SCy Schubert rtnl_link_macsec_set_cipher_suite(link, cs);
1190*a90b9d01SCy Schubert }
1191*a90b9d01SCy Schubert
119285732ac8SCy Schubert err = rtnl_link_add(drv->sk, link, NLM_F_CREATE);
119385732ac8SCy Schubert if (err == -NLE_BUSY) {
119485732ac8SCy Schubert wpa_printf(MSG_INFO,
119585732ac8SCy Schubert DRV_PREFIX "link already exists, using it");
1196c1d255d3SCy Schubert drv->created_link = false;
119785732ac8SCy Schubert } else if (err < 0) {
119885732ac8SCy Schubert rtnl_link_put(link);
119985732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't create link: err %d",
120085732ac8SCy Schubert err);
120185732ac8SCy Schubert return err;
120285732ac8SCy Schubert }
120385732ac8SCy Schubert
120485732ac8SCy Schubert rtnl_link_put(link);
120585732ac8SCy Schubert
120685732ac8SCy Schubert nl_cache_refill(drv->sk, drv->link_cache);
1207*a90b9d01SCy Schubert link = lookup_sc(drv->link_cache, drv->parent_ifi, sci, cs);
120885732ac8SCy Schubert if (!link) {
120985732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't find link");
121085732ac8SCy Schubert return -1;
121185732ac8SCy Schubert }
121285732ac8SCy Schubert
121385732ac8SCy Schubert drv->ifi = rtnl_link_get_ifindex(link);
121485732ac8SCy Schubert ifname = rtnl_link_get_name(link);
12154bc52338SCy Schubert wpa_printf(MSG_DEBUG,
12164bc52338SCy Schubert DRV_PREFIX "%s: create_transmit_sc: ifi=%d ifname=%s",
12174bc52338SCy Schubert drv->common.ifname, drv->ifi, ifname);
121885732ac8SCy Schubert os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
121985732ac8SCy Schubert rtnl_link_put(link);
122085732ac8SCy Schubert
122185732ac8SCy Schubert drv->link = rtnl_link_macsec_alloc();
122285732ac8SCy Schubert if (!drv->link) {
122385732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't allocate link");
122485732ac8SCy Schubert return -1;
122585732ac8SCy Schubert }
122685732ac8SCy Schubert
122785732ac8SCy Schubert rtnl_link_set_name(drv->link, drv->ifname);
122885732ac8SCy Schubert
122985732ac8SCy Schubert /* In case some settings have already been done but we couldn't apply
123085732ac8SCy Schubert * them. */
123185732ac8SCy Schubert return try_commit(drv);
123285732ac8SCy Schubert }
123385732ac8SCy Schubert
123485732ac8SCy Schubert
123585732ac8SCy Schubert /**
123685732ac8SCy Schubert * macsec_drv_delete_transmit_sc - Delete secure connection for transmit
123785732ac8SCy Schubert * @priv: private driver interface data from init()
123885732ac8SCy Schubert * @sc: secure channel
123985732ac8SCy Schubert * Returns: 0 on success, -1 on failure
124085732ac8SCy Schubert */
macsec_drv_delete_transmit_sc(void * priv,struct transmit_sc * sc)124185732ac8SCy Schubert static int macsec_drv_delete_transmit_sc(void *priv, struct transmit_sc *sc)
124285732ac8SCy Schubert {
124385732ac8SCy Schubert struct macsec_drv_data *drv = priv;
124485732ac8SCy Schubert int err;
124585732ac8SCy Schubert
12464bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_transmit_sc -> " SCISTR,
12474bc52338SCy Schubert drv->ifname, SCI2STR(sc->sci.addr, sc->sci.port));
124885732ac8SCy Schubert
124985732ac8SCy Schubert if (!drv->sk)
125085732ac8SCy Schubert return 0;
125185732ac8SCy Schubert
125285732ac8SCy Schubert if (!drv->created_link) {
125385732ac8SCy Schubert rtnl_link_put(drv->link);
125485732ac8SCy Schubert drv->link = NULL;
125585732ac8SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX
125685732ac8SCy Schubert "we didn't create the link, leave it alone");
125785732ac8SCy Schubert return 0;
125885732ac8SCy Schubert }
125985732ac8SCy Schubert
126085732ac8SCy Schubert err = rtnl_link_delete(drv->sk, drv->link);
126185732ac8SCy Schubert if (err < 0)
126285732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't delete link");
126385732ac8SCy Schubert rtnl_link_put(drv->link);
126485732ac8SCy Schubert drv->link = NULL;
126585732ac8SCy Schubert
126685732ac8SCy Schubert return err;
126785732ac8SCy Schubert }
126885732ac8SCy Schubert
126985732ac8SCy Schubert
127085732ac8SCy Schubert /**
127185732ac8SCy Schubert * macsec_drv_create_transmit_sa - Create secure association for transmit
127285732ac8SCy Schubert * @priv: private driver interface data from init()
127385732ac8SCy Schubert * @sa: secure association
127485732ac8SCy Schubert * Returns: 0 on success, -1 on failure
127585732ac8SCy Schubert */
macsec_drv_create_transmit_sa(void * priv,struct transmit_sa * sa)127685732ac8SCy Schubert static int macsec_drv_create_transmit_sa(void *priv, struct transmit_sa *sa)
127785732ac8SCy Schubert {
127885732ac8SCy Schubert struct macsec_drv_data *drv = priv;
127985732ac8SCy Schubert struct macsec_genl_ctx *ctx = &drv->ctx;
128085732ac8SCy Schubert struct nl_msg *msg;
128185732ac8SCy Schubert struct nlattr *nest;
128285732ac8SCy Schubert int ret = -1;
128385732ac8SCy Schubert
12844bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: create_transmit_sa -> %d on "
12854bc52338SCy Schubert SCISTR " (enable_transmit=%d next_pn=%u)",
12864bc52338SCy Schubert drv->ifname, sa->an,
12874bc52338SCy Schubert SCI2STR(sa->sc->sci.addr, sa->sc->sci.port),
12884bc52338SCy Schubert sa->enable_transmit, sa->next_pn);
12894bc52338SCy Schubert wpa_hexdump(MSG_DEBUG, DRV_PREFIX "SA keyid",
12904bc52338SCy Schubert &sa->pkey->key_identifier,
12914bc52338SCy Schubert sizeof(sa->pkey->key_identifier));
12924bc52338SCy Schubert wpa_hexdump_key(MSG_DEBUG, DRV_PREFIX "SA key",
12934bc52338SCy Schubert sa->pkey->key, sa->pkey->key_len);
129485732ac8SCy Schubert
129585732ac8SCy Schubert msg = msg_prepare(MACSEC_CMD_ADD_TXSA, ctx, drv->ifi);
129685732ac8SCy Schubert if (!msg)
129785732ac8SCy Schubert return ret;
129885732ac8SCy Schubert
129985732ac8SCy Schubert nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
130085732ac8SCy Schubert if (!nest)
130185732ac8SCy Schubert goto nla_put_failure;
130285732ac8SCy Schubert
130385732ac8SCy Schubert NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
130485732ac8SCy Schubert NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
130585732ac8SCy Schubert NLA_PUT(msg, MACSEC_SA_ATTR_KEYID, sizeof(sa->pkey->key_identifier),
130685732ac8SCy Schubert &sa->pkey->key_identifier);
130785732ac8SCy Schubert NLA_PUT(msg, MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
130885732ac8SCy Schubert NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, sa->enable_transmit);
130985732ac8SCy Schubert
131085732ac8SCy Schubert nla_nest_end(msg, nest);
131185732ac8SCy Schubert
131285732ac8SCy Schubert ret = nl_send_recv(ctx->sk, msg);
131385732ac8SCy Schubert if (ret < 0) {
131485732ac8SCy Schubert wpa_printf(MSG_ERROR,
131585732ac8SCy Schubert DRV_PREFIX "%s: failed to communicate: %d (%s)",
131685732ac8SCy Schubert __func__, ret, nl_geterror(-ret));
131785732ac8SCy Schubert }
131885732ac8SCy Schubert
131985732ac8SCy Schubert nla_put_failure:
132085732ac8SCy Schubert nlmsg_free(msg);
132185732ac8SCy Schubert return ret;
132285732ac8SCy Schubert }
132385732ac8SCy Schubert
132485732ac8SCy Schubert
132585732ac8SCy Schubert /**
132685732ac8SCy Schubert * macsec_drv_delete_transmit_sa - Delete secure association for transmit
132785732ac8SCy Schubert * @priv: private driver interface data from init()
132885732ac8SCy Schubert * @sa: secure association
132985732ac8SCy Schubert * Returns: 0 on success, -1 on failure
133085732ac8SCy Schubert */
macsec_drv_delete_transmit_sa(void * priv,struct transmit_sa * sa)133185732ac8SCy Schubert static int macsec_drv_delete_transmit_sa(void *priv, struct transmit_sa *sa)
133285732ac8SCy Schubert {
133385732ac8SCy Schubert struct macsec_drv_data *drv = priv;
133485732ac8SCy Schubert struct macsec_genl_ctx *ctx = &drv->ctx;
133585732ac8SCy Schubert struct nl_msg *msg;
133685732ac8SCy Schubert struct nlattr *nest;
133785732ac8SCy Schubert int ret = -1;
133885732ac8SCy Schubert
13394bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_transmit_sa -> %d on "
13404bc52338SCy Schubert SCISTR, drv->ifname, sa->an,
13414bc52338SCy Schubert SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
134285732ac8SCy Schubert
134385732ac8SCy Schubert msg = msg_prepare(MACSEC_CMD_DEL_TXSA, ctx, drv->ifi);
134485732ac8SCy Schubert if (!msg)
134585732ac8SCy Schubert return ret;
134685732ac8SCy Schubert
134785732ac8SCy Schubert nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
134885732ac8SCy Schubert if (!nest)
134985732ac8SCy Schubert goto nla_put_failure;
135085732ac8SCy Schubert
135185732ac8SCy Schubert NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
135285732ac8SCy Schubert
135385732ac8SCy Schubert nla_nest_end(msg, nest);
135485732ac8SCy Schubert
135585732ac8SCy Schubert ret = nl_send_recv(ctx->sk, msg);
135685732ac8SCy Schubert if (ret < 0) {
135785732ac8SCy Schubert wpa_printf(MSG_ERROR,
135885732ac8SCy Schubert DRV_PREFIX "%s: failed to communicate: %d (%s)",
135985732ac8SCy Schubert __func__, ret, nl_geterror(-ret));
136085732ac8SCy Schubert }
136185732ac8SCy Schubert
136285732ac8SCy Schubert nla_put_failure:
136385732ac8SCy Schubert nlmsg_free(msg);
136485732ac8SCy Schubert return ret;
136585732ac8SCy Schubert }
136685732ac8SCy Schubert
136785732ac8SCy Schubert
set_active_tx_sa(const struct macsec_genl_ctx * ctx,int ifindex,unsigned char an,bool state)136885732ac8SCy Schubert static int set_active_tx_sa(const struct macsec_genl_ctx *ctx, int ifindex,
1369c1d255d3SCy Schubert unsigned char an, bool state)
137085732ac8SCy Schubert {
137185732ac8SCy Schubert struct nl_msg *msg;
137285732ac8SCy Schubert struct nlattr *nest;
137385732ac8SCy Schubert int ret = -1;
137485732ac8SCy Schubert
137585732ac8SCy Schubert msg = msg_prepare(MACSEC_CMD_UPD_TXSA, ctx, ifindex);
137685732ac8SCy Schubert if (!msg)
137785732ac8SCy Schubert return ret;
137885732ac8SCy Schubert
137985732ac8SCy Schubert nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
138085732ac8SCy Schubert if (!nest)
138185732ac8SCy Schubert goto nla_put_failure;
138285732ac8SCy Schubert
138385732ac8SCy Schubert NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, an);
138485732ac8SCy Schubert NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, !!state);
138585732ac8SCy Schubert
138685732ac8SCy Schubert nla_nest_end(msg, nest);
138785732ac8SCy Schubert
138885732ac8SCy Schubert ret = nl_send_recv(ctx->sk, msg);
138985732ac8SCy Schubert if (ret < 0) {
139085732ac8SCy Schubert wpa_printf(MSG_ERROR,
139185732ac8SCy Schubert DRV_PREFIX "%s: failed to communicate: %d (%s)",
139285732ac8SCy Schubert __func__, ret, nl_geterror(-ret));
139385732ac8SCy Schubert }
139485732ac8SCy Schubert
139585732ac8SCy Schubert nla_put_failure:
139685732ac8SCy Schubert nlmsg_free(msg);
139785732ac8SCy Schubert return ret;
139885732ac8SCy Schubert }
139985732ac8SCy Schubert
140085732ac8SCy Schubert
140185732ac8SCy Schubert /**
140285732ac8SCy Schubert * macsec_drv_enable_transmit_sa - Enable SA for transmit
140385732ac8SCy Schubert * @priv: private driver interface data from init()
140485732ac8SCy Schubert * @sa: secure association
140585732ac8SCy Schubert * Returns: 0 on success, -1 on failure
140685732ac8SCy Schubert */
macsec_drv_enable_transmit_sa(void * priv,struct transmit_sa * sa)140785732ac8SCy Schubert static int macsec_drv_enable_transmit_sa(void *priv, struct transmit_sa *sa)
140885732ac8SCy Schubert {
140985732ac8SCy Schubert struct macsec_drv_data *drv = priv;
141085732ac8SCy Schubert struct macsec_genl_ctx *ctx = &drv->ctx;
141185732ac8SCy Schubert int ret;
141285732ac8SCy Schubert
14134bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: enable_transmit_sa -> %d on "
14144bc52338SCy Schubert SCISTR, drv->ifname, sa->an,
14154bc52338SCy Schubert SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
141685732ac8SCy Schubert
1417c1d255d3SCy Schubert ret = set_active_tx_sa(ctx, drv->ifi, sa->an, true);
141885732ac8SCy Schubert if (ret < 0) {
141985732ac8SCy Schubert wpa_printf(MSG_ERROR, DRV_PREFIX "failed to enable txsa");
142085732ac8SCy Schubert return ret;
142185732ac8SCy Schubert }
142285732ac8SCy Schubert
1423c1d255d3SCy Schubert drv->encoding_sa_set = true;
142485732ac8SCy Schubert drv->encoding_sa = sa->an;
142585732ac8SCy Schubert
142685732ac8SCy Schubert return try_commit(drv);
142785732ac8SCy Schubert }
142885732ac8SCy Schubert
142985732ac8SCy Schubert
143085732ac8SCy Schubert /**
143185732ac8SCy Schubert * macsec_drv_disable_transmit_sa - Disable SA for transmit
143285732ac8SCy Schubert * @priv: private driver interface data from init()
143385732ac8SCy Schubert * @sa: secure association
143485732ac8SCy Schubert * Returns: 0 on success, -1 on failure
143585732ac8SCy Schubert */
macsec_drv_disable_transmit_sa(void * priv,struct transmit_sa * sa)143685732ac8SCy Schubert static int macsec_drv_disable_transmit_sa(void *priv, struct transmit_sa *sa)
143785732ac8SCy Schubert {
143885732ac8SCy Schubert struct macsec_drv_data *drv = priv;
143985732ac8SCy Schubert struct macsec_genl_ctx *ctx = &drv->ctx;
144085732ac8SCy Schubert
14414bc52338SCy Schubert wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: disable_transmit_sa -> %d on "
14424bc52338SCy Schubert SCISTR, drv->ifname, sa->an,
14434bc52338SCy Schubert SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
144485732ac8SCy Schubert
1445c1d255d3SCy Schubert return set_active_tx_sa(ctx, drv->ifi, sa->an, false);
144685732ac8SCy Schubert }
144785732ac8SCy Schubert
144885732ac8SCy Schubert
macsec_drv_status(void * priv,char * buf,size_t buflen)14494bc52338SCy Schubert static int macsec_drv_status(void *priv, char *buf, size_t buflen)
14504bc52338SCy Schubert {
14514bc52338SCy Schubert struct macsec_drv_data *drv = priv;
14524bc52338SCy Schubert int res;
14534bc52338SCy Schubert char *pos, *end;
14544bc52338SCy Schubert
14554bc52338SCy Schubert pos = buf;
14564bc52338SCy Schubert end = buf + buflen;
14574bc52338SCy Schubert
14584bc52338SCy Schubert res = os_snprintf(pos, end - pos,
14594bc52338SCy Schubert "ifname=%s\n"
14604bc52338SCy Schubert "ifi=%d\n"
14614bc52338SCy Schubert "parent_ifname=%s\n"
14624bc52338SCy Schubert "parent_ifi=%d\n",
14634bc52338SCy Schubert drv->common.ifname, drv->ifi,
14644bc52338SCy Schubert drv->ifname, drv->parent_ifi);
14654bc52338SCy Schubert if (os_snprintf_error(end - pos, res))
14664bc52338SCy Schubert return pos - buf;
14674bc52338SCy Schubert pos += res;
14684bc52338SCy Schubert
14694bc52338SCy Schubert return pos - buf;
14704bc52338SCy Schubert }
14714bc52338SCy Schubert
14724bc52338SCy Schubert
1473206b73d0SCy Schubert #ifdef __linux__
1474206b73d0SCy Schubert
macsec_drv_handle_data(void * ctx,unsigned char * buf,size_t len)1475206b73d0SCy Schubert static void macsec_drv_handle_data(void *ctx, unsigned char *buf, size_t len)
1476206b73d0SCy Schubert {
1477206b73d0SCy Schubert #ifdef HOSTAPD
1478206b73d0SCy Schubert struct ieee8023_hdr *hdr;
1479206b73d0SCy Schubert u8 *pos, *sa;
1480206b73d0SCy Schubert size_t left;
1481206b73d0SCy Schubert union wpa_event_data event;
1482206b73d0SCy Schubert
1483206b73d0SCy Schubert /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest,
1484206b73d0SCy Schubert * 2 byte ethertype */
1485206b73d0SCy Schubert if (len < 14) {
1486206b73d0SCy Schubert wpa_printf(MSG_MSGDUMP, "%s: too short (%lu)",
1487206b73d0SCy Schubert __func__, (unsigned long) len);
1488206b73d0SCy Schubert return;
1489206b73d0SCy Schubert }
1490206b73d0SCy Schubert
1491206b73d0SCy Schubert hdr = (struct ieee8023_hdr *) buf;
1492206b73d0SCy Schubert
1493206b73d0SCy Schubert switch (ntohs(hdr->ethertype)) {
1494206b73d0SCy Schubert case ETH_P_PAE:
1495206b73d0SCy Schubert wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
1496206b73d0SCy Schubert sa = hdr->src;
1497206b73d0SCy Schubert os_memset(&event, 0, sizeof(event));
1498206b73d0SCy Schubert event.new_sta.addr = sa;
1499206b73d0SCy Schubert wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
1500206b73d0SCy Schubert
1501206b73d0SCy Schubert pos = (u8 *) (hdr + 1);
1502206b73d0SCy Schubert left = len - sizeof(*hdr);
1503206b73d0SCy Schubert drv_event_eapol_rx(ctx, sa, pos, left);
1504206b73d0SCy Schubert break;
1505206b73d0SCy Schubert
1506206b73d0SCy Schubert default:
1507206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame",
1508206b73d0SCy Schubert ntohs(hdr->ethertype));
1509206b73d0SCy Schubert break;
1510206b73d0SCy Schubert }
1511206b73d0SCy Schubert #endif /* HOSTAPD */
1512206b73d0SCy Schubert }
1513206b73d0SCy Schubert
1514206b73d0SCy Schubert
macsec_drv_handle_read(int sock,void * eloop_ctx,void * sock_ctx)1515206b73d0SCy Schubert static void macsec_drv_handle_read(int sock, void *eloop_ctx, void *sock_ctx)
1516206b73d0SCy Schubert {
1517206b73d0SCy Schubert int len;
1518206b73d0SCy Schubert unsigned char buf[3000];
1519206b73d0SCy Schubert
1520206b73d0SCy Schubert len = recv(sock, buf, sizeof(buf), 0);
1521206b73d0SCy Schubert if (len < 0) {
1522206b73d0SCy Schubert wpa_printf(MSG_ERROR, "macsec_linux: recv: %s",
1523206b73d0SCy Schubert strerror(errno));
1524206b73d0SCy Schubert return;
1525206b73d0SCy Schubert }
1526206b73d0SCy Schubert
1527206b73d0SCy Schubert macsec_drv_handle_data(eloop_ctx, buf, len);
1528206b73d0SCy Schubert }
1529206b73d0SCy Schubert
1530206b73d0SCy Schubert #endif /* __linux__ */
1531206b73d0SCy Schubert
1532206b73d0SCy Schubert
macsec_drv_init_sockets(struct macsec_drv_data * drv,u8 * own_addr)1533206b73d0SCy Schubert static int macsec_drv_init_sockets(struct macsec_drv_data *drv, u8 *own_addr)
1534206b73d0SCy Schubert {
1535206b73d0SCy Schubert #ifdef __linux__
1536206b73d0SCy Schubert struct ifreq ifr;
1537206b73d0SCy Schubert struct sockaddr_ll addr;
1538206b73d0SCy Schubert
1539206b73d0SCy Schubert drv->common.sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
1540206b73d0SCy Schubert if (drv->common.sock < 0) {
1541206b73d0SCy Schubert wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
1542206b73d0SCy Schubert strerror(errno));
1543206b73d0SCy Schubert return -1;
1544206b73d0SCy Schubert }
1545206b73d0SCy Schubert
1546206b73d0SCy Schubert if (eloop_register_read_sock(drv->common.sock, macsec_drv_handle_read,
1547206b73d0SCy Schubert drv->common.ctx, NULL)) {
1548206b73d0SCy Schubert wpa_printf(MSG_INFO, "Could not register read socket");
1549206b73d0SCy Schubert return -1;
1550206b73d0SCy Schubert }
1551206b73d0SCy Schubert
1552206b73d0SCy Schubert os_memset(&ifr, 0, sizeof(ifr));
1553206b73d0SCy Schubert os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
1554206b73d0SCy Schubert if (ioctl(drv->common.sock, SIOCGIFINDEX, &ifr) != 0) {
1555206b73d0SCy Schubert wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
1556206b73d0SCy Schubert strerror(errno));
1557206b73d0SCy Schubert return -1;
1558206b73d0SCy Schubert }
1559206b73d0SCy Schubert
1560206b73d0SCy Schubert os_memset(&addr, 0, sizeof(addr));
1561206b73d0SCy Schubert addr.sll_family = AF_PACKET;
1562206b73d0SCy Schubert addr.sll_ifindex = ifr.ifr_ifindex;
1563206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
1564206b73d0SCy Schubert addr.sll_ifindex);
1565206b73d0SCy Schubert
1566206b73d0SCy Schubert if (bind(drv->common.sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
1567206b73d0SCy Schubert {
1568206b73d0SCy Schubert wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
1569206b73d0SCy Schubert return -1;
1570206b73d0SCy Schubert }
1571206b73d0SCy Schubert
1572206b73d0SCy Schubert /* filter multicast address */
1573206b73d0SCy Schubert if (wired_multicast_membership(drv->common.sock, ifr.ifr_ifindex,
1574206b73d0SCy Schubert pae_group_addr, 1) < 0) {
1575206b73d0SCy Schubert wpa_printf(MSG_ERROR, "wired: Failed to add multicast group "
1576206b73d0SCy Schubert "membership");
1577206b73d0SCy Schubert return -1;
1578206b73d0SCy Schubert }
1579206b73d0SCy Schubert
1580206b73d0SCy Schubert os_memset(&ifr, 0, sizeof(ifr));
1581206b73d0SCy Schubert os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
1582206b73d0SCy Schubert if (ioctl(drv->common.sock, SIOCGIFHWADDR, &ifr) != 0) {
1583206b73d0SCy Schubert wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s",
1584206b73d0SCy Schubert strerror(errno));
1585206b73d0SCy Schubert return -1;
1586206b73d0SCy Schubert }
1587206b73d0SCy Schubert
1588206b73d0SCy Schubert if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
1589206b73d0SCy Schubert wpa_printf(MSG_INFO, "Invalid HW-addr family 0x%04x",
1590206b73d0SCy Schubert ifr.ifr_hwaddr.sa_family);
1591206b73d0SCy Schubert return -1;
1592206b73d0SCy Schubert }
1593206b73d0SCy Schubert os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
1594206b73d0SCy Schubert
1595206b73d0SCy Schubert return 0;
1596206b73d0SCy Schubert #else /* __linux__ */
1597206b73d0SCy Schubert return -1;
1598206b73d0SCy Schubert #endif /* __linux__ */
1599206b73d0SCy Schubert }
1600206b73d0SCy Schubert
1601206b73d0SCy Schubert
macsec_drv_hapd_init(struct hostapd_data * hapd,struct wpa_init_params * params)1602206b73d0SCy Schubert static void * macsec_drv_hapd_init(struct hostapd_data *hapd,
1603206b73d0SCy Schubert struct wpa_init_params *params)
1604206b73d0SCy Schubert {
1605206b73d0SCy Schubert struct macsec_drv_data *drv;
1606206b73d0SCy Schubert
1607206b73d0SCy Schubert drv = os_zalloc(sizeof(struct macsec_drv_data));
1608206b73d0SCy Schubert if (drv == NULL) {
1609206b73d0SCy Schubert wpa_printf(MSG_INFO,
1610206b73d0SCy Schubert "Could not allocate memory for wired driver data");
1611206b73d0SCy Schubert return NULL;
1612206b73d0SCy Schubert }
1613206b73d0SCy Schubert
1614206b73d0SCy Schubert drv->common.ctx = hapd;
1615206b73d0SCy Schubert os_strlcpy(drv->common.ifname, params->ifname,
1616206b73d0SCy Schubert sizeof(drv->common.ifname));
1617206b73d0SCy Schubert drv->use_pae_group_addr = params->use_pae_group_addr;
1618206b73d0SCy Schubert
1619206b73d0SCy Schubert if (macsec_drv_init_sockets(drv, params->own_addr)) {
1620206b73d0SCy Schubert os_free(drv);
1621206b73d0SCy Schubert return NULL;
1622206b73d0SCy Schubert }
1623206b73d0SCy Schubert
1624206b73d0SCy Schubert return drv;
1625206b73d0SCy Schubert }
1626206b73d0SCy Schubert
1627206b73d0SCy Schubert
macsec_drv_hapd_deinit(void * priv)1628206b73d0SCy Schubert static void macsec_drv_hapd_deinit(void *priv)
1629206b73d0SCy Schubert {
1630206b73d0SCy Schubert struct macsec_drv_data *drv = priv;
1631206b73d0SCy Schubert
1632206b73d0SCy Schubert if (drv->common.sock >= 0) {
1633206b73d0SCy Schubert eloop_unregister_read_sock(drv->common.sock);
1634206b73d0SCy Schubert close(drv->common.sock);
1635206b73d0SCy Schubert }
1636206b73d0SCy Schubert
1637206b73d0SCy Schubert os_free(drv);
1638206b73d0SCy Schubert }
1639206b73d0SCy Schubert
1640206b73d0SCy Schubert
macsec_drv_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)1641206b73d0SCy Schubert static int macsec_drv_send_eapol(void *priv, const u8 *addr,
1642206b73d0SCy Schubert const u8 *data, size_t data_len, int encrypt,
1643*a90b9d01SCy Schubert const u8 *own_addr, u32 flags, int link_id)
1644206b73d0SCy Schubert {
1645206b73d0SCy Schubert struct macsec_drv_data *drv = priv;
1646206b73d0SCy Schubert struct ieee8023_hdr *hdr;
1647206b73d0SCy Schubert size_t len;
1648206b73d0SCy Schubert u8 *pos;
1649206b73d0SCy Schubert int res;
1650206b73d0SCy Schubert
1651206b73d0SCy Schubert len = sizeof(*hdr) + data_len;
1652206b73d0SCy Schubert hdr = os_zalloc(len);
1653206b73d0SCy Schubert if (hdr == NULL) {
1654206b73d0SCy Schubert wpa_printf(MSG_INFO,
1655206b73d0SCy Schubert "%s: malloc() failed (len=%lu)",
1656206b73d0SCy Schubert __func__, (unsigned long) len);
1657206b73d0SCy Schubert return -1;
1658206b73d0SCy Schubert }
1659206b73d0SCy Schubert
1660206b73d0SCy Schubert os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
1661206b73d0SCy Schubert ETH_ALEN);
1662206b73d0SCy Schubert os_memcpy(hdr->src, own_addr, ETH_ALEN);
1663206b73d0SCy Schubert hdr->ethertype = htons(ETH_P_PAE);
1664206b73d0SCy Schubert
1665206b73d0SCy Schubert pos = (u8 *) (hdr + 1);
1666206b73d0SCy Schubert os_memcpy(pos, data, data_len);
1667206b73d0SCy Schubert
1668206b73d0SCy Schubert res = send(drv->common.sock, (u8 *) hdr, len, 0);
1669206b73d0SCy Schubert os_free(hdr);
1670206b73d0SCy Schubert
1671206b73d0SCy Schubert if (res < 0) {
1672206b73d0SCy Schubert wpa_printf(MSG_ERROR,
1673206b73d0SCy Schubert "%s: packet len: %lu - failed: send: %s",
1674206b73d0SCy Schubert __func__, (unsigned long) len, strerror(errno));
1675206b73d0SCy Schubert }
1676206b73d0SCy Schubert
1677206b73d0SCy Schubert return res;
1678206b73d0SCy Schubert }
1679206b73d0SCy Schubert
1680206b73d0SCy Schubert
168185732ac8SCy Schubert const struct wpa_driver_ops wpa_driver_macsec_linux_ops = {
168285732ac8SCy Schubert .name = "macsec_linux",
168385732ac8SCy Schubert .desc = "MACsec Ethernet driver for Linux",
168485732ac8SCy Schubert .get_ssid = driver_wired_get_ssid,
168585732ac8SCy Schubert .get_bssid = driver_wired_get_bssid,
168685732ac8SCy Schubert .get_capa = driver_wired_get_capa,
168785732ac8SCy Schubert .init = macsec_drv_wpa_init,
168885732ac8SCy Schubert .deinit = macsec_drv_wpa_deinit,
1689206b73d0SCy Schubert .hapd_init = macsec_drv_hapd_init,
1690206b73d0SCy Schubert .hapd_deinit = macsec_drv_hapd_deinit,
1691206b73d0SCy Schubert .hapd_send_eapol = macsec_drv_send_eapol,
169285732ac8SCy Schubert
169385732ac8SCy Schubert .macsec_init = macsec_drv_macsec_init,
169485732ac8SCy Schubert .macsec_deinit = macsec_drv_macsec_deinit,
169585732ac8SCy Schubert .macsec_get_capability = macsec_drv_get_capability,
169685732ac8SCy Schubert .enable_protect_frames = macsec_drv_enable_protect_frames,
169785732ac8SCy Schubert .enable_encrypt = macsec_drv_enable_encrypt,
169885732ac8SCy Schubert .set_replay_protect = macsec_drv_set_replay_protect,
1699*a90b9d01SCy Schubert .set_offload = macsec_drv_set_offload,
170085732ac8SCy Schubert .set_current_cipher_suite = macsec_drv_set_current_cipher_suite,
170185732ac8SCy Schubert .enable_controlled_port = macsec_drv_enable_controlled_port,
170285732ac8SCy Schubert .get_receive_lowest_pn = macsec_drv_get_receive_lowest_pn,
17034bc52338SCy Schubert .set_receive_lowest_pn = macsec_drv_set_receive_lowest_pn,
170485732ac8SCy Schubert .get_transmit_next_pn = macsec_drv_get_transmit_next_pn,
170585732ac8SCy Schubert .set_transmit_next_pn = macsec_drv_set_transmit_next_pn,
170685732ac8SCy Schubert .create_receive_sc = macsec_drv_create_receive_sc,
170785732ac8SCy Schubert .delete_receive_sc = macsec_drv_delete_receive_sc,
170885732ac8SCy Schubert .create_receive_sa = macsec_drv_create_receive_sa,
170985732ac8SCy Schubert .delete_receive_sa = macsec_drv_delete_receive_sa,
171085732ac8SCy Schubert .enable_receive_sa = macsec_drv_enable_receive_sa,
171185732ac8SCy Schubert .disable_receive_sa = macsec_drv_disable_receive_sa,
171285732ac8SCy Schubert .create_transmit_sc = macsec_drv_create_transmit_sc,
171385732ac8SCy Schubert .delete_transmit_sc = macsec_drv_delete_transmit_sc,
171485732ac8SCy Schubert .create_transmit_sa = macsec_drv_create_transmit_sa,
171585732ac8SCy Schubert .delete_transmit_sa = macsec_drv_delete_transmit_sa,
171685732ac8SCy Schubert .enable_transmit_sa = macsec_drv_enable_transmit_sa,
171785732ac8SCy Schubert .disable_transmit_sa = macsec_drv_disable_transmit_sa,
17184bc52338SCy Schubert
17194bc52338SCy Schubert .status = macsec_drv_status,
172085732ac8SCy Schubert };
1721