32 #include <netlink-local.h>
33 #include <netlink/netlink.h>
34 #include <netlink/utils.h>
35 #include <netlink/handlers.h>
36 #include <netlink/msg.h>
37 #include <netlink/attr.h>
41 static void __init init_default_cb(
void)
45 if ((nlcb = getenv(
"NLCB"))) {
46 if (!strcasecmp(nlcb,
"default"))
48 else if (!strcasecmp(nlcb,
"verbose"))
50 else if (!strcasecmp(nlcb,
"debug"))
53 fprintf(stderr,
"Unknown value for NLCB, valid values: "
54 "{default | verbose | debug}\n");
59 static uint32_t used_ports_map[32];
60 static pthread_mutex_t port_map_mutex = PTHREAD_MUTEX_INITIALIZER;
62 static uint32_t generate_local_port(
void)
65 uint32_t pid = getpid() & 0x3FFFFF;
67 pthread_mutex_lock(&port_map_mutex);
69 for (i = 0; i < 32; i++) {
70 if (used_ports_map[i] == 0xFFFFFFFF)
73 for (n = 0; n < 32; n++) {
74 if (1UL & (used_ports_map[i] >> n))
77 used_ports_map[i] |= (1UL << n);
83 pthread_mutex_unlock(&port_map_mutex);
85 return pid + (n << 22);
89 pthread_mutex_unlock(&port_map_mutex);
95 static void release_local_port(uint32_t port)
104 pthread_mutex_lock(&port_map_mutex);
105 used_ports_map[nr / 32] &= ~(1 << (nr % 32));
106 pthread_mutex_unlock(&port_map_mutex);
114 static struct nl_sock *__alloc_socket(
struct nl_cb *cb)
118 sk = calloc(1,
sizeof(*sk));
124 sk->s_local.nl_family = AF_NETLINK;
125 sk->s_peer.nl_family = AF_NETLINK;
126 sk->s_seq_expect = sk->s_seq_next = time(0);
127 sk->s_local.nl_pid = generate_local_port();
128 if (sk->s_local.nl_pid == UINT_MAX) {
149 return __alloc_socket(cb);
166 return __alloc_socket(nl_cb_get(cb));
181 if (!(sk->s_flags & NL_OWN_PORT))
182 release_local_port(sk->s_local.nl_pid);
195 static int noop_seq_check(
struct nl_msg *msg,
void *arg)
229 return sk->s_seq_next++;
246 sk->s_flags |= NL_NO_AUTO_ACK;
256 sk->s_flags &= ~NL_NO_AUTO_ACK;
266 uint32_t nl_socket_get_local_port(
const struct nl_sock *sk)
268 return sk->s_local.nl_pid;
282 port = generate_local_port();
287 if (!(sk->s_flags & NL_OWN_PORT))
288 release_local_port(sk->s_local.nl_pid);
290 sk->s_flags &= ~NL_OWN_PORT;
292 if (!(sk->s_flags & NL_OWN_PORT))
293 release_local_port(sk->s_local.nl_pid);
294 sk->s_flags |= NL_OWN_PORT;
297 sk->s_local.nl_pid = port;
329 return -NLE_BAD_SOCK;
337 err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
338 &group,
sizeof(group));
340 return -nl_syserr2nlerr(errno);
342 group = va_arg(ap,
int);
350 int nl_socket_add_membership(
struct nl_sock *sk,
int group)
373 return -NLE_BAD_SOCK;
381 err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
382 &group,
sizeof(group));
384 return -nl_syserr2nlerr(errno);
386 group = va_arg(ap,
int);
394 int nl_socket_drop_membership(
struct nl_sock *sk,
int group)
411 sk->s_local.nl_groups |= groups;
422 uint32_t nl_socket_get_peer_port(
const struct nl_sock *sk)
424 return sk->s_peer.nl_pid;
427 void nl_socket_set_peer_port(
struct nl_sock *sk, uint32_t port)
429 sk->s_peer.nl_pid = port;
432 uint32_t nl_socket_get_peer_groups(
const struct nl_sock *sk)
434 return sk->s_peer.nl_groups;
437 void nl_socket_set_peer_groups(
struct nl_sock *sk, uint32_t groups)
439 sk->s_peer.nl_groups = groups;
451 int nl_socket_get_fd(
const struct nl_sock *sk)
465 return -NLE_BAD_SOCK;
467 if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
468 return -nl_syserr2nlerr(errno);
479 sk->s_flags |= NL_MSG_PEEK;
488 sk->s_flags &= ~NL_MSG_PEEK;
498 struct nl_cb *nl_socket_get_cb(
const struct nl_sock *sk)
500 return nl_cb_get(sk->s_cb);
503 void nl_socket_set_cb(
struct nl_sock *sk,
struct nl_cb *cb)
506 sk->s_cb = nl_cb_get(cb);
523 return nl_cb_set(sk->s_cb, type, kind, func, arg);
538 return nl_cb_err(sk->s_cb, kind, func, arg);
572 return -NLE_BAD_SOCK;
574 err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF,
575 &txbuf,
sizeof(txbuf));
577 return -nl_syserr2nlerr(errno);
579 err = setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF,
580 &rxbuf,
sizeof(rxbuf));
582 return -nl_syserr2nlerr(errno);
584 sk->s_flags |= NL_SOCK_BUFSIZE_SET;
601 return -NLE_BAD_SOCK;
603 err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED,
604 &state,
sizeof(state));
606 return -nl_syserr2nlerr(errno);
609 sk->s_flags |= NL_SOCK_PASSCRED;
611 sk->s_flags &= ~NL_SOCK_PASSCRED;
628 return -NLE_BAD_SOCK;
630 err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_PKTINFO,
631 &state,
sizeof(state));
633 return -nl_syserr2nlerr(errno);