first cut (incomplete) at routing
[unix-history] / usr / src / sys / net / route.c
CommitLineData
c124e997 1/* route.c 4.3 82/03/29 */
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"
9d03c806
SL
9#include "../net/in.h"
10#include "../net/in_systm.h"
ee787340 11#include "../net/if.h"
9d03c806
SL
12#include "../net/af.h"
13#include "../net/route.h"
c124e997 14#include <errno.h>
9d03c806
SL
15
16/*
17 * Packet routing routines.
18 */
19
20/*
21 * With much ado about nothing...
22 * route the cars that climb halfway to the stars...
23 */
c124e997 24allocroute(ro)
9d03c806
SL
25 register struct route *ro;
26{
27 register struct rtentry *rt, *rtmin;
28 register struct mbuf *m;
ee787340 29 register int key;
9d03c806
SL
30 struct afhash h;
31 struct sockaddr *dst = &ro->ro_dst;
ee787340 32 int af = dst->sa_family, doinghost;
9d03c806 33
c124e997
SL
34COUNT(ALLOCROUTE);
35 if (ro->ro_rt && ro->ro_rt->rt_ifp) /* can't happen */
9d03c806
SL
36 return;
37 (*afswitch[af].af_hash)(dst, &h);
38 m = routehash[h.afh_hosthash % RTHASHSIZ];
39 key = h.afh_hostkey;
40 rtmin = 0, doinghost = 1;
41again:
42 for (; m; m = m->m_next) {
43 rt = mtod(m, struct rtentry *);
9d03c806
SL
44 if (rt->rt_key != key)
45 continue;
46 if (doinghost) {
c124e997
SL
47#define equal(a1, a2) \
48 (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof(struct sockaddr)) == 0)
9d03c806
SL
49 if (!equal(&rt->rt_dst, dst))
50 continue;
51 } else {
52 if (rt->rt_dst.sa_family != af)
53 continue;
54 if ((*afswitch[af].af_netmatch)(&rt->rt_dst, dst) == 0)
55 continue;
56 }
57 if (rtmin == 0 || rt->rt_use < rtmin->rt_use)
58 rtmin = rt;
59 }
60 if (rtmin) {
61 ro->ro_dst = rt->rt_dst;
62 ro->ro_rt = rt;
63 rt->rt_refcnt++;
c124e997 64 return (rt->rt_flags & RTF_DIRECT);
9d03c806
SL
65 }
66 if (doinghost) {
67 doinghost = 0;
ee787340 68 m = routehash[h.afh_nethash % RTHASHSIZ];
9d03c806
SL
69 key = h.afh_netkey;
70 goto again;
71 }
9d03c806 72 ro->ro_rt = 0;
c124e997 73 return (0);
9d03c806
SL
74}
75
c124e997
SL
76freeroute(rt)
77 register struct rtentry *rt;
78{
79COUNT(FREEROUTE);
80 if (rt == 0)
81 panic("freeroute");
82 rt->rt_refcnt--;
83 /* on refcnt == 0 reclaim? notify someone? */
84}
85
86#ifdef notdef
9d03c806
SL
87struct rtentry *
88reroute(sa)
89 register struct sockaddr *sa;
90{
91 register struct rtentry *rt;
92 register struct mbuf *m;
ee787340 93 register int key;
9d03c806
SL
94 struct afhash h;
95
96COUNT(REROUTE);
97 (*afswitch[sa->sa_family].af_hash)(sa, &h);
98 m = routehash[h.afh_hosthash];
99 key = h.afh_hostkey;
100 for (; m; m = m->m_next) {
101 rt = mtod(m, struct rtentry *);
102 if (rt->rt_key != key)
103 continue;
104 if (equal(&rt->rt_gateway, sa))
105 return (rt);
106 }
107 return (0);
108}
c124e997 109#endif
9d03c806
SL
110
111/*
c124e997
SL
112 * Carry out a request to change the routing table. Called by
113 * interfaces at boot time to make their ``local routes'' known
114 * and for ioctl's.
9d03c806
SL
115 */
116rtrequest(req, new)
117 int req;
118 register struct rtentry *new;
119{
120 register struct rtentry *rt;
121 register struct mbuf *m, **mprev;
ee787340 122 register int key;
9d03c806
SL
123 struct sockaddr *sa = &new->rt_dst;
124 struct afhash h;
c124e997 125 int af = sa->sa_family, doinghost, s, error = 0;
9d03c806 126
c124e997 127COUNT(RTREQUEST);
9d03c806
SL
128 (*afswitch[af].af_hash)(sa, &h);
129 mprev = &routehash[h.afh_hosthash % RTHASHSIZ];
130 key = h.afh_hostkey;
131 doinghost = 1;
c124e997 132 s = splimp();
9d03c806
SL
133again:
134 for (; m = *mprev; mprev = &m->m_next) {
135 rt = mtod(m, struct rtentry *);
136 if (rt->rt_key != key)
137 continue;
138 if (doinghost) {
ee787340 139 if (!equal(&rt->rt_dst, &new->rt_dst))
9d03c806
SL
140 continue;
141 } else {
142 if (rt->rt_dst.sa_family != af)
143 continue;
144 if ((*afswitch[af].af_netmatch)(&rt->rt_dst, sa) == 0)
145 continue;
146 }
c124e997
SL
147 /* require full match on deletions */
148 if (req == SIOCDELRT &&
149 !equal(&rt->rt_gateway, &new->rt_gateway))
150 continue;
151 /* don't keep multiple identical entries */
152 if (req == SIOCADDRT &&
153 equal(&rt->rt_gateway, &new->rt_gateway)) {
154 error = EEXIST;
155 goto bad;
156 }
9d03c806
SL
157 break;
158 }
159 if (m == 0 && doinghost) {
160 doinghost = 0;
161 mprev = &routehash[h.afh_nethash % RTHASHSIZ];
162 key = h.afh_netkey;
163 goto again;
164 }
165
c124e997
SL
166 if (m == 0 && req != SIOCADDRT) {
167 error = ESRCH;
168 goto bad;
169 }
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? */
c124e997
SL
175 error = EBUSY;
176 else
177 *mprev = m_free(m);
9d03c806
SL
178 break;
179
180 case SIOCCHGRT:
181 rt->rt_flags = new->rt_flags;
182 if (rt->rt_refcnt > 0)
c124e997
SL
183 error = EBUSY;
184 else if (!equal(&rt->rt_gateway, &new->rt_gateway))
9d03c806
SL
185 goto newneighbor;
186 break;
187
188 case SIOCADDRT:
189 m = m_getclr(M_DONTWAIT);
c124e997
SL
190 if (m == 0) {
191 error = ENOBUFS;
192 break;
193 }
9d03c806
SL
194 m->m_off = MMINOFF;
195 *mprev = m;
196 rt = mtod(m, struct rtentry *);
197 *rt = *new;
198 rt->rt_key = h.afh_nethash | h.afh_hosthash;
199newneighbor:
200 rt->rt_ifp = if_ifonnetof(&new->rt_gateway);
201 if (rt->rt_ifp == 0)
202 rt->rt_flags &= ~RTF_UP;
203 rt->rt_refcnt = 0;
204 break;
205 }
c124e997
SL
206bad:
207 splx(s);
208 return (error);
9d03c806 209}