root/luci2/libunl/unl/msg.h @ 6262

Revision 6262, 10.6 KB (checked in by Cyrus, 3 years ago)

Adding libunl

Line 
1/**
2 *   unl - Minimalistic netlink library
3 *   Copyright (C) 2010 Steven Barth <steven@midlink.org>
4 *   Copyright (C) 2010 John Crispin <blogic@openwrt.org>
5 *
6 *   This program is free software; you can redistribute it and/or modify
7 *   it under the terms of the GNU General Public License as published by
8 *   the Free Software Foundation; either version 2 of the License, or
9 *   (at your option) any later version.
10 *
11 *   This program is distributed in the hope that it will be useful,
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *   GNU General Public License for more details.
15 *
16 *   You should have received a copy of the GNU General Public License
17 *   along with this program; if not, write to the Free Software
18 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
22#ifndef UNL_MSG_H_
23#define UNL_MSG_H_
24
25#include <stdint.h>
26#include <string.h>
27#include <sys/socket.h>
28#include <linux/netlink.h>
29#include <linux/genetlink.h>
30
31
32/* Basic NLA_ macros inspired by rtnetlink RTA_ macros from linux kernel headers */
33#define NLA_DATA(nla)   ((void*)(((uint8_t*)(nla)) + NLA_HDRLEN))
34#define NLA_PAYLOAD(nla) ((ssize_t)((nla)->nla_len) - NLA_HDRLEN)
35#define NLA_OK(nla,len) ((len) >= (ssize_t)sizeof(struct nlattr) && \
36                         (nla)->nla_len >= sizeof(struct nlattr) && \
37                         (nla)->nla_len <= (len))
38#define NLA_NEXT(nla,attrlen)   ((attrlen) -= NLA_ALIGN((nla)->nla_len), \
39                                 (struct nlattr*)(((uint8_t*)(nla)) + NLA_ALIGN((nla)->nla_len)))
40
41/**
42 * Checks whether given netlink attribute's payload has given length and if so
43 * returns its value after casting it it to a given type otherwise returns a
44 * default value.
45 *
46 * nla:     netlink attribute
47 * type:    type to cast to
48 * def:     default value if attribute is invalid
49 */
50#define NLA_CAST_NUMBER(nla, type, def) (((nla) && NLA_PAYLOAD(nla) == sizeof(type)) \
51    ? *((type*)NLA_DATA(nla)) : (def))
52
53/**
54 * Same as NLA_CAST_NUMBER, but verifies that the attribute
55 * carries a zero terminated string.
56 */
57#define NLA_CAST_STRING(nla, def) (((nla) && memchr(NLA_DATA(nla), 0, NLA_PAYLOAD(nla))) \
58    ? (char*)NLA_DATA(nla) : (def))
59
60/**
61 * Same as NLA_CAST_NUMBER but only checks whether the attribute has
62 * given length.
63 */
64#define NLA_CAST_FIXED(nla, len, def) (((nla) && NLA_PAYLOAD(nla) == len) ? NLA_DATA(nla) : (def))
65
66
67
68/* Compiler magic */
69#define UNL_FORCE_ALIGNMENT(n) __attribute__((packed,aligned(n)))
70#define UNL_ALIGNED UNL_FORCE_ALIGNMENT(NLMSG_ALIGNTO)
71
72
73
74/****** NETLINK loop helpers ******/
75
76/**
77 * Iterates over each valid netlink message in buffer, using nh as entry pointer
78 * Use NLMSG_DATA(nh) to get a pointer to the payload data
79 * Use NLMSG_PAYLOAD(nh, 0) to get the size of the payload data
80 *
81 * nh:      entry pointer pointing to current struct nlmsghdr
82 * buffer:  the message buffer
83 * len:     the message buffer length
84 */
85#define unl_foreach_msg(nh, buffer, len) \
86    (nh) = (struct nlmsghdr*)(buffer); \
87    for (size_t _blen = (len); NLMSG_OK((nh), _blen); (nh) = NLMSG_NEXT((nh), _blen))
88
89/**
90 * Iterates over each valid netlink attribute using nla as entry pointer
91 * Use NLA_DATA(nla) to get a pointer to the payload data
92 * Use NLA_PAYLOAD(nla) to get the size of the payload data
93 *
94 * nla:     entry pointer pointing to current struct nlmsghdr
95 * buffer:  buffer containing attributes
96 * len:     buffer length
97 */
98#define unl_foreach_attr(nla, buffer, len) \
99    (nla) = (struct nlattr*)(buffer); \
100    for (size_t _rlen = (len); NLA_OK((nla), _rlen); (nla) = NLA_NEXT((nla), _rlen))
101
102
103/**
104 * Iterates over each valid netlink attribute in a netlink message, using nla as entry pointer
105 * Use NLA_DATA(nla) to get a pointer to the payload data
106 * Use NLA_PAYLOAD(nla) to get the size of the payload data
107 *
108 * nla:     entry pointer pointing to current struct nlmsghdr
109 * nh:      netlink message
110 * skip:    the length of the fixed message part - if any - to skip
111 */
112#define unl_msg_foreach_attr(nla, nh, skip) \
113    unl_foreach_attr(nla, ((uint8_t*)NLMSG_DATA((nh))) + NLMSG_ALIGN((skip)), NLMSG_PAYLOAD((nh), (skip)))
114
115
116/**
117 * Same as unl_msg_foreace_attr but skips generic netlink header automatically
118 */
119#define unl_genlmsg_foreach_attr(nla, nh, skip) \
120    unl_msg_foreach_attr(nla, nh, NLMSG_ALIGN(sizeof(struct genlmsghdr)) + skip)
121
122
123/**
124 * Same as unl_foreach_attr but more convenient for nested attributes
125 *
126 * nla:     entry pointer pointing to current struct nlmsghdr
127 * outer:   outer netlink nlattribute
128 */
129#define unl_attr_foreach_attr(nla, outer) \
130    unl_foreach_attr(nla, NLA_DATA((outer)), NLA_PAYLOAD((outer)))
131
132
133
134
135/****** NETLINK message helpers ******/
136
137/**
138 * Initializes a buffer for use as a netlink message and sets type and flags.
139 *
140 * buf:     your buffer (must be at least sizeof(struct nlmsghdr))
141 * type:    netlink message type
142 * flags:   netlink message flags
143 *
144 * Returns a pointer to buf as a nlmsghdr.
145 */
146static inline struct nlmsghdr* unl_msg_init
147(void *buf, uint16_t type, uint16_t flags) {
148    struct nlmsghdr *nh = buf;
149    nh->nlmsg_seq = nh->nlmsg_pid = 0;
150    nh->nlmsg_len = sizeof(*nh);
151    nh->nlmsg_type = type;
152    nh->nlmsg_flags = flags;
153    return nh;
154}
155
156
157/**
158 * Claims an aligned amount of data from the message buffer
159 *
160 * buf:     your buffer
161 * len:     length of your buffer
162 * datalen: data length
163 *
164 * Returns a pointer to the claimed memory
165 */
166static inline void* unl_msg_claim
167(struct nlmsghdr *nh, uint32_t datalen) {
168    void *data = ((uint8_t*)nh) + NLMSG_ALIGN(nh->nlmsg_len);
169    nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len) + datalen;
170    return data;
171}
172
173
174/**
175 * Same as unl_msg_claim but inserts a netlink attribute header before the pointer
176 * type: netlink attribute type
177 */
178static inline void* unl_msg_claim_attr
179(struct nlmsghdr *nh, uint16_t type, uint32_t datalen) {
180    struct nlattr *nla = unl_msg_claim(nh, NLA_HDRLEN + datalen);
181    nla->nla_type = type;
182    nla->nla_len = NLA_HDRLEN + datalen;
183    return ((uint8_t*)nla) + NLA_HDRLEN;
184}
185
186
187/**
188 * Appends a pack of data to the netlink message taking care of alignment, size etc.
189 *
190 * buf:     your buffer
191 * len:     length of your buffer
192 * data:    data to append
193 * datalen: data length
194 *
195 * Returns a pointer to the appended data.
196 */
197static inline void* unl_msg_append
198(struct nlmsghdr *nh, const void *data, uint32_t datalen) {
199    return memcpy(unl_msg_claim(nh, datalen), data, datalen);
200}
201
202
203/**
204 * Same as unl_msg_append but prepends a netlink attribute header
205 * type: netlink attribute type
206 */
207static inline void* unl_msg_append_attr
208(struct nlmsghdr *nh, uint16_t type, const void *data, uint16_t datalen) {
209    return memcpy(unl_msg_claim_attr(nh, type, datalen), data, datalen);
210}
211
212
213/**
214 * Same as unl_msg_append_attr but appends a zero-terminated string
215 */
216static inline void* unl_msg_append_string
217(struct nlmsghdr *nh, uint16_t type, const char *data) {
218    return unl_msg_append_attr(nh, type, data, strlen(data) + 1);
219}
220
221#define unl_msg_append_number(nh, type, datatype, value) \
222    (*((datatype*)unl_msg_claim_attr(nla, type, sizeof(datatype))) = value)
223
224
225/**
226 * Searches a netlink message for a netlink attribute with given type
227 *
228 * nh:      netlink message
229 * skip:    the length of the fixed message part - if any - to skip
230 * type:    attribute type
231 *
232 */
233struct nlattr* unl_msg_find(struct nlmsghdr *nh, size_t skip, uint16_t type);
234
235/**
236 * Searches a netlink message for all netlink attribute upto a given type
237 * id and put them into an array.
238 *
239 * nh:      netlink message
240 * skip:    the length of the fixed message part - if any - to skip
241 * nlatbl:  an array where pointers to the attributes
242 * maxtype: the highest attribute type id to parse
243 *
244 * NOTE: nlatbl must have space for at least max + 1 entries
245 *
246 */
247int unl_msg_parse
248(struct nlmsghdr *nh, size_t skip, struct nlattr *nlatbl[], uint16_t maxtype);
249
250
251/****** Generic netlink helpers *******/
252
253/**
254 * Drop in replacement for unl_msg_init for generic netlink.
255 *
256 * buf:     your buffer
257 * family:  generic netlink family id
258 * flags:   netlink message flags
259 * cmd:     generic netlink commands
260 * version: generic netlink command version
261 */
262static inline struct nlmsghdr* unl_genlmsg_init
263(void *buf, uint16_t family, uint16_t flags, uint8_t cmd, uint8_t version) {
264    struct nlmsghdr *nh = unl_msg_init(buf, family, flags);
265    struct genlmsghdr *gmh = unl_msg_claim(nh, sizeof(*gmh));
266    gmh->cmd = cmd;
267    gmh->version = version;
268    return nh;
269}
270
271/**
272 * Drop in replacement for unl_msg_find for generic netlink.
273 * Automatically skips the generic netlink header.
274 */
275static inline struct nlattr* unl_genlmsg_find(struct nlmsghdr *nh, size_t skip, uint16_t type) {
276    return unl_msg_find(nh, NLMSG_ALIGN(sizeof(struct genlmsghdr)) + skip, type);
277}
278
279
280/****** NETLINK attribute helpers ******/
281
282
283
284
285/**
286 * Same as unl_msg_init but initializes a netlink attribute
287 */
288static inline struct nlattr* unl_attr_init
289(void *buf, uint16_t type) {
290    struct nlattr *nla = buf;
291    nla->nla_len = sizeof(*nla);
292    nla->nla_type = type;
293    return nla;
294}
295
296
297/**
298 * Same as unl_msg_claim but claims from a netlink buffer
299 */
300static inline void* unl_attr_claim
301(struct nlattr *nla, size_t datalen) {
302    void *data = ((uint8_t*)nla) + NLMSG_ALIGN(nla->nla_len);
303    nla->nla_len = NLMSG_ALIGN(nla->nla_len) + datalen;
304    return data;
305}
306
307
308/**
309 * Same as unl_msg_claim but claims from a netlink buffer
310 */
311static inline void* unl_attr_claim_attr
312(struct nlattr *nla, uint16_t type, size_t datalen) {
313    nla = (struct nlattr*)unl_attr_claim(nla, NLA_HDRLEN + datalen);
314    nla->nla_type = type;
315    nla->nla_len = NLA_HDRLEN + datalen;
316    return ((uint8_t*)nla) + NLA_HDRLEN;
317}
318
319
320/**
321 * Same as unl_msg_append but appends to a netlink attribute
322 */
323static inline void* unl_attr_append
324(struct nlattr *nla, const void *data, size_t datalen) {
325    return memcpy(unl_attr_claim(nla, datalen), data, datalen);
326}
327
328
329/**
330 * Same as unl_attr_append but prepends a netlink attribute header
331 * type: netlink attribute type
332 */
333static inline void* unl_attr_append_attr
334(struct nlattr *nla, uint16_t type, const void *data, size_t datalen) {
335    return memcpy(unl_attr_claim_attr(nla, type, datalen), data, datalen);
336}
337
338
339/**
340 * Same as unl_attr_append_nested but appends a zero-terminated string
341 */
342static inline void* unl_attr_append_string
343(struct nlattr *nla, uint16_t type, const char *data) {
344    return unl_attr_append_attr(nla, type, data, strlen(data) + 1);
345}
346
347#define unl_attr_append_number(nla, type, datatype, value) \
348    (*((datatype*)unl_attr_claim_attr(nla, type, sizeof(datatype))) = value)
349
350
351/**
352 * Same as unl_msg_find but searches inside a netlink attribute
353 */
354struct nlattr* unl_attr_find(struct nlattr *nla, uint16_t type);
355
356/**
357 * Same as unl_msg_parse but searches inside a netlink attribute
358 */
359int unl_attr_parse(struct nlattr *nla, struct nlattr *nlatbl[], uint16_t maxtype);
360
361#endif /* UNL_MSG_H_ */
Note: See TracBrowser for help on using the browser.