24#include "nl-default.h"
29#include <sys/socket.h>
31#include <netlink/netlink.h>
32#include <netlink/utils.h>
33#include <netlink/handlers.h>
34#include <netlink/msg.h>
35#include <netlink/attr.h>
38#include "nl-priv-dynamic-core/nl-core.h"
39#include "nl-aux-core/nl-core.h"
42#define SOL_NETLINK 270
47static void _nl_init init_default_cb(
void)
51 if ((nlcb = getenv(
"NLCB"))) {
52 if (!strcasecmp(nlcb,
"default"))
54 else if (!strcasecmp(nlcb,
"verbose"))
56 else if (!strcasecmp(nlcb,
"debug"))
59 fprintf(stderr,
"Unknown value for NLCB, valid values: "
60 "{default | verbose | debug}\n");
65static uint32_t _badrandom_from_time(
void)
73 result = (uint32_t)v64;
78 result ^= (~(v64 >> 32));
83static uint32_t used_ports_map[32];
84static NL_RW_LOCK(port_map_lock);
86static uint32_t generate_local_port(
void)
90 static uint16_t idx_state = 0;
91 uint32_t pid = getpid() & 0x3FFFFF;
93 nl_write_lock(&port_map_lock);
96 uint32_t t = _badrandom_from_time();
100 idx_state = t ^ (t >> 16) ^ 0x3047;
102 idx_state = idx_state + 20011;
106 for (j = 0; j < 32; j++) {
115 i = (((i-1) + 7) % 31) + 1;
117 if (used_ports_map[i] == 0xFFFFFFFF)
120 for (m = 0; m < 32; m++) {
122 if (1UL & (used_ports_map[i] >> n))
125 used_ports_map[i] |= (1UL << n);
131 nl_write_unlock(&port_map_lock);
134 pid = pid + (n << 22);
135 return pid ? pid : 1024;
139 nl_write_unlock(&port_map_lock);
143static void release_local_port(uint32_t port)
151 mask = 1UL << (nr % 32);
154 nl_write_lock(&port_map_lock);
155 BUG_ON((used_ports_map[nr] & mask) != mask);
156 used_ports_map[nr] &= ~mask;
157 nl_write_unlock(&port_map_lock);
161void _nl_socket_used_ports_release_all(
const uint32_t *used_ports)
165 for (i = 0; i < 32; i++) {
166 if (used_ports[i] != 0) {
167 nl_write_lock(&port_map_lock);
168 for (; i < 32; i++) {
169 BUG_ON((used_ports_map[i] & used_ports[i]) != used_ports[i]);
170 used_ports_map[i] &= ~(used_ports[i]);
172 nl_write_unlock(&port_map_lock);
178void _nl_socket_used_ports_set(uint32_t *used_ports, uint32_t port)
184 mask = 1UL << (nr % 32);
192 used_ports[nr] |= mask;
201static struct nl_sock *__alloc_socket(
struct nl_cb *cb)
205 sk = calloc(1,
sizeof(*sk));
210 sk->s_cb = nl_cb_get(cb);
211 sk->s_local.nl_family = AF_NETLINK;
212 sk->s_peer.nl_family = AF_NETLINK;
213 sk->s_seq_next = _badrandom_from_time();
214 sk->s_seq_expect = sk->s_seq_next;
217 sk->s_flags = NL_OWN_PORT;
237 sk = __alloc_socket(cb);
258 return __alloc_socket(cb);
273 if (!(sk->s_flags & NL_OWN_PORT))
274 release_local_port(sk->s_local.nl_pid);
287static int noop_seq_check(
struct nl_msg *msg,
void *arg)
321 if (sk->s_seq_next == UINT_MAX) {
325 return sk->s_seq_next++;
342 sk->s_flags |= NL_NO_AUTO_ACK;
352 sk->s_flags &= ~NL_NO_AUTO_ACK;
358int _nl_socket_is_local_port_unspecified(
struct nl_sock *sk)
360 return (sk->s_local.nl_pid == 0);
363uint32_t _nl_socket_set_local_port_no_release(
struct nl_sock *sk,
int generate_other)
371 port = generate_local_port();
374 sk->s_local.nl_pid = port;
378 sk->s_flags |= NL_OWN_PORT;
380 sk->s_flags &= ~NL_OWN_PORT;
390uint32_t nl_socket_get_local_port(
const struct nl_sock *sk)
392 if (sk->s_local.nl_pid == 0) {
393 struct nl_sock *sk_mutable = (
struct nl_sock *) sk;
404 sk_mutable->s_local.nl_pid = generate_local_port();
405 if (sk_mutable->s_local.nl_pid == 0) {
409 sk_mutable->s_local.nl_pid = UINT32_MAX;
410 sk_mutable->s_flags |= NL_OWN_PORT;
412 sk_mutable->s_flags &= ~NL_OWN_PORT;
414 return sk->s_local.nl_pid;
431 if (!(sk->s_flags & NL_OWN_PORT))
432 release_local_port(sk->s_local.nl_pid);
433 sk->s_flags |= NL_OWN_PORT;
434 sk->s_local.nl_pid = port;
466 return -NLE_BAD_SOCK;
476 err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
477 &group,
sizeof(group));
480 NL_DBG(4,
"nl_socket_add_memberships(%p): setsockopt() failed with %d (%s)\n",
481 sk, errno, nl_strerror_l(errno));
482 return -nl_syserr2nlerr(errno);
485 group = va_arg(ap,
int);
493int nl_socket_add_membership(
struct nl_sock *sk,
int group)
516 return -NLE_BAD_SOCK;
526 err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
527 &group,
sizeof(group));
530 NL_DBG(4,
"nl_socket_drop_memberships(%p): setsockopt() failed with %d (%s)\n",
531 sk, errno, nl_strerror_l(errno));
532 return -nl_syserr2nlerr(errno);
535 group = va_arg(ap,
int);
543int nl_socket_drop_membership(
struct nl_sock *sk,
int group)
560 sk->s_local.nl_groups |= groups;
571uint32_t nl_socket_get_peer_port(
const struct nl_sock *sk)
573 return sk->s_peer.nl_pid;
576void nl_socket_set_peer_port(
struct nl_sock *sk, uint32_t port)
578 sk->s_peer.nl_pid = port;
581uint32_t nl_socket_get_peer_groups(
const struct nl_sock *sk)
583 return sk->s_peer.nl_groups;
586void nl_socket_set_peer_groups(
struct nl_sock *sk, uint32_t groups)
588 sk->s_peer.nl_groups = groups;
645 struct sockaddr_nl local = { 0 };
646 int so_type = -1, so_protocol = -1;
649 return -NLE_BAD_SOCK;
653 addrlen =
sizeof(local);
654 err = getsockname(fd, (
struct sockaddr *) &local,
657 NL_DBG(4,
"nl_socket_set_fd(%p,%d): getsockname() failed with %d (%s)\n",
658 sk, fd, errno, nl_strerror_l(errno));
659 return -nl_syserr2nlerr(errno);
661 if (addrlen !=
sizeof(local))
663 if (local.nl_family != AF_NETLINK) {
664 NL_DBG(4,
"nl_socket_set_fd(%p,%d): getsockname() returned family %d instead of %d (AF_NETLINK)\n",
665 sk, fd, local.nl_family, AF_NETLINK);
669 addrlen =
sizeof(so_type);
670 err = getsockopt(fd, SOL_SOCKET, SO_TYPE, &so_type, &addrlen);
672 NL_DBG(4,
"nl_socket_set_fd(%p,%d): getsockopt() for SO_TYPE failed with %d (%s)\n",
673 sk, fd, errno, nl_strerror_l(errno));
674 return -nl_syserr2nlerr(errno);
676 if (addrlen !=
sizeof(so_type))
678 if (so_type != SOCK_RAW) {
679 NL_DBG(4,
"nl_socket_set_fd(%p,%d): getsockopt() returned SO_TYPE %d instead of %d (SOCK_RAW)\n",
680 sk, fd, so_type, SOCK_RAW);
685 addrlen =
sizeof(so_protocol);
686 err = getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &so_protocol, &addrlen);
688 if (errno == ENOPROTOOPT)
690 NL_DBG(4,
"nl_socket_set_fd(%p,%d): getsockopt() for SO_PROTOCOL failed with %d (%s)\n",
691 sk, fd, errno, nl_strerror_l(errno));
692 return -nl_syserr2nlerr(errno);
694 if (addrlen !=
sizeof(so_protocol))
696 if (protocol >= 0 && protocol != so_protocol) {
697 NL_DBG(4,
"nl_socket_set_fd(%p,%d): getsockopt() for SO_PROTOCOL returned %d instead of %d\n",
698 sk, fd, so_protocol, protocol);
707 NL_DBG(4,
"nl_socket_set_fd(%p,%d): unknown protocol and unable to detect it via SO_PROTOCOL socket option\n",
711 so_protocol = protocol;
717 sk->s_proto = so_protocol;
731 return -NLE_BAD_SOCK;
733 if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0) {
734 NL_DBG(4,
"nl_socket_set_nonblocking(%p): fcntl() failed with %d (%s)\n",
735 sk, errno, nl_strerror_l(errno));
736 return -nl_syserr2nlerr(errno);
750 sk->s_flags |= (NL_MSG_PEEK | NL_MSG_PEEK_EXPLICIT);
761 sk->s_flags |= NL_MSG_PEEK_EXPLICIT;
762 sk->s_flags &= ~NL_MSG_PEEK;
772struct nl_cb *nl_socket_get_cb(
const struct nl_sock *sk)
774 return nl_cb_get(sk->s_cb);
777void nl_socket_set_cb(
struct nl_sock *sk,
struct nl_cb *cb)
783 sk->s_cb = nl_cb_get(cb);
800 return nl_cb_set(sk->s_cb, type, kind, func, arg);
815 return nl_cb_err(sk->s_cb, kind, func, arg);
849 return -NLE_BAD_SOCK;
851 err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF,
852 &txbuf,
sizeof(txbuf));
854 NL_DBG(4,
"nl_socket_set_buffer_size(%p): setsockopt() failed with %d (%s)\n",
855 sk, errno, nl_strerror_l(errno));
856 return -nl_syserr2nlerr(errno);
859 err = setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF,
860 &rxbuf,
sizeof(rxbuf));
862 NL_DBG(4,
"nl_socket_set_buffer_size(%p): setsockopt() failed with %d (%s)\n",
863 sk, errno, nl_strerror_l(errno));
864 return -nl_syserr2nlerr(errno);
897 sk->s_bufsize = bufsize;
910 return sk->s_bufsize;
925 return -NLE_BAD_SOCK;
927 err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED,
928 &state,
sizeof(state));
930 NL_DBG(4,
"nl_socket_set_passcred(%p): setsockopt() failed with %d (%s)\n",
931 sk, errno, nl_strerror_l(errno));
932 return -nl_syserr2nlerr(errno);
936 sk->s_flags |= NL_SOCK_PASSCRED;
938 sk->s_flags &= ~NL_SOCK_PASSCRED;
955 return -NLE_BAD_SOCK;
957 err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_PKTINFO,
958 &state,
sizeof(state));
960 NL_DBG(4,
"nl_socket_recv_pktinfo(%p): setsockopt() failed with %d (%s)\n",
961 sk, errno, nl_strerror_l(errno));
962 return -nl_syserr2nlerr(errno);
int(* nl_recvmsg_err_cb_t)(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg)
nl_recvmsgs() callback for error message processing customization
nl_cb_type
Callback types.
int(* nl_recvmsg_msg_cb_t)(struct nl_msg *msg, void *arg)
nl_recvmsgs() callback for message processing customization
nl_cb_kind
Callback kinds.
int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func, void *arg)
Set up a callback.
struct nl_cb * nl_cb_alloc(enum nl_cb_kind kind)
Allocate a new callback handle.
int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind, nl_recvmsg_err_cb_t func, void *arg)
Set up an error callback.
@ NL_OK
Proceed with whatever would come next.
@ NL_CB_SEQ_CHECK
Called instead of internal sequence number checking.
@ NL_CB_DEFAULT
Default handlers (quiet)
@ NL_CB_CUSTOM
Customized handler specified by the user.
@ NL_CB_VERBOSE
Verbose default handlers (error messages printed)
@ NL_CB_DEBUG
Debug handlers for debugging.
int nl_socket_get_fd(const struct nl_sock *sk)
Return the file descriptor of the backing socket.
void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port)
Set local port of socket.
void nl_socket_disable_auto_ack(struct nl_sock *sk)
Disable automatic request for ACK.
size_t nl_socket_get_msg_buf_size(struct nl_sock *sk)
Get default message buffer size of netlink socket.
int nl_socket_recv_pktinfo(struct nl_sock *sk, int state)
Enable/disable receival of additional packet information.
int nl_socket_modify_err_cb(struct nl_sock *sk, enum nl_cb_kind kind, nl_recvmsg_err_cb_t func, void *arg)
Modify the error callback handler associated with the socket.
void nl_join_groups(struct nl_sock *sk, int groups)
Join multicast groups (deprecated)
int nl_socket_set_passcred(struct nl_sock *sk, int state)
Enable/disable credential passing on netlink socket.
int nl_socket_add_memberships(struct nl_sock *sk, int group,...)
Join groups.
void nl_socket_disable_msg_peek(struct nl_sock *sk)
Disable use of MSG_PEEK when reading from socket.
struct nl_sock * nl_socket_alloc(void)
Allocate new netlink socket.
int nl_socket_set_msg_buf_size(struct nl_sock *sk, size_t bufsize)
Set default message buffer size of netlink socket.
struct nl_sock * nl_socket_alloc_cb(struct nl_cb *cb)
Allocate new socket with custom callbacks.
int nl_socket_set_nonblocking(const struct nl_sock *sk)
Set file descriptor of socket to non-blocking state.
void nl_socket_enable_auto_ack(struct nl_sock *sk)
Enable automatic request for ACK (default)
void nl_socket_enable_msg_peek(struct nl_sock *sk)
Enable use of MSG_PEEK when reading from socket.
int nl_socket_set_fd(struct nl_sock *sk, int protocol, int fd)
Set the socket file descriptor externally which initializes the socket similar to nl_connect().
unsigned int nl_socket_use_seq(struct nl_sock *sk)
Use next sequence number.
void nl_socket_disable_seq_check(struct nl_sock *sk)
Disable sequence number checking.
int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
Set socket buffer size of netlink socket.
void nl_socket_free(struct nl_sock *sk)
Free a netlink socket.
int nl_socket_drop_memberships(struct nl_sock *sk, int group,...)
Leave groups.
int 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)
Modify the callback handler associated with the socket.