1 /*
2 * lib/socket.c Netlink Socket
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 core
14 * @defgroup socket Socket
15 * @{
16 */
17
18 #include <netlink-local.h>
19 #include <netlink/netlink.h>
20 #include <netlink/utils.h>
21 #include <netlink/handlers.h>
22 #include <netlink/msg.h>
23 #include <netlink/attr.h>
24
25 static int default_cb = NL_CB_DEFAULT;
26
init_default_cb(void)27 static void __init init_default_cb(void)
28 {
29 char *nlcb;
30
31 if ((nlcb = getenv("NLCB"))) {
32 if (!strcasecmp(nlcb, "default"))
33 default_cb = NL_CB_DEFAULT;
34 else if (!strcasecmp(nlcb, "verbose"))
35 default_cb = NL_CB_VERBOSE;
36 else if (!strcasecmp(nlcb, "debug"))
37 default_cb = NL_CB_DEBUG;
38 else {
39 fprintf(stderr, "Unknown value for NLCB, valid values: "
40 "{default | verbose | debug}\n");
41 }
42 }
43 }
44
45 static uint32_t used_ports_map[32];
46
generate_local_port(void)47 static uint32_t generate_local_port(void)
48 {
49 int i, n;
50 uint32_t pid = getpid() & 0x3FFFFF;
51
52 for (i = 0; i < 32; i++) {
53 if (used_ports_map[i] == 0xFFFFFFFF)
54 continue;
55
56 for (n = 0; n < 32; n++) {
57 if (1UL & (used_ports_map[i] >> n))
58 continue;
59
60 used_ports_map[i] |= (1UL << n);
61 n += (i * 32);
62
63 /* PID_MAX_LIMIT is currently at 2^22, leaving 10 bit
64 * to, i.e. 1024 unique ports per application. */
65 return pid + (n << 22);
66
67 }
68 }
69
70 /* Out of sockets in our own PID namespace, what to do? FIXME */
71 return UINT_MAX;
72 }
73
release_local_port(uint32_t port)74 static void release_local_port(uint32_t port)
75 {
76 int nr;
77
78 if (port == UINT_MAX)
79 return;
80
81 nr = port >> 22;
82 used_ports_map[nr / 32] &= ~(1 << nr % 32);
83 }
84
85 /**
86 * @name Allocation
87 * @{
88 */
89
__alloc_socket(struct nl_cb * cb)90 static struct nl_sock *__alloc_socket(struct nl_cb *cb)
91 {
92 struct nl_sock *sk;
93
94 sk = calloc(1, sizeof(*sk));
95 if (!sk)
96 return NULL;
97
98 sk->s_fd = -1;
99 sk->s_cb = cb;
100 sk->s_local.nl_family = AF_NETLINK;
101 sk->s_peer.nl_family = AF_NETLINK;
102 sk->s_seq_expect = sk->s_seq_next = time(0);
103 sk->s_local.nl_pid = generate_local_port();
104 if (sk->s_local.nl_pid == UINT_MAX) {
105 nl_socket_free(sk);
106 return NULL;
107 }
108
109 return sk;
110 }
111
112 /**
113 * Allocate new netlink socket
114 *
115 * @return Newly allocated netlink socket or NULL.
116 */
nl_socket_alloc(void)117 struct nl_sock *nl_socket_alloc(void)
118 {
119 struct nl_cb *cb;
120
121 cb = nl_cb_alloc(default_cb);
122 if (!cb)
123 return NULL;
124
125 return __alloc_socket(cb);
126 }
127
128 /**
129 * Allocate new socket with custom callbacks
130 * @arg cb Callback handler
131 *
132 * The reference to the callback handler is taken into account
133 * automatically, it is released again upon calling nl_socket_free().
134 *
135 *@return Newly allocted socket handle or NULL.
136 */
nl_socket_alloc_cb(struct nl_cb * cb)137 struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb)
138 {
139 if (cb == NULL)
140 BUG();
141
142 return __alloc_socket(nl_cb_get(cb));
143 }
144
145 /**
146 * Free a netlink socket.
147 * @arg sk Netlink socket.
148 */
nl_socket_free(struct nl_sock * sk)149 void nl_socket_free(struct nl_sock *sk)
150 {
151 if (!sk)
152 return;
153
154 if (sk->s_fd >= 0)
155 close(sk->s_fd);
156
157 if (!(sk->s_flags & NL_OWN_PORT))
158 release_local_port(sk->s_local.nl_pid);
159
160 nl_cb_put(sk->s_cb);
161 free(sk);
162 }
163
164 /** @} */
165
166 /**
167 * @name Sequence Numbers
168 * @{
169 */
170
noop_seq_check(struct nl_msg * msg,void * arg)171 static int noop_seq_check(struct nl_msg *msg, void *arg)
172 {
173 return NL_OK;
174 }
175
176
177 /**
178 * Disable sequence number checking.
179 * @arg sk Netlink socket.
180 *
181 * Disables checking of sequence numbers on the netlink socket This is
182 * required to allow messages to be processed which were not requested by
183 * a preceding request message, e.g. netlink events.
184 *
185 * @note This function modifies the NL_CB_SEQ_CHECK configuration in
186 * the callback handle associated with the socket.
187 */
nl_socket_disable_seq_check(struct nl_sock * sk)188 void nl_socket_disable_seq_check(struct nl_sock *sk)
189 {
190 nl_cb_set(sk->s_cb, NL_CB_SEQ_CHECK,
191 NL_CB_CUSTOM, noop_seq_check, NULL);
192 }
193
194 /**
195 * Use next sequence number
196 * @arg sk Netlink socket.
197 *
198 * Uses the next available sequence number and increases the counter
199 * by one for subsequent calls.
200 *
201 * @return Unique serial sequence number
202 */
nl_socket_use_seq(struct nl_sock * sk)203 unsigned int nl_socket_use_seq(struct nl_sock *sk)
204 {
205 return sk->s_seq_next++;
206 }
207
208 /**
209 * Disable automatic request for ACK
210 * @arg sk Netlink socket.
211 *
212 * The default behaviour of a socket is to request an ACK for
213 * each message sent to allow for the caller to synchronize to
214 * the completion of the netlink operation. This function
215 * disables this behaviour and will result in requests being
216 * sent which will not have the NLM_F_ACK flag set automatically.
217 * However, it is still possible for the caller to set the
218 * NLM_F_ACK flag explicitely.
219 */
nl_socket_disable_auto_ack(struct nl_sock * sk)220 void nl_socket_disable_auto_ack(struct nl_sock *sk)
221 {
222 sk->s_flags |= NL_NO_AUTO_ACK;
223 }
224
225 /**
226 * Enable automatic request for ACK (default)
227 * @arg sk Netlink socket.
228 * @see nl_socket_disable_auto_ack
229 */
nl_socket_enable_auto_ack(struct nl_sock * sk)230 void nl_socket_enable_auto_ack(struct nl_sock *sk)
231 {
232 sk->s_flags &= ~NL_NO_AUTO_ACK;
233 }
234
235 /** @} */
236
237 /**
238 * @name Source Idenficiation
239 * @{
240 */
241
nl_socket_get_local_port(struct nl_sock * sk)242 uint32_t nl_socket_get_local_port(struct nl_sock *sk)
243 {
244 return sk->s_local.nl_pid;
245 }
246
247 /**
248 * Set local port of socket
249 * @arg sk Netlink socket.
250 * @arg port Local port identifier
251 *
252 * Assigns a local port identifier to the socket. If port is 0
253 * a unique port identifier will be generated automatically.
254 */
nl_socket_set_local_port(struct nl_sock * sk,uint32_t port)255 void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port)
256 {
257 if (port == 0) {
258 port = generate_local_port();
259 sk->s_flags &= ~NL_OWN_PORT;
260 } else {
261 if (!(sk->s_flags & NL_OWN_PORT))
262 release_local_port(sk->s_local.nl_pid);
263 sk->s_flags |= NL_OWN_PORT;
264 }
265
266 sk->s_local.nl_pid = port;
267 }
268
269 /** @} */
270
271 /**
272 * @name Group Subscriptions
273 * @{
274 */
275
276 /**
277 * Join groups
278 * @arg sk Netlink socket
279 * @arg group Group identifier
280 *
281 * Joins the specified groups using the modern socket option which
282 * is available since kernel version 2.6.14. It allows joining an
283 * almost arbitary number of groups without limitation. The list
284 * of groups has to be terminated by 0 (%NFNLGRP_NONE).
285 *
286 * Make sure to use the correct group definitions as the older
287 * bitmask definitions for nl_join_groups() are likely to still
288 * be present for backward compatibility reasons.
289 *
290 * @return 0 on sucess or a negative error code.
291 */
nl_socket_add_memberships(struct nl_sock * sk,int group,...)292 int nl_socket_add_memberships(struct nl_sock *sk, int group, ...)
293 {
294 int err;
295 va_list ap;
296
297 if (sk->s_fd == -1)
298 return -NLE_BAD_SOCK;
299
300 va_start(ap, group);
301
302 while (group != 0) {
303 if (group < 0)
304 return -NLE_INVAL;
305
306 err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
307 &group, sizeof(group));
308 if (err < 0)
309 return -nl_syserr2nlerr(errno);
310
311 group = va_arg(ap, int);
312 }
313
314 va_end(ap);
315
316 return 0;
317 }
318
nl_socket_add_membership(struct nl_sock * sk,int group)319 int nl_socket_add_membership(struct nl_sock *sk, int group)
320 {
321 return nl_socket_add_memberships(sk, group, 0);
322 }
323
324 /**
325 * Leave groups
326 * @arg sk Netlink socket
327 * @arg group Group identifier
328 *
329 * Leaves the specified groups using the modern socket option
330 * which is available since kernel version 2.6.14. The list of groups
331 * has to terminated by 0 (%NFNLGRP_NONE).
332 *
333 * @see nl_socket_add_membership
334 * @return 0 on success or a negative error code.
335 */
nl_socket_drop_memberships(struct nl_sock * sk,int group,...)336 int nl_socket_drop_memberships(struct nl_sock *sk, int group, ...)
337 {
338 int err;
339 va_list ap;
340
341 if (sk->s_fd == -1)
342 return -NLE_BAD_SOCK;
343
344 va_start(ap, group);
345
346 while (group != 0) {
347 if (group < 0)
348 return -NLE_INVAL;
349
350 err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
351 &group, sizeof(group));
352 if (err < 0)
353 return -nl_syserr2nlerr(errno);
354
355 group = va_arg(ap, int);
356 }
357
358 va_end(ap);
359
360 return 0;
361 }
362
nl_socket_drop_membership(struct nl_sock * sk,int group)363 int nl_socket_drop_membership(struct nl_sock *sk, int group)
364 {
365 return nl_socket_drop_memberships(sk, group, 0);
366 }
367
368
369 /**
370 * Join multicast groups (deprecated)
371 * @arg sk Netlink socket.
372 * @arg groups Bitmask of groups to join.
373 *
374 * This function defines the old way of joining multicast group which
375 * has to be done prior to calling nl_connect(). It works on any kernel
376 * version but is very limited as only 32 groups can be joined.
377 */
nl_join_groups(struct nl_sock * sk,int groups)378 void nl_join_groups(struct nl_sock *sk, int groups)
379 {
380 sk->s_local.nl_groups |= groups;
381 }
382
383
384 /** @} */
385
386 /**
387 * @name Peer Identfication
388 * @{
389 */
390
nl_socket_get_peer_port(struct nl_sock * sk)391 uint32_t nl_socket_get_peer_port(struct nl_sock *sk)
392 {
393 return sk->s_peer.nl_pid;
394 }
395
nl_socket_set_peer_port(struct nl_sock * sk,uint32_t port)396 void nl_socket_set_peer_port(struct nl_sock *sk, uint32_t port)
397 {
398 sk->s_peer.nl_pid = port;
399 }
400
401 /** @} */
402
403 /**
404 * @name File Descriptor
405 * @{
406 */
407
nl_socket_get_fd(struct nl_sock * sk)408 int nl_socket_get_fd(struct nl_sock *sk)
409 {
410 return sk->s_fd;
411 }
412
413 /**
414 * Set file descriptor of socket to non-blocking state
415 * @arg sk Netlink socket.
416 *
417 * @return 0 on success or a negative error code.
418 */
nl_socket_set_nonblocking(struct nl_sock * sk)419 int nl_socket_set_nonblocking(struct nl_sock *sk)
420 {
421 if (sk->s_fd == -1)
422 return -NLE_BAD_SOCK;
423
424 if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
425 return -nl_syserr2nlerr(errno);
426
427 return 0;
428 }
429
430 /**
431 * Enable use of MSG_PEEK when reading from socket
432 * @arg sk Netlink socket.
433 */
nl_socket_enable_msg_peek(struct nl_sock * sk)434 void nl_socket_enable_msg_peek(struct nl_sock *sk)
435 {
436 sk->s_flags |= NL_MSG_PEEK;
437 }
438
439 /**
440 * Disable use of MSG_PEEK when reading from socket
441 * @arg sk Netlink socket.
442 */
nl_socket_disable_msg_peek(struct nl_sock * sk)443 void nl_socket_disable_msg_peek(struct nl_sock *sk)
444 {
445 sk->s_flags &= ~NL_MSG_PEEK;
446 }
447
448 /** @} */
449
450 /**
451 * @name Callback Handler
452 * @{
453 */
454
nl_socket_get_cb(struct nl_sock * sk)455 struct nl_cb *nl_socket_get_cb(struct nl_sock *sk)
456 {
457 return nl_cb_get(sk->s_cb);
458 }
459
nl_socket_set_cb(struct nl_sock * sk,struct nl_cb * cb)460 void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb)
461 {
462 nl_cb_put(sk->s_cb);
463 sk->s_cb = nl_cb_get(cb);
464 }
465
466 /**
467 * Modify the callback handler associated to the socket
468 * @arg sk Netlink socket.
469 * @arg type which type callback to set
470 * @arg kind kind of callback
471 * @arg func callback function
472 * @arg arg argument to be passwd to callback function
473 *
474 * @see nl_cb_set
475 */
nl_socket_modify_cb(struct nl_sock * sk,enum nl_cb_type type,enum nl_cb_kind kind,nl_recvmsg_msg_cb_t func,void * arg)476 int nl_socket_modify_cb(struct nl_sock *sk, enum nl_cb_type type,
477 enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func,
478 void *arg)
479 {
480 return nl_cb_set(sk->s_cb, type, kind, func, arg);
481 }
482
483 /** @} */
484
485 /**
486 * @name Utilities
487 * @{
488 */
489
490 /**
491 * Set socket buffer size of netlink socket.
492 * @arg sk Netlink socket.
493 * @arg rxbuf New receive socket buffer size in bytes.
494 * @arg txbuf New transmit socket buffer size in bytes.
495 *
496 * Sets the socket buffer size of a netlink socket to the specified
497 * values \c rxbuf and \c txbuf. Providing a value of \c 0 assumes a
498 * good default value.
499 *
500 * @note It is not required to call this function prior to nl_connect().
501 * @return 0 on sucess or a negative error code.
502 */
nl_socket_set_buffer_size(struct nl_sock * sk,int rxbuf,int txbuf)503 int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
504 {
505 int err;
506
507 if (rxbuf <= 0)
508 rxbuf = 32768;
509
510 if (txbuf <= 0)
511 txbuf = 32768;
512
513 if (sk->s_fd == -1)
514 return -NLE_BAD_SOCK;
515
516 err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF,
517 &txbuf, sizeof(txbuf));
518 if (err < 0)
519 return -nl_syserr2nlerr(errno);
520
521 err = setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF,
522 &rxbuf, sizeof(rxbuf));
523 if (err < 0)
524 return -nl_syserr2nlerr(errno);
525
526 sk->s_flags |= NL_SOCK_BUFSIZE_SET;
527
528 return 0;
529 }
530
531 /**
532 * Enable/disable credential passing on netlink socket.
533 * @arg sk Netlink socket.
534 * @arg state New state (0 - disabled, 1 - enabled)
535 *
536 * @return 0 on success or a negative error code
537 */
nl_socket_set_passcred(struct nl_sock * sk,int state)538 int nl_socket_set_passcred(struct nl_sock *sk, int state)
539 {
540 int err;
541
542 if (sk->s_fd == -1)
543 return -NLE_BAD_SOCK;
544
545 err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED,
546 &state, sizeof(state));
547 if (err < 0)
548 return -nl_syserr2nlerr(errno);
549
550 if (state)
551 sk->s_flags |= NL_SOCK_PASSCRED;
552 else
553 sk->s_flags &= ~NL_SOCK_PASSCRED;
554
555 return 0;
556 }
557
558 /**
559 * Enable/disable receival of additional packet information
560 * @arg sk Netlink socket.
561 * @arg state New state (0 - disabled, 1 - enabled)
562 *
563 * @return 0 on success or a negative error code
564 */
nl_socket_recv_pktinfo(struct nl_sock * sk,int state)565 int nl_socket_recv_pktinfo(struct nl_sock *sk, int state)
566 {
567 int err;
568
569 if (sk->s_fd == -1)
570 return -NLE_BAD_SOCK;
571
572 err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_PKTINFO,
573 &state, sizeof(state));
574 if (err < 0)
575 return -nl_syserr2nlerr(errno);
576
577 return 0;
578 }
579
580 /** @} */
581
582 /** @} */
583