1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * lib/genl/genl.c Generic Netlink
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation version 2.1
8 * of the License.
9 *
10 * Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
11 */
12
13 /**
14 * @defgroup genl Generic Netlink Library (libnl-genl)
15 *
16 * @{
17 */
18
19 #include <netlink-private/genl.h>
20 #include <netlink/netlink.h>
21 #include <netlink/genl/genl.h>
22 #include <netlink/utils.h>
23
24 /**
25 * @name Generic Netlink Socket
26 * @{
27 */
28
29 /**
30 * Connect a Generic Netlink socket
31 * @arg sk Unconnected Netlink socket
32 *
33 * This function expects a struct nl_socket object previously allocated via
34 * nl_socket_alloc(). It calls nl_connect() to create the local socket file
35 * descriptor and binds the socket to the \c NETLINK_GENERIC Netlink protocol.
36 *
37 * Using this function is equivalent to:
38 * @code
39 * nl_connect(sk, NETLINK_GENERIC);
40 * @endcode
41 *
42 * @see nl_connect()
43 *
44 * @return 0 on success or a negative error code.
45 */
genl_connect(struct nl_sock * sk)46 int genl_connect(struct nl_sock *sk)
47 {
48 return nl_connect(sk, NETLINK_GENERIC);
49 }
50
51 /** @} */
52
53 /**
54 * @name Sending Data
55 * @{
56 */
57
58 /**
59 * Send a Generic Netlink message consisting only of a header
60 * @arg sk Generic Netlink socket
61 * @arg family Numeric family identifier
62 * @arg cmd Numeric command identifier
63 * @arg version Interface version
64 * @arg flags Additional Netlink message flags (optional)
65 *
66 * This function is a shortcut for sending a Generic Netlink message without
67 * any message payload. The message will only consist of the Netlink and
68 * Generic Netlink headers. The header is constructed based on the specified
69 * parameters and passed on to nl_send_simple() to send it on the specified
70 * socket.
71 *
72 * @par Example:
73 * @code
74 * #include <netlink/genl/genl.h>
75 * #include <linux/genetlink.h>
76 *
77 * err = genl_send_simple(sk, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, CTRL_VERSION,
78 * NLM_F_DUMP);
79 * @endcode
80 *
81 * @see nl_send_simple()
82 *
83 * @return 0 on success or a negative error code. Due to a bug, this function
84 * returns the number of bytes sent. Treat any non-negative number as success.
85 */
genl_send_simple(struct nl_sock * sk,int family,int cmd,int version,int flags)86 int genl_send_simple(struct nl_sock *sk, int family, int cmd,
87 int version, int flags)
88 {
89 struct genlmsghdr hdr = {
90 .cmd = cmd,
91 .version = version,
92 };
93
94 return nl_send_simple(sk, family, flags, &hdr, sizeof(hdr));
95 }
96
97 /** @} */
98
99 /**
100 * @name Message Parsing
101 * @{
102 */
103
104 /**
105 * Validate Generic Netlink message headers
106 * @arg nlh Pointer to Netlink message header
107 * @arg hdrlen Length of user header
108 *
109 * Verifies the integrity of the Netlink and Generic Netlink headers by
110 * enforcing the following requirements:
111 * - Valid Netlink message header (nlmsg_valid_hdr())
112 * - Presence of a complete Generic Netlink header
113 * - At least \c hdrlen bytes of payload included after the generic
114 * netlink header.
115 *
116 * @return A positive integer (true) if the headers are valid or
117 * 0 (false) if not.
118 */
genlmsg_valid_hdr(struct nlmsghdr * nlh,int hdrlen)119 int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen)
120 {
121 struct genlmsghdr *ghdr;
122
123 if (!nlmsg_valid_hdr(nlh, GENL_HDRLEN))
124 return 0;
125
126 ghdr = nlmsg_data(nlh);
127 if (genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen))
128 return 0;
129
130 return 1;
131 }
132
133 /**
134 * Validate Generic Netlink message including attributes
135 * @arg nlh Pointer to Netlink message header
136 * @arg hdrlen Length of user header
137 * @arg maxtype Maximum attribtue id expected
138 * @arg policy Attribute validation policy
139 *
140 * Verifies the validity of the Netlink and Generic Netlink headers using
141 * genlmsg_valid_hdr() and calls nla_validate() on the message payload to
142 * verify the integrity of eventual attributes.
143 *
144 * @note You may call genlmsg_parse() directly to perform validation and
145 * parsing in a single step.
146 *
147 * @see genlmsg_valid_hdr()
148 * @see nla_validate()
149 * @see genlmsg_parse()
150 *
151 * @return 0 on success or a negative error code.
152 */
genlmsg_validate(struct nlmsghdr * nlh,int hdrlen,int maxtype,const struct nla_policy * policy)153 int genlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
154 const struct nla_policy *policy)
155 {
156 struct genlmsghdr *ghdr;
157
158 if (!genlmsg_valid_hdr(nlh, hdrlen))
159 return -NLE_MSG_TOOSHORT;
160
161 ghdr = nlmsg_data(nlh);
162 return nla_validate(genlmsg_attrdata(ghdr, hdrlen),
163 genlmsg_attrlen(ghdr, hdrlen), maxtype, policy);
164 }
165
166 /**
167 * Parse Generic Netlink message including attributes
168 * @arg nlh Pointer to Netlink message header
169 * @arg hdrlen Length of user header
170 * @arg tb Array to store parsed attributes
171 * @arg maxtype Maximum attribute id expected
172 * @arg policy Attribute validation policy
173 *
174 * Verifies the validity of the Netlink and Generic Netlink headers using
175 * genlmsg_valid_hdr() and calls nla_parse() on the message payload to
176 * parse eventual attributes.
177 *
178 * @par Example:
179 * @code
180 * struct nlattr *attrs[MY_TYPE_MAX+1];
181 *
182 * if ((err = genlmsg_parse(nlmsg_hdr(msg), sizeof(struct my_hdr), attrs,
183 * MY_TYPE_MAX, attr_policy)) < 0)
184 * // ERROR
185 * @endcode
186 *
187 * @see genlmsg_valid_hdr()
188 * @see genlmsg_validate()
189 * @see nla_parse()
190 *
191 * @return 0 on success or a negative error code.
192 */
genlmsg_parse(struct nlmsghdr * nlh,int hdrlen,struct nlattr * tb[],int maxtype,const struct nla_policy * policy)193 int genlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
194 int maxtype, const struct nla_policy *policy)
195 {
196 struct genlmsghdr *ghdr;
197
198 if (!genlmsg_valid_hdr(nlh, hdrlen))
199 return -NLE_MSG_TOOSHORT;
200
201 ghdr = nlmsg_data(nlh);
202 return nla_parse(tb, maxtype, genlmsg_attrdata(ghdr, hdrlen),
203 genlmsg_attrlen(ghdr, hdrlen), policy);
204 }
205
206 /**
207 * Return pointer to Generic Netlink header
208 * @arg nlh Netlink message header
209 *
210 * @return Pointer to Generic Netlink message header
211 */
genlmsg_hdr(struct nlmsghdr * nlh)212 struct genlmsghdr *genlmsg_hdr(struct nlmsghdr *nlh)
213 {
214 return nlmsg_data(nlh);
215 }
216
217 /**
218 * Return length of message payload including user header
219 * @arg gnlh Generic Netlink message header
220 *
221 * @see genlmsg_data()
222 *
223 * @return Length of user payload including an eventual user header in
224 * number of bytes.
225 */
genlmsg_len(const struct genlmsghdr * gnlh)226 int genlmsg_len(const struct genlmsghdr *gnlh)
227 {
228 const struct nlmsghdr *nlh;
229
230 nlh = (const struct nlmsghdr *)((const unsigned char *) gnlh - NLMSG_HDRLEN);
231 return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN);
232 }
233
234
235 /**
236 * Return pointer to user header
237 * @arg gnlh Generic Netlink message header
238 *
239 * Calculates the pointer to the user header based on the pointer to
240 * the Generic Netlink message header.
241 *
242 * @return Pointer to the user header
243 */
genlmsg_user_hdr(const struct genlmsghdr * gnlh)244 void *genlmsg_user_hdr(const struct genlmsghdr *gnlh)
245 {
246 return genlmsg_data(gnlh);
247 }
248
249 /**
250 * Return pointer to user data
251 * @arg gnlh Generic netlink message header
252 * @arg hdrlen Length of user header
253 *
254 * Calculates the pointer to the user data based on the pointer to
255 * the Generic Netlink message header.
256 *
257 * @see genlmsg_user_datalen()
258 *
259 * @return Pointer to the user data
260 */
genlmsg_user_data(const struct genlmsghdr * gnlh,const int hdrlen)261 void *genlmsg_user_data(const struct genlmsghdr *gnlh, const int hdrlen)
262 {
263 return (char *) genlmsg_user_hdr(gnlh) + NLMSG_ALIGN(hdrlen);
264 }
265
266 /**
267 * Return length of user data
268 * @arg gnlh Generic Netlink message header
269 * @arg hdrlen Length of user header
270 *
271 * @see genlmsg_user_data()
272 *
273 * @return Length of user data in bytes
274 */
genlmsg_user_datalen(const struct genlmsghdr * gnlh,const int hdrlen)275 int genlmsg_user_datalen(const struct genlmsghdr *gnlh, const int hdrlen)
276 {
277 return genlmsg_len(gnlh) - NLMSG_ALIGN(hdrlen);
278 }
279
280 /**
281 * Return pointer to message attributes
282 * @arg gnlh Generic Netlink message header
283 * @arg hdrlen Length of user header
284 *
285 * @see genlmsg_attrlen()
286 *
287 * @return Pointer to the start of the message's attributes section.
288 */
genlmsg_attrdata(const struct genlmsghdr * gnlh,int hdrlen)289 struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
290 {
291 return genlmsg_user_data(gnlh, hdrlen);
292 }
293
294 /**
295 * Return length of message attributes
296 * @arg gnlh Generic Netlink message header
297 * @arg hdrlen Length of user header
298 *
299 * @see genlmsg_attrdata()
300 *
301 * @return Length of the message section containing attributes in number
302 * of bytes.
303 */
genlmsg_attrlen(const struct genlmsghdr * gnlh,int hdrlen)304 int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
305 {
306 return genlmsg_len(gnlh) - NLMSG_ALIGN(hdrlen);
307 }
308
309 /** @} */
310
311 /**
312 * @name Message Construction
313 * @{
314 */
315
316 /**
317 * Add Generic Netlink headers to Netlink message
318 * @arg msg Netlink message object
319 * @arg port Netlink port or NL_AUTO_PORT
320 * @arg seq Sequence number of message or NL_AUTO_SEQ
321 * @arg family Numeric family identifier
322 * @arg hdrlen Length of user header
323 * @arg flags Additional Netlink message flags (optional)
324 * @arg cmd Numeric command identifier
325 * @arg version Interface version
326 *
327 * Calls nlmsg_put() on the specified message object to reserve space for
328 * the Netlink header, the Generic Netlink header, and a user header of
329 * specified length. Fills out the header fields with the specified
330 * parameters.
331 *
332 * @par Example:
333 * @code
334 * struct nl_msg *msg;
335 * struct my_hdr *user_hdr;
336 *
337 * if (!(msg = nlmsg_alloc()))
338 * // ERROR
339 *
340 * user_hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, family_id,
341 * sizeof(struct my_hdr), 0, MY_CMD_FOO, 0);
342 * if (!user_hdr)
343 * // ERROR
344 * @endcode
345 *
346 * @see nlmsg_put()
347 *
348 * Returns Pointer to user header or NULL if an error occurred.
349 */
genlmsg_put(struct nl_msg * msg,uint32_t port,uint32_t seq,int family,int hdrlen,int flags,uint8_t cmd,uint8_t version)350 void *genlmsg_put(struct nl_msg *msg, uint32_t port, uint32_t seq, int family,
351 int hdrlen, int flags, uint8_t cmd, uint8_t version)
352 {
353 struct nlmsghdr *nlh;
354 struct genlmsghdr hdr = {
355 .cmd = cmd,
356 .version = version,
357 };
358
359 nlh = nlmsg_put(msg, port, seq, family, GENL_HDRLEN + hdrlen, flags);
360 if (nlh == NULL)
361 return NULL;
362
363 memcpy(nlmsg_data(nlh), &hdr, sizeof(hdr));
364 NL_DBG(2, "msg %p: Added generic netlink header cmd=%d version=%d\n",
365 msg, cmd, version);
366
367 return (char *) nlmsg_data(nlh) + GENL_HDRLEN;
368 }
369
370 /** @} */
371
372 /**
373 * @name Deprecated
374 * @{
375 */
376
377 /**
378 * Return pointer to message payload
379 * @arg gnlh Generic Netlink message header
380 *
381 * @deprecated This function has been deprecated due to inability to specify
382 * the length of the user header. Use genlmsg_user_hdr()
383 * respectively genlmsg_user_data().
384 *
385 * @return Pointer to payload section
386 */
genlmsg_data(const struct genlmsghdr * gnlh)387 void *genlmsg_data(const struct genlmsghdr *gnlh)
388 {
389 return ((unsigned char *) gnlh + GENL_HDRLEN);
390 }
391
392 /** @} */
393 /** @} */
394