📄 route.c
字号:
//==========================================================================
//
// src/sys/net/route.c
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD,
// FreeBSD or other sources, and are covered by the appropriate
// copyright disclaimers included herein.
//
// Portions created by Red Hat are
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
/*
* Copyright (c) 1980, 1986, 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)route.c 8.2 (Berkeley) 11/15/93
* $FreeBSD: src/sys/net/route.c,v 1.59.2.3 2001/07/29 19:18:02 ume Exp $
*/
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/domain.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/ip_mroute.h>
#include <sys/sockio.h> // for eCos routing protocols
#define SA(p) ((struct sockaddr *)(p))
struct route_cb route_cb;
static struct rtstat rtstat;
struct radix_node_head *rt_tables[AF_MAX+1];
static int rttrash; /* routes not in table but not freed */
static void rt_maskedcopy __P((struct sockaddr *,
struct sockaddr *, struct sockaddr *));
static void rtable_init __P((void **));
static void
rtable_init(table)
void **table;
{
struct domain *dom;
for (dom = domains; dom; dom = dom->dom_next)
if (dom->dom_rtattach)
dom->dom_rtattach(&table[dom->dom_family],
dom->dom_rtoffset);
}
static void call_route_init( void * arg )
{
route_init();
}
void
route_init()
{
rn_init(); /* initialize all zeroes, all ones, mask table */
rtable_init((void **)rt_tables);
}
// FIXME: This function is only here because BOOTP fails on a second interface.
// This failure is due to the fact that a route to 0.0.0.0 seems to be
// incredibly sticky, i.e. can't be deleted. BOOTP uses this to
// achieve a generic broadcast. Sadly it seems that BOOTP servers will
// only work this way, thus the hack.
//
// This version enumerates all IPv4 routes and deletes them - this leaks less
// store than the previous version.
static int
rt_reinit_rtdelete( struct radix_node *rn, void *vifp )
{
struct rtentry *rt = (struct rtentry *)rn;
if (rt->rt_ifa->ifa_addr->sa_family == AF_INET) {
rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
0, NULL);
}
return (0);
}
void
cyg_route_reinit(void)
{
int i;
for (i = 0; i < AF_MAX+1; i++) {
struct radix_node_head *rnh;
rnh = rt_tables[i];
if (rnh) {
(*rnh->rnh_walktree)(rnh, rt_reinit_rtdelete, NULL);
}
}
}
/*
* Packet routing routines.
*/
void
rtalloc(ro)
register struct route *ro;
{
rtalloc_ign(ro, 0UL);
}
void
rtalloc_ign(ro, ignore)
register struct route *ro;
u_long ignore;
{
struct rtentry *rt;
int s;
if ((rt = ro->ro_rt) != NULL) {
if (rt->rt_ifp != NULL && rt->rt_flags & RTF_UP)
return;
/* XXX - We are probably always at splnet here already. */
s = splnet();
RTFREE(rt);
ro->ro_rt = NULL;
splx(s);
}
ro->ro_rt = rtalloc1(&ro->ro_dst, 1, ignore);
}
/*
* Look up the route that matches the address given
* Or, at least try.. Create a cloned route if needed.
*/
struct rtentry *
rtalloc1(dst, report, ignflags)
register struct sockaddr *dst;
int report;
u_long ignflags;
{
register struct radix_node_head *rnh = rt_tables[dst->sa_family];
register struct rtentry *rt;
register struct radix_node *rn;
struct rtentry *newrt = 0;
struct rt_addrinfo info;
u_long nflags;
int s = splnet(), err = 0, msgtype = RTM_MISS;
/*
* Look up the address in the table for that Address Family
*/
if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) &&
((rn->rn_flags & RNF_ROOT) == 0)) {
/*
* If we find it and it's not the root node, then
* get a refernce on the rtentry associated.
*/
newrt = rt = (struct rtentry *)rn;
nflags = rt->rt_flags & ~ignflags;
if (report && (nflags & (RTF_CLONING | RTF_PRCLONING))) {
/*
* We are apparently adding (report = 0 in delete).
* If it requires that it be cloned, do so.
* (This implies it wasn't a HOST route.)
*/
err = rtrequest(RTM_RESOLVE, dst, SA(0),
SA(0), 0, &newrt);
if (err) {
/*
* If the cloning didn't succeed, maybe
* what we have will do. Return that.
*/
newrt = rt;
rt->rt_refcnt++;
goto miss;
}
if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
/*
* If the new route specifies it be
* externally resolved, then go do that.
*/
msgtype = RTM_RESOLVE;
goto miss;
}
} else
rt->rt_refcnt++;
} else {
/*
* Either we hit the root or couldn't find any match,
* Which basically means
* "caint get there frm here"
*/
rtstat.rts_unreach++;
miss: if (report) {
/*
* If required, report the failure to the supervising
* Authorities.
* For a delete, this is not an error. (report == 0)
*/
bzero((caddr_t)&info, sizeof(info));
info.rti_info[RTAX_DST] = dst;
rt_missmsg(msgtype, &info, 0, err);
}
}
splx(s);
return (newrt);
}
/*
* Remove a reference count from an rtentry.
* If the count gets low enough, take it out of the routing table
*/
void
rtfree(rt)
register struct rtentry *rt;
{
/*
* find the tree for that address family
*/
register struct radix_node_head *rnh =
rt_tables[rt_key(rt)->sa_family];
register struct ifaddr *ifa;
if (rt == 0 || rnh == 0)
panic("rtfree");
/*
* decrement the reference count by one and if it reaches 0,
* and there is a close function defined, call the close function
*/
rt->rt_refcnt--;
if(rnh->rnh_close && rt->rt_refcnt == 0) {
rnh->rnh_close((struct radix_node *)rt, rnh);
}
/*
* If we are no longer "up" (and ref == 0)
* then we can free the resources associated
* with the route.
*/
if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
panic ("rtfree 2");
/*
* the rtentry must have been removed from the routing table
* so it is represented in rttrash.. remove that now.
*/
rttrash--;
#ifdef DIAGNOSTIC
if (rt->rt_refcnt < 0) {
printf("rtfree: %p not freed (neg refs)\n", rt);
return;
}
#endif
/*
* release references on items we hold them on..
* e.g other routes and ifaddrs.
*/
if((ifa = rt->rt_ifa))
IFAFREE(ifa);
if (rt->rt_parent) {
RTFREE(rt->rt_parent);
}
/*
* The key is separatly alloc'd so free it (see rt_setgate()).
* This also frees the gateway, as they are always malloc'd
* together.
*/
Free(rt_key(rt));
/*
* and the rtentry itself of course
*/
Free(rt);
}
}
void
ifafree(ifa)
register struct ifaddr *ifa;
{
if (ifa == NULL)
panic("ifafree");
if (ifa->ifa_refcnt == 0)
free(ifa, M_IFADDR);
else
ifa->ifa_refcnt--;
}
/*
* Force a routing table entry to the specified
* destination to go through the given gateway.
* Normally called as a result of a routing redirect
* message from the network layer.
*
* N.B.: must be called at splnet
*
*/
void
rtredirect(dst, gateway, netmask, flags, src, rtp)
struct sockaddr *dst, *gateway, *netmask, *src;
int flags;
struct rtentry **rtp;
{
register struct rtentry *rt;
int error = 0;
short *stat = 0;
struct rt_addrinfo info;
struct ifaddr *ifa;
/* verify the gateway is directly reachable */
if ((ifa = ifa_ifwithnet(gateway)) == 0) {
error = ENETUNREACH;
goto out;
}
rt = rtalloc1(dst, 0, 0UL);
/*
* If the redirect isn't from our current router for this dst,
* it's either old or wrong. If it redirects us to ourselves,
* we have a routing loop, perhaps as a result of an interface
* going down recently.
*/
#define equal(a1, a2) \ ((a1)->sa_len == (a2)->sa_len && \ bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
if (!(flags & RTF_DONE) && rt &&
(!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
error = EINVAL;
else if (ifa_ifwithaddr(gateway))
error = EHOSTUNREACH;
if (error)
goto done;
/*
* Create a new entry if we just got back a wildcard entry
* or the the lookup failed. This is necessary for hosts
* which use routing redirects generated by smart gateways
* to dynamically build the routing tables.
*/
if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
goto create;
/*
* Don't listen to the redirect if it's
* for a route to an interface.
*/
if (rt->rt_flags & RTF_GATEWAY) {
if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
/*
* Changing from route to net => route to host.
* Create new route, rather than smashing route to net.
*/
create:
flags |= RTF_GATEWAY | RTF_DYNAMIC;
error = rtrequest((int)RTM_ADD, dst, gateway,
netmask, flags,
(struct rtentry **)0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -