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
25static int default_cb = NL_CB_DEFAULT;
26
27static 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
45static uint32_t used_ports_map[32];
46
47static 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
74static 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
90static 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 */
117struct 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 */
137struct 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 */
149void 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
171static 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 */
188void 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 */
203unsigned 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 */
220void 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 */
230void 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
242uint32_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 */
255void 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 */
292int 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
319int 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 */
336int 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
363int 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 */
378void 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
391uint32_t nl_socket_get_peer_port(struct nl_sock *sk)
392{
393	return sk->s_peer.nl_pid;
394}
395
396void 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
408int 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 */
419int 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 */
434void 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 */
443void 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
455struct nl_cb *nl_socket_get_cb(struct nl_sock *sk)
456{
457	return nl_cb_get(sk->s_cb);
458}
459
460void 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 */
476int 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 */
503int 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 */
538int 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 */
565int 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