1abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/*
2abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Driver interaction with Linux MACsec kernel module
3abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Copyright (c) 2016, Sabrina Dubroca <sd@queasysnail.net> and Red Hat, Inc.
4abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt *
5abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * See README for more details.
7abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
8abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
9abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include "includes.h"
10abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include <sys/ioctl.h>
11abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include <net/if.h>
12abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include <netpacket/packet.h>
13abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include <net/if_arp.h>
14abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include <net/if.h>
15abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include <netlink/netlink.h>
16abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include <netlink/genl/genl.h>
17abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include <netlink/genl/ctrl.h>
18abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include <netlink/route/link.h>
19abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include <netlink/route/link/macsec.h>
20abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include <linux/if_macsec.h>
21abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include <inttypes.h>
22abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
23abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include "utils/common.h"
24abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include "utils/eloop.h"
25abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include "pae/ieee802_1x_kay.h"
26abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include "driver.h"
27abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#include "driver_wired_common.h"
28abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
29abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#define DRV_PREFIX "macsec_linux: "
30abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
31abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#define UNUSED_SCI 0xffffffffffffffff
32abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
33abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstruct cb_arg {
34abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv;
35abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	u32 *pn;
36abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int ifindex;
37abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	u8 txsa;
38abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	u8 rxsa;
39abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	u64 rxsci;
40abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt};
41abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
42abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstruct macsec_genl_ctx {
43abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nl_sock *sk;
44abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int macsec_genl_id;
45abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct cb_arg cb_arg;
46abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt};
47abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
48abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstruct macsec_drv_data {
49abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct driver_wired_common_data common;
50abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct rtnl_link *link;
51abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nl_cache *link_cache;
52abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nl_sock *sk;
53abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_genl_ctx ctx;
54abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
55abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct netlink_data *netlink;
56abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nl_handle *nl;
57abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	char ifname[IFNAMSIZ + 1];
58abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int ifi;
59abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int parent_ifi;
60abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
61abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	Boolean created_link;
62abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
63abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	Boolean controlled_port_enabled;
64abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	Boolean controlled_port_enabled_set;
65abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
66abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	Boolean protect_frames;
67abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	Boolean protect_frames_set;
68abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
69abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	Boolean encrypt;
70abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	Boolean encrypt_set;
71abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
72abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	Boolean replay_protect;
73abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	Boolean replay_protect_set;
74abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
75abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	u32 replay_window;
76abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
77abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	u8 encoding_sa;
78abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	Boolean encoding_sa_set;
79abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt};
80abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
81abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
82abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int dump_callback(struct nl_msg *msg, void *argp);
83abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
84abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
85abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic struct nl_msg * msg_prepare(enum macsec_nl_commands cmd,
86abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				   const struct macsec_genl_ctx *ctx,
87abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				   unsigned int ifindex)
88abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
89abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nl_msg *msg;
90abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
91abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	msg = nlmsg_alloc();
92abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!msg) {
93abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc message");
94abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return NULL;
95abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
96abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
97abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!genlmsg_put(msg, 0, 0, ctx->macsec_genl_id, 0, 0, cmd, 0)) {
98abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX "failed to put header");
99abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto nla_put_failure;
100abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
101abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
102abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U32(msg, MACSEC_ATTR_IFINDEX, ifindex);
103abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
104abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return msg;
105abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
106abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtnla_put_failure:
107abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nlmsg_free(msg);
108abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return NULL;
109abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
110abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
111abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
112abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int nla_put_rxsc_config(struct nl_msg *msg, u64 sci)
113abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
114abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nlattr *nest = nla_nest_start(msg, MACSEC_ATTR_RXSC_CONFIG);
115abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
116abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!nest)
117abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return -1;
118abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
119abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U64(msg, MACSEC_RXSC_ATTR_SCI, sci);
120abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
121abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nla_nest_end(msg, nest);
122abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
123abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return 0;
124abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
125abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtnla_put_failure:
126abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return -1;
127abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
128abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
129abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
130abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int init_genl_ctx(struct macsec_drv_data *drv)
131abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
132abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_genl_ctx *ctx = &drv->ctx;
133abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
134abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ctx->sk = nl_socket_alloc();
135abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!ctx->sk) {
136abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc genl socket");
137abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return -1;
138abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
139abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
140abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (genl_connect(ctx->sk) < 0) {
141abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR,
142abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   DRV_PREFIX "connection to genl socket failed");
143abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto out_free;
144abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
145abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
146abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ctx->macsec_genl_id = genl_ctrl_resolve(ctx->sk, "macsec");
147abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (ctx->macsec_genl_id < 0) {
148abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX "genl resolve failed");
149abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto out_free;
150abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
151abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
152abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	memset(&ctx->cb_arg, 0, sizeof(ctx->cb_arg));
153abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ctx->cb_arg.drv = drv;
154abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
155abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nl_socket_modify_cb(ctx->sk, NL_CB_VALID, NL_CB_CUSTOM, dump_callback,
156abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			    &ctx->cb_arg);
157abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
158abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return 0;
159abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
160abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtout_free:
161abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nl_socket_free(ctx->sk);
162abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ctx->sk = NULL;
163abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return -1;
164abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
165abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
166abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
167abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int try_commit(struct macsec_drv_data *drv)
168abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
169abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int err;
170abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
171abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!drv->link)
172abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return 0;
173abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
174abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (drv->controlled_port_enabled_set) {
175abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		struct rtnl_link *change = rtnl_link_alloc();
176abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
177abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		if (!change)
178abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			return -1;
179abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
180abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		rtnl_link_set_name(change, drv->ifname);
181abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
182abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		if (drv->controlled_port_enabled)
183abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			rtnl_link_set_flags(change, IFF_UP);
184abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		else
185abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			rtnl_link_unset_flags(change, IFF_UP);
186abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
187abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		err = rtnl_link_change(drv->sk, change, change, 0);
188abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		if (err < 0)
189abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			return err;
190abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
191abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		rtnl_link_put(change);
192abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
193abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		drv->controlled_port_enabled_set = FALSE;
194abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
195abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
196abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (drv->protect_frames_set)
197abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		rtnl_link_macsec_set_protect(drv->link, drv->protect_frames);
198abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
199abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (drv->encrypt_set)
200abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		rtnl_link_macsec_set_encrypt(drv->link, drv->encrypt);
201abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
202abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (drv->replay_protect_set) {
203abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		rtnl_link_macsec_set_replay_protect(drv->link,
204abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt						    drv->replay_protect);
205abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		if (drv->replay_protect)
206abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			rtnl_link_macsec_set_window(drv->link,
207abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt						    drv->replay_window);
208abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
209abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
210abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (drv->encoding_sa_set)
211abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		rtnl_link_macsec_set_encoding_sa(drv->link, drv->encoding_sa);
212abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
213abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	err = rtnl_link_add(drv->sk, drv->link, 0);
214abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (err < 0)
215abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return err;
216abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
217abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->protect_frames_set = FALSE;
218abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->encrypt_set = FALSE;
219abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->replay_protect_set = FALSE;
220abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
221abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return 0;
222abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
223abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
224abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
225abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic void macsec_drv_wpa_deinit(void *priv)
226abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
227abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
228abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
229abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	driver_wired_deinit_common(&drv->common);
230abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	os_free(drv);
231abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
232abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
233abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
234abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic void * macsec_drv_wpa_init(void *ctx, const char *ifname)
235abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
236abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv;
237abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
238abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv = os_zalloc(sizeof(*drv));
239abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!drv)
240abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return NULL;
241abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
242abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
243abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		os_free(drv);
244abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return NULL;
245abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
246abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
247abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return drv;
248abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
249abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
250abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
251abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_macsec_init(void *priv, struct macsec_init_params *params)
252abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
253abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
254abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int err;
255abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
256abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s", __func__);
257abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
258abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->sk = nl_socket_alloc();
259abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!drv->sk)
260abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return -1;
261abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
262abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	err = nl_connect(drv->sk, NETLINK_ROUTE);
263abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (err < 0) {
264abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX
265abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   "Unable to connect NETLINK_ROUTE socket: %s",
266abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   strerror(errno));
267abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto sock;
268abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
269abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
270abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	err = rtnl_link_alloc_cache(drv->sk, AF_UNSPEC, &drv->link_cache);
271abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (err < 0) {
272abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX "Unable to get link cache: %s",
273abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   strerror(errno));
274abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto sock;
275abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
276abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
277abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->parent_ifi = rtnl_link_name2i(drv->link_cache, drv->common.ifname);
278abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (drv->parent_ifi == 0) {
279abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX
280abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   "couldn't find ifindex for interface %s",
281abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   drv->common.ifname);
282abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto cache;
283abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
284abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
285abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	err = init_genl_ctx(drv);
286abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (err < 0)
287abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto cache;
288abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
289abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return 0;
290abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
291abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtcache:
292abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nl_cache_free(drv->link_cache);
293abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->link_cache = NULL;
294abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtsock:
295abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nl_socket_free(drv->sk);
296abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->sk = NULL;
297abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return -1;
298abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
299abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
300abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
301abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_macsec_deinit(void *priv)
302abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
303abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
304abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
305abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s", __func__);
306abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
307abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (drv->sk)
308abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		nl_socket_free(drv->sk);
309abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->sk = NULL;
310abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
311abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (drv->link_cache)
312abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		nl_cache_free(drv->link_cache);
313abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->link_cache = NULL;
314abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
315abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (drv->ctx.sk)
316abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		nl_socket_free(drv->ctx.sk);
317abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
318abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return 0;
319abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
320abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
321abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
322abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_get_capability(void *priv, enum macsec_cap *cap)
323abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
324abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s", __func__);
325abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
326abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	*cap = MACSEC_CAP_INTEG_AND_CONF;
327abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
328abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return 0;
329abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
330abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
331abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
332abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
333abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_enable_protect_frames - Set protect frames status
334abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: Private driver interface data
335abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @enabled: TRUE = protect frames enabled
336abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt *           FALSE = protect frames disabled
337abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure (or if not supported)
338abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
339abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_enable_protect_frames(void *priv, Boolean enabled)
340abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
341abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
342abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
343abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
344abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
345abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->protect_frames_set = TRUE;
346abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->protect_frames = enabled;
347abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
348abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return try_commit(drv);
349abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
350abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
351abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
352abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
353abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_enable_encrypt - Set protect frames status
354abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: Private driver interface data
355abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @enabled: TRUE = protect frames enabled
356abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt *           FALSE = protect frames disabled
357abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure (or if not supported)
358abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
359abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_enable_encrypt(void *priv, Boolean enabled)
360abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
361abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
362abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
363abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
364abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
365abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->encrypt_set = TRUE;
366abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->encrypt = enabled;
367abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
368abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return try_commit(drv);
369abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
370abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
371abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
372abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
373abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_set_replay_protect - Set replay protect status and window size
374abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: Private driver interface data
375abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @enabled: TRUE = replay protect enabled
376abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt *           FALSE = replay protect disabled
377abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @window: replay window size, valid only when replay protect enabled
378abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure (or if not supported)
379abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
380abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_set_replay_protect(void *priv, Boolean enabled,
381abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt					 u32 window)
382abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
383abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
384abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
385abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> %s, %u", __func__,
386abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		   enabled ? "TRUE" : "FALSE", window);
387abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
388abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->replay_protect_set = TRUE;
389abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->replay_protect = enabled;
390abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (enabled)
391abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		drv->replay_window = window;
392abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
393abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return try_commit(drv);
394abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
395abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
396abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
397abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
398abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_set_current_cipher_suite - Set current cipher suite
399abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: Private driver interface data
400abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @cs: EUI64 identifier
401abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure (or if not supported)
402abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
403abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_set_current_cipher_suite(void *priv, u64 cs)
404abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
405abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> %016" PRIx64, __func__, cs);
406abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return 0;
407abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
408abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
409abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
410abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
411abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_enable_controlled_port - Set controlled port status
412abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: Private driver interface data
413abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @enabled: TRUE = controlled port enabled
414abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt *           FALSE = controlled port disabled
415abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure (or if not supported)
416abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
417abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_enable_controlled_port(void *priv, Boolean enabled)
418abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
419abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
420abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
421abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
422abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
423abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->controlled_port_enabled = enabled;
424abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->controlled_port_enabled_set = TRUE;
425abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
426abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return try_commit(drv);
427abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
428abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
429abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
430abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic struct nla_policy sa_policy[MACSEC_SA_ATTR_MAX + 1] = {
431abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	[MACSEC_SA_ATTR_AN] = { .type = NLA_U8 },
432abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	[MACSEC_SA_ATTR_ACTIVE] = { .type = NLA_U8 },
433abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	[MACSEC_SA_ATTR_PN] = { .type = NLA_U32 },
434abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	[MACSEC_SA_ATTR_KEYID] = { .type = NLA_BINARY },
435abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt};
436abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
437abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic struct nla_policy sc_policy[MACSEC_RXSC_ATTR_MAX + 1] = {
438abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	[MACSEC_RXSC_ATTR_SCI] = { .type = NLA_U64 },
439abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	[MACSEC_RXSC_ATTR_ACTIVE] = { .type = NLA_U8 },
440abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	[MACSEC_RXSC_ATTR_SA_LIST] = { .type = NLA_NESTED },
441abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt};
442abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
443abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic struct nla_policy main_policy[MACSEC_ATTR_MAX + 1] = {
444abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	[MACSEC_ATTR_IFINDEX] = { .type = NLA_U32 },
445abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	[MACSEC_ATTR_SECY] = { .type = NLA_NESTED },
446abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	[MACSEC_ATTR_TXSA_LIST] = { .type = NLA_NESTED },
447abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	[MACSEC_ATTR_RXSC_LIST] = { .type = NLA_NESTED },
448abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt};
449abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
450abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int dump_callback(struct nl_msg *msg, void *argp)
451abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
452abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nlmsghdr *ret_hdr = nlmsg_hdr(msg);
453abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nlattr *tb_msg[MACSEC_ATTR_MAX + 1];
454abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct cb_arg *arg = (struct cb_arg *) argp;
455abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct genlmsghdr *gnlh = (struct genlmsghdr *) nlmsg_data(ret_hdr);
456abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int err;
457abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
458abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (ret_hdr->nlmsg_type != arg->drv->ctx.macsec_genl_id)
459abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return 0;
460abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
461abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	err = nla_parse(tb_msg, MACSEC_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
462abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			genlmsg_attrlen(gnlh, 0), main_policy);
463abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (err < 0)
464abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return 0;
465abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
466abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!tb_msg[MACSEC_ATTR_IFINDEX])
467abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return 0;
468abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
469abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (nla_get_u32(tb_msg[MACSEC_ATTR_IFINDEX]) != (u32) arg->ifindex)
470abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return 0;
471abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
472abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (arg->txsa < 4 && !tb_msg[MACSEC_ATTR_TXSA_LIST]) {
473abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return 0;
474abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	} else if (arg->txsa < 4) {
475abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		struct nlattr *nla;
476abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		int rem;
477abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
478abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		nla_for_each_nested(nla, tb_msg[MACSEC_ATTR_TXSA_LIST], rem) {
479abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			struct nlattr *tb[MACSEC_SA_ATTR_MAX + 1];
480abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
481abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			err = nla_parse_nested(tb, MACSEC_SA_ATTR_MAX, nla,
482abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt					       sa_policy);
483abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			if (err < 0)
484abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				continue;
485abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			if (!tb[MACSEC_SA_ATTR_AN])
486abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				continue;
487abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			if (nla_get_u8(tb[MACSEC_SA_ATTR_AN]) != arg->txsa)
488abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				continue;
489abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			if (!tb[MACSEC_SA_ATTR_PN])
490abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				return 0;
491abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			*arg->pn = nla_get_u32(tb[MACSEC_SA_ATTR_PN]);
492abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			return 0;
493abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		}
494abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
495abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return 0;
496abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
497abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
498abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (arg->rxsci == UNUSED_SCI)
499abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return 0;
500abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
501abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (tb_msg[MACSEC_ATTR_RXSC_LIST]) {
502abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		struct nlattr *nla;
503abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		int rem;
504abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
505abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		nla_for_each_nested(nla, tb_msg[MACSEC_ATTR_RXSC_LIST], rem) {
506abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			struct nlattr *tb[MACSEC_RXSC_ATTR_MAX + 1];
507abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
508abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			err = nla_parse_nested(tb, MACSEC_RXSC_ATTR_MAX, nla,
509abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt					       sc_policy);
510abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			if (err < 0)
511abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				return 0;
512abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			if (!tb[MACSEC_RXSC_ATTR_SCI])
513abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				continue;
514abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			if (nla_get_u64(tb[MACSEC_RXSC_ATTR_SCI]) != arg->rxsci)
515abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				continue;
516abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			if (!tb[MACSEC_RXSC_ATTR_SA_LIST])
517abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				return 0;
518abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
519abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			nla_for_each_nested(nla, tb[MACSEC_RXSC_ATTR_SA_LIST],
520abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt					    rem) {
521abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
522abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
523abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				err = nla_parse_nested(tb_sa,
524abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt						       MACSEC_SA_ATTR_MAX, nla,
525abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt						       sa_policy);
526abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				if (err < 0)
527abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt					continue;
528abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				if (!tb_sa[MACSEC_SA_ATTR_AN])
529abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt					continue;
530abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				if (nla_get_u8(tb_sa[MACSEC_SA_ATTR_AN]) !=
531abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				    arg->rxsa)
532abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt					continue;
533abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				if (!tb_sa[MACSEC_SA_ATTR_PN])
534abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt					return 0;
535abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				*arg->pn =
536abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt					nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
537abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
538abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				return 0;
539abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			}
540abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
541abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			return 0;
542abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		}
543abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
544abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return 0;
545abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
546abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
547abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return 0;
548abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
549abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
550abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
551abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int nl_send_recv(struct nl_sock *sk, struct nl_msg *msg)
552abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
553abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int ret;
554abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
555abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ret = nl_send_auto_complete(sk, msg);
556abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (ret < 0) {
557abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to send: %d (%s)",
558abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   __func__, ret, nl_geterror(-ret));
559abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return ret;
560abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
561abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
562abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ret = nl_recvmsgs_default(sk);
563abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (ret < 0) {
564abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to recv: %d (%s)",
565abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   __func__, ret, nl_geterror(-ret));
566abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
567abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
568abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return ret;
569abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
570abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
571abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
572abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int do_dump(struct macsec_drv_data *drv, u8 txsa, u64 rxsci, u8 rxsa,
573abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		   u32 *pn)
574abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
575abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_genl_ctx *ctx = &drv->ctx;
576abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nl_msg *msg;
577abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int ret = 1;
578abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
579abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ctx->cb_arg.ifindex = drv->ifi;
580abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ctx->cb_arg.rxsci = rxsci;
581abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ctx->cb_arg.rxsa = rxsa;
582abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ctx->cb_arg.txsa = txsa;
583abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ctx->cb_arg.pn = pn;
584abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
585abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	msg = nlmsg_alloc();
586abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!msg) {
587abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to alloc message",
588abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   __func__);
589abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return 1;
590abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
591abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
592abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ctx->macsec_genl_id, 0,
593abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			 NLM_F_DUMP, MACSEC_CMD_GET_TXSC, 0)) {
594abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to put header",
595abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   __func__);
596abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto out_free_msg;
597abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
598abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
599abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ret = nl_send_recv(ctx->sk, msg);
600abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (ret < 0)
601abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR,
602abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   DRV_PREFIX "failed to communicate: %d (%s)",
603abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   ret, nl_geterror(-ret));
604abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
605abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ctx->cb_arg.pn = 0;
606abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
607abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtout_free_msg:
608abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nlmsg_free(msg);
609abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return ret;
610abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
611abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
612abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
613abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
614abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_get_receive_lowest_pn - Get receive lowest PN
615abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: Private driver interface data
616abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sa: secure association
617abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure (or if not supported)
618abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
619abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
620abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
621abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
622abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int err;
623abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
624abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, DRV_PREFIX "%s", __func__);
625abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
626abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	err = do_dump(drv, 0xff, mka_sci_u64(&sa->sc->sci), sa->an,
627abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		      &sa->lowest_pn);
628abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: result %d", __func__,
629abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		   sa->lowest_pn);
630abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
631abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return err;
632abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
633abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
634abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
635abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
636abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_get_transmit_next_pn - Get transmit next PN
637abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: Private driver interface data
638abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sa: secure association
639abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure (or if not supported)
640abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
641abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
642abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
643abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
644abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int err;
645abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
646abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s", __func__);
647abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
648abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	err = do_dump(drv, sa->an, UNUSED_SCI, 0xff, &sa->next_pn);
649abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: err %d result %d", __func__, err,
650abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		   sa->next_pn);
651abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return err;
652abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
653abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
654abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
655abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
656abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_set_transmit_next_pn - Set transmit next pn
657abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: Private driver interface data
658abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sa: secure association
659abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure (or if not supported)
660abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
661abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
662abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
663abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
664abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_genl_ctx *ctx = &drv->ctx;
665abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nl_msg *msg;
666abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nlattr *nest;
667abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int ret = -1;
668abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
669abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> %d: %d", __func__, sa->an, sa->next_pn);
670abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
671abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	msg = msg_prepare(MACSEC_CMD_UPD_TXSA, ctx, drv->ifi);
672abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!msg)
673abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return ret;
674abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
675abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
676abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!nest)
677abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto nla_put_failure;
678abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
679abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
680abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
681abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
682abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nla_nest_end(msg, nest);
683abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
684abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ret = nl_send_recv(ctx->sk, msg);
685abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (ret < 0) {
686abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR,
687abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   DRV_PREFIX "failed to communicate: %d (%s)",
688abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   ret, nl_geterror(-ret));
689abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
690abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
691abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtnla_put_failure:
692abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nlmsg_free(msg);
693abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return ret;
694abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
695abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
696abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
697abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#define SCISTR MACSTR "::%hx"
698abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt#define SCI2STR(addr, port) MAC2STR(addr), htons(port)
699abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
700abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
701abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_create_receive_sc - Create secure channel for receiving
702abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: Private driver interface data
703abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sc: secure channel
704abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sci_addr: secure channel identifier - address
705abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sci_port: secure channel identifier - port
706abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @conf_offset: confidentiality offset (0, 30, or 50)
707abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @validation: frame validation policy (0 = Disabled, 1 = Checked,
708abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt *	2 = Strict)
709abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure (or if not supported)
710abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
711abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_create_receive_sc(void *priv, struct receive_sc *sc,
712abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt					unsigned int conf_offset,
713abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt					int validation)
714abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
715abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
716abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_genl_ctx *ctx = &drv->ctx;
717abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nl_msg *msg;
718abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int ret = -1;
719abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
720abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> " SCISTR, __func__,
721abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		   SCI2STR(sc->sci.addr, sc->sci.port));
722abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
723abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	msg = msg_prepare(MACSEC_CMD_ADD_RXSC, ctx, drv->ifi);
724abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!msg)
725abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return ret;
726abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
727abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (nla_put_rxsc_config(msg, mka_sci_u64(&sc->sci)))
728abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto nla_put_failure;
729abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
730abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ret = nl_send_recv(ctx->sk, msg);
731abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (ret < 0) {
732abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR,
733abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   DRV_PREFIX "%s: failed to communicate: %d (%s)",
734abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   __func__, ret, nl_geterror(-ret));
735abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
736abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
737abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtnla_put_failure:
738abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nlmsg_free(msg);
739abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return ret;
740abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
741abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
742abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
743abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
744abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_delete_receive_sc - Delete secure connection for receiving
745abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: private driver interface data from init()
746abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sc: secure channel
747abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure
748abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
749abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_delete_receive_sc(void *priv, struct receive_sc *sc)
750abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
751abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
752abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_genl_ctx *ctx = &drv->ctx;
753abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nl_msg *msg;
754abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int ret = -1;
755abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
756abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> " SCISTR, __func__,
757abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		   SCI2STR(sc->sci.addr, sc->sci.port));
758abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
759abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	msg = msg_prepare(MACSEC_CMD_DEL_RXSC, ctx, drv->ifi);
760abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!msg)
761abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return ret;
762abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
763abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (nla_put_rxsc_config(msg, mka_sci_u64(&sc->sci)))
764abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto nla_put_failure;
765abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
766abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ret = nl_send_recv(ctx->sk, msg);
767abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (ret < 0) {
768abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR,
769abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   DRV_PREFIX "%s: failed to communicate: %d (%s)",
770abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   __func__, ret, nl_geterror(-ret));
771abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
772abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
773abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtnla_put_failure:
774abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nlmsg_free(msg);
775abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return ret;
776abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
777abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
778abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
779abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
780abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_create_receive_sa - Create secure association for receive
781abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: private driver interface data from init()
782abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sa: secure association
783abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure
784abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
785abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_create_receive_sa(void *priv, struct receive_sa *sa)
786abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
787abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
788abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_genl_ctx *ctx = &drv->ctx;
789abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nl_msg *msg;
790abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nlattr *nest;
791abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int ret = -1;
792abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
793abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
794abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		   SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
795abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
796abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	msg = msg_prepare(MACSEC_CMD_ADD_RXSA, ctx, drv->ifi);
797abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!msg)
798abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return ret;
799abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
800abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci)))
801abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto nla_put_failure;
802abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
803abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
804abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!nest)
805abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto nla_put_failure;
806abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
807abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
808abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, sa->enable_receive);
809abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
810abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT(msg, MACSEC_SA_ATTR_KEYID, sizeof(sa->pkey->key_identifier),
811abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		&sa->pkey->key_identifier);
812abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT(msg, MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
813abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
814abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nla_nest_end(msg, nest);
815abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
816abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ret = nl_send_recv(ctx->sk, msg);
817abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (ret < 0) {
818abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR,
819abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   DRV_PREFIX "%s: failed to communicate: %d (%s)",
820abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   __func__, ret, nl_geterror(-ret));
821abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
822abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
823abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtnla_put_failure:
824abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nlmsg_free(msg);
825abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return ret;
826abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
827abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
828abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
829abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
830abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_delete_receive_sa - Delete secure association for receive
831abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: private driver interface data from init()
832abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sa: secure association
833abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure
834abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
835abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_delete_receive_sa(void *priv, struct receive_sa *sa)
836abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
837abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
838abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_genl_ctx *ctx = &drv->ctx;
839abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nl_msg *msg;
840abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nlattr *nest;
841abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int ret = -1;
842abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
843abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
844abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		   SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
845abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
846abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	msg = msg_prepare(MACSEC_CMD_DEL_RXSA, ctx, drv->ifi);
847abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!msg)
848abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return ret;
849abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
850abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci)))
851abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto nla_put_failure;
852abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
853abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
854abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!nest)
855abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto nla_put_failure;
856abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
857abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
858abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
859abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nla_nest_end(msg, nest);
860abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
861abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ret = nl_send_recv(ctx->sk, msg);
862abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (ret < 0) {
863abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR,
864abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   DRV_PREFIX "%s: failed to communicate: %d (%s)",
865abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   __func__, ret, nl_geterror(-ret));
866abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
867abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
868abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtnla_put_failure:
869abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nlmsg_free(msg);
870abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return ret;
871abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
872abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
873abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
874abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int set_active_rx_sa(const struct macsec_genl_ctx *ctx, int ifindex,
875abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			    u64 sci, unsigned char an, Boolean state)
876abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
877abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nl_msg *msg;
878abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nlattr *nest;
879abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int ret = -1;
880abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
881abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	msg = msg_prepare(MACSEC_CMD_UPD_RXSA, ctx, ifindex);
882abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!msg)
883abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return ret;
884abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
885abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (nla_put_rxsc_config(msg, sci))
886abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto nla_put_failure;
887abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
888abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
889abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!nest)
890abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto nla_put_failure;
891abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
892abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, an);
893abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, !!state);
894abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
895abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nla_nest_end(msg, nest);
896abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
897abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ret = nl_send_recv(ctx->sk, msg);
898abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (ret < 0)
899abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR,
900abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   DRV_PREFIX "%s: failed to communicate: %d (%s)",
901abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   __func__, ret, nl_geterror(-ret));
902abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
903abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtnla_put_failure:
904abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nlmsg_free(msg);
905abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return ret;
906abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
907abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
908abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
909abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
910abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_enable_receive_sa - Enable the SA for receive
911abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: private driver interface data from init()
912abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sa: secure association
913abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure
914abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
915abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_enable_receive_sa(void *priv, struct receive_sa *sa)
916abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
917abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
918abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_genl_ctx *ctx = &drv->ctx;
919abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
920abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
921abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		   SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
922abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
923abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
924abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				sa->an, TRUE);
925abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
926abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
927abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
928abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
929abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_disable_receive_sa - Disable SA for receive
930abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: private driver interface data from init()
931abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sa: secure association
932abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure
933abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
934abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_disable_receive_sa(void *priv, struct receive_sa *sa)
935abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
936abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
937abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_genl_ctx *ctx = &drv->ctx;
938abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
939abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
940abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		   SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
941abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
942abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
943abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt				sa->an, FALSE);
944abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
945abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
946abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
947abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci)
948abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
949abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct rtnl_link *needle;
950abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	void *match;
951abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
952abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	needle = rtnl_link_macsec_alloc();
953abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!needle)
954abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return NULL;
955abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
956abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	rtnl_link_set_link(needle, parent);
957abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	rtnl_link_macsec_set_sci(needle, sci);
958abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
959abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	match = nl_cache_find(cache, (struct nl_object *) needle);
960abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	rtnl_link_put(needle);
961abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
962abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return (struct rtnl_link *) match;
963abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
964abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
965abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
966abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
967abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_create_transmit_sc - Create secure connection for transmit
968abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: private driver interface data from init()
969abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sc: secure channel
970abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @conf_offset: confidentiality offset
971abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure
972abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
973abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_create_transmit_sc(
974abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	void *priv, struct transmit_sc *sc,
975abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	enum confidentiality_offset conf_offset)
976abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
977abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
978abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct rtnl_link *link;
979abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	char *ifname;
980abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	u64 sci;
981abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int err;
982abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
983abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s", __func__);
984abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
985abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	link = rtnl_link_macsec_alloc();
986abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!link) {
987abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't allocate link");
988abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return -1;
989abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
990abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
991abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	rtnl_link_set_link(link, drv->parent_ifi);
992abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
993abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	sci = mka_sci_u64(&sc->sci);
994abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	rtnl_link_macsec_set_sci(link, sci);
995abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
996abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->created_link = TRUE;
997abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
998abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	err = rtnl_link_add(drv->sk, link, NLM_F_CREATE);
999abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (err == -NLE_BUSY) {
1000abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_INFO,
1001abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   DRV_PREFIX "link already exists, using it");
1002abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		drv->created_link = FALSE;
1003abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	} else if (err < 0) {
1004abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		rtnl_link_put(link);
1005abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't create link: err %d",
1006abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   err);
1007abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return err;
1008abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
1009abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1010abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	rtnl_link_put(link);
1011abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1012abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nl_cache_refill(drv->sk, drv->link_cache);
1013abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	link = lookup_sc(drv->link_cache, drv->parent_ifi, sci);
1014abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!link) {
1015abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't find link");
1016abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return -1;
1017abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
1018abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1019abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->ifi = rtnl_link_get_ifindex(link);
1020abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ifname = rtnl_link_get_name(link);
1021abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
1022abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	rtnl_link_put(link);
1023abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1024abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->link = rtnl_link_macsec_alloc();
1025abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!drv->link) {
1026abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't allocate link");
1027abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return -1;
1028abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
1029abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1030abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	rtnl_link_set_name(drv->link, drv->ifname);
1031abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1032abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	/* In case some settings have already been done but we couldn't apply
1033abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	 * them. */
1034abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return try_commit(drv);
1035abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
1036abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1037abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1038abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
1039abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_delete_transmit_sc - Delete secure connection for transmit
1040abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: private driver interface data from init()
1041abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sc: secure channel
1042abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure
1043abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
1044abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_delete_transmit_sc(void *priv, struct transmit_sc *sc)
1045abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
1046abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
1047abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int err;
1048abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1049abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s", __func__);
1050abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1051abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!drv->created_link) {
1052abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		rtnl_link_put(drv->link);
1053abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		drv->link = NULL;
1054abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_DEBUG, DRV_PREFIX
1055abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   "we didn't create the link, leave it alone");
1056abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return 0;
1057abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
1058abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1059abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	err = rtnl_link_delete(drv->sk, drv->link);
1060abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (err < 0)
1061abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't delete link");
1062abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	rtnl_link_put(drv->link);
1063abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->link = NULL;
1064abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1065abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return err;
1066abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
1067abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1068abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1069abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
1070abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_create_transmit_sa - Create secure association for transmit
1071abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: private driver interface data from init()
1072abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sa: secure association
1073abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure
1074abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
1075abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_create_transmit_sa(void *priv, struct transmit_sa *sa)
1076abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
1077abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
1078abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_genl_ctx *ctx = &drv->ctx;
1079abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nl_msg *msg;
1080abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nlattr *nest;
1081abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int ret = -1;
1082abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1083abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
1084abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1085abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	msg = msg_prepare(MACSEC_CMD_ADD_TXSA, ctx, drv->ifi);
1086abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!msg)
1087abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return ret;
1088abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1089abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
1090abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!nest)
1091abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto nla_put_failure;
1092abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1093abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
1094abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
1095abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT(msg, MACSEC_SA_ATTR_KEYID, sizeof(sa->pkey->key_identifier),
1096abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		&sa->pkey->key_identifier);
1097abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT(msg, MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
1098abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, sa->enable_transmit);
1099abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1100abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nla_nest_end(msg, nest);
1101abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1102abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ret = nl_send_recv(ctx->sk, msg);
1103abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (ret < 0) {
1104abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR,
1105abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   DRV_PREFIX "%s: failed to communicate: %d (%s)",
1106abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   __func__, ret, nl_geterror(-ret));
1107abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
1108abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1109abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtnla_put_failure:
1110abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nlmsg_free(msg);
1111abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return ret;
1112abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
1113abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1114abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1115abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
1116abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_delete_transmit_sa - Delete secure association for transmit
1117abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: private driver interface data from init()
1118abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sa: secure association
1119abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure
1120abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
1121abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_delete_transmit_sa(void *priv, struct transmit_sa *sa)
1122abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
1123abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
1124abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_genl_ctx *ctx = &drv->ctx;
1125abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nl_msg *msg;
1126abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nlattr *nest;
1127abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int ret = -1;
1128abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1129abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
1130abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1131abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	msg = msg_prepare(MACSEC_CMD_DEL_TXSA, ctx, drv->ifi);
1132abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!msg)
1133abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return ret;
1134abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1135abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
1136abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!nest)
1137abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto nla_put_failure;
1138abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1139abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
1140abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1141abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nla_nest_end(msg, nest);
1142abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1143abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ret = nl_send_recv(ctx->sk, msg);
1144abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (ret < 0) {
1145abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR,
1146abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   DRV_PREFIX "%s: failed to communicate: %d (%s)",
1147abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   __func__, ret, nl_geterror(-ret));
1148abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
1149abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1150abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtnla_put_failure:
1151abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nlmsg_free(msg);
1152abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return ret;
1153abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
1154abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1155abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1156abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int set_active_tx_sa(const struct macsec_genl_ctx *ctx, int ifindex,
1157abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			    unsigned char an, Boolean state)
1158abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
1159abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nl_msg *msg;
1160abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct nlattr *nest;
1161abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int ret = -1;
1162abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1163abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	msg = msg_prepare(MACSEC_CMD_UPD_TXSA, ctx, ifindex);
1164abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!msg)
1165abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return ret;
1166abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1167abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
1168abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (!nest)
1169abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		goto nla_put_failure;
1170abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1171abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, an);
1172abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, !!state);
1173abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1174abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nla_nest_end(msg, nest);
1175abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1176abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ret = nl_send_recv(ctx->sk, msg);
1177abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (ret < 0) {
1178abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR,
1179abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   DRV_PREFIX "%s: failed to communicate: %d (%s)",
1180abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt			   __func__, ret, nl_geterror(-ret));
1181abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
1182abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1183abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtnla_put_failure:
1184abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	nlmsg_free(msg);
1185abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return ret;
1186abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
1187abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1188abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1189abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
1190abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_enable_transmit_sa - Enable SA for transmit
1191abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: private driver interface data from init()
1192abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sa: secure association
1193abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure
1194abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
1195abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_enable_transmit_sa(void *priv, struct transmit_sa *sa)
1196abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
1197abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
1198abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_genl_ctx *ctx = &drv->ctx;
1199abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	int ret;
1200abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1201abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
1202abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1203abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	ret = set_active_tx_sa(ctx, drv->ifi, sa->an, TRUE);
1204abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	if (ret < 0) {
1205abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		wpa_printf(MSG_ERROR, DRV_PREFIX "failed to enable txsa");
1206abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt		return ret;
1207abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	}
1208abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1209abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->encoding_sa_set = TRUE;
1210abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	drv->encoding_sa = sa->an;
1211abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1212abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return try_commit(drv);
1213abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
1214abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1215abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1216abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt/**
1217abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * macsec_drv_disable_transmit_sa - Disable SA for transmit
1218abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @priv: private driver interface data from init()
1219abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * @sa: secure association
1220abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt * Returns: 0 on success, -1 on failure
1221abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt */
1222abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtstatic int macsec_drv_disable_transmit_sa(void *priv, struct transmit_sa *sa)
1223abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt{
1224abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_drv_data *drv = priv;
1225abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	struct macsec_genl_ctx *ctx = &drv->ctx;
1226abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1227abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
1228abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1229abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	return set_active_tx_sa(ctx, drv->ifi, sa->an, FALSE);
1230abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt}
1231abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1232abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1233abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidtconst struct wpa_driver_ops wpa_driver_macsec_linux_ops = {
1234abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.name = "macsec_linux",
1235abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.desc = "MACsec Ethernet driver for Linux",
1236abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.get_ssid = driver_wired_get_ssid,
1237abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.get_bssid = driver_wired_get_bssid,
1238abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.get_capa = driver_wired_get_capa,
1239abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.init = macsec_drv_wpa_init,
1240abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.deinit = macsec_drv_wpa_deinit,
1241abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt
1242abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.macsec_init = macsec_drv_macsec_init,
1243abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.macsec_deinit = macsec_drv_macsec_deinit,
1244abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.macsec_get_capability = macsec_drv_get_capability,
1245abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.enable_protect_frames = macsec_drv_enable_protect_frames,
1246abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.enable_encrypt = macsec_drv_enable_encrypt,
1247abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.set_replay_protect = macsec_drv_set_replay_protect,
1248abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.set_current_cipher_suite = macsec_drv_set_current_cipher_suite,
1249abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.enable_controlled_port = macsec_drv_enable_controlled_port,
1250abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.get_receive_lowest_pn = macsec_drv_get_receive_lowest_pn,
1251abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.get_transmit_next_pn = macsec_drv_get_transmit_next_pn,
1252abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.set_transmit_next_pn = macsec_drv_set_transmit_next_pn,
1253abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.create_receive_sc = macsec_drv_create_receive_sc,
1254abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.delete_receive_sc = macsec_drv_delete_receive_sc,
1255abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.create_receive_sa = macsec_drv_create_receive_sa,
1256abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.delete_receive_sa = macsec_drv_delete_receive_sa,
1257abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.enable_receive_sa = macsec_drv_enable_receive_sa,
1258abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.disable_receive_sa = macsec_drv_disable_receive_sa,
1259abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.create_transmit_sc = macsec_drv_create_transmit_sc,
1260abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.delete_transmit_sc = macsec_drv_delete_transmit_sc,
1261abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.create_transmit_sa = macsec_drv_create_transmit_sa,
1262abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.delete_transmit_sa = macsec_drv_delete_transmit_sa,
1263abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.enable_transmit_sa = macsec_drv_enable_transmit_sa,
1264abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt	.disable_transmit_sa = macsec_drv_disable_transmit_sa,
1265abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt};
1266