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