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//#define CHECKING_PACKING 1
21
22#define _GNU_SOURCE
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27#include <assert.h>
28
29#define	DECLARING_GLOBALS
30#include "globals.h"
31
32#include "statemachines.h"
33#include "packetio.h"
34
35extern void qos_init(void);
36
37bool_t          isConfTest;
38
39static void
40usage(void)
41{
42    fprintf(stderr, "usage: %s [-d] [-t TRACELEVEL] INTERFACE [WIRELESS-IF]\n"
43	    "\tRuns a link-layer topology discovery daemon on INTERFACE (eg eth0)\n"
44	    "\t-d : don't background, and log moderate tracing to stdout (debug mode)\n"
45	    "\t-t TRACELEVEL : select tracing by adding together:\n"
46	    "\t\t0x01 : BAND network load control calculations\n"
47	    "\t\t0x02 : packet dump of protocol exchange\n"
48	    "\t\t0x04 : Charge mechanism for protection against denial of service\n"
49	    "\t\t0x08 : system information TLVs (type-length-value)\n"
50	    "\t\t0x10 : State-Machine transitions for smS, smE, and smT\n"
51	    "\t\t0x20 : Qos/qWave extensions\n",
52	    g_Progname);
53    exit(2);
54}
55
56
57static void
58init_from_conf_file()
59{
60    FILE   *conf_file;
61    char   *line = NULL;
62    #define LINEBUFLEN 256
63    char    var[LINEBUFLEN];
64    char    val[LINEBUFLEN];
65    size_t  len  = 0;
66    ssize_t numread;
67    int     assigns;
68    char    default_icon_path[] = {"/etc/icon.ico"};
69
70    /* Set default values for configuration options */
71    /* (avoid strdup() since it doesn't use xmalloc wrapper) */
72    g_icon_path = xmalloc(strlen(default_icon_path)+1);
73    strcpy(g_icon_path,default_icon_path);
74
75    /* Examine configuration file, if it exists */
76    conf_file = fopen("/etc/lld2d.conf", "r");
77    if (conf_file == NULL)  return;
78    while ((numread = getline(&line, &len, conf_file)) != -1)
79    {
80        var[0] = val[0] = '\0';
81        assigns = sscanf(line, "%s = %s", var, val);
82
83        if (assigns==2)
84        {
85            /* compare to each of the 2 allowed vars... */
86            if (!strcmp(var,"icon")) {
87                char *path = NULL;
88                char *cur  = NULL;
89
90                path = xmalloc(strlen(val)+6); // always allow enough room for a possible prefix of '/etc/'
91                cur = path;
92
93                /* Check for leading '/' and prefix '/etc/' if missing */
94                if (val[0] != '/')
95                {
96                    strcpy(cur,"/etc/"); cur += 5;
97                }
98                strncpy(cur,val,strlen(val));
99
100                if (g_icon_path) xfree(g_icon_path);	// always use the most recent occurrence
101                g_icon_path = path;
102                DEBUG({printf("configvar 'g_icon_path' = %s\n", g_icon_path);})
103            } else if (!strcmp(var,"jumbo-icon")) {
104                char *path = NULL;
105                char *cur  = NULL;
106
107                path = xmalloc(strlen(val)+6); // always allow enough room for a possible prefix of '/etc/'
108                cur = path;
109
110                /* Check for leading '/' and prefix '/etc/' if missing */
111                if (val[0] != '/')
112                {
113                    strcpy(cur,"/etc/"); cur += 5;
114                }
115                strncpy(cur,val,strlen(val));
116
117                if (g_jumbo_icon_path) xfree(g_jumbo_icon_path);	// always use the most recent occurrence
118                g_jumbo_icon_path = path;
119                DEBUG({printf("configvar 'g_jumbo_icon_path' = %s\n", g_jumbo_icon_path);})
120            } else {
121                warn("line ignored - var does not match a known string\n");
122            }
123        } else {
124            warn("line ignored - var or val was missing or no equals\n");
125        }
126
127    }
128    if (line!=NULL)  free(line);
129    fclose(conf_file);
130}
131
132//-----------------------------------------------------------------------------------------------------------//
133int
134main(int argc, char **argv)
135{
136    char  *p;
137    int    c;
138    bool_t opt_debug = FALSE;
139    int    opt_trace = 0;
140
141    /* set program name to last component of filename */
142    p = strrchr(argv[0], '/');
143    if (p)
144	g_Progname = p+1;
145    else
146	g_Progname = argv[0];
147
148    /* set a module flag if this is the confidence test */
149    isConfTest = (strstr(g_Progname,"conftest") != NULL ? TRUE : FALSE);
150
151    /* parse arguments */
152    while ((c=getopt(argc, argv, "dt:")) != -1)
153    {
154	switch (c)
155	{
156	case 'd':
157	    opt_debug = TRUE;
158	    break;
159
160	case 't':
161	    opt_trace = atoi(optarg);
162	    if (opt_trace == 0)
163	    {
164		fprintf(stderr, "%s: -t TRACELEVEL: parse error in \"%s\"\n",
165			g_Progname, optarg);
166		usage();
167	    }
168	    break;
169
170	default:
171	    if (isConfTest)
172            {
173                opt_debug = TRUE;
174                opt_trace = TRC_PACKET + TRC_STATE;
175            } else {
176                usage();
177            }
178	    break;
179	}
180    }
181
182    if (isConfTest)
183    {
184        if (optind >= argc)
185        {
186            g_interface = strstr(g_Progname,"x86") != NULL ? "eth0" : "br0";
187            g_wl_interface = strstr(g_Progname,"x86") != NULL ? "eth0" : "eth1";
188            printf("%s: no interface-name argument; '%s' assumed.\n", g_Progname, g_interface);
189        } else {
190            g_interface = strdup(argv[optind]);
191            if ((optind+1) >= argc)
192            {
193                g_wl_interface = g_interface;
194            } else {
195                g_wl_interface = strdup(argv[optind+1]);
196            }
197        }
198    } else {
199        if (optind >= argc)
200        {
201            fprintf(stderr, "%s: error: missing INTERFACE name argument\n", g_Progname);
202            usage();
203        } else {
204            g_interface = strdup(argv[optind]);
205            if ((optind+1) >= argc)
206            {
207                g_wl_interface = g_interface;
208            } else {
209                g_wl_interface = strdup(argv[optind+1]);
210            }
211        }
212    }
213
214#ifdef CHECKING_PACKING
215    printf("etherHdr: " FMT_SIZET "   baseHdr: " FMT_SIZET "    discoverHdr: " \
216            FMT_SIZET "    helloHdr: " FMT_SIZET "    qltlvHdr: " FMT_SIZET "\n",
217            sizeof(topo_ether_header_t),sizeof(topo_base_header_t),sizeof(topo_discover_header_t),
218            sizeof(topo_hello_header_t),sizeof(topo_qltlv_header_t));
219    assert(sizeof(topo_ether_header_t) == 14);
220    assert(sizeof(topo_base_header_t) == 18);
221    assert(sizeof(topo_discover_header_t) == 4);
222    assert(sizeof(topo_hello_header_t) == 14);
223    assert(sizeof(topo_qltlv_header_t) == 4);
224    puts("Passed struct-packing checks!");
225#endif
226
227    /* initialise remaining process state */
228    g_trace_flags = opt_trace;
229    memset(&g_hwaddr,0,sizeof(etheraddr_t));
230
231    g_smE_state = smE_Quiescent;
232    g_smT_state = smT_Quiescent;
233
234    memset (g_sessions,0,MAX_NUM_SESSIONS*sizeof(g_sessions[0]));
235
236    memset(&g_band,0,sizeof(band_t));		/* BAND algorthm's state */
237    g_osl = osl_init();				/* initialise OS-glue Layer */
238    memset(g_rxbuf,0,(size_t)RXBUFSZ);
239    memset(g_emitbuf,0,(size_t)RXBUFSZ);
240    memset(g_txbuf,0,(size_t)TXBUFSZ);
241    memset(g_re_txbuf,0,(size_t)TXBUFSZ);
242    g_sees = seeslist_new(NUM_SEES);
243    g_rcvd_pkt_len = 0;
244    g_rtxseqnum = 0;
245    g_re_tx_len = 0;
246    g_generation = 0;
247    g_sequencenum = 0;
248    g_opcode = Opcode_INVALID;
249    g_ctc_packets = 0;
250    g_ctc_bytes = 0;
251
252#if CAN_FOPEN_IN_SELECT_LOOP
253    /* then we don't need a global to keep the stream open all the time...*/
254#else
255    g_procnetdev = fopen("/proc/net/dev","r");
256    if (g_procnetdev<0)
257        die("fopen of /proc/net/dev failed\n");
258#endif
259
260    /* Initialize the timers (inactivity timers are init'd when session is created) */
261    g_block_timer = g_charge_timer = g_emit_timer = g_hello_timer = NULL;
262
263    /* initialize things from the parameter file, /etc/lld2d.conf
264     * currently, v1.0, this only involves LTLV pointers... */
265
266    init_from_conf_file();
267
268    event_init();
269    qos_init();
270
271    osl_interface_open(g_osl, g_interface, NULL);
272    osl_get_hwaddr(g_osl, &g_hwaddr);
273
274    IF_DEBUG
275        printf("%s: listening at address: " ETHERADDR_FMT "\n",
276	    g_Progname, ETHERADDR_PRINT(&g_hwaddr));
277    END_DEBUG
278    if (!opt_debug)
279    {
280        DEBUG({printf("%s: Using syslog\n", g_Progname);})
281        util_use_syslog();
282        DEBUG({printf("%s: Daemonizing...\n", g_Progname);})
283        osl_become_daemon(g_osl);
284    }
285    DEBUG({printf("%s: listening on interface %s\n", g_Progname, g_interface);})
286
287    osl_write_pidfile(g_osl);
288
289    osl_drop_privs(g_osl);
290
291    /* add IO handlers & run main event loop forever */
292    event_mainloop();
293
294    return 0;
295}
296