Major overhaul and cleanup on read and parse functions
[olsrd.git] / lib / quagga / src / quagga.c
1
2 /***************************************************************************
3  projekt              : olsrd-quagga
4  file                 : quagga.c
5  usage                : communication with the zebra-daemon
6  copyright            : (C) 2006 by Immo 'FaUl' Wehrenberg
7  e-mail               : immo@chaostreff-dortmund.de
8  ***************************************************************************/
9
10 /***************************************************************************
11  *                                                                         *
12  *   This program is free software; you can redistribute it and/or modify  *
13  *   it under the terms of the GNU General Public License version 2 as     *
14  *   published by the Free Software Foundation.                            *
15  *                                                                         *
16  ***************************************************************************/
17
18 #define HAVE_SOCKLEN_T
19
20 #include "quagga.h"
21 #include "olsr.h"
22 #include "log.h"
23 #include "defs.h"
24 #include "routing_table.h"
25
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36
37 #ifdef USE_UNIX_DOMAIN_SOCKET
38 #include <sys/un.h>
39 #define ZEBRA_SOCKET "/var/run/quagga/zserv.api"
40 #endif
41
42 #define ZEBRA_MAX_PACKET_SIZ            4096
43
44 #define ZEBRA_IPV4_ROUTE_ADD            7
45 #define ZEBRA_IPV4_ROUTE_DELETE         8
46 #define ZEBRA_REDISTRIBUTE_ADD          11
47 #define ZEBRA_REDISTRIBUTE_DELETE       12
48 #define ZEBRA_MESSAGE_MAX               23
49
50 #define ZEBRA_ROUTE_OLSR                11
51 #define ZEBRA_ROUTE_MAX                 13
52
53 #define ZEBRA_FLAG_SELECTED             0x10
54
55 #define ZEBRA_NEXTHOP_IFINDEX           1
56 #define ZEBRA_NEXTHOP_IPV4              3
57 #define ZEBRA_NEXTHOP_IPV4_IFINDEX      4
58
59 #define ZAPI_MESSAGE_NEXTHOP  0x01
60 #define ZAPI_MESSAGE_IFINDEX  0x02
61 #define ZAPI_MESSAGE_DISTANCE 0x04
62 #define ZAPI_MESSAGE_METRIC   0x08
63
64 #define BUFSIZE 1024
65
66 #define STATUS_CONNECTED 1
67 #define OPTION_EXPORT 1
68
69 static struct {
70   char status;                         // internal status
71   char options;                        // internal options
72   int sock;                            // Socket to zebra...
73   char redistribute[ZEBRA_ROUTE_MAX];
74   char distance;
75   char flags;
76   struct ipv4_route *v4_rt;            // routes currently exportet to zebra
77 } zebra;
78
79 /* prototypes intern */
80 static unsigned char *zebra_route_packet(uint16_t, struct ipv4_route *);
81 static struct ipv4_route *zebra_parse_route (unsigned char *);
82 static unsigned char *try_read(ssize_t *);
83 #if 0
84 static int parse_interface_add(unsigned char *, size_t);
85 static int parse_interface_delete(unsigned char *, size_t);
86 static int parse_interface_up(unsigned char *, size_t);
87 static int parse_interface_down(unsigned char *, size_t);
88 static int parse_interface_address_add(unsigned char *, size_t);
89 static int parse_interface_address_delete(unsigned char *, size_t);
90 static int ipv4_route_add(unsigned char *, size_t);
91 static int ipv4_route_delete(unsigned char *, size_t);
92 static int parse_ipv6_route_add(unsigned char *, size_t);
93 static void zebra_reconnect(void);
94 #endif
95 static void zebra_connect(void);
96 static void free_ipv4_route(struct ipv4_route *);
97 #if 0
98
99 /*
100 static void update_olsr_zebra_routes (struct ipv4_route*, struct ipv4_route*);
101 static struct ipv4_route *zebra_create_ipv4_route_table_entry (uint32_t,
102                                                                uint32_t,
103                                                                uint32_t);
104 static struct ipv4_route *zebra_create_ipv4_route_table (void);
105 static void zebra_free_ipv4_route_table (struct ipv4_route*);
106 */
107 #endif
108
109 /*static uint8_t masktoprefixlen (uint32_t);*/
110
111 void *
112 my_realloc(void *buf, size_t s, const char *c)
113 {
114   buf = realloc(buf, s);
115   if (!buf) {
116     OLSR_PRINTF(1, "(QUAGGA) OUT OF MEMORY: %s\n", strerror(errno));
117     olsr_syslog(OLSR_LOG_ERR, "olsrd: out of memory!: %m\n");
118     olsr_exit(c, EXIT_FAILURE);
119   }
120   return buf;
121 }
122
123 void
124 init_zebra(void)
125 {
126   zebra_connect();
127   if (!(zebra.status & STATUS_CONNECTED))
128     olsr_exit("(QUAGGA) AIIIII, could not connect to zebra! is zebra running?", EXIT_FAILURE);
129 }
130
131 void
132 zebra_cleanup(void)
133 {
134   int i;
135   struct rt_entry *tmp;
136
137   if (zebra.options & OPTION_EXPORT) {
138     OLSR_FOR_ALL_RT_ENTRIES(tmp) {
139       zebra_del_route(tmp);
140     }
141     OLSR_FOR_ALL_RT_ENTRIES_END(tmp);
142   }
143
144   for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
145     if (zebra.redistribute[i])
146       zebra_disable_redistribute(i);
147 }
148
149 #if 0
150 static void
151 zebra_reconnect(void)
152 {
153   struct rt_entry *tmp;
154   int i;
155
156   zebra_connect();
157   if (!(zebra.status & STATUS_CONNECTED))
158     return;                     // try again next time
159
160   if (zebra.options & OPTION_EXPORT) {
161     OLSR_FOR_ALL_RT_ENTRIES(tmp) {
162       zebra_add_route(tmp);
163     }
164     OLSR_FOR_ALL_RT_ENTRIES_END(tmp);
165   }
166
167   for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
168     if (zebra.redistribute[i])
169       zebra_redistribute(i + 1);
170   /* Zebra sends us all routes of type it knows after
171      zebra_redistribute(type) */
172 }
173 #endif
174
175 /* Connect to the zebra-daemon, returns a socket */
176 static void
177 zebra_connect(void)
178 {
179
180   int ret;
181
182 #ifndef USE_UNIX_DOMAIN_SOCKET
183   struct sockaddr_in i;
184   if (close(zebra.sock) < 0)
185     olsr_exit("(QUAGGA) Could not close socket!", EXIT_FAILURE);
186
187   zebra.sock = socket(AF_INET, SOCK_STREAM, 0);
188 #else
189   struct sockaddr_un i;
190   if (close(zebra.sock) < 0)
191     olsr_exit("(QUAGGA) Could not close socket!", EXIT_FAILURE);
192
193   zebra.sock = socket(AF_UNIX, SOCK_STREAM, 0);
194 #endif
195
196   if (zebra.sock < 0)
197     olsr_exit("(QUAGGA) Could not create socket!", EXIT_FAILURE);
198
199   memset(&i, 0, sizeof i);
200 #ifndef USE_UNIX_DOMAIN_SOCKET
201   i.sin_family = AF_INET;
202   i.sin_port = htons(ZEBRA_PORT);
203   i.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
204 #else
205   i.sun_family = AF_UNIX;
206   strscpy(i.sun_path, ZEBRA_SOCKET, sizeof(i.sun_path));
207 #endif
208
209   ret = connect(zebra.sock, (struct sockaddr *)&i, sizeof i);
210   if (ret < 0)
211     zebra.status &= ~STATUS_CONNECTED;
212   else
213     zebra.status |= STATUS_CONNECTED;
214 }
215
216 /* Sends a command to zebra, command is
217    the command defined in zebra.h, options is the packet-payload,
218    optlen the length, of the payload */
219 int
220 zebra_send_command(unsigned char *options)
221 {
222
223   unsigned char *pnt;
224   uint16_t len;
225   int ret;
226
227   if (!(zebra.status & STATUS_CONNECTED))
228     return 0;
229
230   pnt = options;
231   memcpy(&len, pnt, 2);
232
233   len = ntohs(len);
234
235   do {
236     ret = write(zebra.sock, pnt, len);
237     if (ret < 0) {
238       if ((errno == EINTR) || (errno == EAGAIN)) {
239         errno = 0;
240         ret = 0;
241         continue;
242       } else {
243         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra\n");
244         zebra.status &= ~STATUS_CONNECTED;
245         free(options);
246         return -1;
247       }
248     }
249     pnt = pnt + ret;
250   } while ((len -= ret));
251   free(options);
252   return 0;
253 }
254
255 /* Creates a Route-Packet-Payload, needs address, netmask, nexthop,
256    distance, and a pointer of an size_t */
257 static unsigned char *
258 zebra_route_packet(uint16_t cmd, struct ipv4_route *r)
259 {
260
261   int count;
262   uint8_t len;
263   uint16_t size;
264   uint32_t ind, metric;
265
266   unsigned char *cmdopt, *t;
267
268   cmdopt = olsr_malloc(ZEBRA_MAX_PACKET_SIZ, "zebra add_v4_route");
269
270   t = &cmdopt[2];
271   *t++ = cmd;
272   *t++ = r->type;
273   *t++ = r->flags;
274   *t++ = r->message;
275   *t++ = r->prefixlen;
276   len = (r->prefixlen + 7) / 8;
277   memcpy(t, &r->prefix.v4.s_addr, len);
278   t = t + len;
279
280   if (r->message & ZAPI_MESSAGE_NEXTHOP) {
281     *t++ = r->nh_count + r->ind_num;
282
283       for (count = 0; count < r->nh_count; count++) {
284         *t++ = ZEBRA_NEXTHOP_IPV4;
285         memcpy(t, &r->nexthop[count].v4.s_addr, sizeof r->nexthop[count].v4.s_addr);
286         t += sizeof r->nexthop[count].v4.s_addr;
287       }
288       for (count = 0; count < r->ind_num; count++) {
289         *t++ = ZEBRA_NEXTHOP_IFINDEX;
290         ind = htonl(r->index[count]);
291         memcpy(t, &ind, sizeof ind);
292         t += sizeof ind;
293       }
294   }
295   if ((r->message & ZAPI_MESSAGE_DISTANCE) > 0)
296     *t++ = r->distance;
297   if ((r->message & ZAPI_MESSAGE_METRIC) > 0) {
298     metric = htonl(r->metric);
299     memcpy(t, &metric, sizeof metric);
300     t += sizeof metric;
301   }
302   size = htons(t - cmdopt);
303   memcpy(cmdopt, &size, 2);
304
305   return cmdopt;
306 }
307
308 #if 0
309 /* adds a route to zebra-daemon */
310 int
311 zebra_add_v4_route(const struct ipv4_route r)
312 {
313
314   unsigned char *cmdopt;
315   ssize_t optlen;
316   int retval;
317
318   cmdopt = zebra_route_packet(r, &optlen);
319
320   retval = zebra_send_command(ZEBRA_IPV4_ROUTE_ADD, cmdopt, optlen);
321   free(cmdopt);
322   return retval;
323
324 }
325
326 /* deletes a route from the zebra-daemon */
327 int
328 zebra_delete_v4_route(struct ipv4_route r)
329 {
330
331   unsigned char *cmdopt;
332   ssize_t optlen;
333   int retval;
334
335   cmdopt = zebra_route_packet(r, &optlen);
336
337   retval = zebra_send_command(ZEBRA_IPV4_ROUTE_DELETE, cmdopt, optlen);
338   free(cmdopt);
339
340   return retval;
341
342 }
343 #endif
344
345 /* Check wether there is data from zebra aviable */
346 void
347 zebra_parse(void *foo __attribute__ ((unused)))
348 {
349   unsigned char *data, *f;
350   unsigned char command;
351   uint16_t length;
352   ssize_t len;
353   struct ipv4_route *route;
354
355   if (!(zebra.status & STATUS_CONNECTED)) {
356 //    zebra_reconnect();
357     return;
358   }
359   data = try_read(&len);
360   if (data) {
361     f = data;
362     OLSR_PRINTF(1, "length zebra_parse %u\n", (unsigned int) len);
363     do {
364       memcpy(&length, f, sizeof length);
365       length = ntohs (length);
366       if (!length) // something wired happened
367         olsr_exit("(QUAGGA) Zero message length??? ", EXIT_FAILURE);
368       command = f[2];
369       switch (command) {
370         case ZEBRA_IPV4_ROUTE_ADD:
371           route = zebra_parse_route(f);
372           ip_prefix_list_add(&olsr_cnf->hna_entries, &route->prefix, route->prefixlen);
373           free_ipv4_route(route);
374           free(route);
375           break;
376         case ZEBRA_IPV4_ROUTE_DELETE:
377           route = zebra_parse_route(f);
378           ip_prefix_list_remove(&olsr_cnf->hna_entries, &route->prefix, route->prefixlen);
379           free_ipv4_route(route);
380           free(route);
381           break;
382         default:
383           break;
384       }
385       f += length;
386     }
387     while ((f - data) < len);
388     free(data);
389   }
390 }
391
392 // tries to read a packet from zebra_socket
393 // if there is something to read - make sure to read whole packages
394 static unsigned char *
395 try_read(ssize_t * len)
396 {
397   unsigned char *buf = NULL;
398   ssize_t ret = 0, bsize = 0;
399   uint16_t length = 0, l = 0;
400   int sockstate;
401
402   *len = 0;
403
404   sockstate = fcntl(zebra.sock, F_GETFL, 0);
405   fcntl(zebra.sock, F_SETFL, sockstate | O_NONBLOCK);
406
407   do {
408     if (*len == bsize) {
409       bsize += BUFSIZE;
410       buf = my_realloc(buf, bsize, "Zebra try_read");
411     }
412     ret = read (zebra.sock, buf + *len, bsize - *len);
413     if (!ret) {                 // nothing more to read, packet is broken, discard!
414       free(buf);
415       return NULL;
416     }
417
418     if (ret < 0) {
419       if (errno != EAGAIN) {    // oops - we got disconnected
420         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra\n");
421         zebra.status &= ~STATUS_CONNECTED;
422       }
423       free(buf);
424       return NULL;
425     }
426
427     *len += ret;
428     do {
429       memcpy(&length, buf + l, 2);
430       length = ntohs(length);
431       l += length;
432     } while (*len > l);
433     if (*len < l)
434       fcntl(zebra.sock, F_SETFL, sockstate);
435   }
436   while (*len != l); // GOT FULL PACKAGE!!
437
438   fcntl(zebra.sock, F_SETFL, sockstate);
439   return buf;
440 }
441
442 #if 0
443 /* Parse a packet recived from zebra */
444 int
445 zebra_parse_packet(unsigned char *packet, ssize_t maxlen)
446 {
447
448   uint16_t command;
449   int skip;
450
451   /* Array of functions */
452   int (*foo[ZEBRA_MESSAGE_MAX]) (unsigned char *, size_t) = {
453   parse_interface_add, parse_interface_delete, parse_interface_address_add, parse_interface_address_delete, parse_interface_up,
454       parse_interface_down, ipv4_route_add, ipv4_route_delete, parse_ipv6_route_add};
455
456   uint16_t length;
457   int ret;
458
459   memcpy(&length, packet, 2);
460   length = ntohs(length);
461
462   if (maxlen < length) {
463     OLSR_PRINTF(1, "(QUAGGA) maxlen = %lu, packet_length = %d\n", (unsigned long)maxlen, length);
464     olsr_exit("(QUAGGA) programmer is an idiot", EXIT_FAILURE);
465   }
466 #ifdef ZEBRA_HEADER_MARKER
467   if (packet[2] == 255) {       // found header marker!!
468     //packet[3] == ZSERV_VERSION: FIXME: HANDLE THIS!
469     memcpy(&command, packet + 4, sizeof command);       // two bytes command now!
470     command = ntohs(command) - 1;
471     skip = 6;
472   }
473 #else
474   command = packet[2] - 1;
475   skip = 3;
476 #endif
477
478   if (command < ZEBRA_MESSAGE_MAX && foo[command]) {
479     if (!(ret = foo[command] (packet + skip, length - skip)))
480       return length;
481     else
482       OLSR_PRINTF(1, "(QUAGGA) Parse error: %d\n", ret);
483   } else
484     OLSR_PRINTF(1, "(QUAGGA) Unknown packet type: %d\n", packet[2]);
485
486   OLSR_PRINTF(1, "(Quagga) RECIVED PACKET FROM ZEBRA THAT I CAN'T PARSE");
487
488   return length;
489 }
490
491 static int
492 parse_interface_add(unsigned char *opt __attribute__ ((unused)), size_t len __attribute__ ((unused)))
493 {
494   //todo
495   return 0;
496 }
497
498 static int
499 parse_interface_delete(unsigned char *opt __attribute__ ((unused)), size_t len __attribute__ ((unused)))
500 {
501   //todo
502   return 0;
503 }
504
505 static int
506 parse_interface_address_add(unsigned char *opt __attribute__ ((unused)), size_t len __attribute__ ((unused)))
507 {
508
509   //todo
510   return 0;
511 }
512
513 static int
514 parse_interface_up(unsigned char *opt __attribute__ ((unused)), size_t len __attribute__ ((unused)))
515 {
516
517   //todo
518   return 0;
519 }
520
521 static int
522 parse_interface_down(unsigned char *opt __attribute__ ((unused)), size_t len __attribute__ ((unused)))
523 {
524
525   //todo
526   return 0;
527 }
528
529 static int
530 parse_interface_address_delete(unsigned char *opt __attribute__ ((unused)), size_t len __attribute__ ((unused)))
531 {
532   //todo
533   return 0;
534 }
535 #endif
536
537 /* Parse an ipv4-route-packet recived from zebra
538  */
539 struct ipv4_route
540 *zebra_parse_route(unsigned char *opt)
541 {
542   struct ipv4_route *r;
543   int c;
544   size_t size;
545   uint16_t length;
546   unsigned char *pnt;
547
548   memcpy(&length, opt, sizeof length);
549   length = ntohs (length);
550
551   r = olsr_malloc(sizeof *r, "zebra_parse_route");
552   pnt = &opt[3];
553   r->type = *pnt++;
554   r->flags = *pnt++;
555   r->message = *pnt++;
556   r->prefixlen = *pnt++;
557   r->prefix.v4.s_addr = 0;
558
559   size = (r->prefixlen + 7) / 8;
560   memcpy(&r->prefix.v4.s_addr, pnt, size);
561   pnt += size;
562
563   if (r->message & ZAPI_MESSAGE_NEXTHOP) {
564     r->nh_count = *pnt++;
565     r->nexthop = olsr_malloc((sizeof *r->nexthop) * r->nh_count, "quagga: zebra_parse_route");
566     for (c = 0; c < r->nh_count; c++) {
567       memcpy(&r->nexthop[c].v4.s_addr, pnt, sizeof r->nexthop[c].v4.s_addr);
568       pnt += sizeof r->nexthop[c].v4.s_addr;
569     }
570   }
571
572   if (r->message & ZAPI_MESSAGE_IFINDEX) {
573     r->ind_num = *pnt++;
574     r->index = olsr_malloc(sizeof(uint32_t) * r->ind_num, "quagga: zebra_parse_route");
575     for (c = 0; c < r->ind_num; c++) {
576       memcpy(&r->index[c], pnt, sizeof r->index[c]);
577       r->index[c] = ntohl (r->index[c]);
578       pnt += sizeof r->index[c];
579     }
580   }
581
582   if (r->message & ZAPI_MESSAGE_DISTANCE) {
583     r->distance = *pnt++;
584   }
585
586 // Quagga v0.98.6 BUG workaround: metric is always sent by zebra
587 // even without ZAPI_MESSAGE_METRIC message.
588 //  if (r.message & ZAPI_MESSAGE_METRIC) {
589     memcpy(&r->metric, pnt, sizeof (uint32_t));
590     r->metric = ntohl(r->metric);
591     pnt += sizeof r->metric;
592 //  }
593
594   OLSR_PRINTF(1, "%u \n", (unsigned int) (pnt-opt));
595
596   if (pnt - opt != length) {
597     olsr_exit("(QUAGGA) length does not match ??? ", EXIT_FAILURE);
598   }
599
600   return r;
601 }
602
603 #if 0
604 static int
605 ipv4_route_add(unsigned char *opt, size_t len)
606 {
607
608   struct ipv4_route r;
609   int f;
610
611   f = parse_ipv4_route(opt, len, &r);
612   if (f < 0)
613     return f;
614
615   return add_hna4_route(r);
616 }
617
618 static int
619 ipv4_route_delete(unsigned char *opt, size_t len)
620 {
621   struct ipv4_route r;
622   int f;
623
624   f = parse_ipv4_route(opt, len, &r);
625   if (f < 0)
626     return f;
627
628   return delete_hna4_route(r);
629
630 }
631
632 static int
633 parse_ipv6_route_add(unsigned char *opt __attribute__ ((unused)), size_t len __attribute__ ((unused)))
634 {
635   //todo
636   return 0;
637 }
638 #endif
639
640 static unsigned char
641 *zebra_redistribute_packet (unsigned char cmd, unsigned char type)
642 {
643   unsigned char *data, *pnt;
644   uint16_t size;
645
646   data = olsr_malloc(ZEBRA_MAX_PACKET_SIZ , "zebra_redistribute_packet");
647
648   pnt = &data[2];
649   *pnt++ = cmd;
650   *pnt++ = type;
651   size = htons(pnt - data);
652   memcpy(data, &size, 2);
653
654   return data;
655 }
656
657 /* start redistribution FROM zebra */
658 int
659 zebra_redistribute(unsigned char type)
660 {
661
662   if (zebra_send_command(zebra_redistribute_packet(ZEBRA_REDISTRIBUTE_ADD, type)) < 0)
663     olsr_exit("(QUAGGA) could not send redistribute add command", EXIT_FAILURE);
664
665   if (type > ZEBRA_ROUTE_MAX - 1)
666     return -1;
667   zebra.redistribute[type] = 1;
668
669   return 0;
670
671 }
672
673 /* end redistribution FROM zebra */
674 int
675 zebra_disable_redistribute(unsigned char type)
676 {
677
678   if (zebra_send_command(zebra_redistribute_packet(ZEBRA_REDISTRIBUTE_DELETE, type)) < 0)
679     olsr_exit("(QUAGGA) could not send redistribute delete command", EXIT_FAILURE);
680
681   if (type > ZEBRA_ROUTE_MAX - 1)
682     return -1;
683   zebra.redistribute[type] = 0;
684
685   return 0;
686
687 }
688
689 #if 0
690 int
691 add_hna4_route(struct ipv4_route r)
692 {
693   union olsr_ip_addr net;
694
695   net.v4.s_addr = r.prefix;
696
697   ip_prefix_list_add(&olsr_cnf->hna_entries, &net, r.prefixlen);
698   free_ipv4_route(r);
699   return 0;
700 }
701
702 int
703 delete_hna4_route(struct ipv4_route r)
704 {
705
706   union olsr_ip_addr net;
707
708   net.v4.s_addr = r.prefix;
709
710   ip_prefix_list_remove(&olsr_cnf->hna_entries, &net, r.prefixlen);
711   free_ipv4_route(r);
712   return 0;
713
714 }
715 #endif
716
717 static void
718 free_ipv4_route(struct ipv4_route *r)
719 {
720
721   if(r->ind_num)
722     free(r->index);
723   if(r->nh_count)
724     free(r->nexthop);
725
726 }
727
728 /*
729 static uint8_t masktoprefixlen (uint32_t mask) {
730
731   uint8_t prefixlen = 0;
732
733   mask = htonl (mask);
734
735   if (mask) while (mask << ++prefixlen && prefixlen < 32);
736
737   return prefixlen;
738
739 }
740 */
741
742 int
743 zebra_add_route(const struct rt_entry *r)
744 {
745
746   struct ipv4_route route;
747   int retval;
748
749   route.distance = 0;
750   route.type = ZEBRA_ROUTE_OLSR;
751   route.flags = zebra.flags;
752   route.message = ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_METRIC;
753   route.prefixlen = r->rt_dst.prefix_len;
754   route.prefix.v4.s_addr = r->rt_dst.prefix.v4.s_addr;
755   route.ind_num = 0;
756   route.index = NULL;
757   route.nh_count = 0;
758   route.nexthop = NULL;
759
760   if (r->rt_best->rtp_nexthop.gateway.v4.s_addr == r->rt_dst.prefix.v4.s_addr && route.prefixlen == 32) {
761     return 0;                   /* Quagga BUG workaround: don't add routes with destination = gateway
762                                    see http://lists.olsr.org/pipermail/olsr-users/2006-June/001726.html */
763     route.ind_num++;
764     route.index = olsr_malloc(sizeof *route.index, "zebra_add_route");
765     *route.index = r->rt_best->rtp_nexthop.iif_index;
766   } else {
767     route.nh_count++;
768     route.nexthop = olsr_malloc(sizeof *route.nexthop, "zebra_add_route");
769     route.nexthop->v4.s_addr = r->rt_best->rtp_nexthop.gateway.v4.s_addr;
770   }
771
772   route.metric = r->rt_best->rtp_metric.hops;
773
774   if (zebra.distance) {
775     route.message |= ZAPI_MESSAGE_DISTANCE;
776     route.distance = zebra.distance;
777   }
778
779   retval = zebra_send_command(zebra_route_packet(ZEBRA_IPV4_ROUTE_ADD, &route));
780
781   return retval;
782 }
783
784 int
785 zebra_del_route(const struct rt_entry *r)
786 {
787
788   struct ipv4_route route;
789   int retval;
790   route.distance = 0;
791   route.type = ZEBRA_ROUTE_OLSR;
792   route.flags = zebra.flags;
793   route.message = ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_METRIC;
794   route.prefixlen = r->rt_dst.prefix_len;
795   route.prefix.v4.s_addr = r->rt_dst.prefix.v4.s_addr;
796   route.ind_num = 0;
797   route.index = NULL;
798   route.nh_count = 0;
799   route.nexthop = NULL;
800
801   if (r->rt_nexthop.gateway.v4.s_addr == r->rt_dst.prefix.v4.s_addr && route.prefixlen == 32) {
802     return 0;                   /* Quagga BUG workaround: don't delete routes with destination = gateway
803                                    see http://lists.olsr.org/pipermail/olsr-users/2006-June/001726.html */
804     route.ind_num++;
805     route.index = olsr_malloc(sizeof *route.index, "zebra_del_route");
806     *route.index = r->rt_nexthop.iif_index;
807   } else {
808     route.nh_count++;
809     route.nexthop = olsr_malloc(sizeof *route.nexthop, "zebra_del_route");
810     route.nexthop->v4.s_addr = r->rt_nexthop.gateway.v4.s_addr;
811   }
812
813   route.metric = 0;
814
815   if (zebra.distance) {
816     route.message |= ZAPI_MESSAGE_DISTANCE;
817     route.distance = zebra.distance;
818   }
819
820   retval = zebra_send_command(zebra_route_packet(ZEBRA_IPV4_ROUTE_DELETE, &route));
821
822   return retval;
823 }
824
825 void
826 zebra_olsr_distance(unsigned char dist)
827 {
828   zebra.distance = dist;
829 }
830
831 void
832 zebra_olsr_localpref(void)
833 {
834   zebra.flags &= ZEBRA_FLAG_SELECTED;
835 }
836
837 void
838 zebra_export_routes(unsigned char t)
839 {
840   if (t)
841     zebra.options |= OPTION_EXPORT;
842   else
843     zebra.options &= ~OPTION_EXPORT;
844 }
845
846 /*
847  * Local Variables:
848  * c-basic-offset: 2
849  * indent-tabs-mode: nil
850  * End:
851  */