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