xref: /aosp_15_r20/external/ethtool/netlink/nlsock.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1*1b481fc3SMaciej Żenczykowski /*
2*1b481fc3SMaciej Żenczykowski  * nlsock.c - netlink socket
3*1b481fc3SMaciej Żenczykowski  *
4*1b481fc3SMaciej Żenczykowski  * Data structure and code for netlink socket abstraction.
5*1b481fc3SMaciej Żenczykowski  */
6*1b481fc3SMaciej Żenczykowski 
7*1b481fc3SMaciej Żenczykowski #include <stdint.h>
8*1b481fc3SMaciej Żenczykowski #include <errno.h>
9*1b481fc3SMaciej Żenczykowski 
10*1b481fc3SMaciej Żenczykowski #include "../internal.h"
11*1b481fc3SMaciej Żenczykowski #include "nlsock.h"
12*1b481fc3SMaciej Żenczykowski #include "netlink.h"
13*1b481fc3SMaciej Żenczykowski #include "prettymsg.h"
14*1b481fc3SMaciej Żenczykowski 
15*1b481fc3SMaciej Żenczykowski #define NLSOCK_RECV_BUFFSIZE 65536
16*1b481fc3SMaciej Żenczykowski 
ctrl_msg_summary(const struct nlmsghdr * nlhdr)17*1b481fc3SMaciej Żenczykowski static void ctrl_msg_summary(const struct nlmsghdr *nlhdr)
18*1b481fc3SMaciej Żenczykowski {
19*1b481fc3SMaciej Żenczykowski 	const struct nlmsgerr *nlerr;
20*1b481fc3SMaciej Żenczykowski 
21*1b481fc3SMaciej Żenczykowski 	switch (nlhdr->nlmsg_type) {
22*1b481fc3SMaciej Żenczykowski 	case NLMSG_NOOP:
23*1b481fc3SMaciej Żenczykowski 		printf(" noop\n");
24*1b481fc3SMaciej Żenczykowski 		break;
25*1b481fc3SMaciej Żenczykowski 	case NLMSG_ERROR:
26*1b481fc3SMaciej Żenczykowski 		printf(" error");
27*1b481fc3SMaciej Żenczykowski 		if (nlhdr->nlmsg_len < NLMSG_HDRLEN + sizeof(*nlerr)) {
28*1b481fc3SMaciej Żenczykowski 			printf(" malformed\n");
29*1b481fc3SMaciej Żenczykowski 			break;
30*1b481fc3SMaciej Żenczykowski 		}
31*1b481fc3SMaciej Żenczykowski 		nlerr = mnl_nlmsg_get_payload(nlhdr);
32*1b481fc3SMaciej Żenczykowski 		printf(" errno=%d\n", nlerr->error);
33*1b481fc3SMaciej Żenczykowski 		break;
34*1b481fc3SMaciej Żenczykowski 	case NLMSG_DONE:
35*1b481fc3SMaciej Żenczykowski 		printf(" done\n");
36*1b481fc3SMaciej Żenczykowski 		break;
37*1b481fc3SMaciej Żenczykowski 	case NLMSG_OVERRUN:
38*1b481fc3SMaciej Żenczykowski 		printf(" overrun\n");
39*1b481fc3SMaciej Żenczykowski 		break;
40*1b481fc3SMaciej Żenczykowski 	default:
41*1b481fc3SMaciej Żenczykowski 		printf(" type %u\n", nlhdr->nlmsg_type);
42*1b481fc3SMaciej Żenczykowski 		break;
43*1b481fc3SMaciej Żenczykowski 	}
44*1b481fc3SMaciej Żenczykowski }
45*1b481fc3SMaciej Żenczykowski 
genl_msg_summary(const struct nlmsghdr * nlhdr,int ethnl_fam,bool outgoing,bool pretty)46*1b481fc3SMaciej Żenczykowski static void genl_msg_summary(const struct nlmsghdr *nlhdr, int ethnl_fam,
47*1b481fc3SMaciej Żenczykowski 			     bool outgoing, bool pretty)
48*1b481fc3SMaciej Żenczykowski {
49*1b481fc3SMaciej Żenczykowski 	if (nlhdr->nlmsg_type == ethnl_fam) {
50*1b481fc3SMaciej Żenczykowski 		const struct pretty_nlmsg_desc *msg_desc;
51*1b481fc3SMaciej Żenczykowski 		const struct genlmsghdr *ghdr;
52*1b481fc3SMaciej Żenczykowski 		unsigned int n_desc;
53*1b481fc3SMaciej Żenczykowski 
54*1b481fc3SMaciej Żenczykowski 		printf(" ethool");
55*1b481fc3SMaciej Żenczykowski 		if (nlhdr->nlmsg_len < NLMSG_HDRLEN + GENL_HDRLEN) {
56*1b481fc3SMaciej Żenczykowski 			printf(" malformed\n");
57*1b481fc3SMaciej Żenczykowski 			return;
58*1b481fc3SMaciej Żenczykowski 		}
59*1b481fc3SMaciej Żenczykowski 		ghdr = mnl_nlmsg_get_payload(nlhdr);
60*1b481fc3SMaciej Żenczykowski 
61*1b481fc3SMaciej Żenczykowski 		msg_desc = outgoing ? ethnl_umsg_desc : ethnl_kmsg_desc;
62*1b481fc3SMaciej Żenczykowski 		n_desc = outgoing ? ethnl_umsg_n_desc : ethnl_kmsg_n_desc;
63*1b481fc3SMaciej Żenczykowski 		if (ghdr->cmd < n_desc && msg_desc[ghdr->cmd].name)
64*1b481fc3SMaciej Żenczykowski 			printf(" %s", msg_desc[ghdr->cmd].name);
65*1b481fc3SMaciej Żenczykowski 		else
66*1b481fc3SMaciej Żenczykowski 			printf(" cmd %u", ghdr->cmd);
67*1b481fc3SMaciej Żenczykowski 		fputc('\n', stdout);
68*1b481fc3SMaciej Żenczykowski 
69*1b481fc3SMaciej Żenczykowski 		if (pretty)
70*1b481fc3SMaciej Żenczykowski 			pretty_print_genlmsg(nlhdr, msg_desc, n_desc, 0);
71*1b481fc3SMaciej Żenczykowski 		return;
72*1b481fc3SMaciej Żenczykowski 	}
73*1b481fc3SMaciej Żenczykowski 
74*1b481fc3SMaciej Żenczykowski 	if (nlhdr->nlmsg_type == GENL_ID_CTRL) {
75*1b481fc3SMaciej Żenczykowski 		printf(" genl-ctrl\n");
76*1b481fc3SMaciej Żenczykowski 		if (pretty)
77*1b481fc3SMaciej Żenczykowski 			pretty_print_genlmsg(nlhdr, genlctrl_msg_desc,
78*1b481fc3SMaciej Żenczykowski 					     genlctrl_msg_n_desc, 0);
79*1b481fc3SMaciej Żenczykowski 	} else {
80*1b481fc3SMaciej Żenczykowski 		fputc('\n', stdout);
81*1b481fc3SMaciej Żenczykowski 		if (pretty)
82*1b481fc3SMaciej Żenczykowski 			pretty_print_genlmsg(nlhdr, NULL, 0, 0);
83*1b481fc3SMaciej Żenczykowski 	}
84*1b481fc3SMaciej Żenczykowski }
85*1b481fc3SMaciej Żenczykowski 
rtnl_msg_summary(const struct nlmsghdr * nlhdr,bool pretty)86*1b481fc3SMaciej Żenczykowski static void rtnl_msg_summary(const struct nlmsghdr *nlhdr, bool pretty)
87*1b481fc3SMaciej Żenczykowski {
88*1b481fc3SMaciej Żenczykowski 	unsigned int type = nlhdr->nlmsg_type;
89*1b481fc3SMaciej Żenczykowski 
90*1b481fc3SMaciej Żenczykowski 	if (type < rtnl_msg_n_desc && rtnl_msg_desc[type].name)
91*1b481fc3SMaciej Żenczykowski 		printf(" %s\n", rtnl_msg_desc[type].name);
92*1b481fc3SMaciej Żenczykowski 	else
93*1b481fc3SMaciej Żenczykowski 		printf(" type %u\n", type);
94*1b481fc3SMaciej Żenczykowski 
95*1b481fc3SMaciej Żenczykowski 	if (pretty)
96*1b481fc3SMaciej Żenczykowski 		pretty_print_rtnlmsg(nlhdr, 0);
97*1b481fc3SMaciej Żenczykowski }
98*1b481fc3SMaciej Żenczykowski 
debug_msg_summary(const struct nlmsghdr * nlhdr,int ethnl_fam,int nl_fam,bool outgoing,bool pretty)99*1b481fc3SMaciej Żenczykowski static void debug_msg_summary(const struct nlmsghdr *nlhdr, int ethnl_fam,
100*1b481fc3SMaciej Żenczykowski 			      int nl_fam, bool outgoing, bool pretty)
101*1b481fc3SMaciej Żenczykowski {
102*1b481fc3SMaciej Żenczykowski 	printf("    msg length %u", nlhdr->nlmsg_len);
103*1b481fc3SMaciej Żenczykowski 
104*1b481fc3SMaciej Żenczykowski 	if (nlhdr->nlmsg_type < NLMSG_MIN_TYPE) {
105*1b481fc3SMaciej Żenczykowski 		ctrl_msg_summary(nlhdr);
106*1b481fc3SMaciej Żenczykowski 		return;
107*1b481fc3SMaciej Żenczykowski 	}
108*1b481fc3SMaciej Żenczykowski 
109*1b481fc3SMaciej Żenczykowski 	switch(nl_fam) {
110*1b481fc3SMaciej Żenczykowski 	case NETLINK_GENERIC:
111*1b481fc3SMaciej Żenczykowski 		genl_msg_summary(nlhdr, ethnl_fam, outgoing, pretty);
112*1b481fc3SMaciej Żenczykowski 		break;
113*1b481fc3SMaciej Żenczykowski 	case NETLINK_ROUTE:
114*1b481fc3SMaciej Żenczykowski 		rtnl_msg_summary(nlhdr, pretty);
115*1b481fc3SMaciej Żenczykowski 		break;
116*1b481fc3SMaciej Żenczykowski 	default:
117*1b481fc3SMaciej Żenczykowski 		fputc('\n', stdout);
118*1b481fc3SMaciej Żenczykowski 		break;
119*1b481fc3SMaciej Żenczykowski 	}
120*1b481fc3SMaciej Żenczykowski }
121*1b481fc3SMaciej Żenczykowski 
debug_msg(struct nl_socket * nlsk,const void * msg,unsigned int len,bool outgoing)122*1b481fc3SMaciej Żenczykowski static void debug_msg(struct nl_socket *nlsk, const void *msg, unsigned int len,
123*1b481fc3SMaciej Żenczykowski 		      bool outgoing)
124*1b481fc3SMaciej Żenczykowski {
125*1b481fc3SMaciej Żenczykowski 	const char *dirlabel = outgoing ? "sending" : "received";
126*1b481fc3SMaciej Żenczykowski 	uint32_t debug = nlsk->nlctx->ctx->debug;
127*1b481fc3SMaciej Żenczykowski 	const struct nlmsghdr *nlhdr = msg;
128*1b481fc3SMaciej Żenczykowski 	bool summary, dump, pretty;
129*1b481fc3SMaciej Żenczykowski 	const char *nl_fam_label;
130*1b481fc3SMaciej Żenczykowski 	int left = len;
131*1b481fc3SMaciej Żenczykowski 
132*1b481fc3SMaciej Żenczykowski 	summary = debug_on(debug, DEBUG_NL_MSGS);
133*1b481fc3SMaciej Żenczykowski 	dump = debug_on(debug,
134*1b481fc3SMaciej Żenczykowski 			outgoing ? DEBUG_NL_DUMP_SND : DEBUG_NL_DUMP_RCV);
135*1b481fc3SMaciej Żenczykowski 	pretty = debug_on(debug, DEBUG_NL_PRETTY_MSG);
136*1b481fc3SMaciej Żenczykowski 	if (!summary && !dump)
137*1b481fc3SMaciej Żenczykowski 		return;
138*1b481fc3SMaciej Żenczykowski 	switch(nlsk->nl_fam) {
139*1b481fc3SMaciej Żenczykowski 	case NETLINK_GENERIC:
140*1b481fc3SMaciej Żenczykowski 		nl_fam_label = "genetlink";
141*1b481fc3SMaciej Żenczykowski 		break;
142*1b481fc3SMaciej Żenczykowski 	case NETLINK_ROUTE:
143*1b481fc3SMaciej Żenczykowski 		nl_fam_label = "rtnetlink";
144*1b481fc3SMaciej Żenczykowski 		break;
145*1b481fc3SMaciej Żenczykowski 	default:
146*1b481fc3SMaciej Żenczykowski 		nl_fam_label = "netlink";
147*1b481fc3SMaciej Żenczykowski 		break;
148*1b481fc3SMaciej Żenczykowski 	}
149*1b481fc3SMaciej Żenczykowski 	printf("%s %s packet (%u bytes):\n", dirlabel, nl_fam_label, len);
150*1b481fc3SMaciej Żenczykowski 
151*1b481fc3SMaciej Żenczykowski 	while (nlhdr && left > 0 && mnl_nlmsg_ok(nlhdr, left)) {
152*1b481fc3SMaciej Żenczykowski 		if (summary)
153*1b481fc3SMaciej Żenczykowski 			debug_msg_summary(nlhdr, nlsk->nlctx->ethnl_fam,
154*1b481fc3SMaciej Żenczykowski 					  nlsk->nl_fam, outgoing, pretty);
155*1b481fc3SMaciej Żenczykowski 		if (dump)
156*1b481fc3SMaciej Żenczykowski 			mnl_nlmsg_fprintf(stdout, nlhdr, nlhdr->nlmsg_len,
157*1b481fc3SMaciej Żenczykowski 					  GENL_HDRLEN);
158*1b481fc3SMaciej Żenczykowski 
159*1b481fc3SMaciej Żenczykowski 		nlhdr = mnl_nlmsg_next(nlhdr, &left);
160*1b481fc3SMaciej Żenczykowski 	}
161*1b481fc3SMaciej Żenczykowski }
162*1b481fc3SMaciej Żenczykowski 
163*1b481fc3SMaciej Żenczykowski /**
164*1b481fc3SMaciej Żenczykowski  * nlsock_process_ack() - process NLMSG_ERROR message from kernel
165*1b481fc3SMaciej Żenczykowski  * @nlhdr:          pointer to netlink header
166*1b481fc3SMaciej Żenczykowski  * @len:            length of received data (from nlhdr to end of buffer)
167*1b481fc3SMaciej Żenczykowski  * @suppress_nlerr: 0 show all errors, 1 silence -EOPNOTSUPP, 2 silence all
168*1b481fc3SMaciej Żenczykowski  *
169*1b481fc3SMaciej Żenczykowski  * Return: error code extracted from the message
170*1b481fc3SMaciej Żenczykowski  */
nlsock_process_ack(struct nlmsghdr * nlhdr,unsigned long len,unsigned int suppress_nlerr,bool pretty)171*1b481fc3SMaciej Żenczykowski static int nlsock_process_ack(struct nlmsghdr *nlhdr, unsigned long len,
172*1b481fc3SMaciej Żenczykowski 			      unsigned int suppress_nlerr, bool pretty)
173*1b481fc3SMaciej Żenczykowski {
174*1b481fc3SMaciej Żenczykowski 	const struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
175*1b481fc3SMaciej Żenczykowski 	DECLARE_ATTR_TB_INFO(tb);
176*1b481fc3SMaciej Żenczykowski 	unsigned int err_offset = 0;
177*1b481fc3SMaciej Żenczykowski 	unsigned int tlv_offset;
178*1b481fc3SMaciej Żenczykowski 	struct nlmsgerr *nlerr;
179*1b481fc3SMaciej Żenczykowski 	bool silent;
180*1b481fc3SMaciej Żenczykowski 
181*1b481fc3SMaciej Żenczykowski 	if ((len < NLMSG_HDRLEN + sizeof(*nlerr)) || (len < nlhdr->nlmsg_len))
182*1b481fc3SMaciej Żenczykowski 		return -EFAULT;
183*1b481fc3SMaciej Żenczykowski 	nlerr = mnl_nlmsg_get_payload(nlhdr);
184*1b481fc3SMaciej Żenczykowski 	silent = suppress_nlerr >= 2 ||
185*1b481fc3SMaciej Żenczykowski 		(suppress_nlerr && nlerr->error == -EOPNOTSUPP);
186*1b481fc3SMaciej Żenczykowski 	if (silent || !(nlhdr->nlmsg_flags & NLM_F_ACK_TLVS))
187*1b481fc3SMaciej Żenczykowski 		goto tlv_done;
188*1b481fc3SMaciej Żenczykowski 
189*1b481fc3SMaciej Żenczykowski 	tlv_offset = sizeof(*nlerr);
190*1b481fc3SMaciej Żenczykowski 	if (!(nlhdr->nlmsg_flags & NLM_F_CAPPED))
191*1b481fc3SMaciej Żenczykowski 		tlv_offset += MNL_ALIGN(mnl_nlmsg_get_payload_len(&nlerr->msg));
192*1b481fc3SMaciej Żenczykowski 	if (mnl_attr_parse(nlhdr, tlv_offset, attr_cb, &tb_info) < 0)
193*1b481fc3SMaciej Żenczykowski 		goto tlv_done;
194*1b481fc3SMaciej Żenczykowski 
195*1b481fc3SMaciej Żenczykowski 	if (tb[NLMSGERR_ATTR_MSG]) {
196*1b481fc3SMaciej Żenczykowski 		const char *msg = mnl_attr_get_str(tb[NLMSGERR_ATTR_MSG]);
197*1b481fc3SMaciej Żenczykowski 
198*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "netlink %s: %s",
199*1b481fc3SMaciej Żenczykowski 			nlerr->error ? "error" : "warning", msg);
200*1b481fc3SMaciej Żenczykowski 		if (!pretty && tb[NLMSGERR_ATTR_OFFS])
201*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, " (offset %u)",
202*1b481fc3SMaciej Żenczykowski 				mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]));
203*1b481fc3SMaciej Żenczykowski 		fputc('\n', stderr);
204*1b481fc3SMaciej Żenczykowski 	}
205*1b481fc3SMaciej Żenczykowski 	if (tb[NLMSGERR_ATTR_OFFS])
206*1b481fc3SMaciej Żenczykowski 		err_offset = mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]);
207*1b481fc3SMaciej Żenczykowski 
208*1b481fc3SMaciej Żenczykowski tlv_done:
209*1b481fc3SMaciej Żenczykowski 	if (nlerr->error && !silent) {
210*1b481fc3SMaciej Żenczykowski 		errno = -nlerr->error;
211*1b481fc3SMaciej Żenczykowski 		perror("netlink error");
212*1b481fc3SMaciej Żenczykowski 	}
213*1b481fc3SMaciej Żenczykowski 	if (pretty && !(nlhdr->nlmsg_flags & NLM_F_CAPPED) &&
214*1b481fc3SMaciej Żenczykowski 	    nlhdr->nlmsg_len >= NLMSG_HDRLEN + nlerr->msg.nlmsg_len) {
215*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "offending message%s:\n",
216*1b481fc3SMaciej Żenczykowski 			err_offset ? " and attribute" : "");
217*1b481fc3SMaciej Żenczykowski 		pretty_print_genlmsg(&nlerr->msg, ethnl_umsg_desc,
218*1b481fc3SMaciej Żenczykowski 				     ethnl_umsg_n_desc, err_offset);
219*1b481fc3SMaciej Żenczykowski 	}
220*1b481fc3SMaciej Żenczykowski 	return nlerr->error;
221*1b481fc3SMaciej Żenczykowski }
222*1b481fc3SMaciej Żenczykowski 
223*1b481fc3SMaciej Żenczykowski /**
224*1b481fc3SMaciej Żenczykowski  * nlsock_process_reply() - process reply packet(s) from kernel
225*1b481fc3SMaciej Żenczykowski  * @nlsk:     netlink socket to read from
226*1b481fc3SMaciej Żenczykowski  * @reply_cb: callback to process each message
227*1b481fc3SMaciej Żenczykowski  * @data:     pointer passed as argument to @reply_cb callback
228*1b481fc3SMaciej Żenczykowski  *
229*1b481fc3SMaciej Żenczykowski  * Read packets from kernel and pass reply messages to @reply_cb callback
230*1b481fc3SMaciej Żenczykowski  * until an error is encountered or NLMSG_ERR message is received. In the
231*1b481fc3SMaciej Żenczykowski  * latter case, return value is the error code extracted from it.
232*1b481fc3SMaciej Żenczykowski  *
233*1b481fc3SMaciej Żenczykowski  * Return: 0 on success or negative error code
234*1b481fc3SMaciej Żenczykowski  */
nlsock_process_reply(struct nl_socket * nlsk,mnl_cb_t reply_cb,void * data)235*1b481fc3SMaciej Żenczykowski int nlsock_process_reply(struct nl_socket *nlsk, mnl_cb_t reply_cb, void *data)
236*1b481fc3SMaciej Żenczykowski {
237*1b481fc3SMaciej Żenczykowski 	struct nl_msg_buff *msgbuff = &nlsk->msgbuff;
238*1b481fc3SMaciej Żenczykowski 	struct nlmsghdr *nlhdr;
239*1b481fc3SMaciej Żenczykowski 	ssize_t len;
240*1b481fc3SMaciej Żenczykowski 	char *buff;
241*1b481fc3SMaciej Żenczykowski 	int ret;
242*1b481fc3SMaciej Żenczykowski 
243*1b481fc3SMaciej Żenczykowski 	ret = msgbuff_realloc(msgbuff, NLSOCK_RECV_BUFFSIZE);
244*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
245*1b481fc3SMaciej Żenczykowski 		return ret;
246*1b481fc3SMaciej Żenczykowski 	buff = msgbuff->buff;
247*1b481fc3SMaciej Żenczykowski 
248*1b481fc3SMaciej Żenczykowski 	do {
249*1b481fc3SMaciej Żenczykowski 		len = mnl_socket_recvfrom(nlsk->sk, buff, msgbuff->size);
250*1b481fc3SMaciej Żenczykowski 		if (len <= 0)
251*1b481fc3SMaciej Żenczykowski 			return (len ? -EFAULT : 0);
252*1b481fc3SMaciej Żenczykowski 		debug_msg(nlsk, buff, len, false);
253*1b481fc3SMaciej Żenczykowski 		if (len < NLMSG_HDRLEN)
254*1b481fc3SMaciej Żenczykowski 			return -EFAULT;
255*1b481fc3SMaciej Żenczykowski 
256*1b481fc3SMaciej Żenczykowski 		nlhdr = (struct nlmsghdr *)buff;
257*1b481fc3SMaciej Żenczykowski 		if (nlhdr->nlmsg_type == NLMSG_ERROR) {
258*1b481fc3SMaciej Żenczykowski 			unsigned int suppress = nlsk->nlctx->suppress_nlerr;
259*1b481fc3SMaciej Żenczykowski 			bool pretty;
260*1b481fc3SMaciej Żenczykowski 
261*1b481fc3SMaciej Żenczykowski 			pretty = debug_on(nlsk->nlctx->ctx->debug,
262*1b481fc3SMaciej Żenczykowski 					  DEBUG_NL_PRETTY_MSG);
263*1b481fc3SMaciej Żenczykowski 			return nlsock_process_ack(nlhdr, len, suppress, pretty);
264*1b481fc3SMaciej Żenczykowski 		}
265*1b481fc3SMaciej Żenczykowski 
266*1b481fc3SMaciej Żenczykowski 		msgbuff->nlhdr = nlhdr;
267*1b481fc3SMaciej Żenczykowski 		msgbuff->genlhdr = mnl_nlmsg_get_payload(nlhdr);
268*1b481fc3SMaciej Żenczykowski 		msgbuff->payload =
269*1b481fc3SMaciej Żenczykowski 			mnl_nlmsg_get_payload_offset(nlhdr, GENL_HDRLEN);
270*1b481fc3SMaciej Żenczykowski 		ret = mnl_cb_run(buff, len, nlsk->seq, nlsk->port, reply_cb,
271*1b481fc3SMaciej Żenczykowski 				 data);
272*1b481fc3SMaciej Żenczykowski 	} while (ret > 0);
273*1b481fc3SMaciej Żenczykowski 
274*1b481fc3SMaciej Żenczykowski 	return ret;
275*1b481fc3SMaciej Żenczykowski }
276*1b481fc3SMaciej Żenczykowski 
nlsock_prep_get_request(struct nl_socket * nlsk,unsigned int nlcmd,uint16_t hdr_attrtype,u32 flags)277*1b481fc3SMaciej Żenczykowski int nlsock_prep_get_request(struct nl_socket *nlsk, unsigned int nlcmd,
278*1b481fc3SMaciej Żenczykowski 			    uint16_t hdr_attrtype, u32 flags)
279*1b481fc3SMaciej Żenczykowski {
280*1b481fc3SMaciej Żenczykowski 	unsigned int nlm_flags = NLM_F_REQUEST | NLM_F_ACK;
281*1b481fc3SMaciej Żenczykowski 	struct nl_context *nlctx = nlsk->nlctx;
282*1b481fc3SMaciej Żenczykowski 	const char *devname = nlctx->ctx->devname;
283*1b481fc3SMaciej Żenczykowski 	int ret;
284*1b481fc3SMaciej Żenczykowski 
285*1b481fc3SMaciej Żenczykowski 	if (devname && !strcmp(devname, WILDCARD_DEVNAME)) {
286*1b481fc3SMaciej Żenczykowski 		devname = NULL;
287*1b481fc3SMaciej Żenczykowski 		nlm_flags |= NLM_F_DUMP;
288*1b481fc3SMaciej Żenczykowski 	}
289*1b481fc3SMaciej Żenczykowski 	nlctx->is_dump = !devname;
290*1b481fc3SMaciej Żenczykowski 
291*1b481fc3SMaciej Żenczykowski 	ret = msg_init(nlctx, &nlsk->msgbuff, nlcmd, nlm_flags);
292*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
293*1b481fc3SMaciej Żenczykowski 		return ret;
294*1b481fc3SMaciej Żenczykowski 	if (ethnla_fill_header(&nlsk->msgbuff, hdr_attrtype, devname, flags))
295*1b481fc3SMaciej Żenczykowski 		return -EMSGSIZE;
296*1b481fc3SMaciej Żenczykowski 
297*1b481fc3SMaciej Żenczykowski 	return 0;
298*1b481fc3SMaciej Żenczykowski }
299*1b481fc3SMaciej Żenczykowski 
300*1b481fc3SMaciej Żenczykowski #ifndef TEST_ETHTOOL
301*1b481fc3SMaciej Żenczykowski /**
302*1b481fc3SMaciej Żenczykowski  * nlsock_sendmsg() - send a netlink message to kernel
303*1b481fc3SMaciej Żenczykowski  * @nlsk:    netlink socket
304*1b481fc3SMaciej Żenczykowski  * @altbuff: alternative message buffer; if null, use buffer embedded in @nlsk
305*1b481fc3SMaciej Żenczykowski  *
306*1b481fc3SMaciej Żenczykowski  * Return: sent size or negative error code
307*1b481fc3SMaciej Żenczykowski  */
nlsock_sendmsg(struct nl_socket * nlsk,struct nl_msg_buff * altbuff)308*1b481fc3SMaciej Żenczykowski ssize_t nlsock_sendmsg(struct nl_socket *nlsk, struct nl_msg_buff *altbuff)
309*1b481fc3SMaciej Żenczykowski {
310*1b481fc3SMaciej Żenczykowski 	struct nl_msg_buff *msgbuff = altbuff ?: &nlsk->msgbuff;
311*1b481fc3SMaciej Żenczykowski 	struct nlmsghdr *nlhdr = msgbuff->nlhdr;
312*1b481fc3SMaciej Żenczykowski 
313*1b481fc3SMaciej Żenczykowski 	nlhdr->nlmsg_seq = ++nlsk->seq;
314*1b481fc3SMaciej Żenczykowski 	debug_msg(nlsk, msgbuff->buff, nlhdr->nlmsg_len, true);
315*1b481fc3SMaciej Żenczykowski 	return mnl_socket_sendto(nlsk->sk, nlhdr, nlhdr->nlmsg_len);
316*1b481fc3SMaciej Żenczykowski }
317*1b481fc3SMaciej Żenczykowski #endif
318*1b481fc3SMaciej Żenczykowski 
319*1b481fc3SMaciej Żenczykowski /**
320*1b481fc3SMaciej Żenczykowski  * nlsock_send_get_request() - send request and process reply
321*1b481fc3SMaciej Żenczykowski  * @nlsk: netlink socket
322*1b481fc3SMaciej Żenczykowski  * @cb:   callback to process reply message(s)
323*1b481fc3SMaciej Żenczykowski  *
324*1b481fc3SMaciej Żenczykowski  * This simple helper only handles the most common case when the embedded
325*1b481fc3SMaciej Żenczykowski  * message buffer is sent and @cb takes netlink context (struct nl_context)
326*1b481fc3SMaciej Żenczykowski  * as last argument.
327*1b481fc3SMaciej Żenczykowski  */
nlsock_send_get_request(struct nl_socket * nlsk,mnl_cb_t cb)328*1b481fc3SMaciej Żenczykowski int nlsock_send_get_request(struct nl_socket *nlsk, mnl_cb_t cb)
329*1b481fc3SMaciej Żenczykowski {
330*1b481fc3SMaciej Żenczykowski 	int ret;
331*1b481fc3SMaciej Żenczykowski 
332*1b481fc3SMaciej Żenczykowski 	ret = nlsock_sendmsg(nlsk, NULL);
333*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
334*1b481fc3SMaciej Żenczykowski 		goto err;
335*1b481fc3SMaciej Żenczykowski 	ret = nlsock_process_reply(nlsk, cb, nlsk->nlctx);
336*1b481fc3SMaciej Żenczykowski 	if (ret == 0)
337*1b481fc3SMaciej Żenczykowski 		return 0;
338*1b481fc3SMaciej Żenczykowski err:
339*1b481fc3SMaciej Żenczykowski 	return nlsk->nlctx->exit_code ?: 1;
340*1b481fc3SMaciej Żenczykowski }
341*1b481fc3SMaciej Żenczykowski 
342*1b481fc3SMaciej Żenczykowski /**
343*1b481fc3SMaciej Żenczykowski  * nlsock_init() - allocate and initialize netlink socket
344*1b481fc3SMaciej Żenczykowski  * @nlctx:  netlink context
345*1b481fc3SMaciej Żenczykowski  * @__nlsk: store pointer to the allocated socket here
346*1b481fc3SMaciej Żenczykowski  * @nl_fam: netlink family (e.g. NETLINK_GENERIC or NETLINK_ROUTE)
347*1b481fc3SMaciej Żenczykowski  *
348*1b481fc3SMaciej Żenczykowski  * Allocate and initialize netlink socket and its embedded message buffer.
349*1b481fc3SMaciej Żenczykowski  * Cleans up on error, caller is responsible for destroying the socket with
350*1b481fc3SMaciej Żenczykowski  * nlsock_done() on success.
351*1b481fc3SMaciej Żenczykowski  *
352*1b481fc3SMaciej Żenczykowski  * Return: 0 on success or negative error code
353*1b481fc3SMaciej Żenczykowski  */
nlsock_init(struct nl_context * nlctx,struct nl_socket ** __nlsk,int nl_fam)354*1b481fc3SMaciej Żenczykowski int nlsock_init(struct nl_context *nlctx, struct nl_socket **__nlsk, int nl_fam)
355*1b481fc3SMaciej Żenczykowski {
356*1b481fc3SMaciej Żenczykowski 	struct nl_socket *nlsk;
357*1b481fc3SMaciej Żenczykowski 	int val;
358*1b481fc3SMaciej Żenczykowski 	int ret;
359*1b481fc3SMaciej Żenczykowski 
360*1b481fc3SMaciej Żenczykowski 	nlsk = calloc(1, sizeof(*nlsk));
361*1b481fc3SMaciej Żenczykowski 	if (!nlsk)
362*1b481fc3SMaciej Żenczykowski 		return -ENOMEM;
363*1b481fc3SMaciej Żenczykowski 	nlsk->nlctx = nlctx;
364*1b481fc3SMaciej Żenczykowski 	msgbuff_init(&nlsk->msgbuff);
365*1b481fc3SMaciej Żenczykowski 
366*1b481fc3SMaciej Żenczykowski 	ret = -ECONNREFUSED;
367*1b481fc3SMaciej Żenczykowski 	nlsk->sk = mnl_socket_open(nl_fam);
368*1b481fc3SMaciej Żenczykowski 	if (!nlsk->sk)
369*1b481fc3SMaciej Żenczykowski 		goto out_msgbuff;
370*1b481fc3SMaciej Żenczykowski 	val = 1;
371*1b481fc3SMaciej Żenczykowski 	mnl_socket_setsockopt(nlsk->sk, NETLINK_EXT_ACK, &val, sizeof(val));
372*1b481fc3SMaciej Żenczykowski 	ret = mnl_socket_bind(nlsk->sk, 0, MNL_SOCKET_AUTOPID);
373*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
374*1b481fc3SMaciej Żenczykowski 		goto out_close;
375*1b481fc3SMaciej Żenczykowski 	nlsk->port = mnl_socket_get_portid(nlsk->sk);
376*1b481fc3SMaciej Żenczykowski 	nlsk->nl_fam = nl_fam;
377*1b481fc3SMaciej Żenczykowski 
378*1b481fc3SMaciej Żenczykowski 	*__nlsk = nlsk;
379*1b481fc3SMaciej Żenczykowski 	return 0;
380*1b481fc3SMaciej Żenczykowski 
381*1b481fc3SMaciej Żenczykowski out_close:
382*1b481fc3SMaciej Żenczykowski 	if (nlsk->sk)
383*1b481fc3SMaciej Żenczykowski 		mnl_socket_close(nlsk->sk);
384*1b481fc3SMaciej Żenczykowski out_msgbuff:
385*1b481fc3SMaciej Żenczykowski 	msgbuff_done(&nlsk->msgbuff);
386*1b481fc3SMaciej Żenczykowski 	free(nlsk);
387*1b481fc3SMaciej Żenczykowski 	return ret;
388*1b481fc3SMaciej Żenczykowski }
389*1b481fc3SMaciej Żenczykowski 
390*1b481fc3SMaciej Żenczykowski /**
391*1b481fc3SMaciej Żenczykowski  * nlsock_done() - destroy a netlink socket
392*1b481fc3SMaciej Żenczykowski  * @nlsk: netlink socket
393*1b481fc3SMaciej Żenczykowski  *
394*1b481fc3SMaciej Żenczykowski  * Close the socket and free the structure and related data.
395*1b481fc3SMaciej Żenczykowski  */
nlsock_done(struct nl_socket * nlsk)396*1b481fc3SMaciej Żenczykowski void nlsock_done(struct nl_socket *nlsk)
397*1b481fc3SMaciej Żenczykowski {
398*1b481fc3SMaciej Żenczykowski 	if (!nlsk)
399*1b481fc3SMaciej Żenczykowski 		return;
400*1b481fc3SMaciej Żenczykowski 	if (nlsk->sk)
401*1b481fc3SMaciej Żenczykowski 		mnl_socket_close(nlsk->sk);
402*1b481fc3SMaciej Żenczykowski 	msgbuff_done(&nlsk->msgbuff);
403*1b481fc3SMaciej Żenczykowski 	memset(nlsk, '\0', sizeof(*nlsk));
404*1b481fc3SMaciej Żenczykowski 	free(nlsk);
405*1b481fc3SMaciej Żenczykowski }
406