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