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