diff options
-rw-r--r-- | include/netlink/socket.h | 1 | ||||
-rw-r--r-- | lib/nl.c | 9 | ||||
-rw-r--r-- | lib/socket.c | 62 | ||||
-rw-r--r-- | libnl-3.sym | 1 |
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 *); @@ -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; |