Browse Source

Use NETLINK_ROUTE for rescan

Serj Kalichev 10 years ago
parent
commit
6ea6e6e30c
2 changed files with 67 additions and 23 deletions
  1. 5 4
      birq.c
  2. 62 19
      nl.c

+ 5 - 4
birq.c

@@ -74,7 +74,7 @@ int main(int argc, char **argv)
 	sigset_t sig_set;
 
 	/* NetLink vars */
-	int nl = -1; /* NetLink socket */
+	nl_fds_t *nl_fds = NULL; /* NetLink socket */
 
 	/* IRQ list. It contain all found irqs. */
 	lub_list_t *irqs;
@@ -91,7 +91,7 @@ int main(int argc, char **argv)
 	syslog(LOG_ERR, "Start daemon.\n");
 
 	/* Init NetLink socket */
-	if ((nl = nl_init()) < 0)
+	if (!(nl_fds = nl_init()))
 		goto err;
 
 	/* Fork the daemon */
@@ -165,7 +165,8 @@ int main(int argc, char **argv)
 		}
 
 		/* Timeout and poll for new devices */
-		while ((n = nl_poll(nl, BIRQ_INTERVAL)) != 0) {
+		while ((n = nl_poll(nl_fds, BIRQ_INTERVAL)) != 0) {
+printf("POLL NETLINK: n=%d\n", n);
 			if (-1 == n) {
 				fprintf(stderr,
 					"Error: Broken NetLink socket.\n");
@@ -191,7 +192,7 @@ end:
 	retval = 0;
 err:
 	/* Close NetLink socket */
-	nl_close(nl);
+	nl_close(nl_fds);
 
 	/* Remove pidfile */
 	if (pidfd >= 0) {

+ 62 - 19
nl.c

@@ -1,20 +1,25 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <unistd.h>
 #include <errno.h>
 #include <asm/types.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <linux/netlink.h>
-#include <poll.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <unistd.h>
 
 #include "nl.h"
 
 nl_fds_t * nl_init(void)
 {
 	struct sockaddr_nl nl_addr;
-	int nl;
+	nl_fds_t *nl_fds;
+
+	nl_fds = malloc(sizeof(*nl_fds) * NL_FDS_LEN);
+	if (!nl_fds)
+		return NULL;
 
 	memset(&nl_addr, 0, sizeof(nl_addr));
 	nl_addr.nl_family = AF_NETLINK;
@@ -22,21 +27,33 @@ nl_fds_t * nl_init(void)
 	nl_addr.nl_pid = 0; /* Let kernel to assign id */
 	nl_addr.nl_groups = -1; /* Listen all multicast */
 
-	if ((nl = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT)) < 0) {
-		fprintf(stderr, "Error: Can't create socket\n");
-		return -1;
+	/* NETLINK_KOBJECT_UEVENT for PCI events */
+	if ((nl_fds[0] = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT)) < 0) {
+		fprintf(stderr, "Error: Can't create socket for NETLINK_KOBJECT_UEVENT.\n");
+		return NULL;
 	}
-	if (bind(nl, (void *)&nl_addr, sizeof(nl_addr))) {
-		fprintf(stderr, "Error: Can't bind NetLink\n");
-		return -1;
+	if (bind(nl_fds[0], (void *)&nl_addr, sizeof(nl_addr))) {
+		fprintf(stderr, "Error: Can't bind NETLINK_KOBJECT_UEVENT.\n");
+		return NULL;
 	}
+printf("KOBJECT=%d\n", nl_fds[0]);
 
-	return nl;
+	/* NETLINK_ROUTER for network events like interface up/down */
+	if ((nl_fds[1] = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) {
+		fprintf(stderr, "Error: Can't create socket for NETLINK_ROUTER\n");
+		return NULL;
+	}
+	if (bind(nl_fds[1], (void *)&nl_addr, sizeof(nl_addr))) {
+		fprintf(stderr, "Error: Can't bind NETLINK_ROUTER\n");
+		return NULL;
+	}
+printf("ROUTE=%d\n", nl_fds[1]);
+
+	return nl_fds;
 }
 
 void nl_close(nl_fds_t *nl_fds)
 {
-	int fd;
 	int i;
 
 	if (!nl_fds)
@@ -46,27 +63,53 @@ void nl_close(nl_fds_t *nl_fds)
 		if (nl_fds[i] >= 0)
 			close(nl_fds[i]);
 	}
+
+	free(nl_fds);
 }
 
 int nl_poll(nl_fds_t *nl_fds, int timeout)
 {
-	struct pollfd pfd;
+	fd_set fd_set;
 	char buf[10];
 	int n;
+	int i;
+	int nfds = 0;
+	struct timeval tv;
+
+	if (!nl_fds)
+		return -1;
+
+	/* Initialize the set of active sockets. */
+	FD_ZERO(&fd_set);
+	for (i = 0; i < NL_FDS_LEN; i++) {
+		FD_SET(nl_fds[i], &fd_set);
+		if (nl_fds[i] > nfds)
+			nfds = nl_fds[i];
+	}
+	nfds++;
 
-	pfd.events = POLLIN;
-	pfd.fd = nl;
+	/* Wait up to five seconds. */
+	tv.tv_sec = timeout;
+	tv.tv_usec = 0;
 
-	n = poll(&pfd, 1, (timeout * 1000));
+	n = select(nfds, &fd_set, NULL, NULL, &tv);
+printf("NETLINK: n=%d\n", n);
 	if (n < 0) {
 		if (EINTR == errno)
 			return -2;
 		return -1;
 	}
-	/* Some device-related event */
-	/* Read all messages. We don't need a message content. */
-	if (n > 0)
-		while (recv(nl, buf, sizeof(buf), MSG_DONTWAIT) > 0);
+	if (0 == n)
+		return n;
+
+	/* Service all the sockets with input pending. */
+	for (i = 0; i < NL_FDS_LEN; i++) {
+		if (!FD_ISSET(nl_fds[i], &fd_set))
+				continue;
+printf("RECV %d %d\n", i, nl_fds[i]);
+		/* Read all messages. We don't need a message content. */
+		while (recv(nl_fds[i], buf, sizeof(buf), MSG_DONTWAIT) > 0);
+	}
 
 	return n;
 }