1341618Scy/* 2341618Scy * Driver interaction with Linux MACsec kernel module 3341618Scy * Copyright (c) 2016, Sabrina Dubroca <sd@queasysnail.net> and Red Hat, Inc. 4351611Scy * Copyright (c) 2019, The Linux Foundation 5341618Scy * 6341618Scy * This software may be distributed under the terms of the BSD license. 7341618Scy * See README for more details. 8341618Scy */ 9341618Scy 10341618Scy#include "includes.h" 11341618Scy#include <sys/ioctl.h> 12341618Scy#include <net/if.h> 13341618Scy#include <netpacket/packet.h> 14341618Scy#include <net/if_arp.h> 15341618Scy#include <net/if.h> 16341618Scy#include <netlink/netlink.h> 17341618Scy#include <netlink/genl/genl.h> 18341618Scy#include <netlink/genl/ctrl.h> 19341618Scy#include <netlink/route/link.h> 20341618Scy#include <netlink/route/link/macsec.h> 21341618Scy#include <linux/if_macsec.h> 22341618Scy#include <inttypes.h> 23341618Scy 24341618Scy#include "utils/common.h" 25341618Scy#include "utils/eloop.h" 26351611Scy#include "common/eapol_common.h" 27341618Scy#include "pae/ieee802_1x_kay.h" 28341618Scy#include "driver.h" 29341618Scy#include "driver_wired_common.h" 30341618Scy 31341618Scy#define DRV_PREFIX "macsec_linux: " 32341618Scy 33341618Scy#define UNUSED_SCI 0xffffffffffffffff 34341618Scy 35341618Scystruct cb_arg { 36341618Scy struct macsec_drv_data *drv; 37341618Scy u32 *pn; 38341618Scy int ifindex; 39341618Scy u8 txsa; 40341618Scy u8 rxsa; 41341618Scy u64 rxsci; 42341618Scy}; 43341618Scy 44341618Scystruct macsec_genl_ctx { 45341618Scy struct nl_sock *sk; 46341618Scy int macsec_genl_id; 47341618Scy struct cb_arg cb_arg; 48341618Scy}; 49341618Scy 50341618Scystruct macsec_drv_data { 51341618Scy struct driver_wired_common_data common; 52341618Scy struct rtnl_link *link; 53341618Scy struct nl_cache *link_cache; 54341618Scy struct nl_sock *sk; 55341618Scy struct macsec_genl_ctx ctx; 56341618Scy 57341618Scy struct netlink_data *netlink; 58341618Scy struct nl_handle *nl; 59341618Scy char ifname[IFNAMSIZ + 1]; 60341618Scy int ifi; 61341618Scy int parent_ifi; 62351611Scy int use_pae_group_addr; 63341618Scy 64341618Scy Boolean created_link; 65341618Scy 66341618Scy Boolean controlled_port_enabled; 67341618Scy Boolean controlled_port_enabled_set; 68341618Scy 69341618Scy Boolean protect_frames; 70341618Scy Boolean protect_frames_set; 71341618Scy 72341618Scy Boolean encrypt; 73341618Scy Boolean encrypt_set; 74341618Scy 75341618Scy Boolean replay_protect; 76341618Scy Boolean replay_protect_set; 77341618Scy 78341618Scy u32 replay_window; 79341618Scy 80341618Scy u8 encoding_sa; 81341618Scy Boolean encoding_sa_set; 82341618Scy}; 83341618Scy 84341618Scy 85341618Scystatic int dump_callback(struct nl_msg *msg, void *argp); 86341618Scy 87341618Scy 88341618Scystatic struct nl_msg * msg_prepare(enum macsec_nl_commands cmd, 89341618Scy const struct macsec_genl_ctx *ctx, 90341618Scy unsigned int ifindex) 91341618Scy{ 92341618Scy struct nl_msg *msg; 93341618Scy 94341618Scy msg = nlmsg_alloc(); 95341618Scy if (!msg) { 96341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc message"); 97341618Scy return NULL; 98341618Scy } 99341618Scy 100341618Scy if (!genlmsg_put(msg, 0, 0, ctx->macsec_genl_id, 0, 0, cmd, 0)) { 101341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "failed to put header"); 102341618Scy goto nla_put_failure; 103341618Scy } 104341618Scy 105341618Scy NLA_PUT_U32(msg, MACSEC_ATTR_IFINDEX, ifindex); 106341618Scy 107341618Scy return msg; 108341618Scy 109341618Scynla_put_failure: 110341618Scy nlmsg_free(msg); 111341618Scy return NULL; 112341618Scy} 113341618Scy 114341618Scy 115341618Scystatic int nla_put_rxsc_config(struct nl_msg *msg, u64 sci) 116341618Scy{ 117341618Scy struct nlattr *nest = nla_nest_start(msg, MACSEC_ATTR_RXSC_CONFIG); 118341618Scy 119341618Scy if (!nest) 120341618Scy return -1; 121341618Scy 122341618Scy NLA_PUT_U64(msg, MACSEC_RXSC_ATTR_SCI, sci); 123341618Scy 124341618Scy nla_nest_end(msg, nest); 125341618Scy 126341618Scy return 0; 127341618Scy 128341618Scynla_put_failure: 129341618Scy return -1; 130341618Scy} 131341618Scy 132341618Scy 133341618Scystatic int init_genl_ctx(struct macsec_drv_data *drv) 134341618Scy{ 135341618Scy struct macsec_genl_ctx *ctx = &drv->ctx; 136341618Scy 137341618Scy ctx->sk = nl_socket_alloc(); 138341618Scy if (!ctx->sk) { 139341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc genl socket"); 140341618Scy return -1; 141341618Scy } 142341618Scy 143341618Scy if (genl_connect(ctx->sk) < 0) { 144341618Scy wpa_printf(MSG_ERROR, 145341618Scy DRV_PREFIX "connection to genl socket failed"); 146341618Scy goto out_free; 147341618Scy } 148341618Scy 149341618Scy ctx->macsec_genl_id = genl_ctrl_resolve(ctx->sk, "macsec"); 150341618Scy if (ctx->macsec_genl_id < 0) { 151341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "genl resolve failed"); 152341618Scy goto out_free; 153341618Scy } 154341618Scy 155341618Scy memset(&ctx->cb_arg, 0, sizeof(ctx->cb_arg)); 156341618Scy ctx->cb_arg.drv = drv; 157341618Scy 158341618Scy nl_socket_modify_cb(ctx->sk, NL_CB_VALID, NL_CB_CUSTOM, dump_callback, 159341618Scy &ctx->cb_arg); 160341618Scy 161341618Scy return 0; 162341618Scy 163341618Scyout_free: 164341618Scy nl_socket_free(ctx->sk); 165341618Scy ctx->sk = NULL; 166341618Scy return -1; 167341618Scy} 168341618Scy 169341618Scy 170341618Scystatic int try_commit(struct macsec_drv_data *drv) 171341618Scy{ 172341618Scy int err; 173341618Scy 174341618Scy if (!drv->sk) 175341618Scy return 0; 176341618Scy 177341618Scy if (!drv->link) 178341618Scy return 0; 179341618Scy 180341618Scy if (drv->controlled_port_enabled_set) { 181341618Scy struct rtnl_link *change = rtnl_link_alloc(); 182341618Scy 183346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX 184346981Scy "%s: try_commit controlled_port_enabled=%d", 185346981Scy drv->ifname, drv->controlled_port_enabled); 186341618Scy if (!change) 187341618Scy return -1; 188341618Scy 189341618Scy rtnl_link_set_name(change, drv->ifname); 190341618Scy 191341618Scy if (drv->controlled_port_enabled) 192341618Scy rtnl_link_set_flags(change, IFF_UP); 193341618Scy else 194341618Scy rtnl_link_unset_flags(change, IFF_UP); 195341618Scy 196341618Scy err = rtnl_link_change(drv->sk, change, change, 0); 197341618Scy if (err < 0) 198341618Scy return err; 199341618Scy 200341618Scy rtnl_link_put(change); 201341618Scy 202341618Scy drv->controlled_port_enabled_set = FALSE; 203341618Scy } 204341618Scy 205346981Scy if (drv->protect_frames_set) { 206346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX 207346981Scy "%s: try_commit protect_frames=%d", 208346981Scy drv->ifname, drv->protect_frames); 209341618Scy rtnl_link_macsec_set_protect(drv->link, drv->protect_frames); 210346981Scy } 211341618Scy 212346981Scy if (drv->encrypt_set) { 213346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: try_commit encrypt=%d", 214346981Scy drv->ifname, drv->encrypt); 215341618Scy rtnl_link_macsec_set_encrypt(drv->link, drv->encrypt); 216346981Scy } 217341618Scy 218341618Scy if (drv->replay_protect_set) { 219346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX 220346981Scy "%s: try_commit replay_protect=%d replay_window=%d", 221346981Scy drv->ifname, drv->replay_protect, 222346981Scy drv->replay_window); 223341618Scy rtnl_link_macsec_set_replay_protect(drv->link, 224341618Scy drv->replay_protect); 225341618Scy if (drv->replay_protect) 226341618Scy rtnl_link_macsec_set_window(drv->link, 227341618Scy drv->replay_window); 228341618Scy } 229341618Scy 230346981Scy if (drv->encoding_sa_set) { 231346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX 232346981Scy "%s: try_commit encoding_sa=%d", 233346981Scy drv->ifname, drv->encoding_sa); 234341618Scy rtnl_link_macsec_set_encoding_sa(drv->link, drv->encoding_sa); 235346981Scy } 236341618Scy 237341618Scy err = rtnl_link_add(drv->sk, drv->link, 0); 238341618Scy if (err < 0) 239341618Scy return err; 240341618Scy 241341618Scy drv->protect_frames_set = FALSE; 242341618Scy drv->encrypt_set = FALSE; 243341618Scy drv->replay_protect_set = FALSE; 244341618Scy 245341618Scy return 0; 246341618Scy} 247341618Scy 248341618Scy 249341618Scystatic void macsec_drv_wpa_deinit(void *priv) 250341618Scy{ 251341618Scy struct macsec_drv_data *drv = priv; 252341618Scy 253341618Scy driver_wired_deinit_common(&drv->common); 254341618Scy os_free(drv); 255341618Scy} 256341618Scy 257341618Scy 258341618Scystatic int macsec_check_macsec(void) 259341618Scy{ 260341618Scy struct nl_sock *sk; 261341618Scy int err = -1; 262341618Scy 263341618Scy sk = nl_socket_alloc(); 264341618Scy if (!sk) { 265341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc genl socket"); 266341618Scy return -1; 267341618Scy } 268341618Scy 269341618Scy if (genl_connect(sk) < 0) { 270341618Scy wpa_printf(MSG_ERROR, 271341618Scy DRV_PREFIX "connection to genl socket failed"); 272341618Scy goto out_free; 273341618Scy } 274341618Scy 275341618Scy if (genl_ctrl_resolve(sk, "macsec") < 0) { 276341618Scy wpa_printf(MSG_ERROR, 277341618Scy DRV_PREFIX "genl resolve failed - macsec kernel module not present?"); 278341618Scy goto out_free; 279341618Scy } 280341618Scy 281341618Scy err = 0; 282341618Scy 283341618Scyout_free: 284341618Scy nl_socket_free(sk); 285341618Scy return err; 286341618Scy} 287341618Scy 288341618Scy 289341618Scystatic void * macsec_drv_wpa_init(void *ctx, const char *ifname) 290341618Scy{ 291341618Scy struct macsec_drv_data *drv; 292341618Scy 293341618Scy if (macsec_check_macsec() < 0) 294341618Scy return NULL; 295341618Scy 296341618Scy drv = os_zalloc(sizeof(*drv)); 297341618Scy if (!drv) 298341618Scy return NULL; 299341618Scy 300341618Scy if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) { 301341618Scy os_free(drv); 302341618Scy return NULL; 303341618Scy } 304341618Scy 305341618Scy return drv; 306341618Scy} 307341618Scy 308341618Scy 309341618Scystatic int macsec_drv_macsec_init(void *priv, struct macsec_init_params *params) 310341618Scy{ 311341618Scy struct macsec_drv_data *drv = priv; 312341618Scy int err; 313341618Scy 314341618Scy wpa_printf(MSG_DEBUG, "%s", __func__); 315341618Scy 316341618Scy drv->sk = nl_socket_alloc(); 317341618Scy if (!drv->sk) 318341618Scy return -1; 319341618Scy 320341618Scy err = nl_connect(drv->sk, NETLINK_ROUTE); 321341618Scy if (err < 0) { 322341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX 323341618Scy "Unable to connect NETLINK_ROUTE socket: %s", 324341618Scy strerror(errno)); 325341618Scy goto sock; 326341618Scy } 327341618Scy 328341618Scy err = rtnl_link_alloc_cache(drv->sk, AF_UNSPEC, &drv->link_cache); 329341618Scy if (err < 0) { 330341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "Unable to get link cache: %s", 331341618Scy strerror(errno)); 332341618Scy goto sock; 333341618Scy } 334341618Scy 335341618Scy drv->parent_ifi = rtnl_link_name2i(drv->link_cache, drv->common.ifname); 336341618Scy if (drv->parent_ifi == 0) { 337341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX 338341618Scy "couldn't find ifindex for interface %s", 339341618Scy drv->common.ifname); 340341618Scy goto cache; 341341618Scy } 342346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX "ifname=%s parent_ifi=%d", 343346981Scy drv->common.ifname, drv->parent_ifi); 344341618Scy 345341618Scy err = init_genl_ctx(drv); 346341618Scy if (err < 0) 347341618Scy goto cache; 348341618Scy 349341618Scy return 0; 350341618Scy 351341618Scycache: 352341618Scy nl_cache_free(drv->link_cache); 353341618Scy drv->link_cache = NULL; 354341618Scysock: 355341618Scy nl_socket_free(drv->sk); 356341618Scy drv->sk = NULL; 357341618Scy return -1; 358341618Scy} 359341618Scy 360341618Scy 361341618Scystatic int macsec_drv_macsec_deinit(void *priv) 362341618Scy{ 363341618Scy struct macsec_drv_data *drv = priv; 364341618Scy 365341618Scy wpa_printf(MSG_DEBUG, "%s", __func__); 366341618Scy 367341618Scy if (drv->sk) 368341618Scy nl_socket_free(drv->sk); 369341618Scy drv->sk = NULL; 370341618Scy 371341618Scy if (drv->link_cache) 372341618Scy nl_cache_free(drv->link_cache); 373341618Scy drv->link_cache = NULL; 374341618Scy 375341618Scy if (drv->ctx.sk) 376341618Scy nl_socket_free(drv->ctx.sk); 377341618Scy 378341618Scy return 0; 379341618Scy} 380341618Scy 381341618Scy 382341618Scystatic int macsec_drv_get_capability(void *priv, enum macsec_cap *cap) 383341618Scy{ 384341618Scy wpa_printf(MSG_DEBUG, "%s", __func__); 385341618Scy 386341618Scy *cap = MACSEC_CAP_INTEG_AND_CONF; 387341618Scy 388341618Scy return 0; 389341618Scy} 390341618Scy 391341618Scy 392341618Scy/** 393341618Scy * macsec_drv_enable_protect_frames - Set protect frames status 394341618Scy * @priv: Private driver interface data 395341618Scy * @enabled: TRUE = protect frames enabled 396341618Scy * FALSE = protect frames disabled 397341618Scy * Returns: 0 on success, -1 on failure (or if not supported) 398341618Scy */ 399341618Scystatic int macsec_drv_enable_protect_frames(void *priv, Boolean enabled) 400341618Scy{ 401341618Scy struct macsec_drv_data *drv = priv; 402341618Scy 403341618Scy wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE"); 404341618Scy 405341618Scy drv->protect_frames_set = TRUE; 406341618Scy drv->protect_frames = enabled; 407341618Scy 408341618Scy return try_commit(drv); 409341618Scy} 410341618Scy 411341618Scy 412341618Scy/** 413341618Scy * macsec_drv_enable_encrypt - Set protect frames status 414341618Scy * @priv: Private driver interface data 415341618Scy * @enabled: TRUE = protect frames enabled 416341618Scy * FALSE = protect frames disabled 417341618Scy * Returns: 0 on success, -1 on failure (or if not supported) 418341618Scy */ 419341618Scystatic int macsec_drv_enable_encrypt(void *priv, Boolean enabled) 420341618Scy{ 421341618Scy struct macsec_drv_data *drv = priv; 422341618Scy 423341618Scy wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE"); 424341618Scy 425341618Scy drv->encrypt_set = TRUE; 426341618Scy drv->encrypt = enabled; 427341618Scy 428341618Scy return try_commit(drv); 429341618Scy} 430341618Scy 431341618Scy 432341618Scy/** 433341618Scy * macsec_drv_set_replay_protect - Set replay protect status and window size 434341618Scy * @priv: Private driver interface data 435341618Scy * @enabled: TRUE = replay protect enabled 436341618Scy * FALSE = replay protect disabled 437341618Scy * @window: replay window size, valid only when replay protect enabled 438341618Scy * Returns: 0 on success, -1 on failure (or if not supported) 439341618Scy */ 440341618Scystatic int macsec_drv_set_replay_protect(void *priv, Boolean enabled, 441341618Scy u32 window) 442341618Scy{ 443341618Scy struct macsec_drv_data *drv = priv; 444341618Scy 445341618Scy wpa_printf(MSG_DEBUG, "%s -> %s, %u", __func__, 446341618Scy enabled ? "TRUE" : "FALSE", window); 447341618Scy 448341618Scy drv->replay_protect_set = TRUE; 449341618Scy drv->replay_protect = enabled; 450341618Scy if (enabled) 451341618Scy drv->replay_window = window; 452341618Scy 453341618Scy return try_commit(drv); 454341618Scy} 455341618Scy 456341618Scy 457341618Scy/** 458341618Scy * macsec_drv_set_current_cipher_suite - Set current cipher suite 459341618Scy * @priv: Private driver interface data 460341618Scy * @cs: EUI64 identifier 461341618Scy * Returns: 0 on success, -1 on failure (or if not supported) 462341618Scy */ 463341618Scystatic int macsec_drv_set_current_cipher_suite(void *priv, u64 cs) 464341618Scy{ 465341618Scy wpa_printf(MSG_DEBUG, "%s -> %016" PRIx64, __func__, cs); 466341618Scy return 0; 467341618Scy} 468341618Scy 469341618Scy 470341618Scy/** 471341618Scy * macsec_drv_enable_controlled_port - Set controlled port status 472341618Scy * @priv: Private driver interface data 473341618Scy * @enabled: TRUE = controlled port enabled 474341618Scy * FALSE = controlled port disabled 475341618Scy * Returns: 0 on success, -1 on failure (or if not supported) 476341618Scy */ 477341618Scystatic int macsec_drv_enable_controlled_port(void *priv, Boolean enabled) 478341618Scy{ 479341618Scy struct macsec_drv_data *drv = priv; 480341618Scy 481341618Scy wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE"); 482341618Scy 483341618Scy drv->controlled_port_enabled = enabled; 484341618Scy drv->controlled_port_enabled_set = TRUE; 485341618Scy 486341618Scy return try_commit(drv); 487341618Scy} 488341618Scy 489341618Scy 490341618Scystatic struct nla_policy sa_policy[MACSEC_SA_ATTR_MAX + 1] = { 491341618Scy [MACSEC_SA_ATTR_AN] = { .type = NLA_U8 }, 492341618Scy [MACSEC_SA_ATTR_ACTIVE] = { .type = NLA_U8 }, 493341618Scy [MACSEC_SA_ATTR_PN] = { .type = NLA_U32 }, 494341618Scy [MACSEC_SA_ATTR_KEYID] = { .type = NLA_BINARY }, 495341618Scy}; 496341618Scy 497341618Scystatic struct nla_policy sc_policy[MACSEC_RXSC_ATTR_MAX + 1] = { 498341618Scy [MACSEC_RXSC_ATTR_SCI] = { .type = NLA_U64 }, 499341618Scy [MACSEC_RXSC_ATTR_ACTIVE] = { .type = NLA_U8 }, 500341618Scy [MACSEC_RXSC_ATTR_SA_LIST] = { .type = NLA_NESTED }, 501341618Scy}; 502341618Scy 503341618Scystatic struct nla_policy main_policy[MACSEC_ATTR_MAX + 1] = { 504341618Scy [MACSEC_ATTR_IFINDEX] = { .type = NLA_U32 }, 505341618Scy [MACSEC_ATTR_SECY] = { .type = NLA_NESTED }, 506341618Scy [MACSEC_ATTR_TXSA_LIST] = { .type = NLA_NESTED }, 507341618Scy [MACSEC_ATTR_RXSC_LIST] = { .type = NLA_NESTED }, 508341618Scy}; 509341618Scy 510341618Scystatic int dump_callback(struct nl_msg *msg, void *argp) 511341618Scy{ 512341618Scy struct nlmsghdr *ret_hdr = nlmsg_hdr(msg); 513341618Scy struct nlattr *tb_msg[MACSEC_ATTR_MAX + 1]; 514341618Scy struct cb_arg *arg = (struct cb_arg *) argp; 515341618Scy struct genlmsghdr *gnlh = (struct genlmsghdr *) nlmsg_data(ret_hdr); 516341618Scy int err; 517341618Scy 518341618Scy if (ret_hdr->nlmsg_type != arg->drv->ctx.macsec_genl_id) 519341618Scy return 0; 520341618Scy 521341618Scy err = nla_parse(tb_msg, MACSEC_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 522341618Scy genlmsg_attrlen(gnlh, 0), main_policy); 523341618Scy if (err < 0) 524341618Scy return 0; 525341618Scy 526341618Scy if (!tb_msg[MACSEC_ATTR_IFINDEX]) 527341618Scy return 0; 528341618Scy 529341618Scy if (nla_get_u32(tb_msg[MACSEC_ATTR_IFINDEX]) != (u32) arg->ifindex) 530341618Scy return 0; 531341618Scy 532341618Scy if (arg->txsa < 4 && !tb_msg[MACSEC_ATTR_TXSA_LIST]) { 533341618Scy return 0; 534341618Scy } else if (arg->txsa < 4) { 535341618Scy struct nlattr *nla; 536341618Scy int rem; 537341618Scy 538341618Scy nla_for_each_nested(nla, tb_msg[MACSEC_ATTR_TXSA_LIST], rem) { 539341618Scy struct nlattr *tb[MACSEC_SA_ATTR_MAX + 1]; 540341618Scy 541341618Scy err = nla_parse_nested(tb, MACSEC_SA_ATTR_MAX, nla, 542341618Scy sa_policy); 543341618Scy if (err < 0) 544341618Scy continue; 545341618Scy if (!tb[MACSEC_SA_ATTR_AN]) 546341618Scy continue; 547341618Scy if (nla_get_u8(tb[MACSEC_SA_ATTR_AN]) != arg->txsa) 548341618Scy continue; 549341618Scy if (!tb[MACSEC_SA_ATTR_PN]) 550341618Scy return 0; 551341618Scy *arg->pn = nla_get_u32(tb[MACSEC_SA_ATTR_PN]); 552341618Scy return 0; 553341618Scy } 554341618Scy 555341618Scy return 0; 556341618Scy } 557341618Scy 558341618Scy if (arg->rxsci == UNUSED_SCI) 559341618Scy return 0; 560341618Scy 561341618Scy if (tb_msg[MACSEC_ATTR_RXSC_LIST]) { 562341618Scy struct nlattr *nla; 563341618Scy int rem; 564341618Scy 565341618Scy nla_for_each_nested(nla, tb_msg[MACSEC_ATTR_RXSC_LIST], rem) { 566341618Scy struct nlattr *tb[MACSEC_RXSC_ATTR_MAX + 1]; 567341618Scy 568341618Scy err = nla_parse_nested(tb, MACSEC_RXSC_ATTR_MAX, nla, 569341618Scy sc_policy); 570341618Scy if (err < 0) 571341618Scy return 0; 572341618Scy if (!tb[MACSEC_RXSC_ATTR_SCI]) 573341618Scy continue; 574341618Scy if (nla_get_u64(tb[MACSEC_RXSC_ATTR_SCI]) != arg->rxsci) 575341618Scy continue; 576341618Scy if (!tb[MACSEC_RXSC_ATTR_SA_LIST]) 577341618Scy return 0; 578341618Scy 579341618Scy nla_for_each_nested(nla, tb[MACSEC_RXSC_ATTR_SA_LIST], 580341618Scy rem) { 581341618Scy struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1]; 582341618Scy 583341618Scy err = nla_parse_nested(tb_sa, 584341618Scy MACSEC_SA_ATTR_MAX, nla, 585341618Scy sa_policy); 586341618Scy if (err < 0) 587341618Scy continue; 588341618Scy if (!tb_sa[MACSEC_SA_ATTR_AN]) 589341618Scy continue; 590341618Scy if (nla_get_u8(tb_sa[MACSEC_SA_ATTR_AN]) != 591341618Scy arg->rxsa) 592341618Scy continue; 593341618Scy if (!tb_sa[MACSEC_SA_ATTR_PN]) 594341618Scy return 0; 595341618Scy *arg->pn = 596341618Scy nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]); 597341618Scy 598341618Scy return 0; 599341618Scy } 600341618Scy 601341618Scy return 0; 602341618Scy } 603341618Scy 604341618Scy return 0; 605341618Scy } 606341618Scy 607341618Scy return 0; 608341618Scy} 609341618Scy 610341618Scy 611341618Scystatic int nl_send_recv(struct nl_sock *sk, struct nl_msg *msg) 612341618Scy{ 613341618Scy int ret; 614341618Scy 615341618Scy ret = nl_send_auto_complete(sk, msg); 616341618Scy if (ret < 0) { 617341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to send: %d (%s)", 618341618Scy __func__, ret, nl_geterror(-ret)); 619341618Scy return ret; 620341618Scy } 621341618Scy 622341618Scy ret = nl_recvmsgs_default(sk); 623341618Scy if (ret < 0) { 624341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to recv: %d (%s)", 625341618Scy __func__, ret, nl_geterror(-ret)); 626341618Scy } 627341618Scy 628341618Scy return ret; 629341618Scy} 630341618Scy 631341618Scy 632341618Scystatic int do_dump(struct macsec_drv_data *drv, u8 txsa, u64 rxsci, u8 rxsa, 633341618Scy u32 *pn) 634341618Scy{ 635341618Scy struct macsec_genl_ctx *ctx = &drv->ctx; 636341618Scy struct nl_msg *msg; 637341618Scy int ret = 1; 638341618Scy 639341618Scy ctx->cb_arg.ifindex = drv->ifi; 640341618Scy ctx->cb_arg.rxsci = rxsci; 641341618Scy ctx->cb_arg.rxsa = rxsa; 642341618Scy ctx->cb_arg.txsa = txsa; 643341618Scy ctx->cb_arg.pn = pn; 644341618Scy 645341618Scy msg = nlmsg_alloc(); 646341618Scy if (!msg) { 647341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to alloc message", 648341618Scy __func__); 649341618Scy return 1; 650341618Scy } 651341618Scy 652341618Scy if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ctx->macsec_genl_id, 0, 653341618Scy NLM_F_DUMP, MACSEC_CMD_GET_TXSC, 0)) { 654341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to put header", 655341618Scy __func__); 656341618Scy goto out_free_msg; 657341618Scy } 658341618Scy 659341618Scy ret = nl_send_recv(ctx->sk, msg); 660341618Scy if (ret < 0) 661341618Scy wpa_printf(MSG_ERROR, 662341618Scy DRV_PREFIX "failed to communicate: %d (%s)", 663341618Scy ret, nl_geterror(-ret)); 664341618Scy 665341618Scy ctx->cb_arg.pn = NULL; 666341618Scy 667341618Scyout_free_msg: 668341618Scy nlmsg_free(msg); 669341618Scy return ret; 670341618Scy} 671341618Scy 672341618Scy 673341618Scy/** 674341618Scy * macsec_drv_get_receive_lowest_pn - Get receive lowest PN 675341618Scy * @priv: Private driver interface data 676341618Scy * @sa: secure association 677341618Scy * Returns: 0 on success, -1 on failure (or if not supported) 678341618Scy */ 679341618Scystatic int macsec_drv_get_receive_lowest_pn(void *priv, struct receive_sa *sa) 680341618Scy{ 681341618Scy struct macsec_drv_data *drv = priv; 682341618Scy int err; 683341618Scy 684341618Scy wpa_printf(MSG_DEBUG, DRV_PREFIX "%s", __func__); 685341618Scy 686341618Scy err = do_dump(drv, 0xff, mka_sci_u64(&sa->sc->sci), sa->an, 687341618Scy &sa->lowest_pn); 688341618Scy wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: result %d", __func__, 689341618Scy sa->lowest_pn); 690341618Scy 691341618Scy return err; 692341618Scy} 693341618Scy 694341618Scy 695341618Scy/** 696346981Scy * macsec_drv_set_receive_lowest_pn - Set receive lowest PN 697346981Scy * @priv: Private driver interface data 698346981Scy * @sa: secure association 699346981Scy * Returns: 0 on success, -1 on failure (or if not supported) 700346981Scy */ 701346981Scystatic int macsec_drv_set_receive_lowest_pn(void *priv, struct receive_sa *sa) 702346981Scy{ 703346981Scy struct macsec_drv_data *drv = priv; 704346981Scy struct macsec_genl_ctx *ctx = &drv->ctx; 705346981Scy struct nl_msg *msg; 706346981Scy struct nlattr *nest; 707346981Scy int ret = -1; 708346981Scy 709346981Scy wpa_printf(MSG_DEBUG, 710346981Scy DRV_PREFIX "%s: set_receive_lowest_pn -> %d: %d", 711346981Scy drv->ifname, sa->an, sa->next_pn); 712346981Scy 713346981Scy msg = msg_prepare(MACSEC_CMD_UPD_RXSA, ctx, drv->ifi); 714346981Scy if (!msg) 715346981Scy return ret; 716346981Scy 717346981Scy nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG); 718346981Scy if (!nest) 719346981Scy goto nla_put_failure; 720346981Scy 721346981Scy NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an); 722346981Scy NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn); 723346981Scy 724346981Scy nla_nest_end(msg, nest); 725346981Scy 726346981Scy ret = nl_send_recv(ctx->sk, msg); 727346981Scy if (ret < 0) { 728346981Scy wpa_printf(MSG_ERROR, 729346981Scy DRV_PREFIX "failed to communicate: %d (%s)", 730346981Scy ret, nl_geterror(-ret)); 731346981Scy } 732346981Scy 733346981Scynla_put_failure: 734346981Scy nlmsg_free(msg); 735346981Scy return ret; 736346981Scy} 737346981Scy 738346981Scy 739346981Scy/** 740341618Scy * macsec_drv_get_transmit_next_pn - Get transmit next PN 741341618Scy * @priv: Private driver interface data 742341618Scy * @sa: secure association 743341618Scy * Returns: 0 on success, -1 on failure (or if not supported) 744341618Scy */ 745341618Scystatic int macsec_drv_get_transmit_next_pn(void *priv, struct transmit_sa *sa) 746341618Scy{ 747341618Scy struct macsec_drv_data *drv = priv; 748341618Scy int err; 749341618Scy 750341618Scy wpa_printf(MSG_DEBUG, "%s", __func__); 751341618Scy 752341618Scy err = do_dump(drv, sa->an, UNUSED_SCI, 0xff, &sa->next_pn); 753341618Scy wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: err %d result %d", __func__, err, 754341618Scy sa->next_pn); 755341618Scy return err; 756341618Scy} 757341618Scy 758341618Scy 759341618Scy/** 760341618Scy * macsec_drv_set_transmit_next_pn - Set transmit next pn 761341618Scy * @priv: Private driver interface data 762341618Scy * @sa: secure association 763341618Scy * Returns: 0 on success, -1 on failure (or if not supported) 764341618Scy */ 765341618Scystatic int macsec_drv_set_transmit_next_pn(void *priv, struct transmit_sa *sa) 766341618Scy{ 767341618Scy struct macsec_drv_data *drv = priv; 768341618Scy struct macsec_genl_ctx *ctx = &drv->ctx; 769341618Scy struct nl_msg *msg; 770341618Scy struct nlattr *nest; 771341618Scy int ret = -1; 772341618Scy 773341618Scy wpa_printf(MSG_DEBUG, "%s -> %d: %d", __func__, sa->an, sa->next_pn); 774341618Scy 775341618Scy msg = msg_prepare(MACSEC_CMD_UPD_TXSA, ctx, drv->ifi); 776341618Scy if (!msg) 777341618Scy return ret; 778341618Scy 779341618Scy nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG); 780341618Scy if (!nest) 781341618Scy goto nla_put_failure; 782341618Scy 783341618Scy NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an); 784341618Scy NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn); 785341618Scy 786341618Scy nla_nest_end(msg, nest); 787341618Scy 788341618Scy ret = nl_send_recv(ctx->sk, msg); 789341618Scy if (ret < 0) { 790341618Scy wpa_printf(MSG_ERROR, 791341618Scy DRV_PREFIX "failed to communicate: %d (%s)", 792341618Scy ret, nl_geterror(-ret)); 793341618Scy } 794341618Scy 795341618Scynla_put_failure: 796341618Scy nlmsg_free(msg); 797341618Scy return ret; 798341618Scy} 799341618Scy 800341618Scy 801341618Scy#define SCISTR MACSTR "::%hx" 802341618Scy#define SCI2STR(addr, port) MAC2STR(addr), htons(port) 803341618Scy 804341618Scy/** 805341618Scy * macsec_drv_create_receive_sc - Create secure channel for receiving 806341618Scy * @priv: Private driver interface data 807341618Scy * @sc: secure channel 808341618Scy * @sci_addr: secure channel identifier - address 809341618Scy * @sci_port: secure channel identifier - port 810341618Scy * @conf_offset: confidentiality offset (0, 30, or 50) 811341618Scy * @validation: frame validation policy (0 = Disabled, 1 = Checked, 812341618Scy * 2 = Strict) 813341618Scy * Returns: 0 on success, -1 on failure (or if not supported) 814341618Scy */ 815341618Scystatic int macsec_drv_create_receive_sc(void *priv, struct receive_sc *sc, 816341618Scy unsigned int conf_offset, 817341618Scy int validation) 818341618Scy{ 819341618Scy struct macsec_drv_data *drv = priv; 820341618Scy struct macsec_genl_ctx *ctx = &drv->ctx; 821341618Scy struct nl_msg *msg; 822341618Scy int ret = -1; 823341618Scy 824346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: create_receive_sc -> " SCISTR 825346981Scy " (conf_offset=%u validation=%d)", 826346981Scy drv->ifname, SCI2STR(sc->sci.addr, sc->sci.port), 827346981Scy conf_offset, validation); 828341618Scy 829341618Scy msg = msg_prepare(MACSEC_CMD_ADD_RXSC, ctx, drv->ifi); 830341618Scy if (!msg) 831341618Scy return ret; 832341618Scy 833341618Scy if (nla_put_rxsc_config(msg, mka_sci_u64(&sc->sci))) 834341618Scy goto nla_put_failure; 835341618Scy 836341618Scy ret = nl_send_recv(ctx->sk, msg); 837341618Scy if (ret < 0) { 838341618Scy wpa_printf(MSG_ERROR, 839341618Scy DRV_PREFIX "%s: failed to communicate: %d (%s)", 840341618Scy __func__, ret, nl_geterror(-ret)); 841341618Scy } 842341618Scy 843341618Scynla_put_failure: 844341618Scy nlmsg_free(msg); 845341618Scy return ret; 846341618Scy} 847341618Scy 848341618Scy 849341618Scy/** 850341618Scy * macsec_drv_delete_receive_sc - Delete secure connection for receiving 851341618Scy * @priv: private driver interface data from init() 852341618Scy * @sc: secure channel 853341618Scy * Returns: 0 on success, -1 on failure 854341618Scy */ 855341618Scystatic int macsec_drv_delete_receive_sc(void *priv, struct receive_sc *sc) 856341618Scy{ 857341618Scy struct macsec_drv_data *drv = priv; 858341618Scy struct macsec_genl_ctx *ctx = &drv->ctx; 859341618Scy struct nl_msg *msg; 860341618Scy int ret = -1; 861341618Scy 862346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_receive_sc -> " SCISTR, 863346981Scy drv->ifname, SCI2STR(sc->sci.addr, sc->sci.port)); 864341618Scy 865341618Scy msg = msg_prepare(MACSEC_CMD_DEL_RXSC, ctx, drv->ifi); 866341618Scy if (!msg) 867341618Scy return ret; 868341618Scy 869341618Scy if (nla_put_rxsc_config(msg, mka_sci_u64(&sc->sci))) 870341618Scy goto nla_put_failure; 871341618Scy 872341618Scy ret = nl_send_recv(ctx->sk, msg); 873341618Scy if (ret < 0) { 874341618Scy wpa_printf(MSG_ERROR, 875341618Scy DRV_PREFIX "%s: failed to communicate: %d (%s)", 876341618Scy __func__, ret, nl_geterror(-ret)); 877341618Scy } 878341618Scy 879341618Scynla_put_failure: 880341618Scy nlmsg_free(msg); 881341618Scy return ret; 882341618Scy} 883341618Scy 884341618Scy 885341618Scy/** 886341618Scy * macsec_drv_create_receive_sa - Create secure association for receive 887341618Scy * @priv: private driver interface data from init() 888341618Scy * @sa: secure association 889341618Scy * Returns: 0 on success, -1 on failure 890341618Scy */ 891341618Scystatic int macsec_drv_create_receive_sa(void *priv, struct receive_sa *sa) 892341618Scy{ 893341618Scy struct macsec_drv_data *drv = priv; 894341618Scy struct macsec_genl_ctx *ctx = &drv->ctx; 895341618Scy struct nl_msg *msg; 896341618Scy struct nlattr *nest; 897341618Scy int ret = -1; 898341618Scy 899346981Scy wpa_printf(MSG_DEBUG, 900346981Scy DRV_PREFIX "%s: create_receive_sa -> %d on " SCISTR 901346981Scy " (enable_receive=%d next_pn=%u)", 902346981Scy drv->ifname, sa->an, 903346981Scy SCI2STR(sa->sc->sci.addr, sa->sc->sci.port), 904346981Scy sa->enable_receive, sa->next_pn); 905346981Scy wpa_hexdump(MSG_DEBUG, DRV_PREFIX "SA keyid", 906346981Scy &sa->pkey->key_identifier, 907346981Scy sizeof(sa->pkey->key_identifier)); 908346981Scy wpa_hexdump_key(MSG_DEBUG, DRV_PREFIX "SA key", 909346981Scy sa->pkey->key, sa->pkey->key_len); 910341618Scy 911341618Scy msg = msg_prepare(MACSEC_CMD_ADD_RXSA, ctx, drv->ifi); 912341618Scy if (!msg) 913341618Scy return ret; 914341618Scy 915341618Scy if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci))) 916341618Scy goto nla_put_failure; 917341618Scy 918341618Scy nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG); 919341618Scy if (!nest) 920341618Scy goto nla_put_failure; 921341618Scy 922341618Scy NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an); 923341618Scy NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, sa->enable_receive); 924341618Scy NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn); 925341618Scy NLA_PUT(msg, MACSEC_SA_ATTR_KEYID, sizeof(sa->pkey->key_identifier), 926341618Scy &sa->pkey->key_identifier); 927341618Scy NLA_PUT(msg, MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key); 928341618Scy 929341618Scy nla_nest_end(msg, nest); 930341618Scy 931341618Scy ret = nl_send_recv(ctx->sk, msg); 932341618Scy if (ret < 0) { 933341618Scy wpa_printf(MSG_ERROR, 934341618Scy DRV_PREFIX "%s: failed to communicate: %d (%s)", 935341618Scy __func__, ret, nl_geterror(-ret)); 936341618Scy } 937341618Scy 938341618Scynla_put_failure: 939341618Scy nlmsg_free(msg); 940341618Scy return ret; 941341618Scy} 942341618Scy 943341618Scy 944341618Scy/** 945341618Scy * macsec_drv_delete_receive_sa - Delete secure association for receive 946341618Scy * @priv: private driver interface data from init() 947341618Scy * @sa: secure association 948341618Scy * Returns: 0 on success, -1 on failure 949341618Scy */ 950341618Scystatic int macsec_drv_delete_receive_sa(void *priv, struct receive_sa *sa) 951341618Scy{ 952341618Scy struct macsec_drv_data *drv = priv; 953341618Scy struct macsec_genl_ctx *ctx = &drv->ctx; 954341618Scy struct nl_msg *msg; 955341618Scy struct nlattr *nest; 956341618Scy int ret = -1; 957341618Scy 958346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_receive_sa -> %d on " 959346981Scy SCISTR, drv->ifname, sa->an, 960341618Scy SCI2STR(sa->sc->sci.addr, sa->sc->sci.port)); 961341618Scy 962341618Scy msg = msg_prepare(MACSEC_CMD_DEL_RXSA, ctx, drv->ifi); 963341618Scy if (!msg) 964341618Scy return ret; 965341618Scy 966341618Scy if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci))) 967341618Scy goto nla_put_failure; 968341618Scy 969341618Scy nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG); 970341618Scy if (!nest) 971341618Scy goto nla_put_failure; 972341618Scy 973341618Scy NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an); 974341618Scy 975341618Scy nla_nest_end(msg, nest); 976341618Scy 977341618Scy ret = nl_send_recv(ctx->sk, msg); 978341618Scy if (ret < 0) { 979341618Scy wpa_printf(MSG_ERROR, 980341618Scy DRV_PREFIX "%s: failed to communicate: %d (%s)", 981341618Scy __func__, ret, nl_geterror(-ret)); 982341618Scy } 983341618Scy 984341618Scynla_put_failure: 985341618Scy nlmsg_free(msg); 986341618Scy return ret; 987341618Scy} 988341618Scy 989341618Scy 990341618Scystatic int set_active_rx_sa(const struct macsec_genl_ctx *ctx, int ifindex, 991341618Scy u64 sci, unsigned char an, Boolean state) 992341618Scy{ 993341618Scy struct nl_msg *msg; 994341618Scy struct nlattr *nest; 995341618Scy int ret = -1; 996341618Scy 997341618Scy msg = msg_prepare(MACSEC_CMD_UPD_RXSA, ctx, ifindex); 998341618Scy if (!msg) 999341618Scy return ret; 1000341618Scy 1001341618Scy if (nla_put_rxsc_config(msg, sci)) 1002341618Scy goto nla_put_failure; 1003341618Scy 1004341618Scy nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG); 1005341618Scy if (!nest) 1006341618Scy goto nla_put_failure; 1007341618Scy 1008341618Scy NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, an); 1009341618Scy NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, !!state); 1010341618Scy 1011341618Scy nla_nest_end(msg, nest); 1012341618Scy 1013341618Scy ret = nl_send_recv(ctx->sk, msg); 1014341618Scy if (ret < 0) 1015341618Scy wpa_printf(MSG_ERROR, 1016341618Scy DRV_PREFIX "%s: failed to communicate: %d (%s)", 1017341618Scy __func__, ret, nl_geterror(-ret)); 1018341618Scy 1019341618Scynla_put_failure: 1020341618Scy nlmsg_free(msg); 1021341618Scy return ret; 1022341618Scy} 1023341618Scy 1024341618Scy 1025341618Scy/** 1026341618Scy * macsec_drv_enable_receive_sa - Enable the SA for receive 1027341618Scy * @priv: private driver interface data from init() 1028341618Scy * @sa: secure association 1029341618Scy * Returns: 0 on success, -1 on failure 1030341618Scy */ 1031341618Scystatic int macsec_drv_enable_receive_sa(void *priv, struct receive_sa *sa) 1032341618Scy{ 1033341618Scy struct macsec_drv_data *drv = priv; 1034341618Scy struct macsec_genl_ctx *ctx = &drv->ctx; 1035341618Scy 1036346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: enable_receive_sa -> %d on " 1037346981Scy SCISTR, drv->ifname, sa->an, 1038341618Scy SCI2STR(sa->sc->sci.addr, sa->sc->sci.port)); 1039341618Scy 1040341618Scy return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci), 1041341618Scy sa->an, TRUE); 1042341618Scy} 1043341618Scy 1044341618Scy 1045341618Scy/** 1046341618Scy * macsec_drv_disable_receive_sa - Disable SA for receive 1047341618Scy * @priv: private driver interface data from init() 1048341618Scy * @sa: secure association 1049341618Scy * Returns: 0 on success, -1 on failure 1050341618Scy */ 1051341618Scystatic int macsec_drv_disable_receive_sa(void *priv, struct receive_sa *sa) 1052341618Scy{ 1053341618Scy struct macsec_drv_data *drv = priv; 1054341618Scy struct macsec_genl_ctx *ctx = &drv->ctx; 1055341618Scy 1056346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: disable_receive_sa -> %d on " 1057346981Scy SCISTR, drv->ifname, sa->an, 1058341618Scy SCI2STR(sa->sc->sci.addr, sa->sc->sci.port)); 1059341618Scy 1060341618Scy return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci), 1061341618Scy sa->an, FALSE); 1062341618Scy} 1063341618Scy 1064341618Scy 1065341618Scystatic struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci) 1066341618Scy{ 1067341618Scy struct rtnl_link *needle; 1068341618Scy void *match; 1069341618Scy 1070341618Scy needle = rtnl_link_macsec_alloc(); 1071341618Scy if (!needle) 1072341618Scy return NULL; 1073341618Scy 1074341618Scy rtnl_link_set_link(needle, parent); 1075341618Scy rtnl_link_macsec_set_sci(needle, sci); 1076341618Scy 1077341618Scy match = nl_cache_find(cache, (struct nl_object *) needle); 1078341618Scy rtnl_link_put(needle); 1079341618Scy 1080341618Scy return (struct rtnl_link *) match; 1081341618Scy} 1082341618Scy 1083341618Scy 1084341618Scy/** 1085341618Scy * macsec_drv_create_transmit_sc - Create secure connection for transmit 1086341618Scy * @priv: private driver interface data from init() 1087341618Scy * @sc: secure channel 1088341618Scy * @conf_offset: confidentiality offset 1089341618Scy * Returns: 0 on success, -1 on failure 1090341618Scy */ 1091341618Scystatic int macsec_drv_create_transmit_sc( 1092341618Scy void *priv, struct transmit_sc *sc, 1093341618Scy unsigned int conf_offset) 1094341618Scy{ 1095341618Scy struct macsec_drv_data *drv = priv; 1096341618Scy struct rtnl_link *link; 1097341618Scy char *ifname; 1098341618Scy u64 sci; 1099341618Scy int err; 1100341618Scy 1101346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX 1102346981Scy "%s: create_transmit_sc -> " SCISTR " (conf_offset=%d)", 1103346981Scy drv->common.ifname, SCI2STR(sc->sci.addr, sc->sci.port), 1104346981Scy conf_offset); 1105341618Scy 1106341618Scy if (!drv->sk) { 1107341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "NULL rtnl socket"); 1108341618Scy return -1; 1109341618Scy } 1110341618Scy 1111341618Scy link = rtnl_link_macsec_alloc(); 1112341618Scy if (!link) { 1113341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't allocate link"); 1114341618Scy return -1; 1115341618Scy } 1116341618Scy 1117341618Scy rtnl_link_set_link(link, drv->parent_ifi); 1118341618Scy 1119341618Scy sci = mka_sci_u64(&sc->sci); 1120341618Scy rtnl_link_macsec_set_sci(link, sci); 1121341618Scy 1122341618Scy drv->created_link = TRUE; 1123341618Scy 1124341618Scy err = rtnl_link_add(drv->sk, link, NLM_F_CREATE); 1125341618Scy if (err == -NLE_BUSY) { 1126341618Scy wpa_printf(MSG_INFO, 1127341618Scy DRV_PREFIX "link already exists, using it"); 1128341618Scy drv->created_link = FALSE; 1129341618Scy } else if (err < 0) { 1130341618Scy rtnl_link_put(link); 1131341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't create link: err %d", 1132341618Scy err); 1133341618Scy return err; 1134341618Scy } 1135341618Scy 1136341618Scy rtnl_link_put(link); 1137341618Scy 1138341618Scy nl_cache_refill(drv->sk, drv->link_cache); 1139341618Scy link = lookup_sc(drv->link_cache, drv->parent_ifi, sci); 1140341618Scy if (!link) { 1141341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't find link"); 1142341618Scy return -1; 1143341618Scy } 1144341618Scy 1145341618Scy drv->ifi = rtnl_link_get_ifindex(link); 1146341618Scy ifname = rtnl_link_get_name(link); 1147346981Scy wpa_printf(MSG_DEBUG, 1148346981Scy DRV_PREFIX "%s: create_transmit_sc: ifi=%d ifname=%s", 1149346981Scy drv->common.ifname, drv->ifi, ifname); 1150341618Scy os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); 1151341618Scy rtnl_link_put(link); 1152341618Scy 1153341618Scy drv->link = rtnl_link_macsec_alloc(); 1154341618Scy if (!drv->link) { 1155341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't allocate link"); 1156341618Scy return -1; 1157341618Scy } 1158341618Scy 1159341618Scy rtnl_link_set_name(drv->link, drv->ifname); 1160341618Scy 1161341618Scy /* In case some settings have already been done but we couldn't apply 1162341618Scy * them. */ 1163341618Scy return try_commit(drv); 1164341618Scy} 1165341618Scy 1166341618Scy 1167341618Scy/** 1168341618Scy * macsec_drv_delete_transmit_sc - Delete secure connection for transmit 1169341618Scy * @priv: private driver interface data from init() 1170341618Scy * @sc: secure channel 1171341618Scy * Returns: 0 on success, -1 on failure 1172341618Scy */ 1173341618Scystatic int macsec_drv_delete_transmit_sc(void *priv, struct transmit_sc *sc) 1174341618Scy{ 1175341618Scy struct macsec_drv_data *drv = priv; 1176341618Scy int err; 1177341618Scy 1178346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_transmit_sc -> " SCISTR, 1179346981Scy drv->ifname, SCI2STR(sc->sci.addr, sc->sci.port)); 1180341618Scy 1181341618Scy if (!drv->sk) 1182341618Scy return 0; 1183341618Scy 1184341618Scy if (!drv->created_link) { 1185341618Scy rtnl_link_put(drv->link); 1186341618Scy drv->link = NULL; 1187341618Scy wpa_printf(MSG_DEBUG, DRV_PREFIX 1188341618Scy "we didn't create the link, leave it alone"); 1189341618Scy return 0; 1190341618Scy } 1191341618Scy 1192341618Scy err = rtnl_link_delete(drv->sk, drv->link); 1193341618Scy if (err < 0) 1194341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't delete link"); 1195341618Scy rtnl_link_put(drv->link); 1196341618Scy drv->link = NULL; 1197341618Scy 1198341618Scy return err; 1199341618Scy} 1200341618Scy 1201341618Scy 1202341618Scy/** 1203341618Scy * macsec_drv_create_transmit_sa - Create secure association for transmit 1204341618Scy * @priv: private driver interface data from init() 1205341618Scy * @sa: secure association 1206341618Scy * Returns: 0 on success, -1 on failure 1207341618Scy */ 1208341618Scystatic int macsec_drv_create_transmit_sa(void *priv, struct transmit_sa *sa) 1209341618Scy{ 1210341618Scy struct macsec_drv_data *drv = priv; 1211341618Scy struct macsec_genl_ctx *ctx = &drv->ctx; 1212341618Scy struct nl_msg *msg; 1213341618Scy struct nlattr *nest; 1214341618Scy int ret = -1; 1215341618Scy 1216346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: create_transmit_sa -> %d on " 1217346981Scy SCISTR " (enable_transmit=%d next_pn=%u)", 1218346981Scy drv->ifname, sa->an, 1219346981Scy SCI2STR(sa->sc->sci.addr, sa->sc->sci.port), 1220346981Scy sa->enable_transmit, sa->next_pn); 1221346981Scy wpa_hexdump(MSG_DEBUG, DRV_PREFIX "SA keyid", 1222346981Scy &sa->pkey->key_identifier, 1223346981Scy sizeof(sa->pkey->key_identifier)); 1224346981Scy wpa_hexdump_key(MSG_DEBUG, DRV_PREFIX "SA key", 1225346981Scy sa->pkey->key, sa->pkey->key_len); 1226341618Scy 1227341618Scy msg = msg_prepare(MACSEC_CMD_ADD_TXSA, ctx, drv->ifi); 1228341618Scy if (!msg) 1229341618Scy return ret; 1230341618Scy 1231341618Scy nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG); 1232341618Scy if (!nest) 1233341618Scy goto nla_put_failure; 1234341618Scy 1235341618Scy NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an); 1236341618Scy NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn); 1237341618Scy NLA_PUT(msg, MACSEC_SA_ATTR_KEYID, sizeof(sa->pkey->key_identifier), 1238341618Scy &sa->pkey->key_identifier); 1239341618Scy NLA_PUT(msg, MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key); 1240341618Scy NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, sa->enable_transmit); 1241341618Scy 1242341618Scy nla_nest_end(msg, nest); 1243341618Scy 1244341618Scy ret = nl_send_recv(ctx->sk, msg); 1245341618Scy if (ret < 0) { 1246341618Scy wpa_printf(MSG_ERROR, 1247341618Scy DRV_PREFIX "%s: failed to communicate: %d (%s)", 1248341618Scy __func__, ret, nl_geterror(-ret)); 1249341618Scy } 1250341618Scy 1251341618Scynla_put_failure: 1252341618Scy nlmsg_free(msg); 1253341618Scy return ret; 1254341618Scy} 1255341618Scy 1256341618Scy 1257341618Scy/** 1258341618Scy * macsec_drv_delete_transmit_sa - Delete secure association for transmit 1259341618Scy * @priv: private driver interface data from init() 1260341618Scy * @sa: secure association 1261341618Scy * Returns: 0 on success, -1 on failure 1262341618Scy */ 1263341618Scystatic int macsec_drv_delete_transmit_sa(void *priv, struct transmit_sa *sa) 1264341618Scy{ 1265341618Scy struct macsec_drv_data *drv = priv; 1266341618Scy struct macsec_genl_ctx *ctx = &drv->ctx; 1267341618Scy struct nl_msg *msg; 1268341618Scy struct nlattr *nest; 1269341618Scy int ret = -1; 1270341618Scy 1271346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_transmit_sa -> %d on " 1272346981Scy SCISTR, drv->ifname, sa->an, 1273346981Scy SCI2STR(sa->sc->sci.addr, sa->sc->sci.port)); 1274341618Scy 1275341618Scy msg = msg_prepare(MACSEC_CMD_DEL_TXSA, ctx, drv->ifi); 1276341618Scy if (!msg) 1277341618Scy return ret; 1278341618Scy 1279341618Scy nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG); 1280341618Scy if (!nest) 1281341618Scy goto nla_put_failure; 1282341618Scy 1283341618Scy NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an); 1284341618Scy 1285341618Scy nla_nest_end(msg, nest); 1286341618Scy 1287341618Scy ret = nl_send_recv(ctx->sk, msg); 1288341618Scy if (ret < 0) { 1289341618Scy wpa_printf(MSG_ERROR, 1290341618Scy DRV_PREFIX "%s: failed to communicate: %d (%s)", 1291341618Scy __func__, ret, nl_geterror(-ret)); 1292341618Scy } 1293341618Scy 1294341618Scynla_put_failure: 1295341618Scy nlmsg_free(msg); 1296341618Scy return ret; 1297341618Scy} 1298341618Scy 1299341618Scy 1300341618Scystatic int set_active_tx_sa(const struct macsec_genl_ctx *ctx, int ifindex, 1301341618Scy unsigned char an, Boolean state) 1302341618Scy{ 1303341618Scy struct nl_msg *msg; 1304341618Scy struct nlattr *nest; 1305341618Scy int ret = -1; 1306341618Scy 1307341618Scy msg = msg_prepare(MACSEC_CMD_UPD_TXSA, ctx, ifindex); 1308341618Scy if (!msg) 1309341618Scy return ret; 1310341618Scy 1311341618Scy nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG); 1312341618Scy if (!nest) 1313341618Scy goto nla_put_failure; 1314341618Scy 1315341618Scy NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, an); 1316341618Scy NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, !!state); 1317341618Scy 1318341618Scy nla_nest_end(msg, nest); 1319341618Scy 1320341618Scy ret = nl_send_recv(ctx->sk, msg); 1321341618Scy if (ret < 0) { 1322341618Scy wpa_printf(MSG_ERROR, 1323341618Scy DRV_PREFIX "%s: failed to communicate: %d (%s)", 1324341618Scy __func__, ret, nl_geterror(-ret)); 1325341618Scy } 1326341618Scy 1327341618Scynla_put_failure: 1328341618Scy nlmsg_free(msg); 1329341618Scy return ret; 1330341618Scy} 1331341618Scy 1332341618Scy 1333341618Scy/** 1334341618Scy * macsec_drv_enable_transmit_sa - Enable SA for transmit 1335341618Scy * @priv: private driver interface data from init() 1336341618Scy * @sa: secure association 1337341618Scy * Returns: 0 on success, -1 on failure 1338341618Scy */ 1339341618Scystatic int macsec_drv_enable_transmit_sa(void *priv, struct transmit_sa *sa) 1340341618Scy{ 1341341618Scy struct macsec_drv_data *drv = priv; 1342341618Scy struct macsec_genl_ctx *ctx = &drv->ctx; 1343341618Scy int ret; 1344341618Scy 1345346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: enable_transmit_sa -> %d on " 1346346981Scy SCISTR, drv->ifname, sa->an, 1347346981Scy SCI2STR(sa->sc->sci.addr, sa->sc->sci.port)); 1348341618Scy 1349341618Scy ret = set_active_tx_sa(ctx, drv->ifi, sa->an, TRUE); 1350341618Scy if (ret < 0) { 1351341618Scy wpa_printf(MSG_ERROR, DRV_PREFIX "failed to enable txsa"); 1352341618Scy return ret; 1353341618Scy } 1354341618Scy 1355341618Scy drv->encoding_sa_set = TRUE; 1356341618Scy drv->encoding_sa = sa->an; 1357341618Scy 1358341618Scy return try_commit(drv); 1359341618Scy} 1360341618Scy 1361341618Scy 1362341618Scy/** 1363341618Scy * macsec_drv_disable_transmit_sa - Disable SA for transmit 1364341618Scy * @priv: private driver interface data from init() 1365341618Scy * @sa: secure association 1366341618Scy * Returns: 0 on success, -1 on failure 1367341618Scy */ 1368341618Scystatic int macsec_drv_disable_transmit_sa(void *priv, struct transmit_sa *sa) 1369341618Scy{ 1370341618Scy struct macsec_drv_data *drv = priv; 1371341618Scy struct macsec_genl_ctx *ctx = &drv->ctx; 1372341618Scy 1373346981Scy wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: disable_transmit_sa -> %d on " 1374346981Scy SCISTR, drv->ifname, sa->an, 1375346981Scy SCI2STR(sa->sc->sci.addr, sa->sc->sci.port)); 1376341618Scy 1377341618Scy return set_active_tx_sa(ctx, drv->ifi, sa->an, FALSE); 1378341618Scy} 1379341618Scy 1380341618Scy 1381346981Scystatic int macsec_drv_status(void *priv, char *buf, size_t buflen) 1382346981Scy{ 1383346981Scy struct macsec_drv_data *drv = priv; 1384346981Scy int res; 1385346981Scy char *pos, *end; 1386346981Scy 1387346981Scy pos = buf; 1388346981Scy end = buf + buflen; 1389346981Scy 1390346981Scy res = os_snprintf(pos, end - pos, 1391346981Scy "ifname=%s\n" 1392346981Scy "ifi=%d\n" 1393346981Scy "parent_ifname=%s\n" 1394346981Scy "parent_ifi=%d\n", 1395346981Scy drv->common.ifname, drv->ifi, 1396346981Scy drv->ifname, drv->parent_ifi); 1397346981Scy if (os_snprintf_error(end - pos, res)) 1398346981Scy return pos - buf; 1399346981Scy pos += res; 1400346981Scy 1401346981Scy return pos - buf; 1402346981Scy} 1403346981Scy 1404346981Scy 1405351611Scy#ifdef __linux__ 1406351611Scy 1407351611Scystatic void macsec_drv_handle_data(void *ctx, unsigned char *buf, size_t len) 1408351611Scy{ 1409351611Scy#ifdef HOSTAPD 1410351611Scy struct ieee8023_hdr *hdr; 1411351611Scy u8 *pos, *sa; 1412351611Scy size_t left; 1413351611Scy union wpa_event_data event; 1414351611Scy 1415351611Scy /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest, 1416351611Scy * 2 byte ethertype */ 1417351611Scy if (len < 14) { 1418351611Scy wpa_printf(MSG_MSGDUMP, "%s: too short (%lu)", 1419351611Scy __func__, (unsigned long) len); 1420351611Scy return; 1421351611Scy } 1422351611Scy 1423351611Scy hdr = (struct ieee8023_hdr *) buf; 1424351611Scy 1425351611Scy switch (ntohs(hdr->ethertype)) { 1426351611Scy case ETH_P_PAE: 1427351611Scy wpa_printf(MSG_MSGDUMP, "Received EAPOL packet"); 1428351611Scy sa = hdr->src; 1429351611Scy os_memset(&event, 0, sizeof(event)); 1430351611Scy event.new_sta.addr = sa; 1431351611Scy wpa_supplicant_event(ctx, EVENT_NEW_STA, &event); 1432351611Scy 1433351611Scy pos = (u8 *) (hdr + 1); 1434351611Scy left = len - sizeof(*hdr); 1435351611Scy drv_event_eapol_rx(ctx, sa, pos, left); 1436351611Scy break; 1437351611Scy 1438351611Scy default: 1439351611Scy wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame", 1440351611Scy ntohs(hdr->ethertype)); 1441351611Scy break; 1442351611Scy } 1443351611Scy#endif /* HOSTAPD */ 1444351611Scy} 1445351611Scy 1446351611Scy 1447351611Scystatic void macsec_drv_handle_read(int sock, void *eloop_ctx, void *sock_ctx) 1448351611Scy{ 1449351611Scy int len; 1450351611Scy unsigned char buf[3000]; 1451351611Scy 1452351611Scy len = recv(sock, buf, sizeof(buf), 0); 1453351611Scy if (len < 0) { 1454351611Scy wpa_printf(MSG_ERROR, "macsec_linux: recv: %s", 1455351611Scy strerror(errno)); 1456351611Scy return; 1457351611Scy } 1458351611Scy 1459351611Scy macsec_drv_handle_data(eloop_ctx, buf, len); 1460351611Scy} 1461351611Scy 1462351611Scy#endif /* __linux__ */ 1463351611Scy 1464351611Scy 1465351611Scystatic int macsec_drv_init_sockets(struct macsec_drv_data *drv, u8 *own_addr) 1466351611Scy{ 1467351611Scy#ifdef __linux__ 1468351611Scy struct ifreq ifr; 1469351611Scy struct sockaddr_ll addr; 1470351611Scy 1471351611Scy drv->common.sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE)); 1472351611Scy if (drv->common.sock < 0) { 1473351611Scy wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s", 1474351611Scy strerror(errno)); 1475351611Scy return -1; 1476351611Scy } 1477351611Scy 1478351611Scy if (eloop_register_read_sock(drv->common.sock, macsec_drv_handle_read, 1479351611Scy drv->common.ctx, NULL)) { 1480351611Scy wpa_printf(MSG_INFO, "Could not register read socket"); 1481351611Scy return -1; 1482351611Scy } 1483351611Scy 1484351611Scy os_memset(&ifr, 0, sizeof(ifr)); 1485351611Scy os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name)); 1486351611Scy if (ioctl(drv->common.sock, SIOCGIFINDEX, &ifr) != 0) { 1487351611Scy wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s", 1488351611Scy strerror(errno)); 1489351611Scy return -1; 1490351611Scy } 1491351611Scy 1492351611Scy os_memset(&addr, 0, sizeof(addr)); 1493351611Scy addr.sll_family = AF_PACKET; 1494351611Scy addr.sll_ifindex = ifr.ifr_ifindex; 1495351611Scy wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", 1496351611Scy addr.sll_ifindex); 1497351611Scy 1498351611Scy if (bind(drv->common.sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) 1499351611Scy { 1500351611Scy wpa_printf(MSG_ERROR, "bind: %s", strerror(errno)); 1501351611Scy return -1; 1502351611Scy } 1503351611Scy 1504351611Scy /* filter multicast address */ 1505351611Scy if (wired_multicast_membership(drv->common.sock, ifr.ifr_ifindex, 1506351611Scy pae_group_addr, 1) < 0) { 1507351611Scy wpa_printf(MSG_ERROR, "wired: Failed to add multicast group " 1508351611Scy "membership"); 1509351611Scy return -1; 1510351611Scy } 1511351611Scy 1512351611Scy os_memset(&ifr, 0, sizeof(ifr)); 1513351611Scy os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name)); 1514351611Scy if (ioctl(drv->common.sock, SIOCGIFHWADDR, &ifr) != 0) { 1515351611Scy wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s", 1516351611Scy strerror(errno)); 1517351611Scy return -1; 1518351611Scy } 1519351611Scy 1520351611Scy if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { 1521351611Scy wpa_printf(MSG_INFO, "Invalid HW-addr family 0x%04x", 1522351611Scy ifr.ifr_hwaddr.sa_family); 1523351611Scy return -1; 1524351611Scy } 1525351611Scy os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); 1526351611Scy 1527351611Scy return 0; 1528351611Scy#else /* __linux__ */ 1529351611Scy return -1; 1530351611Scy#endif /* __linux__ */ 1531351611Scy} 1532351611Scy 1533351611Scy 1534351611Scystatic void * macsec_drv_hapd_init(struct hostapd_data *hapd, 1535351611Scy struct wpa_init_params *params) 1536351611Scy{ 1537351611Scy struct macsec_drv_data *drv; 1538351611Scy 1539351611Scy drv = os_zalloc(sizeof(struct macsec_drv_data)); 1540351611Scy if (drv == NULL) { 1541351611Scy wpa_printf(MSG_INFO, 1542351611Scy "Could not allocate memory for wired driver data"); 1543351611Scy return NULL; 1544351611Scy } 1545351611Scy 1546351611Scy drv->common.ctx = hapd; 1547351611Scy os_strlcpy(drv->common.ifname, params->ifname, 1548351611Scy sizeof(drv->common.ifname)); 1549351611Scy drv->use_pae_group_addr = params->use_pae_group_addr; 1550351611Scy 1551351611Scy if (macsec_drv_init_sockets(drv, params->own_addr)) { 1552351611Scy os_free(drv); 1553351611Scy return NULL; 1554351611Scy } 1555351611Scy 1556351611Scy return drv; 1557351611Scy} 1558351611Scy 1559351611Scy 1560351611Scystatic void macsec_drv_hapd_deinit(void *priv) 1561351611Scy{ 1562351611Scy struct macsec_drv_data *drv = priv; 1563351611Scy 1564351611Scy if (drv->common.sock >= 0) { 1565351611Scy eloop_unregister_read_sock(drv->common.sock); 1566351611Scy close(drv->common.sock); 1567351611Scy } 1568351611Scy 1569351611Scy os_free(drv); 1570351611Scy} 1571351611Scy 1572351611Scy 1573351611Scystatic int macsec_drv_send_eapol(void *priv, const u8 *addr, 1574351611Scy const u8 *data, size_t data_len, int encrypt, 1575351611Scy const u8 *own_addr, u32 flags) 1576351611Scy{ 1577351611Scy struct macsec_drv_data *drv = priv; 1578351611Scy struct ieee8023_hdr *hdr; 1579351611Scy size_t len; 1580351611Scy u8 *pos; 1581351611Scy int res; 1582351611Scy 1583351611Scy len = sizeof(*hdr) + data_len; 1584351611Scy hdr = os_zalloc(len); 1585351611Scy if (hdr == NULL) { 1586351611Scy wpa_printf(MSG_INFO, 1587351611Scy "%s: malloc() failed (len=%lu)", 1588351611Scy __func__, (unsigned long) len); 1589351611Scy return -1; 1590351611Scy } 1591351611Scy 1592351611Scy os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr, 1593351611Scy ETH_ALEN); 1594351611Scy os_memcpy(hdr->src, own_addr, ETH_ALEN); 1595351611Scy hdr->ethertype = htons(ETH_P_PAE); 1596351611Scy 1597351611Scy pos = (u8 *) (hdr + 1); 1598351611Scy os_memcpy(pos, data, data_len); 1599351611Scy 1600351611Scy res = send(drv->common.sock, (u8 *) hdr, len, 0); 1601351611Scy os_free(hdr); 1602351611Scy 1603351611Scy if (res < 0) { 1604351611Scy wpa_printf(MSG_ERROR, 1605351611Scy "%s: packet len: %lu - failed: send: %s", 1606351611Scy __func__, (unsigned long) len, strerror(errno)); 1607351611Scy } 1608351611Scy 1609351611Scy return res; 1610351611Scy} 1611351611Scy 1612351611Scy 1613341618Scyconst struct wpa_driver_ops wpa_driver_macsec_linux_ops = { 1614341618Scy .name = "macsec_linux", 1615341618Scy .desc = "MACsec Ethernet driver for Linux", 1616341618Scy .get_ssid = driver_wired_get_ssid, 1617341618Scy .get_bssid = driver_wired_get_bssid, 1618341618Scy .get_capa = driver_wired_get_capa, 1619341618Scy .init = macsec_drv_wpa_init, 1620341618Scy .deinit = macsec_drv_wpa_deinit, 1621351611Scy .hapd_init = macsec_drv_hapd_init, 1622351611Scy .hapd_deinit = macsec_drv_hapd_deinit, 1623351611Scy .hapd_send_eapol = macsec_drv_send_eapol, 1624341618Scy 1625341618Scy .macsec_init = macsec_drv_macsec_init, 1626341618Scy .macsec_deinit = macsec_drv_macsec_deinit, 1627341618Scy .macsec_get_capability = macsec_drv_get_capability, 1628341618Scy .enable_protect_frames = macsec_drv_enable_protect_frames, 1629341618Scy .enable_encrypt = macsec_drv_enable_encrypt, 1630341618Scy .set_replay_protect = macsec_drv_set_replay_protect, 1631341618Scy .set_current_cipher_suite = macsec_drv_set_current_cipher_suite, 1632341618Scy .enable_controlled_port = macsec_drv_enable_controlled_port, 1633341618Scy .get_receive_lowest_pn = macsec_drv_get_receive_lowest_pn, 1634346981Scy .set_receive_lowest_pn = macsec_drv_set_receive_lowest_pn, 1635341618Scy .get_transmit_next_pn = macsec_drv_get_transmit_next_pn, 1636341618Scy .set_transmit_next_pn = macsec_drv_set_transmit_next_pn, 1637341618Scy .create_receive_sc = macsec_drv_create_receive_sc, 1638341618Scy .delete_receive_sc = macsec_drv_delete_receive_sc, 1639341618Scy .create_receive_sa = macsec_drv_create_receive_sa, 1640341618Scy .delete_receive_sa = macsec_drv_delete_receive_sa, 1641341618Scy .enable_receive_sa = macsec_drv_enable_receive_sa, 1642341618Scy .disable_receive_sa = macsec_drv_disable_receive_sa, 1643341618Scy .create_transmit_sc = macsec_drv_create_transmit_sc, 1644341618Scy .delete_transmit_sc = macsec_drv_delete_transmit_sc, 1645341618Scy .create_transmit_sa = macsec_drv_create_transmit_sa, 1646341618Scy .delete_transmit_sa = macsec_drv_delete_transmit_sa, 1647341618Scy .enable_transmit_sa = macsec_drv_enable_transmit_sa, 1648341618Scy .disable_transmit_sa = macsec_drv_disable_transmit_sa, 1649346981Scy 1650346981Scy .status = macsec_drv_status, 1651341618Scy}; 1652