Commit | Line | Data |
---|---|---|
e831d540 | 1 | /* |
ad787160 C |
2 | * Copyright (c) 1988, 1991, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
e831d540 | 4 | * |
ad787160 C |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
e831d540 | 20 | * |
ad787160 C |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | * | |
33 | * @(#)rtsock.c 8.1 (Berkeley) 6/10/93 | |
e831d540 KS |
34 | */ |
35 | ||
5548a02f KB |
36 | #include <sys/param.h> |
37 | #include <sys/systm.h> | |
38 | #include <sys/proc.h> | |
39 | #include <sys/mbuf.h> | |
40 | #include <sys/socket.h> | |
41 | #include <sys/socketvar.h> | |
42 | #include <sys/domain.h> | |
43 | #include <sys/protosw.h> | |
e831d540 | 44 | |
5548a02f KB |
45 | #include <net/af.h> |
46 | #include <net/if.h> | |
47 | #include <net/route.h> | |
48 | #include <net/raw_cb.h> | |
e831d540 | 49 | |
e684b424 KS |
50 | struct sockaddr route_dst = { 2, PF_ROUTE, }; |
51 | struct sockaddr route_src = { 2, PF_ROUTE, }; | |
52 | struct sockproto route_proto = { PF_ROUTE, }; | |
53 | ||
54 | struct walkarg { | |
55 | int w_op, w_arg, w_given, w_needed, w_tmemsize; | |
56 | caddr_t w_where, w_tmem; | |
57 | }; | |
58 | ||
a15dacc5 KB |
59 | static struct mbuf * |
60 | rt_msg1 __P((int, struct rt_addrinfo *)); | |
61 | static int rt_msg2 __P((int, | |
62 | struct rt_addrinfo *, caddr_t, struct walkarg *)); | |
63 | static void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); | |
e684b424 KS |
64 | |
65 | /* Sleazy use of local variables throughout file, warning!!!! */ | |
66 | #define dst info.rti_info[RTAX_DST] | |
67 | #define gate info.rti_info[RTAX_GATEWAY] | |
68 | #define netmask info.rti_info[RTAX_NETMASK] | |
69 | #define genmask info.rti_info[RTAX_GENMASK] | |
70 | #define ifpaddr info.rti_info[RTAX_IFP] | |
71 | #define ifaaddr info.rti_info[RTAX_IFA] | |
72 | #define brdaddr info.rti_info[RTAX_BRD] | |
b72a6efb | 73 | |
e831d540 | 74 | /*ARGSUSED*/ |
a15dacc5 | 75 | int |
a0d75f26 | 76 | route_usrreq(so, req, m, nam, control) |
e831d540 KS |
77 | register struct socket *so; |
78 | int req; | |
a0d75f26 | 79 | struct mbuf *m, *nam, *control; |
e831d540 KS |
80 | { |
81 | register int error = 0; | |
82 | register struct rawcb *rp = sotorawcb(so); | |
67336957 | 83 | int s; |
b72a6efb KS |
84 | if (req == PRU_ATTACH) { |
85 | MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); | |
86 | if (so->so_pcb = (caddr_t)rp) | |
87 | bzero(so->so_pcb, sizeof(*rp)); | |
88 | ||
89 | } | |
e831d540 KS |
90 | if (req == PRU_DETACH && rp) { |
91 | int af = rp->rcb_proto.sp_protocol; | |
92 | if (af == AF_INET) | |
93 | route_cb.ip_count--; | |
94 | else if (af == AF_NS) | |
95 | route_cb.ns_count--; | |
e831d540 KS |
96 | else if (af == AF_ISO) |
97 | route_cb.iso_count--; | |
e831d540 KS |
98 | route_cb.any_count--; |
99 | } | |
67336957 | 100 | s = splnet(); |
a0d75f26 | 101 | error = raw_usrreq(so, req, m, nam, control); |
e831d540 | 102 | rp = sotorawcb(so); |
b72a6efb | 103 | if (req == PRU_ATTACH && rp) { |
e831d540 | 104 | int af = rp->rcb_proto.sp_protocol; |
b72a6efb KS |
105 | if (error) { |
106 | free((caddr_t)rp, M_PCB); | |
67336957 | 107 | splx(s); |
b72a6efb KS |
108 | return (error); |
109 | } | |
e831d540 KS |
110 | if (af == AF_INET) |
111 | route_cb.ip_count++; | |
112 | else if (af == AF_NS) | |
113 | route_cb.ns_count++; | |
e831d540 KS |
114 | else if (af == AF_ISO) |
115 | route_cb.iso_count++; | |
b72a6efb | 116 | rp->rcb_faddr = &route_src; |
e831d540 KS |
117 | route_cb.any_count++; |
118 | soisconnected(so); | |
2e5be88b | 119 | so->so_options |= SO_USELOOPBACK; |
e831d540 | 120 | } |
67336957 | 121 | splx(s); |
e831d540 KS |
122 | return (error); |
123 | } | |
e831d540 | 124 | |
b72a6efb | 125 | /*ARGSUSED*/ |
a15dacc5 | 126 | int |
e831d540 KS |
127 | route_output(m, so) |
128 | register struct mbuf *m; | |
129 | struct socket *so; | |
130 | { | |
67336957 | 131 | register struct rt_msghdr *rtm = 0; |
e831d540 | 132 | register struct rtentry *rt = 0; |
a0d75f26 | 133 | struct rtentry *saved_nrt = 0; |
e684b424 | 134 | struct rt_addrinfo info; |
b72a6efb | 135 | int len, error = 0; |
d6bc9b28 | 136 | struct ifnet *ifp = 0; |
f157971f | 137 | struct ifaddr *ifa = 0; |
e831d540 | 138 | |
a0d75f26 | 139 | #define senderr(e) { error = e; goto flush;} |
2bd12e1b KS |
140 | if (m == 0 || ((m->m_len < sizeof(long)) && |
141 | (m = m_pullup(m, sizeof(long))) == 0)) | |
32dfe9ab | 142 | return (ENOBUFS); |
e831d540 | 143 | if ((m->m_flags & M_PKTHDR) == 0) |
32dfe9ab | 144 | panic("route_output"); |
e831d540 | 145 | len = m->m_pkthdr.len; |
67336957 | 146 | if (len < sizeof(*rtm) || |
00feb013 RC |
147 | len != mtod(m, struct rt_msghdr *)->rtm_msglen) { |
148 | dst = 0; | |
a0d75f26 | 149 | senderr(EINVAL); |
00feb013 | 150 | } |
e831d540 | 151 | R_Malloc(rtm, struct rt_msghdr *, len); |
00feb013 RC |
152 | if (rtm == 0) { |
153 | dst = 0; | |
a0d75f26 | 154 | senderr(ENOBUFS); |
00feb013 | 155 | } |
e831d540 | 156 | m_copydata(m, 0, len, (caddr_t)rtm); |
00feb013 RC |
157 | if (rtm->rtm_version != RTM_VERSION) { |
158 | dst = 0; | |
a0d75f26 | 159 | senderr(EPROTONOSUPPORT); |
00feb013 | 160 | } |
31c32e48 | 161 | rtm->rtm_pid = curproc->p_pid; |
e684b424 KS |
162 | info.rti_addrs = rtm->rtm_addrs; |
163 | rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info); | |
164 | if (dst == 0) | |
79e0ea5d | 165 | senderr(EINVAL); |
e684b424 | 166 | if (genmask) { |
a15dacc5 KB |
167 | struct radix_node *t; |
168 | t = rn_addmask((caddr_t)genmask, 1, 2); | |
d6bc9b28 KS |
169 | if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0) |
170 | genmask = (struct sockaddr *)(t->rn_key); | |
171 | else | |
172 | senderr(ENOBUFS); | |
173 | } | |
e831d540 | 174 | switch (rtm->rtm_type) { |
e684b424 | 175 | |
e831d540 | 176 | case RTM_ADD: |
79e0ea5d KS |
177 | if (gate == 0) |
178 | senderr(EINVAL); | |
e831d540 KS |
179 | error = rtrequest(RTM_ADD, dst, gate, netmask, |
180 | rtm->rtm_flags, &saved_nrt); | |
79e0ea5d KS |
181 | if (error == 0 && saved_nrt) { |
182 | rt_setmetrics(rtm->rtm_inits, | |
183 | &rtm->rtm_rmx, &saved_nrt->rt_rmx); | |
a0d75f26 | 184 | saved_nrt->rt_refcnt--; |
d6bc9b28 | 185 | saved_nrt->rt_genmask = genmask; |
79e0ea5d | 186 | } |
e831d540 KS |
187 | break; |
188 | ||
189 | case RTM_DELETE: | |
190 | error = rtrequest(RTM_DELETE, dst, gate, netmask, | |
b72a6efb | 191 | rtm->rtm_flags, (struct rtentry **)0); |
e831d540 KS |
192 | break; |
193 | ||
194 | case RTM_GET: | |
195 | case RTM_CHANGE: | |
196 | case RTM_LOCK: | |
197 | rt = rtalloc1(dst, 0); | |
198 | if (rt == 0) | |
a0d75f26 | 199 | senderr(ESRCH); |
5f88e1ef | 200 | if (rtm->rtm_type != RTM_GET) {/* XXX: too grotty */ |
a15dacc5 | 201 | struct radix_node *rn; |
5f88e1ef KS |
202 | extern struct radix_node_head *mask_rnhead; |
203 | ||
f157971f KS |
204 | if (Bcmp(dst, rt_key(rt), dst->sa_len) != 0) |
205 | senderr(ESRCH); | |
5f88e1ef | 206 | if (netmask && (rn = rn_search(netmask, |
222d6275 | 207 | mask_rnhead->rnh_treetop))) |
5f88e1ef KS |
208 | netmask = (struct sockaddr *)rn->rn_key; |
209 | for (rn = rt->rt_nodes; rn; rn = rn->rn_dupedkey) | |
210 | if (netmask == (struct sockaddr *)rn->rn_mask) | |
211 | break; | |
212 | if (rn == 0) | |
f3de5579 | 213 | senderr(ETOOMANYREFS); |
5f88e1ef | 214 | rt = (struct rtentry *)rn; |
f3de5579 | 215 | } |
e831d540 | 216 | switch(rtm->rtm_type) { |
e831d540 KS |
217 | |
218 | case RTM_GET: | |
e684b424 KS |
219 | dst = rt_key(rt); |
220 | gate = rt->rt_gateway; | |
221 | netmask = rt_mask(rt); | |
222 | genmask = rt->rt_genmask; | |
371d5f56 | 223 | if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { |
e684b424 KS |
224 | if (ifp = rt->rt_ifp) { |
225 | ifpaddr = ifp->if_addrlist->ifa_addr; | |
371d5f56 | 226 | ifaaddr = rt->rt_ifa->ifa_addr; |
e684b424 | 227 | rtm->rtm_index = ifp->if_index; |
371d5f56 | 228 | } else { |
e684b424 KS |
229 | ifpaddr = 0; |
230 | ifaaddr = 0; | |
231 | } | |
371d5f56 | 232 | } |
e684b424 KS |
233 | len = rt_msg2(RTM_GET, &info, (caddr_t)0, |
234 | (struct walkarg *)0); | |
e831d540 KS |
235 | if (len > rtm->rtm_msglen) { |
236 | struct rt_msghdr *new_rtm; | |
237 | R_Malloc(new_rtm, struct rt_msghdr *, len); | |
238 | if (new_rtm == 0) | |
a0d75f26 | 239 | senderr(ENOBUFS); |
e831d540 KS |
240 | Bcopy(rtm, new_rtm, rtm->rtm_msglen); |
241 | Free(rtm); rtm = new_rtm; | |
f3de5579 | 242 | } |
e684b424 KS |
243 | (void)rt_msg2(RTM_GET, &info, (caddr_t)rtm, |
244 | (struct walkarg *)0); | |
f3de5579 KS |
245 | rtm->rtm_flags = rt->rt_flags; |
246 | rtm->rtm_rmx = rt->rt_rmx; | |
48d4b313 | 247 | rtm->rtm_addrs = info.rti_addrs; |
e831d540 KS |
248 | break; |
249 | ||
250 | case RTM_CHANGE: | |
1a4f8a91 | 251 | if (gate && rt_setgate(rt, rt_key(rt), gate)) |
a0d75f26 | 252 | senderr(EDQUOT); |
d6bc9b28 KS |
253 | /* new gateway could require new ifaddr, ifp; |
254 | flags may also be different; ifp may be specified | |
255 | by ll sockaddr when protocol address is ambiguous */ | |
f157971f KS |
256 | if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) && |
257 | (ifp = ifa->ifa_ifp)) | |
258 | ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, | |
259 | ifp); | |
260 | else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) || | |
261 | (ifa = ifa_ifwithroute(rt->rt_flags, | |
262 | rt_key(rt), gate))) | |
263 | ifp = ifa->ifa_ifp; | |
d6bc9b28 | 264 | if (ifa) { |
f157971f KS |
265 | register struct ifaddr *oifa = rt->rt_ifa; |
266 | if (oifa != ifa) { | |
267 | if (oifa && oifa->ifa_rtrequest) | |
268 | oifa->ifa_rtrequest(RTM_DELETE, | |
269 | rt, gate); | |
222d6275 | 270 | IFAFREE(rt->rt_ifa); |
d6bc9b28 | 271 | rt->rt_ifa = ifa; |
222d6275 | 272 | ifa->ifa_refcnt++; |
f157971f | 273 | rt->rt_ifp = ifp; |
d6bc9b28 KS |
274 | } |
275 | } | |
f157971f KS |
276 | rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, |
277 | &rt->rt_rmx); | |
d6bc9b28 KS |
278 | if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) |
279 | rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate); | |
280 | if (genmask) | |
281 | rt->rt_genmask = genmask; | |
e831d540 KS |
282 | /* |
283 | * Fall into | |
284 | */ | |
79e0ea5d | 285 | case RTM_LOCK: |
0274ce41 | 286 | rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); |
79e0ea5d KS |
287 | rt->rt_rmx.rmx_locks |= |
288 | (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); | |
e831d540 | 289 | break; |
e831d540 | 290 | } |
e684b424 | 291 | break; |
e831d540 KS |
292 | |
293 | default: | |
a0d75f26 | 294 | senderr(EOPNOTSUPP); |
e831d540 KS |
295 | } |
296 | ||
297 | flush: | |
298 | if (rtm) { | |
299 | if (error) | |
300 | rtm->rtm_errno = error; | |
301 | else | |
302 | rtm->rtm_flags |= RTF_DONE; | |
303 | } | |
304 | cleanup: | |
305 | if (rt) | |
306 | rtfree(rt); | |
2e5be88b KS |
307 | { |
308 | register struct rawcb *rp = 0; | |
309 | /* | |
310 | * Check to see if we don't want our own messages. | |
311 | */ | |
312 | if ((so->so_options & SO_USELOOPBACK) == 0) { | |
313 | if (route_cb.any_count <= 1) { | |
314 | if (rtm) | |
315 | Free(rtm); | |
316 | m_freem(m); | |
317 | return (error); | |
318 | } | |
319 | /* There is another listener, so construct message */ | |
320 | rp = sotorawcb(so); | |
321 | } | |
371d5f56 KS |
322 | if (rtm) { |
323 | m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); | |
32dfe9ab KS |
324 | Free(rtm); |
325 | } | |
2e5be88b KS |
326 | if (rp) |
327 | rp->rcb_proto.sp_family = 0; /* Avoid us */ | |
f3de5579 KS |
328 | if (dst) |
329 | route_proto.sp_protocol = dst->sa_family; | |
32dfe9ab | 330 | raw_input(m, &route_proto, &route_src, &route_dst); |
2e5be88b KS |
331 | if (rp) |
332 | rp->rcb_proto.sp_family = PF_ROUTE; | |
333 | } | |
e831d540 KS |
334 | return (error); |
335 | } | |
336 | ||
a15dacc5 | 337 | void |
d6bc9b28 | 338 | rt_setmetrics(which, in, out) |
79e0ea5d KS |
339 | u_long which; |
340 | register struct rt_metrics *in, *out; | |
341 | { | |
342 | #define metric(f, e) if (which & (f)) out->e = in->e; | |
343 | metric(RTV_RPIPE, rmx_recvpipe); | |
344 | metric(RTV_SPIPE, rmx_sendpipe); | |
345 | metric(RTV_SSTHRESH, rmx_ssthresh); | |
346 | metric(RTV_RTT, rmx_rtt); | |
347 | metric(RTV_RTTVAR, rmx_rttvar); | |
348 | metric(RTV_HOPCOUNT, rmx_hopcount); | |
349 | metric(RTV_MTU, rmx_mtu); | |
4784d9b2 | 350 | metric(RTV_EXPIRE, rmx_expire); |
79e0ea5d KS |
351 | #undef metric |
352 | } | |
353 | ||
e684b424 KS |
354 | #define ROUNDUP(a) \ |
355 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) | |
356 | #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) | |
357 | ||
358 | static void | |
359 | rt_xaddrs(cp, cplim, rtinfo) | |
360 | register caddr_t cp, cplim; | |
361 | register struct rt_addrinfo *rtinfo; | |
362 | { | |
363 | register struct sockaddr *sa; | |
364 | register int i; | |
365 | ||
366 | bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); | |
367 | for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { | |
368 | if ((rtinfo->rti_addrs & (1 << i)) == 0) | |
369 | continue; | |
370 | rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; | |
371 | ADVANCE(cp, sa); | |
372 | } | |
373 | } | |
00feb013 | 374 | |
e831d540 KS |
375 | /* |
376 | * Copy data from a buffer back into the indicated mbuf chain, | |
377 | * starting "off" bytes from the beginning, extending the mbuf | |
378 | * chain if necessary. | |
379 | */ | |
a15dacc5 | 380 | void |
e831d540 KS |
381 | m_copyback(m0, off, len, cp) |
382 | struct mbuf *m0; | |
383 | register int off; | |
384 | register int len; | |
385 | caddr_t cp; | |
e831d540 KS |
386 | { |
387 | register int mlen; | |
388 | register struct mbuf *m = m0, *n; | |
389 | int totlen = 0; | |
390 | ||
391 | if (m0 == 0) | |
392 | return; | |
31c32e48 | 393 | while (off > (mlen = m->m_len)) { |
e831d540 KS |
394 | off -= mlen; |
395 | totlen += mlen; | |
396 | if (m->m_next == 0) { | |
397 | n = m_getclr(M_DONTWAIT, m->m_type); | |
398 | if (n == 0) | |
399 | goto out; | |
400 | n->m_len = min(MLEN, len + off); | |
401 | m->m_next = n; | |
402 | } | |
403 | m = m->m_next; | |
404 | } | |
405 | while (len > 0) { | |
406 | mlen = min (m->m_len - off, len); | |
b72a6efb | 407 | bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); |
e831d540 KS |
408 | cp += mlen; |
409 | len -= mlen; | |
410 | mlen += off; | |
411 | off = 0; | |
412 | totlen += mlen; | |
413 | if (len == 0) | |
414 | break; | |
415 | if (m->m_next == 0) { | |
416 | n = m_get(M_DONTWAIT, m->m_type); | |
417 | if (n == 0) | |
418 | break; | |
419 | n->m_len = min(MLEN, len); | |
420 | m->m_next = n; | |
421 | } | |
422 | m = m->m_next; | |
423 | } | |
424 | out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) | |
425 | m->m_pkthdr.len = totlen; | |
426 | } | |
427 | ||
e684b424 KS |
428 | static struct mbuf * |
429 | rt_msg1(type, rtinfo) | |
430 | int type; | |
431 | register struct rt_addrinfo *rtinfo; | |
e831d540 KS |
432 | { |
433 | register struct rt_msghdr *rtm; | |
434 | register struct mbuf *m; | |
e684b424 KS |
435 | register int i; |
436 | register struct sockaddr *sa; | |
437 | int len, dlen; | |
e831d540 | 438 | |
e831d540 KS |
439 | m = m_gethdr(M_DONTWAIT, MT_DATA); |
440 | if (m == 0) | |
e684b424 KS |
441 | return (m); |
442 | switch (type) { | |
443 | ||
444 | case RTM_DELADDR: | |
445 | case RTM_NEWADDR: | |
446 | len = sizeof(struct ifa_msghdr); | |
447 | break; | |
448 | ||
449 | case RTM_IFINFO: | |
450 | len = sizeof(struct if_msghdr); | |
451 | break; | |
452 | ||
453 | default: | |
454 | len = sizeof(struct rt_msghdr); | |
455 | } | |
456 | if (len > MHLEN) | |
457 | panic("rt_msg1"); | |
458 | m->m_pkthdr.len = m->m_len = len; | |
e831d540 KS |
459 | m->m_pkthdr.rcvif = 0; |
460 | rtm = mtod(m, struct rt_msghdr *); | |
e684b424 KS |
461 | bzero((caddr_t)rtm, len); |
462 | for (i = 0; i < RTAX_MAX; i++) { | |
463 | if ((sa = rtinfo->rti_info[i]) == NULL) | |
464 | continue; | |
465 | rtinfo->rti_addrs |= (1 << i); | |
466 | dlen = ROUNDUP(sa->sa_len); | |
467 | m_copyback(m, len, dlen, (caddr_t)sa); | |
468 | len += dlen; | |
469 | } | |
470 | if (m->m_pkthdr.len != len) { | |
471 | m_freem(m); | |
472 | return (NULL); | |
473 | } | |
e831d540 | 474 | rtm->rtm_msglen = len; |
79e0ea5d | 475 | rtm->rtm_version = RTM_VERSION; |
e831d540 | 476 | rtm->rtm_type = type; |
e684b424 KS |
477 | return (m); |
478 | } | |
479 | ||
480 | static int | |
481 | rt_msg2(type, rtinfo, cp, w) | |
482 | int type; | |
483 | register struct rt_addrinfo *rtinfo; | |
484 | caddr_t cp; | |
485 | struct walkarg *w; | |
486 | { | |
487 | register int i; | |
488 | int len, dlen, second_time = 0; | |
489 | caddr_t cp0; | |
490 | ||
491 | rtinfo->rti_addrs = 0; | |
492 | again: | |
493 | switch (type) { | |
494 | ||
495 | case RTM_DELADDR: | |
496 | case RTM_NEWADDR: | |
497 | len = sizeof(struct ifa_msghdr); | |
498 | break; | |
499 | ||
500 | case RTM_IFINFO: | |
501 | len = sizeof(struct if_msghdr); | |
502 | break; | |
503 | ||
504 | default: | |
505 | len = sizeof(struct rt_msghdr); | |
e831d540 | 506 | } |
e684b424 KS |
507 | if (cp0 = cp) |
508 | cp += len; | |
509 | for (i = 0; i < RTAX_MAX; i++) { | |
510 | register struct sockaddr *sa; | |
511 | ||
512 | if ((sa = rtinfo->rti_info[i]) == 0) | |
513 | continue; | |
514 | rtinfo->rti_addrs |= (1 << i); | |
515 | dlen = ROUNDUP(sa->sa_len); | |
516 | if (cp) { | |
517 | bcopy((caddr_t)sa, cp, (unsigned)dlen); | |
518 | cp += dlen; | |
519 | } | |
e831d540 | 520 | len += dlen; |
e831d540 | 521 | } |
e684b424 KS |
522 | if (cp == 0 && w != NULL && !second_time) { |
523 | register struct walkarg *rw = w; | |
524 | ||
525 | rw->w_needed += len; | |
526 | if (rw->w_needed <= 0 && rw->w_where) { | |
527 | if (rw->w_tmemsize < len) { | |
528 | if (rw->w_tmem) | |
529 | free(rw->w_tmem, M_RTABLE); | |
530 | if (rw->w_tmem = (caddr_t) | |
531 | malloc(len, M_RTABLE, M_NOWAIT)) | |
532 | rw->w_tmemsize = len; | |
533 | } | |
534 | if (rw->w_tmem) { | |
535 | cp = rw->w_tmem; | |
536 | second_time = 1; | |
537 | goto again; | |
538 | } else | |
539 | rw->w_where = 0; | |
540 | } | |
e831d540 | 541 | } |
e684b424 KS |
542 | if (cp) { |
543 | register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; | |
544 | ||
545 | rtm->rtm_version = RTM_VERSION; | |
546 | rtm->rtm_type = type; | |
547 | rtm->rtm_msglen = len; | |
e831d540 | 548 | } |
e684b424 KS |
549 | return (len); |
550 | } | |
551 | ||
552 | /* | |
553 | * This routine is called to generate a message from the routing | |
554 | * socket indicating that a redirect has occured, a routing lookup | |
555 | * has failed, or that a protocol has detected timeouts to a particular | |
556 | * destination. | |
557 | */ | |
a15dacc5 | 558 | void |
e684b424 KS |
559 | rt_missmsg(type, rtinfo, flags, error) |
560 | int type, flags, error; | |
561 | register struct rt_addrinfo *rtinfo; | |
562 | { | |
563 | register struct rt_msghdr *rtm; | |
564 | register struct mbuf *m; | |
565 | register int i; | |
566 | struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; | |
567 | ||
568 | if (route_cb.any_count == 0) | |
e831d540 | 569 | return; |
e684b424 KS |
570 | m = rt_msg1(type, rtinfo); |
571 | if (m == 0) | |
572 | return; | |
573 | rtm = mtod(m, struct rt_msghdr *); | |
574 | rtm->rtm_flags = RTF_DONE | flags; | |
b72a6efb | 575 | rtm->rtm_errno = error; |
e684b424 KS |
576 | rtm->rtm_addrs = rtinfo->rti_addrs; |
577 | route_proto.sp_protocol = sa ? sa->sa_family : 0; | |
e831d540 KS |
578 | raw_input(m, &route_proto, &route_src, &route_dst); |
579 | } | |
580 | ||
e684b424 KS |
581 | /* |
582 | * This routine is called to generate a message from the routing | |
583 | * socket indicating that the status of a network interface has changed. | |
584 | */ | |
a15dacc5 | 585 | void |
e684b424 KS |
586 | rt_ifmsg(ifp) |
587 | register struct ifnet *ifp; | |
588 | { | |
589 | register struct if_msghdr *ifm; | |
590 | struct mbuf *m; | |
591 | struct rt_addrinfo info; | |
592 | ||
593 | if (route_cb.any_count == 0) | |
594 | return; | |
595 | bzero((caddr_t)&info, sizeof(info)); | |
596 | m = rt_msg1(RTM_IFINFO, &info); | |
597 | if (m == 0) | |
598 | return; | |
599 | ifm = mtod(m, struct if_msghdr *); | |
600 | ifm->ifm_index = ifp->if_index; | |
601 | ifm->ifm_flags = ifp->if_flags; | |
602 | ifm->ifm_data = ifp->if_data; | |
603 | ifm->ifm_addrs = 0; | |
604 | route_proto.sp_protocol = 0; | |
605 | raw_input(m, &route_proto, &route_src, &route_dst); | |
606 | } | |
607 | ||
608 | /* | |
609 | * This is called to generate messages from the routing socket | |
610 | * indicating a network interface has had addresses associated with it. | |
611 | * if we ever reverse the logic and replace messages TO the routing | |
612 | * socket indicate a request to configure interfaces, then it will | |
613 | * be unnecessary as the routing socket will automatically generate | |
614 | * copies of it. | |
615 | */ | |
a15dacc5 | 616 | void |
e684b424 KS |
617 | rt_newaddrmsg(cmd, ifa, error, rt) |
618 | int cmd, error; | |
619 | register struct ifaddr *ifa; | |
620 | register struct rtentry *rt; | |
621 | { | |
622 | struct rt_addrinfo info; | |
623 | struct sockaddr *sa; | |
624 | int pass; | |
625 | struct mbuf *m; | |
626 | struct ifnet *ifp = ifa->ifa_ifp; | |
627 | ||
628 | if (route_cb.any_count == 0) | |
629 | return; | |
630 | for (pass = 1; pass < 3; pass++) { | |
631 | bzero((caddr_t)&info, sizeof(info)); | |
632 | if ((cmd == RTM_ADD && pass == 1) || | |
633 | (cmd == RTM_DELETE && pass == 2)) { | |
634 | register struct ifa_msghdr *ifam; | |
635 | int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; | |
636 | ||
637 | ifaaddr = sa = ifa->ifa_addr; | |
638 | ifpaddr = ifp->if_addrlist->ifa_addr; | |
639 | netmask = ifa->ifa_netmask; | |
640 | brdaddr = ifa->ifa_dstaddr; | |
641 | if ((m = rt_msg1(ncmd, &info)) == NULL) | |
642 | continue; | |
643 | ifam = mtod(m, struct ifa_msghdr *); | |
644 | ifam->ifam_index = ifp->if_index; | |
645 | ifam->ifam_metric = ifa->ifa_metric; | |
7c4c8224 | 646 | ifam->ifam_flags = ifa->ifa_flags; |
e684b424 KS |
647 | ifam->ifam_addrs = info.rti_addrs; |
648 | } | |
649 | if ((cmd == RTM_ADD && pass == 2) || | |
650 | (cmd == RTM_DELETE && pass == 1)) { | |
651 | register struct rt_msghdr *rtm; | |
652 | ||
653 | if (rt == 0) | |
654 | continue; | |
655 | netmask = rt_mask(rt); | |
656 | dst = sa = rt_key(rt); | |
657 | gate = rt->rt_gateway; | |
658 | if ((m = rt_msg1(cmd, &info)) == NULL) | |
659 | continue; | |
660 | rtm = mtod(m, struct rt_msghdr *); | |
661 | rtm->rtm_index = ifp->if_index; | |
662 | rtm->rtm_flags |= rt->rt_flags; | |
663 | rtm->rtm_errno = error; | |
664 | rtm->rtm_addrs = info.rti_addrs; | |
665 | } | |
666 | route_proto.sp_protocol = sa ? sa->sa_family : 0; | |
667 | raw_input(m, &route_proto, &route_src, &route_dst); | |
668 | } | |
669 | } | |
670 | ||
a0d75f26 | 671 | /* |
ee0f9e0d | 672 | * This is used in dumping the kernel table via sysctl(). |
a0d75f26 | 673 | */ |
a15dacc5 | 674 | int |
ee0f9e0d | 675 | sysctl_dumpentry(rn, w) |
a0d75f26 KS |
676 | struct radix_node *rn; |
677 | register struct walkarg *w; | |
678 | { | |
679 | register struct sockaddr *sa; | |
a0d75f26 | 680 | register struct rtentry *rt = (struct rtentry *)rn; |
e684b424 KS |
681 | int n, error = 0, size; |
682 | struct rt_addrinfo info; | |
a0d75f26 | 683 | |
ee0f9e0d | 684 | if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) |
1f29be1c | 685 | return 0; |
e684b424 KS |
686 | bzero((caddr_t)&info, sizeof(info)); |
687 | dst = rt_key(rt); | |
688 | gate = rt->rt_gateway; | |
689 | netmask = rt_mask(rt); | |
690 | genmask = rt->rt_genmask; | |
691 | size = rt_msg2(RTM_GET, &info, 0, w); | |
692 | if (w->w_where && w->w_tmem) { | |
693 | register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; | |
694 | ||
695 | rtm->rtm_flags = rt->rt_flags; | |
696 | rtm->rtm_use = rt->rt_use; | |
697 | rtm->rtm_rmx = rt->rt_rmx; | |
698 | rtm->rtm_index = rt->rt_ifp->if_index; | |
699 | rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; | |
700 | rtm->rtm_addrs = info.rti_addrs; | |
701 | if (error = copyout((caddr_t)rtm, w->w_where, size)) | |
702 | w->w_where = NULL; | |
703 | else | |
704 | w->w_where += size; | |
705 | } | |
706 | return (error); | |
707 | } | |
708 | ||
a15dacc5 | 709 | int |
ee0f9e0d | 710 | sysctl_iflist(af, w) |
e684b424 KS |
711 | int af; |
712 | register struct walkarg *w; | |
713 | { | |
714 | register struct ifnet *ifp; | |
715 | register struct ifaddr *ifa; | |
716 | struct rt_addrinfo info; | |
717 | struct sockaddr *sa; | |
718 | int len, error = 0; | |
719 | ||
720 | bzero((caddr_t)&info, sizeof(info)); | |
721 | for (ifp = ifnet; ifp; ifp = ifp->if_next) { | |
f21e4b71 KS |
722 | if (w->w_arg && w->w_arg != ifp->if_index) |
723 | continue; | |
e684b424 KS |
724 | ifa = ifp->if_addrlist; |
725 | ifpaddr = ifa->ifa_addr; | |
726 | len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w); | |
727 | ifpaddr = 0; | |
728 | if (w->w_where && w->w_tmem) { | |
729 | register struct if_msghdr *ifm; | |
730 | ||
731 | ifm = (struct if_msghdr *)w->w_tmem; | |
732 | ifm->ifm_index = ifp->if_index; | |
733 | ifm->ifm_flags = ifp->if_flags; | |
734 | ifm->ifm_data = ifp->if_data; | |
735 | ifm->ifm_addrs = info.rti_addrs; | |
736 | if (error = copyout((caddr_t)ifm, w->w_where, len)) | |
737 | return (error); | |
738 | w->w_where += len; | |
739 | } | |
740 | while (ifa = ifa->ifa_next) { | |
f21e4b71 KS |
741 | if (af && af != ifa->ifa_addr->sa_family) |
742 | continue; | |
e684b424 KS |
743 | ifaaddr = ifa->ifa_addr; |
744 | netmask = ifa->ifa_netmask; | |
745 | brdaddr = ifa->ifa_dstaddr; | |
746 | len = rt_msg2(RTM_NEWADDR, &info, 0, w); | |
747 | if (w->w_where && w->w_tmem) { | |
748 | register struct ifa_msghdr *ifam; | |
749 | ||
750 | ifam = (struct ifa_msghdr *)w->w_tmem; | |
751 | ifam->ifam_index = ifa->ifa_ifp->if_index; | |
752 | ifam->ifam_flags = ifa->ifa_flags; | |
753 | ifam->ifam_metric = ifa->ifa_metric; | |
754 | ifam->ifam_addrs = info.rti_addrs; | |
755 | if (error = copyout(w->w_tmem, w->w_where, len)) | |
756 | return (error); | |
757 | w->w_where += len; | |
758 | } | |
e684b424 | 759 | } |
f21e4b71 | 760 | ifaaddr = netmask = brdaddr = 0; |
a0d75f26 | 761 | } |
a0d75f26 | 762 | return (0); |
a0d75f26 KS |
763 | } |
764 | ||
a15dacc5 | 765 | int |
ee0f9e0d KM |
766 | sysctl_rtable(name, namelen, where, given, new, newlen) |
767 | int *name; | |
768 | int namelen; | |
a0d75f26 | 769 | caddr_t where; |
8d1b82ff | 770 | size_t *given; |
ee0f9e0d | 771 | caddr_t *new; |
8d1b82ff | 772 | size_t newlen; |
a0d75f26 KS |
773 | { |
774 | register struct radix_node_head *rnh; | |
e684b424 | 775 | int i, s, error = EINVAL; |
ee0f9e0d | 776 | u_char af; |
a0d75f26 KS |
777 | struct walkarg w; |
778 | ||
ee0f9e0d KM |
779 | if (new) |
780 | return (EPERM); | |
781 | if (namelen != 3) | |
782 | return (EINVAL); | |
783 | af = name[0]; | |
a0d75f26 | 784 | Bzero(&w, sizeof(w)); |
ee0f9e0d KM |
785 | w.w_where = where; |
786 | w.w_given = *given; | |
a0d75f26 | 787 | w.w_needed = 0 - w.w_given; |
ee0f9e0d KM |
788 | w.w_op = name[1]; |
789 | w.w_arg = name[2]; | |
a0d75f26 KS |
790 | |
791 | s = splnet(); | |
ee0f9e0d | 792 | switch (w.w_op) { |
e684b424 | 793 | |
ee0f9e0d KM |
794 | case NET_RT_DUMP: |
795 | case NET_RT_FLAGS: | |
e684b424 KS |
796 | for (i = 1; i <= AF_MAX; i++) |
797 | if ((rnh = rt_tables[i]) && (af == 0 || af == i) && | |
d2ca79ee KS |
798 | (error = rnh->rnh_walktree(rnh, |
799 | sysctl_dumpentry, &w))) | |
e684b424 KS |
800 | break; |
801 | break; | |
802 | ||
ee0f9e0d KM |
803 | case NET_RT_IFLIST: |
804 | error = sysctl_iflist(af, &w); | |
a0d75f26 | 805 | } |
e684b424 KS |
806 | splx(s); |
807 | if (w.w_tmem) | |
808 | free(w.w_tmem, M_RTABLE); | |
a0d75f26 | 809 | w.w_needed += w.w_given; |
ee0f9e0d | 810 | if (where) { |
a0d75f26 | 811 | *given = w.w_where - where; |
ee0f9e0d KM |
812 | if (*given < w.w_needed) |
813 | return (ENOMEM); | |
814 | } else { | |
815 | *given = (11 * w.w_needed) / 10; | |
816 | } | |
a0d75f26 KS |
817 | return (error); |
818 | } | |
819 | ||
e831d540 KS |
820 | /* |
821 | * Definitions of protocols supported in the ROUTE domain. | |
822 | */ | |
823 | ||
e831d540 KS |
824 | extern struct domain routedomain; /* or at least forward */ |
825 | ||
826 | struct protosw routesw[] = { | |
827 | { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, | |
828 | raw_input, route_output, raw_ctlinput, 0, | |
829 | route_usrreq, | |
830 | raw_init, 0, 0, 0, | |
ee0f9e0d | 831 | sysctl_rtable, |
e831d540 KS |
832 | } |
833 | }; | |
834 | ||
e831d540 | 835 | struct domain routedomain = |
5c48f39f | 836 | { PF_ROUTE, "route", route_init, 0, 0, |
e831d540 | 837 | routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; |