2 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
3 * based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
4 * Internet Initiative Japan, Inc (IIJ)
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * $FreeBSD: src/usr.sbin/ppp/route.c,v 1.60.2.8 2003/04/05 10:39:05 ume Exp $
29 * $DragonFly: src/usr.sbin/ppp/route.c,v 1.3 2004/03/27 01:39:13 cpressey Exp $
32 #include <sys/param.h>
33 #include <sys/socket.h>
34 #include <net/if_types.h>
35 #include <net/route.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <net/if_dl.h>
40 #include <netinet/in_systm.h>
41 #include <netinet/ip.h>
49 #include <sys/sysctl.h>
60 #include "throughput.h"
67 #include "slcompress.h"
71 #include "descriptor.h"
86 p_sockaddr(struct prompt
*prompt
, struct sockaddr
*phost
,
87 struct sockaddr
*pmask
, int width
)
89 struct ncprange range
;
91 struct sockaddr_dl
*dl
= (struct sockaddr_dl
*)phost
;
93 if (log_IsKept(LogDEBUG
)) {
96 log_Printf(LogDEBUG
, "Found the following sockaddr:\n");
97 log_Printf(LogDEBUG
, " Family %d, len %d\n",
98 (int)phost
->sa_family
, (int)phost
->sa_len
);
99 inet_ntop(phost
->sa_family
, phost
->sa_data
, tmp
, sizeof tmp
);
100 log_Printf(LogDEBUG
, " Addr %s\n", tmp
);
102 inet_ntop(pmask
->sa_family
, pmask
->sa_data
, tmp
, sizeof tmp
);
103 log_Printf(LogDEBUG
, " Mask %s\n", tmp
);
107 switch (phost
->sa_family
) {
112 ncprange_setsa(&range
, phost
, pmask
);
113 if (ncprange_isdefault(&range
))
114 prompt_Printf(prompt
, "%-*s ", width
- 1, "default");
116 prompt_Printf(prompt
, "%-*s ", width
- 1, ncprange_ntoa(&range
));
121 snprintf(buf
, sizeof buf
, "%.*s", dl
->sdl_nlen
, dl
->sdl_data
);
122 else if (dl
->sdl_alen
) {
123 if (dl
->sdl_type
== IFT_ETHER
) {
124 if (dl
->sdl_alen
< sizeof buf
/ 3) {
128 MAC
= (u_char
*)dl
->sdl_data
+ dl
->sdl_nlen
;
129 for (f
= 0; f
< dl
->sdl_alen
; f
++)
130 sprintf(buf
+f
*3, "%02x:", MAC
[f
]);
133 strcpy(buf
, "??:??:??:??:??:??");
135 sprintf(buf
, "<IFT type %d>", dl
->sdl_type
);
136 } else if (dl
->sdl_slen
)
137 sprintf(buf
, "<slen %d?>", dl
->sdl_slen
);
139 sprintf(buf
, "link#%d", dl
->sdl_index
);
143 sprintf(buf
, "<AF type %d>", phost
->sa_family
);
147 prompt_Printf(prompt
, "%-*s ", width
-1, buf
);
155 { RTF_GATEWAY
, 'G' },
158 { RTF_DYNAMIC
, 'D' },
159 { RTF_MODIFIED
, 'M' },
161 { RTF_CLONING
, 'C' },
162 { RTF_XRESOLVE
, 'X' },
167 { RTF_BLACKHOLE
, 'B' },
169 { RTF_WASCLONED
, 'W' },
172 { RTF_PRCLONING
, 'c' },
178 { RTF_BROADCAST
, 'b' },
183 #ifndef RTF_WASCLONED
184 #define RTF_WASCLONED (0)
188 p_flags(struct prompt
*prompt
, u_int32_t f
, int max
)
190 char name
[33], *flags
;
191 struct bits
*p
= bits
;
193 if (max
> sizeof name
- 1)
194 max
= sizeof name
- 1;
196 for (flags
= name
; p
->b_mask
&& flags
- name
< max
; p
++)
200 prompt_Printf(prompt
, "%-*.*s", max
, max
, name
);
203 static int route_nifs
= -1;
209 * XXX: Maybe we should select() on the routing socket so that we can
210 * notice interfaces that come & go (PCCARD support).
211 * Or we could even support a signal that resets these so that
212 * the PCCARD insert/remove events can signal ppp.
214 static char **ifs
; /* Figure these out once */
215 static int debug_done
; /* Debug once */
217 if (idx
> route_nifs
|| (idx
> 0 && ifs
[idx
-1] == NULL
)) {
218 int mib
[6], have
, had
;
220 char *buf
, *ptr
, *end
;
221 struct sockaddr_dl
*dl
;
222 struct if_msghdr
*ifm
;
235 mib
[4] = NET_RT_IFLIST
;
238 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
239 log_Printf(LogERROR
, "Index2Nam: sysctl: estimate: %s\n",
241 return NumStr(idx
, NULL
, 0);
243 if ((buf
= malloc(needed
)) == NULL
)
244 return NumStr(idx
, NULL
, 0);
245 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
247 return NumStr(idx
, NULL
, 0);
252 for (ptr
= buf
; ptr
< end
; ptr
+= ifm
->ifm_msglen
) {
253 ifm
= (struct if_msghdr
*)ptr
;
254 if (ifm
->ifm_type
!= RTM_IFINFO
)
256 dl
= (struct sockaddr_dl
*)(ifm
+ 1);
257 if (ifm
->ifm_index
> 0) {
258 if (ifm
->ifm_index
> have
) {
262 have
= ifm
->ifm_index
+ 5;
264 newifs
= (char **)realloc(ifs
, sizeof(char *) * have
);
266 newifs
= (char **)malloc(sizeof(char *) * have
);
268 log_Printf(LogDEBUG
, "Index2Nam: %s\n", strerror(errno
));
275 return NumStr(idx
, NULL
, 0);
278 memset(ifs
+ had
, '\0', sizeof(char *) * (have
- had
));
280 if (ifs
[ifm
->ifm_index
-1] == NULL
) {
281 ifs
[ifm
->ifm_index
-1] = (char *)malloc(dl
->sdl_nlen
+1);
282 memcpy(ifs
[ifm
->ifm_index
-1], dl
->sdl_data
, dl
->sdl_nlen
);
283 ifs
[ifm
->ifm_index
-1][dl
->sdl_nlen
] = '\0';
284 if (route_nifs
< ifm
->ifm_index
)
285 route_nifs
= ifm
->ifm_index
;
287 } else if (log_IsKept(LogDEBUG
))
288 log_Printf(LogDEBUG
, "Skipping out-of-range interface %d!\n",
294 if (log_IsKept(LogDEBUG
) && !debug_done
) {
297 log_Printf(LogDEBUG
, "Found the following interfaces:\n");
298 for (f
= 0; f
< route_nifs
; f
++)
300 log_Printf(LogDEBUG
, " Index %d, name \"%s\"\n", f
+1, ifs
[f
]);
304 if (idx
< 1 || idx
> route_nifs
|| ifs
[idx
-1] == NULL
)
305 return NumStr(idx
, NULL
, 0);
311 route_ParseHdr(struct rt_msghdr
*rtm
, struct sockaddr
*sa
[RTAX_MAX
])
316 wp
= (char *)(rtm
+ 1);
318 for (rtax
= 0; rtax
< RTAX_MAX
; rtax
++)
319 if (rtm
->rtm_addrs
& (1 << rtax
)) {
320 sa
[rtax
] = (struct sockaddr
*)wp
;
321 wp
+= ROUNDUP(sa
[rtax
]->sa_len
);
322 if (sa
[rtax
]->sa_family
== 0)
323 sa
[rtax
] = NULL
; /* ??? */
329 route_Show(struct cmdargs
const *arg
)
331 struct rt_msghdr
*rtm
;
332 struct sockaddr
*sa
[RTAX_MAX
];
341 mib
[4] = NET_RT_DUMP
;
343 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
344 log_Printf(LogERROR
, "route_Show: sysctl: estimate: %s\n", strerror(errno
));
350 if (sysctl(mib
, 6, sp
, &needed
, NULL
, 0) < 0) {
351 log_Printf(LogERROR
, "route_Show: sysctl: getroute: %s\n", strerror(errno
));
357 prompt_Printf(arg
->prompt
, "%-20s%-20sFlags Netif\n",
358 "Destination", "Gateway");
359 for (cp
= sp
; cp
< ep
; cp
+= rtm
->rtm_msglen
) {
360 rtm
= (struct rt_msghdr
*)cp
;
362 route_ParseHdr(rtm
, sa
);
364 if (sa
[RTAX_DST
] && sa
[RTAX_GATEWAY
]) {
365 p_sockaddr(arg
->prompt
, sa
[RTAX_DST
], sa
[RTAX_NETMASK
], 20);
366 p_sockaddr(arg
->prompt
, sa
[RTAX_GATEWAY
], NULL
, 20);
368 p_flags(arg
->prompt
, rtm
->rtm_flags
, 6);
369 prompt_Printf(arg
->prompt
, " %s\n", Index2Nam(rtm
->rtm_index
));
371 prompt_Printf(arg
->prompt
, "<can't parse routing entry>\n");
378 * Delete routes associated with our interface
381 route_IfDelete(struct bundle
*bundle
, int all
)
383 struct rt_msghdr
*rtm
;
384 struct sockaddr
*sa
[RTAX_MAX
];
385 struct ncprange range
;
391 log_Printf(LogDEBUG
, "route_IfDelete (%d)\n", bundle
->iface
->index
);
397 mib
[4] = NET_RT_DUMP
;
399 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
400 log_Printf(LogERROR
, "route_IfDelete: sysctl: estimate: %s\n",
409 if (sysctl(mib
, 6, sp
, &needed
, NULL
, 0) < 0) {
410 log_Printf(LogERROR
, "route_IfDelete: sysctl: getroute: %s\n",
417 for (pass
= 0; pass
< 2; pass
++) {
419 * We do 2 passes. The first deletes all cloned routes. The second
420 * deletes all non-cloned routes. This is done to avoid
421 * potential errors from trying to delete route X after route Y where
422 * route X was cloned from route Y (and is no longer there 'cos it
423 * may have gone with route Y).
425 if (RTF_WASCLONED
== 0 && pass
== 0)
426 /* So we can't tell ! */
428 for (cp
= sp
; cp
< ep
; cp
+= rtm
->rtm_msglen
) {
429 rtm
= (struct rt_msghdr
*)cp
;
430 route_ParseHdr(rtm
, sa
);
431 if (rtm
->rtm_index
== bundle
->iface
->index
&&
432 sa
[RTAX_DST
] && sa
[RTAX_GATEWAY
] &&
433 (sa
[RTAX_DST
]->sa_family
== AF_INET
435 || sa
[RTAX_DST
]->sa_family
== AF_INET6
438 (all
|| (rtm
->rtm_flags
& RTF_GATEWAY
))) {
439 if (log_IsKept(LogDEBUG
)) {
442 ncprange_setsa(&range
, sa
[RTAX_DST
], sa
[RTAX_NETMASK
]);
443 ncpaddr_setsa(&gw
, sa
[RTAX_GATEWAY
]);
444 snprintf(gwstr
, sizeof gwstr
, "%s", ncpaddr_ntoa(&gw
));
445 log_Printf(LogDEBUG
, "Found %s %s\n", ncprange_ntoa(&range
), gwstr
);
447 if (sa
[RTAX_GATEWAY
]->sa_family
== AF_INET
||
449 sa
[RTAX_GATEWAY
]->sa_family
== AF_INET6
||
451 sa
[RTAX_GATEWAY
]->sa_family
== AF_LINK
) {
452 if ((pass
== 0 && (rtm
->rtm_flags
& RTF_WASCLONED
)) ||
453 (pass
== 1 && !(rtm
->rtm_flags
& RTF_WASCLONED
))) {
454 ncprange_setsa(&range
, sa
[RTAX_DST
], sa
[RTAX_NETMASK
]);
455 rt_Set(bundle
, RTM_DELETE
, &range
, NULL
, 0, 0);
457 log_Printf(LogDEBUG
, "route_IfDelete: Skip it (pass %d)\n", pass
);
460 "route_IfDelete: Can't remove routes for family %d\n",
461 sa
[RTAX_GATEWAY
]->sa_family
);
470 * Update the MTU on all routes for the given interface
473 route_UpdateMTU(struct bundle
*bundle
)
475 struct rt_msghdr
*rtm
;
476 struct sockaddr
*sa
[RTAX_MAX
];
482 log_Printf(LogDEBUG
, "route_UpdateMTU (%d)\n", bundle
->iface
->index
);
488 mib
[4] = NET_RT_DUMP
;
490 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
491 log_Printf(LogERROR
, "route_IfDelete: sysctl: estimate: %s\n",
500 if (sysctl(mib
, 6, sp
, &needed
, NULL
, 0) < 0) {
501 log_Printf(LogERROR
, "route_IfDelete: sysctl: getroute: %s\n",
508 for (cp
= sp
; cp
< ep
; cp
+= rtm
->rtm_msglen
) {
509 rtm
= (struct rt_msghdr
*)cp
;
510 route_ParseHdr(rtm
, sa
);
511 if (sa
[RTAX_DST
] && (sa
[RTAX_DST
]->sa_family
== AF_INET
513 || sa
[RTAX_DST
]->sa_family
== AF_INET6
516 sa
[RTAX_GATEWAY
] && rtm
->rtm_index
== bundle
->iface
->index
) {
517 if (log_IsKept(LogTCPIP
)) {
518 ncprange_setsa(&dst
, sa
[RTAX_DST
], sa
[RTAX_NETMASK
]);
519 log_Printf(LogTCPIP
, "route_UpdateMTU: Netif: %d (%s), dst %s,"
520 " mtu %d\n", rtm
->rtm_index
, Index2Nam(rtm
->rtm_index
),
521 ncprange_ntoa(&dst
), bundle
->iface
->mtu
);
523 rt_Update(bundle
, sa
[RTAX_DST
], sa
[RTAX_GATEWAY
], sa
[RTAX_NETMASK
]);
531 GetIfIndex(char *name
)
536 while (route_nifs
== -1 || idx
< route_nifs
)
537 if (strcmp(Index2Nam(idx
), name
) == 0)
545 route_Change(struct bundle
*bundle
, struct sticky_route
*r
,
546 const struct ncpaddr
*me
, const struct ncpaddr
*peer
)
550 for (; r
; r
= r
->next
) {
551 ncprange_getaddr(&r
->dst
, &dst
);
552 if (ncpaddr_family(me
) == AF_INET
) {
553 if ((r
->type
& ROUTE_DSTMYADDR
) && !ncpaddr_equal(&dst
, me
)) {
554 rt_Set(bundle
, RTM_DELETE
, &r
->dst
, NULL
, 1, 0);
555 ncprange_sethost(&r
->dst
, me
);
556 if (r
->type
& ROUTE_GWHISADDR
)
557 ncpaddr_copy(&r
->gw
, peer
);
558 } else if ((r
->type
& ROUTE_DSTHISADDR
) && !ncpaddr_equal(&dst
, peer
)) {
559 rt_Set(bundle
, RTM_DELETE
, &r
->dst
, NULL
, 1, 0);
560 ncprange_sethost(&r
->dst
, peer
);
561 if (r
->type
& ROUTE_GWHISADDR
)
562 ncpaddr_copy(&r
->gw
, peer
);
563 } else if ((r
->type
& ROUTE_DSTDNS0
) && !ncpaddr_equal(&dst
, peer
)) {
564 if (bundle
->ncp
.ipcp
.ns
.dns
[0].s_addr
== INADDR_NONE
)
566 rt_Set(bundle
, RTM_DELETE
, &r
->dst
, NULL
, 1, 0);
567 if (r
->type
& ROUTE_GWHISADDR
)
568 ncpaddr_copy(&r
->gw
, peer
);
569 } else if ((r
->type
& ROUTE_DSTDNS1
) && !ncpaddr_equal(&dst
, peer
)) {
570 if (bundle
->ncp
.ipcp
.ns
.dns
[1].s_addr
== INADDR_NONE
)
572 rt_Set(bundle
, RTM_DELETE
, &r
->dst
, NULL
, 1, 0);
573 if (r
->type
& ROUTE_GWHISADDR
)
574 ncpaddr_copy(&r
->gw
, peer
);
575 } else if ((r
->type
& ROUTE_GWHISADDR
) && !ncpaddr_equal(&r
->gw
, peer
))
576 ncpaddr_copy(&r
->gw
, peer
);
578 } else if (ncpaddr_family(me
) == AF_INET6
) {
579 if ((r
->type
& ROUTE_DSTMYADDR6
) && !ncpaddr_equal(&dst
, me
)) {
580 rt_Set(bundle
, RTM_DELETE
, &r
->dst
, NULL
, 1, 0);
581 ncprange_sethost(&r
->dst
, me
);
582 if (r
->type
& ROUTE_GWHISADDR
)
583 ncpaddr_copy(&r
->gw
, peer
);
584 } else if ((r
->type
& ROUTE_DSTHISADDR6
) && !ncpaddr_equal(&dst
, peer
)) {
585 rt_Set(bundle
, RTM_DELETE
, &r
->dst
, NULL
, 1, 0);
586 ncprange_sethost(&r
->dst
, peer
);
587 if (r
->type
& ROUTE_GWHISADDR
)
588 ncpaddr_copy(&r
->gw
, peer
);
589 } else if ((r
->type
& ROUTE_GWHISADDR6
) && !ncpaddr_equal(&r
->gw
, peer
))
590 ncpaddr_copy(&r
->gw
, peer
);
593 rt_Set(bundle
, RTM_ADD
, &r
->dst
, &r
->gw
, 1, 0);
598 route_Add(struct sticky_route
**rp
, int type
, const struct ncprange
*dst
,
599 const struct ncpaddr
*gw
)
601 struct sticky_route
*r
;
602 int dsttype
= type
& ROUTE_DSTANY
;
606 if ((dsttype
&& dsttype
== ((*rp
)->type
& ROUTE_DSTANY
)) ||
607 (!dsttype
&& ncprange_equal(&(*rp
)->dst
, dst
))) {
608 /* Oops, we already have this route - unlink it */
609 free(r
); /* impossible really */
617 r
= (struct sticky_route
*)malloc(sizeof(struct sticky_route
));
620 ncprange_copy(&r
->dst
, dst
);
621 ncpaddr_copy(&r
->gw
, gw
);
626 route_Delete(struct sticky_route
**rp
, int type
, const struct ncprange
*dst
)
628 struct sticky_route
*r
;
629 int dsttype
= type
& ROUTE_DSTANY
;
631 for (; *rp
; rp
= &(*rp
)->next
) {
632 if ((dsttype
&& dsttype
== ((*rp
)->type
& ROUTE_DSTANY
)) ||
633 (!dsttype
&& ncprange_equal(dst
, &(*rp
)->dst
))) {
643 route_DeleteAll(struct sticky_route
**rp
)
645 struct sticky_route
*r
, *rn
;
647 for (r
= *rp
; r
; r
= rn
) {
655 route_ShowSticky(struct prompt
*p
, struct sticky_route
*r
, const char *tag
,
658 int tlen
= strlen(tag
);
660 if (tlen
+ 2 > indent
)
661 prompt_Printf(p
, "%s:\n%*s", tag
, indent
, "");
663 prompt_Printf(p
, "%s:%*s", tag
, indent
- tlen
- 1, "");
665 for (; r
; r
= r
->next
) {
666 prompt_Printf(p
, "%*sadd ", tlen
? 0 : indent
, "");
668 if (r
->type
& ROUTE_DSTMYADDR
)
669 prompt_Printf(p
, "MYADDR");
670 else if (r
->type
& ROUTE_DSTMYADDR6
)
671 prompt_Printf(p
, "MYADDR6");
672 else if (r
->type
& ROUTE_DSTHISADDR
)
673 prompt_Printf(p
, "HISADDR");
674 else if (r
->type
& ROUTE_DSTHISADDR6
)
675 prompt_Printf(p
, "HISADDR6");
676 else if (r
->type
& ROUTE_DSTDNS0
)
677 prompt_Printf(p
, "DNS0");
678 else if (r
->type
& ROUTE_DSTDNS1
)
679 prompt_Printf(p
, "DNS1");
680 else if (ncprange_isdefault(&r
->dst
))
681 prompt_Printf(p
, "default");
683 prompt_Printf(p
, "%s", ncprange_ntoa(&r
->dst
));
685 if (r
->type
& ROUTE_GWHISADDR
)
686 prompt_Printf(p
, " HISADDR\n");
687 else if (r
->type
& ROUTE_GWHISADDR6
)
688 prompt_Printf(p
, " HISADDR6\n");
690 prompt_Printf(p
, " %s\n", ncpaddr_ntoa(&r
->gw
));
695 struct rt_msghdr m_rtm
;
700 memcpy_roundup(char *cp
, const void *data
, size_t len
)
704 padlen
= ROUNDUP(len
);
705 memcpy(cp
, data
, len
);
707 memset(cp
+ len
, '\0', padlen
- len
);
712 #if defined(__KAME__) && !defined(NOINET6)
714 add_scope(struct sockaddr
*sa
, int ifindex
)
716 struct sockaddr_in6
*sa6
;
718 if (sa
->sa_family
!= AF_INET6
)
720 sa6
= (struct sockaddr_in6
*)sa
;
721 if (!IN6_IS_ADDR_LINKLOCAL(&sa6
->sin6_addr
) &&
722 !IN6_IS_ADDR_MC_LINKLOCAL(&sa6
->sin6_addr
))
724 if (*(u_int16_t
*)&sa6
->sin6_addr
.s6_addr
[2] != 0)
726 *(u_int16_t
*)&sa6
->sin6_addr
.s6_addr
[2] = htons(ifindex
);
731 rt_Set(struct bundle
*bundle
, int cmd
, const struct ncprange
*dst
,
732 const struct ncpaddr
*gw
, int bang
, int quiet
)
738 struct sockaddr_storage sadst
, samask
, sagw
;
742 cmdstr
= (cmd
== RTM_ADD
? "Add!" : "Delete!");
744 cmdstr
= (cmd
== RTM_ADD
? "Add" : "Delete");
745 s
= ID0socket(PF_ROUTE
, SOCK_RAW
, 0);
747 log_Printf(LogERROR
, "rt_Set: socket(): %s\n", strerror(errno
));
750 memset(&rtmes
, '\0', sizeof rtmes
);
751 rtmes
.m_rtm
.rtm_version
= RTM_VERSION
;
752 rtmes
.m_rtm
.rtm_type
= cmd
;
753 rtmes
.m_rtm
.rtm_addrs
= RTA_DST
;
754 rtmes
.m_rtm
.rtm_seq
= ++bundle
->routing_seq
;
755 rtmes
.m_rtm
.rtm_pid
= getpid();
756 rtmes
.m_rtm
.rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_STATIC
;
758 if (cmd
== RTM_ADD
) {
759 if (bundle
->ncp
.cfg
.sendpipe
> 0) {
760 rtmes
.m_rtm
.rtm_rmx
.rmx_sendpipe
= bundle
->ncp
.cfg
.sendpipe
;
761 rtmes
.m_rtm
.rtm_inits
|= RTV_SPIPE
;
763 if (bundle
->ncp
.cfg
.recvpipe
> 0) {
764 rtmes
.m_rtm
.rtm_rmx
.rmx_recvpipe
= bundle
->ncp
.cfg
.recvpipe
;
765 rtmes
.m_rtm
.rtm_inits
|= RTV_RPIPE
;
769 ncprange_getsa(dst
, &sadst
, &samask
);
770 #if defined(__KAME__) && !defined(NOINET6)
771 add_scope((struct sockaddr
*)&sadst
, bundle
->iface
->index
);
775 cp
+= memcpy_roundup(cp
, &sadst
, sadst
.ss_len
);
776 if (cmd
== RTM_ADD
) {
778 log_Printf(LogERROR
, "rt_Set: Program error\n");
782 ncpaddr_getsa(gw
, &sagw
);
783 #if defined(__KAME__) && !defined(NOINET6)
784 add_scope((struct sockaddr
*)&sagw
, bundle
->iface
->index
);
786 if (ncpaddr_isdefault(gw
)) {
788 log_Printf(LogERROR
, "rt_Set: Cannot add a route with"
789 " gateway 0.0.0.0\n");
793 cp
+= memcpy_roundup(cp
, &sagw
, sagw
.ss_len
);
794 rtmes
.m_rtm
.rtm_addrs
|= RTA_GATEWAY
;
798 if (!ncprange_ishost(dst
)) {
799 cp
+= memcpy_roundup(cp
, &samask
, samask
.ss_len
);
800 rtmes
.m_rtm
.rtm_addrs
|= RTA_NETMASK
;
803 nb
= cp
- (char *)&rtmes
;
804 rtmes
.m_rtm
.rtm_msglen
= nb
;
805 wb
= ID0write(s
, &rtmes
, nb
);
807 log_Printf(LogTCPIP
, "rt_Set failure:\n");
808 log_Printf(LogTCPIP
, "rt_Set: Cmd = %s\n", cmdstr
);
809 log_Printf(LogTCPIP
, "rt_Set: Dst = %s\n", ncprange_ntoa(dst
));
811 log_Printf(LogTCPIP
, "rt_Set: Gateway = %s\n", ncpaddr_ntoa(gw
));
813 if (cmd
== RTM_ADD
&& (rtmes
.m_rtm
.rtm_errno
== EEXIST
||
814 (rtmes
.m_rtm
.rtm_errno
== 0 && errno
== EEXIST
))) {
816 log_Printf(LogWARN
, "Add route failed: %s already exists\n",
818 result
= 0; /* Don't add to our dynamic list */
820 rtmes
.m_rtm
.rtm_type
= cmd
= RTM_CHANGE
;
821 if ((wb
= ID0write(s
, &rtmes
, nb
)) < 0)
824 } else if (cmd
== RTM_DELETE
&&
825 (rtmes
.m_rtm
.rtm_errno
== ESRCH
||
826 (rtmes
.m_rtm
.rtm_errno
== 0 && errno
== ESRCH
))) {
828 log_Printf(LogWARN
, "Del route failed: %s: Non-existent\n",
830 } else if (rtmes
.m_rtm
.rtm_errno
== 0) {
831 if (!quiet
|| errno
!= ENETUNREACH
)
832 log_Printf(LogWARN
, "%s route failed: %s: errno: %s\n", cmdstr
,
833 ncprange_ntoa(dst
), strerror(errno
));
835 log_Printf(LogWARN
, "%s route failed: %s: %s\n",
836 cmdstr
, ncprange_ntoa(dst
), strerror(rtmes
.m_rtm
.rtm_errno
));
839 if (log_IsKept(LogDEBUG
)) {
843 snprintf(gwstr
, sizeof gwstr
, "%s", ncpaddr_ntoa(gw
));
845 snprintf(gwstr
, sizeof gwstr
, "<none>");
846 log_Printf(LogDEBUG
, "wrote %d: cmd = %s, dst = %s, gateway = %s\n",
847 wb
, cmdstr
, ncprange_ntoa(dst
), gwstr
);
855 rt_Update(struct bundle
*bundle
, const struct sockaddr
*dst
,
856 const struct sockaddr
*gw
, const struct sockaddr
*mask
)
858 struct ncprange ncpdst
;
863 s
= ID0socket(PF_ROUTE
, SOCK_RAW
, 0);
865 log_Printf(LogERROR
, "rt_Update: socket(): %s\n", strerror(errno
));
869 memset(&rtmes
, '\0', sizeof rtmes
);
870 rtmes
.m_rtm
.rtm_version
= RTM_VERSION
;
871 rtmes
.m_rtm
.rtm_type
= RTM_CHANGE
;
872 rtmes
.m_rtm
.rtm_addrs
= 0;
873 rtmes
.m_rtm
.rtm_seq
= ++bundle
->routing_seq
;
874 rtmes
.m_rtm
.rtm_pid
= getpid();
875 rtmes
.m_rtm
.rtm_flags
= RTF_UP
| RTF_STATIC
;
877 if (bundle
->ncp
.cfg
.sendpipe
> 0) {
878 rtmes
.m_rtm
.rtm_rmx
.rmx_sendpipe
= bundle
->ncp
.cfg
.sendpipe
;
879 rtmes
.m_rtm
.rtm_inits
|= RTV_SPIPE
;
882 if (bundle
->ncp
.cfg
.recvpipe
> 0) {
883 rtmes
.m_rtm
.rtm_rmx
.rmx_recvpipe
= bundle
->ncp
.cfg
.recvpipe
;
884 rtmes
.m_rtm
.rtm_inits
|= RTV_RPIPE
;
887 rtmes
.m_rtm
.rtm_rmx
.rmx_mtu
= bundle
->iface
->mtu
;
888 rtmes
.m_rtm
.rtm_inits
|= RTV_MTU
;
892 rtmes
.m_rtm
.rtm_addrs
|= RTA_DST
;
893 p
+= memcpy_roundup(p
, dst
, dst
->sa_len
);
896 rtmes
.m_rtm
.rtm_addrs
|= RTA_GATEWAY
;
897 p
+= memcpy_roundup(p
, gw
, gw
->sa_len
);
899 rtmes
.m_rtm
.rtm_addrs
|= RTA_NETMASK
;
900 p
+= memcpy_roundup(p
, mask
, mask
->sa_len
);
903 rtmes
.m_rtm
.rtm_msglen
= p
- (char *)&rtmes
;
905 wb
= ID0write(s
, &rtmes
, rtmes
.m_rtm
.rtm_msglen
);
907 ncprange_setsa(&ncpdst
, dst
, mask
);
909 log_Printf(LogTCPIP
, "rt_Update failure:\n");
910 log_Printf(LogTCPIP
, "rt_Update: Dst = %s\n", ncprange_ntoa(&ncpdst
));
912 if (rtmes
.m_rtm
.rtm_errno
== 0)
913 log_Printf(LogWARN
, "%s: Change route failed: errno: %s\n",
914 ncprange_ntoa(&ncpdst
), strerror(errno
));
916 log_Printf(LogWARN
, "%s: Change route failed: %s\n",
917 ncprange_ntoa(&ncpdst
), strerror(rtmes
.m_rtm
.rtm_errno
));