xref: /aosp_15_r20/external/ethtool/netlink/permaddr.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1 /*
2  * permaddr.c - netlink implementation of permanent address request
3  *
4  * Implementation of "ethtool -P <dev>"
5  */
6 
7 #include <errno.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <linux/rtnetlink.h>
11 #include <linux/if_link.h>
12 
13 #include "../internal.h"
14 #include "../common.h"
15 #include "netlink.h"
16 
17 /* PERMADDR_GET */
18 
permaddr_prep_request(struct nl_socket * nlsk)19 static int permaddr_prep_request(struct nl_socket *nlsk)
20 {
21 	unsigned int nlm_flags = NLM_F_REQUEST | NLM_F_ACK;
22 	struct nl_context *nlctx = nlsk->nlctx;
23 	const char *devname = nlctx->ctx->devname;
24 	struct nl_msg_buff *msgbuff = &nlsk->msgbuff;
25 	struct ifinfomsg *ifinfo;
26 	struct nlmsghdr *nlhdr;
27 	int ret;
28 
29 	if (devname && !strcmp(devname, WILDCARD_DEVNAME)) {
30 		devname = NULL;
31 		nlm_flags |= NLM_F_DUMP;
32 	}
33 	nlctx->is_dump = !devname;
34 
35         ret = msgbuff_realloc(msgbuff, MNL_SOCKET_BUFFER_SIZE);
36         if (ret < 0)
37                 return ret;
38         memset(msgbuff->buff, '\0', NLMSG_HDRLEN + sizeof(*ifinfo));
39 
40 	nlhdr = mnl_nlmsg_put_header(msgbuff->buff);
41 	nlhdr->nlmsg_type = RTM_GETLINK;
42 	nlhdr->nlmsg_flags = nlm_flags;
43 	msgbuff->nlhdr = nlhdr;
44 	ifinfo = mnl_nlmsg_put_extra_header(nlhdr, sizeof(*ifinfo));
45 
46 	if (devname) {
47 		uint16_t type = IFLA_IFNAME;
48 
49 		if (strlen(devname) >= IFNAMSIZ)
50 			type = IFLA_ALT_IFNAME;
51 		if (ethnla_put_strz(msgbuff, type, devname))
52 			return -EMSGSIZE;
53 	}
54 	if (ethnla_put_u32(msgbuff, IFLA_EXT_MASK, RTEXT_FILTER_SKIP_STATS))
55 		return -EMSGSIZE;
56 
57 	return 0;
58 }
59 
permaddr_reply_cb(const struct nlmsghdr * nlhdr,void * data)60 int permaddr_reply_cb(const struct nlmsghdr *nlhdr, void *data)
61 {
62 	const struct nlattr *tb[__IFLA_MAX] = {};
63 	DECLARE_ATTR_TB_INFO(tb);
64 	struct nl_context *nlctx = data;
65 	const uint8_t *permaddr;
66 	unsigned int i;
67 	int ret;
68 
69 	if (nlhdr->nlmsg_type != RTM_NEWLINK)
70 		goto err;
71 	ret = mnl_attr_parse(nlhdr, sizeof(struct ifinfomsg), attr_cb,
72 			     &tb_info);
73 	if (ret < 0 || !tb[IFLA_IFNAME])
74 		goto err;
75 	nlctx->devname = mnl_attr_get_str(tb[IFLA_IFNAME]);
76 	if (!dev_ok(nlctx))
77 		goto err;
78 
79 	if (!tb[IFLA_PERM_ADDRESS]) {
80 		if (!nlctx->is_dump)
81 			printf("Permanent address: not set\n");
82 		return MNL_CB_OK;
83 	}
84 
85 	if (nlctx->is_dump)
86 		printf("Permanent address of %s:", nlctx->devname);
87 	else
88 		printf("Permanent address:");
89 	permaddr = mnl_attr_get_payload(tb[IFLA_PERM_ADDRESS]);
90 	for (i = 0; i < mnl_attr_get_payload_len(tb[IFLA_PERM_ADDRESS]); i++)
91 		printf("%c%02x", i ? ':' : ' ', permaddr[i]);
92 	putchar('\n');
93 	return MNL_CB_OK;
94 
95 err:
96 	if (nlctx->is_dump || nlctx->is_monitor)
97 		return MNL_CB_OK;
98 	nlctx->exit_code = 2;
99 	return MNL_CB_ERROR;
100 }
101 
nl_permaddr(struct cmd_context * ctx)102 int nl_permaddr(struct cmd_context *ctx)
103 {
104 	struct nl_context *nlctx = ctx->nlctx;
105 	int ret;
106 
107 	ret = netlink_init_rtnl_socket(nlctx);
108 	if (ret < 0)
109 		return ret;
110 	ret = permaddr_prep_request(nlctx->rtnl_socket);
111 	if (ret < 0)
112 		return ret;
113 	return nlsock_send_get_request(nlctx->rtnl_socket, permaddr_reply_cb);
114 }
115