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