xref: /csrg-svn/sys/net/route.c (revision 6331)
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  */
22 route(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 
31 COUNT(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;
38 again:
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 
73 struct rtentry *
74 reroute(sa)
75 	register struct sockaddr *sa;
76 {
77 	register struct rtentry *rt;
78 	register struct mbuf *m;
79 	struct afhash h;
80 
81 COUNT(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  */
99 rtcontrol(req, addr)
100 	caddr_t addr;
101 {
102 	register struct rtreq rq;
103 	int x = splimp(), err = 0;
104 
105 COUNT(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);
113 bad:
114 	splx(x);
115 	return (err);
116 }
117 
118 /*
119  * Carry out a user request to modify the data base.
120  */
121 rtrequest(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;
135 again:
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;
186 newneighbor:
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 }
195