hal/hald/linux2 classdev.c, 1.4, 1.5 hotplug.c, 1.2, 1.3 osspec.c, 1.2, 1.3

David Zeuthen david at freedesktop.org
Wed Jan 26 12:15:01 PST 2005


Update of /cvs/hal/hal/hald/linux2
In directory gabe:/tmp/cvs-serv4134/hald/linux2

Modified Files:
	classdev.c hotplug.c osspec.c 
Log Message:
2005-01-26  David Zeuthen  <davidz at redhat.com>

	* hald/linux2/osspec.c (link_detection_handle_message): New function.
	(netlink_socket_data): New function
	(osspec_init): Listen to netlink socket

	* hald/linux2/hotplug.c (fixup_net_device_for_renaming): New function.
	For coping with net interfaces being renamed before hald can handle
	them (For testing, put in the line g_spawn_command_line_sync 
	("/path/to/ifrename", NULL, NULL, NULL, NULL); in the top of hotplug_
	event_begin().
	(hotplug_event_begin): Call fixup_net_device_for_renaming()

	* hald/linux2/classdev.c (net_add): Be a bit more defensive
	about errors; export the net.80203.can_detect_link property



Index: classdev.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux2/classdev.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- classdev.c	23 Jan 2005 23:11:59 -0000	1.4
+++ classdev.c	26 Jan 2005 20:14:58 -0000	1.5
@@ -171,19 +171,15 @@
 
 	d = NULL;
 
-	if (physdev == NULL) {
-		goto out;
-	}
+	if (physdev == NULL)
+		goto error;
 
 	d = hal_device_new ();
 	hal_device_property_set_string (d, "linux.sysfs_path", sysfs_path);
 	hal_device_property_set_string (d, "info.parent", physdev->udi);
 
-	if (!hal_util_set_driver (d, "net.linux.driver", sysfs_path)) {
-		hal_device_store_remove (hald_get_tdl (), d);
-		d = NULL;
-		goto out;
-	}
+	if (!hal_util_set_driver (d, "net.linux.driver", sysfs_path))
+		goto error;
 
 	hal_device_property_set_string (d, "info.category", "net");
 	hal_device_add_capability (d, "net");
@@ -193,12 +189,21 @@
 	ifname = hal_util_get_last_element (sysfs_path);
 	hal_device_property_set_string (d, "net.interface", ifname);
 
-	hal_util_set_string_from_file (d, "net.address", sysfs_path, "address");
-	hal_util_set_int_from_file (d, "net.linux.ifindex", sysfs_path, "ifindex", 10);
+	if (!hal_util_set_string_from_file (d, "net.address", sysfs_path, "address"))
+		goto error;
+	if (!hal_util_set_int_from_file (d, "net.linux.ifindex", sysfs_path, "ifindex", 10))
+		goto error;
 
-	hal_util_set_int_from_file (d, "net.arp_proto_hw_id", sysfs_path, "type", 10);
-	media_type = hal_device_property_get_int (d, "net.arp_proto_hw_id");
+	if (!hal_util_set_int_from_file (d, "net.arp_proto_hw_id", sysfs_path, "type", 10))
+		goto error;
+
+	if (!hal_util_get_int_from_file (sysfs_path, "flags", &flags, 16))
+		goto error;
+	hal_device_property_set_bool (d, "net.interface_up", flags & IFF_UP);
+
+	hal_device_property_set_string (d, "info.product", "Networking Interface");
 
+	media_type = hal_device_property_get_int (d, "net.arp_proto_hw_id");
 	if (media_type == ARPHRD_ETHER) {
 		FILE *f;
 		gboolean is_wireless;
@@ -248,11 +253,15 @@
 			hal_device_property_set_string (d, "info.category", "net.80203");
 			hal_device_add_capability (d, "net.80203");
 
-			hal_util_get_int_from_file (sysfs_path, "carrier", &have_link, 10);
-			hal_device_property_set_bool (d, "net.80203.link", have_link != 0);
-			if (have_link != 0) {
-				HAL_INFO (("FIXME: no speed file in sysfs; assuming link speed is 100Mbps"));
-				hal_device_property_set_uint64 (d, "net.80203.rate", 100 * 1000 * 1000);
+			if (hal_util_get_int_from_file (sysfs_path, "carrier", &have_link, 10)) {
+				hal_device_property_set_bool (d, "net.80203.can_detect_link", TRUE);
+				hal_device_property_set_bool (d, "net.80203.link", have_link != 0);
+				if (have_link != 0) {
+					HAL_INFO (("FIXME: no speed file in sysfs; assuming link speed is 100Mbps"));
+					hal_device_property_set_uint64 (d, "net.80203.rate", 100 * 1000 * 1000);
+				}
+			} else {
+				hal_device_property_set_bool (d, "net.80203.can_detect_link", FALSE);
 			}
 		}
 
@@ -279,13 +288,13 @@
 		}
 	}
 
