libnl  1.1
socket.c
1 /*
2  * lib/socket.c Netlink Socket Handle
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-2006 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @ingroup nl
14  * @defgroup socket Socket
15  * @brief Handle representing a netlink socket.
16  *
17  * The socket is represented in a structure called the netlink handle,
18  * besides the socket, it stores various settings and values related
19  * to the socket. Every socket handle has a mandatory association with
20  * a set of callbacks which can be used to modify the behaviour when
21  * sending/receiving data from the socket.
22  *
23  * @par Socket Attributes
24  * - \b Local \b Port: The local port is a netlink port identifying the
25  * local endpoint. It is used as source address for outgoing messages
26  * and will be addressed in replies. It must therefore be unique among
27  * all userspace applications. When the socket handle is allocated, a
28  * unique port number is generated automatically in the form of 22 bits
29  * Process Identifier + 10 bits Arbitary Number. Therefore the library
30  * is capable of generating 1024 unique local port numbers for every
31  * process. If more sockets are required, the application has to manage
32  * port numbers itself using nl_socket_set_local_port().
33  * - \b Group \b Subscriptions: A socket can subscribe to any number of
34  * multicast groups. It will then receive a copy of all messages sent
35  * to one of the groups. This method is mainly used for event notification.
36  * Prior to kernel 2.6.14, the group subscription was done via bitmask
37  * which limited to a total number of groups of 32. With 2.6.14 a new
38  * method was added based on continous identifiers which supports an
39  * arbitary number of groups. Both methods are supported, see
40  * nl_join_groups() respectively nl_socket_add_membership() and
41  * nl_socket_drop_membership().
42  * - \b Peer \b Port: The peer port is a netlink port identifying the
43  * peer's endpoint. If no peer port is specified, the kernel will try to
44  * autobind to a socket of the specified netlink family automatically.
45  * This is very common as typically only one listening socket exists
46  * on the kernel side. The peer port can be modified using
47  * nl_socket_set_peer_port().
48  * - \b Peer \b Groups:
49  * - \b File \b Descriptor: The file descriptor of the socket, it can be
50  * accessed via nl_socket_get_fd() to change socket options or monitor
51  * activity using poll()/select().
52  * - \b Protocol: Once connected, the socket is bound to stick to one
53  * netlink family. This field is invisible, it is maintained automatically.
54  * (See nl_connect())
55  * - \b Next \b Sequence \b Number: Next available sequence number to be used
56  * for the next message being sent out. (Initial value: UNIX time when the
57  * socket was allocated.) Sequence numbers can be used via
58  * nl_socket_use_seq().
59  * - \b Expected \b Sequence \b Number: Expected sequence number in the next
60  * message received from the socket. (Initial value: Equal to next sequence
61  * number.)
62  * - \b Callbacks \b Configuration:
63  *
64  * @par 1) Creating the netlink handle
65  * @code
66  * struct nl_handle *handle;
67  *
68  * // Allocate and initialize a new netlink handle
69  * handle = nl_handle_alloc();
70  *
71  * // Use nl_socket_get_fd() to fetch the file description, for example to
72  * // put a socket into non-blocking i/o mode.
73  * fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
74  * @endcode
75  *
76  * @par 2) Group Subscriptions
77  * @code
78  * // Event notifications are typically sent to multicast addresses which
79  * // represented by groups. Join a group to f.e. receive link notifications.
80  * nl_socket_add_membership(handle, RTNLGRP_LINK);
81  * @endcode
82  *
83  * @par 6) Cleaning up
84  * @code
85  * // Finally destroy the netlink handle
86  * nl_handle_destroy(handle);
87  * @endcode
88  *
89  * @{
90  */
91 
92 #include <pthread.h>
93 
94 #include <netlink-local.h>
95 #include <netlink/netlink.h>
96 #include <netlink/utils.h>
97 #include <netlink/handlers.h>
98 #include <netlink/msg.h>
99 #include <netlink/attr.h>
100 
101 static int default_cb = NL_CB_DEFAULT;
102 
103 static void __init init_default_cb(void)
104 {
105  char *nlcb;
106 
107  if ((nlcb = getenv("NLCB"))) {
108  if (!strcasecmp(nlcb, "default"))
109  default_cb = NL_CB_DEFAULT;
110  else if (!strcasecmp(nlcb, "verbose"))
111  default_cb = NL_CB_VERBOSE;
112  else if (!strcasecmp(nlcb, "debug"))
113  default_cb = NL_CB_DEBUG;
114  else {
115  fprintf(stderr, "Unknown value for NLCB, valid values: "
116  "{default | verbose | debug}\n");
117  }
118  }
119 }
120 
121 static uint32_t used_ports_map[32];
122 static pthread_mutex_t port_map_mutex = PTHREAD_MUTEX_INITIALIZER;
123 
124 static uint32_t generate_local_port(void)
125 {
126  int i, n;
127  uint32_t pid = getpid() & 0x3FFFFF;
128 
129  pthread_mutex_lock(&port_map_mutex);
130 
131  for (i = 0; i < 32; i++) {
132  if (used_ports_map[i] == 0xFFFFFFFF)
133  continue;
134 
135  for (n = 0; n < 32; n++) {
136  if (1UL & (used_ports_map[i] >> n))
137  continue;
138 
139  used_ports_map[i] |= (1UL << n);
140  n += (i * 32);
141 
142  /* PID_MAX_LIMIT is currently at 2^22, leaving 10 bit
143  * to, i.e. 1024 unique ports per application. */
144 
145  pthread_mutex_unlock(&port_map_mutex);
146 
147  return pid + (n << 22);
148  }
149  }
150 
151  pthread_mutex_unlock(&port_map_mutex);
152 
153  /* Out of sockets in our own PID namespace, what to do? FIXME */
154  return UINT_MAX;
155 }
156 
157 static void release_local_port(uint32_t port)
158 {
159  int nr;
160 
161  if (port == UINT_MAX)
162  return;
163 
164  nr = port >> 22;
165 
166  pthread_mutex_lock(&port_map_mutex);
167  used_ports_map[nr / 32] &= ~(1 << (nr % 32));
168  pthread_mutex_unlock(&port_map_mutex);
169 }
170 
171 /**
172  * @name Allocation
173  * @{
174  */
175 
176 static struct nl_handle *__alloc_handle(struct nl_cb *cb)
177 {
178  struct nl_handle *handle;
179 
180  handle = calloc(1, sizeof(*handle));
181  if (!handle) {
182  nl_errno(ENOMEM);
183  return NULL;
184  }
185 
186  handle->h_fd = -1;
187  handle->h_cb = cb;
188  handle->h_local.nl_family = AF_NETLINK;
189  handle->h_peer.nl_family = AF_NETLINK;
190  handle->h_seq_expect = handle->h_seq_next = time(0);
191  handle->h_local.nl_pid = generate_local_port();
192  if (handle->h_local.nl_pid == UINT_MAX) {
193  nl_handle_destroy(handle);
194  nl_error(ENOBUFS, "Out of local ports");
195  return NULL;
196  }
197 
198  return handle;
199 }
200 
201 /**
202  * Allocate new netlink socket handle.
203  *
204  * @return Newly allocated netlink socket handle or NULL.
205  */
206 struct nl_handle *nl_handle_alloc(void)
207 {
208  struct nl_cb *cb;
209 
210  cb = nl_cb_alloc(default_cb);
211  if (!cb) {
212  nl_errno(ENOMEM);
213  return NULL;
214  }
215 
216  return __alloc_handle(cb);
217 }
218 
219 /**
220  * Allocate new socket handle with custom callbacks
221  * @arg cb Callback handler
222  *
223  * The reference to the callback handler is taken into account
224  * automatically, it is released again upon calling nl_handle_destroy().
225  *
226  *@return Newly allocted socket handle or NULL.
227  */
228 struct nl_handle *nl_handle_alloc_cb(struct nl_cb *cb)
229 {
230  if (cb == NULL)
231  BUG();
232 
233  return __alloc_handle(nl_cb_get(cb));
234 }
235 
236 /**
237  * Destroy netlink handle.
238  * @arg handle Netlink handle.
239  */
240 void nl_handle_destroy(struct nl_handle *handle)
241 {
242  if (!handle)
243  return;
244 
245  if (handle->h_fd >= 0)
246  close(handle->h_fd);
247 
248  if (!(handle->h_flags & NL_OWN_PORT))
249  release_local_port(handle->h_local.nl_pid);
250 
251  nl_cb_put(handle->h_cb);
252  free(handle);
253 }
254 
255 /** @} */
256 
257 /**
258  * @name Sequence Numbers
259  * @{
260  */
261 
262 static int noop_seq_check(struct nl_msg *msg, void *arg)
263 {
264  return NL_OK;
265 }
266 
267 
268 /**
269  * Disable sequence number checking.
270  * @arg handle Netlink handle.
271  *
272  * Disables checking of sequence numbers on the netlink handle. This is
273  * required to allow messages to be processed which were not requested by
274  * a preceding request message, e.g. netlink events.
275  *
276  * @note This function modifies the NL_CB_SEQ_CHECK configuration in
277  * the callback handle associated with the socket.
278  */
279 void nl_disable_sequence_check(struct nl_handle *handle)
280 {
281  nl_cb_set(handle->h_cb, NL_CB_SEQ_CHECK,
282  NL_CB_CUSTOM, noop_seq_check, NULL);
283 }
284 
285 /**
286  * Use next sequence number
287  * @arg handle Netlink handle
288  *
289  * Uses the next available sequence number and increases the counter
290  * by one for subsequent calls.
291  *
292  * @return Unique serial sequence number
293  */
294 unsigned int nl_socket_use_seq(struct nl_handle *handle)
295 {
296  return handle->h_seq_next++;
297 }
298 
299 /** @} */
300 
301 /**
302  * @name Source Idenficiation
303  * @{
304  */
305 
306 uint32_t nl_socket_get_local_port(struct nl_handle *handle)
307 {
308  return handle->h_local.nl_pid;
309 }
310 
311 /**
312  * Set local port of socket
313  * @arg handle Netlink handle
314  * @arg port Local port identifier
315  *
316  * Assigns a local port identifier to the socket. If port is 0
317  * a unique port identifier will be generated automatically.
318  */
319 void nl_socket_set_local_port(struct nl_handle *handle, uint32_t port)
320 {
321  if (port == 0) {
322  port = generate_local_port();
323  handle->h_flags &= ~NL_OWN_PORT;
324  } else {
325  if (!(handle->h_flags & NL_OWN_PORT))
326  release_local_port(handle->h_local.nl_pid);
327  handle->h_flags |= NL_OWN_PORT;
328  }
329 
330  handle->h_local.nl_pid = port;
331 }
332 
333 /** @} */
334 
335 /**
336  * @name Group Subscriptions
337  * @{
338  */
339 
340 /**
341  * Join a group
342  * @arg handle Netlink handle
343  * @arg group Group identifier
344  *
345  * Joins the specified group using the modern socket option which
346  * is available since kernel version 2.6.14. It allows joining an
347  * almost arbitary number of groups without limitation.
348  *
349  * Make sure to use the correct group definitions as the older
350  * bitmask definitions for nl_join_groups() are likely to still
351  * be present for backward compatibility reasons.
352  *
353  * @return 0 on sucess or a negative error code.
354  */
355 int nl_socket_add_membership(struct nl_handle *handle, int group)
356 {
357  int err;
358 
359  if (handle->h_fd == -1)
360  return nl_error(EBADFD, "Socket not connected");
361 
362  err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
363  &group, sizeof(group));
364  if (err < 0)
365  return nl_error(errno, "setsockopt(NETLINK_ADD_MEMBERSHIP) "
366  "failed");
367 
368  return 0;
369 }
370 
371 /**
372  * Leave a group
373  * @arg handle Netlink handle
374  * @arg group Group identifier
375  *
376  * Leaves the specified group using the modern socket option
377  * which is available since kernel version 2.6.14.
378  *
379  * @see nl_socket_add_membership
380  * @return 0 on success or a negative error code.
381  */
382 int nl_socket_drop_membership(struct nl_handle *handle, int group)
383 {
384  int err;
385 
386  if (handle->h_fd == -1)
387  return nl_error(EBADFD, "Socket not connected");
388 
389  err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
390  &group, sizeof(group));
391  if (err < 0)
392  return nl_error(errno, "setsockopt(NETLINK_DROP_MEMBERSHIP) "
393  "failed");
394 
395  return 0;
396 }
397 
398 /**
399  * Join multicast groups (deprecated)
400  * @arg handle Netlink handle.
401  * @arg groups Bitmask of groups to join.
402  *
403  * This function defines the old way of joining multicast group which
404  * has to be done prior to calling nl_connect(). It works on any kernel
405  * version but is very limited as only 32 groups can be joined.
406  */
407 void nl_join_groups(struct nl_handle *handle, int groups)
408 {
409  handle->h_local.nl_groups |= groups;
410 }
411 
412 
413 /** @} */
414 
415 /**
416  * @name Peer Identfication
417  * @{
418  */
419 
420 uint32_t nl_socket_get_peer_port(struct nl_handle *handle)
421 {
422  return handle->h_peer.nl_pid;
423 }
424 
425 void nl_socket_set_peer_port(struct nl_handle *handle, uint32_t port)
426 {
427  handle->h_peer.nl_pid = port;
428 }
429 
430 /** @} */
431 
432 /**
433  * @name File Descriptor
434  * @{
435  */
436 
437 int nl_socket_get_fd(struct nl_handle *handle)
438 {
439  return handle->h_fd;
440 }
441 
442 /**
443  * Set file descriptor of socket handle to non-blocking state
444  * @arg handle Netlink socket
445  *
446  * @return 0 on success or a negative error code.
447  */
448 int nl_socket_set_nonblocking(struct nl_handle *handle)
449 {
450  if (handle->h_fd == -1)
451  return nl_error(EBADFD, "Socket not connected");
452 
453  if (fcntl(handle->h_fd, F_SETFL, O_NONBLOCK) < 0)
454  return nl_error(errno, "fcntl(F_SETFL, O_NONBLOCK) failed");
455 
456  return 0;
457 }
458 
459 /**
460  * Enable use of MSG_PEEK when reading from socket
461  * @arg handle Netlink socket
462  */
463 void nl_socket_enable_msg_peek(struct nl_handle *handle)
464 {
465  handle->h_flags |= NL_MSG_PEEK;
466 }
467 
468 /**
469  * Disable use of MSG_PEEK when reading from socket
470  * @arg handle Netlink socket
471  */
472 void nl_socket_disable_msg_peek(struct nl_handle *handle)
473 {
474  handle->h_flags &= ~NL_MSG_PEEK;
475 }
476 
477 /** @} */
478 
479 /**
480  * @name Callback Handler
481  * @{
482  */
483 
484 struct nl_cb *nl_socket_get_cb(struct nl_handle *handle)
485 {
486  return nl_cb_get(handle->h_cb);
487 }
488 
489 void nl_socket_set_cb(struct nl_handle *handle, struct nl_cb *cb)
490 {
491  nl_cb_put(handle->h_cb);
492  handle->h_cb = nl_cb_get(cb);
493 }
494 
495 /**
496  * Modify the callback handler associated to the socket
497  * @arg handle netlink handle
498  * @arg type which type callback to set
499  * @arg kind kind of callback
500  * @arg func callback function
501  * @arg arg argument to be passwd to callback function
502  *
503  * @see nl_cb_set
504  */
505 int nl_socket_modify_cb(struct nl_handle *handle, enum nl_cb_type type,
506  enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func,
507  void *arg)
508 {
509  return nl_cb_set(handle->h_cb, type, kind, func, arg);
510 }
511 
512 /** @} */
513 
514 /**
515  * @name Utilities
516  * @{
517  */
518 
519 /**
520  * Set socket buffer size of netlink handle.
521  * @arg handle Netlink handle.
522  * @arg rxbuf New receive socket buffer size in bytes.
523  * @arg txbuf New transmit socket buffer size in bytes.
524  *
525  * Sets the socket buffer size of a netlink handle to the specified
526  * values \c rxbuf and \c txbuf. Providing a value of \c 0 assumes a
527  * good default value.
528  *
529  * @note It is not required to call this function prior to nl_connect().
530  * @return 0 on sucess or a negative error code.
531  */
532 int nl_set_buffer_size(struct nl_handle *handle, int rxbuf, int txbuf)
533 {
534  int err;
535 
536  if (rxbuf <= 0)
537  rxbuf = 32768;
538 
539  if (txbuf <= 0)
540  txbuf = 32768;
541 
542  if (handle->h_fd == -1)
543  return nl_error(EBADFD, "Socket not connected");
544 
545  err = setsockopt(handle->h_fd, SOL_SOCKET, SO_SNDBUF,
546  &txbuf, sizeof(txbuf));
547  if (err < 0)
548  return nl_error(errno, "setsockopt(SO_SNDBUF) failed");
549 
550  err = setsockopt(handle->h_fd, SOL_SOCKET, SO_RCVBUF,
551  &rxbuf, sizeof(rxbuf));
552  if (err < 0)
553  return nl_error(errno, "setsockopt(SO_RCVBUF) failed");
554 
555  handle->h_flags |= NL_SOCK_BUFSIZE_SET;
556 
557  return 0;
558 }
559 
560 /**
561  * Enable/disable credential passing on netlink handle.
562  * @arg handle Netlink handle
563  * @arg state New state (0 - disabled, 1 - enabled)
564  *
565  * @return 0 on success or a negative error code
566  */
567 int nl_set_passcred(struct nl_handle *handle, int state)
568 {
569  int err;
570 
571  if (handle->h_fd == -1)
572  return nl_error(EBADFD, "Socket not connected");
573 
574  err = setsockopt(handle->h_fd, SOL_SOCKET, SO_PASSCRED,
575  &state, sizeof(state));
576  if (err < 0)
577  return nl_error(errno, "setsockopt(SO_PASSCRED) failed");
578 
579  if (state)
580  handle->h_flags |= NL_SOCK_PASSCRED;
581  else
582  handle->h_flags &= ~NL_SOCK_PASSCRED;
583 
584  return 0;
585 }
586 
587 /**
588  * Enable/disable receival of additional packet information
589  * @arg handle Netlink handle
590  * @arg state New state (0 - disabled, 1 - enabled)
591  *
592  * @return 0 on success or a negative error code
593  */
594 int nl_socket_recv_pktinfo(struct nl_handle *handle, int state)
595 {
596  int err;
597 
598  if (handle->h_fd == -1)
599  return nl_error(EBADFD, "Socket not connected");
600 
601  err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_PKTINFO,
602  &state, sizeof(state));
603  if (err < 0)
604  return nl_error(errno, "setsockopt(NETLINK_PKTINFO) failed");
605 
606  return 0;
607 }
608 
609 /** @} */
610 
611 /** @} */