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