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