genl.c revision 1155370f520cb64657e25153255cf7dc1424317f
1/*
2 * lib/genl/genl.c		Generic Netlink
3 *
4 *	This library is free software; you can redistribute it and/or
5 *	modify it under the terms of the GNU Lesser General Public
6 *	License as published by the Free Software Foundation version 2.1
7 *	of the License.
8 *
9 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
10 */
11
12/**
13 * @ingroup nlfam
14 * @defgroup genl Generic Netlink
15 *
16 * @par Message Format
17 * @code
18 *  <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) --->
19 * +----------------------------+- - -+- - - - - - - - - - -+- - -+
20 * |           Header           | Pad |       Payload       | Pad |
21 * |      struct nlmsghdr       |     |                     |     |
22 * +----------------------------+- - -+- - - - - - - - - - -+- - -+
23 * @endcode
24 * @code
25 *  <-------- GENL_HDRLEN -------> <--- hdrlen -->
26 *                                 <------- genlmsg_len(ghdr) ------>
27 * +------------------------+- - -+---------------+- - -+------------+
28 * | Generic Netlink Header | Pad | Family Header | Pad | Attributes |
29 * |    struct genlmsghdr   |     |               |     |            |
30 * +------------------------+- - -+---------------+- - -+------------+
31 * genlmsg_data(ghdr)--------------^                     ^
32 * genlmsg_attrdata(ghdr, hdrlen)-------------------------
33 * @endcode
34 *
35 * @par Example
36 * @code
37 * #include <netlink/netlink.h>
38 * #include <netlink/genl/genl.h>
39 * #include <netlink/genl/ctrl.h>
40 *
41 * struct nl_sock *sock;
42 * struct nl_msg *msg;
43 * int family;
44 *
45 * // Allocate a new netlink socket
46 * sock = nl_socket_alloc();
47 *
48 * // Connect to generic netlink socket on kernel side
49 * genl_connect(sock);
50 *
51 * // Ask kernel to resolve family name to family id
52 * family = genl_ctrl_resolve(sock, "generic_netlink_family_name");
53 *
54 * // Construct a generic netlink by allocating a new message, fill in
55 * // the header and append a simple integer attribute.
56 * msg = nlmsg_alloc();
57 * genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_ECHO,
58 *             CMD_FOO_GET, FOO_VERSION);
59 * nla_put_u32(msg, ATTR_FOO, 123);
60 *
61 * // Send message over netlink socket
62 * nl_send_auto_complete(sock, msg);
63 *
64 * // Free message
65 * nlmsg_free(msg);
66 *
67 * // Prepare socket to receive the answer by specifying the callback
68 * // function to be called for valid messages.
69 * nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, NULL);
70 *
71 * // Wait for the answer and receive it
72 * nl_recvmsgs_default(sock);
73 *
74 * static int parse_cb(struct nl_msg *msg, void *arg)
75 * {
76 *     struct nlmsghdr *nlh = nlmsg_hdr(msg);
77 *     struct nlattr *attrs[ATTR_MAX+1];
78 *
79 *     // Validate message and parse attributes
80 *     genlmsg_parse(nlh, 0, attrs, ATTR_MAX, policy);
81 *
82 *     if (attrs[ATTR_FOO]) {
83 *         uint32_t value = nla_get_u32(attrs[ATTR_FOO]);
84 *         ...
85 *     }
86 *
87 *     return 0;
88 * }
89 * @endcode
90 * @{
91 */
92
93#include <netlink-generic.h>
94#include <netlink/netlink.h>
95#include <netlink/genl/genl.h>
96#include <netlink/utils.h>
97
98/**
99 * @name Socket Creating
100 * @{
101 */
102
103int genl_connect(struct nl_sock *sk)
104{
105	return nl_connect(sk, NETLINK_GENERIC);
106}
107
108/** @} */
109
110/**
111 * @name Sending
112 * @{
113 */
114
115/**
116 * Send trivial generic netlink message
117 * @arg sk		Netlink socket.
118 * @arg family		Generic netlink family
119 * @arg cmd		Command
120 * @arg version		Version
121 * @arg flags		Additional netlink message flags.
122 *
123 * Fills out a routing netlink request message and sends it out
124 * using nl_send_simple().
125 *
126 * @return 0 on success or a negative error code.
127 */
128int genl_send_simple(struct nl_sock *sk, int family, int cmd,
129		     int version, int flags)
130{
131	struct genlmsghdr hdr = {
132		.cmd = cmd,
133		.version = version,
134	};
135
136	return nl_send_simple(sk, family, flags, &hdr, sizeof(hdr));
137}
138
139/** @} */
140
141
142/**
143 * @name Message Parsing
144 * @{
145 */
146
147int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen)
148{
149	struct genlmsghdr *ghdr;
150
151	if (!nlmsg_valid_hdr(nlh, GENL_HDRLEN))
152		return 0;
153
154	ghdr = nlmsg_data(nlh);
155	if (genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen))
156		return 0;
157
158	return 1;
159}
160
161int genlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
162		   struct nla_policy *policy)
163{
164	struct genlmsghdr *ghdr;
165
166	if (!genlmsg_valid_hdr(nlh, hdrlen))
167		return -NLE_MSG_TOOSHORT;
168
169	ghdr = nlmsg_data(nlh);
170	return nla_validate(genlmsg_attrdata(ghdr, hdrlen),
171			    genlmsg_attrlen(ghdr, hdrlen), maxtype, policy);
172}
173
174int genlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
175		  int maxtype, struct nla_policy *policy)
176{
177	struct genlmsghdr *ghdr;
178
179	if (!genlmsg_valid_hdr(nlh, hdrlen))
180		return -NLE_MSG_TOOSHORT;
181
182	ghdr = nlmsg_data(nlh);
183	return nla_parse(tb, maxtype, genlmsg_attrdata(ghdr, hdrlen),
184			 genlmsg_attrlen(ghdr, hdrlen), policy);
185}
186
187/**
188 * Get head of message payload
189 * @arg gnlh	genetlink messsage header
190 */
191void *genlmsg_data(const struct genlmsghdr *gnlh)
192{
193	return ((unsigned char *) gnlh + GENL_HDRLEN);
194}
195
196/**
197 * Get lenght of message payload
198 * @arg gnlh	genetlink message header
199 */
200int genlmsg_len(const struct genlmsghdr *gnlh)
201{
202	struct nlmsghdr *nlh = (struct nlmsghdr *)((unsigned char *)gnlh -
203							NLMSG_HDRLEN);
204	return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN);
205}
206
207/**
208 * Get head of attribute data
209 * @arg gnlh	generic netlink message header
210 * @arg hdrlen	length of family specific header
211 */
212struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
213{
214	return genlmsg_data(gnlh) + NLMSG_ALIGN(hdrlen);
215}
216
217/**
218 * Get length of attribute data
219 * @arg gnlh	generic netlink message header
220 * @arg hdrlen	length of family specific header
221 */
222int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
223{
224	return genlmsg_len(gnlh) - NLMSG_ALIGN(hdrlen);
225}
226
227/** @} */
228
229/**
230 * @name Message Building
231 * @{
232 */
233
234/**
235 * Add generic netlink header to netlink message
236 * @arg msg		netlink message
237 * @arg pid		netlink process id or NL_AUTO_PID
238 * @arg seq		sequence number of message or NL_AUTO_SEQ
239 * @arg family		generic netlink family
240 * @arg hdrlen		length of user specific header
241 * @arg flags		message flags
242 * @arg cmd		generic netlink command
243 * @arg version		protocol version
244 *
245 * Returns pointer to user specific header.
246 */
247void *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family,
248		  int hdrlen, int flags, uint8_t cmd, uint8_t version)
249{
250	struct nlmsghdr *nlh;
251	struct genlmsghdr hdr = {
252		.cmd = cmd,
253		.version = version,
254	};
255
256	nlh = nlmsg_put(msg, pid, seq, family, GENL_HDRLEN + hdrlen, flags);
257	if (nlh == NULL)
258		return NULL;
259
260	memcpy(nlmsg_data(nlh), &hdr, sizeof(hdr));
261	NL_DBG(2, "msg %p: Added generic netlink header cmd=%d version=%d\n",
262	       msg, cmd, version);
263
264	return nlmsg_data(nlh) + GENL_HDRLEN;
265}
266
267/** @} */
268
269/** @} */
270