1 /*
2  */
3 
4 #include "graph.h"
5 
6 /*
7  * Dynamic objects used only during text read
8  */
9 
10 MOBJ *mobjlist [NB_MOBJ] ;
11 
12 MOBJ *vlistmobj ;
13 
14 /******************************************************************************
15 Small memory allocation function
16 ******************************************************************************/
17 
my_malloc(size_t s)18 void *my_malloc (size_t s)
19 {
20     void *p ;
21 
22     p = malloc (s) ;
23     if (p == NULL)
24 	error (1, "cannot malloc") ;
25     memset (p, 0, s) ;
26 
27     return p ;
28 }
29 
30 /******************************************************************************
31 Check an existing node and returns a pointer to it
32 ******************************************************************************/
33 
check_node(char * name,char * context)34 static struct node *check_node (char *name, char *context)
35 {
36     struct node *node ;
37 
38     node = symtab_to_node (symtab_get (name)) ;
39     if (node == NULL)
40     {
41 	inconsistency ("Reference to a non-existant node '%s' (context '%s')",
42 						name, context) ;
43 	exit (1) ;
44     }
45     return node ;
46 }
47 
48 
49 /******************************************************************************
50 Link management
51 ******************************************************************************/
52 
create_link(char * name,char * n1,char * n2)53 struct link *create_link (char *name, char *n1, char *n2)
54 {
55     struct link *l ;
56     struct linklist *ll ;
57     char *tab [2] ;
58     int i ;
59 
60     l = mobj_alloc (linkmobj, 1) ;
61 
62     if (name != NULL)
63 	name = symtab_to_name (symtab_get (name)) ;
64     l->name = name ;
65 
66     tab [0] = n1 ;
67     tab [1] = n2 ;
68     for (i = 0 ; i < 2 ; i++)
69     {
70 	l->node [i] = check_node (tab [i], "link statement") ;
71 
72 	ll = mobj_alloc (llistmobj, 1) ;
73 	ll->link = l ;
74 	ll->next = l->node [i]->linklist ;
75 	l->node [i]->linklist = ll ;
76     }
77 
78     return l ;
79 }
80 
81 /******************************************************************************
82 Ssid management
83 ******************************************************************************/
84 
create_ssid(char * name,char * mode)85 struct ssid *create_ssid (char *name, char *mode)
86 {
87     struct ssid *s ;
88 
89     s = mobj_alloc (ssidmobj, 1) ;
90 
91     if (name != NULL)
92 	name = symtab_to_name (symtab_get (name)) ;
93     s->name = name ;
94 
95     if (strcmp (mode, "open") == 0)
96 	s->mode = SSID_OPEN ;
97     else if (strcmp (mode, "auth") == 0)
98 	s->mode = SSID_AUTH ;
99     else
100     {
101 	inconsistency ("Invalid mode '%s' for ssid '%s'", mode, name) ;
102 	exit (1) ;
103     }
104 
105     return s ;
106 }
107 
108 /******************************************************************************
109 Attribute parsing
110 ******************************************************************************/
111 
112 struct attrtab
113 {
114     char *attr ;
115     struct attrvallist *first, *last ;
116     struct attrtab *next ;
117 } ;
118 
119 struct attrvallist
120 {
121     char *val ;
122     struct attrvallist *next ;
123 } ;
124 
attr_init(void)125 static struct attrtab *attr_init (void)
126 {
127     return NULL ;
128 }
129 
attr_close(struct attrtab * at)130 static void attr_close (struct attrtab *at)
131 {
132     while (at != NULL)
133     {
134 	struct attrtab *t ;
135 	struct attrvallist *av ;
136 
137 	t = at->next ;
138 	av = at->first ;
139 	while (av != NULL)
140 	{
141 	    struct attrvallist *tv ;
142 
143 	    tv = av->next ;
144 	    free (av->val) ;
145 	    free (av) ;
146 	    av = tv ;
147 	}
148 	free (at->attr) ;
149 	free (at) ;
150 	at = t ;
151     }
152 }
153 
attr_get(struct attrtab * at,char * name)154 static struct attrtab *attr_get (struct attrtab *at, char *name)
155 {
156     while (at != NULL)
157     {
158 	if (strcmp (at->attr, name) == 0)
159 	    return at ;
160 	at = at->next ;
161     }
162     return NULL ;
163 }
164 
attr_get_vallist(struct attrtab * at,char * name)165 static struct attrvallist *attr_get_vallist (struct attrtab *at, char *name)
166 {
167     struct attrtab *a ;
168     struct attrvallist *av ;
169 
170     a = attr_get (at, name) ;
171     if (a == NULL)
172 	av = NULL ;
173     else
174 	av = a->first ;
175 
176     return av ;
177 }
178 
attr_get_val(struct attrvallist * av)179 static char *attr_get_val (struct attrvallist *av)
180 {
181     return av->val ;
182 }
183 
184 /* insert a new attribute (without value) in attr list */
attr_append(struct attrtab ** hd,char * name)185 static struct attrtab *attr_append (struct attrtab **hd, char *name)
186 {
187     struct attrtab *at ;
188 
189     at = my_malloc (sizeof *at) ;
190     at->attr = my_malloc (strlen (name) + 1) ;
191     strcpy (at->attr, name) ;
192     at->first = at->last = NULL ;
193     at->next = *hd ;
194     *hd = at ;
195     return at ;
196 }
197 
attr_val_append(struct attrtab * at,char * val)198 static void attr_val_append (struct attrtab *at, char *val)
199 {
200     struct attrvallist *av ;
201 
202     av = my_malloc (sizeof *av) ;
203     av->val = my_malloc (strlen (val) + 1) ;
204     strcpy (av->val, val) ;
205     av->next = NULL ;
206     if (at->last != NULL)
207 	at->last->next = av ;
208     if (at->first == NULL)
209 	at->first = av ;
210     at->last = av ;
211 }
212 
213 /* nb of val for attr */
attr_get_nval(struct attrvallist * av)214 static int attr_get_nval (struct attrvallist *av)
215 {
216     int n ;
217 
218     n = 0 ;
219     while (av != NULL)
220     {
221 	n++ ;
222 	av = av->next ;
223     }
224     return n ;
225 }
226 
227 
228 
parse_attr(char * tab[],int ntab,struct attrtab ** hd)229 static void parse_attr (char *tab [], int ntab, struct attrtab **hd)
230 {
231     int i, j ;
232     struct attrtab *at ;
233     char val [MAXLINE], *p ;
234     static struct
235     {
236 	char *name ;			/* attribute name */
237 	int  nparam ;			/* number of parameters for this attr */
238     } attrtypes [] =
239     {
240 	{ "type",	1, },
241 	{ "eq",		1, },
242 	{ "name",	1, },
243 	{ "desc",	1, },
244 	{ "link",	1, },
245 	{ "stat",	1, },
246 	{ "encap",	1, },
247 	{ "net",	1, },
248 	{ "vlan",	1, },
249 	{ "allow",	2, },
250 	{ "addr",	1, },
251 	{ "instance",	1, },
252 	{ "model",	1, },
253 	{ "snmp",	1, },
254 	{ "incoming",	1, },
255 	{ "declared",	1, },
256 	{ "location",	1, },
257 	{ "radio",	2, },
258 	{ "ssid",	2, },
259 	{ "iface",	1, },
260 	{ "ssidname",	1, },
261 	{ "mode",	1, },
262 	{ "native",	1, },
263 	{ "voice",	1, },
264 	{ "manual",	1, },
265 	{ "ipmac",	1, },
266 	{ "portmac",	1, },
267 	{ "ifname",	1, },
268     } ;
269 
270 
271     while (ntab > 0)
272     {
273 	for (i = 0 ; i < NTAB (attrtypes) ; i++)
274 	{
275 	    if (strcmp (tab [0], attrtypes [i].name) == 0)
276 	    {
277 		at = attr_get (*hd, tab [0]) ;
278 		if (at == NULL)
279 		    at = attr_append (hd, tab [0]) ;
280 
281 		ntab-- ; tab++ ;
282 
283 		if (ntab < attrtypes [i].nparam)
284 		{
285 		    inconsistency ("Not enough values for attribute '%s'", tab [0]) ;
286 		    exit (1) ;
287 		}
288 
289 		for (j = 0 ; j < attrtypes [i].nparam ; j++)
290 		{
291 		    if (j == 0)
292 			p = val ;
293 		    else
294 			*p++ = ' ' ;
295 
296 		    strcpy (p, tab [0]) ;
297 		    p += strlen (p) ;
298 
299 		    ntab-- ; tab++ ;
300 		}
301 
302 		attr_val_append (at, val) ;
303 		break ;
304 	    }
305 	}
306 	if (i >= NTAB (attrtypes))
307 	{
308 	    inconsistency ("Unrecognized keyword '%s'", tab [0]) ;
309 	    exit (1) ;
310 	}
311     }
312 }
313 
314 /******************************************************************************
315 Process net lists associated to L1 & L2 interfaces
316 ******************************************************************************/
317 
process_netlist(struct netlist ** head,struct attrtab * attrtab)318 static void process_netlist (struct netlist **head, struct attrtab *attrtab)
319 {
320     struct attrvallist *av ;
321     struct netlist *nl ;
322 
323     *head = NULL ;
324 
325     av = attr_get_vallist (attrtab, "net") ;
326     while (av != NULL)
327     {
328 	char *addr ;
329 	struct network *n ;
330 
331 	addr = attr_get_val (av) ;
332 	n = net_get_p (addr) ;
333 
334 	/*
335 	 * First, look for the same network in our list, just in case
336 	 */
337 
338 	for (nl = *head ; nl != NULL ; nl = nl->next)
339 	    if (ip_equal (&nl->net->addr, &n->addr))
340 		break ;
341 
342 	/*
343 	 * If not found, insert it
344 	 */
345 
346 	if (nl == NULL)
347 	{
348 	    nl = mobj_alloc (nlistmobj, 1) ;
349 	    nl->net = n ;
350 	    nl->next = *head ;
351 	    *head = nl ;
352 	}
353 
354 	av = av->next ;
355     }
356 }
357 
358 /******************************************************************************
359 Build the initial graph
360 ******************************************************************************/
361 
process_L1(struct attrtab * attrtab,struct node * n)362 static void process_L1 (struct attrtab *attrtab, struct node *n)
363 {
364     char *ifname ;
365     char *ifdesc ;
366     char *link ;
367     char *encap ;
368     char *stat ;
369     struct attrvallist *avlr, *avls ;
370 
371     ifname = attr_get_val (attr_get_vallist (attrtab, "name")) ;
372     n->u.l1.ifname = symtab_to_name (symtab_get (ifname)) ;
373 
374     ifdesc = attr_get_val (attr_get_vallist (attrtab, "desc")) ;
375     ifdesc = symtab_to_name (symtab_get (ifdesc)) ;
376     if (strcmp (ifdesc, "-") == 0) {
377 	ifdesc = NULL ;
378     }
379     n->u.l1.ifdesc = ifdesc ;
380 
381     link = attr_get_val (attr_get_vallist (attrtab, "link")) ;
382     n->u.l1.link = symtab_to_name (symtab_get (link)) ;
383 
384     stat = attr_get_val (attr_get_vallist (attrtab, "stat")) ;
385     stat = symtab_to_name (symtab_get (stat)) ;
386     if (strcmp (stat, "-") == 0) {
387 	stat = NULL ;
388     }
389     n->u.l1.stat = stat ;
390 
391     encap = attr_get_val (attr_get_vallist (attrtab, "encap")) ;
392     if (strcmp (encap, "disabled") == 0)
393 	n->u.l1.l1type = L1T_DISABLED ;
394     else if (strcmp (encap, "trunk") == 0)
395 	n->u.l1.l1type = L1T_TRUNK ;
396     else if (strcmp (encap, "ether") == 0)
397 	n->u.l1.l1type = L1T_ETHER ;
398     else
399     {
400 	inconsistency ("Invalid encap type (%s)", encap) ;
401 	exit (1) ;
402     }
403 
404     avlr = attr_get_vallist (attrtab, "radio") ;
405     avls = attr_get_vallist (attrtab, "ssid") ;
406     if (avlr != NULL || avls != NULL)
407     {
408 	struct radio *r ;
409 	char *m = NULL ;
410 	char *p, *q ;
411 
412 	if (avlr == NULL)
413 	    m = "SSID parameter without radio information on %s/%s" ;
414 	if (avls == NULL)
415 	    m = "Radio parameters without ssid on %s/%s" ;
416 	if (m != NULL)
417 	{
418 	    inconsistency (m, n->eq->name, n->u.l1.ifname) ;
419 	    return ;
420 	}
421 
422 	r = &(n->u.l1.radio) ;
423 
424 	/* process radio parameters */
425 
426 	p = attr_get_val (avlr) ;
427 	while (isspace (*p))
428 	    p++ ;
429 	/* first word */
430 	q = p ;
431 	while (! isspace (*p) && *p != '\0')
432 	    p++ ;
433 	if (*p == '\0')
434 	{
435 	    inconsistency ("Too few radio parameters on %s/%s", n->eq->name, n->u.l1.ifname) ;
436 	    return ;
437 	}
438 	*p++ = '\0' ;
439 	if (strcmp (q, "dfs") == 0)
440 	    r->channel = CHAN_DFS ;
441 	else if (sscanf (q, "%d", &r->channel) != 1)
442 	    inconsistency ("Invalid radio channel (%s) on %s/%s", q, n->eq->name, n->u.l1.ifname) ;
443 	/* second word */
444 	while (isspace (*p))
445 	    p++ ;
446 	if (sscanf (p, "%d", &r->power) != 1)
447 	    inconsistency ("Invalid radio power (%s) on %s/%s", p, n->eq->name, n->u.l1.ifname) ;
448 
449 	/* process ssid list */
450 	while (avls != NULL)
451 	{
452 	    char *ssidname, *ssidmode ;
453 	    struct ssid *s ;
454 
455 	    ssidmode = ssidname = attr_get_val (avls) ;
456 	    while (*ssidmode != ' ' && *ssidmode != '\0')
457 		ssidmode ++ ;
458 	    if (*ssidmode == '\0')
459 		error (0, "Internal error : no mode found for ssid") ;
460 	    *ssidmode++ = '\0' ;
461 
462 	    s = create_ssid (ssidname, ssidmode) ;
463 	    s->next = r->ssid ;
464 	    r->ssid = s ;
465 
466 	    avls = avls->next ;
467 	}
468     }
469 }
470 
process_L2(struct attrtab * attrtab,struct node * n)471 static void process_L2 (struct attrtab *attrtab, struct node *n)
472 {
473     char *s ;
474     vlan_t vlan ;
475     char *stat ;
476     char *ifname ;
477     struct attrvallist *av ;
478 
479     av = attr_get_vallist (attrtab, "native") ;
480     if (av == NULL)
481     {
482 	n->u.l2.native = 0 ;
483     }
484     else
485     {
486 	n->u.l2.native = atoi (attr_get_val (av)) ;
487     }
488 
489     s = attr_get_val (attr_get_vallist (attrtab, "vlan")) ;
490     vlan = atoi (s) ;
491     if (vlan < 0)
492     {
493 	inconsistency ("Invalid vlan-id (%s)", s) ;
494 	exit (1) ;
495     }
496     n->u.l2.vlan = vlan ;
497 
498     stat = attr_get_val (attr_get_vallist (attrtab, "stat")) ;
499     stat = symtab_to_name (symtab_get (stat)) ;
500     if (strcmp (stat, "-") == 0) {
501 	stat = NULL ;
502     }
503     n->u.l2.stat = stat ;
504 
505     ifname = attr_get_val (attr_get_vallist (attrtab, "ifname")) ;
506     ifname = symtab_to_name (symtab_get (ifname)) ;
507     if (strcmp (ifname, "-") == 0) {
508 	ifname = NULL ;
509     }
510     n->u.l2.ifname = ifname ;
511 
512 }
513 
process_L3(struct attrtab * attrtab,struct node * n)514 static void process_L3 (struct attrtab *attrtab, struct node *n)
515 {
516     char *addr ;
517     int r ;
518 
519     addr = attr_get_val (attr_get_vallist (attrtab, "addr")) ;
520     r = ip_pton (addr, &n->u.l3.addr) ;
521     if (r == 0)
522     {
523 	inconsistency ("Invalid address (%s)", addr) ;
524 	exit (1) ;
525     }
526 }
527 
process_bridge(struct attrtab * attrtab,struct node * n)528 static void process_bridge (struct attrtab *attrtab, struct node *n)
529 {
530     /* nothing to do for bridges */
531 }
532 
process_router(struct attrtab * attrtab,struct node * n)533 static void process_router (struct attrtab *attrtab, struct node *n)
534 {
535     char *instance ;
536 
537     instance = attr_get_val (attr_get_vallist (attrtab, "instance")) ;
538     n->u.router.name = symtab_to_name (symtab_get (instance)) ;
539 }
540 
process_L2pat(struct attrtab * attrtab,struct node * n)541 static void process_L2pat (struct attrtab *attrtab, struct node *n)
542 {
543     struct attrvallist *av ;
544     vlan_t native ;
545 
546     av = attr_get_vallist (attrtab, "native") ;
547     if (av != NULL)
548     {
549 	if (sscanf (attr_get_val (av), "%d", &native) != 1)
550 	{
551 	    inconsistency ("Unrecognized native vlan (%s)", attr_get_val (av)) ;
552 	    exit (1) ;
553 	}
554 	n->u.l2pat.native = native ;
555     }
556     else
557     {
558 	n->u.l2pat.native = -1 ;
559     }
560 
561     av = attr_get_vallist (attrtab, "allow") ;
562     while (av != NULL)
563     {
564 	vlan_t v1, v2 ;
565 	struct vlanlist *vl ;
566 
567 	if (sscanf (attr_get_val (av), "%d %d", &v1, &v2) != 2)
568 	{
569 	    inconsistency ("Unrecognized vlan range (%s)", attr_get_val (av)) ;
570 	    exit (1) ;
571 	}
572 
573 	vl = mobj_alloc (vlistmobj, 1) ;
574 	vl->min = v1 ;
575 	vl->max = v2 ;
576 	vl->next = n->u.l2pat.allowed ;
577 	n->u.l2pat.allowed = vl ;
578 
579 	av = av->next ;
580     }
581 }
582 
process_brpat(struct attrtab * attrtab,struct node * n)583 static void process_brpat (struct attrtab *attrtab, struct node *n)
584 {
585     /* nothing to do for bridge patterns */
586 }
587 
588 struct attrcheck
589 {
590     char *attr ;
591     int minoccurr ;
592     int maxoccurr ;
593 } ;
594 
check_attr(struct attrtab * attrtab,struct attrcheck ac[])595 static int check_attr (struct attrtab *attrtab, struct attrcheck ac [])
596 {
597     int i ;
598     struct attrvallist *av ;
599     int noc ;
600 
601     for (i = 0 ; ac [i].attr != NULL ; i++)
602     {
603 	av = attr_get_vallist (attrtab, ac [i].attr) ;
604 	if (av == NULL)
605 	    noc = 0 ;
606 	else
607 	    noc = attr_get_nval (av) ;
608 
609 	if (noc < ac [i].minoccurr || noc > ac [i].maxoccurr)
610 	{
611 	    inconsistency ("Invalid number (%d) of '%s' values (should be in [%d..%d])",
612 			noc,  ac [i].attr, ac [i].minoccurr, ac [i].maxoccurr) ;
613 	    return 0 ;
614 	}
615     }
616 
617     /*
618      * XXX : we should test that every attribute mentionned for this
619      *		node is in the struct attrcheck array.
620      */
621 
622     return 1 ;
623 }
624 
process_eq(char * tab[0],int ntab)625 static void process_eq (char *tab [0], int ntab)
626 {
627     struct eq *eq ;
628     char *eqname ;
629     char *eqtype ;
630     char *eqmodel ;
631     char *eqsnmp ;
632     char *eqlocation ;
633     int eqmanual ;
634     int eqipmac ;
635     int eqportmac ;
636     struct attrtab *attrtab ;			/* head of attribute table */
637     struct attrvallist *av ;
638     static struct attrcheck eqattr [] = {
639 	{ "type", 1, 1},
640 	{ "model", 1, 1},
641 	{ "snmp", 1, 1},
642 	{ "location", 0, 1},
643 	{ "manual", 0, 1},
644 	{ "ipmac", 0, 1},
645 	{ "portmac", 0, 1},
646 	{ NULL, 0, 0}
647     } ;
648 
649 
650     if (ntab < 2)
651     {
652 	inconsistency ("Eq declaration has not enough attributes") ;
653 	exit (1) ;
654     }
655 
656     eqname = tab [1] ;
657     tab += 2 ;
658     ntab -= 2 ;
659 
660     /*
661      * Locate proper equipement
662      */
663 
664     eq = eq_get (eqname, 0) ;
665 
666     /*
667      * Parse all attributes
668      */
669 
670     attrtab = attr_init () ;
671     parse_attr (tab, ntab, &attrtab) ;
672 
673     if (! check_attr (attrtab, eqattr))
674     {
675 	inconsistency ("Incorrect eq attribute list") ;
676 	exit (1) ;
677     }
678 
679     av = attr_get_vallist (attrtab, "type") ;
680     if (av != NULL)
681 	eqtype = attr_get_val (av) ;
682     else
683     {
684 	inconsistency ("Should not happen : 'eq %s' without type", eqname) ;
685 	exit (1) ;
686     }
687 
688     av = attr_get_vallist (attrtab, "model") ;
689     if (av != NULL)
690 	eqmodel = attr_get_val (av) ;
691     else
692     {
693 	inconsistency ("Should not happen : 'eq %s' without model", eqname) ;
694 	exit (1) ;
695     }
696 
697     av = attr_get_vallist (attrtab, "snmp") ;
698     if (av != NULL)
699 	eqsnmp = attr_get_val (av) ;
700     else
701     {
702 	inconsistency ("Should not happen : 'eq %s' without SNMP community", eqname) ;
703 	exit (1) ;
704     }
705 
706     av = attr_get_vallist (attrtab, "location") ;
707     if (av != NULL)
708 	eqlocation = attr_get_val (av) ;
709     else
710     {
711 	inconsistency ("Should not happen : 'eq %s' without location", eqname) ;
712 	exit (1) ;
713     }
714 
715     av = attr_get_vallist (attrtab, "manual") ;
716     eqmanual = ((av == NULL) ? 1 : atoi (attr_get_val (av))) ;
717 
718     av = attr_get_vallist (attrtab, "ipmac") ;
719     eqipmac = ((av == NULL) ? 0 : atoi (attr_get_val (av))) ;
720 
721     av = attr_get_vallist (attrtab, "portmac") ;
722     eqportmac = ((av == NULL) ? 0 : atoi (attr_get_val (av))) ;
723 
724     eq->type = symtab_to_name (symtab_get (eqtype)) ;
725     eq->model = symtab_to_name (symtab_get (eqmodel)) ;
726     if (strcmp (eqsnmp, "-") == 0)
727 	eq->snmp = NULL ;
728     else eq->snmp = symtab_to_name (symtab_get (eqsnmp)) ;
729     if (strcmp (eqlocation, "-") == 0)
730 	eq->location = NULL ;
731     else eq->location = symtab_to_name (symtab_get (eqlocation)) ;
732     eq->manual = eqmanual ;
733     eq->ipmac = eqipmac ;
734     eq->portmac = eqportmac ;
735 
736     attr_close (attrtab) ;
737 }
738 
739 
740 #define MAXKWBYTYPE 20
741 
process_node(char * tab[],int ntab)742 static void process_node (char *tab [], int ntab)
743 {
744     int i ;
745     struct node *n ;
746     char *nodename ;
747     char *nodetype ;
748     struct eq *eq ;
749     struct attrtab *attrtab ;			/* head of attribute table */
750     struct attrvallist *av ;
751     static struct
752     {
753 	char *type ;
754 	enum nodetype nodetype ;
755 	void (*fct) (struct attrtab *, struct node *) ;
756 	struct attrcheck attr [MAXKWBYTYPE] ;
757     } attrbytype [] =
758     {
759 	{ "L1" , NT_L1,     process_L1, {
760 			{ "type", 1, 1 },
761 		        { "eq", 1, 1 },
762 		        { "name", 1, 1 },
763 		        { "desc", 1, 1 },
764 		        { "link", 1, 1 },
765 		        { "stat", 1, 1 },
766 		        { "encap", 1, 1 },
767 		        { "radio", 0, 1 },
768 		        { "ssid", 0, 1000000 },
769 			{ "net", 0, 1000000 },
770 		        { NULL, 0 },
771 	       },
772 	},
773 	{ "L2" , NT_L2,     process_L2, {
774 			{ "type", 1, 1 },
775 			{ "eq", 1, 1 },
776 			{ "vlan", 1, 1 },
777 		        { "stat", 1, 1 },
778 		        { "ifname", 1, 1 },
779 			{ "native", 0, 1 },
780 			{ NULL, 0 },
781 		},
782 	},
783 	{ "L3" , NT_L3,     process_L3, {
784 			{ "type", 1, 1 },
785 			{ "eq", 1, 1 },
786 			{ "addr", 1, 1 },
787 			{ NULL, 0 },
788 		},
789 	},
790 	{ "router" , NT_ROUTER, process_router, {
791 			{ "type", 1, 1 },
792 			{ "eq", 1, 1 },
793 			{ "instance", 1, 1 },
794 			{ NULL, 0 },
795 		    },
796 	},
797 	{ "bridge" , NT_BRIDGE, process_bridge, {
798 			{ "type", 1, 1 },
799 			{ "eq", 1, 1 },
800 			{ NULL, 0 },
801 		    },
802 	},
803 	{ "L2pat" , NT_L2PAT,  process_L2pat, {
804 			{ "type", 1, 1 },
805 			{ "eq", 1, 1 },
806 			{ "native", 0, 1 },
807 			{ "allow", 0, 1000000 },
808 			{ NULL, 0 },
809 		    },
810 	},
811 	{ "brpat" , NT_BRPAT,  process_brpat, {
812 			{ "type", 1, 1 },
813 			{ "eq", 1, 1 },
814 			{ NULL, 0 },
815 		    },
816 	},
817     } ;
818 
819 
820     if (ntab < 2)
821     {
822 	inconsistency ("Node has not enough attributes") ;
823 	exit (1) ;
824     }
825 
826     nodename = tab [1] ;
827     tab += 2 ;
828     ntab -= 2 ;
829 
830     /*
831      * Parse all attributes
832      */
833 
834     attrtab = attr_init () ;
835     parse_attr (tab, ntab, &attrtab) ;
836 
837     av = attr_get_vallist (attrtab, "type") ;
838     if (av == NULL)
839     {
840 	inconsistency ("Node '%s' has no type", nodename) ;
841 	exit (1) ;
842     }
843     nodetype = attr_get_val (av) ;
844 
845     /*
846      * Specific analysis given the nodetype
847      */
848 
849     for (i = 0 ; i < NTAB (attrbytype) ; i++)
850     {
851 	if (strcmp (nodetype, attrbytype [i].type) == 0)
852 	{
853 	    if (! check_attr (attrtab, attrbytype [i].attr))
854 	    {
855 		inconsistency ("Incorrect node attribute list") ;
856 		exit (1) ;
857 	    }
858 
859 	    eq = eq_get (attr_get_val (attr_get_vallist (attrtab, "eq")), 0) ;
860 
861 	    n = create_node (nodename, eq,  attrbytype [i].nodetype) ;
862 	    (*attrbytype [i].fct) (attrtab, n) ;
863 	    break ;
864 	}
865     }
866     if (i >= NTAB (attrbytype))
867     {
868 	inconsistency ("Unrecognized type '%s' for node '%s'", nodetype, nodename) ;
869 	exit (1) ;
870     }
871 
872     attr_close (attrtab) ;
873 }
874 
process_link(char * tab[],int ntab)875 static void process_link (char *tab [], int ntab)
876 {
877     char *linkname ;
878     char *n1, *n2 ;
879     struct attrtab *attrtab ;			/* head of attribute table */
880     struct attrvallist *av ;
881     static struct attrcheck linkattr [] = {
882 	{ "name", 0, 1},
883 	{ NULL, 0, 0}
884     } ;
885 
886     if (ntab < 3)
887     {
888 	inconsistency ("Link has not enough data") ;
889 	exit (1) ;
890     }
891 
892     n1 = tab [1] ;
893     n2 = tab [2] ;
894     tab += 3 ;
895     ntab -= 3 ;
896 
897     /*
898      * Parse all attributes
899      */
900 
901     attrtab = attr_init () ;
902     parse_attr (tab, ntab, &attrtab) ;
903 
904     if (! check_attr (attrtab, linkattr))
905     {
906 	inconsistency ("Incorrect link attribute list") ;
907 	exit (1) ;
908     }
909 
910     av = attr_get_vallist (attrtab, "name") ;
911     if (av != NULL)
912 	linkname = attr_get_val (av) ;
913     else linkname = NULL ;
914 
915     (void) create_link (linkname, n1, n2) ;
916 }
917 
process_static_routes(char * tab[],int ntab)918 struct route *process_static_routes (char *tab [], int ntab)
919 {
920     struct route *head, *r ;
921 
922     if (ntab % 2 != 0)
923     {
924 	inconsistency ("Odd number of route entries") ;
925 	exit (1) ;
926     }
927     head = NULL ;
928     while (ntab > 0)
929     {
930 	r = mobj_alloc (routemobj, 1) ;
931 
932 	if (! ip_pton (tab [0], &r->net))
933 	    inconsistency ("Route '%s'->'%s' has a bad address", tab [0], tab [1]) ;
934 	if (! ip_pton (tab [1], &r->gw))
935 	    inconsistency ("Route '%s'->'%s' has a bad gateway", tab [0], tab [1]) ;
936 
937 	r->next = head ;
938 	head = r ;
939 
940 	tab += 2 ;
941 	ntab -= 2 ;
942     }
943     return head ;
944 }
945 
process_rnet(char * tab[],int ntab)946 static void process_rnet (char *tab [], int ntab)
947 {
948     struct rnet *n ;
949     struct network *net ;
950     char *vrrpaddr ;
951 
952     if (ntab < 8)
953     {
954 	inconsistency ("Routed network has not enough data") ;
955 	exit (1) ;
956     }
957 
958     MOBJ_ALLOC_INSERT (n, rnetmobj) ;
959 
960     net = net_get_p (tab [1]) ;
961     if (net == NULL)
962 	error (0, "Cannot find a slot for net") ;
963     n->net = net ;
964 
965     n->router = check_node (tab [2], tab [1]) ;
966     n->l3     = check_node (tab [3], tab [1]) ;
967     n->l2     = check_node (tab [4], tab [1]) ;
968     n->l1     = check_node (tab [5], tab [1]) ;
969 
970     vrrpaddr = tab [6] ;
971     if (strcmp (vrrpaddr, "-") == 0)
972 	vrrpaddr = "0.0.0.0/0" ;
973     if (! ip_pton (vrrpaddr, &n->vrrpaddr))
974 	inconsistency ("Routed network '%s' has a bad VRRP address (%s)",
975 					tab [1], vrrpaddr) ;
976     n->vrrpprio = atoi (tab [7]) ;
977 
978     tab += 8 ;
979     ntab -= 8 ;
980     n->routelist = process_static_routes (tab, ntab) ;
981 }
982 
process_vlan(char * tab[],int ntab)983 static void process_vlan (char *tab [], int ntab)
984 {
985     int vlanid ;
986     char *id, *desc ;
987     struct attrtab *attrtab ;			/* head of attribute table */
988     struct attrvallist *av ;
989     static struct attrcheck vlanattr [] = {
990 	{ "desc", 1, 1},
991 	{ "voice",  1, 1},
992 	{ "net",  0, 100000},
993 	{ NULL, 0, 0}
994     } ;
995     struct vlan *tabvlan ;
996 
997     if (ntab < 2)
998     {
999 	inconsistency ("Vlan declaration has not enough attributes") ;
1000 	exit (1) ;
1001     }
1002 
1003     tabvlan = mobj_data (vlanmobj) ;
1004     vlanid = 0 ;
1005 
1006     id = tab [1] ;
1007     if (sscanf (id, "%d", &vlanid) != 1 || vlanid  >= MAXVLAN)
1008 	inconsistency ("Incorrect vlan-id ('%s')", id) ;
1009 
1010     tab += 2 ;
1011     ntab -= 2 ;
1012 
1013     /*
1014      * Parse all attributes
1015      */
1016 
1017     attrtab = attr_init () ;
1018     parse_attr (tab, ntab, &attrtab) ;
1019 
1020     if (! check_attr (attrtab, vlanattr))
1021     {
1022 	inconsistency ("Incorrect vlan attribute list") ;
1023 	exit (1) ;
1024     }
1025 
1026     av = attr_get_vallist (attrtab, "desc") ;
1027     if (av != NULL)
1028 	desc = symtab_to_name (symtab_get (attr_get_val (av))) ;
1029     else desc = NULL ;
1030     tabvlan [vlanid].name = desc ;
1031 
1032     av = attr_get_vallist (attrtab, "voice") ;
1033     tabvlan [vlanid].voice = (av == NULL) ? 0 : atoi (attr_get_val (av)) ;
1034 
1035     process_netlist (&tabvlan [vlanid].netlist, attrtab) ;
1036 
1037     attr_close (attrtab) ;
1038 }
1039 
process_lvlan(char * tab[],int ntab)1040 static void process_lvlan (char *tab [], int ntab)
1041 {
1042     int vlanid ;
1043     char *id, *eqname, *flag ;
1044     struct eq *eq ;
1045     struct attrtab *attrtab ;			/* head of attribute table */
1046     struct attrvallist *av ;
1047     static struct attrcheck lvlanattr [] = {
1048 	{ "desc",     1, 1},
1049 	{ "incoming", 0, 1},
1050 	{ "declared", 0, 1},
1051 	{ NULL, 0, 0}
1052     } ;
1053     struct vlan *tabvlan ;
1054     struct lvlan *lv ;
1055 
1056     if (ntab < 3)
1057     {
1058 	inconsistency ("Lvlan declaration has not enough attributes") ;
1059 	exit (1) ;
1060     }
1061 
1062 
1063     eqname = tab [1] ;
1064     id = tab [2] ;
1065     tab += 3 ;
1066     ntab -= 3 ;
1067 
1068     /*
1069      * Locate proper equipement
1070      */
1071 
1072     eq = eq_get (eqname, 0) ;
1073 
1074     /*
1075      * Translate vlan id
1076      */
1077 
1078     vlanid = 0 ;
1079     if (sscanf (id, "%d", &vlanid) != 1 || vlanid  >= MAXVLAN)
1080 	inconsistency ("Incorrect vlan-id ('%s')", id) ;
1081 
1082     tabvlan = mobj_data (vlanmobj) ;
1083 
1084     /*
1085      * Insert lvlan in vlan table
1086      */
1087 
1088     lv = mobj_alloc (lvlanmobj, 1) ;
1089 
1090     lv->next = tabvlan [vlanid].lvlan ;
1091     tabvlan [vlanid].lvlan = lv ;
1092 
1093     lv->vlanid = vlanid ;
1094     lv->eq = eq ;
1095     lv->name = NULL ;
1096     lv->mark = 0 ;
1097 
1098     /*
1099      * Parse all attributes
1100      */
1101 
1102     attrtab = attr_init () ;
1103     parse_attr (tab, ntab, &attrtab) ;
1104 
1105     if (! check_attr (attrtab, lvlanattr))
1106     {
1107 	inconsistency ("Incorrect lvlan attribute list") ;
1108 	exit (1) ;
1109     }
1110 
1111     av = attr_get_vallist (attrtab, "desc") ;
1112     if (av != NULL)
1113 	lv->name = symtab_to_name (symtab_get (attr_get_val (av))) ;
1114 
1115     av = attr_get_vallist (attrtab, "incoming") ;
1116     if (av != NULL)
1117     {
1118 	flag = attr_get_val (av) ;
1119 	if (strcmp (flag, "yes") == 0)
1120 	    lv->mark |= LVLAN_INCOMING ;
1121     }
1122 
1123     av = attr_get_vallist (attrtab, "declared") ;
1124     if (av != NULL)
1125     {
1126 	flag = attr_get_val (av) ;
1127 	if (strcmp (flag, "yes") == 0)
1128 	    lv->mark |= LVLAN_DECLARED ;
1129     }
1130 
1131     attr_close (attrtab) ;
1132 }
1133 
process_ssidprobe(char * tab[0],int ntab)1134 static void process_ssidprobe (char *tab [0], int ntab)
1135 {
1136     char *name ;				/* name of probe */
1137     char *eqname ;
1138     struct eq *eq ;
1139     char *ifname ;
1140     struct node *iface ;
1141     char *ssidname ;
1142     struct ssid *ssid ;
1143     char *mode ;
1144     enum ssidprobe_mode m ;
1145     struct ssidprobe *sp ;
1146     struct attrtab *attrtab ;			/* head of attribute table */
1147     struct attrvallist *av ;
1148     static struct attrcheck eqattr [] = {
1149 	{ "eq", 1, 1},
1150 	{ "iface", 1, 1},
1151 	{ "ssidname", 1, 1},
1152 	{ "mode", 1, 1},
1153 	{ NULL, 0, 0}
1154     } ;
1155 
1156 
1157     if (ntab < 2)
1158     {
1159 	inconsistency ("Ssidprobe declaration has not enough attributes") ;
1160 	exit (1) ;
1161     }
1162 
1163     name = symtab_to_name (symtab_get (tab [1])) ;
1164     tab += 2 ;
1165     ntab -= 2 ;
1166 
1167     /*
1168      * Parse all attributes
1169      */
1170 
1171     attrtab = attr_init () ;
1172     parse_attr (tab, ntab, &attrtab) ;
1173 
1174     if (! check_attr (attrtab, eqattr))
1175     {
1176 	inconsistency ("Incorrect eq attribute list") ;
1177 	exit (1) ;
1178     }
1179 
1180     av = attr_get_vallist (attrtab, "eq") ;
1181     if (av != NULL)
1182 	eqname = attr_get_val (av) ;
1183     else
1184     {
1185 	inconsistency ("Should not happen : 'ssidprobe %s' without eq", name) ;
1186 	exit (1) ;
1187     }
1188     eq = eq_get (eqname, 0) ;
1189 
1190     av = attr_get_vallist (attrtab, "iface") ;
1191     if (av != NULL)
1192 	ifname = attr_get_val (av) ;
1193     else
1194     {
1195 	inconsistency ("Should not happen : 'ssidprobe %s' without iface", name) ;
1196 	exit (1) ;
1197     }
1198     iface = symtab_to_node (symtab_get (ifname)) ;
1199     if (iface == NULL)
1200     {
1201 	inconsistency ("Interface '%s' not found for ssidprobe '%s'", ifname, name) ;
1202 	exit (1) ;
1203     }
1204     if (iface->eq != eq || iface->nodetype != NT_L1)
1205     {
1206 	inconsistency ("Interface '%s' not found on '%s' for ssidprobe '%s'", ifname, eq->name, name) ;
1207 	exit (1) ;
1208     }
1209 
1210     av = attr_get_vallist (attrtab, "ssidname") ;
1211     if (av != NULL)
1212 	ssidname = attr_get_val (av) ;
1213     else
1214     {
1215 	inconsistency ("Should not happen : 'ssidprobe %s' without ssidname", name) ;
1216 	exit (1) ;
1217     }
1218     ssidname = symtab_to_name (symtab_get (ssidname)) ;
1219     for (ssid = iface->u.l1.radio.ssid ; ssid != NULL ; ssid = ssid->next)
1220     {
1221 	if (ssid->name == ssidname)
1222 	    break ;
1223     }
1224     if (ssid == NULL)
1225     {
1226 	inconsistency ("Ssid '%s' not found for ssidprobe '%s'", ssidname, name) ;
1227 	exit (1) ;
1228     }
1229 
1230     av = attr_get_vallist (attrtab, "mode") ;
1231     if (av != NULL)
1232 	mode = attr_get_val (av) ;
1233     else
1234     {
1235 	inconsistency ("Should not happen : 'ssidprobe %s' without mode", name) ;
1236 	exit (1) ;
1237     }
1238     if (strcmp (mode, "assoc") == 0)
1239 	m = SSIDPROBE_ASSOC ;
1240     else if (strcmp (mode, "auth") == 0)
1241 	m = SSIDPROBE_AUTH ;
1242     else
1243     {
1244 	inconsistency ("Invalid mode '%s' for ssidprobe '%s'", mode, name) ;
1245 	exit (1) ;
1246     }
1247 
1248     /*
1249      * Object creation
1250      */
1251 
1252     MOBJ_ALLOC_INSERT (sp, ssidprobemobj) ;
1253 
1254     sp->name = name ;
1255     sp->eq = eq ;
1256     sp->l1 = iface ;
1257     sp->ssid = ssid ;
1258     sp->mode = m ;
1259 
1260     attr_close (attrtab) ;
1261 }
1262 
1263 
1264 
1265 /******************************************************************************
1266 The real function of this file
1267 ******************************************************************************/
1268 
text_read(FILE * fpin)1269 void text_read (FILE *fpin)
1270 {
1271     char orgline [MAXLINE] ;
1272     char line [MAXLINE] ;
1273     MOBJ *args ; char **argv ;
1274     char *p ;
1275     char *tok ;
1276     int n ;
1277 
1278     hashmobj  = mobj_init (sizeof (struct symtab *), MOBJ_CONST) ;
1279     symtab_init () ;
1280 
1281     symmobj       = mobj_init (sizeof (struct symtab   ), MOBJ_MALLOC) ;
1282     strmobj       = mobj_init (sizeof (char            ), MOBJ_MALLOC) ;
1283     nodemobj      = mobj_init (sizeof (struct node     ), MOBJ_MALLOC) ;
1284     linkmobj      = mobj_init (sizeof (struct link     ), MOBJ_MALLOC) ;
1285     llistmobj     = mobj_init (sizeof (struct linklist ), MOBJ_MALLOC) ;
1286     eqmobj        = mobj_init (sizeof (struct eq       ), MOBJ_MALLOC) ;
1287     lvlanmobj     = mobj_init (sizeof (struct lvlan    ), MOBJ_MALLOC) ;
1288     netmobj       = mobj_init (sizeof (struct network  ), MOBJ_MALLOC) ;
1289     nlistmobj     = mobj_init (sizeof (struct netlist  ), MOBJ_MALLOC) ;
1290     rnetmobj      = mobj_init (sizeof (struct rnet     ), MOBJ_MALLOC) ;
1291     routemobj     = mobj_init (sizeof (struct route    ), MOBJ_MALLOC) ;
1292     vlistmobj     = mobj_init (sizeof (struct vlanlist ), MOBJ_MALLOC) ;
1293     ssidmobj      = mobj_init (sizeof (struct ssid     ), MOBJ_MALLOC) ;
1294     ssidprobemobj = mobj_init (sizeof (struct ssidprobe), MOBJ_MALLOC) ;
1295 
1296     vlanmobj  = mobj_init (sizeof (struct vlan    ), MOBJ_CONST) ;
1297     mobj_alloc (vlanmobj, MAXVLAN) ;
1298 
1299     args = mobj_init (sizeof (char *), MOBJ_REALLOC) ;
1300 
1301     lineno = 0 ;
1302     while (fgets (line, sizeof line, fpin) != NULL)
1303     {
1304 	lineno++ ;
1305 	strcpy (orgline, line) ;	/* save a copy for later use */
1306 
1307 	p = strchr (line, '\n') ;
1308 	if (p != NULL)
1309 	    *p = '\0' ;
1310 
1311 	p = strchr (line, '#') ;	/* remove comments */
1312 	if (p != NULL)
1313 	    *p = '\0' ;
1314 
1315 	/*
1316 	 * Very simplistic syntax analysis
1317 	 */
1318 
1319 	p = line ;
1320 
1321 	mobj_empty (args) ;
1322 	(void) mobj_alloc (args, 1) ;	/* last NULL entry */
1323 
1324 	n = 0 ;
1325 	argv = mobj_data (args) ;
1326 	argv [n] = NULL ;
1327 
1328 	while ((tok = strsep (&p, " \t")) != NULL)
1329 	    if (tok [0] != '\0')
1330 	    {
1331 		(void) mobj_alloc (args, 1) ;
1332 		argv = mobj_data (args) ;
1333 		argv [n++] = tok ;
1334 		argv [n] = NULL ;
1335 	    }
1336 
1337 	argv = mobj_data (args) ;
1338 
1339 	if (argv [0] != NULL)
1340 	{
1341 	    if (strcmp (argv [0], "eq") == 0)
1342 		process_eq (argv, n) ;
1343 	    else if (strcmp (argv [0], "node") == 0)
1344 		process_node (argv, n) ;
1345 	    else if (strcmp (argv [0], "link") == 0)
1346 		process_link (argv, n) ;
1347 	    else if (strcmp (argv [0], "rnet") == 0)
1348 		process_rnet (argv, n) ;
1349 	    else if (strcmp (argv [0], "vlan") == 0)
1350 		process_vlan (argv, n) ;
1351 	    else if (strcmp (argv [0], "lvlan") == 0)
1352 		process_lvlan (argv, n) ;
1353 	    else if (strcmp (argv [0], "ssidprobe") == 0)
1354 		process_ssidprobe (argv, n) ;
1355 	    else
1356 	    {
1357 		inconsistency ("Unknown directive '%s'", argv [0]) ;
1358 		exit (1) ;
1359 	    }
1360 	}
1361 	else
1362 	    ;				/* ignore it */
1363     }
1364     lineno = -1 ;
1365 
1366     mobj_close (args) ;
1367 }
1368