00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #ifdef HAVE_CONFIG_H
00028 # include <config.h>
00029 #endif
00030
00031 #include <ctype.h>
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <getopt.h>
00036 #include <assert.h>
00037 #include <unistd.h>
00038 #include <stdarg.h>
00039 #include <limits.h>
00040 #include <errno.h>
00041 #include <sys/types.h>
00042 #include <sys/stat.h>
00043 #include <sys/ioctl.h>
00044 #include <fcntl.h>
00045 #include <net/if_arp.h>
00046 #include <sys/socket.h>
00047 #include <linux/types.h>
00048 #include <linux/netlink.h>
00049 #include <linux/rtnetlink.h>
00050 #include <sys/ioctl.h>
00051 #include <net/if.h>
00052
00053 #include "../logger.h"
00054 #include "../device_store.h"
00055 #include "../hald.h"
00056
00057 #include "class_device.h"
00058 #include "common.h"
00059
00067 static const char *
00068 media_type_to_string (int media_type)
00069 {
00070 switch (media_type) {
00071 case ARPHRD_NETROM:
00072 return "NET/ROM pseudo";
00073
00074 case ARPHRD_ETHER:
00075 return "Ethernet";
00076
00077 case ARPHRD_EETHER:
00078 return "Experimental Ethernet";
00079
00080 case ARPHRD_AX25:
00081 return "AX.25 Level 2";
00082
00083 case ARPHRD_PRONET:
00084 return "PROnet token ring";
00085
00086 case ARPHRD_CHAOS:
00087 return "Chaosnet";
00088
00089 case ARPHRD_ARCNET:
00090 return "ARCnet";
00091
00092 case ARPHRD_APPLETLK:
00093 return "Appletalk";
00094
00095 case ARPHRD_DLCI:
00096 return "Frame Relay DLCI";
00097
00098 case ARPHRD_ATM:
00099 return "ATM";
00100
00101 case ARPHRD_METRICOM:
00102 return "Metricom STRIP (new IANA id)";
00103
00104 #ifdef ARPHRD_IEEE1394
00105 case ARPHRD_IEEE1394:
00106 return "IEEE1394 IPv4 - RFC 2734";
00107 #endif
00108
00109 default:
00110 return "Unknown";
00111 }
00112 }
00113
00120 static guint16
00121 mdio_read (int sockfd, struct ifreq *ifr, int location,
00122 gboolean new_ioctl_nums)
00123 {
00124 guint16 *data = (guint16 *) &(ifr->ifr_data);
00125
00126 data[1] = location;
00127
00128 if (ioctl (sockfd,
00129 new_ioctl_nums ? 0x8948 : SIOCDEVPRIVATE + 1,
00130 ifr) < 0) {
00131 HAL_ERROR (("SIOCGMIIREG on %s failed: %s\n",
00132 ifr->ifr_name, strerror (errno)));
00133 return -1;
00134 }
00135 return data[3];
00136 }
00137
00138 static void
00139 mii_get_rate (HalDevice *d)
00140 {
00141 const char *ifname;
00142 int sockfd;
00143 struct ifreq ifr;
00144 gboolean new_ioctl_nums;
00145 guint16 link_word;
00146
00147 ifname = hal_device_property_get_string (d, "net.interface");
00148
00149 sockfd = socket (AF_INET, SOCK_DGRAM, 0);
00150 if (sockfd < 0) {
00151 HAL_ERROR (("cannot open socket on interface %s; errno=%d",
00152 ifname, errno));
00153 return;
00154 }
00155
00156 snprintf (ifr.ifr_name, IFNAMSIZ, ifname);
00157
00158 if (ioctl (sockfd, 0x8947, &ifr) >= 0)
00159 new_ioctl_nums = TRUE;
00160 else if (ioctl (sockfd, SIOCDEVPRIVATE, &ifr) >= 0)
00161 new_ioctl_nums = FALSE;
00162 else {
00163 HAL_ERROR (("SIOCGMIIPHY on %s failed: %s",
00164 ifr.ifr_name, strerror (errno)));
00165 close (sockfd);
00166 return;
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 link_word = mdio_read (sockfd, &ifr, 5, new_ioctl_nums);
00183
00184 if (link_word & 0x380) {
00185 hal_device_property_set_int (d, "net.ethernet.rate",
00186 100 * 1000 * 1000);
00187 }
00188
00189 if (link_word & 0x60) {
00190 hal_device_property_set_int (d, "net.ethernet.rate",
00191 10 * 1000 * 1000);
00192 }
00193
00194 close (sockfd);
00195 }
00196
00197 static void
00198 mii_get_link (HalDevice *d)
00199 {
00200 const char *ifname;
00201 int sockfd;
00202 struct ifreq ifr;
00203 gboolean new_ioctl_nums;
00204 guint16 status_word;
00205
00206 ifname = hal_device_property_get_string (d, "net.interface");
00207
00208 sockfd = socket (AF_INET, SOCK_DGRAM, 0);
00209 if (sockfd < 0) {
00210 HAL_ERROR (("cannot open socket on interface %s; errno=%d",
00211 ifname, errno));
00212 return;
00213 }
00214
00215 snprintf (ifr.ifr_name, IFNAMSIZ, ifname);
00216
00217 if (ioctl (sockfd, 0x8947, &ifr) >= 0)
00218 new_ioctl_nums = TRUE;
00219 else if (ioctl (sockfd, SIOCDEVPRIVATE, &ifr) >= 0)
00220 new_ioctl_nums = FALSE;
00221 else {
00222 HAL_ERROR (("SIOCGMIIPHY on %s failed: %s",
00223 ifr.ifr_name, strerror (errno)));
00224 close (sockfd);
00225 return;
00226 }
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244 status_word = mdio_read (sockfd, &ifr, 1, new_ioctl_nums);
00245 status_word = mdio_read (sockfd, &ifr, 1, new_ioctl_nums);
00246
00247 if ((status_word & 0x0016) == 0x0004)
00248 hal_device_property_set_bool (d, "net.ethernet.link", TRUE);
00249 else
00250 hal_device_property_set_bool (d, "net.ethernet.link", FALSE);
00251
00252
00253 mii_get_rate (d);
00254
00255 close (sockfd);
00256 }
00257
00258 static void
00259 link_detection_handle_message (struct nlmsghdr *hdr, HalDevice *d)
00260 {
00261 struct ifinfomsg *ifinfo;
00262 char ifname[1024];
00263 struct rtattr *attr;
00264 int attr_len;
00265
00266 ifinfo = NLMSG_DATA (hdr);
00267
00268 if (hdr->nlmsg_len < NLMSG_LENGTH (sizeof (struct ifinfomsg))) {
00269 HAL_ERROR (("Packet too small or truncated for ifinfomsg"));
00270 return;
00271 }
00272
00273 memset (&ifname, 0, sizeof (ifname));
00274
00275 attr = (void *) ifinfo + NLMSG_ALIGN (sizeof (struct ifinfomsg));
00276 attr_len = NLMSG_PAYLOAD (hdr, sizeof (struct ifinfomsg));
00277
00278 while (RTA_OK (attr, attr_len)) {
00279 if (attr->rta_type == IFLA_IFNAME) {
00280 int l = RTA_PAYLOAD (attr);
00281
00282 if (l > 1023)
00283 l = 1023;
00284
00285 strncpy (ifname, RTA_DATA (attr), l);
00286 }
00287
00288 attr = RTA_NEXT (attr, attr_len);
00289 }
00290
00291 hal_device_property_set_bool (d, "net.ethernet.link",
00292 ifinfo->ifi_flags & IFF_RUNNING ?
00293 TRUE : FALSE);
00294
00295
00296
00297
00298
00299 if (!hal_device_has_property (d, "net.ethernet.rate"))
00300 mii_get_rate (d);
00301 }
00302
00303 #define VALID_NLMSG(h, s) ((NLMSG_OK (h, s) && \
00304 s >= sizeof (struct nlmsghdr) && \
00305 s >= h->nlmsg_len))
00306
00307 static gboolean
00308 link_detection_data_ready (GIOChannel *channel, GIOCondition cond,
00309 gpointer user_data)
00310 {
00311 HalDevice *d = HAL_DEVICE (user_data);
00312 int fd;
00313 int bytes_read;
00314 int total_read = 0;
00315 char buf[1024];
00316
00317 if (cond & ~(G_IO_IN | G_IO_PRI)) {
00318 HAL_ERROR (("Error occurred on netlink socket"));
00319 return FALSE;
00320 }
00321
00322 fd = g_io_channel_unix_get_fd (channel);
00323
00324 do {
00325 errno = 0;
00326 bytes_read = recv (fd,
00327 buf + total_read,
00328 sizeof (buf) - total_read,
00329 MSG_DONTWAIT);
00330
00331 if (bytes_read > 0)
00332 total_read += bytes_read;
00333 } while (bytes_read > 0 || errno == EINTR);
00334
00335 if (bytes_read < 0 && errno != EAGAIN) {
00336 HAL_ERROR (("Error reading data off netlink socket"));
00337 return FALSE;
00338 }
00339
00340 if (total_read > 0) {
00341 struct nlmsghdr *hdr = (struct nlmsghdr *) buf;
00342 int offset = 0;
00343
00344 while (offset < total_read &&
00345 VALID_NLMSG (hdr, total_read - offset)) {
00346 if (hdr->nlmsg_type == NLMSG_DONE)
00347 break;
00348
00349 if (hdr->nlmsg_type == RTM_NEWLINK ||
00350 hdr->nlmsg_type == RTM_DELLINK)
00351 link_detection_handle_message (hdr, d);
00352
00353 offset += hdr->nlmsg_len;
00354 hdr = (struct nlmsghdr *) (buf + offset);
00355 }
00356
00357 if (offset < total_read &&
00358 !VALID_NLMSG (hdr, total_read - offset)) {
00359 HAL_ERROR (("Packet too small or truncated"));
00360 return FALSE;
00361 }
00362 }
00363
00364 return TRUE;
00365 }
00366
00367 static void
00368 link_detection_init (HalDevice *d)
00369 {
00370 int fd;
00371 struct sockaddr_nl addr;
00372 GIOChannel *channel;
00373
00374 fd = socket (PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
00375
00376 if (fd < 0) {
00377 HAL_ERROR (("Unable to create netlink socket"));
00378 return;
00379 }
00380
00381 memset (&addr, 0, sizeof (addr));
00382 addr.nl_family = AF_NETLINK;
00383 addr.nl_pid = getpid ();
00384 addr.nl_groups = RTMGRP_LINK;
00385
00386 if (bind (fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
00387 HAL_ERROR (("Unable to bind to netlink socket"));
00388 return;
00389 }
00390
00391 channel = g_io_channel_unix_new (fd);
00392
00393 g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_NVAL,
00394 link_detection_data_ready, d);
00395 }
00396
00411 static void
00412 net_class_pre_process (ClassDeviceHandler *self,
00413 HalDevice *d,
00414 const char *sysfs_path,
00415 struct sysfs_class_device *class_device)
00416 {
00417 struct sysfs_attribute *attr;
00418 char *address = NULL;
00419 int media_type = 0;
00420 const char *media;
00421
00422 hal_device_property_set_string (d, "net.linux.sysfs_path", sysfs_path);
00423 hal_device_property_set_string (d, "net.interface",
00424 class_device->name);
00425
00426 attr = sysfs_get_classdev_attr (class_device, "address");
00427
00428 if (attr != NULL)
00429 address = g_strstrip (g_strdup (attr->value));
00430
00431 attr = sysfs_get_classdev_attr (class_device, "type");
00432
00433 if (attr != NULL)
00434 media_type = parse_dec (attr->value);
00435
00436
00437 if (address != NULL && media_type == ARPHRD_ETHER) {
00438 unsigned int a5, a4, a3, a2, a1, a0;
00439
00440 hal_device_property_set_string (d, "net.ethernet.mac_addr",
00441 address);
00442
00443 if (sscanf (address, "%x:%x:%x:%x:%x:%x",
00444 &a5, &a4, &a3, &a2, &a1, &a0) == 6) {
00445 dbus_uint32_t mac_upper, mac_lower;
00446
00447 mac_upper = (a5 << 16) | (a4 << 8) | a3;
00448 mac_lower = (a2 << 16) | (a1 << 8) | a0;
00449
00450 hal_device_property_set_int (d,
00451 "net.ethernet.mac_addr_upper24",
00452 (dbus_int32_t) mac_upper);
00453 hal_device_property_set_int (d,
00454 "net.ethernet.mac_addr_lower24",
00455 (dbus_int32_t) mac_lower);
00456 }
00457
00458
00459 mii_get_link (d);
00460 }
00461
00462 g_free (address);
00463
00464 hal_device_property_set_int (d, "net.arp_proto_hw_id", media_type);
00465
00466 media = media_type_to_string (media_type);
00467 hal_device_property_set_string (d, "net.media", media);
00468 }
00469
00470 static void
00471 net_class_post_merge (ClassDeviceHandler *self, HalDevice *d)
00472 {
00473 if (hal_device_has_capability (d, "net.ethernet"))
00474 link_detection_init (d);
00475 }
00476
00478 ClassDeviceHandler net_class_handler = {
00479 class_device_init,
00480 class_device_detection_done,
00481 class_device_shutdown,
00482 class_device_tick,
00483 class_device_accept,
00484 class_device_visit,
00485 class_device_removed,
00486 class_device_udev_event,
00487 class_device_get_device_file_target,
00488 net_class_pre_process,
00489 net_class_post_merge,
00490 class_device_got_udi,
00491 NULL,
00492 "net",
00493 "net",
00494 FALSE,
00495 TRUE
00496 };
00497