aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSkylar Chang <chiaweic@codeaurora.org>2017-04-20 21:19:43 +0000
committerandroid-build-merger <android-build-merger@google.com>2017-04-20 21:19:43 +0000
commit778ee9446bf404669d47acc751e9b6100d9a0dfe (patch)
tree5d479604c436cbaa6934441c0a8184f3b3941e91
parentc8f3a04573f5bd205a5ee33e2c991a7ba4d7cabe (diff)
parenteb7fce344a79d7c35dfa10baa046aa3efabb6f5f (diff)
downloadlibnfnetlink-778ee9446bf404669d47acc751e9b6100d9a0dfe.tar.gz
Add support for passing pre-bound file descriptor am: 789db9e676 am: b18c9afa9f am: 3ba75fb771
am: eb7fce344a Change-Id: If30eb3ec1bf12e2d09771d20b8f16d73920576bf
-rw-r--r--include/libnfnetlink/libnfnetlink.h7
-rw-r--r--src/libnfnetlink.c116
2 files changed, 106 insertions, 17 deletions
diff --git a/include/libnfnetlink/libnfnetlink.h b/include/libnfnetlink/libnfnetlink.h
index 1d8c49d..90c5672 100644
--- a/include/libnfnetlink/libnfnetlink.h
+++ b/include/libnfnetlink/libnfnetlink.h
@@ -18,6 +18,7 @@
#include <sys/socket.h> /* for sa_family_t */
#include <linux/netlink.h>
#include <libnfnetlink/linux_nfnetlink.h>
+#include <stdbool.h>
#ifndef NETLINK_NETFILTER
#define NETLINK_NETFILTER 12
@@ -66,11 +67,17 @@ extern unsigned int nfnl_portid(const struct nfnl_handle *h);
/* get a new library handle */
extern struct nfnl_handle *nfnl_open(void);
+extern struct nfnl_handle *nfnl_open2(int fd, bool bind);
extern int nfnl_close(struct nfnl_handle *);
+extern int nfnl_close2(struct nfnl_handle *);
extern struct nfnl_subsys_handle *nfnl_subsys_open(struct nfnl_handle *,
u_int8_t, u_int8_t,
unsigned int);
+extern struct nfnl_subsys_handle *nfnl_subsys_open2(struct nfnl_handle *,
+ u_int8_t, u_int8_t,
+ unsigned int,
+ bool bind);
extern void nfnl_subsys_close(struct nfnl_subsys_handle *);
/* set and unset sequence tracking */
diff --git a/src/libnfnetlink.c b/src/libnfnetlink.c
index 4b2bcd0..5759308 100644
--- a/src/libnfnetlink.c
+++ b/src/libnfnetlink.c
@@ -161,6 +161,18 @@ static int recalc_rebind_subscriptions(struct nfnl_handle *nfnlh)
return 0;
}
+static void recalc_subscriptions(struct nfnl_handle *nfnlh)
+{
+ int i;
+ u_int32_t new_subscriptions = nfnlh->subscriptions;
+
+ for (i = 0; i < NFNL_MAX_SUBSYS; i++)
+ new_subscriptions |= nfnlh->subsys[i].subscriptions;
+
+ nfnlh->local.nl_groups = new_subscriptions;
+ nfnlh->subscriptions = new_subscriptions;
+}
+
/**
* nfnl_open - open a nfnetlink handler
*
@@ -173,16 +185,42 @@ static int recalc_rebind_subscriptions(struct nfnl_handle *nfnlh)
struct nfnl_handle *nfnl_open(void)
{
struct nfnl_handle *nfnlh;
+ int fd;
+
+ fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
+ if (fd == -1)
+ return NULL;
+ nfnlh = nfnl_open2(fd, true);
+ if (nfnlh == NULL)
+ close(fd);
+ return nfnlh;
+}
+
+/**
+ * nfnl_open2 - open a nfnetlink handler
+ * @fd: passing file descriptor
+ * @bind: indicate the passing fd needs to be binded or not
+ *
+ * This function creates a nfnetlink handler, this is required to establish
+ * a communication between the userspace and the nfnetlink system.
+ *
+ * On success, a valid address that points to a nfnl_handle structure
+ * is returned. On error, NULL is returned and errno is set approapiately.
+ */
+struct nfnl_handle *nfnl_open2(int fd, bool bind)
+{
+ struct nfnl_handle *nfnlh;
unsigned int addr_len;
+ if (fd < 0)
+ goto err;
+
nfnlh = malloc(sizeof(*nfnlh));
if (!nfnlh)
return NULL;
memset(nfnlh, 0, sizeof(*nfnlh));
- nfnlh->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
- if (nfnlh->fd == -1)
- goto err_free;
+ nfnlh->fd = fd;
nfnlh->local.nl_family = AF_NETLINK;
nfnlh->peer.nl_family = AF_NETLINK;
@@ -191,11 +229,11 @@ struct nfnl_handle *nfnl_open(void)
getsockname(nfnlh->fd, (struct sockaddr *)&nfnlh->local, &addr_len);
if (addr_len != sizeof(nfnlh->local)) {
errno = EINVAL;
- goto err_close;
+ goto err_free;
}
if (nfnlh->local.nl_family != AF_NETLINK) {
errno = EINVAL;
- goto err_close;
+ goto err_free;
}
nfnlh->seq = time(NULL);
nfnlh->rcv_buffer_size = NFNL_BUFFSIZE;
@@ -204,25 +242,28 @@ struct nfnl_handle *nfnl_open(void)
* binding to pid '0' will default */
/* let us do the initial bind */
- if (recalc_rebind_subscriptions(nfnlh) < 0)
- goto err_close;
+ if (bind) {
+ if (recalc_rebind_subscriptions(nfnlh) < 0)
+ goto err_free;
+ } else {
+ recalc_subscriptions(nfnlh);
+ }
/* use getsockname to get the netlink pid that the kernel assigned us */
addr_len = sizeof(nfnlh->local);
getsockname(nfnlh->fd, (struct sockaddr *)&nfnlh->local, &addr_len);
if (addr_len != sizeof(nfnlh->local)) {
errno = EINVAL;
- goto err_close;
+ goto err_free;
}
/* sequence tracking enabled by default */
nfnlh->flags |= NFNL_F_SEQTRACK_ENABLED;
return nfnlh;
-err_close:
- close(nfnlh->fd);
err_free:
free(nfnlh);
+err:
return NULL;
}
@@ -276,7 +317,31 @@ struct nfnl_subsys_handle *
nfnl_subsys_open(struct nfnl_handle *nfnlh, u_int8_t subsys_id,
u_int8_t cb_count, u_int32_t subscriptions)
{
+ return nfnl_subsys_open2 (nfnlh, subsys_id, cb_count, subscriptions, true);
+}
+
+/**
+ * nfnl_subsys_open2 - open a netlink subsystem
+ * @nfnlh: libnfnetlink handle
+ * @subsys_id: which nfnetlink subsystem we are interested in
+ * @cb_count: number of callbacks that are used maximum.
+ * @subscriptions: netlink groups we want to be subscribed to
+ * @bind: indicate the passing fd needs to be binded or not
+ *
+ * This function creates a subsystem handler that contains the set of
+ * callbacks that handle certain types of messages coming from a netfilter
+ * subsystem. Initially the callback set is empty, you can register callbacks
+ * via nfnl_callback_register().
+ *
+ * On error, NULL is returned and errno is set appropiately. On success,
+ * a valid address that points to a nfnl_subsys_handle structure is returned.
+ */
+struct nfnl_subsys_handle *
+nfnl_subsys_open2(struct nfnl_handle *nfnlh, u_int8_t subsys_id,
+ u_int8_t cb_count, u_int32_t subscriptions, bool bind)
+{
struct nfnl_subsys_handle *ssh;
+ int err = 0;
assert(nfnlh);
@@ -302,12 +367,15 @@ nfnl_subsys_open(struct nfnl_handle *nfnlh, u_int8_t subsys_id,
/* although now we have nfnl_join to subscribe to certain
* groups, just keep this to ensure compatibility */
- if (recalc_rebind_subscriptions(nfnlh) < 0) {
+ if (bind)
+ err = recalc_rebind_subscriptions(nfnlh);
+ else
+ recalc_subscriptions(nfnlh);
+ if (err < 0) {
free(ssh->cb);
ssh->cb = NULL;
return NULL;
}
-
return ssh;
}
@@ -338,16 +406,30 @@ void nfnl_subsys_close(struct nfnl_subsys_handle *ssh)
*/
int nfnl_close(struct nfnl_handle *nfnlh)
{
- int i, ret;
+ int ret;
assert(nfnlh);
-
- for (i = 0; i < NFNL_MAX_SUBSYS; i++)
- nfnl_subsys_close(&nfnlh->subsys[i]);
-
ret = close(nfnlh->fd);
if (ret < 0)
return ret;
+ return nfnl_close2(nfnlh);
+}
+
+/**
+ * nfnl_close2 - close a nfnetlink handler but keep fd
+ * @nfnlh: nfnetlink handler
+ *
+ * This function closes the nfnetlink handler. On success, 0 is returned.
+ * On error, -1 is returned and errno is set appropiately.
+ */
+int nfnl_close2(struct nfnl_handle *nfnlh)
+{
+ int i;
+
+ assert(nfnlh);
+
+ for (i = 0; i < NFNL_MAX_SUBSYS; i++)
+ nfnl_subsys_close(&nfnlh->subsys[i]);
free(nfnlh);