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