OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 | |||
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 | */ |
||
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 | |||
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 | |||
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 | |||
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 | */ |
||
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 | */ |
||
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 | */ |
||
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 | */ |
||
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 | */ |
||
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 | /** @} */ |