diff options
author | Thomas Haller <thaller@redhat.com> | 2015-03-05 09:50:04 (GMT) |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-03-05 10:26:22 (GMT) |
commit | 9614acf4c4354892b5b734cace4778acfc019999 (patch) | |
tree | a5f951654c089a097be94c9ae5f91ed0d6b03eac | |
parent | 15824e42730980132a9e52d0c9d6929808e5ae78 (diff) | |
download | libnl-9614acf4c4354892b5b734cace4778acfc019999.zip libnl-9614acf4c4354892b5b734cace4778acfc019999.tar.gz libnl-9614acf4c4354892b5b734cace4778acfc019999.tar.bz2 |
lib/nl: preserve s_local if nl_connect() fails
s_local.nl_pid is used to track the generated port unless NL_OWN_PORT is set.
Ensure that getsockname() doesn't overwrite the value and possibly reset
the local port manually to release the generated port.
Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r-- | lib/nl.c | 24 |
1 files changed, 16 insertions, 8 deletions
@@ -98,6 +98,7 @@ int nl_connect(struct nl_sock *sk, int protocol) int err, flags = 0; int errsv; socklen_t addrlen; + struct sockaddr_nl local = { 0 }; char buf[64]; #ifdef SOCK_CLOEXEC @@ -163,8 +164,8 @@ int nl_connect(struct nl_sock *sk, int protocol) } } - addrlen = sizeof(sk->s_local); - err = getsockname(sk->s_fd, (struct sockaddr *) &sk->s_local, + addrlen = sizeof(local); + err = getsockname(sk->s_fd, (struct sockaddr *) &local, &addrlen); if (err < 0) { NL_DBG(4, "nl_connect(%p): getsockname() failed with %d (%s)\n", @@ -173,24 +174,31 @@ int nl_connect(struct nl_sock *sk, int protocol) goto errout; } - if (addrlen != sizeof(sk->s_local)) { + if (addrlen != sizeof(local)) { err = -NLE_NOADDR; goto errout; } - if (sk->s_local.nl_family != AF_NETLINK) { + if (local.nl_family != AF_NETLINK) { err = -NLE_AF_NOSUPPORT; goto errout; } + if (sk->s_local.nl_pid != local.nl_pid) { + /* strange, the port id is not as expected. Set the local + * port id to release a possibly generated port and un-own + * it. */ + nl_socket_set_local_port (sk, local.nl_pid); + } + sk->s_local = local; sk->s_proto = protocol; return 0; errout: - if (sk->s_fd != -1) { - close(sk->s_fd); - sk->s_fd = -1; - } + if (sk->s_fd != -1) { + close(sk->s_fd); + sk->s_fd = -1; + } return err; } |