xref: /csrg-svn/sys/net/route.c (revision 10696)
1 /*	route.c	4.15	83/02/02	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/mbuf.h"
6 #include "../h/protosw.h"
7 #include "../h/socket.h"
8 #include "../h/ioctl.h"
9 #include "../net/if.h"
10 #include "../net/af.h"
11 #include "../net/route.h"
12 #include <errno.h>
13 
14 int	rttrash;		/* routes not in table but not freed */
15 /*
16  * Packet routing routines.
17  */
18 rtalloc(ro)
19 	register struct route *ro;
20 {
21 	register struct rtentry *rt, *rtmin;
22 	register struct mbuf *m;
23 	register unsigned hash;
24 	register int (*match)();
25 	struct afhash h;
26 	struct sockaddr *dst = &ro->ro_dst;
27 	int af = dst->sa_family;
28 
29 	if (ro->ro_rt && ro->ro_rt->rt_ifp)			/* XXX */
30 		return;
31 	if (af >= AF_MAX)
32 		return;
33 	(*afswitch[af].af_hash)(dst, &h);
34 	rtmin = 0, hash = h.afh_hosthash;
35 	for (m = rthost[hash % RTHASHSIZ]; m; m = m->m_next) {
36 		rt = mtod(m, struct rtentry *);
37 		if (rt->rt_hash != hash)
38 			continue;
39 		if ((rt->rt_flags & RTF_UP) == 0 ||
40 		    (rt->rt_ifp->if_flags & IFF_UP) == 0)
41 			continue;
42 		if (bcmp((caddr_t)&rt->rt_dst, (caddr_t)dst, sizeof (*dst)))
43 			continue;
44 		if (rtmin == 0 || rt->rt_use < rtmin->rt_use)
45 			rtmin = rt;
46 	}
47 	if (rtmin)
48 		goto found;
49 
50 	hash = h.afh_nethash;
51 	match = afswitch[af].af_netmatch;
52 	for (m = rtnet[hash % RTHASHSIZ]; m; m = m->m_next) {
53 		rt = mtod(m, struct rtentry *);
54 		if (rt->rt_hash != hash)
55 			continue;
56 		if ((rt->rt_flags & RTF_UP) == 0 ||
57 		    (rt->rt_ifp->if_flags & IFF_UP) == 0)
58 			continue;
59 		if (rt->rt_dst.sa_family != af || !(*match)(&rt->rt_dst, dst))
60 			continue;
61 		if (rtmin == 0 || rt->rt_use < rtmin->rt_use)
62 			rtmin = rt;
63 	}
64 found:
65 	ro->ro_rt = rtmin;
66 	if (rtmin)
67 		rtmin->rt_refcnt++;
68 }
69 
70 rtfree(rt)
71 	register struct rtentry *rt;
72 {
73 
74 	if (rt == 0)
75 		panic("rtfree");
76 	rt->rt_refcnt--;
77 	if (rt->rt_refcnt == 0 && (rt->rt_flags&RTF_UP) == 0) {
78 		rttrash--;
79 		(void) m_free(dtom(rt));
80 	}
81 }
82 
83 /*
84  * Carry out a request to change the routing table.  Called by
85  * interfaces at boot time to make their ``local routes'' known
86  * and for ioctl's.
87  */
88 rtrequest(req, entry)
89 	int req;
90 	register struct rtentry *entry;
91 {
92 	register struct mbuf *m, **mprev;
93 	register struct rtentry *rt;
94 	struct afhash h;
95 	int af, s, error = 0, hash, (*match)();
96 	struct ifnet *ifp;
97 
98 	af = entry->rt_dst.sa_family;
99 	if (af >= AF_MAX)
100 		return (EAFNOSUPPORT);
101 	(*afswitch[af].af_hash)(&entry->rt_dst, &h);
102 	if (entry->rt_flags & RTF_HOST) {
103 		hash = h.afh_hosthash;
104 		mprev = &rthost[hash % RTHASHSIZ];
105 	} else {
106 		hash = h.afh_nethash;
107 		mprev = &rtnet[hash % RTHASHSIZ];
108 	}
109 	match = afswitch[af].af_netmatch;
110 	s = splimp();
111 	for (; m = *mprev; mprev = &m->m_next) {
112 		rt = mtod(m, struct rtentry *);
113 		if (rt->rt_hash != hash)
114 			continue;
115 		if (entry->rt_flags & RTF_HOST) {
116 #define	equal(a1, a2) \
117 	(bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
118 			if (!equal(&rt->rt_dst, &entry->rt_dst))
119 				continue;
120 		} else {
121 			if (rt->rt_dst.sa_family != entry->rt_dst.sa_family ||
122 			    (*match)(&rt->rt_dst, &entry->rt_dst) == 0)
123 				continue;
124 		}
125 		if (equal(&rt->rt_gateway, &entry->rt_gateway))
126 			break;
127 	}
128 	switch (req) {
129 
130 	case SIOCDELRT:
131 		if (m == 0) {
132 			error = ESRCH;
133 			goto bad;
134 		}
135 		*mprev = m->m_next;
136 		if (rt->rt_refcnt > 0) {
137 			rt->rt_flags &= ~RTF_UP;
138 			rttrash++;
139 			m->m_next = 0;
140 		} else
141 			(void) m_free(m);
142 		break;
143 
144 	case SIOCADDRT:
145 		if (m) {
146 			error = EEXIST;
147 			goto bad;
148 		}
149 		ifp = if_ifwithaddr(&entry->rt_gateway);
150 		if (ifp == 0) {
151 			ifp = if_ifwithnet(&entry->rt_gateway);
152 			if (ifp == 0) {
153 				error = ENETUNREACH;
154 				goto bad;
155 			}
156 		}
157 		m = m_get(M_DONTWAIT, MT_RTABLE);
158 		if (m == 0) {
159 			error = ENOBUFS;
160 			goto bad;
161 		}
162 		*mprev = m;
163 		m->m_off = MMINOFF;
164 		m->m_len = sizeof (struct rtentry);
165 		rt = mtod(m, struct rtentry *);
166 		rt->rt_hash = hash;
167 		rt->rt_dst = entry->rt_dst;
168 		rt->rt_gateway = entry->rt_gateway;
169 		rt->rt_flags =
170 		    RTF_UP | (entry->rt_flags & (RTF_HOST|RTF_GATEWAY));
171 		rt->rt_refcnt = 0;
172 		rt->rt_use = 0;
173 		rt->rt_ifp = ifp;
174 		break;
175 	}
176 bad:
177 	splx(s);
178 	return (error);
179 }
180 
181 /*
182  * Set up a routing table entry, normally
183  * for an interface.
184  */
185 rtinit(dst, gateway, flags)
186 	struct sockaddr *dst, *gateway;
187 	int flags;
188 {
189 	struct rtentry route;
190 
191 	bzero((caddr_t)&route, sizeof (route));
192 	route.rt_dst = *dst;
193 	route.rt_gateway = *gateway;
194 	route.rt_flags = flags;
195 	(void) rtrequest((int)SIOCADDRT, &route);
196 }
197