summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/netlink/socket.h1
-rw-r--r--lib/nl.c9
-rw-r--r--lib/socket.c62
-rw-r--r--libnl-3.sym1
4 files changed, 71 insertions, 2 deletions
diff --git a/include/netlink/socket.h b/include/netlink/socket.h
index 1007eba..9a68cad 100644
--- a/include/netlink/socket.h
+++ b/include/netlink/socket.h
@@ -60,6 +60,7 @@ extern void nl_socket_disable_auto_ack(struct nl_sock *);
extern void nl_socket_enable_auto_ack(struct nl_sock *);
extern int nl_socket_get_fd(const struct nl_sock *);
+extern int nl_socket_set_fd(struct nl_sock *sk, int protocol, int fd);
extern int nl_socket_set_nonblocking(const struct nl_sock *);
extern void nl_socket_enable_msg_peek(struct nl_sock *);
extern void nl_socket_disable_msg_peek(struct nl_sock *);
diff --git a/lib/nl.c b/lib/nl.c
index 8e4c455..8fc9ec1 100644
--- a/lib/nl.c
+++ b/lib/nl.c
@@ -86,8 +86,13 @@
* This capability is indicated by
* `%NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE`.
*
+ * @note nl_connect() creates and sets the file descriptor. You can setup the file
+ * descriptor yourself by creating and binding it, and then calling
+ * nl_socket_set_fd(). The result will be the same.
+ *
* @see nl_socket_alloc()
* @see nl_close()
+ * @see nl_socket_set_fd()
*
* @return 0 on success or a negative error code.
*
@@ -105,8 +110,8 @@ int nl_connect(struct nl_sock *sk, int protocol)
flags |= SOCK_CLOEXEC;
#endif
- if (sk->s_fd != -1)
- return -NLE_BAD_SOCK;
+ if (sk->s_fd != -1)
+ return -NLE_BAD_SOCK;
sk->s_fd = socket(AF_NETLINK, SOCK_RAW | flags, protocol);
if (sk->s_fd < 0) {
diff --git a/lib/socket.c b/lib/socket.c
index 628a96d..049b8b9 100644
--- a/lib/socket.c
+++ b/lib/socket.c
@@ -573,6 +573,68 @@ int nl_socket_get_fd(const struct nl_sock *sk)
}
/**
+ * Set the socket file descriptor externally which initializes the
+ * socket similar to nl_connect().
+ *
+ * @arg sk Netlink socket (required)
+ * @arg protocol Netlink protocol to use (required)
+ * @arg fd Socket file descriptor to use (required)
+ *
+ * Set the socket file descriptor. @fd must be valid and bind'ed.
+ *
+ * This is an alternative to nl_connect(). nl_connect() creates, binds and
+ * sets the socket. With this function you can set the socket to an externally
+ * created file descriptor.
+ *
+ * @see nl_connect()
+ *
+ * @return 0 on success or a negative error code. On error, @fd is not closed but
+ * possibly unusable.
+ *
+ * @retval -NLE_BAD_SOCK Netlink socket is already connected
+ * @retval -NLE_INVAL Socket is not connected
+ */
+int nl_socket_set_fd(struct nl_sock *sk, int protocol, int fd)
+{
+ int err = 0;
+ socklen_t addrlen;
+ char buf[64];
+ struct sockaddr_nl local = { 0 };
+
+ if (sk->s_fd != -1)
+ return -NLE_BAD_SOCK;
+ if (fd < 0)
+ return -NLE_INVAL;
+
+ addrlen = sizeof(local);
+ err = getsockname(fd, (struct sockaddr *) &local,
+ &addrlen);
+ if (err < 0) {
+ NL_DBG(4, "nl_socket_set_fd(%p): getsockname() failed with %d (%s)\n",
+ sk, errno, strerror_r(errno, buf, sizeof(buf)));
+ return -nl_syserr2nlerr(errno);
+ }
+
+ if (addrlen != sizeof(local))
+ return -NLE_NOADDR;
+
+ if (local.nl_family != AF_NETLINK)
+ return -NLE_AF_NOSUPPORT;
+
+ if (sk->s_local.nl_pid != local.nl_pid) {
+ /* the port id differs. The socket is using a port id not managed by
+ * libnl, hence reset the local port id to release a possibly generated
+ * port. */
+ nl_socket_set_local_port (sk, local.nl_pid);
+ }
+ sk->s_local = local;
+ sk->s_fd = fd;
+ sk->s_proto = protocol;
+
+ return 0;
+}
+
+/**
* Set file descriptor of socket to non-blocking state
* @arg sk Netlink socket.
*
diff --git a/libnl-3.sym b/libnl-3.sym
index df61001..c8ef8a3 100644
--- a/libnl-3.sym
+++ b/libnl-3.sym
@@ -328,4 +328,5 @@ libnl_3_2_26 {
global:
nl_cache_pickup_checkdup;
nl_pickup_keep_syserr;
+ nl_socket_set_fd;
} libnl_3;