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