94 #include <netlink-local.h>
95 #include <netlink/netlink.h>
96 #include <netlink/utils.h>
97 #include <netlink/handlers.h>
98 #include <netlink/msg.h>
99 #include <netlink/attr.h>
103 static void __init init_default_cb(
void)
107 if ((nlcb = getenv(
"NLCB"))) {
108 if (!strcasecmp(nlcb,
"default"))
110 else if (!strcasecmp(nlcb,
"verbose"))
112 else if (!strcasecmp(nlcb,
"debug"))
115 fprintf(stderr,
"Unknown value for NLCB, valid values: "
116 "{default | verbose | debug}\n");
121 static uint32_t used_ports_map[32];
122 static pthread_mutex_t port_map_mutex = PTHREAD_MUTEX_INITIALIZER;
124 static uint32_t generate_local_port(
void)
127 uint32_t pid = getpid() & 0x3FFFFF;
129 pthread_mutex_lock(&port_map_mutex);
131 for (i = 0; i < 32; i++) {
132 if (used_ports_map[i] == 0xFFFFFFFF)
135 for (n = 0; n < 32; n++) {
136 if (1UL & (used_ports_map[i] >> n))
139 used_ports_map[i] |= (1UL << n);
145 pthread_mutex_unlock(&port_map_mutex);
147 return pid + (n << 22);
151 pthread_mutex_unlock(&port_map_mutex);
157 static void release_local_port(uint32_t port)
161 if (port == UINT_MAX)
166 pthread_mutex_lock(&port_map_mutex);
167 used_ports_map[nr / 32] &= ~(1 << (nr % 32));
168 pthread_mutex_unlock(&port_map_mutex);
176 static struct nl_handle *__alloc_handle(
struct nl_cb *cb)
178 struct nl_handle *handle;
180 handle = calloc(1,
sizeof(*handle));
188 handle->h_local.nl_family = AF_NETLINK;
189 handle->h_peer.nl_family = AF_NETLINK;
190 handle->h_seq_expect = handle->h_seq_next = time(0);
191 handle->h_local.nl_pid = generate_local_port();
192 if (handle->h_local.nl_pid == UINT_MAX) {
194 nl_error(ENOBUFS,
"Out of local ports");
216 return __alloc_handle(cb);
233 return __alloc_handle(nl_cb_get(cb));
245 if (handle->h_fd >= 0)
248 if (!(handle->h_flags & NL_OWN_PORT))
249 release_local_port(handle->h_local.nl_pid);
251 nl_cb_put(handle->h_cb);
262 static int noop_seq_check(
struct nl_msg *msg,
void *arg)
296 return handle->h_seq_next++;
306 uint32_t nl_socket_get_local_port(
struct nl_handle *handle)
308 return handle->h_local.nl_pid;
322 port = generate_local_port();
323 handle->h_flags &= ~NL_OWN_PORT;
325 if (!(handle->h_flags & NL_OWN_PORT))
326 release_local_port(handle->h_local.nl_pid);
327 handle->h_flags |= NL_OWN_PORT;
330 handle->h_local.nl_pid = port;
359 if (handle->h_fd == -1)
360 return nl_error(EBADFD,
"Socket not connected");
362 err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
363 &group,
sizeof(group));
365 return nl_error(errno,
"setsockopt(NETLINK_ADD_MEMBERSHIP) "
386 if (handle->h_fd == -1)
387 return nl_error(EBADFD,
"Socket not connected");
389 err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
390 &group,
sizeof(group));
392 return nl_error(errno,
"setsockopt(NETLINK_DROP_MEMBERSHIP) "
409 handle->h_local.nl_groups |= groups;
420 uint32_t nl_socket_get_peer_port(
struct nl_handle *handle)
422 return handle->h_peer.nl_pid;
425 void nl_socket_set_peer_port(
struct nl_handle *handle, uint32_t port)
427 handle->h_peer.nl_pid = port;
437 int nl_socket_get_fd(
struct nl_handle *handle)
450 if (handle->h_fd == -1)
451 return nl_error(EBADFD,
"Socket not connected");
453 if (fcntl(handle->h_fd, F_SETFL, O_NONBLOCK) < 0)
454 return nl_error(errno,
"fcntl(F_SETFL, O_NONBLOCK) failed");
465 handle->h_flags |= NL_MSG_PEEK;
474 handle->h_flags &= ~NL_MSG_PEEK;
484 struct nl_cb *nl_socket_get_cb(
struct nl_handle *handle)
486 return nl_cb_get(handle->h_cb);
489 void nl_socket_set_cb(
struct nl_handle *handle,
struct nl_cb *cb)
491 nl_cb_put(handle->h_cb);
492 handle->h_cb = nl_cb_get(cb);
509 return nl_cb_set(handle->h_cb, type, kind, func, arg);
542 if (handle->h_fd == -1)
543 return nl_error(EBADFD,
"Socket not connected");
545 err = setsockopt(handle->h_fd, SOL_SOCKET, SO_SNDBUF,
546 &txbuf,
sizeof(txbuf));
548 return nl_error(errno,
"setsockopt(SO_SNDBUF) failed");
550 err = setsockopt(handle->h_fd, SOL_SOCKET, SO_RCVBUF,
551 &rxbuf,
sizeof(rxbuf));
553 return nl_error(errno,
"setsockopt(SO_RCVBUF) failed");
555 handle->h_flags |= NL_SOCK_BUFSIZE_SET;
571 if (handle->h_fd == -1)
572 return nl_error(EBADFD,
"Socket not connected");
574 err = setsockopt(handle->h_fd, SOL_SOCKET, SO_PASSCRED,
575 &state,
sizeof(state));
577 return nl_error(errno,
"setsockopt(SO_PASSCRED) failed");
580 handle->h_flags |= NL_SOCK_PASSCRED;
582 handle->h_flags &= ~NL_SOCK_PASSCRED;
598 if (handle->h_fd == -1)
599 return nl_error(EBADFD,
"Socket not connected");
601 err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_PKTINFO,
602 &state,
sizeof(state));
604 return nl_error(errno,
"setsockopt(NETLINK_PKTINFO) failed");