summaryrefslogtreecommitdiff
path: root/src/nlapi.c
diff options
context:
space:
mode:
authorAndrew Shadura <andrew.shadura@collabora.co.uk>2016-06-21 11:57:24 +0200
committerAndrew Shadura <andrew.shadura@collabora.co.uk>2016-06-21 11:57:24 +0200
commit0af3fe8aecc7ee52a6ee0eb926aab985513c4204 (patch)
tree1297533f6cec6790a4c11fab567c69a2dfc56369 /src/nlapi.c
Imported Upstream version 0.26
Diffstat (limited to 'src/nlapi.c')
-rw-r--r--src/nlapi.c134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/nlapi.c b/src/nlapi.c
new file mode 100644
index 0000000..acf94dc
--- /dev/null
+++ b/src/nlapi.c
@@ -0,0 +1,134 @@
+/* $Id: nlapi.c 116 2004-12-19 00:24:29Z lennart $ */
+
+/*
+ * This file is part of ifplugd.
+ *
+ * ifplugd is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * ifplugd is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with ifplugd; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include <libdaemon/dlog.h>
+
+#include "nlapi.h"
+
+int nlapi_fd = -1;
+
+struct callback_info {
+ nlapi_callback_t callback;
+ void *userdata;
+ struct callback_info * next;
+};
+
+struct callback_info *callbacks = NULL;
+
+int nlapi_open(uint32_t groups) {
+ struct sockaddr_nl addr;
+
+ if ((nlapi_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) {
+ daemon_log(LOG_ERR, "socket(PF_NETLINK): %s\n", strerror(errno));
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ addr.nl_groups = groups;
+ addr.nl_pid = getpid();
+
+ if (bind(nlapi_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ close(nlapi_fd);
+ daemon_log(LOG_ERR, "bind(): %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int nlapi_work(int block) {
+
+ assert(nlapi_fd >= 0);
+
+ for (;;) {
+ int bytes;
+ char replybuf[1024];
+ struct nlmsghdr *p = (struct nlmsghdr *) replybuf;
+
+ if ((bytes = recv(nlapi_fd, &replybuf, sizeof(replybuf), block ? 0 : MSG_DONTWAIT)) < 0) {
+
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
+ daemon_log(LOG_ERR, "NLAPI: recv(): %s\n", strerror(errno));
+ return -1;
+ }
+
+ for (; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
+ struct callback_info *c;
+
+ if (!NLMSG_OK(p, bytes) || (size_t) bytes < sizeof(struct nlmsghdr) || (size_t) bytes < p->nlmsg_len) {
+ daemon_log(LOG_ERR, "NLAPI: Packet too small or truncated!\n");
+ return -1;
+ }
+
+ for (c = callbacks; c; c = c->next)
+ if (c->callback(p, c->userdata) < 0)
+ return -1;
+ }
+
+ if (block)
+ break;
+ }
+
+ return 0;
+}
+
+void nlapi_close(void) {
+ if (nlapi_fd >= 0)
+ close(nlapi_fd);
+ nlapi_fd = -1;
+
+ while (callbacks) {
+ struct callback_info *c = callbacks;
+ callbacks = callbacks->next;
+ free(c);
+ }
+}
+
+int nlapi_register(int (*callback) (struct nlmsghdr *n, void *u), void *u) {
+ struct callback_info *c;
+
+ assert(callback);
+
+ if (!(c = malloc(sizeof(struct callback_info)))) {
+ daemon_log(LOG_ERR, "NLAPI: Not enough memory.\n");
+ return -1;
+ }
+
+ c->callback = callback;
+ c->userdata = u;
+
+ c->next = callbacks;
+ callbacks = c;
+ return 0;
+}