28f69470b19ce71967732e47452a72e9984769aa
[olsrd.git] / lib / txtinfo / src / olsrd_txtinfo.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in
14  *   the documentation and/or other materials provided with the
15  *   distribution.
16  * * Neither the name of olsr.org, olsrd nor the names of its
17  *   contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
35  * If you find this software useful feel free to make a donation
36  * to the project. For more information see the website or contact
37  * the copyright holders.
38  *
39  */
40
41 /*
42  * Dynamic linked library for the olsr.org olsr daemon
43  */
44 #include "olsrd_txtinfo.h"
45 #include "olsr.h"
46 #include "ipcalc.h"
47 #include "neighbor_table.h"
48 #include "two_hop_neighbor_table.h"
49 #include "mpr_selector_set.h"
50 #include "tc_set.h"
51 #include "hna_set.h"
52 #include "mid_set.h"
53 #include "routing_table.h"
54 #include "log.h"
55 #include "misc.h"
56 #include "olsr_ip_prefix_list.h"
57
58 #include "common/autobuf.h"
59
60 #include <unistd.h>
61 #include <errno.h>
62
63 #ifdef WIN32
64 #undef EWOULDBLOCK
65 #undef EAGAIN
66 #define EWOULDBLOCK WSAEWOULDBLOCK
67 #define EAGAIN WSAEWOULDBLOCK
68 #undef errno
69 #define errno WSAGetLastError()
70 #undef SHUT_WR
71 #define SHUT_WR SD_SEND
72 #undef strerror
73 #define strerror(x) StrError(x)
74 #define read(fd,buf,size) recv((fd), (buf), (size), 0)
75 #define write(fd,buf,size) send((fd), (buf), (size), 0)
76 #endif
77
78
79 struct ipc_conn {
80     struct autobuf resp;
81     int respstart;
82     int requlen;
83     char requ[256];
84 };
85
86 static int listen_socket = -1;
87
88
89 static void conn_destroy(struct ipc_conn *);
90
91 static void ipc_action(int, void *, unsigned int);
92
93 static void ipc_http(int, void *, unsigned int);
94
95 static void ipc_http_read(int, struct ipc_conn *);
96
97 static void ipc_http_read_dummy(int, struct ipc_conn *);
98
99 static void ipc_http_write(int, struct ipc_conn *);
100
101 static int send_info(struct ipc_conn *, int);
102
103 static int ipc_print_neigh(struct ipc_conn *);
104
105 static int ipc_print_link(struct ipc_conn *);
106
107 static int ipc_print_routes(struct ipc_conn *);
108
109 static int ipc_print_topology(struct ipc_conn *);
110
111 static int ipc_print_hna_entry(struct autobuf *, const struct olsr_ip_prefix *, const union olsr_ip_addr *);
112 static int ipc_print_hna(struct ipc_conn *);
113
114 static int ipc_print_mid(struct ipc_conn *);
115
116 #define isprefix(str, pre) (strncmp((str), (pre), strlen(pre)) == 0)
117
118 #define SIW_NEIGH       (1 << 0)
119 #define SIW_LINK        (1 << 1)
120 #define SIW_ROUTE       (1 << 2)
121 #define SIW_HNA         (1 << 3)
122 #define SIW_MID         (1 << 4)
123 #define SIW_TOPO        (1 << 5)
124 #define SIW_ALL         (SIW_NEIGH|SIW_LINK|SIW_ROUTE|SIW_HNA|SIW_MID|SIW_TOPO)
125
126 /**
127  * destructor - called at unload
128  */
129 void olsr_plugin_exit(void)
130 {
131     CLOSESOCKET(listen_socket);
132 }
133
134 /**
135  *Do initialization here
136  *
137  *This function is called by the my_init
138  *function in uolsrd_plugin.c
139  */
140 int
141 olsrd_plugin_init(void)
142 {
143     struct sockaddr_storage sst;
144     uint32_t yes = 1;
145     socklen_t addrlen;
146
147     /* Init ipc socket */
148     listen_socket = socket(olsr_cnf->ip_version, SOCK_STREAM, 0);
149     if (listen_socket == -1) {
150 #ifndef NODEBUG
151         OLSR_PRINTF(1, "(TXTINFO) socket()=%s\n", strerror(errno));
152 #endif
153         return 0;
154     }
155     if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
156 #ifndef NODEBUG
157         OLSR_PRINTF(1, "(TXTINFO) setsockopt()=%s\n", strerror(errno));
158 #endif
159         CLOSESOCKET(listen_socket);
160         return 0;
161     }
162
163 #if defined __FreeBSD__ && defined SO_NOSIGPIPE
164     if (setsockopt(listen_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) {
165         perror("SO_REUSEADDR failed");
166         CLOSESOCKET(listen_socket);
167         return 0;
168     }
169 #endif
170     /* Bind the socket */
171
172     /* complete the socket structure */
173     memset(&sst, 0, sizeof(sst));
174     if (olsr_cnf->ip_version == AF_INET) {
175         struct sockaddr_in *addr4 = (struct sockaddr_in *)&sst;
176         addr4->sin_family = AF_INET;
177         addrlen = sizeof(*addr4);
178 #ifdef SIN6_LEN
179         addr4->sin_len = addrlen;
180 #endif
181         addr4->sin_addr.s_addr = INADDR_ANY;
182         addr4->sin_port = htons(ipc_port);
183     } else {
184         struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&sst;
185         addr6->sin6_family = AF_INET6;
186         addrlen = sizeof(*addr6);
187 #ifdef SIN6_LEN
188         addr6->sin6_len = addrlen;
189 #endif
190         addr6->sin6_addr = in6addr_any;
191         addr6->sin6_port = htons(ipc_port);
192     }
193
194     /* bind the socket to the port number */
195     if (bind(listen_socket, (struct sockaddr *)&sst, addrlen) == -1) {
196 #ifndef NODEBUG
197         OLSR_PRINTF(1, "(TXTINFO) bind()=%s\n", strerror(errno));
198 #endif
199         CLOSESOCKET(listen_socket);
200         return 0;
201     }
202
203     /* show that we are willing to listen */
204     if (listen(listen_socket, 1) == -1) {
205 #ifndef NODEBUG
206         OLSR_PRINTF(1, "(TXTINFO) listen()=%s\n", strerror(errno));
207 #endif
208         CLOSESOCKET(listen_socket);
209         return 0;
210     }
211
212     /* Register with olsrd */
213     add_olsr_socket(listen_socket, NULL, &ipc_action, NULL, SP_IMM_READ);
214
215 #ifndef NODEBUG
216     OLSR_PRINTF(2, "(TXTINFO) listening on port %d\n",ipc_port);
217 #endif
218     return 1;
219 }
220
221 /* destroy the connection */
222 static void conn_destroy(struct ipc_conn *conn)
223 {
224     abuf_free(&conn->resp);
225     free(conn);
226 }
227
228 static void kill_connection(int fd, struct ipc_conn *conn)
229 {
230     remove_olsr_socket(fd, NULL, &ipc_http);
231     CLOSESOCKET(fd);
232     conn_destroy(conn);
233 }
234
235 static void ipc_action(int fd, void *data __attribute__((unused)), unsigned int flags __attribute__((unused)))
236 {
237     struct ipc_conn *conn;
238     struct sockaddr_storage pin;
239 #ifndef NODEBUG
240     char addr[INET6_ADDRSTRLEN];
241 #endif
242     socklen_t addrlen = sizeof(pin);
243     int http_connection = accept(fd, (struct sockaddr *)&pin, &addrlen);
244     union olsr_ip_addr *ipaddr;
245
246     if (http_connection == -1) {
247         /* this may well happen if the other side immediately closes the connection. */
248 #ifndef NODEBUG
249         OLSR_PRINTF(1, "(TXTINFO) accept()=%s\n", strerror(errno));
250 #endif
251         return;
252     }
253
254     /* check if we want ot speak with it */
255     if(olsr_cnf->ip_version == AF_INET) {
256       struct sockaddr_in *addr4 = (struct sockaddr_in *)&pin;
257       ipaddr = (union olsr_ip_addr *)&addr4->sin_addr;
258     } else {
259       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&pin;
260       ipaddr = (union olsr_ip_addr *)&addr6->sin6_addr;
261     }
262
263     if (!ip_acl_acceptable(&allowed_nets, ipaddr, olsr_cnf->ip_version)) {
264       OLSR_PRINTF(1, "(TXTINFO) From host(%s) not allowed!\n", addr);
265       CLOSESOCKET(http_connection);
266       return;
267     }
268 #ifndef NODEBUG
269     OLSR_PRINTF(2, "(TXTINFO) Connect from %s\n",addr);
270 #endif
271
272     /* make the fd non-blocking */
273     if (set_nonblocking(http_connection) < 0) {
274         CLOSESOCKET(http_connection);
275         return;
276     }
277
278     conn = malloc(sizeof(*conn));
279     if (conn == NULL) {
280         OLSR_WARN(LOG_PLUGINS, "(TXTINFO) Out of memory!");
281         CLOSESOCKET(http_connection);
282         return;
283     }
284     conn->requlen = 0;
285     *conn->requ = '\0';
286     conn->respstart = 0;
287     abuf_init(&conn->resp, 1000);
288     add_olsr_socket(http_connection, NULL, &ipc_http, conn, SP_IMM_READ);
289 }
290
291 static void ipc_http_read_dummy(int fd, struct ipc_conn *conn)
292 {
293     /* just read dummy stuff */
294     ssize_t bytes_read;
295     char dummybuf[128];
296     do {
297         bytes_read = read(fd, dummybuf, sizeof(dummybuf));
298     } while (bytes_read > 0);
299     if (bytes_read == 0) {
300         /* EOF */
301         if (conn->respstart < conn->resp.len && conn->resp.len > 0) {
302             disable_olsr_socket(fd, NULL, &ipc_http, SP_IMM_READ);
303             conn->requlen = -1;
304             return;
305         }
306     } else if (errno == EINTR || errno == EAGAIN) {
307         /* ignore interrupted sys-calls */
308         return;
309     }
310     /* we had either an error or EOF and we are completely done */
311     kill_connection(fd, conn);
312 }
313
314 static void ipc_http_read(int fd, struct ipc_conn *conn)
315 {
316     int send_what;
317     const char *p;
318     ssize_t bytes_read = read(fd, conn->requ+conn->requlen, sizeof(conn->requ)-conn->requlen-1); /* leave space for a terminating '\0' */
319     if (bytes_read < 0) {
320         if (errno == EINTR || errno == EAGAIN) {
321             return;
322         }
323         OLSR_WARN(LOG_PLUGINS, "(TXTINFO) read error: %s", strerror(errno));
324         kill_connection(fd, conn);
325         return;
326     }
327     conn->requlen += bytes_read;
328     conn->requ[conn->requlen] = '\0';
329
330     /* look if we have the necessary info. We get here somethign like "GET /path HTTP/1.0" */
331     p = strchr(conn->requ, '/');
332     if (p == NULL) {
333         /* input buffer full ? */
334         if ((sizeof(conn->requ)-conn->requlen-1) == 0) {
335           kill_connection(fd, conn);
336           return;
337         }
338         /* we didn't get all. Wait for more data. */
339         return;
340     }
341     if (isprefix(p, "/neighbours")) send_what=SIW_LINK|SIW_NEIGH;
342     else if (isprefix(p, "/neigh")) send_what=SIW_NEIGH;
343     else if (isprefix(p, "/link")) send_what=SIW_LINK;
344     else if (isprefix(p, "/route")) send_what=SIW_ROUTE;
345     else if (isprefix(p, "/hna")) send_what=SIW_HNA;
346     else if (isprefix(p, "/mid")) send_what=SIW_MID;
347     else if (isprefix(p, "/topo")) send_what=SIW_TOPO;
348     else send_what = SIW_ALL;
349
350     if (send_info(conn, send_what) < 0) {
351         kill_connection(fd, conn);
352         return;
353     }
354     enable_olsr_socket(fd, NULL, &ipc_http, SP_IMM_WRITE);
355 }
356
357 static void ipc_http_write(int fd, struct ipc_conn *conn)
358 {
359     ssize_t bytes_written = write(fd, conn->resp.buf+conn->respstart,
360       conn->resp.len-conn->respstart);
361     if (bytes_written < 0) {
362         if (errno == EINTR || errno == EAGAIN) {
363             return;
364         }
365         OLSR_WARN(LOG_PLUGINS, "(TXTINFO) write error: %s", strerror(errno));
366         kill_connection(fd, conn);
367         return;
368     }
369     conn->respstart += bytes_written;
370     if (conn->respstart >= conn->resp.len) {
371         /* we are done. */
372         if (conn->requlen < 0) {
373             /* we are completely done. */
374             kill_connection(fd, conn);
375         } else if (shutdown(fd, SHUT_WR) < 0) {
376             kill_connection(fd, conn);
377         } else {
378             disable_olsr_socket(fd, NULL, &ipc_http, SP_IMM_WRITE);
379         }
380     }
381 }
382
383 static void ipc_http(int fd, void *data, unsigned int flags)
384 {
385     struct ipc_conn *conn = data;
386     if ((flags & SP_IMM_READ) != 0) {
387         if (conn->resp.len > 0) {
388             ipc_http_read_dummy(fd, conn);
389         } else {
390             ipc_http_read(fd, conn);
391         }
392     }
393     if ((flags & SP_IMM_WRITE) != 0) {
394         ipc_http_write(fd, conn);
395     }
396 }
397
398
399 static int ipc_print_neigh(struct ipc_conn *conn)
400 {
401     struct neighbor_entry *neigh;
402
403     if (abuf_appendf(&conn->resp, "Table: Neighbors\nIP address\tSYM\tMPR\tMPRS\tWill.\t2 Hop Neighbors\n") < 0) {
404         return -1;
405     }
406
407     /* Neighbors */
408     OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
409         struct neighbor_2_list_entry *list_2;
410         struct ipaddr_str buf1;
411         int thop_cnt = 0;
412         for (list_2 = neigh->neighbor_2_list.next;
413              list_2 != &neigh->neighbor_2_list;
414              list_2 = list_2->next) {
415             thop_cnt++;
416         }
417         if (abuf_appendf(&conn->resp,
418                             "%s\t%s\t%s\t%s\t%d\t%d\n",
419                             olsr_ip_to_string(&buf1, &neigh->neighbor_main_addr),
420                             neigh->status == SYM ? "YES" : "NO",
421                             neigh->is_mpr ? "YES" : "NO",
422                             olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO",
423                             neigh->willingness,
424                             thop_cnt) < 0) {
425             return -1;
426         }
427     } OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
428     if (abuf_appendf(&conn->resp, "\n") < 0) {
429         return -1;
430     }
431     return 0;
432 }
433
434 static int ipc_print_link(struct ipc_conn *conn)
435 {
436     struct link_entry *lnk;
437
438     if (abuf_appendf(&conn->resp, "Table: Links\nLocal IP\tRemote IP\tLQ\tNLQ\tCost\n") < 0) {
439         return -1;
440     }
441
442     /* Link set */
443     OLSR_FOR_ALL_LINK_ENTRIES(lnk) {
444         struct ipaddr_str buf1, buf2;
445         struct lqtextbuffer lqbuffer1, lqbuffer2;
446         if (abuf_appendf(&conn->resp,
447                             "%s\t%s\t%s\t%s\t\n",
448                             olsr_ip_to_string(&buf1, &lnk->local_iface_addr),
449                             olsr_ip_to_string(&buf2, &lnk->neighbor_iface_addr),
450                             get_link_entry_text(lnk, '\t', &lqbuffer1),
451                             get_linkcost_text(lnk->linkcost, false, &lqbuffer2)) < 0) {
452             return -1;
453         }
454     } OLSR_FOR_ALL_LINK_ENTRIES_END(lnk);
455
456     if (abuf_appendf(&conn->resp, "\n") < 0) {
457         return -1;
458     }
459     return 0;
460 }
461
462 static int ipc_print_routes(struct ipc_conn *conn)
463 {
464     struct rt_entry *rt;
465
466     if (abuf_appendf(&conn->resp, "Table: Routes\nDestination\tGateway IP\tMetric\tETX\tInterface\n") < 0) {
467         return -1;
468     }
469
470     /* Walk the route table */
471     OLSR_FOR_ALL_RT_ENTRIES(rt) {
472         struct ipaddr_str buf;
473         struct ipprefix_str prefixstr;
474         struct lqtextbuffer lqbuffer;
475         if (abuf_appendf(&conn->resp,
476                             "%s\t%s\t%u\t%s\t%s\t\n",
477                             olsr_ip_prefix_to_string(&prefixstr, &rt->rt_dst),
478                             olsr_ip_to_string(&buf, &rt->rt_best->rtp_nexthop.gateway),
479                             rt->rt_best->rtp_metric.hops,
480                             get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuffer),
481                             rt->rt_best->rtp_nexthop.interface ? rt->rt_best->rtp_nexthop.interface->int_name : "[null]") < 0) {
482             return -1;
483         }
484     } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
485
486     if (abuf_appendf(&conn->resp, "\n") < 0) {
487         return -1;
488     }
489     return 0;
490 }
491
492 static int ipc_print_topology(struct ipc_conn *conn)
493 {
494     struct tc_entry *tc;
495
496     if (abuf_appendf(&conn->resp, "Table: Topology\nDest. IP\tLast hop IP\tLQ\tNLQ\tCost\n") < 0) {
497         return -1;
498     }
499
500     /* Topology */
501     OLSR_FOR_ALL_TC_ENTRIES(tc) {
502         struct tc_edge_entry *tc_edge;
503         OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
504             if (tc_edge->edge_inv)  {
505                 struct ipaddr_str dstbuf, addrbuf;
506                 struct lqtextbuffer lqbuffer1, lqbuffer2;
507                 if (abuf_appendf(&conn->resp,
508                                     "%s\t%s\t%s\t%s\n",
509                                     olsr_ip_to_string(&dstbuf, &tc_edge->T_dest_addr),
510                                     olsr_ip_to_string(&addrbuf, &tc->addr),
511                                     get_tc_edge_entry_text(tc_edge, '\t', &lqbuffer1),
512                                     get_linkcost_text(tc_edge->cost, false, &lqbuffer2)) < 0) {
513                     return -1;
514                 }
515             }
516         } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
517     } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
518
519     if (abuf_appendf(&conn->resp, "\n") < 0) {
520         return -1;
521     }
522     return 0;
523 }
524
525 static int ipc_print_hna_entry(struct autobuf *autobuf,
526                                const struct olsr_ip_prefix *hna_prefix,
527                                const union olsr_ip_addr *ipaddr)
528 {
529     struct ipaddr_str mainaddrbuf;
530     struct ipprefix_str addrbuf;
531     return abuf_appendf(autobuf,
532                            "%s\t%s\n",
533                            olsr_ip_prefix_to_string(&addrbuf, hna_prefix),
534                            olsr_ip_to_string(&mainaddrbuf, ipaddr));
535 }
536
537 static int ipc_print_hna(struct ipc_conn *conn)
538 {
539     const struct ip_prefix_entry *hna;
540     struct tc_entry *tc;
541
542     if (abuf_appendf(&conn->resp, "Table: HNA\nDestination\tGateway\n") < 0) {
543         return -1;
544     }
545
546     /* Announced HNA entries */
547     OLSR_FOR_ALL_IPPREFIX_ENTRIES(&olsr_cnf->hna_entries, hna) {
548         if (ipc_print_hna_entry(&conn->resp, &hna->net, &olsr_cnf->router_id) < 0) {
549             return -1;
550         }
551     } OLSR_FOR_ALL_IPPREFIX_ENTRIES_END()
552
553     /* HNA entries */
554     OLSR_FOR_ALL_TC_ENTRIES(tc) {
555         struct hna_net *tmp_net;
556         /* Check all networks */
557         OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, tmp_net) {
558             if (ipc_print_hna_entry(&conn->resp, &tmp_net->hna_prefix, &tc->addr) < 0) {
559                 return -1;
560             }
561         } OLSR_FOR_ALL_TC_HNA_ENTRIES_END(tc, tmp_net);
562     } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
563
564     if (abuf_appendf(&conn->resp, "\n") < 0) {
565         return -1;
566     }
567     return 0;
568 }
569
570 static int ipc_print_mid(struct ipc_conn *conn)
571 {
572     struct tc_entry *tc;
573
574     if (abuf_appendf(&conn->resp, "Table: MID\nIP address\tAliases\n") < 0) {
575         return -1;
576     }
577
578     /* MID root is the TC entry */
579     OLSR_FOR_ALL_TC_ENTRIES(tc) {
580         struct ipaddr_str buf;
581         struct mid_entry *alias;
582         char sep = '\t';
583         if (abuf_puts(&conn->resp,  olsr_ip_to_string(&buf, &tc->addr)) < 0) {
584             return -1;
585         }
586
587         OLSR_FOR_ALL_TC_MID_ENTRIES(tc, alias) {
588             if (abuf_appendf(&conn->resp,
589                                 "%c%s",
590                                 sep,
591                                 olsr_ip_to_string(&buf, &alias->mid_alias_addr)) < 0) {
592                 return -1;
593             }
594             sep = ';';
595         }  OLSR_FOR_ALL_TC_MID_ENTRIES_END(tc, alias);
596         if (abuf_appendf(&conn->resp, "\n") < 0) {
597             return -1;
598         }
599     } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
600     if (abuf_appendf(&conn->resp, "\n") < 0) {
601         return -1;
602     }
603     return 0;
604 }
605
606 static int send_info(struct ipc_conn *conn, int send_what)
607 {
608     int rv;
609
610     /* Print minimal http header */
611     if (abuf_appendf(&conn->resp,
612                         "HTTP/1.0 200 OK\n"
613                         "Content-type: text/plain\n\n") < 0) {
614         return -1;
615     }
616
617      /* Print tables to IPC socket */
618
619     rv = 0;
620      /* links + Neighbors */
621     if ((send_what & SIW_LINK) != 0 && ipc_print_link(conn) < 0) {
622         rv = -1;
623     }
624     if ((send_what & SIW_NEIGH) != 0 && ipc_print_neigh(conn) < 0) {
625         rv = -1;
626     }
627      /* topology */
628     if ((send_what & SIW_TOPO) != 0) {
629         rv = ipc_print_topology(conn);
630     }
631      /* hna */
632     if ((send_what & SIW_HNA) != 0) {
633         rv = ipc_print_hna(conn);
634     }
635      /* mid */
636     if ((send_what & SIW_MID) != 0) {
637         rv = ipc_print_mid(conn);
638     }
639      /* routes */
640     if ((send_what & SIW_ROUTE) != 0) {
641         rv = ipc_print_routes(conn);
642     }
643     return rv;
644 }
645
646 /*
647  * Local Variables:
648  * mode: c
649  * style: linux
650  * c-basic-offset: 4
651  * indent-tabs-mode: nil
652  * End:
653  */