1/* 2 * LICENSE NOTICE. 3 * 4 * Use of the Microsoft Windows Rally Development Kit is covered under 5 * the Microsoft Windows Rally Development Kit License Agreement, 6 * which is provided within the Microsoft Windows Rally Development 7 * Kit or at http://www.microsoft.com/whdc/rally/rallykit.mspx. If you 8 * want a license from Microsoft to use the software in the Microsoft 9 * Windows Rally Development Kit, you must (1) complete the designated 10 * "licensee" information in the Windows Rally Development Kit License 11 * Agreement, and (2) sign and return the Agreement AS IS to Microsoft 12 * at the address provided in the Agreement. 13 */ 14 15/* 16 * Copyright (c) Microsoft Corporation 2005. All rights reserved. 17 * This software is provided with NO WARRANTY. 18 */ 19 20#include <stdio.h> 21#include <ctype.h> 22#include <sys/socket.h> 23#include <features.h> 24#include <netpacket/packet.h> 25#include <net/ethernet.h> 26#include <net/if_arp.h> 27#include <sys/ioctl.h> 28#include <sys/types.h> 29#include <sys/stat.h> 30#include <fcntl.h> 31#include <netinet/in.h> 32#include <signal.h> 33 34/* We use the POSIX.1e capability subsystem to drop all but 35 * CAP_NET_ADMIN rights */ 36//#define HAVE_CAPABILITIES 37#ifdef HAVE_CAPABILITIES 38# include <sys/capability.h> 39#endif 40 41/* Do you have wireless extensions available? (most modern kernels do) */ 42#define HAVE_WIRELESS 43 44#ifdef HAVE_WIRELESS 45 /* for get access-point address (BSSID) and infrastructure mode */ 46# include <linux/wireless.h> 47#else /* ! HAVE_WIRELESS */ 48 /* still want struct ifreq and friends */ 49# include <net/if.h> 50#endif /* ! HAVE_WIRELESS */ 51 52 53/* for uname: */ 54#include <sys/utsname.h> 55 56#include <stdlib.h> 57#include <unistd.h> 58 59#include <string.h> 60#include <errno.h> 61 62#include "globals.h" 63 64#include "packetio.h" 65 66/* helper functions */ 67 68/* Convert from name "interface" to its index, or die on error. */ 69static int 70if_get_index(int sock, char *interface) 71{ 72 struct ifreq req; 73 int ret; 74 75 memset(&req, 0, sizeof(req)); 76 strncpy(req.ifr_name, interface, sizeof(req.ifr_name)); 77 ret = ioctl(sock, SIOCGIFINDEX, &req); 78 if (ret != 0) 79 die("if_get_index: for interface %s: %s\n", 80 interface, strerror(errno)); 81 82 return req.ifr_ifindex; 83} 84 85 86osl_t * 87osl_init(void) 88{ 89 osl_t *osl; 90 91 osl = xmalloc(sizeof(*osl)); 92 osl->sock = -1; 93 osl->arpsock = -1; 94 osl->arp_enabled = FALSE; 95 return osl; 96} 97 98 99 100/* pidfile maintenance: this is not locking (there's plenty of scope 101 * for races here!) but it should stop most accidental runs of two 102 * lld2d instances on the same interface. We open the pidfile for 103 * read: if it exists and the named pid is running we abort ourselves. 104 * Otherwise we reopen the pidfile for write and log our pid to it. */ 105void 106osl_write_pidfile(osl_t *osl) 107{ 108 char pidfile[80]; 109 char pidbuf[16]; 110 int fd; 111 int ret; 112 113 snprintf(pidfile, sizeof(pidfile), "/var/run/lld2d-ct-%.10s.pid", osl->interface); 114 fd = open(pidfile, O_RDONLY); 115 if (fd < 0) 116 { 117 if (errno != ENOENT) 118 die("osl_write_pidfile: opening pidfile %s for read: %s\n", 119 pidfile, strerror(errno)); 120 /* ENOENT is good: the pidfile doesn't exist */ 121 } 122 else 123 { 124 /* the pidfile exists: read it and check whether the named pid 125 is still around */ 126 int pid; 127 char *end; 128 129 ret = read(fd, pidbuf, sizeof(pidbuf)); 130 if (ret < 0) 131 die("osl_write_pidfile: read of pre-existing %s failed: %s\n", 132 pidfile, strerror(errno)); 133 pid = strtol(pidbuf, &end, 10); 134 if (*end != '\0' && *end != '\n') 135 die("osl_write_pidfile: couldn't parse \"%s\" as a pid (from file %s); " 136 "aborting\n", pidbuf, pidfile); 137 ret = kill(pid, 0); /* try sending signal 0 to the pid to check it exists */ 138 if (ret == 0) 139 die("osl_write_pidfile: %s contains pid %d which is still running; aborting\n", 140 pidfile, pid); 141 /* pid doesn't exist, looks like we can proceed */ 142 close(fd); 143 } 144 145 /* re-open pidfile for write, possibly creating it */ 146 fd = open(pidfile, O_WRONLY|O_CREAT|O_TRUNC, 0644); 147 if (fd < 0) 148 die("osl_write_pidfile: open %s for write/create: %s\n", pidfile, strerror(errno)); 149 snprintf(pidbuf, sizeof(pidbuf), "%d\n", getpid()); 150 ret = write(fd, pidbuf, strlen(pidbuf)); 151 if (ret < 0) 152 die("osl_write_pidfile: writing my PID to lockfile %s: %s\n", 153 pidfile, strerror(errno)); 154 close(fd); 155} 156 157 158/* Open "interface", and add packetio_recv_handler(state) as the IO 159 * event handler for its packets (or die on failure). If possible, 160 * the OSL should try to set the OS to filter packets so just frames 161 * with ethertype == topology protocol are received, but if not the 162 * packetio_recv_handler will filter appropriately, so providing more 163 * frames than necessary is safe. */ 164void 165osl_interface_open(osl_t *osl, char *interface, void *state) 166{ 167 struct sockaddr_ll addr; 168 int ret; 169 170 osl->sock = socket(PF_PACKET, SOCK_RAW, TOPO_ETHERTYPE); 171 if (osl->sock < 0) 172 die("osl_interface_open: open %s failed: %s\n", 173 interface, strerror(errno)); 174 175 osl->interface = interface; 176 177 /* perhaps check interface flags indicate it is up? */ 178 179 /* set filter to only topology frames on this one interface */ 180 memset(&addr, 0, sizeof(addr)); 181 addr.sll_family = AF_PACKET; 182 addr.sll_protocol = TOPO_ETHERTYPE; 183 addr.sll_ifindex = if_get_index(osl->sock, interface); 184 DEBUG({printf("binding raw socket (index= %d, fd=%d) on %s to TOPO_ETHERTYPE\n", addr.sll_ifindex, osl->sock, osl->interface);}) 185 ret = bind(osl->sock, (struct sockaddr*)&addr, sizeof(addr)); 186 if (ret != 0) 187 die("osl_interface_open: binding to interface %s (index %d): %s\n", 188 osl->interface, addr.sll_ifindex, strerror(errno)); 189 190 event_add_io(osl->sock, packetio_recv_handler, state); 191 192 /* create the ARP socket here too, while we still have enough rights */ 193 osl->arpsock = socket(PF_PACKET, SOCK_RAW, TOPO_ARP_ETHERTYPE); 194 if (osl->arpsock < 0) 195 die("osl_interface_open: open ARP socket on %s failed: %s\n", 196 osl->interface, strerror(errno)); 197} 198 199 200/* Permanently drop elevated privilleges. */ 201/* Actually, drop all but CAP_NET_ADMIN rights, so we can still enable 202 * and disable promiscuous mode, and listen to ARPs. */ 203void 204osl_drop_privs(osl_t *osl) 205{ 206#ifdef HAVE_CAPABILITIES 207 cap_t caps = cap_init(); 208 cap_value_t netadmin[] = {CAP_NET_ADMIN}; 209 210 if (!caps) 211 die("osl_drop_privs: cap_init failed: %s\n", strerror(errno)); 212 if (cap_set_flag(caps, CAP_PERMITTED, 1, netadmin, CAP_SET) < 0) 213 die("osl_drop_privs: cap_set_flag (permitted) %s\n", strerror(errno)); 214 if (cap_set_flag(caps, CAP_EFFECTIVE, 1, netadmin, CAP_SET) < 0) 215 die("osl_drop_privs: cap_set_flag (effective): %s\n", strerror(errno)); 216 if (cap_set_proc(caps) < 0) 217 die("osl_drop_privs: cap_set_proc: %s\n", strerror(errno)); 218 cap_free(caps); 219#endif 220} 221 222 223/* Turn promiscuous mode on or off */ 224void 225osl_set_promisc(osl_t *osl, bool_t promisc) 226{ 227 struct ifreq req; 228 int ret=0; 229 230 /* we query to get the previous state of the flags so as not to 231 * change any others by accident */ 232 memset(&req, 0, sizeof(req)); 233 strncpy(req.ifr_name, osl->interface, sizeof(req.ifr_name)-1); 234 ret = ioctl(osl->sock, SIOCGIFFLAGS, &req); 235 if (ret != 0) 236 die("osl_set_promisc: couldn't get interface flags for %s: %s\n", 237 osl->interface, strerror(errno)); 238 239 /* now clear (and optionally set) the IFF_PROMISC bit */ 240 req.ifr_flags &= ~IFF_PROMISC; 241 if (promisc) 242 req.ifr_flags |= IFF_PROMISC; 243 244 ret = ioctl(osl->sock, SIOCSIFFLAGS, &req); 245 if (ret != 0) 246 die("osl_set_promisc: couldn't set interface flags for %s: %s\n", 247 osl->interface, strerror(errno)); 248} 249 250 251 252/* Return the Ethernet address for "interface", or FALSE on error. */ 253static bool_t 254get_hwaddr(const char *interface, /*OUT*/ etheraddr_t *addr, 255 bool_t expect_ethernet) 256{ 257 int rqfd; 258 struct ifreq req; 259 int ret; 260 261 memset(&req, 0, sizeof(req)); 262 strncpy(req.ifr_name, interface, sizeof(req.ifr_name)); 263 rqfd = socket(AF_INET,SOCK_DGRAM,0); 264 if (rqfd<0) 265 { 266 warn("get_hwaddr: FAILED creating request socket for \'%s\' : %s\n",interface,strerror(errno)); 267 return FALSE; 268 } 269 ret = ioctl(rqfd, SIOCGIFHWADDR, &req); 270 if (ret < 0) 271 { 272 warn("get_hwaddr(%d,%s): FAILED : %s\n", rqfd, interface, strerror(errno)); 273 return FALSE; 274 } 275 close(rqfd); 276 if (req.ifr_hwaddr.sa_family != ARPHRD_ETHER) 277 { 278 if (expect_ethernet) 279 warn("get_hwaddr: was expecting addr type to be Ether, not type %d\n", 280 req.ifr_hwaddr.sa_family); 281 return FALSE; 282 } 283 284 memcpy(addr, req.ifr_hwaddr.sa_data, sizeof(*addr)); 285 return TRUE; 286} 287 288/* Return the Ethernet address for socket "sock", or die. */ 289void 290osl_get_hwaddr(osl_t *osl, /*OUT*/ etheraddr_t *addr) 291{ 292 if (!get_hwaddr(osl->interface, addr, TRUE)) 293 die("osl_get_hw_addr: expected an ethernet address on our interface\n"); 294} 295 296 297ssize_t 298osl_read(int fd, void *buf, size_t count) 299{ 300 return read(fd, buf, count); 301} 302 303ssize_t 304osl_write(osl_t *osl, const void *buf, size_t count) 305{ 306 return write(osl->sock, buf, count); 307} 308 309 310 311/* TRUE if x is less than y (lexographically) */ 312static bool_t 313etheraddr_lt(const etheraddr_t *x, const etheraddr_t *y) 314{ 315 int i; 316 317 for (i=0; i<6; i++) 318 { 319 if (x->a[i] > y->a[i]) 320 return FALSE; 321 else if (x->a[i] < y->a[i]) 322 return TRUE; 323 } 324 325 return FALSE; /* they're equal */ 326} 327 328/* Find hardware address of "interface" and if it's lower than 329 * "lowest", update lowest. */ 330static void 331pick_lowest_address(const char *interface, void *state) 332{ 333 etheraddr_t *lowest = state; 334 etheraddr_t candidate; 335 336 /* query the interface's hardware address */ 337 if (!get_hwaddr(interface, &candidate, FALSE)) 338 return; /* failure; just ignore (maybe it's not an Ethernet NIC, eg loopback) */ 339 340 if (etheraddr_lt(&candidate, lowest)) 341 *lowest = candidate; 342 343 uint8_t *bytes = (uint8_t*)state; 344} 345 346typedef void (*foreach_interface_fn)(const char *interface, void *state); 347 348/* enumerate all interfaces on this host via /proc/net/dev */ 349char buf[160]; 350static bool_t 351foreach_interface(foreach_interface_fn fn, void *state) 352{ 353 char *p, *colon, *name; 354 FILE *netdev; 355 356/* Note: When I dropped this on the WRT54GS version 4, the following fopen() hung the box... who knows why? */ 357/* the workaround involves keeping the descriptor open from before the first select in the event loop. */ 358 359#if CAN_FOPEN_IN_SELECT_LOOP 360 netdev = fopen("/proc/net/dev", "r"); 361#else 362 netdev = g_procnetdev; 363#endif 364 if (!netdev) 365 { 366 warn("foreach_interface: open(\"/proc/net/dev\") for read failed: %s; " 367 "not able to determine hostId, so no support for multiple NICs.\n", 368 strerror(errno)); 369 return FALSE; 370 } 371 372 /* skip first 2 lines (header) */ 373 fgets(buf, sizeof(buf), netdev); 374 fgets(buf, sizeof(buf), netdev); 375 376 /* interface name is non-whitespace up to the colon (but a colon 377 * might be part of a virtual interface eg eth0:0 */ 378 while (fgets(buf, sizeof(buf), netdev)) 379 { 380 name = buf; 381 while (isspace(*name)) 382 name++; 383 colon = strchr(name, ':'); 384 if (!colon) 385 { 386 warn("foreach_interface: parse error reading /proc/net/dev: missing colon\n"); 387 fclose(netdev); 388 return FALSE; 389 } 390 391 /* see if there's an optional ":DIGITS" virtual interface here */ 392 p = colon+1; 393 while (isdigit(*p)) 394 p++; 395 if (*p == ':') 396 *p = '\0'; /* virtual interface name */ 397 else 398 *colon = '\0'; /* normal interface name */ 399 400 fn(name, state); 401 } 402 403 if (ferror(netdev)) 404 { 405 warn("foreach_interface: error during reading of /proc/net/dev\n"); 406 fclose(netdev); 407 return FALSE; 408 } 409 410#if CAN_FOPEN_IN_SELECT_LOOP 411 fclose(netdev); 412#endif 413 return TRUE; 414} 415 416 417/* Recipe from section 1.7 of the Unix Programming FAQ */ 418/* http://www.erlenstar.demon.co.uk/unix/faq_toc.html */ 419void 420osl_become_daemon(osl_t *osl) 421{ 422 /* 1) fork */ 423 pid_t pid = fork(); 424 if (pid == -1) 425 die("osl_become_daemon: fork to drop process group leadership failed: %s\n", 426 strerror(errno)); 427 if (pid != 0) 428 exit(0); /* parent exits; child continues */ 429 430 /* we are now guaranteed not to be a process group leader */ 431 432 /* 2) setsid() */ 433 pid = setsid(); 434 if (pid == -1) 435 die("osl_become_daemon: setsid failed?!: %s\n", strerror(errno)); 436 437 /* we are now the new group leader, and have successfully 438 * jettisonned our controlling terminal - hooray! */ 439 440 /* 3) fork again */ 441 pid = fork(); 442 if (pid == -1) 443 die("osl_become_daemon: fork to lose group leadership (again) failed: %s\n", 444 strerror(errno)); 445 if (pid != 0) 446 exit(0); /* parent exits; child continues */ 447 448 /* we now have no controlling terminal, and are not a group leader 449 (and thus have no way of acquiring a controlling terminal). */ 450 451 /* 4) chdir("/") */ 452 if (chdir("/") != 0) 453 die("osl_become_daemon: chdir(\"/\") failed: %s\n", strerror(errno)); 454 /* this allows admins to umount filesystems etc since we're not 455 * keeping them busy.*/ 456 457 /* 5) umask(0) */ 458 umask(0); /* if we create any files, we specify full mode bits */ 459 460 /* 6) close fds */ 461 462 /* 7) re-establish stdin/out/err to logfiles or /dev/console as needed */ 463} 464 465 466/********************** T L V _ G E T _ F N s ******************************/ 467 468/* Return a 6-byte identifier which will be unique and consistent for 469 * this host, across all of its interfaces. Here we enumerate all the 470 * interfaces that are up and have assigned Ethernet addresses, and 471 * pick the lowest of them to represent this host. */ 472int 473get_hostid(void *data) 474{ 475/* TLVDEF( etheraddr_t, hostid, , 1, Access_unset ) */ 476 477 etheraddr_t *hid = (etheraddr_t*) data; 478 479 *hid = Etheraddr_broadcast; 480 481 if (!foreach_interface(pick_lowest_address, hid)) 482 { 483 if (TRACE(TRC_TLVINFO)) 484 dbgprintf("get_hostid(): FAILED picking lowest address.\n"); 485 return TLV_GET_FAILED; 486 } 487 if (ETHERADDR_EQUALS(hid, &Etheraddr_broadcast)) 488 { 489 if (TRACE(TRC_TLVINFO)) 490 dbgprintf("get_hostid(): FAILED, because chosen hostid = broadcast address\n"); 491 return TLV_GET_FAILED; 492 } else { 493 if (TRACE(TRC_TLVINFO)) 494 dbgprintf("get_hostid: hostid=" ETHERADDR_FMT "\n", ETHERADDR_PRINT(hid)); 495 return TLV_GET_SUCCEEDED; 496 } 497} 498 499 500int 501get_net_flags(void *data) 502{ 503/* TLVDEF( uint32_t, net_flags, , 2, Access_unset ) */ 504 505 uint32_t* nf = (uint32_t*) data; 506 507#define fLP 0x08000000 // Looping back outbound packets, if set 508#define fMW 0x10000000 // Has management web page accessible via HTTP, if set 509#define fFD 0x20000000 // Full Duplex if set 510#define fNX 0x40000000 // NAT private-side if set 511#define fNP 0x80000000 // NAT public-side if set 512 513 /* If your device has a management page at the url 514 http://<device-ip-address>/ 515 then use the fMW flag, otherwise, remove it */ 516 *nf = htonl(fFD | fNX | fMW); 517 518 return TLV_GET_SUCCEEDED; 519} 520 521 522int 523get_physical_medium(void *data) 524{ 525/* TLVDEF( uint32_t, physical_medium, , 3, Access_unset ) */ 526 527 uint32_t* pm = (uint32_t*) data; 528 529 /* Since this interface is bridged, we should actually return two responses, 530 * one for the wireless, and one for the ethernet switch. It's probably OK to 531 * just say "ethernet" though... */ 532//!! *pm = htonl(71); // "wireless" 533 *pm = htonl(6); // "ethernet" 534 535 536 return TLV_GET_SUCCEEDED; 537} 538 539/* Note that most of the code in this block is not pertinent to the WRT, and has not been tested. In particular, 540 * there may be many cases of network byte order not being observed.... */ 541 542#ifdef HAVE_WIRELESS 543 544/* Return TRUE on successful query, setting "wireless_mode" to: 545 * 0 = ad-hoc mode 546 * 1 = infrastructure mode ie ESS (Extended Service Set) mode 547 * 2 = auto/unknown (device may auto-switch between ad-hoc and infrastructure modes) 548 */ 549int 550get_wireless_mode(void *data) 551{ 552/* TLVDEF( uint32_t, wireless_mode, , 4, Access_unset ) */ 553 554 uint32_t* wl_mode = (uint32_t*) data; 555 556 int rqfd; 557 struct iwreq req; 558 int ret; 559 560 memset(&req, 0, sizeof(req)); 561 strncpy(req.ifr_ifrn.ifrn_name, g_osl->interface, sizeof(req.ifr_ifrn.ifrn_name)); 562//*/printf("get_wireless_mode: requesting addr for interface \'%s\'\n",g_osl->interface); 563 rqfd = socket(AF_INET,SOCK_DGRAM,0); 564 if (rqfd<0) 565 { 566 warn("get_wireless_mode: FAILED creating request socket for \'%s\' : %s\n",g_osl->interface,strerror(errno)); 567 return FALSE; 568 } 569 ret = ioctl(rqfd, SIOCGIWMODE, &req); 570 close(rqfd); 571 if (ret != 0) 572 { 573 /* We don't whine about "Operation Not Supported" since that 574 * just means the interface does not have wireless extensions. */ 575 if (errno != EOPNOTSUPP) 576 warn("get_wireless_mode: get associated Access Point MAC failed: %s\n", 577 strerror(errno)); 578 return TLV_GET_FAILED; 579 } 580 581 switch (req.u.mode) { 582 case IW_MODE_AUTO: 583 *wl_mode = 2; 584 break; 585 586 case IW_MODE_ADHOC: 587 *wl_mode = 0; 588 break; 589 590 case IW_MODE_INFRA: 591 *wl_mode = 1; 592 break; 593 594 default: 595 /* this is a pretty complex wireless device (probably acting 596 * as an AP); we can't express its features just like this, so 597 * we'll not return a wireless mode TLV. */ 598 IF_TRACED(TRC_TLVINFO) 599 printf("get_wireless_mode(): mode (%d) unrecognizable - FAILING the get...\n", req.u.mode); 600 END_TRACE 601 return TLV_GET_FAILED; 602 } 603 IF_TRACED(TRC_TLVINFO) 604 printf("get_wireless_mode(): wireless_mode=%d\n", *wl_mode); 605 END_TRACE 606 607 return TLV_GET_SUCCEEDED; 608} 609 610 611/* If the interface is 802.11 wireless in infrastructure mode, and it 612 * has successfully associated to an AP (Access Point) then it will 613 * have a BSSID (Basic Service Set Identifier), which is usually the 614 * AP's MAC address. 615 * Of course, this code resides in an AP, so this is actually quite 616 * meaningless. */ 617int 618get_bssid(void *data) 619{ 620/* TLVDEF( etheraddr_t, bssid, , 5, Access_unset ) */ 621 622#ifdef NOT_ACCESSPOINT 623 etheraddr_t* bssid = (etheraddr_t*) data; 624 625 struct iwreq req; 626 int ret; 627 628 memset(&req, 0, sizeof(req)); 629 strncpy(req.ifr_ifrn.ifrn_name, g_osl->interface, sizeof(req.ifr_ifrn.ifrn_name)); 630 ret = ioctl(g_osl->sock, SIOCGIWAP, &req); 631 if (ret != 0) 632 { 633 /* We don't whine about "Operation Not Supported" since that 634 * just means the interface does not have wireless extensions. */ 635 if (errno != EOPNOTSUPP) 636 warn("get_bssid: get associated Access Point MAC failed: %s\n", 637 strerror(errno)); 638 return TLV_GET_FAILED; 639 } 640 641 if (req.u.ap_addr.sa_family != ARPHRD_ETHER) 642 { 643 warn("get_bssid: expecting Ethernet address back, not sa_family=%d\n", 644 req.u.ap_addr.sa_family); 645 return TLV_GET_FAILED; 646 } 647 648 memcpy(bssid, req.u.ap_addr.sa_data, sizeof(etheraddr_t)); 649 650 IF_TRACED(TRC_TLVINFO) 651 printf("get_bssid(): bssid=" ETHERADDR_FMT "\n", ETHERADDR_PRINT(bssid)); 652 END_TRACE 653 654 return TLV_GET_SUCCEEDED; 655#else 656 return TLV_GET_FAILED; // This is an AP - no associated BSSID // 657#endif 658} 659 660 661int 662get_ssid(void *data) 663{ 664/* TLVDEF( ssid_t, ssid, , 6, Access_unset ) */ 665 666// ssid_t* ssid = (ssid_t*) data; 667 668 return TLV_GET_FAILED; 669} 670 671#endif /* HAVE_WIRELESS */ 672 673 674int 675get_ipv4addr(void *data) 676{ 677/* TLVDEF( ipv4addr_t, ipv4addr, , 7, Access_unset ) */ 678 679 int rqfd, ret; 680 struct ifreq req; 681 ipv4addr_t* ipv4addr = (ipv4addr_t*) data; 682 char dflt_if[] = {"br0"}; 683 char *interface = g_interface; 684 685 if (interface == NULL) interface = dflt_if; 686 memset(&req, 0, sizeof(req)); 687 strncpy(req.ifr_name, interface, sizeof(req.ifr_name)); 688 rqfd = socket(AF_INET,SOCK_DGRAM,0); 689 if (rqfd<0) 690 { 691 warn("get_ipv4addr: FAILED creating request socket for \'%s\' : %s\n",interface,strerror(errno)); 692 return TLV_GET_FAILED; 693 } 694 ret = ioctl(rqfd, SIOCGIFADDR, &req); 695 if (ret < 0) 696 { 697 warn("get_ipv4addr(%d,%s): FAILED : %s\n", rqfd, interface, strerror(errno)); 698 return TLV_GET_FAILED; 699 } 700 close(rqfd); 701 IF_DEBUG 702 /* Interestingly, the ioctl to get the ipv4 address returns that 703 address offset by 2 bytes into the buf. Leaving this in case 704 one of the ports results in a different offset... */ 705 unsigned char *d; 706 d = (unsigned char*)req.ifr_addr.sa_data; 707 /* Dump out the whole 14-byte buffer */ 708 printf("get_ipv4addr: sa_data = 0x%02x-0x%02x-0x%02x-0x%02x-0x%02x-0x%02x-0x%02x-0x%02x-0x%02x-0x%02x-0x%02x-0x%02x-0x%02x-0x%02x\n",d[0],d[1],d[2],d[3],d[4],d[5],d[6],d[7],d[8],d[9],d[10],d[11],d[12],d[13]); 709 END_DEBUG 710 711 memcpy(ipv4addr,&req.ifr_addr.sa_data[2],sizeof(uint32_t)); 712 IF_DEBUG 713 printf("get_ipv4addr: returning %d.%d.%d.%d as ipv4addr\n", \ 714 *((uint8_t*)ipv4addr),*((uint8_t*)ipv4addr +1), \ 715 *((uint8_t*)ipv4addr +2),*((uint8_t*)ipv4addr +3)); 716 END_DEBUG 717 718 return TLV_GET_SUCCEEDED; 719} 720 721 722int 723get_ipv6addr(void *data) 724{ 725/* TLVDEF( ipv6addr_t, ipv6addr, , 8, Access_unset ) */ 726 727 ipv6addr_t* ipv6addr = (ipv6addr_t*) data; 728 729 return TLV_GET_FAILED; 730} 731 732 733int 734get_max_op_rate(void *data) 735{ 736/* TLVDEF( uint16_t, max_op_rate, , 9, Access_unset ) units of 0.5 Mbs */ 737 738 uint16_t* morate = (uint16_t*) data; 739 740 *morate = htons(108); /* 54 Mbs / 0.5 Mbs = 108 */ 741 742 return TLV_GET_SUCCEEDED; 743} 744 745 746int 747get_tsc_ticks_per_sec(void *data) 748{ 749/* TLVDEF( uint64_t, tsc_ticks_per_sec, , 0xA, Access_unset ) */ 750 751 uint64_t ticks; 752 uint8_t *srcticks = (uint8_t*)(&ticks) + sizeof(uint64_t) - 1; 753 uint8_t *dstticks = (uint8_t*) data; 754 755 int i; 756 757 ticks = (uint64_t) 0x999e36LL; // 10M (100ns) ticks - YMMV 758 759 /* do our own htonll() here.... */ 760 for (i=0; i<sizeof(uint64_t); i++) *dstticks++ = *srcticks--; 761 762 return TLV_GET_SUCCEEDED; 763} 764 765 766int 767get_link_speed(void *data) 768{ 769/* TLVDEF( uint32_t, link_speed, , 0xC, Access_unset ) // 100bps increments */ 770 771 uint32_t* speed = (uint32_t*) data; 772 773 /* Since this is a bridged pair of interfaces (br0 = eth1 + wl0), I am returning the 774 * wireless speed, which is the lowest of the upper limits on the two interfaces... */ 775 776 *speed = htonl(540000); // 54Mbit wireless... (540k x 100 = 54Mbs) 777 778 return TLV_GET_SUCCEEDED; 779} 780 781 782/* Unless this box is used as a wireless client, RSSI is meaningless - which client should be measured? */ 783int 784get_rssi(void *data) 785{ 786/* TLVDEF( uint32_t, rssi, , 0xD, Access_unset ) */ 787 788 uint32_t* rssi = (uint32_t*) data; 789 790 return TLV_GET_FAILED; 791} 792 793 794int 795get_icon_image(void *data) 796{ 797/* TLVDEF( icon_file_t, icon_image, , 0xE ) // Usually LTLV style (Windows .ico file > 1k long) */ 798 799 icon_file_t* icon = (icon_file_t*) data; 800 int fd; 801 802 /* The configuration file (lld2d.conf, in /etc) may have specified an icon file, which will be sent as 803 * a TLV if it is smaller than the lesser of 1k and whatever space is left in the send-buffer... Such a 804 * determination will be made at the time of the write, tho.... 805 * 806 * In main.c, we read the config file, and established a value for the iconfile_path in "g_icon_path". 807 * This path-value ( a char* ) MAY be NULL, if no path was configured correctly. 808 * Here, we test that path, opening a file descriptor if it exists, and save its size for the writer-routine. */ 809 810 /* Close any still-open fd to a previously "gotten" iconfile */ 811 if (icon->fd_icon != -1 && icon->sz_iconfile != 0) 812 close(icon->fd_icon); 813 814 /* set defaults */ 815 icon->sz_iconfile = 0; 816 icon->fd_icon = -1; 817 818 if (g_icon_path == NULL || g_icon_path[0] == 0) 819 { 820 return TLV_GET_FAILED; // No iconfile was correctly declared. This may NOT be an error! 821 } 822 823 fd = open(g_icon_path, O_RDONLY); 824 if (fd < 0) 825 { 826 warn("get_icon_image: reading iconfile %s FAILED : %s\n", 827 g_icon_path, strerror(errno)); 828 return TLV_GET_FAILED; 829 } else { 830 /* size the file, for the writer to determine if it needs to force an LTLV */ 831 struct stat filestats; 832 int statstat; 833 834 statstat = fstat( fd, &filestats ); 835 if (statstat < 0) 836 { 837 warn("get_icon_image: stat-ing iconfile %s FAILED : %s\n", 838 g_icon_path, strerror(errno)); 839 return TLV_GET_FAILED; 840 } else { 841 /* Finally! SUCCESS! */ 842 icon->sz_iconfile = filestats.st_size; 843 icon->fd_icon = fd; 844 IF_TRACED(TRC_TLVINFO) 845 printf("get_icon_image: stat\'ing iconfile %s returned length=%d\n",g_icon_path, icon->sz_iconfile); 846 END_TRACE 847 } 848 } 849 return TLV_GET_SUCCEEDED; 850} 851 852 853int 854get_machine_name(void *data) 855{ 856/* TLVDEF( ucs2char_t, machine_name, [16], 0xF, Access_unset ) */ 857 858 ucs2char_t* name = (ucs2char_t*) data; 859 860 int ret; 861 struct utsname unamebuf; 862 863 /* use uname() to get the system's hostname */ 864 ret = uname(&unamebuf); 865 if (ret != -1) 866 { 867 /* nuke any '.' in what should be a nodename, not a FQDN */ 868 char *p = strchr(unamebuf.nodename, '.'); 869 if (p) 870 *p = '\0'; 871 872 size_t namelen = strlen(unamebuf.nodename); 873 874 /* because I am a fool, and can't remember how to refer to the sizeof a structure 875 * element directly, there is an unnecessary declaration here... */ 876 tlv_info_t* fool; 877 util_copy_ascii_to_ucs2(name, sizeof(fool->machine_name), unamebuf.nodename); 878 IF_TRACED(TRC_TLVINFO) 879 dbgprintf("get_machine_name(): space= %d, len=%d, machine name = %s\n", 880 sizeof(fool->machine_name), namelen, unamebuf.nodename); 881 END_TRACE 882 return TLV_GET_SUCCEEDED; 883 } 884 885 IF_TRACED(TRC_TLVINFO) 886 dbgprintf("get_machine_name(): uname() FAILED, returning %d\n", ret); 887 END_TRACE 888 889 return TLV_GET_FAILED; 890} 891 892 893int 894get_support_info(void *data) 895{ 896/* TLVDEF( ucs2char_t, support_info, [32], 0x10, Access_unset ) // RLS: was "contact_info" */ 897 898 ucs2char_t * support = (ucs2char_t*) data; 899 900 return TLV_GET_FAILED; 901} 902 903 904int 905get_friendly_name(void *data) 906{ 907/* TLVDEF( ucs2char_t, friendly_name, [32], 0x11, Access_unset ) */ 908 909 ucs2char_t * fname = (ucs2char_t*) data; 910 911 return TLV_GET_FAILED; 912} 913 914 915int 916get_upnp_uuid(void *data) 917{ 918/* TLVDEF( uuid_t, upnp_uuid, , 0x12, Access_unset ) // 16 bytes long */ 919 920// uuid_t* uuid = (uuid_t*) data; 921 922 return TLV_GET_FAILED; 923} 924 925 926int 927get_hw_id(void *data) 928{ 929/* TLVDEF( ucs2char_t, hw_id, [200], 0x13, Access_unset ) // 400 bytes long, max */ 930 931 ucs2char_t * hwid = (ucs2char_t*) data; 932 933 return TLV_GET_FAILED; 934} 935 936 937int 938get_qos_flags(void *data) 939{ 940/* TLVDEF( uint32_t, qos_flags, , 0x14, Access_unset ) */ 941 942 int32_t* qosf = (int32_t*) data; 943 944#define TAG8P 0x20000000 // supports 802.1p priority tagging 945#define TAG8Q 0x40000000 // supports 802.1q VLAN tagging 946#define QW 0x80000000 // has Microsoft qWave service implemented; this is not LLTD QoS extensions 947 948 *qosf = htonl(TAG8P); 949 950 return TLV_GET_SUCCEEDED; 951} 952 953 954int 955get_wl_physical_medium(void *data) 956{ 957/* TLVDEF( uint8_t, wl_physical_medium, , 0x15, Access_unset ) */ 958 959 uint8_t* wpm = (uint8_t*) data; 960 961 return TLV_GET_FAILED; 962} 963 964 965int 966get_accesspt_assns(void *data) 967{ 968/* TLVDEF( ltlv_t, accesspt_assns, , 0x16, Access_unset ) // RLS: Large_TLV */ 969 970// ltlv_t* assns = (ltlv_t*) data; 971 972 return TLV_GET_FAILED; 973} 974