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
00040 #include <glib.h>
00041
00042 #include <errno.h>
00043 #include <net/if.h>
00044 #include <sys/ioctl.h>
00045 #include <sys/socket.h>
00046
00047 #include <net/if_arp.h>
00048
00049 #include "../hald.h"
00050 #include "../logger.h"
00051 #include "../device_store.h"
00052 #include "linux_class_net.h"
00053
00062
00063 static void visit_class_device_net_got_sysdevice(HalDevice* parent,
00064 void* data1, void* data2);
00065
00074 void visit_class_device_net(const char* path,
00075 struct sysfs_class_device* class_device)
00076 {
00077 int i;
00078 int len;
00079 HalDevice* d;
00080 struct sysfs_attribute* cur;
00081 char attr_name[SYSFS_NAME_LEN];
00082 char* addr_store = NULL;
00083 int media_type = 0;
00084 char* media;
00085
00086 if( class_device->sysdevice==NULL )
00087 {
00088 HAL_WARNING(("Net class device at sysfs path %s doesn't have "
00089 "sysdevice", path));
00090 return;
00091 }
00092
00093 d = ds_device_new();
00094 ds_property_set_string(d, "net.interface", class_device->name);
00095 ds_property_set_string(d, "net.linux.sysfs_path", path);
00096
00097 dlist_for_each_data(sysfs_get_classdev_attributes(class_device), cur,
00098 struct sysfs_attribute)
00099 {
00100 if( sysfs_get_name_from_path(cur->path,
00101 attr_name, SYSFS_NAME_LEN) != 0 )
00102 continue;
00103
00104
00105 len = strlen(cur->value);
00106 for(i=len-1; i>=0 && isspace(cur->value[i]); --i)
00107 cur->value[i] = '\0';
00108
00109 if( strcmp(attr_name, "address")==0 )
00110 {
00111 addr_store = cur->value;
00112 }
00113 else if( strcmp(attr_name, "type")==0 )
00114 {
00115 media_type = parse_dec(cur->value);
00116 }
00117 }
00118
00119 if( addr_store!=NULL && media_type==ARPHRD_ETHER )
00120 {
00121 unsigned int a5, a4, a3 ,a2, a1, a0;
00122
00123 ds_property_set_string(d, "net.ethernet.mac_addr", addr_store);
00124
00125 if( sscanf(addr_store, "%x:%x:%x:%x:%x:%x",
00126 &a5, &a4, &a3, &a2, &a1, &a0)==6 )
00127 {
00128 dbus_uint32_t mac_upper, mac_lower;
00129
00130 mac_upper = (a5<<16)|(a4<<8)|a3;
00131 mac_lower = (a2<<16)|(a1<<8)|a0;
00132
00133 ds_property_set_int(d, "net.ethernet.mac_addr_upper24",
00134 (dbus_int32_t) mac_upper);
00135 ds_property_set_int(d, "net.ethernet.mac_addr_lower24",
00136 (dbus_int32_t) mac_lower);
00137 }
00138 }
00139
00140
00141
00142 if( class_device->driver!=NULL )
00143 {
00144 ds_property_set_string(d, "linux.driver",
00145 class_device->driver->name);
00146 }
00147
00148
00149 ds_property_set_int(d, "net.arp_proto_hw_id",
00150 media_type);
00151
00152
00153
00154
00155
00156
00157 ds_property_set_string(d, "info.category", "net");
00158 ds_add_capability(d, "net");
00159
00160
00161
00162
00163
00164 switch(media_type)
00165 {
00166 case ARPHRD_NETROM:
00167 media="NET/ROM pseudo";
00168 break;
00169 case ARPHRD_ETHER:
00170 media="Ethernet";
00171 ds_add_capability(d, "net.ethernet");
00172 break;
00173 case ARPHRD_EETHER:
00174 media="Experimenal Ethernet";
00175 break;
00176 case ARPHRD_AX25:
00177 media="AX.25 Level 2";
00178 break;
00179 case ARPHRD_PRONET:
00180 media="PROnet tokenring";
00181 ds_add_capability(d, "net.tokenring");
00182 break;
00183 case ARPHRD_CHAOS:
00184 media="Chaosnet";
00185 break;
00186 case ARPHRD_IEEE802:
00187 media="IEEE802";
00188 break;
00189 case ARPHRD_ARCNET:
00190 media="ARCnet";
00191 break;
00192 case ARPHRD_APPLETLK:
00193 media="APPLEtalk";
00194 break;
00195 case ARPHRD_DLCI:
00196 media="Frame Relay DLCI";
00197 break;
00198 case ARPHRD_ATM:
00199 media="ATM";
00200 ds_add_capability(d, "net.atm");
00201 break;
00202 case ARPHRD_METRICOM:
00203 media="Metricom STRIP (new IANA id)";
00204 break;
00205 #ifdef ARPHRD_IEEE1394
00206 case ARPHRD_IEEE1394:
00207 media="IEEE1394 IPv4 - RFC 2734";
00208 break;
00209 #endif
00210 default:
00211 media="Unknown";
00212 break;
00213 }
00214 ds_property_set_string(d, "net.media", media);
00215
00216
00217
00218
00219
00220 ds_device_async_find_by_key_value_string(
00221 "linux.sysfs_path_device",
00222 class_device->sysdevice->path,
00223 FALSE,
00224 visit_class_device_net_got_sysdevice,
00225 (void*) d, NULL,
00226 is_probing ? 0 :
00227 HAL_LINUX_HOTPLUG_TIMEOUT);
00228 }
00229
00237 static void visit_class_device_net_got_sysdevice(HalDevice* sysdevice,
00238 void* data1, void* data2)
00239 {
00240 HalDevice* d = (HalDevice*) data1;
00241
00242 if( sysdevice==NULL )
00243 {
00244 HAL_WARNING(("Sysdevice for a class net device never appeared!"));
00245 }
00246 else
00247 {
00248
00249
00250
00251 ds_device_merge(sysdevice, d);
00252 }
00253
00254
00255 ds_device_destroy(d);
00256 }
00257
00258
00259
00261 typedef struct link_detection_if_s
00262 {
00263 HalDevice* device;
00264 int skfd;
00265 struct ifreq ifr;
00266 int new_ioctl_nums;
00267 dbus_uint16_t status_word_baseline;
00268 struct link_detection_if_s* next;
00269 } link_detection_if;
00270
00272 static link_detection_if* link_detection_list_head = NULL;
00273
00280 static dbus_uint16_t mdio_read(link_detection_if* iface, int location)
00281 {
00282 dbus_uint16_t *data = (dbus_uint16_t *)(&(iface->ifr.ifr_data));
00283
00284 data[1] = location;
00285
00286 if( ioctl(iface->skfd,
00287 iface->new_ioctl_nums ? 0x8948 : SIOCDEVPRIVATE+1,
00288 &(iface->ifr)) < 0)
00289 {
00290 HAL_ERROR(("SIOCGMIIREG on %s failed: %s\n",
00291 iface->ifr.ifr_name, strerror(errno)));
00292 return -1;
00293 }
00294 return data[3];
00295 }
00296
00301 static void link_detection_process(link_detection_if* iface)
00302 {
00303 dbus_bool_t got_link = FALSE;
00304 dbus_uint16_t status_word;
00305 dbus_uint16_t link_word;
00306 dbus_uint16_t status_word_new;
00307
00308
00309
00310 status_word_new = mdio_read(iface, 1);
00311 if( status_word_new!=iface->status_word_baseline )
00312 {
00313 iface->status_word_baseline = status_word_new;
00314
00315 HAL_INFO(("Ethernet link status change on hal udi %s)",
00316 iface->device->udi));
00317
00318
00319 status_word = mdio_read(iface, 1);
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 property_atomic_update_begin();
00337
00338 if( (status_word&0x0016)==0x0004 )
00339 {
00340 ds_property_set_bool(iface->device,
00341 "net.ethernet.link", TRUE);
00342 got_link = TRUE;
00343 }
00344 else
00345 {
00346 ds_property_set_bool(iface->device,
00347 "net.ethernet.link", FALSE);
00348 }
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 link_word = mdio_read(iface, 1);
00364
00365
00366 if( link_word&0x0300 )
00367 {
00368 ds_property_set_int(iface->device, "net.ethernet.rate",
00369 100*1000*1000);
00370 }
00371 if( link_word&0x60 )
00372 {
00373 ds_property_set_int(iface->device, "net.ethernet.rate",
00374 10*1000*1000);
00375 }
00376
00377 property_atomic_update_end();
00378
00379 emit_condition(iface->device, "NetLinkEvent",
00380 DBUS_TYPE_BOOLEAN, got_link,
00381 DBUS_TYPE_INVALID);
00382 }
00383 }
00384
00390 static gboolean link_detection_timer_handler(gpointer data)
00391 {
00392 link_detection_if* iface;
00393
00394 for(iface=link_detection_list_head; iface!=NULL; iface=iface->next)
00395 link_detection_process(iface);
00396
00397 return TRUE;
00398 }
00399
00404 static void link_detection_add(HalDevice* device)
00405 {
00406 const char* interface_name;
00407 link_detection_if* iface;
00408
00409 iface = malloc(sizeof(link_detection_if));
00410 if( iface==NULL )
00411 DIE(("No memory"));
00412
00413 interface_name = ds_property_get_string(device, "net.interface");
00414 if( interface_name==NULL )
00415 {
00416 HAL_WARNING(("device '%s' does not have net.interface\n",
00417 device->udi));
00418 free(iface);
00419 return;
00420 }
00421
00422 iface->device = device;
00423
00424 snprintf(iface->ifr.ifr_name, IFNAMSIZ, interface_name);
00425
00426
00427 if( (iface->skfd = socket(AF_INET, SOCK_DGRAM,0))<0 )
00428 {
00429 HAL_ERROR(("cannot open socket on interface %s; errno=%d\n",
00430 interface_name, errno));
00431 free(iface);
00432 return;
00433 }
00434
00435 if( ioctl(iface->skfd, 0x8947, &(iface->ifr))>=0 )
00436 {
00437 iface->new_ioctl_nums = 1;
00438 }
00439 else if( ioctl(iface->skfd, SIOCDEVPRIVATE, &(iface->ifr))>=0 )
00440 {
00441 iface->new_ioctl_nums = 0;
00442 }
00443 else
00444 {
00445 HAL_ERROR(("SIOCGMIIPHY on %s failed: %s\n", iface->ifr.ifr_name,
00446 strerror(errno)));
00447 (void) close(iface->skfd);
00448 free(iface);
00449 return;
00450 }
00451
00452 iface->status_word_baseline = 0x5555;
00453
00454
00455 link_detection_process(iface);
00456
00457 iface->next = link_detection_list_head;
00458 link_detection_list_head = iface;
00459 }
00460
00464 static void link_detection_remove(HalDevice* device)
00465 {
00466 link_detection_if* iface;
00467 link_detection_if* iface_prev = NULL;
00468
00469 for(iface=link_detection_list_head; iface!=NULL; iface=iface->next)
00470 {
00471 if( iface->device==device )
00472 {
00473
00474 HAL_INFO(("Stopping ethernet link monitoring on device %s",
00475 device->udi));
00476
00477 if( iface_prev!=NULL )
00478 {
00479 iface_prev->next = iface->next;
00480 }
00481 else
00482 {
00483 link_detection_list_head = iface->next;
00484 }
00485
00486 close(iface->skfd);
00487 free(iface);
00488 }
00489
00490 iface_prev = iface;
00491 }
00492 }
00493
00494
00502 static void new_capability(HalDevice* device, const char* capability,
00503 dbus_bool_t in_gdl)
00504 {
00505 if( in_gdl )
00506 {
00507 if( strcmp(capability, "net.ethernet")==0 )
00508 {
00509 link_detection_add(device);
00510 }
00511 }
00512 }
00513
00519 static void gdl_changed(HalDevice* device, dbus_bool_t is_added)
00520 {
00521 if( is_added )
00522 {
00523 if( ds_query_capability(device, "net.ethernet") )
00524 {
00525 link_detection_add(device);
00526 }
00527 }
00528 else
00529 {
00530
00531
00532
00533 link_detection_remove(device);
00534 }
00535 }
00536
00537
00538
00539
00543 void linux_class_net_init()
00544 {
00545 g_timeout_add(1000, link_detection_timer_handler, NULL);
00546
00547
00548 ds_add_cb_newcap(new_capability);
00549 ds_add_cb_gdl_changed(gdl_changed);
00550 }
00551
00556 void linux_class_net_detection_done()
00557 {
00558 }
00559
00563 void linux_class_net_shutdown()
00564 {
00565 }
00566