1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
/*
* permaddr.c - netlink implementation of permanent address request
*
* Implementation of "ethtool -P <dev>"
*/
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <linux/rtnetlink.h>
#include <linux/if_link.h>
#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);
}
|