Better boolean handling and more
[olsrd.git] / src / cfgparser / olsrd_conf.c
1 /*
2  * OLSR ad-hoc routing table management protocol config parser
3  * Copyright (C) 2004 Andreas T√łnnesen (andreto@olsr.org)
4  *
5  * This file is part of the olsr.org OLSR daemon.
6  *
7  * olsr.org is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * olsr.org is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with olsr.org; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  * 
21  * 
22  * $Id: olsrd_conf.c,v 1.11 2004/11/03 09:22:18 kattemat Exp $
23  *
24  */
25
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34
35 #include "olsrd_conf.h"
36
37
38 extern FILE *yyin;
39 extern int yyparse(void);
40
41
42 #ifdef MAKELIB
43
44 /* Build as DLL */
45
46 void __attribute__ ((constructor)) 
47 my_init(void);
48
49 void __attribute__ ((destructor)) 
50 my_fini(void);
51
52
53 /**
54  *Constructor
55  */
56 void
57 my_init()
58 {
59   /* Print plugin info to stdout */
60   printf("olsrd config file parser %s loaded\n", PARSER_VERSION);
61
62   return;
63 }
64
65 /**
66  *Destructor
67  */
68 void
69 my_fini()
70 {
71   printf("See you around!\n");
72   return;
73 }
74
75 #else
76
77 #ifdef MAKEBIN
78
79 /* Build as standalone binary */
80 int 
81 main(int argc, char *argv[])
82 {
83   struct olsrd_config *cnf;
84
85   if(argc == 1)
86     {
87       fprintf(stderr, "Usage: olsrd_cfgparser [filename] -print\n\n");
88       exit(EXIT_FAILURE);
89     }
90
91   if((cnf = olsrd_parse_cnf(argv[1])) != NULL)
92     {
93       if((argc > 2) && (!strcmp(argv[2], "-print")))
94         {
95           olsrd_print_cnf(cnf);  
96           olsrd_write_cnf(cnf, "./out.conf");
97         }
98       else
99         printf("Use -print to view parsed values\n");
100       printf("Configfile parsed OK\n");
101     }
102   else
103     {
104       printf("Failed parsing \"%s\"\n", argv[1]);
105     }
106
107   return 0;
108 }
109
110 #else
111
112 /* Build as part of olsrd */
113
114
115 #endif
116
117 #endif
118
119 struct olsrd_config *
120 olsrd_parse_cnf(char *filename)
121 {
122   struct olsr_if *in;
123
124   cnf = malloc(sizeof(struct olsrd_config));
125   if (cnf == NULL)
126     {
127       fprintf(stderr, "Out of memory %s\n", __func__);
128       return NULL;
129   }
130
131   set_default_cnf(cnf);
132
133   printf("Parsing file: \"%s\"\n", filename);
134
135   yyin = fopen(filename, "r");
136   
137   if (yyin == NULL)
138     {
139       fprintf(stderr, "Cannot open configuration file '%s': %s.\n",
140               filename, strerror(errno));
141       free(cnf);
142       return NULL;
143   }
144
145   current_line = 1;
146
147   if (yyparse() != 0)
148     {
149       fclose(yyin);
150       olsrd_free_cnf(cnf);
151       exit(0);
152     }
153   
154   fclose(yyin);
155
156
157   in = cnf->interfaces;
158
159   while(in)
160     {
161       /* set various stuff */
162       in->index = cnf->ifcnt++;
163       in->configured = FALSE;
164       in->interf = NULL;
165       in = in->next;
166     }
167
168
169   return cnf;
170 }
171
172
173 void
174 olsrd_free_cnf(struct olsrd_config *cnf)
175 {
176   struct hna4_entry        *h4d, *h4 = cnf->hna4_entries;
177   struct hna6_entry        *h6d, *h6 = cnf->hna6_entries;
178   struct olsr_if           *ind, *in = cnf->interfaces;
179   struct plugin_entry      *ped, *pe = cnf->plugins;
180   struct if_config_options *iod, *io;
181   
182   while(h4)
183     {
184       h4d = h4;
185       h4 = h4->next;
186       free(h4d);
187     }
188
189   while(h6)
190     {
191       h6d = h6;
192       h6 = h6->next;
193       free(h6d);
194     }
195
196   while(in)
197     {
198       io = in->cnf;
199       while(io)
200         {
201           iod = io;
202           io = io->next;
203           free(iod);
204         }
205       ind = in;
206       in = in->next;
207       free(ind->name);
208       free(ind->config);
209       free(ind);
210     }
211
212   while(pe)
213     {
214       ped = pe;
215       pe = pe->next;
216       free(ped->name);
217       free(ped);
218     }
219
220   return;
221 }
222
223
224
225 struct olsrd_config *
226 olsrd_get_default_cnf()
227 {
228   cnf = malloc(sizeof(struct olsrd_config));
229   if (cnf == NULL)
230     {
231       fprintf(stderr, "Out of memory %s\n", __func__);
232       return NULL;
233   }
234
235   set_default_cnf(cnf);
236
237   return cnf;
238 }
239
240
241
242
243 void
244 set_default_cnf(struct olsrd_config *cnf)
245 {
246     memset(cnf, 0, sizeof(struct olsrd_config));
247     
248     cnf->debug_level = DEF_DEBUGLVL;
249     cnf->ip_version  = AF_INET;
250     cnf->allow_no_interfaces = DEF_ALLOW_NO_INTS;
251     cnf->tos = DEF_TOS;
252     cnf->willingness_auto = DEF_WILL_AUTO;
253     cnf->open_ipc = DEF_OPEN_IPC;
254
255     cnf->use_hysteresis = DEF_USE_HYST;
256     cnf->hysteresis_param.scaling = HYST_SCALING;
257     cnf->hysteresis_param.thr_high = HYST_THRESHOLD_HIGH;
258     cnf->hysteresis_param.thr_low = HYST_THRESHOLD_LOW;
259
260     cnf->pollrate = DEF_POLLRATE;
261
262     cnf->tc_redundancy = TC_REDUNDANCY;
263     cnf->mpr_coverage = MPR_COVERAGE;
264 }
265
266
267
268
269 struct if_config_options *
270 get_default_if_config()
271 {
272   struct if_config_options *io = malloc(sizeof(struct if_config_options));
273   struct in6_addr in6;
274  
275   memset(io, 0, sizeof(struct if_config_options));
276
277   io->ipv6_addrtype = 1; /* XXX - FixMe */
278
279   if(inet_pton(AF_INET6, OLSR_IPV6_MCAST_SITE_LOCAL, &in6) < 0)
280     {
281       fprintf(stderr, "Failed converting IP address %s\n", OLSR_IPV6_MCAST_SITE_LOCAL);
282       exit(EXIT_FAILURE);
283     }
284   memcpy(&io->ipv6_multi_site.v6, &in6, sizeof(struct in6_addr));
285
286   if(inet_pton(AF_INET6, OLSR_IPV6_MCAST_GLOBAL, &in6) < 0)
287     {
288       fprintf(stderr, "Failed converting IP address %s\n", OLSR_IPV6_MCAST_GLOBAL);
289       exit(EXIT_FAILURE);
290     }
291   memcpy(&io->ipv6_multi_glbl.v6, &in6, sizeof(struct in6_addr));
292
293
294   io->hello_params.emission_interval = HELLO_INTERVAL;
295   io->hello_params.validity_time = NEIGHB_HOLD_TIME;
296   io->tc_params.emission_interval = TC_INTERVAL;
297   io->tc_params.validity_time = TOP_HOLD_TIME;
298   io->mid_params.emission_interval = MID_INTERVAL;
299   io->mid_params.validity_time = MID_HOLD_TIME;
300   io->hna_params.emission_interval = HNA_INTERVAL;
301   io->hna_params.validity_time = HNA_HOLD_TIME;
302
303   return io;
304
305 }
306
307
308
309
310
311 int
312 olsrd_write_cnf(struct olsrd_config *cnf, char *fname)
313 {
314   struct hna4_entry        *h4 = cnf->hna4_entries;
315   struct hna6_entry        *h6 = cnf->hna6_entries;
316   struct olsr_if           *in = cnf->interfaces;
317   struct plugin_entry      *pe = cnf->plugins;
318   struct plugin_param      *pp;
319   char ipv6_buf[100];             /* buffer for IPv6 inet_htop */
320   struct in_addr in4;
321
322   FILE *fd;
323
324   fd = fopen(fname, "w");
325
326   if(fd == NULL)
327     {
328       fprintf(stderr, "Could not open file %s for writing\n%s\n", fname, strerror(errno));
329       return -1;
330     }
331
332   printf("Writing config to file \"%s\".... ", fname);
333
334   fprintf(fd, "#\n# Configuration file for olsr.org olsrd\n# automatically generated by olsrd-cnf %s\n#\n\n\n", PARSER_VERSION);
335
336   /* Debug level */
337   fprintf(fd, "# Debug level(0-9)\n# If set to 0 the daemon runs in the background\n\nDebugLevel\t%d\n\n", cnf->debug_level);
338
339   /* IP version */
340   if(cnf->ip_version == AF_INET6)
341     fprintf(fd, "# IP version to use (4 or 6)\n\nIpVersion\t6\n\n");
342   else
343     fprintf(fd, "# IP version to use (4 or 6)\n\nIpVersion\t4\n\n");
344
345
346   /* HNA IPv4 */
347   fprintf(fd, "# HNA IPv4 routes\n# syntax: netaddr netmask\n# Example Internet gateway:\n# 0.0.0.0 0.0.0.0\n\nHna4\n{\n");
348   while(h4)
349     {
350       in4.s_addr = h4->net.v4;
351       fprintf(fd, "    %s ", inet_ntoa(in4));
352       in4.s_addr = h4->netmask.v4;
353       fprintf(fd, "%s\n", inet_ntoa(in4));
354       h4 = h4->next;
355     }
356   fprintf(fd, "}\n\n");
357
358
359   /* HNA IPv6 */
360   fprintf(fd, "# HNA IPv6 routes\n# syntax: netaddr prefix\n# Example Internet gateway:\nHna6\n{\n");
361   while(h6)
362     {
363       fprintf(fd, "    %s/%d\n", (char *)inet_ntop(AF_INET6, &h6->net.v6, ipv6_buf, sizeof(ipv6_buf)), h6->prefix_len);
364       h6 = h6->next;
365     }
366
367   fprintf(fd, "}\n\n");
368
369   /* No interfaces */
370   fprintf(fd, "# Should olsrd keep on running even if there are\n# no interfaces available? This is a good idea\n# for a PCMCIA/USB hotswap environment.\n# \"yes\" OR \"no\"\n\nAllowNoInt\t");
371   if(cnf->allow_no_interfaces)
372     fprintf(fd, "yes\n\n");
373   else
374     fprintf(fd, "no\n\n");
375
376   /* TOS */
377   fprintf(fd, "# TOS(type of service) value for\n# the IP header of control traffic.\n# default is 16\n\n");
378   fprintf(fd, "TosValue\t%d\n\n", cnf->tos);
379
380   /* Willingness */
381   fprintf(fd, "# The fixed willingness to use(0-7)\n# If not set willingness will be calculated\n# dynammically based on battery/power status\n\n");
382   if(cnf->willingness_auto)
383     fprintf(fd, "#Willingness\t4\n\n");
384   else
385     fprintf(fd, "Willingness%d\n\n", cnf->willingness);
386
387   /* IPC */
388   fprintf(fd, "# Allow processes like the GUI front-end\n# to connect to the daemon. 'yes' or 'no'\n\n");
389   if(cnf->open_ipc)
390     fprintf(fd, "IpcConnect\tyes\n\n");
391   else
392     fprintf(fd, "IpcConnect\tno\n\n");
393
394
395
396   /* Hysteresis */
397   fprintf(fd, "# Wether to use hysteresis or not\n# Hysteresis adds more robustness to the\n# link sensing but delays neighbor registration.\n# Used by default. 'yes' or 'no'\n\n");
398
399   if(cnf->use_hysteresis)
400     {
401       fprintf(fd, "UseHysteresis\tyes\n\n");
402       fprintf(fd, "# Hysteresis parameters\n# Do not alter these unless you know \n# what you are doing!\n# Set to auto by default. Allowed\n# values are floating point values\n# in the interval 0,1\n# THR_LOW must always be lower than\n# THR_HIGH!!\n\n");
403       fprintf(fd, "HystScaling\t%0.2f\n", cnf->hysteresis_param.scaling);
404       fprintf(fd, "HystThrHigh\t%0.2f\n", cnf->hysteresis_param.thr_high);
405       fprintf(fd, "HystThrLow\t%0.2f\n", cnf->hysteresis_param.thr_low);
406     }
407   else
408     fprintf(fd, "UseHysteresis\tno\n\n");
409
410   fprintf(fd, "\n\n");
411
412   /* Pollrate */
413   fprintf(fd, "# Polling rate in seconds(float).\n# Auto uses default value 0.1 sec\n\n");
414   fprintf(fd, "Pollrate\t%0.2f\n", cnf->pollrate);
415
416   /* TC redundancy */
417   fprintf(fd, "# TC redundancy\n# Specifies how much neighbor info should\n# be sent in TC messages\n# Possible values are:\n# 0 - only send MPR selectors\n# 1 - send MPR selectors and MPRs\n# 2 - send all neighbors\n#\n# defaults to 0\n\n");
418   fprintf(fd, "TcRedundancy\t%d\n\n", cnf->tc_redundancy);
419
420   /* MPR coverage */
421   fprintf(fd, "# MPR coverage\n# Specifies how many MPRs a node should\n# try select to reach every 2 hop neighbor\n# Can be set to any integer >0\n# defaults to 1\n\n");
422
423   fprintf(fd, "MprCoverage\t%d\n\n", cnf->mpr_coverage);
424    
425
426
427   /* Plugins */
428   fprintf(fd, "# Olsrd plugins to load\n# This must be the absolute path to the file\n# or the loader will use the following scheme:\n# - Try the paths in the LD_LIBRARY_PATH \n#   environment variable.\n# - The list of libraries cached in /etc/ld.so.cache\n# - /lib, followed by /usr/lib\n\n");
429   if(pe)
430     {
431       while(pe)
432         {
433           fprintf(fd, "LoadPlugin \"%s\"\n{\n", pe->name);
434           pp = pe->params;
435           while(pp)
436             {
437               fprintf(fd, "    PlParam \"%s\" \"%s\"\n", pp->key, pp->value);
438               pp = pp->next;
439             }
440           fprintf(fd, "}\n");
441           pe = pe->next;
442         }
443     }
444   fprintf(fd, "\n");
445
446   
447   
448
449   /* Interfaces */
450   fprintf(fd, "# Interfaces\n\n");
451   /* Interfaces */
452   if(in)
453     {
454       while(in)
455         {
456           fprintf(fd, "Interface \"%s\"\n{\n", in->name);
457           fprintf(fd, "\n");
458       
459           fprintf(fd, "    # IPv4 broadcast address to use. The\n    # one usefull example would be 255.255.255.255\n    # If not defined the broadcastaddress\n    # every card is configured with is used\n\n");
460
461           if(in->cnf->ipv4_broadcast.v4)
462             {
463               in4.s_addr = in->cnf->ipv4_broadcast.v4;
464               fprintf(fd, "    Ip4Broadcast\t %s\n\n", inet_ntoa(in4));
465             }
466           else
467             {
468               fprintf(fd, "    #Ip4Broadcast\t255.255.255.255\n\n");
469             }
470           
471           
472           fprintf(fd, "    # IPv6 address scope to use.\n    # Must be 'site-local' or 'global'\n\n");
473           if(in->cnf->ipv6_addrtype)
474             fprintf(fd, "    Ip6AddrType \tsite-local\n\n");
475           else
476             fprintf(fd, "    Ip6AddrType \tglobal\n\n");
477           
478           fprintf(fd, "    # IPv6 multicast address to use when\n    # using site-local addresses.\n    # If not defined, ff05::15 is used\n");
479           fprintf(fd, "    Ip6MulticastSite\t%s\n\n", (char *)inet_ntop(AF_INET6, &in->cnf->ipv6_multi_site.v6, ipv6_buf, sizeof(ipv6_buf)));
480           fprintf(fd, "    # IPv6 multicast address to use when\n    # using global addresses\n    # If not defined, ff0e::1 is used\n");
481           fprintf(fd, "    Ip6MulticastGlobal\t%s\n\n", (char *)inet_ntop(AF_INET6, &in->cnf->ipv6_multi_glbl.v6, ipv6_buf, sizeof(ipv6_buf)));
482           
483           
484           
485           fprintf(fd, "    # Emission and validity intervals.\n    # If not defined, RFC proposed values will\n    # in most cases be used.\n\n");
486           
487           
488           if(in->cnf->hello_params.emission_interval != HELLO_INTERVAL)
489             fprintf(fd, "    HelloInterval\t%0.2f\n", in->cnf->hello_params.emission_interval);
490           else
491             fprintf(fd, "    #HelloInterval\t%0.2f\n", in->cnf->hello_params.emission_interval);
492           if(in->cnf->hello_params.validity_time != NEIGHB_HOLD_TIME)
493             fprintf(fd, "    HelloValidityTime\t%0.2f\n", in->cnf->hello_params.validity_time);
494           else
495             fprintf(fd, "    #HelloValidityTime\t%0.2f\n", in->cnf->hello_params.validity_time);
496           if(in->cnf->tc_params.emission_interval != TC_INTERVAL)
497             fprintf(fd, "    TcInterval\t\t%0.2f\n", in->cnf->tc_params.emission_interval);
498           else
499             fprintf(fd, "    #TcInterval\t\t%0.2f\n", in->cnf->tc_params.emission_interval);
500           if(in->cnf->tc_params.validity_time != TOP_HOLD_TIME)
501             fprintf(fd, "    TcValidityTime\t%0.2f\n", in->cnf->tc_params.validity_time);
502           else
503             fprintf(fd, "    #TcValidityTime\t%0.2f\n", in->cnf->tc_params.validity_time);
504           if(in->cnf->mid_params.emission_interval != MID_INTERVAL)
505             fprintf(fd, "    MidInterval\t\t%0.2f\n", in->cnf->mid_params.emission_interval);
506           else
507             fprintf(fd, "    #MidInterval\t%0.2f\n", in->cnf->mid_params.emission_interval);
508           if(in->cnf->mid_params.validity_time != MID_HOLD_TIME)
509             fprintf(fd, "    MidValidityTime\t%0.2f\n", in->cnf->mid_params.validity_time);
510           else
511             fprintf(fd, "    #MidValidityTime\t%0.2f\n", in->cnf->mid_params.validity_time);
512           if(in->cnf->hna_params.emission_interval != HNA_INTERVAL)
513             fprintf(fd, "    HnaInterval\t\t%0.2f\n", in->cnf->hna_params.emission_interval);
514           else
515             fprintf(fd, "    #HnaInterval\t%0.2f\n", in->cnf->hna_params.emission_interval);
516           if(in->cnf->hna_params.validity_time != HNA_HOLD_TIME)
517             fprintf(fd, "    HnaValidityTime\t%0.2f\n", in->cnf->hna_params.validity_time);       
518           else
519             fprintf(fd, "    #HnaValidityTime\t%0.2f\n", in->cnf->hna_params.validity_time);      
520           
521           
522           
523           fprintf(fd, "}\n\n");
524           in = in->next;
525         }
526
527     }
528
529
530   fprintf(fd, "\n# END AUTOGENERATED CONFIG\n");
531
532   fclose(fd);
533   printf("DONE\n");
534
535   return 1;
536 }
537
538
539
540
541
542 void
543 olsrd_print_cnf(struct olsrd_config *cnf)
544 {
545   struct hna4_entry        *h4 = cnf->hna4_entries;
546   struct hna6_entry        *h6 = cnf->hna6_entries;
547   struct olsr_if           *in = cnf->interfaces;
548   struct plugin_entry      *pe = cnf->plugins;
549   char ipv6_buf[100];             /* buffer for IPv6 inet_htop */
550   struct in_addr in4;
551
552   printf(" *** olsrd configuration ***\n");
553
554   printf("Debug Level      : %d\n", cnf->debug_level);
555   printf("IpVersion        : %d\n", cnf->ip_version);
556   if(cnf->allow_no_interfaces)
557     printf("No interfaces    : ALLOWED\n");
558   else
559     printf("No interfaces    : NOT ALLOWED\n");
560   printf("TOS              : 0x%02x\n", cnf->tos);
561   if(cnf->willingness_auto)
562     printf("Willingness      : AUTO\n");
563   else
564     printf("Willingness      : %d\n", cnf->willingness);
565
566   if(cnf->open_ipc)
567     printf("IPC              : ENABLED\n");
568   else
569     printf("IPC              : DISABLED\n");
570
571   printf("Pollrate         : %0.2f\n", cnf->pollrate);
572
573   printf("TC redundancy    : %d\n", cnf->tc_redundancy);
574
575   printf("MPR coverage     : %d\n", cnf->mpr_coverage);
576    
577   /* Interfaces */
578   if(in)
579     {
580       printf("Interfaces:\n");
581       while(in)
582         {
583           printf(" dev: \"%s\"\n", in->name);
584           
585           if(in->cnf->ipv4_broadcast.v4)
586             {
587               in4.s_addr = in->cnf->ipv4_broadcast.v4;
588               printf("\tIPv4 broadcast        : %s\n", inet_ntoa(in4));
589             }
590           else
591             {
592               printf("\tIPv4 broadcast        : AUTO\n");
593             }
594           
595           if(in->cnf->ipv6_addrtype)
596             printf("\tIPv6 addrtype         : site-local\n");
597           else
598             printf("\tIPv6 addrtype         : global\n");
599           
600           //union olsr_ip_addr       ipv6_multi_site;
601           //union olsr_ip_addr       ipv6_multi_glbl;
602           printf("\tIPv6 multicast site   : %s\n", (char *)inet_ntop(AF_INET6, &in->cnf->ipv6_multi_site.v6, ipv6_buf, sizeof(ipv6_buf)));
603           printf("\tIPv6 multicast global : %s\n", (char *)inet_ntop(AF_INET6, &in->cnf->ipv6_multi_glbl.v6, ipv6_buf, sizeof(ipv6_buf)));
604           
605           printf("\tHELLO emission int    : %0.2f\n", in->cnf->hello_params.emission_interval);
606           printf("\tHELLO validity time   : %0.2f\n", in->cnf->hello_params.validity_time);
607           printf("\tTC emission int       : %0.2f\n", in->cnf->tc_params.emission_interval);
608           printf("\tTC validity time      : %0.2f\n", in->cnf->tc_params.validity_time);
609           printf("\tMID emission int      : %0.2f\n", in->cnf->mid_params.emission_interval);
610           printf("\tMID validity time     : %0.2f\n", in->cnf->mid_params.validity_time);
611           printf("\tHNA emission int      : %0.2f\n", in->cnf->hna_params.emission_interval);
612           printf("\tHNA validity time     : %0.2f\n", in->cnf->hna_params.validity_time);
613           
614           
615           
616           in = in->next;
617
618         }
619     }
620
621
622
623
624   /* Plugins */
625   if(pe)
626     {
627       printf("Plugins:\n");
628
629       while(pe)
630         {
631           printf("\tName: \"%s\"\n", pe->name);
632           pe = pe->next;
633         }
634     }
635
636   /* Hysteresis */
637   if(cnf->use_hysteresis)
638     {
639       printf("Using hysteresis:\n");
640       printf("\tScaling : %0.2f\n", cnf->hysteresis_param.scaling);
641       printf("\tThr high: %0.2f\n", cnf->hysteresis_param.thr_high);
642       printf("\tThr low : %0.2f\n", cnf->hysteresis_param.thr_low);
643     }
644   else
645     printf("Not using hysteresis\n");
646
647   /* HNA IPv4 */
648   if(h4)
649     {
650
651       printf("HNA4 entries:\n");
652       while(h4)
653         {
654           in4.s_addr = h4->net.v4;
655           printf("\t%s/", inet_ntoa(in4));
656           in4.s_addr = h4->netmask.v4;
657           printf("%s\n", inet_ntoa(in4));
658
659           h4 = h4->next;
660         }
661     }
662
663   /* HNA IPv6 */
664   if(h6)
665     {
666       printf("HNA6 entries:\n");
667       while(h6)
668         {
669           printf("\t%s/%d\n", (char *)inet_ntop(AF_INET6, &h6->net.v6, ipv6_buf, sizeof(ipv6_buf)), h6->prefix_len);
670           h6 = h6->next;
671         }
672     }
673 }
674
675