MiniDLNA update: 1.0.19.1 to 1.0.20
[tomato.git] / release / src / router / zebra / zebra / rt_ioctl.c
blobed70f33be44855e9e9dafae3c48ea32620384822
1 /*
2 * kernel routing table update by ioctl().
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
5 * This file is part of GNU Zebra.
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
23 #include <zebra.h>
25 #include "prefix.h"
26 #include "log.h"
27 #include "if.h"
29 #include "zebra/rib.h"
30 #include "zebra/debug.h"
32 /* Initialize of kernel interface. There is no kernel communication
33 support under ioctl(). So this is dummy stub function. */
34 void
35 kernel_init ()
37 return;
40 /* Dummy function of routing socket. */
41 void
42 kernel_read (int sock)
44 return;
47 #if 0
48 /* Initialization prototype of struct sockaddr_in. */
49 static struct sockaddr_in sin_proto =
51 #ifdef HAVE_SIN_LEN
52 sizeof (struct sockaddr_in),
53 #endif /* HAVE_SIN_LEN */
54 AF_INET, 0, {0}, {0}
56 #endif /* 0 */
58 /* Solaris has ortentry. */
59 #ifdef HAVE_OLD_RTENTRY
60 #define rtentry ortentry
61 #endif /* HAVE_OLD_RTENTRY */
63 /* Interface to ioctl route message. */
64 int
65 kernel_add_route (struct prefix_ipv4 *dest, struct in_addr *gate,
66 int index, int flags)
68 int ret;
69 int sock;
70 struct rtentry rtentry;
71 struct sockaddr_in sin_dest, sin_mask, sin_gate;
73 memset (&rtentry, 0, sizeof (struct rtentry));
75 /* Make destination. */
76 memset (&sin_dest, 0, sizeof (struct sockaddr_in));
77 sin_dest.sin_family = AF_INET;
78 #ifdef HAVE_SIN_LEN
79 sin_dest.sin_len = sizeof (struct sockaddr_in);
80 #endif /* HAVE_SIN_LEN */
81 sin_dest.sin_addr = dest->prefix;
83 /* Make gateway. */
84 if (gate)
86 memset (&sin_gate, 0, sizeof (struct sockaddr_in));
87 sin_gate.sin_family = AF_INET;
88 #ifdef HAVE_SIN_LEN
89 sin_gate.sin_len = sizeof (struct sockaddr_in);
90 #endif /* HAVE_SIN_LEN */
91 sin_gate.sin_addr = *gate;
94 memset (&sin_mask, 0, sizeof (struct sockaddr_in));
95 sin_mask.sin_family = AF_INET;
96 #ifdef HAVE_SIN_LEN
97 sin_gate.sin_len = sizeof (struct sockaddr_in);
98 #endif /* HAVE_SIN_LEN */
99 masklen2ip (dest->prefixlen, &sin_mask.sin_addr);
101 /* Set destination address, mask and gateway.*/
102 memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
103 if (gate)
104 memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
105 #ifndef SUNOS_5
106 memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
107 #endif /* SUNOS_5 */
109 /* Routing entry flag set. */
110 if (dest->prefixlen == 32)
111 rtentry.rt_flags |= RTF_HOST;
113 if (gate && gate->s_addr != INADDR_ANY)
114 rtentry.rt_flags |= RTF_GATEWAY;
116 rtentry.rt_flags |= RTF_UP;
118 /* Additional flags */
119 rtentry.rt_flags |= flags;
122 /* For tagging route. */
123 /* rtentry.rt_flags |= RTF_DYNAMIC; */
125 /* Open socket for ioctl. */
126 sock = socket (AF_INET, SOCK_DGRAM, 0);
127 if (sock < 0)
129 zlog_warn ("can't make socket\n");
130 return -1;
133 /* Send message by ioctl(). */
134 ret = ioctl (sock, SIOCADDRT, &rtentry);
135 if (ret < 0)
137 switch (errno)
139 case EEXIST:
140 close (sock);
141 return ZEBRA_ERR_RTEXIST;
142 break;
143 case ENETUNREACH:
144 close (sock);
145 return ZEBRA_ERR_RTUNREACH;
146 break;
147 case EPERM:
148 close (sock);
149 return ZEBRA_ERR_EPERM;
150 break;
153 close (sock);
154 zlog_warn ("write : %s (%d)", strerror (errno), errno);
155 return 1;
157 close (sock);
159 return ret;
162 /* Interface to ioctl route message. */
164 kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family)
166 int ret;
167 int sock;
168 struct rtentry rtentry;
169 struct sockaddr_in sin_dest, sin_mask, sin_gate;
170 struct nexthop *nexthop;
171 int nexthop_num = 0;
172 struct interface *ifp;
174 memset (&rtentry, 0, sizeof (struct rtentry));
176 /* Make destination. */
177 memset (&sin_dest, 0, sizeof (struct sockaddr_in));
178 sin_dest.sin_family = AF_INET;
179 #ifdef HAVE_SIN_LEN
180 sin_dest.sin_len = sizeof (struct sockaddr_in);
181 #endif /* HAVE_SIN_LEN */
182 sin_dest.sin_addr = p->u.prefix4;
184 if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
186 SET_FLAG (rtentry.rt_flags, RTF_REJECT);
188 if (cmd == SIOCADDRT)
189 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
190 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
192 goto skip;
195 memset (&sin_gate, 0, sizeof (struct sockaddr_in));
197 /* Make gateway. */
198 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
200 if ((cmd == SIOCADDRT
201 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
202 || (cmd == SIOCDELRT
203 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
205 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
207 if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
208 nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
210 sin_gate.sin_family = AF_INET;
211 #ifdef HAVE_SIN_LEN
212 sin_gate.sin_len = sizeof (struct sockaddr_in);
213 #endif /* HAVE_SIN_LEN */
214 sin_gate.sin_addr = nexthop->rgate.ipv4;
215 rtentry.rt_flags |= RTF_GATEWAY;
217 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
218 || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
220 ifp = if_lookup_by_index (nexthop->rifindex);
221 if (ifp)
222 rtentry.rt_dev = ifp->name;
223 else
224 return -1;
227 else
229 if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
230 nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
232 sin_gate.sin_family = AF_INET;
233 #ifdef HAVE_SIN_LEN
234 sin_gate.sin_len = sizeof (struct sockaddr_in);
235 #endif /* HAVE_SIN_LEN */
236 sin_gate.sin_addr = nexthop->gate.ipv4;
237 rtentry.rt_flags |= RTF_GATEWAY;
239 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
240 || nexthop->type == NEXTHOP_TYPE_IFNAME)
242 ifp = if_lookup_by_index (nexthop->ifindex);
243 if (ifp)
244 rtentry.rt_dev = ifp->name;
245 else
246 return -1;
250 if (cmd == SIOCADDRT)
251 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
253 nexthop_num++;
254 break;
258 /* If there is no useful nexthop then return. */
259 if (nexthop_num == 0)
261 if (IS_ZEBRA_DEBUG_KERNEL)
262 zlog_info ("kernel_ioctl_ipv4(): No useful nexthop.");
263 return 0;
266 skip:
268 memset (&sin_mask, 0, sizeof (struct sockaddr_in));
269 sin_mask.sin_family = AF_INET;
270 #ifdef HAVE_SIN_LEN
271 sin_mask.sin_len = sizeof (struct sockaddr_in);
272 #endif /* HAVE_SIN_LEN */
273 masklen2ip (p->prefixlen, &sin_mask.sin_addr);
275 /* Set destination address, mask and gateway.*/
276 memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
278 if (rtentry.rt_flags & RTF_GATEWAY)
279 memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
281 #ifndef SUNOS_5
282 memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
283 #endif /* SUNOS_5 */
285 /* Metric. It seems metric minus one value is installed... */
286 rtentry.rt_metric = rib->metric;
288 /* Routing entry flag set. */
289 if (p->prefixlen == 32)
290 rtentry.rt_flags |= RTF_HOST;
292 rtentry.rt_flags |= RTF_UP;
294 /* Additional flags */
295 /* rtentry.rt_flags |= flags; */
297 /* For tagging route. */
298 /* rtentry.rt_flags |= RTF_DYNAMIC; */
300 /* Open socket for ioctl. */
301 sock = socket (AF_INET, SOCK_DGRAM, 0);
302 if (sock < 0)
304 zlog_warn ("can't make socket\n");
305 return -1;
308 /* Send message by ioctl(). */
309 ret = ioctl (sock, cmd, &rtentry);
310 if (ret < 0)
312 switch (errno)
314 case EEXIST:
315 close (sock);
316 return ZEBRA_ERR_RTEXIST;
317 break;
318 case ENETUNREACH:
319 close (sock);
320 return ZEBRA_ERR_RTUNREACH;
321 break;
322 case EPERM:
323 close (sock);
324 return ZEBRA_ERR_EPERM;
325 break;
328 close (sock);
329 zlog_warn ("write : %s (%d)", strerror (errno), errno);
330 return ret;
332 close (sock);
334 return ret;
338 kernel_add_ipv4 (struct prefix *p, struct rib *rib)
340 return kernel_ioctl_ipv4 (SIOCADDRT, p, rib, AF_INET);
344 kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
346 return kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET);
349 #ifdef HAVE_IPV6
351 /* Below is hack for GNU libc definition and Linux 2.1.X header. */
352 #undef RTF_DEFAULT
353 #undef RTF_ADDRCONF
355 #include <asm/types.h>
357 #if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
358 /* struct in6_rtmsg will be declared in net/route.h. */
359 #else
360 #include <linux/ipv6_route.h>
361 #endif
364 kernel_ioctl_ipv6 (u_long type, struct prefix_ipv6 *dest, struct in6_addr *gate,
365 int index, int flags)
367 int ret;
368 int sock;
369 struct in6_rtmsg rtm;
371 memset (&rtm, 0, sizeof (struct in6_rtmsg));
373 rtm.rtmsg_flags |= RTF_UP;
374 rtm.rtmsg_metric = 1;
375 memcpy (&rtm.rtmsg_dst, &dest->prefix, sizeof (struct in6_addr));
376 rtm.rtmsg_dst_len = dest->prefixlen;
378 /* We need link local index. But this should be done caller...
379 if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
381 index = if_index_address (&rtm.rtmsg_gateway);
382 rtm.rtmsg_ifindex = index;
384 else
385 rtm.rtmsg_ifindex = 0;
388 rtm.rtmsg_flags |= RTF_GATEWAY;
390 /* For tagging route. */
391 /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
393 memcpy (&rtm.rtmsg_gateway, gate, sizeof (struct in6_addr));
395 if (index)
396 rtm.rtmsg_ifindex = index;
397 else
398 rtm.rtmsg_ifindex = 0;
400 rtm.rtmsg_metric = 1;
402 sock = socket (AF_INET6, SOCK_DGRAM, 0);
403 if (sock < 0)
405 zlog_warn ("can't make socket\n");
406 return -1;
409 /* Send message via ioctl. */
410 ret = ioctl (sock, type, &rtm);
411 if (ret < 0)
413 zlog_warn ("can't %s ipv6 route: %s\n", type == SIOCADDRT ? "add" : "delete",
414 strerror(errno));
415 ret = errno;
416 close (sock);
417 return ret;
419 close (sock);
421 return ret;
425 kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib,
426 int family)
428 int ret;
429 int sock;
430 struct in6_rtmsg rtm;
431 struct nexthop *nexthop;
432 int nexthop_num = 0;
434 memset (&rtm, 0, sizeof (struct in6_rtmsg));
436 rtm.rtmsg_flags |= RTF_UP;
437 rtm.rtmsg_metric = rib->metric;
438 memcpy (&rtm.rtmsg_dst, &p->u.prefix, sizeof (struct in6_addr));
439 rtm.rtmsg_dst_len = p->prefixlen;
441 /* We need link local index. But this should be done caller...
442 if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
444 index = if_index_address (&rtm.rtmsg_gateway);
445 rtm.rtmsg_ifindex = index;
447 else
448 rtm.rtmsg_ifindex = 0;
451 if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
452 SET_FLAG (rtm.rtmsg_flags, RTF_REJECT);
454 rtm.rtmsg_flags |= RTF_GATEWAY;
456 /* For tagging route. */
457 /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
459 /* Make gateway. */
460 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
462 if ((cmd == SIOCADDRT
463 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
464 || (cmd == SIOCDELRT
465 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
467 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
469 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
470 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
471 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
473 memcpy (&rtm.rtmsg_gateway, &nexthop->rgate.ipv6,
474 sizeof (struct in6_addr));
476 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
477 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
478 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
479 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
480 rtm.rtmsg_ifindex = nexthop->rifindex;
481 else
482 rtm.rtmsg_ifindex = 0;
485 else
487 if (nexthop->type == NEXTHOP_TYPE_IPV6
488 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
489 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
491 memcpy (&rtm.rtmsg_gateway, &nexthop->gate.ipv6,
492 sizeof (struct in6_addr));
494 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
495 || nexthop->type == NEXTHOP_TYPE_IFNAME
496 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
497 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
498 rtm.rtmsg_ifindex = nexthop->ifindex;
499 else
500 rtm.rtmsg_ifindex = 0;
501 if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
503 #ifdef HAVE_IN6ADDR_GLOBAL
504 rtm.rtmsg_gateway = in6addr_loopback;
505 #else /*HAVE_IN6ADDR_GLOBAL*/
506 inet_pton (AF_INET6, "::1", &rtm.rtmsg_gateway);
507 #endif /*HAVE_IN6ADDR_GLOBAL*/
511 if (cmd == SIOCADDRT)
512 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
514 nexthop_num++;
515 break;
519 /* If there is no useful nexthop then return. */
520 if (nexthop_num == 0)
522 if (IS_ZEBRA_DEBUG_KERNEL)
523 zlog_info ("kernel_ioctl_ipv6_multipath(): No useful nexthop.");
524 return 0;
527 sock = socket (AF_INET6, SOCK_DGRAM, 0);
528 if (sock < 0)
530 zlog_warn ("can't make socket\n");
531 return -1;
534 /* Send message via ioctl. */
535 ret = ioctl (sock, cmd, &rtm);
536 if (ret < 0)
538 zlog_warn ("can't %s ipv6 route: %s\n",
539 cmd == SIOCADDRT ? "add" : "delete",
540 strerror(errno));
541 ret = errno;
542 close (sock);
543 return ret;
545 close (sock);
547 return ret;
551 kernel_add_ipv6 (struct prefix *p, struct rib *rib)
553 return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6);
557 kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
559 return kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6);
562 /* Delete IPv6 route from the kernel. */
564 kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
565 int index, int flags, int table)
567 return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, flags);
569 #endif /* HAVE_IPV6 */