/* * permaddr.c - netlink implementation of permanent address request * * Implementation of "ethtool -P " */ #include #include #include #include #include #include "../internal.h" #include "../common.h" #include "netlink.h" /* PERMADDR_GET */ static int permaddr_prep_request(struct nl_socket *nlsk) { unsigned int nlm_flags = NLM_F_REQUEST | NLM_F_ACK; struct nl_context *nlctx = nlsk->nlctx; const char *devname = nlctx->ctx->devname; struct nl_msg_buff *msgbuff = &nlsk->msgbuff; struct ifinfomsg *ifinfo; struct nlmsghdr *nlhdr; int ret; if (devname && !strcmp(devname, WILDCARD_DEVNAME)) { devname = NULL; nlm_flags |= NLM_F_DUMP; } nlctx->is_dump = !devname; ret = msgbuff_realloc(msgbuff, MNL_SOCKET_BUFFER_SIZE); if (ret < 0) return ret; memset(msgbuff->buff, '\0', NLMSG_HDRLEN + sizeof(*ifinfo)); nlhdr = mnl_nlmsg_put_header(msgbuff->buff); nlhdr->nlmsg_type = RTM_GETLINK; nlhdr->nlmsg_flags = nlm_flags; msgbuff->nlhdr = nlhdr; ifinfo = mnl_nlmsg_put_extra_header(nlhdr, sizeof(*ifinfo)); if (devname) { uint16_t type = IFLA_IFNAME; if (strlen(devname) >= IFNAMSIZ) type = IFLA_ALT_IFNAME; if (ethnla_put_strz(msgbuff, type, devname)) return -EMSGSIZE; } if (ethnla_put_u32(msgbuff, IFLA_EXT_MASK, RTEXT_FILTER_SKIP_STATS)) return -EMSGSIZE; return 0; } int permaddr_reply_cb(const struct nlmsghdr *nlhdr, void *data) { const struct nlattr *tb[__IFLA_MAX] = {}; DECLARE_ATTR_TB_INFO(tb); struct nl_context *nlctx = data; const uint8_t *permaddr; unsigned int i; int ret; if (nlhdr->nlmsg_type != RTM_NEWLINK) goto err; ret = mnl_attr_parse(nlhdr, sizeof(struct ifinfomsg), attr_cb, &tb_info); if (ret < 0 || !tb[IFLA_IFNAME]) goto err; nlctx->devname = mnl_attr_get_str(tb[IFLA_IFNAME]); if (!dev_ok(nlctx)) goto err; if (!tb[IFLA_PERM_ADDRESS]) { if (!nlctx->is_dump) printf("Permanent address: not set\n"); return MNL_CB_OK; } if (nlctx->is_dump) printf("Permanent address of %s:", nlctx->devname); else printf("Permanent address:"); permaddr = mnl_attr_get_payload(tb[IFLA_PERM_ADDRESS]); for (i = 0; i < mnl_attr_get_payload_len(tb[IFLA_PERM_ADDRESS]); i++) printf("%c%02x", i ? ':' : ' ', permaddr[i]); putchar('\n'); return MNL_CB_OK; err: if (nlctx->is_dump || nlctx->is_monitor) return MNL_CB_OK; nlctx->exit_code = 2; return MNL_CB_ERROR; } int nl_permaddr(struct cmd_context *ctx) { struct nl_context *nlctx = ctx->nlctx; int ret; ret = netlink_init_rtnl_socket(nlctx); if (ret < 0) return ret; ret = permaddr_prep_request(nlctx->rtnl_socket); if (ret < 0) return ret; return nlsock_send_get_request(nlctx->rtnl_socket, permaddr_reply_cb); }