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->wireless_if = g_wl_interface; 94 return osl; 95} 96 97 98 99/* pidfile maintenance: this is not locking (there's plenty of scope 100 * for races here!) but it should stop most accidental runs of two 101 * lld2d instances on the same interface. We open the pidfile for 102 * read: if it exists and the named pid is running we abort ourselves. 103 * Otherwise we reopen the pidfile for write and log our pid to it. */ 104void 105osl_write_pidfile(osl_t *osl) 106{ 107 char pidfile[80]; 108 char pidbuf[16]; 109 int fd; 110 int ret; 111 112 snprintf(pidfile, sizeof(pidfile), "/var/run/%s-%.10s.pid", g_Progname, osl->responder_if); 113 fd = open(pidfile, O_RDONLY); 114 if (fd < 0) 115 { 116 if (errno != ENOENT) 117 die("osl_write_pidfile: opening pidfile %s for read: %s\n", 118 pidfile, strerror(errno)); 119 /* ENOENT is good: the pidfile doesn't exist */ 120 } 121 else 122 { 123 /* the pidfile exists: read it and check whether the named pid 124 is still around */ 125 int pid; 126 char *end; 127 128 ret = read(fd, pidbuf, sizeof(pidbuf)); 129 if (ret < 0) 130 die("osl_write_pidfile: read of pre-existing %s failed: %s\n", 131 pidfile, strerror(errno)); 132 pid = strtol(pidbuf, &end, 10); 133 if (*end != '\0' && *end != '\n') 134 die("osl_write_pidfile: couldn't parse \"%s\" as a pid (from file %s); " 135 "aborting\n", pidbuf, pidfile); 136 ret = kill(pid, 0); /* try sending signal 0 to the pid to check it exists */ 137 if (ret == 0) 138 die("osl_write_pidfile: %s contains pid %d which is still running; aborting\n", 139 pidfile, pid); 140 /* pid doesn't exist, looks like we can proceed */ 141 close(fd); 142 } 143 144 /* re-open pidfile for write, possibly creating it */ 145 fd = open(pidfile, O_WRONLY|O_CREAT|O_TRUNC, 0644); 146 if (fd < 0) 147 die("osl_write_pidfile: open %s for write/create: %s\n", pidfile, strerror(errno)); 148 snprintf(pidbuf, sizeof(pidbuf), "%d\n", getpid()); 149 ret = write(fd, pidbuf, strlen(pidbuf)); 150 if (ret < 0) 151 die("osl_write_pidfile: writing my PID to lockfile %s: %s\n", 152 pidfile, strerror(errno)); 153 close(fd); 154} 155 156 157/* Open "interface", and add packetio_recv_handler(state) as the IO 158 * event handler for its packets (or die on failure). If possible, 159 * the OSL should try to set the OS to filter packets so just frames 160 * with ethertype == topology protocol are received, but if not the 161 * packetio_recv_handler will filter appropriately, so providing more 162 * frames than necessary is safe. */ 163void 164osl_interface_open(osl_t *osl, char *interface, void *state) 165{ 166 struct sockaddr_ll addr; 167 int ret; 168 169 osl->sock = socket(PF_PACKET, SOCK_RAW, TOPO_ETHERTYPE); 170 if (osl->sock < 0) 171 die("osl_interface_open: open %s failed: %s\n", 172 interface, strerror(errno)); 173 174 osl->responder_if = interface; 175 176 /* perhaps check interface flags indicate it is up? */ 177 178 /* set filter to only topology frames on this one interface */ 179 memset(&addr, 0, sizeof(addr)); 180 addr.sll_family = AF_PACKET; 181 addr.sll_protocol = TOPO_ETHERTYPE; 182 addr.sll_ifindex = if_get_index(osl->sock, interface); 183 DEBUG({printf("binding raw socket (index= %d, fd=%d) on %s to TOPO_ETHERTYPE\n", addr.sll_ifindex, osl->sock, osl->responder_if);}) 184 ret = bind(osl->sock, (struct sockaddr*)&addr, sizeof(addr)); 185 if (ret != 0) 186 die("osl_interface_open: binding to interface %s (index %d): %s\n", 187 osl->responder_if, addr.sll_ifindex, strerror(errno)); 188 189 event_add_io(osl->sock, packetio_recv_handler, state); 190} 191 192 193/* Permanently drop elevated privilleges. */ 194/* Actually, drop all but CAP_NET_ADMIN rights, so we can still enable 195 * and disable promiscuous mode, and listen to ARPs. */ 196void 197osl_drop_privs(osl_t *osl) 198{ 199#ifdef HAVE_CAPABILITIES 200 cap_t caps = cap_init(); 201 cap_value_t netadmin[] = {CAP_NET_ADMIN}; 202 203 if (!caps) 204 die("osl_drop_privs: cap_init failed: %s\n", strerror(errno)); 205 if (cap_set_flag(caps, CAP_PERMITTED, 1, netadmin, CAP_SET) < 0) 206 die("osl_drop_privs: cap_set_flag (permitted) %s\n", strerror(errno)); 207 if (cap_set_flag(caps, CAP_EFFECTIVE, 1, netadmin, CAP_SET) < 0) 208 die("osl_drop_privs: cap_set_flag (effective): %s\n", strerror(errno)); 209 if (cap_set_proc(caps) < 0) 210 die("osl_drop_privs: cap_set_proc: %s\n", strerror(errno)); 211 cap_free(caps); 212#endif 213} 214 215 216/* Turn promiscuous mode on or off */ 217void 218osl_set_promisc(osl_t *osl, bool_t promisc) 219{ 220 struct ifreq req; 221 int ret=0; 222 223 /* we query to get the previous state of the flags so as not to 224 * change any others by accident */ 225 memset(&req, 0, sizeof(req)); 226 strncpy(req.ifr_name, osl->responder_if, sizeof(req.ifr_name)-1); 227 ret = ioctl(osl->sock, SIOCGIFFLAGS, &req); 228 if (ret != 0) 229 die("osl_set_promisc: couldn't get interface flags for %s: %s\n", 230 osl->responder_if, strerror(errno)); 231 232 /* now clear (and optionally set) the IFF_PROMISC bit */ 233 req.ifr_flags &= ~IFF_PROMISC; 234 if (promisc) 235 req.ifr_flags |= IFF_PROMISC; 236 237 ret = ioctl(osl->sock, SIOCSIFFLAGS, &req); 238 if (ret != 0) 239 die("osl_set_promisc: couldn't set interface flags for %s: %s\n", 240 osl->responder_if, strerror(errno)); 241} 242 243 244 245/* Return the Ethernet address for "interface", or FALSE on error. */ 246static bool_t 247get_hwaddr(const char *interface, /*OUT*/ etheraddr_t *addr, 248 bool_t expect_ethernet) 249{ 250 int rqfd; 251 struct ifreq req; 252 int ret; 253 254 memset(&req, 0, sizeof(req)); 255 strncpy(req.ifr_name, interface, sizeof(req.ifr_name)); 256 rqfd = socket(AF_INET,SOCK_DGRAM,0); 257 if (rqfd<0) 258 { 259 warn("get_hwaddr: FAILED creating request socket for \'%s\' : %s\n",interface,strerror(errno)); 260 return FALSE; 261 } 262 ret = ioctl(rqfd, SIOCGIFHWADDR, &req); 263 if (ret < 0) 264 { 265 warn("get_hwaddr(%d,%s): FAILED : %s\n", rqfd, interface, strerror(errno)); 266 return FALSE; 267 } 268 close(rqfd); 269 if (req.ifr_hwaddr.sa_family != ARPHRD_ETHER) 270 { 271 if (expect_ethernet) 272 warn("get_hwaddr: was expecting addr type to be Ether, not type %d\n", 273 req.ifr_hwaddr.sa_family); 274 return FALSE; 275 } 276 277 memcpy(addr, req.ifr_hwaddr.sa_data, sizeof(*addr)); 278 return TRUE; 279} 280 281/* Return the Ethernet address for socket "sock", or die. */ 282void 283osl_get_hwaddr(osl_t *osl, /*OUT*/ etheraddr_t *addr) 284{ 285 if (!get_hwaddr(osl->responder_if, addr, TRUE)) 286 die("osl_get_hw_addr: expected an ethernet address on our interface\n"); 287} 288 289 290ssize_t 291osl_read(int fd, void *buf, size_t count) 292{ 293 return read(fd, buf, count); 294} 295 296ssize_t 297osl_write(osl_t *osl, const void *buf, size_t count) 298{ 299 return write(osl->sock, buf, count); 300} 301 302 303 304/* TRUE if x is less than y (lexographically) */ 305static bool_t 306etheraddr_lt(const etheraddr_t *x, const etheraddr_t *y) 307{ 308 int i; 309 310 for (i=0; i<6; i++) 311 { 312 if (x->a[i] > y->a[i]) 313 return FALSE; 314 else if (x->a[i] < y->a[i]) 315 return TRUE; 316 } 317 318 return FALSE; /* they're equal */ 319} 320 321/* Find hardware address of "interface" and if it's lower than 322 * "lowest", update lowest. */ 323static void 324pick_lowest_address(const char *interface, void *state) 325{ 326 etheraddr_t *lowest = state; 327 etheraddr_t candidate; 328 329 /* query the interface's hardware address */ 330 if (!get_hwaddr(interface, &candidate, FALSE)) 331 return; /* failure; just ignore (maybe it's not an Ethernet NIC, eg loopback) */ 332 333 if (etheraddr_lt(&candidate, lowest)) 334 *lowest = candidate; 335} 336 337typedef void (*foreach_interface_fn)(const char *interface, void *state); 338 339/* enumerate all interfaces on this host via /proc/net/dev */ 340static bool_t 341foreach_interface(foreach_interface_fn fn, void *state) 342{ 343 char *p, *colon, *name; 344 FILE *netdev; 345 346/* Note: When I dropped this on the WRT54GS version 4, the following fopen() hung the box... who knows why? */ 347/* the workaround involves keeping the descriptor open from before the first select in the event loop. */ 348 349#if CAN_FOPEN_IN_SELECT_LOOP 350 netdev = fopen("/proc/net/dev", "r"); 351#else 352 netdev = g_procnetdev; 353#endif 354 if (!netdev) 355 { 356 warn("foreach_interface: open(\"/proc/net/dev\") for read failed: %s; " 357 "not able to determine hostId, so no support for multiple NICs.\n", 358 strerror(errno)); 359 return FALSE; 360 } 361 362 /* skip first 2 lines (header) */ 363 fgets(g_buf, sizeof(g_buf), netdev); 364 fgets(g_buf, sizeof(g_buf), netdev); 365 366 /* interface name is non-whitespace up to the colon (but a colon 367 * might be part of a virtual interface eg eth0:0 */ 368 while (fgets(g_buf, sizeof(g_buf), netdev)) 369 { 370 name = g_buf; 371 while (isspace(*name)) 372 name++; 373 colon = strchr(name, ':'); 374 if (!colon) 375 { 376 warn("foreach_interface: parse error reading /proc/net/dev: missing colon\n"); 377 fclose(netdev); 378 return FALSE; 379 } 380 381 /* see if there's an optional ":DIGITS" virtual interface here */ 382 p = colon+1; 383 while (isdigit(*p)) 384 p++; 385 if (*p == ':') 386 *p = '\0'; /* virtual interface name */ 387 else 388 *colon = '\0'; /* normal interface name */ 389 390 fn(name, state); 391 } 392 393 if (ferror(netdev)) 394 { 395 warn("foreach_interface: error during reading of /proc/net/dev\n"); 396 fclose(netdev); 397 return FALSE; 398 } 399 400#if CAN_FOPEN_IN_SELECT_LOOP 401 fclose(netdev); 402#endif 403 return TRUE; 404} 405 406 407/* Recipe from section 1.7 of the Unix Programming FAQ */ 408/* http://www.erlenstar.demon.co.uk/unix/faq_toc.html */ 409void 410osl_become_daemon(osl_t *osl) 411{ 412 /* 1) fork */ 413 pid_t pid = fork(); 414 if (pid == -1) 415 die("osl_become_daemon: fork to drop process group leadership failed: %s\n", 416 strerror(errno)); 417 if (pid != 0) 418 exit(0); /* parent exits; child continues */ 419 420 /* we are now guaranteed not to be a process group leader */ 421 422 /* 2) setsid() */ 423 pid = setsid(); 424 if (pid == -1) 425 die("osl_become_daemon: setsid failed?!: %s\n", strerror(errno)); 426 427 /* we are now the new group leader, and have successfully 428 * jettisonned our controlling terminal - hooray! */ 429 430 /* 3) fork again */ 431 pid = fork(); 432 if (pid == -1) 433 die("osl_become_daemon: fork to lose group leadership (again) failed: %s\n", 434 strerror(errno)); 435 if (pid != 0) 436 exit(0); /* parent exits; child continues */ 437 438 /* we now have no controlling terminal, and are not a group leader 439 (and thus have no way of acquiring a controlling terminal). */ 440 441 /* 4) chdir("/") */ 442 if (chdir("/") != 0) 443 die("osl_become_daemon: chdir(\"/\") failed: %s\n", strerror(errno)); 444 /* this allows admins to umount filesystems etc since we're not 445 * keeping them busy.*/ 446 447 /* 5) umask(0) */ 448 umask(0); /* if we create any files, we specify full mode bits */ 449 450 /* 6) close fds */ 451 452 /* 7) re-establish stdin/out/err to logfiles or /dev/console as needed */ 453} 454 455 456/************************* E X T E R N A L S f o r T L V _ G E T _ F N s ***************************/ 457#define TLVDEF(_type, _name, _repeat, _number, _access, _inHello) \ 458extern int get_ ## _name (void *data); 459#include "tlvdef.h" 460#undef TLVDEF 461 462 463/********************** T L V _ G E T _ F N s ******************************/ 464 465/* Return a 6-byte identifier which will be unique and consistent for 466 * this host, across all of its interfaces. Here we enumerate all the 467 * interfaces that are up and have assigned Ethernet addresses, and 468 * pick the lowest of them to represent this host. */ 469int 470get_hostid(void *data) 471{ 472/* TLVDEF( etheraddr_t, hostid, , 1, Access_unset ) */ 473 474 etheraddr_t *hid = (etheraddr_t*) data; 475 476 memcpy(hid,&Etheraddr_broadcast,sizeof(etheraddr_t)); 477 478 if (!foreach_interface(pick_lowest_address, hid)) 479 { 480 if (TRACE(TRC_TLVINFO)) 481 dbgprintf("get_hostid(): FAILED picking lowest address.\n"); 482 return TLV_GET_FAILED; 483 } 484 if (ETHERADDR_EQUALS(hid, &Etheraddr_broadcast)) 485 { 486 if (TRACE(TRC_TLVINFO)) 487 dbgprintf("get_hostid(): FAILED, because chosen hostid = broadcast address\n"); 488 return TLV_GET_FAILED; 489 } else { 490 if (TRACE(TRC_TLVINFO)) 491 dbgprintf("get_hostid: hostid=" ETHERADDR_FMT "\n", ETHERADDR_PRINT(hid)); 492 return TLV_GET_SUCCEEDED; 493 } 494} 495 496 497int 498get_net_flags(void *data) 499{ 500/* TLVDEF( uint32_t, net_flags, , 2, Access_unset ) */ 501 502 uint32_t nf; 503 504#define fLP 0x08000000 // Looping back outbound packets, if set 505#define fMW 0x10000000 // Has management web page accessible via HTTP, if set 506#define fFD 0x20000000 // Full Duplex if set 507#define fNX 0x40000000 // NAT private-side if set 508#define fNP 0x80000000 // NAT public-side if set 509 510 /* If your device has a management page at the url 511 http://<device-ip-address>/ 512 then use the fMW flag, otherwise, remove it */ 513 nf = htonl(fFD | fMW); 514 515 memcpy(data,&nf,4); 516 517 return TLV_GET_SUCCEEDED; 518} 519 520 521int 522get_physical_medium(void *data) 523{ 524/* TLVDEF( uint32_t, physical_medium, , 3, Access_unset ) */ 525 526 uint32_t pm; 527 528 pm = htonl(6); // "ethernet" 529 530 memcpy(data,&pm,4); 531 532 return TLV_GET_SUCCEEDED; 533} 534 535#ifdef HAVE_WIRELESS 536 537/* Return TRUE on successful query, setting "wireless_mode" to: 538 * 0 = ad-hoc mode 539 * 1 = infrastructure mode ie ESS (Extended Service Set) mode 540 * 2 = auto/unknown (device may auto-switch between ad-hoc and infrastructure modes) 541 */ 542int 543get_wireless_mode(void *data) 544{ 545/* TLVDEF( uint32_t, wireless_mode, , 4, Access_unset ) */ 546 547 uint32_t* wl_mode = (uint32_t*) data; 548 549 int rqfd; 550 struct iwreq req; 551 int ret; 552 553 memset(&req, 0, sizeof(req)); 554 strncpy(req.ifr_ifrn.ifrn_name, g_osl->wireless_if, sizeof(req.ifr_ifrn.ifrn_name)); 555//*/printf("get_wireless_mode: requesting addr for interface \'%s\'\n",g_osl->wireless_if); 556 rqfd = socket(AF_INET,SOCK_DGRAM,0); 557 if (rqfd<0) 558 { 559 warn("get_wireless_mode: FAILED creating request socket for \'%s\' : %s\n",g_osl->wireless_if,strerror(errno)); 560 return FALSE; 561 } 562 ret = ioctl(rqfd, SIOCGIWMODE, &req); 563 close(rqfd); 564 if (ret != 0) 565 { 566 /* We don't whine about "Operation Not Supported" since that 567 * just means the interface does not have wireless extensions. */ 568 if (errno != EOPNOTSUPP && errno != EFAULT) 569 warn("get_wireless_mode: get associated Access Point MAC failed: Error %d, %s\n", 570 errno,strerror(errno)); 571 return TLV_GET_FAILED; 572 } 573 574 switch (req.u.mode) { 575 case IW_MODE_AUTO: 576 *wl_mode = 2; 577 break; 578 579 case IW_MODE_ADHOC: 580 *wl_mode = 0; 581 break; 582 583 case IW_MODE_INFRA: 584 *wl_mode = 1; 585 break; 586 587 case IW_MODE_MASTER: 588 *wl_mode = 1; 589 break; 590 591 case IW_MODE_REPEAT: 592 *wl_mode = 1; 593 break; 594 595 case IW_MODE_SECOND: 596 *wl_mode = 1; 597 break; 598 599 default: 600 /* this is a wireless device that is probably acting 601 * as a listen-only monitor; we can't express its features like 602 * this, so we'll not return a wireless mode TLV. */ 603 IF_TRACED(TRC_TLVINFO) 604 printf("get_wireless_mode(): mode (%d) unrecognizable - FAILING the get...\n", req.u.mode); 605 END_TRACE 606 return TLV_GET_FAILED; 607 } 608 IF_TRACED(TRC_TLVINFO) 609 printf("get_wireless_mode(): wireless_mode=%d\n", *wl_mode); 610 END_TRACE 611 612 return TLV_GET_SUCCEEDED; 613} 614 615 616/* If the interface is 802.11 wireless in infrastructure mode, and it 617 * has successfully associated to an AP (Access Point) then it will 618 * have a BSSID (Basic Service Set Identifier), which is usually the 619 * AP's MAC address. 620 * Of course, this code resides in an AP, so we just return the AP's 621 * BSSID. */ 622int 623get_bssid(void *data) 624{ 625/* TLVDEF( etheraddr_t, bssid, , 5, Access_unset ) */ 626 627 etheraddr_t* bssid = (etheraddr_t*) data; 628 629 struct iwreq req; 630 int ret; 631 632 memset(&req, 0, sizeof(req)); 633 strncpy(req.ifr_ifrn.ifrn_name, g_osl->wireless_if, sizeof(req.ifr_ifrn.ifrn_name)); 634 ret = ioctl(g_osl->sock, SIOCGIWAP, &req); 635 if (ret != 0) 636 { 637 /* We don't whine about "Operation Not Supported" since that 638 * just means the interface does not have wireless extensions. */ 639 if (errno != EOPNOTSUPP) 640 warn("get_bssid: get associated Access Point MAC failed: %s\n", 641 strerror(errno)); 642 return TLV_GET_FAILED; 643 } 644 645 if (req.u.ap_addr.sa_family != ARPHRD_ETHER) 646 { 647 warn("get_bssid: expecting Ethernet address back, not sa_family=%d\n", 648 req.u.ap_addr.sa_family); 649 return TLV_GET_FAILED; 650 } 651 652 memcpy(bssid, req.u.ap_addr.sa_data, sizeof(etheraddr_t)); 653 654 IF_TRACED(TRC_TLVINFO) 655 printf("get_bssid(): bssid=" ETHERADDR_FMT "\n", ETHERADDR_PRINT(bssid)); 656 END_TRACE 657 658 return TLV_GET_SUCCEEDED; 659} 660 661 662int 663get_ssid(void *data) 664{ 665/* TLVDEF( ssid_t, ssid, , 6, Access_unset ) */ 666 667// ssid_t* ssid = (ssid_t*) data; 668 669 return TLV_GET_FAILED; 670} 671#else 672int 673get_wireless_mode(void *data) 674{ 675 return TLV_GET_FAILED; 676} 677 678int 679get_bssid(void *data) 680{ 681 return TLV_GET_FAILED; 682} 683#endif /* HAVE_WIRELESS */ 684 685 686int 687get_ipv4addr(void *data) 688{ 689/* TLVDEF( ipv4addr_t, ipv4addr, , 7, Access_unset ) */ 690 691 int rqfd, ret; 692 struct ifreq req; 693 ipv4addr_t* ipv4addr = (ipv4addr_t*) data; 694 char dflt_if[] = {"br0"}; 695 char *interface = g_interface; 696 697 if (interface == NULL) interface = dflt_if; 698 memset(&req, 0, sizeof(req)); 699 strncpy(req.ifr_name, interface, sizeof(req.ifr_name)); 700 rqfd = socket(AF_INET,SOCK_DGRAM,0); 701 if (rqfd<0) 702 { 703 warn("get_ipv4addr: FAILED creating request socket for \'%s\' : %s\n",interface,strerror(errno)); 704 return TLV_GET_FAILED; 705 } 706 ret = ioctl(rqfd, SIOCGIFADDR, &req); 707 if (ret < 0) 708 { 709 warn("get_ipv4addr(%d,%s): FAILED : %s\n", rqfd, interface, strerror(errno)); 710 return TLV_GET_FAILED; 711 } 712 close(rqfd); 713 IF_DEBUG 714 /* Interestingly, the ioctl to get the ipv4 address returns that 715 address offset by 2 bytes into the buf. Leaving this in case 716 one of the ports results in a different offset... */ 717 unsigned char *d; 718 d = (unsigned char*)req.ifr_addr.sa_data; 719 /* Dump out the whole 14-byte buffer */ 720 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]); 721 END_DEBUG 722 723 memcpy(ipv4addr,&req.ifr_addr.sa_data[2],sizeof(ipv4addr_t)); 724 IF_DEBUG 725 printf("get_ipv4addr: returning %d.%d.%d.%d as ipv4addr\n", \ 726 *((uint8_t*)ipv4addr),*((uint8_t*)ipv4addr +1), \ 727 *((uint8_t*)ipv4addr +2),*((uint8_t*)ipv4addr +3)); 728 END_DEBUG 729 730 return TLV_GET_SUCCEEDED; 731} 732 733 734int 735get_ipv6addr(void *data) 736{ 737/* TLVDEF( ipv6addr_t, ipv6addr, , 8, Access_unset ) */ 738 739 ipv6addr_t* ipv6addr = (ipv6addr_t*) data; 740 741 return TLV_GET_FAILED; 742} 743 744 745int 746get_max_op_rate(void *data) 747{ 748/* TLVDEF( uint16_t, max_op_rate, , 9, Access_unset ) units of 0.5 Mbs */ 749 750 uint16_t morate; 751 752 morate = htons(108); /* (OpenWRT, 802.11g) 54 Mbs / 0.5 Mbs = 108 */ 753 memcpy(data, &morate, 2); 754 755 return TLV_GET_SUCCEEDED; 756} 757 758 759int 760get_tsc_ticks_per_sec(void *data) 761{ 762/* TLVDEF( uint64_t, tsc_ticks_per_sec, , 0xA, Access_unset ) */ 763 764 uint64_t ticks; 765 766 ticks = (uint64_t) 0xF4240LL; // 1M (1us) ticks - YMMV 767 768 cpy_hton64(data, &ticks); 769 770 return TLV_GET_SUCCEEDED; 771} 772 773 774int 775get_link_speed(void *data) 776{ 777/* TLVDEF( uint32_t, link_speed, , 0xC, Access_unset ) // 100bps increments */ 778 779 uint32_t speed; 780 781 /* OpenWRT: 782 * Since this is a bridged pair of interfaces (br0 = vlan0 + eth1), I am returning the 783 * wireless speed (eth1), which is the lowest of the upper limits on the two interfaces... */ 784 785 speed = htonl(540000); // 54Mbit wireless... (540k x 100 = 54Mbs) 786 787 memcpy(data, &speed, 4); 788 789 return TLV_GET_SUCCEEDED; 790} 791 792 793/* Unless this box is used as a wireless client, RSSI is meaningless - which client should be measured? */ 794int 795get_rssi(void *data) 796{ 797/* TLVDEF( uint32_t, rssi, , 0xD, Access_unset ) */ 798 799 return TLV_GET_FAILED; 800} 801 802 803int 804get_icon_image(void *data) 805{ 806/* TLVDEF( icon_file_t, icon_image, , 0xE ) // Usually LTLV style (Windows .ico file > 1k long) */ 807 808 icon_file_t* icon = (icon_file_t*) data; 809 int fd; 810 811 /* The configuration file (lld2d.conf, in /etc) may have specified an icon file, which will be sent as 812 * a TLV if it is smaller than the lesser of 1k and whatever space is left in the send-buffer... Such a 813 * determination will be made at the time of the write, tho.... 814 * 815 * In main.c, we read the config file, and established a value for the iconfile_path in "g_icon_path". 816 * This path-value ( a char* ) MAY be NULL, if no path was configured correctly. 817 * Here, we test that path, opening a file descriptor if it exists, and save its size for the writer-routine. */ 818 819 /* Close any still-open fd to a previously "gotten" iconfile */ 820 if (icon->fd_icon != -1 && icon->sz_iconfile != 0) 821 close(icon->fd_icon); 822 823 /* set defaults */ 824 icon->sz_iconfile = 0; 825 icon->fd_icon = -1; 826 827 if (g_icon_path == NULL || g_icon_path[0] == 0) 828 { 829 return TLV_GET_FAILED; // No iconfile was correctly declared. This may NOT be an error! 830 } 831 832 fd = open(g_icon_path, O_RDONLY); 833 if (fd < 0) 834 { 835 warn("get_icon_image: reading iconfile %s FAILED : %s\n", 836 g_icon_path, strerror(errno)); 837 return TLV_GET_FAILED; 838 } else { 839 /* size the file, for the writer to determine if it needs to force an LTLV */ 840 struct stat filestats; 841 int statstat; 842 843 statstat = fstat( fd, &filestats ); 844 if (statstat < 0) 845 { 846 warn("get_icon_image: stat-ing iconfile %s FAILED : %s\n", 847 g_icon_path, strerror(errno)); 848 return TLV_GET_FAILED; 849 } else { 850 /* Finally! SUCCESS! */ 851 icon->sz_iconfile = filestats.st_size; 852 icon->fd_icon = fd; 853 IF_TRACED(TRC_TLVINFO) 854 printf("get_icon_image: stat\'ing iconfile %s returned length=" FMT_SIZET "\n", 855 g_icon_path, icon->sz_iconfile); 856 END_TRACE 857 } 858 if (icon->sz_iconfile <= 0 || icon->sz_iconfile >= 32768) 859 return TLV_GET_FAILED; 860 } 861 return TLV_GET_SUCCEEDED; 862} 863 864 865int 866get_machine_name(void *data) 867{ 868/* TLVDEF( ucs2char_t, machine_name, [16], 0xF, Access_unset ) */ 869 870 ucs2char_t* name = (ucs2char_t*) data; 871 872 int ret; 873 struct utsname unamebuf; 874 875 /* use uname() to get the system's hostname */ 876 ret = uname(&unamebuf); 877 if (ret != -1) 878 { 879 /* because I am a fool, and can't remember how to refer to the sizeof a structure 880 * element directly, there is an unnecessary declaration here... */ 881 tlv_info_t* fool; 882 size_t namelen; 883 884 /* nuke any '.' in what should be a nodename, not a FQDN */ 885 char *p = strchr(unamebuf.nodename, '.'); 886 if (p) 887 *p = '\0'; 888 889 namelen = strlen(unamebuf.nodename); 890 891 util_copy_ascii_to_ucs2(name, sizeof(fool->machine_name), unamebuf.nodename); 892 893 IF_TRACED(TRC_TLVINFO) 894 dbgprintf("get_machine_name(): space=" FMT_SIZET ", len=" FMT_SIZET ", machine name = %s\n", 895 sizeof(fool->machine_name), namelen, unamebuf.nodename); 896 END_TRACE 897 return TLV_GET_SUCCEEDED; 898 } 899 900 IF_TRACED(TRC_TLVINFO) 901 dbgprintf("get_machine_name(): uname() FAILED, returning %d\n", ret); 902 END_TRACE 903 904 return TLV_GET_FAILED; 905} 906 907 908int 909get_support_info(void *data) 910{ 911/* TLVDEF( ucs2char_t, support_info, [32], 0x10, Access_unset ) // RLS: was "contact_info" */ 912 913 ucs2char_t * support = (ucs2char_t*) data; 914 915 return TLV_GET_FAILED; 916} 917 918 919int 920get_friendly_name(void *data) 921{ 922/* TLVDEF( ucs2char_t, friendly_name, [32], 0x11, Access_unset ) */ 923 924 ucs2char_t * fname = (ucs2char_t*) data; 925 926 return TLV_GET_FAILED; 927} 928 929 930int 931get_upnp_uuid(void *data) 932{ 933/* TLVDEF( uuid_t, upnp_uuid, , 0x12, Access_unset ) // 16 bytes long */ 934 935// uuid_t* uuid = (uuid_t*) data; 936 937 return TLV_GET_FAILED; 938} 939 940 941int 942get_hw_id(void *data) 943{ 944/* TLVDEF( ucs2char_t, hw_id, [200], 0x13, Access_unset ) // 400 bytes long, max */ 945 946 ucs2char_t * hwid = (ucs2char_t*) data; 947 948 return TLV_GET_FAILED; 949} 950 951 952int 953get_qos_flags(void *data) 954{ 955/* TLVDEF( uint32_t, qos_flags, , 0x14, Access_unset ) */ 956 957 int32_t qosf; 958 959#define TAG8P 0x20000000 // supports 802.1p priority tagging 960#define TAG8Q 0x40000000 // supports 802.1q VLAN tagging 961#define QW 0x80000000 // has Microsoft qWave service implemented; this is not LLTD QoS extensions 962 963 qosf = htonl(0); 964 965 memcpy(data,&qosf,4); 966 967 return TLV_GET_SUCCEEDED; 968} 969 970 971int 972get_wl_physical_medium(void *data) 973{ 974/* TLVDEF( uint8_t, wl_physical_medium, , 0x15, Access_unset ) */ 975 976 uint8_t* wpm = (uint8_t*) data; 977 978 return TLV_GET_FAILED; 979} 980 981 982int 983get_accesspt_assns(void *data) 984{ 985/* TLVDEF( assns_t, accesspt_assns, , 0x16, Access_unset ) // RLS: Large_TLV */ 986 987#if 0 988 /* NOTE: This routine depends implicitly upon the data area being zero'd initially. */ 989 assns_t* assns = (assns_t*) data; 990 struct timeval now; 991 992 if (assns->table == NULL) 993 { 994 /* generate the associations-table, with a maximum size of 1000 entries */ 995 assns->table = (assn_table_entry_t*)xmalloc(1000*sizeof(assn_table_entry_t)); 996 assns->assn_cnt = 0; 997 } 998 999 /* The writer routine will zero out the assn_cnt when it sends the last packet of the LTLV.. 1000 * Keep the table around for two seconds at most, and refresh if older than that. 1001 */ 1002 gettimeofday(&now, NULL); 1003 1004 if ((now.tv_sec - assns->collection_time.tv_sec) > 2) 1005 { 1006 assns->assn_cnt = 0; 1007 } 1008 1009 /* Force a re-assessment, whenever the count is zero */ 1010 if (assns->assn_cnt == 0) 1011 { 1012 uint8_t dummyMAC[6] = {0x00,0x02,0x44,0xA4,0x46,0xF1}; 1013 1014 /* fill the allocated buffer with 1 association-table-entry, with everything in network byte order */ 1015 memcpy(&assns->table[0].MACaddr, &dummyMAC, sizeof(etheraddr_t)); 1016 assns->table[0].MOR = htons(108); // units of 1/2 Mb per sec 1017 assns->table[0].PHYtype = 0x02; // DSSS 2.4 GHZ (802.11g) 1018 assns->assn_cnt = 1; 1019 assns->collection_time = now; 1020 } 1021 1022 return TLV_GET_SUCCEEDED; 1023#else 1024 return TLV_GET_FAILED; 1025#endif 1026} 1027 1028 1029int 1030get_jumbo_icon(void *data) 1031{ 1032/* TLVDEF( lg_icon_t, jumbo_icon, , 0x18, Access_unset ) // RLS: Large_TLV only */ 1033 lg_icon_t *jumbo = (lg_icon_t*)data; 1034 int fd; 1035 1036 /* The configuration file (lld2d.conf, in /etc) may have specified a jumbo-icon file, which will be sent 1037 * only as an LTLV... 1038 * 1039 * In main.c, we read the config file, and established a value for the iconfile_path in "g_jumbo_icon_path". 1040 * This path-value ( a char* ) MAY be NULL, if no path was configured correctly. 1041 * Here, we test that path, opening a file descriptor if it exists, and save its size for the writer-routine. */ 1042 1043 /* Close any still-open fd to a previously "gotten" iconfile */ 1044 if (jumbo->fd_icon != -1 && jumbo->sz_iconfile != 0) 1045 close(jumbo->fd_icon); 1046 1047 /* set defaults */ 1048 jumbo->sz_iconfile = 0; 1049 jumbo->fd_icon = -1; 1050 1051 if (g_jumbo_icon_path == NULL || g_jumbo_icon_path[0] == 0) 1052 { 1053 return TLV_GET_FAILED; // No jumbo-iconfile was correctly declared. This may NOT be an error! 1054 } 1055 1056 fd = open(g_jumbo_icon_path, O_RDONLY); 1057 if (fd < 0) 1058 { 1059 warn("get_jumbo_icon: reading iconfile %s FAILED : %s\n", 1060 g_jumbo_icon_path, strerror(errno)); 1061 return TLV_GET_FAILED; 1062 } else { 1063 /* size the file, for the writer to determine if it needs to force an LTLV */ 1064 struct stat filestats; 1065 int statstat; 1066 1067 statstat = fstat( fd, &filestats ); 1068 if (statstat < 0) 1069 { 1070 warn("get_jumbo_icon: stat-ing iconfile %s FAILED : %s\n", 1071 g_jumbo_icon_path, strerror(errno)); 1072 return TLV_GET_FAILED; 1073 } else { 1074 /* Finally! SUCCESS! */ 1075 jumbo->sz_iconfile = filestats.st_size; 1076 jumbo->fd_icon = fd; 1077 IF_TRACED(TRC_TLVINFO) 1078 printf("get_jumbo_icon: stat\'ing iconfile %s returned length=" FMT_SIZET "\n", 1079 g_jumbo_icon_path, jumbo->sz_iconfile); 1080 END_TRACE 1081 } 1082 if (jumbo->sz_iconfile <= 0 || jumbo->sz_iconfile > 262144) 1083 return TLV_GET_FAILED; 1084 } 1085 1086 return TLV_GET_SUCCEEDED; 1087} 1088 1089 1090int 1091get_sees_max(void *data) 1092{ 1093/* TLVDEF( uint16_t, sees_max, , 0x19, Access_unset, TRUE ) */ 1094 1095 uint16_t *sees_max = (uint16_t*)data; 1096 1097 g_short_reorder_buffer = htons(NUM_SEES); 1098 memcpy(sees_max, &g_short_reorder_buffer, 2); 1099 1100 return TLV_GET_SUCCEEDED; 1101} 1102 1103 1104radio_t my_radio; 1105 1106int 1107get_component_tbl(void *data) 1108{ 1109/* TLVDEF( comptbl_t, component_tbl, , 0x1A, Access_unset, FALSE ) */ 1110 1111 comptbl_t *cmptbl = (comptbl_t*)data; 1112 1113 uint16_t cur_mode; 1114 etheraddr_t bssid; 1115 1116 cmptbl->version = 1; 1117 cmptbl->bridge_behavior = 0; // all packets transiting the bridge are seen by Responder 1118 cmptbl->link_speed = htonl((uint32_t)(100000000/100)); // units of 100bps 1119 cmptbl->radio_cnt = 1; 1120 cmptbl->radios = &my_radio; 1121 1122 cmptbl->radios->MOR = htons((uint16_t)(54000000/500000)); // units of 1/2 Mb/sec 1123 cmptbl->radios->PHYtype = 2; // 0=>Unk; 1=>2.4G-FH; 2=>2.4G-DS; 3=>IR; 4=>OFDM5G; 5=>HRDSSS; 6=>ERP 1124 if (get_wireless_mode((void*)&cur_mode) == TLV_GET_FAILED) 1125 { 1126 cur_mode = 2; // default is "automatic or unknown" 1127 } 1128 cmptbl->radios->mode = (uint8_t)cur_mode; 1129 if (get_bssid((void*)&bssid) == TLV_GET_FAILED) 1130 { 1131 memcpy(&bssid, &g_hwaddr, sizeof(etheraddr_t)); 1132 } 1133 memcpy(&cmptbl->radios->BSSID, &bssid, sizeof(etheraddr_t)); 1134 1135 return TLV_GET_SUCCEEDED; 1136} 1137