nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * lib/nl.c Core Netlink Interface |
||
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 core Core |
||
14 | * |
||
15 | * @details |
||
16 | * @par 1) Connecting the socket |
||
17 | * @code |
||
18 | * // Bind and connect the socket to a protocol, NETLINK_ROUTE in this example. |
||
19 | * nl_connect(sk, NETLINK_ROUTE); |
||
20 | * @endcode |
||
21 | * |
||
22 | * @par 2) Sending data |
||
23 | * @code |
||
24 | * // The most rudimentary method is to use nl_sendto() simply pushing |
||
25 | * // a piece of data to the other netlink peer. This method is not |
||
26 | * // recommended. |
||
27 | * const char buf[] = { 0x01, 0x02, 0x03, 0x04 }; |
||
28 | * nl_sendto(sk, buf, sizeof(buf)); |
||
29 | * |
||
30 | * // A more comfortable interface is nl_send() taking a pointer to |
||
31 | * // a netlink message. |
||
32 | * struct nl_msg *msg = my_msg_builder(); |
||
33 | * nl_send(sk, nlmsg_hdr(msg)); |
||
34 | * |
||
35 | * // nl_sendmsg() provides additional control over the sendmsg() message |
||
36 | * // header in order to allow more specific addressing of multiple peers etc. |
||
37 | * struct msghdr hdr = { ... }; |
||
38 | * nl_sendmsg(sk, nlmsg_hdr(msg), &hdr); |
||
39 | * |
||
40 | * // You're probably too lazy to fill out the netlink pid, sequence number |
||
41 | * // and message flags all the time. nl_send_auto_complete() automatically |
||
42 | * // extends your message header as needed with an appropriate sequence |
||
43 | * // number, the netlink pid stored in the netlink socket and the message |
||
44 | * // flags NLM_F_REQUEST and NLM_F_ACK (if not disabled in the socket) |
||
45 | * nl_send_auto_complete(sk, nlmsg_hdr(msg)); |
||
46 | * |
||
47 | * // Simple protocols don't require the complex message construction interface |
||
48 | * // and may favour nl_send_simple() to easly send a bunch of payload |
||
49 | * // encapsulated in a netlink message header. |
||
50 | * nl_send_simple(sk, MY_MSG_TYPE, 0, buf, sizeof(buf)); |
||
51 | * @endcode |
||
52 | * |
||
53 | * @par 3) Receiving data |
||
54 | * @code |
||
55 | * // nl_recv() receives a single message allocating a buffer for the message |
||
56 | * // content and gives back the pointer to you. |
||
57 | * struct sockaddr_nl peer; |
||
58 | * unsigned char *msg; |
||
59 | * nl_recv(sk, &peer, &msg); |
||
60 | * |
||
61 | * // nl_recvmsgs() receives a bunch of messages until the callback system |
||
62 | * // orders it to state, usually after receving a compolete multi part |
||
63 | * // message series. |
||
64 | * nl_recvmsgs(sk, my_callback_configuration); |
||
65 | * |
||
66 | * // nl_recvmsgs_default() acts just like nl_recvmsg() but uses the callback |
||
67 | * // configuration stored in the socket. |
||
68 | * nl_recvmsgs_default(sk); |
||
69 | * |
||
70 | * // In case you want to wait for the ACK to be recieved that you requested |
||
71 | * // with your latest message, you can call nl_wait_for_ack() |
||
72 | * nl_wait_for_ack(sk); |
||
73 | * @endcode |
||
74 | * |
||
75 | * @par 4) Closing |
||
76 | * @code |
||
77 | * // Close the socket first to release kernel memory |
||
78 | * nl_close(sk); |
||
79 | * @endcode |
||
80 | * |
||
81 | * @{ |
||
82 | */ |
||
83 | |||
84 | #include <netlink-local.h> |
||
85 | #include <netlink/netlink.h> |
||
86 | #include <netlink/utils.h> |
||
87 | #include <netlink/handlers.h> |
||
88 | #include <netlink/msg.h> |
||
89 | #include <netlink/attr.h> |
||
90 | |||
91 | /** |
||
92 | * @name Connection Management |
||
93 | * @{ |
||
94 | */ |
||
95 | |||
96 | /** |
||
97 | * Create and connect netlink socket. |
||
98 | * @arg sk Netlink socket. |
||
99 | * @arg protocol Netlink protocol to use. |
||
100 | * |
||
101 | * Creates a netlink socket using the specified protocol, binds the socket |
||
102 | * and issues a connection attempt. |
||
103 | * |
||
104 | * @return 0 on success or a negative error code. |
||
105 | */ |
||
106 | int nl_connect(struct nl_sock *sk, int protocol) |
||
107 | { |
||
108 | int err; |
||
109 | socklen_t addrlen; |
||
110 | |||
111 | sk->s_fd = socket(AF_NETLINK, SOCK_RAW, protocol); |
||
112 | if (sk->s_fd < 0) { |
||
113 | err = -nl_syserr2nlerr(errno); |
||
114 | goto errout; |
||
115 | } |
||
116 | |||
117 | if (!(sk->s_flags & NL_SOCK_BUFSIZE_SET)) { |
||
118 | err = nl_socket_set_buffer_size(sk, 0, 0); |
||
119 | if (err < 0) |
||
120 | goto errout; |
||
121 | } |
||
122 | |||
123 | err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local, |
||
124 | sizeof(sk->s_local)); |
||
125 | if (err < 0) { |
||
126 | err = -nl_syserr2nlerr(errno); |
||
127 | goto errout; |
||
128 | } |
||
129 | |||
130 | addrlen = sizeof(sk->s_local); |
||
131 | err = getsockname(sk->s_fd, (struct sockaddr *) &sk->s_local, |
||
132 | &addrlen); |
||
133 | if (err < 0) { |
||
134 | err = -nl_syserr2nlerr(errno); |
||
135 | goto errout; |
||
136 | } |
||
137 | |||
138 | if (addrlen != sizeof(sk->s_local)) { |
||
139 | err = -NLE_NOADDR; |
||
140 | goto errout; |
||
141 | } |
||
142 | |||
143 | if (sk->s_local.nl_family != AF_NETLINK) { |
||
144 | err = -NLE_AF_NOSUPPORT; |
||
145 | goto errout; |
||
146 | } |
||
147 | |||
148 | sk->s_proto = protocol; |
||
149 | |||
150 | return 0; |
||
151 | errout: |
||
152 | close(sk->s_fd); |
||
153 | sk->s_fd = -1; |
||
154 | |||
155 | return err; |
||
156 | } |
||
157 | |||
158 | /** |
||
159 | * Close/Disconnect netlink socket. |
||
160 | * @arg sk Netlink socket. |
||
161 | */ |
||
162 | void nl_close(struct nl_sock *sk) |
||
163 | { |
||
164 | if (sk->s_fd >= 0) { |
||
165 | close(sk->s_fd); |
||
166 | sk->s_fd = -1; |
||
167 | } |
||
168 | |||
169 | sk->s_proto = 0; |
||
170 | } |
||
171 | |||
172 | /** @} */ |
||
173 | |||
174 | /** |
||
175 | * @name Send |
||
176 | * @{ |
||
177 | */ |
||
178 | |||
179 | /** |
||
180 | * Send raw data over netlink socket. |
||
181 | * @arg sk Netlink socket. |
||
182 | * @arg buf Data buffer. |
||
183 | * @arg size Size of data buffer. |
||
184 | * @return Number of characters written on success or a negative error code. |
||
185 | */ |
||
186 | int nl_sendto(struct nl_sock *sk, void *buf, size_t size) |
||
187 | { |
||
188 | int ret; |
||
189 | |||
190 | ret = sendto(sk->s_fd, buf, size, 0, (struct sockaddr *) |
||
191 | &sk->s_peer, sizeof(sk->s_peer)); |
||
192 | if (ret < 0) |
||
193 | return -nl_syserr2nlerr(errno); |
||
194 | |||
195 | return ret; |
||
196 | } |
||
197 | |||
198 | /** |
||
199 | * Send netlink message with control over sendmsg() message header. |
||
200 | * @arg sk Netlink socket. |
||
201 | * @arg msg Netlink message to be sent. |
||
202 | * @arg hdr Sendmsg() message header. |
||
203 | * @return Number of characters sent on sucess or a negative error code. |
||
204 | */ |
||
205 | int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr) |
||
206 | { |
||
207 | struct nl_cb *cb; |
||
208 | int ret; |
||
209 | |||
210 | nlmsg_set_src(msg, &sk->s_local); |
||
211 | |||
212 | cb = sk->s_cb; |
||
213 | if (cb->cb_set[NL_CB_MSG_OUT]) |
||
214 | if (nl_cb_call(cb, NL_CB_MSG_OUT, msg) != NL_OK) |
||
215 | return 0; |
||
216 | |||
217 | ret = sendmsg(sk->s_fd, hdr, 0); |
||
218 | if (ret < 0) |
||
219 | return -nl_syserr2nlerr(errno); |
||
220 | |||
221 | NL_DBG(4, "sent %d bytes\n", ret); |
||
222 | return ret; |
||
223 | } |
||
224 | |||
225 | |||
226 | /** |
||
227 | * Send netlink message. |
||
228 | * @arg sk Netlink socket. |
||
229 | * @arg msg Netlink message to be sent. |
||
230 | * @arg iov iovec to be sent. |
||
231 | * @arg iovlen number of struct iovec to be sent. |
||
232 | * @see nl_sendmsg() |
||
233 | * @return Number of characters sent on success or a negative error code. |
||
234 | */ |
||
235 | int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen) |
||
236 | { |
||
237 | struct sockaddr_nl *dst; |
||
238 | struct ucred *creds; |
||
239 | struct msghdr hdr = { |
||
240 | .msg_name = (void *) &sk->s_peer, |
||
241 | .msg_namelen = sizeof(struct sockaddr_nl), |
||
242 | .msg_iov = iov, |
||
243 | .msg_iovlen = iovlen, |
||
244 | }; |
||
245 | |||
246 | /* Overwrite destination if specified in the message itself, defaults |
||
247 | * to the peer address of the socket. |
||
248 | */ |
||
249 | dst = nlmsg_get_dst(msg); |
||
250 | if (dst->nl_family == AF_NETLINK) |
||
251 | hdr.msg_name = dst; |
||
252 | |||
253 | /* Add credentials if present. */ |
||
254 | creds = nlmsg_get_creds(msg); |
||
255 | if (creds != NULL) { |
||
256 | char buf[CMSG_SPACE(sizeof(struct ucred))]; |
||
257 | struct cmsghdr *cmsg; |
||
258 | |||
259 | hdr.msg_control = buf; |
||
260 | hdr.msg_controllen = sizeof(buf); |
||
261 | |||
262 | cmsg = CMSG_FIRSTHDR(&hdr); |
||
263 | cmsg->cmsg_level = SOL_SOCKET; |
||
264 | cmsg->cmsg_type = SCM_CREDENTIALS; |
||
265 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); |
||
266 | memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred)); |
||
267 | } |
||
268 | |||
269 | return nl_sendmsg(sk, msg, &hdr); |
||
270 | } |
||
271 | |||
272 | |||
273 | |||
274 | /** |
||
275 | * Send netlink message. |
||
276 | * @arg sk Netlink socket. |
||
277 | * @arg msg Netlink message to be sent. |
||
278 | * @see nl_sendmsg() |
||
279 | * @return Number of characters sent on success or a negative error code. |
||
280 | */ |
||
281 | int nl_send(struct nl_sock *sk, struct nl_msg *msg) |
||
282 | { |
||
283 | struct iovec iov = { |
||
284 | .iov_base = (void *) nlmsg_hdr(msg), |
||
285 | .iov_len = nlmsg_hdr(msg)->nlmsg_len, |
||
286 | }; |
||
287 | |||
288 | return nl_send_iovec(sk, msg, &iov, 1); |
||
289 | } |
||
290 | |||
291 | void nl_auto_complete(struct nl_sock *sk, struct nl_msg *msg) |
||
292 | { |
||
293 | struct nlmsghdr *nlh; |
||
294 | |||
295 | nlh = nlmsg_hdr(msg); |
||
296 | if (nlh->nlmsg_pid == 0) |
||
297 | nlh->nlmsg_pid = sk->s_local.nl_pid; |
||
298 | |||
299 | if (nlh->nlmsg_seq == 0) |
||
300 | nlh->nlmsg_seq = sk->s_seq_next++; |
||
301 | |||
302 | if (msg->nm_protocol == -1) |
||
303 | msg->nm_protocol = sk->s_proto; |
||
304 | |||
305 | nlh->nlmsg_flags |= NLM_F_REQUEST; |
||
306 | |||
307 | if (!(sk->s_flags & NL_NO_AUTO_ACK)) |
||
308 | nlh->nlmsg_flags |= NLM_F_ACK; |
||
309 | } |
||
310 | |||
311 | /** |
||
312 | * Send netlink message and check & extend header values as needed. |
||
313 | * @arg sk Netlink socket. |
||
314 | * @arg msg Netlink message to be sent. |
||
315 | * |
||
316 | * Checks the netlink message \c nlh for completness and extends it |
||
317 | * as required before sending it out. Checked fields include pid, |
||
318 | * sequence nr, and flags. |
||
319 | * |
||
320 | * @see nl_send() |
||
321 | * @return Number of characters sent or a negative error code. |
||
322 | */ |
||
323 | int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg) |
||
324 | { |
||
325 | struct nl_cb *cb = sk->s_cb; |
||
326 | |||
327 | nl_auto_complete(sk, msg); |
||
328 | |||
329 | if (cb->cb_send_ow) |
||
330 | return cb->cb_send_ow(sk, msg); |
||
331 | else |
||
332 | return nl_send(sk, msg); |
||
333 | } |
||
334 | |||
335 | /** |
||
336 | * Send simple netlink message using nl_send_auto_complete() |
||
337 | * @arg sk Netlink socket. |
||
338 | * @arg type Netlink message type. |
||
339 | * @arg flags Netlink message flags. |
||
340 | * @arg buf Data buffer. |
||
341 | * @arg size Size of data buffer. |
||
342 | * |
||
343 | * Builds a netlink message with the specified type and flags and |
||
344 | * appends the specified data as payload to the message. |
||
345 | * |
||
346 | * @see nl_send_auto_complete() |
||
347 | * @return Number of characters sent on success or a negative error code. |
||
348 | */ |
||
349 | int nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf, |
||
350 | size_t size) |
||
351 | { |
||
352 | int err; |
||
353 | struct nl_msg *msg; |
||
354 | |||
355 | msg = nlmsg_alloc_simple(type, flags); |
||
356 | if (!msg) |
||
357 | return -NLE_NOMEM; |
||
358 | |||
359 | if (buf && size) { |
||
360 | err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO); |
||
361 | if (err < 0) |
||
362 | goto errout; |
||
363 | } |
||
364 | |||
365 | |||
366 | err = nl_send_auto_complete(sk, msg); |
||
367 | errout: |
||
368 | nlmsg_free(msg); |
||
369 | |||
370 | return err; |
||
371 | } |
||
372 | |||
373 | /** @} */ |
||
374 | |||
375 | /** |
||
376 | * @name Receive |
||
377 | * @{ |
||
378 | */ |
||
379 | |||
380 | /** |
||
381 | * Receive data from netlink socket |
||
382 | * @arg sk Netlink socket. |
||
383 | * @arg nla Destination pointer for peer's netlink address. |
||
384 | * @arg buf Destination pointer for message content. |
||
385 | * @arg creds Destination pointer for credentials. |
||
386 | * |
||
387 | * Receives a netlink message, allocates a buffer in \c *buf and |
||
388 | * stores the message content. The peer's netlink address is stored |
||
389 | * in \c *nla. The caller is responsible for freeing the buffer allocated |
||
390 | * in \c *buf if a positive value is returned. Interruped system calls |
||
391 | * are handled by repeating the read. The input buffer size is determined |
||
392 | * by peeking before the actual read is done. |
||
393 | * |
||
394 | * A non-blocking sockets causes the function to return immediately with |
||
395 | * a return value of 0 if no data is available. |
||
396 | * |
||
397 | * @return Number of octets read, 0 on EOF or a negative error code. |
||
398 | */ |
||
399 | int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, |
||
400 | unsigned char **buf, struct ucred **creds) |
||
401 | { |
||
402 | int n; |
||
403 | int flags = 0; |
||
404 | static int page_size = 0; |
||
405 | struct iovec iov; |
||
406 | struct msghdr msg = { |
||
407 | .msg_name = (void *) nla, |
||
408 | .msg_namelen = sizeof(struct sockaddr_nl), |
||
409 | .msg_iov = &iov, |
||
410 | .msg_iovlen = 1, |
||
411 | .msg_control = NULL, |
||
412 | .msg_controllen = 0, |
||
413 | .msg_flags = 0, |
||
414 | }; |
||
415 | struct cmsghdr *cmsg; |
||
416 | |||
417 | if (sk->s_flags & NL_MSG_PEEK) |
||
418 | flags |= MSG_PEEK; |
||
419 | |||
420 | if (page_size == 0) |
||
421 | page_size = getpagesize(); |
||
422 | |||
423 | iov.iov_len = page_size; |
||
424 | iov.iov_base = *buf = malloc(iov.iov_len); |
||
425 | |||
426 | if (sk->s_flags & NL_SOCK_PASSCRED) { |
||
427 | msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred)); |
||
428 | msg.msg_control = calloc(1, msg.msg_controllen); |
||
429 | } |
||
430 | retry: |
||
431 | |||
432 | n = recvmsg(sk->s_fd, &msg, flags); |
||
433 | if (!n) |
||
434 | goto abort; |
||
435 | else if (n < 0) { |
||
436 | if (errno == EINTR) { |
||
437 | NL_DBG(3, "recvmsg() returned EINTR, retrying\n"); |
||
438 | goto retry; |
||
439 | } else if (errno == EAGAIN) { |
||
440 | NL_DBG(3, "recvmsg() returned EAGAIN, aborting\n"); |
||
441 | goto abort; |
||
442 | } else { |
||
443 | free(msg.msg_control); |
||
444 | free(*buf); |
||
445 | return -nl_syserr2nlerr(errno); |
||
446 | } |
||
447 | } |
||
448 | |||
449 | if (iov.iov_len < n || |
||
450 | msg.msg_flags & MSG_TRUNC) { |
||
451 | /* Provided buffer is not long enough, enlarge it |
||
452 | * and try again. */ |
||
453 | iov.iov_len *= 2; |
||
454 | iov.iov_base = *buf = realloc(*buf, iov.iov_len); |
||
455 | goto retry; |
||
456 | } else if (msg.msg_flags & MSG_CTRUNC) { |
||
457 | msg.msg_controllen *= 2; |
||
458 | msg.msg_control = realloc(msg.msg_control, msg.msg_controllen); |
||
459 | goto retry; |
||
460 | } else if (flags != 0) { |
||
461 | /* Buffer is big enough, do the actual reading */ |
||
462 | flags = 0; |
||
463 | goto retry; |
||
464 | } |
||
465 | |||
466 | if (msg.msg_namelen != sizeof(struct sockaddr_nl)) { |
||
467 | free(msg.msg_control); |
||
468 | free(*buf); |
||
469 | return -NLE_NOADDR; |
||
470 | } |
||
471 | |||
472 | for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { |
||
473 | if (cmsg->cmsg_level == SOL_SOCKET && |
||
474 | cmsg->cmsg_type == SCM_CREDENTIALS) { |
||
475 | *creds = calloc(1, sizeof(struct ucred)); |
||
476 | memcpy(*creds, CMSG_DATA(cmsg), sizeof(struct ucred)); |
||
477 | break; |
||
478 | } |
||
479 | } |
||
480 | |||
481 | free(msg.msg_control); |
||
482 | return n; |
||
483 | |||
484 | abort: |
||
485 | free(msg.msg_control); |
||
486 | free(*buf); |
||
487 | return 0; |
||
488 | } |
||
489 | |||
490 | #define NL_CB_CALL(cb, type, msg) \ |
||
491 | do { \ |
||
492 | err = nl_cb_call(cb, type, msg); \ |
||
493 | switch (err) { \ |
||
494 | case NL_OK: \ |
||
495 | err = 0; \ |
||
496 | break; \ |
||
497 | case NL_SKIP: \ |
||
498 | goto skip; \ |
||
499 | case NL_STOP: \ |
||
500 | goto stop; \ |
||
501 | default: \ |
||
502 | goto out; \ |
||
503 | } \ |
||
504 | } while (0) |
||
505 | |||
506 | static int recvmsgs(struct nl_sock *sk, struct nl_cb *cb) |
||
507 | { |
||
508 | int n, err = 0, multipart = 0; |
||
509 | unsigned char *buf = NULL; |
||
510 | struct nlmsghdr *hdr; |
||
511 | struct sockaddr_nl nla = {0}; |
||
512 | struct nl_msg *msg = NULL; |
||
513 | struct ucred *creds = NULL; |
||
514 | |||
515 | continue_reading: |
||
516 | NL_DBG(3, "Attempting to read from %p\n", sk); |
||
517 | if (cb->cb_recv_ow) |
||
518 | n = cb->cb_recv_ow(sk, &nla, &buf, &creds); |
||
519 | else |
||
520 | n = nl_recv(sk, &nla, &buf, &creds); |
||
521 | |||
522 | if (n <= 0) |
||
523 | return n; |
||
524 | |||
525 | NL_DBG(3, "recvmsgs(%p): Read %d bytes\n", sk, n); |
||
526 | |||
527 | hdr = (struct nlmsghdr *) buf; |
||
528 | while (nlmsg_ok(hdr, n)) { |
||
529 | NL_DBG(3, "recgmsgs(%p): Processing valid message...\n", sk); |
||
530 | |||
531 | nlmsg_free(msg); |
||
532 | msg = nlmsg_convert(hdr); |
||
533 | if (!msg) { |
||
534 | err = -NLE_NOMEM; |
||
535 | goto out; |
||
536 | } |
||
537 | |||
538 | nlmsg_set_proto(msg, sk->s_proto); |
||
539 | nlmsg_set_src(msg, &nla); |
||
540 | if (creds) |
||
541 | nlmsg_set_creds(msg, creds); |
||
542 | |||
543 | /* Raw callback is the first, it gives the most control |
||
544 | * to the user and he can do his very own parsing. */ |
||
545 | if (cb->cb_set[NL_CB_MSG_IN]) |
||
546 | NL_CB_CALL(cb, NL_CB_MSG_IN, msg); |
||
547 | |||
548 | /* Sequence number checking. The check may be done by |
||
549 | * the user, otherwise a very simple check is applied |
||
550 | * enforcing strict ordering */ |
||
551 | if (cb->cb_set[NL_CB_SEQ_CHECK]) |
||
552 | NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg); |
||
553 | else if (hdr->nlmsg_seq != sk->s_seq_expect) { |
||
554 | if (cb->cb_set[NL_CB_INVALID]) |
||
555 | NL_CB_CALL(cb, NL_CB_INVALID, msg); |
||
556 | else { |
||
557 | err = -NLE_SEQ_MISMATCH; |
||
558 | goto out; |
||
559 | } |
||
560 | } |
||
561 | |||
562 | if (hdr->nlmsg_type == NLMSG_DONE || |
||
563 | hdr->nlmsg_type == NLMSG_ERROR || |
||
564 | hdr->nlmsg_type == NLMSG_NOOP || |
||
565 | hdr->nlmsg_type == NLMSG_OVERRUN) { |
||
566 | /* We can't check for !NLM_F_MULTI since some netlink |
||
567 | * users in the kernel are broken. */ |
||
568 | sk->s_seq_expect++; |
||
569 | NL_DBG(3, "recvmsgs(%p): Increased expected " \ |
||
570 | "sequence number to %d\n", |
||
571 | sk, sk->s_seq_expect); |
||
572 | } |
||
573 | |||
574 | if (hdr->nlmsg_flags & NLM_F_MULTI) |
||
575 | multipart = 1; |
||
576 | |||
577 | /* Other side wishes to see an ack for this message */ |
||
578 | if (hdr->nlmsg_flags & NLM_F_ACK) { |
||
579 | if (cb->cb_set[NL_CB_SEND_ACK]) |
||
580 | NL_CB_CALL(cb, NL_CB_SEND_ACK, msg); |
||
581 | else { |
||
582 | /* FIXME: implement */ |
||
583 | } |
||
584 | } |
||
585 | |||
586 | /* messages terminates a multpart message, this is |
||
587 | * usually the end of a message and therefore we slip |
||
588 | * out of the loop by default. the user may overrule |
||
589 | * this action by skipping this packet. */ |
||
590 | if (hdr->nlmsg_type == NLMSG_DONE) { |
||
591 | multipart = 0; |
||
592 | if (cb->cb_set[NL_CB_FINISH]) |
||
593 | NL_CB_CALL(cb, NL_CB_FINISH, msg); |
||
594 | } |
||
595 | |||
596 | /* Message to be ignored, the default action is to |
||
597 | * skip this message if no callback is specified. The |
||
598 | * user may overrule this action by returning |
||
599 | * NL_PROCEED. */ |
||
600 | else if (hdr->nlmsg_type == NLMSG_NOOP) { |
||
601 | if (cb->cb_set[NL_CB_SKIPPED]) |
||
602 | NL_CB_CALL(cb, NL_CB_SKIPPED, msg); |
||
603 | else |
||
604 | goto skip; |
||
605 | } |
||
606 | |||
607 | /* Data got lost, report back to user. The default action is to |
||
608 | * quit parsing. The user may overrule this action by retuning |
||
609 | * NL_SKIP or NL_PROCEED (dangerous) */ |
||
610 | else if (hdr->nlmsg_type == NLMSG_OVERRUN) { |
||
611 | if (cb->cb_set[NL_CB_OVERRUN]) |
||
612 | NL_CB_CALL(cb, NL_CB_OVERRUN, msg); |
||
613 | else { |
||
614 | err = -NLE_MSG_OVERFLOW; |
||
615 | goto out; |
||
616 | } |
||
617 | } |
||
618 | |||
619 | /* Message carries a nlmsgerr */ |
||
620 | else if (hdr->nlmsg_type == NLMSG_ERROR) { |
||
621 | struct nlmsgerr *e = nlmsg_data(hdr); |
||
622 | |||
623 | if (hdr->nlmsg_len < nlmsg_msg_size(sizeof(*e))) { |
||
624 | /* Truncated error message, the default action |
||
625 | * is to stop parsing. The user may overrule |
||
626 | * this action by returning NL_SKIP or |
||
627 | * NL_PROCEED (dangerous) */ |
||
628 | if (cb->cb_set[NL_CB_INVALID]) |
||
629 | NL_CB_CALL(cb, NL_CB_INVALID, msg); |
||
630 | else { |
||
631 | err = -NLE_MSG_TRUNC; |
||
632 | goto out; |
||
633 | } |
||
634 | } else if (e->error) { |
||
635 | /* Error message reported back from kernel. */ |
||
636 | if (cb->cb_err) { |
||
637 | err = cb->cb_err(&nla, e, |
||
638 | cb->cb_err_arg); |
||
639 | if (err < 0) |
||
640 | goto out; |
||
641 | else if (err == NL_SKIP) |
||
642 | goto skip; |
||
643 | else if (err == NL_STOP) { |
||
644 | err = -nl_syserr2nlerr(e->error); |
||
645 | goto out; |
||
646 | } |
||
647 | } else { |
||
648 | err = -nl_syserr2nlerr(e->error); |
||
649 | goto out; |
||
650 | } |
||
651 | } else if (cb->cb_set[NL_CB_ACK]) |
||
652 | NL_CB_CALL(cb, NL_CB_ACK, msg); |
||
653 | } else { |
||
654 | /* Valid message (not checking for MULTIPART bit to |
||
655 | * get along with broken kernels. NL_SKIP has no |
||
656 | * effect on this. */ |
||
657 | if (cb->cb_set[NL_CB_VALID]) |
||
658 | NL_CB_CALL(cb, NL_CB_VALID, msg); |
||
659 | } |
||
660 | skip: |
||
661 | err = 0; |
||
662 | hdr = nlmsg_next(hdr, &n); |
||
663 | } |
||
664 | |||
665 | nlmsg_free(msg); |
||
666 | free(buf); |
||
667 | free(creds); |
||
668 | buf = NULL; |
||
669 | msg = NULL; |
||
670 | creds = NULL; |
||
671 | |||
672 | if (multipart) { |
||
673 | /* Multipart message not yet complete, continue reading */ |
||
674 | goto continue_reading; |
||
675 | } |
||
676 | stop: |
||
677 | err = 0; |
||
678 | out: |
||
679 | nlmsg_free(msg); |
||
680 | free(buf); |
||
681 | free(creds); |
||
682 | |||
683 | return err; |
||
684 | } |
||
685 | |||
686 | /** |
||
687 | * Receive a set of messages from a netlink socket. |
||
688 | * @arg sk Netlink socket. |
||
689 | * @arg cb set of callbacks to control behaviour. |
||
690 | * |
||
691 | * Repeatedly calls nl_recv() or the respective replacement if provided |
||
692 | * by the application (see nl_cb_overwrite_recv()) and parses the |
||
693 | * received data as netlink messages. Stops reading if one of the |
||
694 | * callbacks returns NL_STOP or nl_recv returns either 0 or a negative error code. |
||
695 | * |
||
696 | * A non-blocking sockets causes the function to return immediately if |
||
697 | * no data is available. |
||
698 | * |
||
699 | * @return 0 on success or a negative error code from nl_recv(). |
||
700 | */ |
||
701 | int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb) |
||
702 | { |
||
703 | if (cb->cb_recvmsgs_ow) |
||
704 | return cb->cb_recvmsgs_ow(sk, cb); |
||
705 | else |
||
706 | return recvmsgs(sk, cb); |
||
707 | } |
||
708 | |||
709 | /** |
||
710 | * Receive a set of message from a netlink socket using handlers in nl_sock. |
||
711 | * @arg sk Netlink socket. |
||
712 | * |
||
713 | * Calls nl_recvmsgs() with the handlers configured in the netlink socket. |
||
714 | */ |
||
715 | int nl_recvmsgs_default(struct nl_sock *sk) |
||
716 | { |
||
717 | return nl_recvmsgs(sk, sk->s_cb); |
||
718 | |||
719 | } |
||
720 | |||
721 | static int ack_wait_handler(struct nl_msg *msg, void *arg) |
||
722 | { |
||
723 | return NL_STOP; |
||
724 | } |
||
725 | |||
726 | /** |
||
727 | * Wait for ACK. |
||
728 | * @arg sk Netlink socket. |
||
729 | * @pre The netlink socket must be in blocking state. |
||
730 | * |
||
731 | * Waits until an ACK is received for the latest not yet acknowledged |
||
732 | * netlink message. |
||
733 | */ |
||
734 | int nl_wait_for_ack(struct nl_sock *sk) |
||
735 | { |
||
736 | int err; |
||
737 | struct nl_cb *cb; |
||
738 | |||
739 | cb = nl_cb_clone(sk->s_cb); |
||
740 | if (cb == NULL) |
||
741 | return -NLE_NOMEM; |
||
742 | |||
743 | nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, NULL); |
||
744 | err = nl_recvmsgs(sk, cb); |
||
745 | nl_cb_put(cb); |
||
746 | |||
747 | return err; |
||
748 | } |
||
749 | |||
750 | /** @} */ |
||
751 | |||
752 | /** @} */ |