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