date and time created 82/03/27 22:57:41 by sam
[unix-history] / usr / src / sys / net / route.c
CommitLineData
9d03c806
SL
1/* route.c 4.1 82/03/27 */
2
3#include "../h/param.h"
4#include "../h/mbuf.h"
5#include "../h/protosw.h"
6#include "../h/socket.h"
7#include "../h/socketvar.h"
8#include "../net/in.h"
9#include "../net/in_systm.h"
10#include "../net/af.h"
11#include "../net/route.h"
12#include <errno.h>
13
14/*
15 * Packet routing routines.
16 */
17
18/*
19 * With much ado about nothing...
20 * route the cars that climb halfway to the stars...
21 */
22route(ro)
23 register struct route *ro;
24{
25 register struct rtentry *rt, *rtmin;
26 register struct mbuf *m;
27 struct afhash h;
28 struct sockaddr *dst = &ro->ro_dst;
29 int af = dst->sa_family;
30
31COUNT(ROUTE);
32 if (ro->ro_ifp) /* ??? */
33 return;
34 (*afswitch[af].af_hash)(dst, &h);
35 m = routehash[h.afh_hosthash % RTHASHSIZ];
36 key = h.afh_hostkey;
37 rtmin = 0, doinghost = 1;
38again:
39 for (; m; m = m->m_next) {
40 rt = mtod(m, struct rtentry *);
41#define equal(a1, a2) \
42 (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof(struct sockaddr)) == 0)
43 if (rt->rt_key != key)
44 continue;
45 if (doinghost) {
46 if (!equal(&rt->rt_dst, dst))
47 continue;
48 } else {
49 if (rt->rt_dst.sa_family != af)
50 continue;
51 if ((*afswitch[af].af_netmatch)(&rt->rt_dst, dst) == 0)
52 continue;
53 }
54 if (rtmin == 0 || rt->rt_use < rtmin->rt_use)
55 rtmin = rt;
56 }
57 if (rtmin) {
58 ro->ro_dst = rt->rt_dst;
59 ro->ro_rt = rt;
60 rt->rt_refcnt++;
61 return;
62 }
63 if (doinghost) {
64 doinghost = 0;
65 m = routethash[h.afh_nethash % RTHASHSIZ];
66 key = h.afh_netkey;
67 goto again;
68 }
69 ro->ro_ifp = 0;
70 ro->ro_rt = 0;
71}
72
73struct rtentry *
74reroute(sa)
75 register struct sockaddr *sa;
76{
77 register struct rtentry *rt;
78 register struct mbuf *m;
79 struct afhash h;
80
81COUNT(REROUTE);
82 (*afswitch[sa->sa_family].af_hash)(sa, &h);
83 m = routehash[h.afh_hosthash];
84 key = h.afh_hostkey;
85 for (; m; m = m->m_next) {
86 rt = mtod(m, struct rtentry *);
87 if (rt->rt_key != key)
88 continue;
89 if (equal(&rt->rt_gateway, sa))
90 return (rt);
91 }
92 return (0);
93}
94
95/*
96 * Routing control calls allow a routing daemon
97 * to consistenly access the routing data base for updates.
98 */
99rtcontrol(req, addr)
100 caddr_t addr;
101{
102 register struct rtreq rq;
103 int x = splimp(), err = 0;
104
105COUNT(RTCONTROL);
106 if (suser())
107 goto bad;
108 if (copyin(addr, (caddr_t)&rq, sizeof(struct rtreq))) {
109 u.u_error = EFAULT;
110 goto bad;
111 }
112 err = rtrequest(req, &rq);
113bad:
114 splx(x);
115 return (err);
116}
117
118/*
119 * Carry out a user request to modify the data base.
120 */
121rtrequest(req, new)
122 int req;
123 register struct rtentry *new;
124{
125 register struct rtentry *rt;
126 register struct mbuf *m, **mprev;
127 struct sockaddr *sa = &new->rt_dst;
128 struct afhash h;
129 int af = sa->sa_family;
130
131 (*afswitch[af].af_hash)(sa, &h);
132 mprev = &routehash[h.afh_hosthash % RTHASHSIZ];
133 key = h.afh_hostkey;
134 doinghost = 1;
135again:
136 for (; m = *mprev; mprev = &m->m_next) {
137 rt = mtod(m, struct rtentry *);
138 if (rt->rt_key != key)
139 continue;
140 if (doinghost) {
141 if (!equal(&rt->rt_dst, dst))
142 continue;
143 } else {
144 if (rt->rt_dst.sa_family != af)
145 continue;
146 if ((*afswitch[af].af_netmatch)(&rt->rt_dst, sa) == 0)
147 continue;
148 }
149 break;
150 }
151 if (m == 0 && doinghost) {
152 doinghost = 0;
153 mprev = &routehash[h.afh_nethash % RTHASHSIZ];
154 key = h.afh_netkey;
155 goto again;
156 }
157
158 if (m == 0 && req != SIOCADDRT)
159 return (ESEARCH);
160 switch (req) {
161
162 case SIOCDELRT:
163 rt->rt_flags &= ~RTF_UP;
164 if (rt->rt_refcnt > 0) /* should we notify protocols? */
165 break;
166 *mprev = m_free(m);
167 break;
168
169 case SIOCCHGRT:
170 rt->rt_flags = new->rt_flags;
171 if (rt->rt_refcnt > 0)
172 return (EINUSE);
173 if (!equal(&rt->rt_gateway, &new->rt_gateway))
174 goto newneighbor;
175 break;
176
177 case SIOCADDRT:
178 m = m_getclr(M_DONTWAIT);
179 if (m == 0)
180 return (ENOBUFS);
181 m->m_off = MMINOFF;
182 *mprev = m;
183 rt = mtod(m, struct rtentry *);
184 *rt = *new;
185 rt->rt_key = h.afh_nethash | h.afh_hosthash;
186newneighbor:
187 rt->rt_ifp = if_ifonnetof(&new->rt_gateway);
188 if (rt->rt_ifp == 0)
189 rt->rt_flags &= ~RTF_UP;
190 rt->rt_refcnt = 0;
191 break;
192 }
193 return (0);
194}