xref: /aosp_15_r20/external/ltp/lib/tst_netlink.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) 2021 Linux Test Project
4*49cdfc7eSAndroid Build Coastguard Worker  */
5*49cdfc7eSAndroid Build Coastguard Worker 
6*49cdfc7eSAndroid Build Coastguard Worker #include <stdlib.h>
7*49cdfc7eSAndroid Build Coastguard Worker #include <limits.h>
8*49cdfc7eSAndroid Build Coastguard Worker #include <asm/types.h>
9*49cdfc7eSAndroid Build Coastguard Worker #include <linux/netlink.h>
10*49cdfc7eSAndroid Build Coastguard Worker #include <linux/rtnetlink.h>
11*49cdfc7eSAndroid Build Coastguard Worker #include <sys/types.h>
12*49cdfc7eSAndroid Build Coastguard Worker #include <sys/socket.h>
13*49cdfc7eSAndroid Build Coastguard Worker #include <sys/poll.h>
14*49cdfc7eSAndroid Build Coastguard Worker #define TST_NO_DEFAULT_MAIN
15*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
16*49cdfc7eSAndroid Build Coastguard Worker #include "tst_netlink.h"
17*49cdfc7eSAndroid Build Coastguard Worker 
18*49cdfc7eSAndroid Build Coastguard Worker struct tst_netlink_context {
19*49cdfc7eSAndroid Build Coastguard Worker 	int socket;
20*49cdfc7eSAndroid Build Coastguard Worker 	pid_t pid;
21*49cdfc7eSAndroid Build Coastguard Worker 	uint32_t seq;
22*49cdfc7eSAndroid Build Coastguard Worker 	size_t bufsize, datalen;
23*49cdfc7eSAndroid Build Coastguard Worker 	char *buffer;
24*49cdfc7eSAndroid Build Coastguard Worker 	struct nlmsghdr *curmsg;
25*49cdfc7eSAndroid Build Coastguard Worker };
26*49cdfc7eSAndroid Build Coastguard Worker 
27*49cdfc7eSAndroid Build Coastguard Worker int tst_netlink_errno;
28*49cdfc7eSAndroid Build Coastguard Worker 
netlink_grow_buffer(const char * file,const int lineno,struct tst_netlink_context * ctx,size_t size)29*49cdfc7eSAndroid Build Coastguard Worker static int netlink_grow_buffer(const char *file, const int lineno,
30*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_netlink_context *ctx, size_t size)
31*49cdfc7eSAndroid Build Coastguard Worker {
32*49cdfc7eSAndroid Build Coastguard Worker 	size_t needed, offset, curlen = NLMSG_ALIGN(ctx->datalen);
33*49cdfc7eSAndroid Build Coastguard Worker 	char *buf;
34*49cdfc7eSAndroid Build Coastguard Worker 
35*49cdfc7eSAndroid Build Coastguard Worker 	if (ctx->bufsize - curlen >= size)
36*49cdfc7eSAndroid Build Coastguard Worker 		return 1;
37*49cdfc7eSAndroid Build Coastguard Worker 
38*49cdfc7eSAndroid Build Coastguard Worker 	needed = size - (ctx->bufsize - curlen);
39*49cdfc7eSAndroid Build Coastguard Worker 	size = ctx->bufsize + (ctx->bufsize > needed ? ctx->bufsize : needed);
40*49cdfc7eSAndroid Build Coastguard Worker 	size = NLMSG_ALIGN(size);
41*49cdfc7eSAndroid Build Coastguard Worker 	buf = safe_realloc(file, lineno, ctx->buffer, size);
42*49cdfc7eSAndroid Build Coastguard Worker 
43*49cdfc7eSAndroid Build Coastguard Worker 	if (!buf)
44*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
45*49cdfc7eSAndroid Build Coastguard Worker 
46*49cdfc7eSAndroid Build Coastguard Worker 	memset(buf + ctx->bufsize, 0, size - ctx->bufsize);
47*49cdfc7eSAndroid Build Coastguard Worker 	offset = ((char *)ctx->curmsg) - ctx->buffer;
48*49cdfc7eSAndroid Build Coastguard Worker 	ctx->buffer = buf;
49*49cdfc7eSAndroid Build Coastguard Worker 	ctx->curmsg = (struct nlmsghdr *)(buf + offset);
50*49cdfc7eSAndroid Build Coastguard Worker 	ctx->bufsize = size;
51*49cdfc7eSAndroid Build Coastguard Worker 
52*49cdfc7eSAndroid Build Coastguard Worker 	return 1;
53*49cdfc7eSAndroid Build Coastguard Worker }
54*49cdfc7eSAndroid Build Coastguard Worker 
tst_netlink_destroy_context(const char * file,const int lineno,struct tst_netlink_context * ctx)55*49cdfc7eSAndroid Build Coastguard Worker void tst_netlink_destroy_context(const char *file, const int lineno,
56*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_netlink_context *ctx)
57*49cdfc7eSAndroid Build Coastguard Worker {
58*49cdfc7eSAndroid Build Coastguard Worker 	if (!ctx)
59*49cdfc7eSAndroid Build Coastguard Worker 		return;
60*49cdfc7eSAndroid Build Coastguard Worker 
61*49cdfc7eSAndroid Build Coastguard Worker 	safe_close(file, lineno, NULL, ctx->socket);
62*49cdfc7eSAndroid Build Coastguard Worker 	free(ctx->buffer);
63*49cdfc7eSAndroid Build Coastguard Worker 	free(ctx);
64*49cdfc7eSAndroid Build Coastguard Worker }
65*49cdfc7eSAndroid Build Coastguard Worker 
tst_netlink_create_context(const char * file,const int lineno,int protocol)66*49cdfc7eSAndroid Build Coastguard Worker struct tst_netlink_context *tst_netlink_create_context(const char *file,
67*49cdfc7eSAndroid Build Coastguard Worker 	const int lineno, int protocol)
68*49cdfc7eSAndroid Build Coastguard Worker {
69*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_netlink_context *ctx;
70*49cdfc7eSAndroid Build Coastguard Worker 	struct sockaddr_nl addr = { .nl_family = AF_NETLINK };
71*49cdfc7eSAndroid Build Coastguard Worker 
72*49cdfc7eSAndroid Build Coastguard Worker 	ctx = safe_malloc(file, lineno, NULL,
73*49cdfc7eSAndroid Build Coastguard Worker 		sizeof(struct tst_netlink_context));
74*49cdfc7eSAndroid Build Coastguard Worker 
75*49cdfc7eSAndroid Build Coastguard Worker 	if (!ctx)
76*49cdfc7eSAndroid Build Coastguard Worker 		return NULL;
77*49cdfc7eSAndroid Build Coastguard Worker 
78*49cdfc7eSAndroid Build Coastguard Worker 	ctx->pid = 0;
79*49cdfc7eSAndroid Build Coastguard Worker 	ctx->seq = 0;
80*49cdfc7eSAndroid Build Coastguard Worker 	ctx->buffer = NULL;
81*49cdfc7eSAndroid Build Coastguard Worker 	ctx->bufsize = 1024;
82*49cdfc7eSAndroid Build Coastguard Worker 	ctx->datalen = 0;
83*49cdfc7eSAndroid Build Coastguard Worker 	ctx->curmsg = NULL;
84*49cdfc7eSAndroid Build Coastguard Worker 	ctx->socket = safe_socket(file, lineno, NULL, AF_NETLINK,
85*49cdfc7eSAndroid Build Coastguard Worker 		SOCK_DGRAM | SOCK_CLOEXEC, protocol);
86*49cdfc7eSAndroid Build Coastguard Worker 
87*49cdfc7eSAndroid Build Coastguard Worker 	if (ctx->socket < 0) {
88*49cdfc7eSAndroid Build Coastguard Worker 		free(ctx);
89*49cdfc7eSAndroid Build Coastguard Worker 		return NULL;
90*49cdfc7eSAndroid Build Coastguard Worker 	}
91*49cdfc7eSAndroid Build Coastguard Worker 
92*49cdfc7eSAndroid Build Coastguard Worker 	if (safe_bind(file, lineno, NULL, ctx->socket, (struct sockaddr *)&addr,
93*49cdfc7eSAndroid Build Coastguard Worker 		sizeof(addr))) {
94*49cdfc7eSAndroid Build Coastguard Worker 		tst_netlink_destroy_context(file, lineno, ctx);
95*49cdfc7eSAndroid Build Coastguard Worker 		return NULL;
96*49cdfc7eSAndroid Build Coastguard Worker 	}
97*49cdfc7eSAndroid Build Coastguard Worker 
98*49cdfc7eSAndroid Build Coastguard Worker 	ctx->buffer = safe_malloc(file, lineno, NULL, ctx->bufsize);
99*49cdfc7eSAndroid Build Coastguard Worker 
100*49cdfc7eSAndroid Build Coastguard Worker 	if (!ctx->buffer) {
101*49cdfc7eSAndroid Build Coastguard Worker 		tst_netlink_destroy_context(file, lineno, ctx);
102*49cdfc7eSAndroid Build Coastguard Worker 		return NULL;
103*49cdfc7eSAndroid Build Coastguard Worker 	}
104*49cdfc7eSAndroid Build Coastguard Worker 
105*49cdfc7eSAndroid Build Coastguard Worker 	memset(ctx->buffer, 0, ctx->bufsize);
106*49cdfc7eSAndroid Build Coastguard Worker 
107*49cdfc7eSAndroid Build Coastguard Worker 	return ctx;
108*49cdfc7eSAndroid Build Coastguard Worker }
109*49cdfc7eSAndroid Build Coastguard Worker 
tst_netlink_free_message(struct tst_netlink_message * msg)110*49cdfc7eSAndroid Build Coastguard Worker void tst_netlink_free_message(struct tst_netlink_message *msg)
111*49cdfc7eSAndroid Build Coastguard Worker {
112*49cdfc7eSAndroid Build Coastguard Worker 	if (!msg)
113*49cdfc7eSAndroid Build Coastguard Worker 		return;
114*49cdfc7eSAndroid Build Coastguard Worker 
115*49cdfc7eSAndroid Build Coastguard Worker 	// all ptr->header and ptr->info pointers point to the same buffer
116*49cdfc7eSAndroid Build Coastguard Worker 	// msg->header is the start of the buffer
117*49cdfc7eSAndroid Build Coastguard Worker 	free(msg->header);
118*49cdfc7eSAndroid Build Coastguard Worker 	free(msg);
119*49cdfc7eSAndroid Build Coastguard Worker }
120*49cdfc7eSAndroid Build Coastguard Worker 
tst_netlink_send(const char * file,const int lineno,struct tst_netlink_context * ctx)121*49cdfc7eSAndroid Build Coastguard Worker int tst_netlink_send(const char *file, const int lineno,
122*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_netlink_context *ctx)
123*49cdfc7eSAndroid Build Coastguard Worker {
124*49cdfc7eSAndroid Build Coastguard Worker 	int ret;
125*49cdfc7eSAndroid Build Coastguard Worker 	struct sockaddr_nl addr = { .nl_family = AF_NETLINK };
126*49cdfc7eSAndroid Build Coastguard Worker 	struct iovec iov;
127*49cdfc7eSAndroid Build Coastguard Worker 	struct msghdr msg = {
128*49cdfc7eSAndroid Build Coastguard Worker 		.msg_name = &addr,
129*49cdfc7eSAndroid Build Coastguard Worker 		.msg_namelen = sizeof(addr),
130*49cdfc7eSAndroid Build Coastguard Worker 		.msg_iov = &iov,
131*49cdfc7eSAndroid Build Coastguard Worker 		.msg_iovlen = 1
132*49cdfc7eSAndroid Build Coastguard Worker 	};
133*49cdfc7eSAndroid Build Coastguard Worker 
134*49cdfc7eSAndroid Build Coastguard Worker 	if (!ctx->curmsg) {
135*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno, TBROK, "%s(): No message to send",
136*49cdfc7eSAndroid Build Coastguard Worker 			__func__);
137*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
138*49cdfc7eSAndroid Build Coastguard Worker 	}
139*49cdfc7eSAndroid Build Coastguard Worker 
140*49cdfc7eSAndroid Build Coastguard Worker 	if (ctx->curmsg->nlmsg_flags & NLM_F_MULTI) {
141*49cdfc7eSAndroid Build Coastguard Worker 		struct nlmsghdr eom = { .nlmsg_type = NLMSG_DONE };
142*49cdfc7eSAndroid Build Coastguard Worker 
143*49cdfc7eSAndroid Build Coastguard Worker 		if (!tst_netlink_add_message(file, lineno, ctx, &eom, NULL, 0))
144*49cdfc7eSAndroid Build Coastguard Worker 			return 0;
145*49cdfc7eSAndroid Build Coastguard Worker 
146*49cdfc7eSAndroid Build Coastguard Worker 		/* NLMSG_DONE message must not have NLM_F_MULTI flag */
147*49cdfc7eSAndroid Build Coastguard Worker 		ctx->curmsg->nlmsg_flags = 0;
148*49cdfc7eSAndroid Build Coastguard Worker 	}
149*49cdfc7eSAndroid Build Coastguard Worker 
150*49cdfc7eSAndroid Build Coastguard Worker 	iov.iov_base = ctx->buffer;
151*49cdfc7eSAndroid Build Coastguard Worker 	iov.iov_len = ctx->datalen;
152*49cdfc7eSAndroid Build Coastguard Worker 	ret = safe_sendmsg(file, lineno, ctx->datalen, ctx->socket, &msg, 0);
153*49cdfc7eSAndroid Build Coastguard Worker 
154*49cdfc7eSAndroid Build Coastguard Worker 	if (ret > 0)
155*49cdfc7eSAndroid Build Coastguard Worker 		ctx->curmsg = NULL;
156*49cdfc7eSAndroid Build Coastguard Worker 
157*49cdfc7eSAndroid Build Coastguard Worker 	return ret;
158*49cdfc7eSAndroid Build Coastguard Worker }
159*49cdfc7eSAndroid Build Coastguard Worker 
tst_netlink_wait(struct tst_netlink_context * ctx)160*49cdfc7eSAndroid Build Coastguard Worker int tst_netlink_wait(struct tst_netlink_context *ctx)
161*49cdfc7eSAndroid Build Coastguard Worker {
162*49cdfc7eSAndroid Build Coastguard Worker 	struct pollfd fdinfo = {
163*49cdfc7eSAndroid Build Coastguard Worker 		.fd = ctx->socket,
164*49cdfc7eSAndroid Build Coastguard Worker 		.events = POLLIN
165*49cdfc7eSAndroid Build Coastguard Worker 	};
166*49cdfc7eSAndroid Build Coastguard Worker 
167*49cdfc7eSAndroid Build Coastguard Worker 	return poll(&fdinfo, 1, 1000);
168*49cdfc7eSAndroid Build Coastguard Worker }
169*49cdfc7eSAndroid Build Coastguard Worker 
tst_netlink_recv(const char * file,const int lineno,struct tst_netlink_context * ctx)170*49cdfc7eSAndroid Build Coastguard Worker struct tst_netlink_message *tst_netlink_recv(const char *file,
171*49cdfc7eSAndroid Build Coastguard Worker 	const int lineno, struct tst_netlink_context *ctx)
172*49cdfc7eSAndroid Build Coastguard Worker {
173*49cdfc7eSAndroid Build Coastguard Worker 	char tmp, *tmpbuf, *buffer = NULL;
174*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_netlink_message *ret;
175*49cdfc7eSAndroid Build Coastguard Worker 	struct nlmsghdr *ptr;
176*49cdfc7eSAndroid Build Coastguard Worker 	size_t retsize, bufsize = 0;
177*49cdfc7eSAndroid Build Coastguard Worker 	ssize_t size;
178*49cdfc7eSAndroid Build Coastguard Worker 	int i, size_left, msgcount;
179*49cdfc7eSAndroid Build Coastguard Worker 
180*49cdfc7eSAndroid Build Coastguard Worker 	/* Each recv() call returns one message, read all pending messages */
181*49cdfc7eSAndroid Build Coastguard Worker 	while (1) {
182*49cdfc7eSAndroid Build Coastguard Worker 		errno = 0;
183*49cdfc7eSAndroid Build Coastguard Worker 		size = recv(ctx->socket, &tmp, 1,
184*49cdfc7eSAndroid Build Coastguard Worker 			MSG_DONTWAIT | MSG_PEEK | MSG_TRUNC);
185*49cdfc7eSAndroid Build Coastguard Worker 
186*49cdfc7eSAndroid Build Coastguard Worker 		if (size < 0) {
187*49cdfc7eSAndroid Build Coastguard Worker 			if (errno != EAGAIN) {
188*49cdfc7eSAndroid Build Coastguard Worker 				tst_brk_(file, lineno, TBROK | TERRNO,
189*49cdfc7eSAndroid Build Coastguard Worker 					"recv() failed");
190*49cdfc7eSAndroid Build Coastguard Worker 			}
191*49cdfc7eSAndroid Build Coastguard Worker 
192*49cdfc7eSAndroid Build Coastguard Worker 			break;
193*49cdfc7eSAndroid Build Coastguard Worker 		}
194*49cdfc7eSAndroid Build Coastguard Worker 
195*49cdfc7eSAndroid Build Coastguard Worker 		tmpbuf = safe_realloc(file, lineno, buffer, bufsize + size);
196*49cdfc7eSAndroid Build Coastguard Worker 
197*49cdfc7eSAndroid Build Coastguard Worker 		if (!tmpbuf)
198*49cdfc7eSAndroid Build Coastguard Worker 			break;
199*49cdfc7eSAndroid Build Coastguard Worker 
200*49cdfc7eSAndroid Build Coastguard Worker 		buffer = tmpbuf;
201*49cdfc7eSAndroid Build Coastguard Worker 		size = safe_recv(file, lineno, size, ctx->socket,
202*49cdfc7eSAndroid Build Coastguard Worker 			buffer + bufsize, size, 0);
203*49cdfc7eSAndroid Build Coastguard Worker 
204*49cdfc7eSAndroid Build Coastguard Worker 		if (size < 0)
205*49cdfc7eSAndroid Build Coastguard Worker 			break;
206*49cdfc7eSAndroid Build Coastguard Worker 
207*49cdfc7eSAndroid Build Coastguard Worker 		bufsize += size;
208*49cdfc7eSAndroid Build Coastguard Worker 	}
209*49cdfc7eSAndroid Build Coastguard Worker 
210*49cdfc7eSAndroid Build Coastguard Worker 	if (!bufsize) {
211*49cdfc7eSAndroid Build Coastguard Worker 		free(buffer);
212*49cdfc7eSAndroid Build Coastguard Worker 		return NULL;
213*49cdfc7eSAndroid Build Coastguard Worker 	}
214*49cdfc7eSAndroid Build Coastguard Worker 
215*49cdfc7eSAndroid Build Coastguard Worker 	ptr = (struct nlmsghdr *)buffer;
216*49cdfc7eSAndroid Build Coastguard Worker 	size_left = bufsize;
217*49cdfc7eSAndroid Build Coastguard Worker 	msgcount = 0;
218*49cdfc7eSAndroid Build Coastguard Worker 
219*49cdfc7eSAndroid Build Coastguard Worker 	for (; size_left > 0 && NLMSG_OK(ptr, size_left); msgcount++)
220*49cdfc7eSAndroid Build Coastguard Worker 		ptr = NLMSG_NEXT(ptr, size_left);
221*49cdfc7eSAndroid Build Coastguard Worker 
222*49cdfc7eSAndroid Build Coastguard Worker 	retsize = (msgcount + 1) * sizeof(struct tst_netlink_message);
223*49cdfc7eSAndroid Build Coastguard Worker 	ret = safe_malloc(file, lineno, NULL, retsize);
224*49cdfc7eSAndroid Build Coastguard Worker 
225*49cdfc7eSAndroid Build Coastguard Worker 	if (!ret) {
226*49cdfc7eSAndroid Build Coastguard Worker 		free(buffer);
227*49cdfc7eSAndroid Build Coastguard Worker 		return NULL;
228*49cdfc7eSAndroid Build Coastguard Worker 	}
229*49cdfc7eSAndroid Build Coastguard Worker 
230*49cdfc7eSAndroid Build Coastguard Worker 	memset(ret, 0, retsize);
231*49cdfc7eSAndroid Build Coastguard Worker 	ptr = (struct nlmsghdr *)buffer;
232*49cdfc7eSAndroid Build Coastguard Worker 	size_left = bufsize;
233*49cdfc7eSAndroid Build Coastguard Worker 
234*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < msgcount; i++, ptr = NLMSG_NEXT(ptr, size_left)) {
235*49cdfc7eSAndroid Build Coastguard Worker 		ret[i].header = ptr;
236*49cdfc7eSAndroid Build Coastguard Worker 		ret[i].payload = NLMSG_DATA(ptr);
237*49cdfc7eSAndroid Build Coastguard Worker 		ret[i].payload_size = NLMSG_PAYLOAD(ptr, 0);
238*49cdfc7eSAndroid Build Coastguard Worker 
239*49cdfc7eSAndroid Build Coastguard Worker 		if (ptr->nlmsg_type == NLMSG_ERROR)
240*49cdfc7eSAndroid Build Coastguard Worker 			ret[i].err = NLMSG_DATA(ptr);
241*49cdfc7eSAndroid Build Coastguard Worker 	}
242*49cdfc7eSAndroid Build Coastguard Worker 
243*49cdfc7eSAndroid Build Coastguard Worker 	return ret;
244*49cdfc7eSAndroid Build Coastguard Worker }
245*49cdfc7eSAndroid Build Coastguard Worker 
tst_netlink_add_message(const char * file,const int lineno,struct tst_netlink_context * ctx,const struct nlmsghdr * header,const void * payload,size_t payload_size)246*49cdfc7eSAndroid Build Coastguard Worker int tst_netlink_add_message(const char *file, const int lineno,
247*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_netlink_context *ctx, const struct nlmsghdr *header,
248*49cdfc7eSAndroid Build Coastguard Worker 	const void *payload, size_t payload_size)
249*49cdfc7eSAndroid Build Coastguard Worker {
250*49cdfc7eSAndroid Build Coastguard Worker 	size_t size;
251*49cdfc7eSAndroid Build Coastguard Worker 	unsigned int extra_flags = 0;
252*49cdfc7eSAndroid Build Coastguard Worker 
253*49cdfc7eSAndroid Build Coastguard Worker 	if (!netlink_grow_buffer(file, lineno, ctx, NLMSG_SPACE(payload_size)))
254*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
255*49cdfc7eSAndroid Build Coastguard Worker 
256*49cdfc7eSAndroid Build Coastguard Worker 	if (!ctx->curmsg) {
257*49cdfc7eSAndroid Build Coastguard Worker 		/*
258*49cdfc7eSAndroid Build Coastguard Worker 		 * datalen may hold the size of last sent message for ACK
259*49cdfc7eSAndroid Build Coastguard Worker 		 * checking, reset it back to 0 here
260*49cdfc7eSAndroid Build Coastguard Worker 		 */
261*49cdfc7eSAndroid Build Coastguard Worker 		ctx->datalen = 0;
262*49cdfc7eSAndroid Build Coastguard Worker 		ctx->curmsg = (struct nlmsghdr *)ctx->buffer;
263*49cdfc7eSAndroid Build Coastguard Worker 	} else {
264*49cdfc7eSAndroid Build Coastguard Worker 		size = NLMSG_ALIGN(ctx->curmsg->nlmsg_len);
265*49cdfc7eSAndroid Build Coastguard Worker 
266*49cdfc7eSAndroid Build Coastguard Worker 		extra_flags = NLM_F_MULTI;
267*49cdfc7eSAndroid Build Coastguard Worker 		ctx->curmsg->nlmsg_flags |= extra_flags;
268*49cdfc7eSAndroid Build Coastguard Worker 		ctx->curmsg = NLMSG_NEXT(ctx->curmsg, size);
269*49cdfc7eSAndroid Build Coastguard Worker 		ctx->datalen = NLMSG_ALIGN(ctx->datalen);
270*49cdfc7eSAndroid Build Coastguard Worker 	}
271*49cdfc7eSAndroid Build Coastguard Worker 
272*49cdfc7eSAndroid Build Coastguard Worker 	*ctx->curmsg = *header;
273*49cdfc7eSAndroid Build Coastguard Worker 	ctx->curmsg->nlmsg_len = NLMSG_LENGTH(payload_size);
274*49cdfc7eSAndroid Build Coastguard Worker 	ctx->curmsg->nlmsg_flags |= extra_flags;
275*49cdfc7eSAndroid Build Coastguard Worker 	ctx->curmsg->nlmsg_seq = ctx->seq++;
276*49cdfc7eSAndroid Build Coastguard Worker 	ctx->curmsg->nlmsg_pid = ctx->pid;
277*49cdfc7eSAndroid Build Coastguard Worker 
278*49cdfc7eSAndroid Build Coastguard Worker 	if (payload_size)
279*49cdfc7eSAndroid Build Coastguard Worker 		memcpy(NLMSG_DATA(ctx->curmsg), payload, payload_size);
280*49cdfc7eSAndroid Build Coastguard Worker 
281*49cdfc7eSAndroid Build Coastguard Worker 	ctx->datalen += ctx->curmsg->nlmsg_len;
282*49cdfc7eSAndroid Build Coastguard Worker 
283*49cdfc7eSAndroid Build Coastguard Worker 	return 1;
284*49cdfc7eSAndroid Build Coastguard Worker }
285*49cdfc7eSAndroid Build Coastguard Worker 
tst_netlink_add_attr(const char * file,const int lineno,struct tst_netlink_context * ctx,unsigned short type,const void * data,unsigned short len)286*49cdfc7eSAndroid Build Coastguard Worker int tst_netlink_add_attr(const char *file, const int lineno,
287*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_netlink_context *ctx, unsigned short type,
288*49cdfc7eSAndroid Build Coastguard Worker 	const void *data, unsigned short len)
289*49cdfc7eSAndroid Build Coastguard Worker {
290*49cdfc7eSAndroid Build Coastguard Worker 	size_t size = NLA_HDRLEN + NLA_ALIGN(len);
291*49cdfc7eSAndroid Build Coastguard Worker 	struct nlattr *attr;
292*49cdfc7eSAndroid Build Coastguard Worker 
293*49cdfc7eSAndroid Build Coastguard Worker 	if (!ctx->curmsg) {
294*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno, TBROK,
295*49cdfc7eSAndroid Build Coastguard Worker 			"%s(): No message to add attributes to", __func__);
296*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
297*49cdfc7eSAndroid Build Coastguard Worker 	}
298*49cdfc7eSAndroid Build Coastguard Worker 
299*49cdfc7eSAndroid Build Coastguard Worker 	if (!netlink_grow_buffer(file, lineno, ctx, size))
300*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
301*49cdfc7eSAndroid Build Coastguard Worker 
302*49cdfc7eSAndroid Build Coastguard Worker 	size = NLMSG_ALIGN(ctx->curmsg->nlmsg_len);
303*49cdfc7eSAndroid Build Coastguard Worker 	attr = (struct nlattr *)(((char *)ctx->curmsg) + size);
304*49cdfc7eSAndroid Build Coastguard Worker 	attr->nla_type = type;
305*49cdfc7eSAndroid Build Coastguard Worker 	attr->nla_len = NLA_HDRLEN + len;
306*49cdfc7eSAndroid Build Coastguard Worker 	memcpy(((char *)attr) + NLA_HDRLEN, data, len);
307*49cdfc7eSAndroid Build Coastguard Worker 	ctx->curmsg->nlmsg_len = size + attr->nla_len;
308*49cdfc7eSAndroid Build Coastguard Worker 	ctx->datalen = NLMSG_ALIGN(ctx->datalen) + attr->nla_len;
309*49cdfc7eSAndroid Build Coastguard Worker 
310*49cdfc7eSAndroid Build Coastguard Worker 	return 1;
311*49cdfc7eSAndroid Build Coastguard Worker }
312*49cdfc7eSAndroid Build Coastguard Worker 
tst_netlink_add_attr_string(const char * file,const int lineno,struct tst_netlink_context * ctx,unsigned short type,const char * data)313*49cdfc7eSAndroid Build Coastguard Worker int tst_netlink_add_attr_string(const char *file, const int lineno,
314*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_netlink_context *ctx, unsigned short type,
315*49cdfc7eSAndroid Build Coastguard Worker 	const char *data)
316*49cdfc7eSAndroid Build Coastguard Worker {
317*49cdfc7eSAndroid Build Coastguard Worker 	return tst_netlink_add_attr(file, lineno, ctx, type, data,
318*49cdfc7eSAndroid Build Coastguard Worker 		strlen(data) + 1);
319*49cdfc7eSAndroid Build Coastguard Worker }
320*49cdfc7eSAndroid Build Coastguard Worker 
tst_netlink_add_attr_list(const char * file,const int lineno,struct tst_netlink_context * ctx,const struct tst_netlink_attr_list * list)321*49cdfc7eSAndroid Build Coastguard Worker int tst_netlink_add_attr_list(const char *file, const int lineno,
322*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_netlink_context *ctx,
323*49cdfc7eSAndroid Build Coastguard Worker 	const struct tst_netlink_attr_list *list)
324*49cdfc7eSAndroid Build Coastguard Worker {
325*49cdfc7eSAndroid Build Coastguard Worker 	int i, ret;
326*49cdfc7eSAndroid Build Coastguard Worker 	size_t offset;
327*49cdfc7eSAndroid Build Coastguard Worker 
328*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; list[i].len >= 0; i++) {
329*49cdfc7eSAndroid Build Coastguard Worker 		if (list[i].len > USHRT_MAX) {
330*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk_(file, lineno, TBROK,
331*49cdfc7eSAndroid Build Coastguard Worker 				"%s(): Attribute value too long", __func__);
332*49cdfc7eSAndroid Build Coastguard Worker 			return -1;
333*49cdfc7eSAndroid Build Coastguard Worker 		}
334*49cdfc7eSAndroid Build Coastguard Worker 
335*49cdfc7eSAndroid Build Coastguard Worker 		offset = NLMSG_ALIGN(ctx->datalen);
336*49cdfc7eSAndroid Build Coastguard Worker 		ret = tst_netlink_add_attr(file, lineno, ctx, list[i].type,
337*49cdfc7eSAndroid Build Coastguard Worker 			list[i].data, list[i].len);
338*49cdfc7eSAndroid Build Coastguard Worker 
339*49cdfc7eSAndroid Build Coastguard Worker 		if (!ret)
340*49cdfc7eSAndroid Build Coastguard Worker 			return -1;
341*49cdfc7eSAndroid Build Coastguard Worker 
342*49cdfc7eSAndroid Build Coastguard Worker 		if (list[i].sublist) {
343*49cdfc7eSAndroid Build Coastguard Worker 			struct rtattr *attr;
344*49cdfc7eSAndroid Build Coastguard Worker 
345*49cdfc7eSAndroid Build Coastguard Worker 			ret = tst_netlink_add_attr_list(file, lineno, ctx,
346*49cdfc7eSAndroid Build Coastguard Worker 				list[i].sublist);
347*49cdfc7eSAndroid Build Coastguard Worker 
348*49cdfc7eSAndroid Build Coastguard Worker 			if (ret < 0)
349*49cdfc7eSAndroid Build Coastguard Worker 				return ret;
350*49cdfc7eSAndroid Build Coastguard Worker 
351*49cdfc7eSAndroid Build Coastguard Worker 			attr = (struct rtattr *)(ctx->buffer + offset);
352*49cdfc7eSAndroid Build Coastguard Worker 
353*49cdfc7eSAndroid Build Coastguard Worker 			if (ctx->datalen - offset > USHRT_MAX) {
354*49cdfc7eSAndroid Build Coastguard Worker 				tst_brk_(file, lineno, TBROK,
355*49cdfc7eSAndroid Build Coastguard Worker 					"%s(): Sublist too long", __func__);
356*49cdfc7eSAndroid Build Coastguard Worker 				return -1;
357*49cdfc7eSAndroid Build Coastguard Worker 			}
358*49cdfc7eSAndroid Build Coastguard Worker 
359*49cdfc7eSAndroid Build Coastguard Worker 			attr->rta_len = ctx->datalen - offset;
360*49cdfc7eSAndroid Build Coastguard Worker 		}
361*49cdfc7eSAndroid Build Coastguard Worker 	}
362*49cdfc7eSAndroid Build Coastguard Worker 
363*49cdfc7eSAndroid Build Coastguard Worker 	return i;
364*49cdfc7eSAndroid Build Coastguard Worker }
365*49cdfc7eSAndroid Build Coastguard Worker 
tst_rtnl_add_attr(const char * file,const int lineno,struct tst_netlink_context * ctx,unsigned short type,const void * data,unsigned short len)366*49cdfc7eSAndroid Build Coastguard Worker int tst_rtnl_add_attr(const char *file, const int lineno,
367*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_netlink_context *ctx, unsigned short type,
368*49cdfc7eSAndroid Build Coastguard Worker 	const void *data, unsigned short len)
369*49cdfc7eSAndroid Build Coastguard Worker {
370*49cdfc7eSAndroid Build Coastguard Worker 	size_t size;
371*49cdfc7eSAndroid Build Coastguard Worker 	struct rtattr *attr;
372*49cdfc7eSAndroid Build Coastguard Worker 
373*49cdfc7eSAndroid Build Coastguard Worker 	if (!ctx->curmsg) {
374*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno, TBROK,
375*49cdfc7eSAndroid Build Coastguard Worker 			"%s(): No message to add attributes to", __func__);
376*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
377*49cdfc7eSAndroid Build Coastguard Worker 	}
378*49cdfc7eSAndroid Build Coastguard Worker 
379*49cdfc7eSAndroid Build Coastguard Worker 	if (!netlink_grow_buffer(file, lineno, ctx, RTA_SPACE(len)))
380*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
381*49cdfc7eSAndroid Build Coastguard Worker 
382*49cdfc7eSAndroid Build Coastguard Worker 	size = NLMSG_ALIGN(ctx->curmsg->nlmsg_len);
383*49cdfc7eSAndroid Build Coastguard Worker 	attr = (struct rtattr *)(((char *)ctx->curmsg) + size);
384*49cdfc7eSAndroid Build Coastguard Worker 	attr->rta_type = type;
385*49cdfc7eSAndroid Build Coastguard Worker 	attr->rta_len = RTA_LENGTH(len);
386*49cdfc7eSAndroid Build Coastguard Worker 	memcpy(RTA_DATA(attr), data, len);
387*49cdfc7eSAndroid Build Coastguard Worker 	ctx->curmsg->nlmsg_len = size + attr->rta_len;
388*49cdfc7eSAndroid Build Coastguard Worker 	ctx->datalen = NLMSG_ALIGN(ctx->datalen) + attr->rta_len;
389*49cdfc7eSAndroid Build Coastguard Worker 
390*49cdfc7eSAndroid Build Coastguard Worker 	return 1;
391*49cdfc7eSAndroid Build Coastguard Worker }
392*49cdfc7eSAndroid Build Coastguard Worker 
tst_rtnl_add_attr_string(const char * file,const int lineno,struct tst_netlink_context * ctx,unsigned short type,const char * data)393*49cdfc7eSAndroid Build Coastguard Worker int tst_rtnl_add_attr_string(const char *file, const int lineno,
394*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_netlink_context *ctx, unsigned short type,
395*49cdfc7eSAndroid Build Coastguard Worker 	const char *data)
396*49cdfc7eSAndroid Build Coastguard Worker {
397*49cdfc7eSAndroid Build Coastguard Worker 	return tst_rtnl_add_attr(file, lineno, ctx, type, data,
398*49cdfc7eSAndroid Build Coastguard Worker 		strlen(data) + 1);
399*49cdfc7eSAndroid Build Coastguard Worker }
400*49cdfc7eSAndroid Build Coastguard Worker 
tst_rtnl_add_attr_list(const char * file,const int lineno,struct tst_netlink_context * ctx,const struct tst_netlink_attr_list * list)401*49cdfc7eSAndroid Build Coastguard Worker int tst_rtnl_add_attr_list(const char *file, const int lineno,
402*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_netlink_context *ctx,
403*49cdfc7eSAndroid Build Coastguard Worker 	const struct tst_netlink_attr_list *list)
404*49cdfc7eSAndroid Build Coastguard Worker {
405*49cdfc7eSAndroid Build Coastguard Worker 	int i, ret;
406*49cdfc7eSAndroid Build Coastguard Worker 	size_t offset;
407*49cdfc7eSAndroid Build Coastguard Worker 
408*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; list[i].len >= 0; i++) {
409*49cdfc7eSAndroid Build Coastguard Worker 		if (list[i].len > USHRT_MAX) {
410*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk_(file, lineno, TBROK,
411*49cdfc7eSAndroid Build Coastguard Worker 				"%s(): Attribute value too long", __func__);
412*49cdfc7eSAndroid Build Coastguard Worker 			return -1;
413*49cdfc7eSAndroid Build Coastguard Worker 		}
414*49cdfc7eSAndroid Build Coastguard Worker 
415*49cdfc7eSAndroid Build Coastguard Worker 		offset = NLMSG_ALIGN(ctx->datalen);
416*49cdfc7eSAndroid Build Coastguard Worker 		ret = tst_rtnl_add_attr(file, lineno, ctx, list[i].type,
417*49cdfc7eSAndroid Build Coastguard Worker 			list[i].data, list[i].len);
418*49cdfc7eSAndroid Build Coastguard Worker 
419*49cdfc7eSAndroid Build Coastguard Worker 		if (!ret)
420*49cdfc7eSAndroid Build Coastguard Worker 			return -1;
421*49cdfc7eSAndroid Build Coastguard Worker 
422*49cdfc7eSAndroid Build Coastguard Worker 		if (list[i].sublist) {
423*49cdfc7eSAndroid Build Coastguard Worker 			struct rtattr *attr;
424*49cdfc7eSAndroid Build Coastguard Worker 
425*49cdfc7eSAndroid Build Coastguard Worker 			ret = tst_rtnl_add_attr_list(file, lineno, ctx,
426*49cdfc7eSAndroid Build Coastguard Worker 				list[i].sublist);
427*49cdfc7eSAndroid Build Coastguard Worker 
428*49cdfc7eSAndroid Build Coastguard Worker 			if (ret < 0)
429*49cdfc7eSAndroid Build Coastguard Worker 				return ret;
430*49cdfc7eSAndroid Build Coastguard Worker 
431*49cdfc7eSAndroid Build Coastguard Worker 			attr = (struct rtattr *)(ctx->buffer + offset);
432*49cdfc7eSAndroid Build Coastguard Worker 
433*49cdfc7eSAndroid Build Coastguard Worker 			if (ctx->datalen - offset > USHRT_MAX) {
434*49cdfc7eSAndroid Build Coastguard Worker 				tst_brk_(file, lineno, TBROK,
435*49cdfc7eSAndroid Build Coastguard Worker 					"%s(): Sublist too long", __func__);
436*49cdfc7eSAndroid Build Coastguard Worker 				return -1;
437*49cdfc7eSAndroid Build Coastguard Worker 			}
438*49cdfc7eSAndroid Build Coastguard Worker 
439*49cdfc7eSAndroid Build Coastguard Worker 			attr->rta_len = ctx->datalen - offset;
440*49cdfc7eSAndroid Build Coastguard Worker 		}
441*49cdfc7eSAndroid Build Coastguard Worker 	}
442*49cdfc7eSAndroid Build Coastguard Worker 
443*49cdfc7eSAndroid Build Coastguard Worker 	return i;
444*49cdfc7eSAndroid Build Coastguard Worker }
445*49cdfc7eSAndroid Build Coastguard Worker 
tst_netlink_check_acks(const char * file,const int lineno,struct tst_netlink_context * ctx,struct tst_netlink_message * res)446*49cdfc7eSAndroid Build Coastguard Worker int tst_netlink_check_acks(const char *file, const int lineno,
447*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_netlink_context *ctx, struct tst_netlink_message *res)
448*49cdfc7eSAndroid Build Coastguard Worker {
449*49cdfc7eSAndroid Build Coastguard Worker 	struct nlmsghdr *msg = (struct nlmsghdr *)ctx->buffer;
450*49cdfc7eSAndroid Build Coastguard Worker 	int size_left = ctx->datalen;
451*49cdfc7eSAndroid Build Coastguard Worker 
452*49cdfc7eSAndroid Build Coastguard Worker 	for (; size_left > 0 && NLMSG_OK(msg, size_left);
453*49cdfc7eSAndroid Build Coastguard Worker 		msg = NLMSG_NEXT(msg, size_left)) {
454*49cdfc7eSAndroid Build Coastguard Worker 
455*49cdfc7eSAndroid Build Coastguard Worker 		if (!(msg->nlmsg_flags & NLM_F_ACK))
456*49cdfc7eSAndroid Build Coastguard Worker 			continue;
457*49cdfc7eSAndroid Build Coastguard Worker 
458*49cdfc7eSAndroid Build Coastguard Worker 		while (res->header && !(res->err && res->err->error) &&
459*49cdfc7eSAndroid Build Coastguard Worker 			res->header->nlmsg_seq != msg->nlmsg_seq)
460*49cdfc7eSAndroid Build Coastguard Worker 			res++;
461*49cdfc7eSAndroid Build Coastguard Worker 
462*49cdfc7eSAndroid Build Coastguard Worker 		if (res->err && res->err->error) {
463*49cdfc7eSAndroid Build Coastguard Worker 			tst_netlink_errno = -res->err->error;
464*49cdfc7eSAndroid Build Coastguard Worker 			return 0;
465*49cdfc7eSAndroid Build Coastguard Worker 		}
466*49cdfc7eSAndroid Build Coastguard Worker 
467*49cdfc7eSAndroid Build Coastguard Worker 		if (!res->header || res->header->nlmsg_seq != msg->nlmsg_seq) {
468*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk_(file, lineno, TBROK,
469*49cdfc7eSAndroid Build Coastguard Worker 				"No ACK found for Netlink message %u",
470*49cdfc7eSAndroid Build Coastguard Worker 				msg->nlmsg_seq);
471*49cdfc7eSAndroid Build Coastguard Worker 			return 0;
472*49cdfc7eSAndroid Build Coastguard Worker 		}
473*49cdfc7eSAndroid Build Coastguard Worker 	}
474*49cdfc7eSAndroid Build Coastguard Worker 
475*49cdfc7eSAndroid Build Coastguard Worker 	return 1;
476*49cdfc7eSAndroid Build Coastguard Worker }
477*49cdfc7eSAndroid Build Coastguard Worker 
tst_netlink_send_validate(const char * file,const int lineno,struct tst_netlink_context * ctx)478*49cdfc7eSAndroid Build Coastguard Worker int tst_netlink_send_validate(const char *file, const int lineno,
479*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_netlink_context *ctx)
480*49cdfc7eSAndroid Build Coastguard Worker {
481*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_netlink_message *response;
482*49cdfc7eSAndroid Build Coastguard Worker 	int ret;
483*49cdfc7eSAndroid Build Coastguard Worker 
484*49cdfc7eSAndroid Build Coastguard Worker 	tst_netlink_errno = 0;
485*49cdfc7eSAndroid Build Coastguard Worker 
486*49cdfc7eSAndroid Build Coastguard Worker 	if (tst_netlink_send(file, lineno, ctx) <= 0)
487*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
488*49cdfc7eSAndroid Build Coastguard Worker 
489*49cdfc7eSAndroid Build Coastguard Worker 	tst_netlink_wait(ctx);
490*49cdfc7eSAndroid Build Coastguard Worker 	response = tst_netlink_recv(file, lineno, ctx);
491*49cdfc7eSAndroid Build Coastguard Worker 
492*49cdfc7eSAndroid Build Coastguard Worker 	if (!response)
493*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
494*49cdfc7eSAndroid Build Coastguard Worker 
495*49cdfc7eSAndroid Build Coastguard Worker 	ret = tst_netlink_check_acks(file, lineno, ctx, response);
496*49cdfc7eSAndroid Build Coastguard Worker 	tst_netlink_free_message(response);
497*49cdfc7eSAndroid Build Coastguard Worker 
498*49cdfc7eSAndroid Build Coastguard Worker 	return ret;
499*49cdfc7eSAndroid Build Coastguard Worker }
500