20 #include <netlink-local.h>
21 #include <netlink/netlink.h>
22 #include <netlink/utils.h>
23 #include <netlink/handlers.h>
24 #include <netlink/msg.h>
25 #include <netlink/attr.h>
29 static void __init init_default_cb(
void)
33 if ((nlcb = getenv(
"NLCB"))) {
34 if (!strcasecmp(nlcb,
"default"))
36 else if (!strcasecmp(nlcb,
"verbose"))
38 else if (!strcasecmp(nlcb,
"debug"))
41 fprintf(stderr,
"Unknown value for NLCB, valid values: "
42 "{default | verbose | debug}\n");
47 static uint32_t used_ports_map[32];
48 static pthread_mutex_t port_map_mutex = PTHREAD_MUTEX_INITIALIZER;
50 static uint32_t generate_local_port(
void)
53 uint32_t pid = getpid() & 0x3FFFFF;
55 pthread_mutex_lock(&port_map_mutex);
57 for (i = 0; i < 32; i++) {
58 if (used_ports_map[i] == 0xFFFFFFFF)
61 for (n = 0; n < 32; n++) {
62 if (1UL & (used_ports_map[i] >> n))
65 used_ports_map[i] |= (1UL << n);
71 pthread_mutex_unlock(&port_map_mutex);
73 return pid + (n << 22);
77 pthread_mutex_unlock(&port_map_mutex);
83 static void release_local_port(uint32_t port)
92 pthread_mutex_lock(&port_map_mutex);
93 used_ports_map[nr / 32] &= ~(1 << (nr % 32));
94 pthread_mutex_unlock(&port_map_mutex);
102 static struct nl_sock *__alloc_socket(
struct nl_cb *cb)
106 sk = calloc(1,
sizeof(*sk));
112 sk->s_local.nl_family = AF_NETLINK;
113 sk->s_peer.nl_family = AF_NETLINK;
114 sk->s_seq_expect = sk->s_seq_next = time(0);
115 sk->s_local.nl_pid = generate_local_port();
116 if (sk->s_local.nl_pid == UINT_MAX) {
137 return __alloc_socket(cb);
154 return __alloc_socket(nl_cb_get(cb));
169 if (!(sk->s_flags & NL_OWN_PORT))
170 release_local_port(sk->s_local.nl_pid);
183 static int noop_seq_check(
struct nl_msg *msg,
void *arg)
217 return sk->s_seq_next++;
234 sk->s_flags |= NL_NO_AUTO_ACK;
244 sk->s_flags &= ~NL_NO_AUTO_ACK;
254 uint32_t nl_socket_get_local_port(
const struct nl_sock *sk)
256 return sk->s_local.nl_pid;
270 port = generate_local_port();
275 if (!(sk->s_flags & NL_OWN_PORT))
276 release_local_port(sk->s_local.nl_pid);
278 sk->s_flags &= ~NL_OWN_PORT;
280 if (!(sk->s_flags & NL_OWN_PORT))
281 release_local_port(sk->s_local.nl_pid);
282 sk->s_flags |= NL_OWN_PORT;
285 sk->s_local.nl_pid = port;
317 return -NLE_BAD_SOCK;
325 err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
326 &group,
sizeof(group));
328 return -nl_syserr2nlerr(errno);
330 group = va_arg(ap,
int);
338 int nl_socket_add_membership(
struct nl_sock *sk,
int group)
361 return -NLE_BAD_SOCK;
369 err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
370 &group,
sizeof(group));
372 return -nl_syserr2nlerr(errno);
374 group = va_arg(ap,
int);
382 int nl_socket_drop_membership(
struct nl_sock *sk,
int group)
399 sk->s_local.nl_groups |= groups;
410 uint32_t nl_socket_get_peer_port(
const struct nl_sock *sk)
412 return sk->s_peer.nl_pid;
415 void nl_socket_set_peer_port(
struct nl_sock *sk, uint32_t port)
417 sk->s_peer.nl_pid = port;
420 uint32_t nl_socket_get_peer_groups(
const struct nl_sock *sk)
422 return sk->s_peer.nl_groups;
425 void nl_socket_set_peer_groups(
struct nl_sock *sk, uint32_t groups)
427 sk->s_peer.nl_groups = groups;
439 int nl_socket_get_fd(
const struct nl_sock *sk)
453 return -NLE_BAD_SOCK;
455 if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
456 return -nl_syserr2nlerr(errno);
467 sk->s_flags |= NL_MSG_PEEK;
476 sk->s_flags &= ~NL_MSG_PEEK;
486 struct nl_cb *nl_socket_get_cb(
const struct nl_sock *sk)
488 return nl_cb_get(sk->s_cb);
491 void nl_socket_set_cb(
struct nl_sock *sk,
struct nl_cb *cb)
494 sk->s_cb = nl_cb_get(cb);
511 return nl_cb_set(sk->s_cb, type, kind, func, arg);
526 return nl_cb_err(sk->s_cb, kind, func, arg);
560 return -NLE_BAD_SOCK;
562 err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF,
563 &txbuf,
sizeof(txbuf));
565 return -nl_syserr2nlerr(errno);
567 err = setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF,
568 &rxbuf,
sizeof(rxbuf));
570 return -nl_syserr2nlerr(errno);
572 sk->s_flags |= NL_SOCK_BUFSIZE_SET;
589 return -NLE_BAD_SOCK;
591 err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED,
592 &state,
sizeof(state));
594 return -nl_syserr2nlerr(errno);
597 sk->s_flags |= NL_SOCK_PASSCRED;
599 sk->s_flags &= ~NL_SOCK_PASSCRED;
616 return -NLE_BAD_SOCK;
618 err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_PKTINFO,
619 &state,
sizeof(state));
621 return -nl_syserr2nlerr(errno);