xref: /OK3568_Linux_fs/app/forlinx/quectelCM/libmnl/nlmsg.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify
5*4882a593Smuzhiyun  * it under the terms of the GNU Lesser General Public License as published
6*4882a593Smuzhiyun  * by the Free Software Foundation; either version 2.1 of the License, or
7*4882a593Smuzhiyun  * (at your option) any later version.
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun #include <stdbool.h>
10*4882a593Smuzhiyun #include <stdio.h>
11*4882a593Smuzhiyun #include <stdlib.h>
12*4882a593Smuzhiyun #include <ctype.h>
13*4882a593Smuzhiyun #include <errno.h>
14*4882a593Smuzhiyun #include <string.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include "libmnl.h"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun /**
19*4882a593Smuzhiyun  * \defgroup nlmsg Netlink message helpers
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * Netlink message:
22*4882a593Smuzhiyun  * \verbatim
23*4882a593Smuzhiyun 	|<----------------- 4 bytes ------------------->|
24*4882a593Smuzhiyun 	|<----- 2 bytes ------>|<------- 2 bytes ------>|
25*4882a593Smuzhiyun 	|-----------------------------------------------|
26*4882a593Smuzhiyun 	|      Message length (including header)        |
27*4882a593Smuzhiyun 	|-----------------------------------------------|
28*4882a593Smuzhiyun 	|     Message type     |     Message flags      |
29*4882a593Smuzhiyun 	|-----------------------------------------------|
30*4882a593Smuzhiyun 	|           Message sequence number             |
31*4882a593Smuzhiyun 	|-----------------------------------------------|
32*4882a593Smuzhiyun 	|                 Netlink PortID                |
33*4882a593Smuzhiyun 	|-----------------------------------------------|
34*4882a593Smuzhiyun 	|                                               |
35*4882a593Smuzhiyun 	.                   Payload                     .
36*4882a593Smuzhiyun 	|_______________________________________________|
37*4882a593Smuzhiyun \endverbatim
38*4882a593Smuzhiyun  *
39*4882a593Smuzhiyun  * There is usually an extra header after the the Netlink header (at the
40*4882a593Smuzhiyun  * beginning of the payload). This extra header is specific of the Netlink
41*4882a593Smuzhiyun  * subsystem. After this extra header, it comes the sequence of attributes
42*4882a593Smuzhiyun  * that are expressed in Type-Length-Value (TLV) format.
43*4882a593Smuzhiyun  *
44*4882a593Smuzhiyun  * @{
45*4882a593Smuzhiyun  */
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /**
48*4882a593Smuzhiyun  * mnl_nlmsg_size - calculate the size of Netlink message (without alignment)
49*4882a593Smuzhiyun  * \param len length of the Netlink payload
50*4882a593Smuzhiyun  *
51*4882a593Smuzhiyun  * This function returns the size of a netlink message (header plus payload)
52*4882a593Smuzhiyun  * without alignment.
53*4882a593Smuzhiyun  */
mnl_nlmsg_size(size_t len)54*4882a593Smuzhiyun size_t mnl_nlmsg_size(size_t len)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	return len + MNL_NLMSG_HDRLEN;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun /**
60*4882a593Smuzhiyun  * mnl_nlmsg_get_payload_len - get the length of the Netlink payload
61*4882a593Smuzhiyun  * \param nlh pointer to the header of the Netlink message
62*4882a593Smuzhiyun  *
63*4882a593Smuzhiyun  * This function returns the Length of the netlink payload, ie. the length
64*4882a593Smuzhiyun  * of the full message minus the size of the Netlink header.
65*4882a593Smuzhiyun  */
mnl_nlmsg_get_payload_len(const struct nlmsghdr * nlh)66*4882a593Smuzhiyun size_t mnl_nlmsg_get_payload_len(const struct nlmsghdr *nlh)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	return nlh->nlmsg_len - MNL_NLMSG_HDRLEN;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun /**
72*4882a593Smuzhiyun  * mnl_nlmsg_put_header - reserve and prepare room for Netlink header
73*4882a593Smuzhiyun  * \param buf memory already allocated to store the Netlink header
74*4882a593Smuzhiyun  *
75*4882a593Smuzhiyun  * This function sets to zero the room that is required to put the Netlink
76*4882a593Smuzhiyun  * header in the memory buffer passed as parameter. This function also
77*4882a593Smuzhiyun  * initializes the nlmsg_len field to the size of the Netlink header. This
78*4882a593Smuzhiyun  * function returns a pointer to the Netlink header structure.
79*4882a593Smuzhiyun  */
mnl_nlmsg_put_header(void * buf)80*4882a593Smuzhiyun struct nlmsghdr *mnl_nlmsg_put_header(void *buf)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	int len = MNL_ALIGN(sizeof(struct nlmsghdr));
83*4882a593Smuzhiyun 	struct nlmsghdr *nlh = buf;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	memset(buf, 0, len);
86*4882a593Smuzhiyun 	nlh->nlmsg_len = len;
87*4882a593Smuzhiyun 	return nlh;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun /**
91*4882a593Smuzhiyun  * mnl_nlmsg_put_extra_header - reserve and prepare room for an extra header
92*4882a593Smuzhiyun  * \param nlh pointer to Netlink header
93*4882a593Smuzhiyun  * \param size size of the extra header that we want to put
94*4882a593Smuzhiyun  *
95*4882a593Smuzhiyun  * This function sets to zero the room that is required to put the extra
96*4882a593Smuzhiyun  * header after the initial Netlink header. This function also increases
97*4882a593Smuzhiyun  * the nlmsg_len field. You have to invoke mnl_nlmsg_put_header() before
98*4882a593Smuzhiyun  * you call this function. This function returns a pointer to the extra
99*4882a593Smuzhiyun  * header.
100*4882a593Smuzhiyun  */
mnl_nlmsg_put_extra_header(struct nlmsghdr * nlh,size_t size)101*4882a593Smuzhiyun void *mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh,
102*4882a593Smuzhiyun 					       size_t size)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	char *ptr = (char *)nlh + nlh->nlmsg_len;
105*4882a593Smuzhiyun 	size_t len = MNL_ALIGN(size);
106*4882a593Smuzhiyun 	nlh->nlmsg_len += len;
107*4882a593Smuzhiyun 	memset(ptr, 0, len);
108*4882a593Smuzhiyun 	return ptr;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun /**
112*4882a593Smuzhiyun  * mnl_nlmsg_get_payload - get a pointer to the payload of the netlink message
113*4882a593Smuzhiyun  * \param nlh pointer to a netlink header
114*4882a593Smuzhiyun  *
115*4882a593Smuzhiyun  * This function returns a pointer to the payload of the netlink message.
116*4882a593Smuzhiyun  */
mnl_nlmsg_get_payload(const struct nlmsghdr * nlh)117*4882a593Smuzhiyun void *mnl_nlmsg_get_payload(const struct nlmsghdr *nlh)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun 	return (void *)nlh + MNL_NLMSG_HDRLEN;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun /**
123*4882a593Smuzhiyun  * mnl_nlmsg_get_payload_offset - get a pointer to the payload of the message
124*4882a593Smuzhiyun  * \param nlh pointer to a netlink header
125*4882a593Smuzhiyun  * \param offset offset to the payload of the attributes TLV set
126*4882a593Smuzhiyun  *
127*4882a593Smuzhiyun  * This function returns a pointer to the payload of the netlink message plus
128*4882a593Smuzhiyun  * a given offset.
129*4882a593Smuzhiyun  */
mnl_nlmsg_get_payload_offset(const struct nlmsghdr * nlh,size_t offset)130*4882a593Smuzhiyun void *mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh,
131*4882a593Smuzhiyun 						 size_t offset)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	return (void *)nlh + MNL_NLMSG_HDRLEN + MNL_ALIGN(offset);
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun /**
137*4882a593Smuzhiyun  * mnl_nlmsg_ok - check a there is room for netlink message
138*4882a593Smuzhiyun  * \param nlh netlink message that we want to check
139*4882a593Smuzhiyun  * \param len remaining bytes in a buffer that contains the netlink message
140*4882a593Smuzhiyun  *
141*4882a593Smuzhiyun  * This function is used to check that a buffer that contains a netlink
142*4882a593Smuzhiyun  * message has enough room for the netlink message that it stores, ie. this
143*4882a593Smuzhiyun  * function can be used to verify that a netlink message is not malformed nor
144*4882a593Smuzhiyun  * truncated.
145*4882a593Smuzhiyun  *
146*4882a593Smuzhiyun  * This function does not set errno in case of error since it is intended
147*4882a593Smuzhiyun  * for iterations. Thus, it returns true on success and false on error.
148*4882a593Smuzhiyun  *
149*4882a593Smuzhiyun  * The len parameter may become negative in malformed messages during message
150*4882a593Smuzhiyun  * iteration, that is why we use a signed integer.
151*4882a593Smuzhiyun  */
mnl_nlmsg_ok(const struct nlmsghdr * nlh,int len)152*4882a593Smuzhiyun bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	return len >= (int)sizeof(struct nlmsghdr) &&
155*4882a593Smuzhiyun 	       nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
156*4882a593Smuzhiyun 	       (int)nlh->nlmsg_len <= len;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun /**
160*4882a593Smuzhiyun  * mnl_nlmsg_next - get the next netlink message in a multipart message
161*4882a593Smuzhiyun  * \param nlh current netlink message that we are handling
162*4882a593Smuzhiyun  * \param len length of the remaining bytes in the buffer (passed by reference).
163*4882a593Smuzhiyun  *
164*4882a593Smuzhiyun  * This function returns a pointer to the next netlink message that is part
165*4882a593Smuzhiyun  * of a multi-part netlink message. Netlink can batch several messages into
166*4882a593Smuzhiyun  * one buffer so that the receiver has to iterate over the whole set of
167*4882a593Smuzhiyun  * Netlink messages.
168*4882a593Smuzhiyun  *
169*4882a593Smuzhiyun  * You have to use mnl_nlmsg_ok() to check if the next Netlink message is
170*4882a593Smuzhiyun  * valid.
171*4882a593Smuzhiyun  */
mnl_nlmsg_next(const struct nlmsghdr * nlh,int * len)172*4882a593Smuzhiyun struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh,
173*4882a593Smuzhiyun 					      int *len)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun 	*len -= MNL_ALIGN(nlh->nlmsg_len);
176*4882a593Smuzhiyun 	return (struct nlmsghdr *)((void *)nlh + MNL_ALIGN(nlh->nlmsg_len));
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun /**
180*4882a593Smuzhiyun  * mnl_nlmsg_get_payload_tail - get the ending of the netlink message
181*4882a593Smuzhiyun  * \param nlh pointer to netlink message
182*4882a593Smuzhiyun  *
183*4882a593Smuzhiyun  * This function returns a pointer to the netlink message tail. This is useful
184*4882a593Smuzhiyun  * to build a message since we continue adding attributes at the end of the
185*4882a593Smuzhiyun  * message.
186*4882a593Smuzhiyun  */
mnl_nlmsg_get_payload_tail(const struct nlmsghdr * nlh)187*4882a593Smuzhiyun void *mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun 	return (void *)nlh + MNL_ALIGN(nlh->nlmsg_len);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun /**
193*4882a593Smuzhiyun  * mnl_nlmsg_seq_ok - perform sequence tracking
194*4882a593Smuzhiyun  * \param nlh current netlink message that we are handling
195*4882a593Smuzhiyun  * \param seq last sequence number used to send a message
196*4882a593Smuzhiyun  *
197*4882a593Smuzhiyun  * This functions returns true if the sequence tracking is fulfilled, otherwise
198*4882a593Smuzhiyun  * false is returned. We skip the tracking for netlink messages whose sequence
199*4882a593Smuzhiyun  * number is zero since it is usually reserved for event-based kernel
200*4882a593Smuzhiyun  * notifications. On the other hand, if seq is set but the message sequence
201*4882a593Smuzhiyun  * number is not set (i.e. this is an event message coming from kernel-space),
202*4882a593Smuzhiyun  * then we also skip the tracking. This approach is good if we use the same
203*4882a593Smuzhiyun  * socket to send commands to kernel-space (that we want to track) and to
204*4882a593Smuzhiyun  * listen to events (that we do not track).
205*4882a593Smuzhiyun  */
mnl_nlmsg_seq_ok(const struct nlmsghdr * nlh,unsigned int seq)206*4882a593Smuzhiyun bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh,
207*4882a593Smuzhiyun 				    unsigned int seq)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun 	return nlh->nlmsg_seq && seq ? nlh->nlmsg_seq == seq : true;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun /**
213*4882a593Smuzhiyun  * mnl_nlmsg_portid_ok - perform portID origin check
214*4882a593Smuzhiyun  * \param nlh current netlink message that we are handling
215*4882a593Smuzhiyun  * \param portid netlink portid that we want to check
216*4882a593Smuzhiyun  *
217*4882a593Smuzhiyun  * This functions returns true if the origin is fulfilled, otherwise
218*4882a593Smuzhiyun  * false is returned. We skip the tracking for netlink message whose portID
219*4882a593Smuzhiyun  * is zero since it is reserved for event-based kernel notifications. On the
220*4882a593Smuzhiyun  * other hand, if portid is set but the message PortID is not (i.e. this
221*4882a593Smuzhiyun  * is an event message coming from kernel-space), then we also skip the
222*4882a593Smuzhiyun  * tracking. This approach is good if we use the same socket to send commands
223*4882a593Smuzhiyun  * to kernel-space (that we want to track) and to listen to events (that we
224*4882a593Smuzhiyun  * do not track).
225*4882a593Smuzhiyun  */
mnl_nlmsg_portid_ok(const struct nlmsghdr * nlh,unsigned int portid)226*4882a593Smuzhiyun bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh,
227*4882a593Smuzhiyun 				       unsigned int portid)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun 	return nlh->nlmsg_pid && portid ? nlh->nlmsg_pid == portid : true;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun 
mnl_nlmsg_fprintf_header(FILE * fd,const struct nlmsghdr * nlh)232*4882a593Smuzhiyun static void mnl_nlmsg_fprintf_header(FILE *fd, const struct nlmsghdr *nlh)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun 	fprintf(fd, "----------------\t------------------\n");
235*4882a593Smuzhiyun 	fprintf(fd, "|  %.010u  |\t| message length |\n", nlh->nlmsg_len);
236*4882a593Smuzhiyun 	fprintf(fd, "| %.05u | %c%c%c%c |\t|  type | flags  |\n",
237*4882a593Smuzhiyun 		nlh->nlmsg_type,
238*4882a593Smuzhiyun 		nlh->nlmsg_flags & NLM_F_REQUEST ? 'R' : '-',
239*4882a593Smuzhiyun 		nlh->nlmsg_flags & NLM_F_MULTI ? 'M' : '-',
240*4882a593Smuzhiyun 		nlh->nlmsg_flags & NLM_F_ACK ? 'A' : '-',
241*4882a593Smuzhiyun 		nlh->nlmsg_flags & NLM_F_ECHO ? 'E' : '-');
242*4882a593Smuzhiyun 	fprintf(fd, "|  %.010u  |\t| sequence number|\n", nlh->nlmsg_seq);
243*4882a593Smuzhiyun 	fprintf(fd, "|  %.010u  |\t|     port ID    |\n", nlh->nlmsg_pid);
244*4882a593Smuzhiyun 	fprintf(fd, "----------------\t------------------\n");
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
mnl_nlmsg_fprintf_payload(FILE * fd,const struct nlmsghdr * nlh,size_t extra_header_size)247*4882a593Smuzhiyun static void mnl_nlmsg_fprintf_payload(FILE *fd, const struct nlmsghdr *nlh,
248*4882a593Smuzhiyun 				      size_t extra_header_size)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun 	int rem = 0;
251*4882a593Smuzhiyun 	unsigned int i;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	for (i=sizeof(struct nlmsghdr); i<nlh->nlmsg_len; i+=4) {
254*4882a593Smuzhiyun 		char *b = (char *) nlh;
255*4882a593Smuzhiyun 		struct nlattr *attr = (struct nlattr *) (b+i);
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 		/* netlink control message. */
258*4882a593Smuzhiyun 		if (nlh->nlmsg_type < NLMSG_MIN_TYPE) {
259*4882a593Smuzhiyun 			fprintf(fd, "| %.2x %.2x %.2x %.2x  |\t",
260*4882a593Smuzhiyun 				0xff & b[i],	0xff & b[i+1],
261*4882a593Smuzhiyun 				0xff & b[i+2],	0xff & b[i+3]);
262*4882a593Smuzhiyun 			fprintf(fd, "|                |\n");
263*4882a593Smuzhiyun 		/* special handling for the extra header. */
264*4882a593Smuzhiyun 		} else if (extra_header_size > 0) {
265*4882a593Smuzhiyun 			extra_header_size -= 4;
266*4882a593Smuzhiyun 			fprintf(fd, "| %.2x %.2x %.2x %.2x  |\t",
267*4882a593Smuzhiyun 				0xff & b[i],	0xff & b[i+1],
268*4882a593Smuzhiyun 				0xff & b[i+2],	0xff & b[i+3]);
269*4882a593Smuzhiyun 			fprintf(fd, "|  extra header  |\n");
270*4882a593Smuzhiyun 		/* this seems like an attribute header. */
271*4882a593Smuzhiyun 		} else if (rem == 0 && (attr->nla_type & NLA_TYPE_MASK) != 0) {
272*4882a593Smuzhiyun 			fprintf(fd, "|%c[%d;%dm"
273*4882a593Smuzhiyun 				    "%.5u"
274*4882a593Smuzhiyun 				    "%c[%dm"
275*4882a593Smuzhiyun 				    "|"
276*4882a593Smuzhiyun 				    "%c[%d;%dm"
277*4882a593Smuzhiyun 				    "%c%c"
278*4882a593Smuzhiyun 				    "%c[%dm"
279*4882a593Smuzhiyun 				    "|"
280*4882a593Smuzhiyun 				    "%c[%d;%dm"
281*4882a593Smuzhiyun 				    "%.5u"
282*4882a593Smuzhiyun 				    "%c[%dm|\t",
283*4882a593Smuzhiyun 				27, 1, 31,
284*4882a593Smuzhiyun 				attr->nla_len,
285*4882a593Smuzhiyun 				27, 0,
286*4882a593Smuzhiyun 				27, 1, 32,
287*4882a593Smuzhiyun 				attr->nla_type & NLA_F_NESTED ? 'N' : '-',
288*4882a593Smuzhiyun 				attr->nla_type &
289*4882a593Smuzhiyun 					NLA_F_NET_BYTEORDER ? 'B' : '-',
290*4882a593Smuzhiyun 				27, 0,
291*4882a593Smuzhiyun 				27, 1, 34,
292*4882a593Smuzhiyun 				attr->nla_type & NLA_TYPE_MASK,
293*4882a593Smuzhiyun 				27, 0);
294*4882a593Smuzhiyun 			fprintf(fd, "|len |flags| type|\n");
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 			if (!(attr->nla_type & NLA_F_NESTED)) {
297*4882a593Smuzhiyun 				rem = NLA_ALIGN(attr->nla_len) -
298*4882a593Smuzhiyun 					sizeof(struct nlattr);
299*4882a593Smuzhiyun 			}
300*4882a593Smuzhiyun 		/* this is the attribute payload. */
301*4882a593Smuzhiyun 		} else if (rem > 0) {
302*4882a593Smuzhiyun 			rem -= 4;
303*4882a593Smuzhiyun 			fprintf(fd, "| %.2x %.2x %.2x %.2x  |\t",
304*4882a593Smuzhiyun 				0xff & b[i],	0xff & b[i+1],
305*4882a593Smuzhiyun 				0xff & b[i+2],	0xff & b[i+3]);
306*4882a593Smuzhiyun 			fprintf(fd, "|      data      |");
307*4882a593Smuzhiyun 			fprintf(fd, "\t %c %c %c %c\n",
308*4882a593Smuzhiyun 				isprint(b[i]) ? b[i] : ' ',
309*4882a593Smuzhiyun 				isprint(b[i+1]) ? b[i+1] : ' ',
310*4882a593Smuzhiyun 				isprint(b[i+2]) ? b[i+2] : ' ',
311*4882a593Smuzhiyun 				isprint(b[i+3]) ? b[i+3] : ' ');
312*4882a593Smuzhiyun 		}
313*4882a593Smuzhiyun 	}
314*4882a593Smuzhiyun 	fprintf(fd, "----------------\t------------------\n");
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun /**
318*4882a593Smuzhiyun  * mnl_nlmsg_fprintf - print netlink message to file
319*4882a593Smuzhiyun  * \param fd pointer to file type
320*4882a593Smuzhiyun  * \param data pointer to the buffer that contains messages to be printed
321*4882a593Smuzhiyun  * \param datalen length of data stored in the buffer
322*4882a593Smuzhiyun  * \param extra_header_size size of the extra header (if any)
323*4882a593Smuzhiyun  *
324*4882a593Smuzhiyun  * This function prints the netlink header to a file handle.
325*4882a593Smuzhiyun  * It may be useful for debugging purposes. One example of the output
326*4882a593Smuzhiyun  * is the following:
327*4882a593Smuzhiyun  *
328*4882a593Smuzhiyun  *\verbatim
329*4882a593Smuzhiyun ----------------        ------------------
330*4882a593Smuzhiyun |  0000000040  |        | message length |
331*4882a593Smuzhiyun | 00016 | R-A- |        |  type | flags  |
332*4882a593Smuzhiyun |  1289148991  |        | sequence number|
333*4882a593Smuzhiyun |  0000000000  |        |     port ID    |
334*4882a593Smuzhiyun ----------------        ------------------
335*4882a593Smuzhiyun | 00 00 00 00  |        |  extra header  |
336*4882a593Smuzhiyun | 00 00 00 00  |        |  extra header  |
337*4882a593Smuzhiyun | 01 00 00 00  |        |  extra header  |
338*4882a593Smuzhiyun | 01 00 00 00  |        |  extra header  |
339*4882a593Smuzhiyun |00008|--|00003|        |len |flags| type|
340*4882a593Smuzhiyun | 65 74 68 30  |        |      data      |       e t h 0
341*4882a593Smuzhiyun ----------------        ------------------
342*4882a593Smuzhiyun \endverbatim
343*4882a593Smuzhiyun  *
344*4882a593Smuzhiyun  * This example above shows the netlink message that is send to kernel-space
345*4882a593Smuzhiyun  * to set up the link interface eth0. The netlink and attribute header data
346*4882a593Smuzhiyun  * are displayed in base 10 whereas the extra header and the attribute payload
347*4882a593Smuzhiyun  * are expressed in base 16. The possible flags in the netlink header are:
348*4882a593Smuzhiyun  *
349*4882a593Smuzhiyun  * - R, that indicates that NLM_F_REQUEST is set.
350*4882a593Smuzhiyun  * - M, that indicates that NLM_F_MULTI is set.
351*4882a593Smuzhiyun  * - A, that indicates that NLM_F_ACK is set.
352*4882a593Smuzhiyun  * - E, that indicates that NLM_F_ECHO is set.
353*4882a593Smuzhiyun  *
354*4882a593Smuzhiyun  * The lack of one flag is displayed with '-'. On the other hand, the possible
355*4882a593Smuzhiyun  * attribute flags available are:
356*4882a593Smuzhiyun  *
357*4882a593Smuzhiyun  * - N, that indicates that NLA_F_NESTED is set.
358*4882a593Smuzhiyun  * - B, that indicates that NLA_F_NET_BYTEORDER is set.
359*4882a593Smuzhiyun  */
mnl_nlmsg_fprintf(FILE * fd,const void * data,size_t datalen,size_t extra_header_size)360*4882a593Smuzhiyun void mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen,
361*4882a593Smuzhiyun 				     size_t extra_header_size)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun 	const struct nlmsghdr *nlh = data;
364*4882a593Smuzhiyun 	int len = datalen;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	while (mnl_nlmsg_ok(nlh, len)) {
367*4882a593Smuzhiyun 		mnl_nlmsg_fprintf_header(fd, nlh);
368*4882a593Smuzhiyun 		mnl_nlmsg_fprintf_payload(fd, nlh, extra_header_size);
369*4882a593Smuzhiyun 		nlh = mnl_nlmsg_next(nlh, &len);
370*4882a593Smuzhiyun 	}
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun /**
374*4882a593Smuzhiyun  * @}
375*4882a593Smuzhiyun  */
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun /**
378*4882a593Smuzhiyun  * \defgroup batch Netlink message batch helpers
379*4882a593Smuzhiyun  *
380*4882a593Smuzhiyun  * This library provides helpers to batch several messages into one single
381*4882a593Smuzhiyun  * datagram. These helpers do not perform strict memory boundary checkings.
382*4882a593Smuzhiyun  *
383*4882a593Smuzhiyun  * The following figure represents a Netlink message batch:
384*4882a593Smuzhiyun  *
385*4882a593Smuzhiyun  *   |<-------------- MNL_SOCKET_BUFFER_SIZE ------------->|
386*4882a593Smuzhiyun  *   |<-------------------- batch ------------------>|     |
387*4882a593Smuzhiyun  *   |-----------|-----------|-----------|-----------|-----------|
388*4882a593Smuzhiyun  *   |<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|
389*4882a593Smuzhiyun  *   |-----------|-----------|-----------|-----------|-----------|
390*4882a593Smuzhiyun  *                                             ^           ^
391*4882a593Smuzhiyun  *                                             |           |
392*4882a593Smuzhiyun  *                                        message N   message N+1
393*4882a593Smuzhiyun  *
394*4882a593Smuzhiyun  * To start the batch, you have to call mnl_nlmsg_batch_start() and you can
395*4882a593Smuzhiyun  * use mnl_nlmsg_batch_stop() to release it.
396*4882a593Smuzhiyun  *
397*4882a593Smuzhiyun  * You have to invoke mnl_nlmsg_batch_next() to get room for a new message
398*4882a593Smuzhiyun  * in the batch. If this function returns NULL, it means that the last
399*4882a593Smuzhiyun  * message that was added (message N+1 in the figure above) does not fit the
400*4882a593Smuzhiyun  * batch. Thus, you have to send the batch (which includes until message N)
401*4882a593Smuzhiyun  * and, then, you have to call mnl_nlmsg_batch_reset() to re-initialize
402*4882a593Smuzhiyun  * the batch (this moves message N+1 to the head of the buffer). For that
403*4882a593Smuzhiyun  * reason, the buffer that you have to use to store the batch must be double
404*4882a593Smuzhiyun  * of MNL_SOCKET_BUFFER_SIZE to ensure that the last message (message N+1)
405*4882a593Smuzhiyun  * that did not fit into the batch is written inside valid memory boundaries.
406*4882a593Smuzhiyun  *
407*4882a593Smuzhiyun  * @{
408*4882a593Smuzhiyun  */
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun struct mnl_nlmsg_batch {
411*4882a593Smuzhiyun 	/* the buffer that is used to store the batch. */
412*4882a593Smuzhiyun 	void *buf;
413*4882a593Smuzhiyun 	size_t limit;
414*4882a593Smuzhiyun 	size_t buflen;
415*4882a593Smuzhiyun 	/* the current netlink message in the batch. */
416*4882a593Smuzhiyun 	void *cur;
417*4882a593Smuzhiyun 	bool overflow;
418*4882a593Smuzhiyun };
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun /**
421*4882a593Smuzhiyun  * mnl_nlmsg_batch_start - initialize a batch
422*4882a593Smuzhiyun  * \param buf pointer to the buffer that will store this batch
423*4882a593Smuzhiyun  * \param limit maximum size of the batch (should be MNL_SOCKET_BUFFER_SIZE).
424*4882a593Smuzhiyun  *
425*4882a593Smuzhiyun  * The buffer that you pass must be double of MNL_SOCKET_BUFFER_SIZE. The
426*4882a593Smuzhiyun  * limit must be half of the buffer size, otherwise expect funny memory
427*4882a593Smuzhiyun  * corruptions 8-).
428*4882a593Smuzhiyun  *
429*4882a593Smuzhiyun  * You can allocate the buffer that you use to store the batch in the stack or
430*4882a593Smuzhiyun  * the heap, no restrictions in this regard. This function returns NULL on
431*4882a593Smuzhiyun  * error.
432*4882a593Smuzhiyun  */
mnl_nlmsg_batch_start(void * buf,size_t limit)433*4882a593Smuzhiyun struct mnl_nlmsg_batch *mnl_nlmsg_batch_start(void *buf,
434*4882a593Smuzhiyun 							    size_t limit)
435*4882a593Smuzhiyun {
436*4882a593Smuzhiyun 	struct mnl_nlmsg_batch *b;
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	b = malloc(sizeof(struct mnl_nlmsg_batch));
439*4882a593Smuzhiyun 	if (b == NULL)
440*4882a593Smuzhiyun 		return NULL;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	b->buf = buf;
443*4882a593Smuzhiyun 	b->limit = limit;
444*4882a593Smuzhiyun 	b->buflen = 0;
445*4882a593Smuzhiyun 	b->cur = buf;
446*4882a593Smuzhiyun 	b->overflow = false;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	return b;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun /**
452*4882a593Smuzhiyun  * mnl_nlmsg_batch_stop - release a batch
453*4882a593Smuzhiyun  * \param b pointer to batch
454*4882a593Smuzhiyun  *
455*4882a593Smuzhiyun  * This function releases the batch allocated by mnl_nlmsg_batch_start().
456*4882a593Smuzhiyun  */
mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch * b)457*4882a593Smuzhiyun void mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch *b)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun 	free(b);
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun /**
463*4882a593Smuzhiyun  * mnl_nlmsg_batch_next - get room for the next message in the batch
464*4882a593Smuzhiyun  * \param b pointer to batch
465*4882a593Smuzhiyun  *
466*4882a593Smuzhiyun  * This function returns false if the last message did not fit into the
467*4882a593Smuzhiyun  * batch. Otherwise, it prepares the batch to provide room for the new
468*4882a593Smuzhiyun  * Netlink message in the batch and returns true.
469*4882a593Smuzhiyun  *
470*4882a593Smuzhiyun  * You have to put at least one message in the batch before calling this
471*4882a593Smuzhiyun  * function, otherwise your application is likely to crash.
472*4882a593Smuzhiyun  */
mnl_nlmsg_batch_next(struct mnl_nlmsg_batch * b)473*4882a593Smuzhiyun bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun 	struct nlmsghdr *nlh = b->cur;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	if (b->buflen + nlh->nlmsg_len > b->limit) {
478*4882a593Smuzhiyun 		b->overflow = true;
479*4882a593Smuzhiyun 		return false;
480*4882a593Smuzhiyun 	}
481*4882a593Smuzhiyun 	b->cur = b->buf + b->buflen + nlh->nlmsg_len;
482*4882a593Smuzhiyun 	b->buflen += nlh->nlmsg_len;
483*4882a593Smuzhiyun 	return true;
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun /**
487*4882a593Smuzhiyun  * mnl_nlmsg_batch_reset - reset the batch
488*4882a593Smuzhiyun  * \param b pointer to batch
489*4882a593Smuzhiyun  *
490*4882a593Smuzhiyun  * This function allows to reset a batch, so you can reuse it to create a
491*4882a593Smuzhiyun  * new one. This function moves the last message which does not fit the
492*4882a593Smuzhiyun  * batch to the head of the buffer, if any.
493*4882a593Smuzhiyun  */
mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch * b)494*4882a593Smuzhiyun void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b)
495*4882a593Smuzhiyun {
496*4882a593Smuzhiyun 	if (b->overflow) {
497*4882a593Smuzhiyun 		struct nlmsghdr *nlh = b->cur;
498*4882a593Smuzhiyun 		memcpy(b->buf, b->cur, nlh->nlmsg_len);
499*4882a593Smuzhiyun 		b->buflen = nlh->nlmsg_len;
500*4882a593Smuzhiyun 		b->cur = b->buf + b->buflen;
501*4882a593Smuzhiyun 		b->overflow = false;
502*4882a593Smuzhiyun 	} else {
503*4882a593Smuzhiyun 		b->buflen = 0;
504*4882a593Smuzhiyun 		b->cur = b->buf;
505*4882a593Smuzhiyun 	}
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun /**
509*4882a593Smuzhiyun  * mnl_nlmsg_batch_size - get current size of the batch
510*4882a593Smuzhiyun  * \param b pointer to batch
511*4882a593Smuzhiyun  *
512*4882a593Smuzhiyun  * This function returns the current size of the batch.
513*4882a593Smuzhiyun  */
mnl_nlmsg_batch_size(struct mnl_nlmsg_batch * b)514*4882a593Smuzhiyun size_t mnl_nlmsg_batch_size(struct mnl_nlmsg_batch *b)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun 	return b->buflen;
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun /**
520*4882a593Smuzhiyun  * mnl_nlmsg_batch_head - get head of this batch
521*4882a593Smuzhiyun  * \param b pointer to batch
522*4882a593Smuzhiyun  *
523*4882a593Smuzhiyun  * This function returns a pointer to the head of the batch, which is the
524*4882a593Smuzhiyun  * beginning of the buffer that is used.
525*4882a593Smuzhiyun  */
mnl_nlmsg_batch_head(struct mnl_nlmsg_batch * b)526*4882a593Smuzhiyun void *mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b)
527*4882a593Smuzhiyun {
528*4882a593Smuzhiyun 	return b->buf;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun /**
532*4882a593Smuzhiyun  * mnl_nlmsg_batch_current - returns current position in the batch
533*4882a593Smuzhiyun  * \param b pointer to batch
534*4882a593Smuzhiyun  *
535*4882a593Smuzhiyun  * This function returns a pointer to the current position in the buffer
536*4882a593Smuzhiyun  * that is used to store the batch.
537*4882a593Smuzhiyun  */
mnl_nlmsg_batch_current(struct mnl_nlmsg_batch * b)538*4882a593Smuzhiyun void *mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b)
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun 	return b->cur;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun /**
544*4882a593Smuzhiyun  * mnl_nlmsg_batch_is_empty - check if there is any message in the batch
545*4882a593Smuzhiyun  * \param b pointer to batch
546*4882a593Smuzhiyun  *
547*4882a593Smuzhiyun  * This function returns true if the batch is empty.
548*4882a593Smuzhiyun  */
mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch * b)549*4882a593Smuzhiyun bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b)
550*4882a593Smuzhiyun {
551*4882a593Smuzhiyun 	return b->buflen == 0;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun /**
555*4882a593Smuzhiyun  * @}
556*4882a593Smuzhiyun  */
557