-	hal_util_get_int_from_file (sysfs_path, "flags", &flags, 16);
-	hal_device_property_set_bool (d, "net.interface_up", flags & IFF_UP);
-
-	hal_device_property_set_string (d, "info.product", "Networking Interface");
-
+	return d;
+error:
+	if (d != NULL) {
+		hal_device_store_remove (hald_get_tdl (), d);
+		d = NULL;
+	}
 
-out:
 	return d;
 }
 

Index: hotplug.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux2/hotplug.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- hotplug.c	23 Jan 2005 23:11:59 -0000	1.2
+++ hotplug.c	26 Jan 2005 20:14:59 -0000	1.3
@@ -72,6 +72,53 @@
 }
 
 
+
+static void
+fixup_net_device_for_renaming (HotplugEvent *hotplug_event)
+{
+	/* fixup net devices by looking at ifindex */
+	if (strcmp (hotplug_event->subsystem, "net") == 0 && hotplug_event->net_ifindex != -1) {
+		int ifindex;
+		
+		if (!hal_util_get_int_from_file (hotplug_event->sysfs_path, "ifindex", &ifindex, 10) ||
+		    (ifindex != hotplug_event->net_ifindex)) {
+			GDir *dir;
+			char path[HAL_PATH_MAX];
+			char path1[HAL_PATH_MAX];
+			GError *err = NULL;
+			const gchar *f;
+			
+			/* search for new name */
+			HAL_WARNING (("Net interface @ %s with ifindex %d was probably renamed",
+				      hotplug_event->sysfs_path, hotplug_event->net_ifindex));
+			
+			
+			g_snprintf (path, HAL_PATH_MAX, "%s/class/net" , hal_sysfs_path);
+			if ((dir = g_dir_open (path, 0, &err)) == NULL) {
+				HAL_ERROR (("Unable to open %/class/net: %s", hal_sysfs_path, err->message));
+				g_error_free (err);
+				goto out;
+			}
+			while ((f = g_dir_read_name (dir)) != NULL) {
+				g_snprintf (path1, HAL_PATH_MAX, "%s/class/net/%s" , hal_sysfs_path, f);
+				if (hal_util_get_int_from_file (path1, "ifindex", &ifindex, 10)) {
+					if (ifindex == hotplug_event->net_ifindex) {
+						HAL_INFO (("Using sysfs path %s for ifindex %d", path1, ifindex));
+						strncpy (hotplug_event->sysfs_path, path1, HAL_PATH_MAX);
+						g_dir_close (dir);
+						goto out;
+					}
+				}
+				
+			}
+			g_dir_close (dir);	
+		}
+	}
+out:
+	;
+}
+
+
 static void
 hotplug_event_begin (HotplugEvent *hotplug_event)
 {
@@ -111,7 +158,10 @@
 
 			sysfs_path_in_devices = NULL;
 
-			/* TODO: fixup net devices by looking at ifindex */
+			/* /sbin/ifrename may be called from a hotplug handler before we process this,
+			 * so if index doesn't match, go ahead and find a new sysfs path
+			 */
+			fixup_net_device_for_renaming (hotplug_event);
 			
 			g_snprintf (physdevpath, HAL_PATH_MAX, "%s/device", hotplug_event->sysfs_path);
 			if (((target = g_file_read_link (physdevpath, NULL)) != NULL)) {

Index: osspec.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux2/osspec.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- osspec.c	25 Jan 2005 16:55:09 -0000	1.2
+++ osspec.c	26 Jan 2005 20:14:59 -0000	1.3
@@ -27,16 +27,37 @@
 #  include <config.h>
 #endif
 
+#include <ctype.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <mntent.h>
+#include <getopt.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <limits.h>
 #include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
+#include <mntent.h>
 #include <sys/un.h>
 #include <sys/utsname.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <net/if_arp.h> /* for ARPHRD_... */
+#include <sys/socket.h>
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
@@ -45,6 +66,7 @@
 #include "../osspec.h"
 #include "../logger.h"
 #include "../hald.h"
+#include "../hald_dbus.h"
 #include "../callout.h"
 #include "../device_info.h"
 #include "../hald_conf.h"
@@ -60,6 +82,198 @@
 char hal_sysfs_path [HAL_PATH_MAX];
 char hal_proc_path [HAL_PATH_MAX];
 
+/* TODO: clean up netlink socket handling - this is almost a verbatim copy from 0.4.x */
+
+static void
+link_detection_handle_message (struct nlmsghdr *hdr)
+{
+	struct ifinfomsg *ifinfo;
+	char ifname[1024];
+	struct rtattr *attr;
+	int attr_len;
+	HalDevice *d;
+	const char *hal_ifname;
+
+	ifinfo = NLMSG_DATA (hdr);
+
+	if (hdr->nlmsg_len < NLMSG_LENGTH (sizeof (struct ifinfomsg))) {
+		HAL_ERROR (("Packet too small or truncated for ifinfomsg"));
+		return;
+	}
+
+	memset (&ifname, 0, sizeof (ifname));
+
+	attr = (struct rtattr *) ((unsigned char *)ifinfo + NLMSG_ALIGN (sizeof (struct ifinfomsg)));
+	attr_len = NLMSG_PAYLOAD (hdr, sizeof (struct ifinfomsg));
+
+	while (RTA_OK (attr, attr_len)) {
+		if (attr->rta_type == IFLA_IFNAME) {
+			unsigned int l = RTA_PAYLOAD (attr);
+
+			if (l > sizeof (ifname) - 1)
+				l = sizeof (ifname) - 1;
+
+			strncpy (ifname, RTA_DATA (attr), l);
+		}
+
+		attr = RTA_NEXT (attr, attr_len);
+	}
+
+	/* bail out if there is no interface name */
+	if (strlen (ifname) == 0)
+		goto out;
+
+	HAL_INFO (("type=0x%02x, SEQ=%d, ifi_flags=0x%04x, ifi_change=0x%04x, ifi_index=%d, ifname='%s'", 
+		   hdr->nlmsg_type, 
+		   hdr->nlmsg_seq,
+		   ifinfo->ifi_flags,
+		   ifinfo->ifi_change,
+		   ifinfo->ifi_index,
+		   ifname));
+
+	/* find hal device object this event applies to */
+	d = hal_device_store_match_key_value_int (hald_get_gdl (), "net.linux.ifindex", ifinfo->ifi_index);
+	if (d == NULL) {
+		HAL_WARNING (("No HAL device object corresponding to ifindex=%d, ifname='%s'",
+			      ifinfo->ifi_index, ifname));
+		goto out;
+	}
+
+	device_property_atomic_update_begin ();
+	{
+
+		/* handle link changes */
+		if (ifinfo->ifi_flags & IFF_RUNNING) {
+			if (hal_device_has_capability (d, "net.80203") && 
+			    hal_device_property_get_bool (d, "net.80203.can_detect_link")) {
+				if (!hal_device_property_get_bool (d, "net.80203.link")) {
+					hal_device_property_set_bool (d, "net.80203.link", TRUE);
+					HAL_INFO (("Assuming link speed is 100Mbps"));
+					hal_device_property_set_uint64 (d, "net.80203.rate", 100 * 1000 * 1000);
+				}
+			}
+		} else {
+			if (hal_device_has_capability (d, "net.80203") && 
+			    hal_device_property_get_bool (d, "net.80203.can_detect_link")) {
+				if (hal_device_property_get_bool (d, "net.80203.link")) {
+					hal_device_property_set_bool (d, "net.80203.link", FALSE);
+					/* only have rate when we have a link */
+					hal_device_property_remove (d, "net.80203.rate");
+				}
+			}
+		}
+		
+		/* handle events for renaming */
+		hal_ifname = hal_device_property_get_string (d, "net.interface");
+		if (hal_ifname != NULL && strcmp (hal_ifname, ifname) != 0) {
+			char new_sysfs_path[256];
+			const char *sysfs_path;
+			char *p;
+
+			HAL_INFO (("Net interface '%s' renamed to '%s'", hal_ifname, ifname));
+
+			hal_device_property_set_string (d, "net.interface", ifname);
+
+			sysfs_path = hal_device_property_get_string (d, "net.linux.sysfs_path");
+			strncpy (new_sysfs_path, sysfs_path, sizeof (new_sysfs_path) - 1);
+			p = strrchr (new_sysfs_path, '/');
+			if (p != NULL) {
+				strncpy (p + 1, ifname, sizeof (new_sysfs_path) - 1 - (p + 1 - new_sysfs_path));
+				hal_device_property_set_string (d, "net.linux.sysfs_path", new_sysfs_path);
+			}
+		}
+
+		/* handle up/down status */
+		if (ifinfo->ifi_flags & IFF_UP) {
+			if (!hal_device_property_get_bool (d, "net.interface_up")) {
+				hal_device_property_set_bool (d, "net.interface_up", TRUE);
+			}
+		} else {
+			if (hal_device_property_get_bool (d, "net.interface_up")) {
+				hal_device_property_set_bool (d, "net.interface_up", FALSE);
+			}
+		}
+		
+	}
+	device_property_atomic_update_end ();
+
+out:
+	return;
+}
+
+#define VALID_NLMSG(h, s) ((NLMSG_OK (h, s) && \
+                           s >= sizeof (struct nlmsghdr) && \
+                           s >= h->nlmsg_len))
+
+static gboolean
+netlink_socket_data (GIOChannel *channel, GIOCondition cond, gpointer user_data)
+{
+	int fd;
+	int bytes_read;
+	guint total_read = 0;
+	struct sockaddr_nl nladdr;
+	socklen_t nladdrlen = sizeof(nladdr);
+	char buf[1024];
+
+	if (cond & ~(G_IO_IN | G_IO_PRI)) {
+		HAL_ERROR (("Error occurred on netlink socket"));
+		return TRUE;
+	}
+
+	fd = g_io_channel_unix_get_fd (channel);
+	do {
+		errno = 0;
+		bytes_read = recvfrom (fd,
+				       buf + total_read,
+				       sizeof (buf) - total_read,
+				       MSG_DONTWAIT,
+				       (struct sockaddr*)&nladdr, &nladdrlen);
+		if (nladdrlen != sizeof(nladdr)) {
+			HAL_ERROR(("Bad address size reading netlink socket"));
+			return TRUE;
+		}
+		if (nladdr.nl_pid) {
+			HAL_ERROR(("Spoofed packet received on netlink socket"));
+			return TRUE;
+		}
+		if (bytes_read > 0)
+			total_read += bytes_read;
+	} while (bytes_read > 0 || errno == EINTR);
+
+	if (bytes_read < 0 && errno != EAGAIN) {
+		HAL_ERROR (("Error reading data off netlink socket"));
+		return TRUE;
+	}
+
+	if (total_read > 0) {
+		struct nlmsghdr *hdr = (struct nlmsghdr *) buf;
+		guint offset = 0;
+
+		while (offset < total_read &&
+		       VALID_NLMSG (hdr, total_read - offset)) {
+
+			if (hdr->nlmsg_type == NLMSG_DONE)
+				break;
+
+			if (hdr->nlmsg_type == RTM_NEWLINK ||
+			    hdr->nlmsg_type == RTM_DELLINK)
+				link_detection_handle_message (hdr);
+
+			offset += hdr->nlmsg_len;
+			hdr = (struct nlmsghdr *) (buf + offset);
+		}
+
+		if (offset < total_read &&
+		    !VALID_NLMSG (hdr, total_read - offset)) {
+			HAL_ERROR (("Packet too small or truncated"));
+			return TRUE;
+		}
+	}
+
+	return TRUE;
+}
+
+
 static gboolean
 hald_helper_data (GIOChannel *source, 
 		  GIOCondition condition, 
@@ -154,6 +368,8 @@
 void
 osspec_init (void)
 {
+	int netlinkfd;
+	struct sockaddr_nl netlink_addr;
 	int socketfd;
 	struct sockaddr_un saddr;
 	socklen_t addrlen;
@@ -176,7 +392,6 @@
 		fprintf (stderr, "Error binding to %s: %s\n", HALD_HELPER_SOCKET_PATH, strerror(errno));
 		exit (1);
 	}
-
 	/* enable receiving of the sender credentials */
 	setsockopt(socketfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
 
@@ -191,13 +406,32 @@
 		goto error;
 	}
 	HAL_INFO (("sysfs mount point is '%s'", hal_sysfs_path));
-
 	if (!hal_util_get_fs_mnt_path ("proc", hal_proc_path, sizeof (hal_proc_path))) {
 		HAL_ERROR (("Could not get proc mount point"));
 		goto error;
 	}
 	HAL_INFO (("proc mount point is '%s'", hal_proc_path));
 
+
+	/* Listen to the netlink socket */
+	netlinkfd = socket (PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+
+	if (netlinkfd < 0) {
+		DIE (("Couldn't open socket"));
+	}
+
+	memset (&netlink_addr, 0, sizeof (netlink_addr));
+	netlink_addr.nl_family = AF_NETLINK;
+	netlink_addr.nl_pid = getpid ();
+	netlink_addr.nl_groups = RTMGRP_LINK;
+	if (bind (netlinkfd, (struct sockaddr *) &netlink_addr, sizeof (netlink_addr)) < 0) {
+		DIE (("Unable to bind to netlink socket"));
+		return;
+	}
+	channel = g_io_channel_unix_new (netlinkfd);
+	g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_NVAL,
+			netlink_socket_data, NULL);
+	
 	/* Load various hardware id databases */
 	ids_init ();
 




More information about the hal-commit mailing list