Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Copyright (c) 1988, 1991 Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
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. | |
20 | * | |
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 | * | |
70c5ff60 | 33 | * from: @(#)rtsock.c 7.18 (Berkeley) 6/27/91 |
fde1aeb2 | 34 | * $Id: rtsock.c,v 1.5 1993/11/25 01:34:12 wollman Exp $ |
15637ed4 RG |
35 | */ |
36 | ||
37 | #include "param.h" | |
dd18dc33 | 38 | #include "systm.h" |
15637ed4 RG |
39 | #include "mbuf.h" |
40 | #include "proc.h" | |
41 | #include "socket.h" | |
42 | #include "socketvar.h" | |
43 | #include "domain.h" | |
44 | #include "protosw.h" | |
45 | ||
15637ed4 RG |
46 | #include "if.h" |
47 | #include "route.h" | |
48 | #include "raw_cb.h" | |
49 | ||
50 | #include "machine/mtpr.h" | |
51 | ||
4c45483e GW |
52 | static void rt_setmetrics(u_long, struct rt_metrics *, struct rt_metrics *); |
53 | ||
8ace4366 | 54 | struct route_cb route_cb; |
15637ed4 RG |
55 | struct sockaddr route_dst = { 2, PF_ROUTE, }; |
56 | struct sockaddr route_src = { 2, PF_ROUTE, }; | |
57 | struct sockproto route_proto = { PF_ROUTE, }; | |
58 | ||
59 | /*ARGSUSED*/ | |
4c45483e | 60 | int |
15637ed4 RG |
61 | route_usrreq(so, req, m, nam, control) |
62 | register struct socket *so; | |
63 | int req; | |
64 | struct mbuf *m, *nam, *control; | |
65 | { | |
66 | register int error = 0; | |
67 | register struct rawcb *rp = sotorawcb(so); | |
68 | int s; | |
69 | if (req == PRU_ATTACH) { | |
70 | MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); | |
71 | if (so->so_pcb = (caddr_t)rp) | |
72 | bzero(so->so_pcb, sizeof(*rp)); | |
73 | ||
74 | } | |
75 | if (req == PRU_DETACH && rp) { | |
76 | int af = rp->rcb_proto.sp_protocol; | |
77 | if (af == AF_INET) | |
78 | route_cb.ip_count--; | |
79 | else if (af == AF_NS) | |
80 | route_cb.ns_count--; | |
81 | else if (af == AF_ISO) | |
82 | route_cb.iso_count--; | |
83 | route_cb.any_count--; | |
84 | } | |
85 | s = splnet(); | |
fde1aeb2 | 86 | error = raw_usrreq(so, req, m, nam, control, 0); |
15637ed4 RG |
87 | rp = sotorawcb(so); |
88 | if (req == PRU_ATTACH && rp) { | |
89 | int af = rp->rcb_proto.sp_protocol; | |
90 | if (error) { | |
91 | free((caddr_t)rp, M_PCB); | |
92 | splx(s); | |
93 | return (error); | |
94 | } | |
95 | if (af == AF_INET) | |
96 | route_cb.ip_count++; | |
97 | else if (af == AF_NS) | |
98 | route_cb.ns_count++; | |
99 | else if (af == AF_ISO) | |
100 | route_cb.iso_count++; | |
101 | rp->rcb_faddr = &route_src; | |
102 | route_cb.any_count++; | |
103 | soisconnected(so); | |
104 | so->so_options |= SO_USELOOPBACK; | |
105 | } | |
106 | splx(s); | |
107 | return (error); | |
108 | } | |
109 | #define ROUNDUP(a) \ | |
110 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) | |
111 | #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) | |
112 | ||
113 | /*ARGSUSED*/ | |
4c45483e | 114 | int |
15637ed4 RG |
115 | route_output(m, so) |
116 | register struct mbuf *m; | |
117 | struct socket *so; | |
118 | { | |
119 | register struct rt_msghdr *rtm = 0; | |
120 | register struct rtentry *rt = 0; | |
121 | struct rtentry *saved_nrt = 0; | |
122 | struct sockaddr *dst = 0, *gate = 0, *netmask = 0, *genmask = 0; | |
123 | struct sockaddr *ifpaddr = 0, *ifaaddr = 0; | |
124 | caddr_t cp, lim; | |
125 | int len, error = 0; | |
126 | struct ifnet *ifp = 0; | |
127 | struct ifaddr *ifa = 0; | |
128 | struct ifaddr *ifaof_ifpforaddr(), *ifa_ifwithroute(); | |
129 | ||
130 | #define senderr(e) { error = e; goto flush;} | |
131 | if (m == 0 || m->m_len < sizeof(long)) | |
132 | return (ENOBUFS); | |
133 | if ((m = m_pullup(m, sizeof(long))) == 0) | |
134 | return (ENOBUFS); | |
135 | if ((m->m_flags & M_PKTHDR) == 0) | |
136 | panic("route_output"); | |
137 | len = m->m_pkthdr.len; | |
138 | if (len < sizeof(*rtm) || | |
139 | len != mtod(m, struct rt_msghdr *)->rtm_msglen) | |
140 | senderr(EINVAL); | |
141 | R_Malloc(rtm, struct rt_msghdr *, len); | |
142 | if (rtm == 0) | |
143 | senderr(ENOBUFS); | |
144 | m_copydata(m, 0, len, (caddr_t)rtm); | |
145 | if (rtm->rtm_version != RTM_VERSION) | |
146 | senderr(EPROTONOSUPPORT); | |
147 | rtm->rtm_pid = curproc->p_pid; | |
148 | lim = len + (caddr_t) rtm; | |
149 | cp = (caddr_t) (rtm + 1); | |
150 | if (rtm->rtm_addrs & RTA_DST) { | |
151 | dst = (struct sockaddr *)cp; | |
152 | ADVANCE(cp, dst); | |
153 | } else | |
154 | senderr(EINVAL); | |
155 | if ((rtm->rtm_addrs & RTA_GATEWAY) && cp < lim) { | |
156 | gate = (struct sockaddr *)cp; | |
157 | ADVANCE(cp, gate); | |
158 | } | |
159 | if ((rtm->rtm_addrs & RTA_NETMASK) && cp < lim) { | |
160 | netmask = (struct sockaddr *)cp; | |
161 | ADVANCE(cp, netmask); | |
162 | } | |
163 | if ((rtm->rtm_addrs & RTA_GENMASK) && cp < lim) { | |
164 | struct radix_node *t, *rn_addmask(); | |
165 | genmask = (struct sockaddr *)cp; | |
166 | ADVANCE(cp, genmask); | |
167 | t = rn_addmask(genmask, 1, 2); | |
168 | if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0) | |
169 | genmask = (struct sockaddr *)(t->rn_key); | |
170 | else | |
171 | senderr(ENOBUFS); | |
172 | } | |
173 | if ((rtm->rtm_addrs & RTA_IFP) && cp < lim) { | |
174 | ifpaddr = (struct sockaddr *)cp; | |
175 | ADVANCE(cp, ifpaddr); | |
176 | } | |
177 | if ((rtm->rtm_addrs & RTA_IFA) && cp < lim) { | |
178 | ifaaddr = (struct sockaddr *)cp; | |
179 | } | |
180 | switch (rtm->rtm_type) { | |
181 | case RTM_ADD: | |
182 | if (gate == 0) | |
183 | senderr(EINVAL); | |
184 | error = rtrequest(RTM_ADD, dst, gate, netmask, | |
185 | rtm->rtm_flags, &saved_nrt); | |
186 | if (error == 0 && saved_nrt) { | |
187 | rt_setmetrics(rtm->rtm_inits, | |
188 | &rtm->rtm_rmx, &saved_nrt->rt_rmx); | |
189 | saved_nrt->rt_refcnt--; | |
190 | saved_nrt->rt_genmask = genmask; | |
191 | } | |
192 | break; | |
193 | ||
194 | case RTM_DELETE: | |
195 | error = rtrequest(RTM_DELETE, dst, gate, netmask, | |
196 | rtm->rtm_flags, (struct rtentry **)0); | |
197 | break; | |
198 | ||
199 | case RTM_GET: | |
200 | case RTM_CHANGE: | |
201 | case RTM_LOCK: | |
202 | rt = rtalloc1(dst, 0); | |
203 | if (rt == 0) | |
204 | senderr(ESRCH); | |
205 | if (rtm->rtm_type != RTM_GET) { | |
206 | if (Bcmp(dst, rt_key(rt), dst->sa_len) != 0) | |
207 | senderr(ESRCH); | |
208 | if (rt->rt_nodes->rn_dupedkey && | |
209 | (netmask == 0 || | |
210 | Bcmp(netmask, rt_mask(rt), netmask->sa_len))) | |
211 | senderr(ETOOMANYREFS); | |
212 | } | |
213 | switch(rtm->rtm_type) { | |
214 | ||
215 | case RTM_GET: | |
216 | dst = rt_key(rt); len = sizeof(*rtm); | |
217 | ADVANCE(len, dst); | |
218 | rtm->rtm_addrs |= RTA_DST; | |
219 | if (gate = rt->rt_gateway) { | |
220 | ADVANCE(len, gate); | |
221 | rtm->rtm_addrs |= RTA_GATEWAY; | |
222 | } else | |
223 | rtm->rtm_addrs &= ~RTA_GATEWAY; | |
224 | if (netmask = rt_mask(rt)) { | |
225 | ADVANCE(len, netmask); | |
226 | rtm->rtm_addrs |= RTA_NETMASK; | |
227 | } else | |
228 | rtm->rtm_addrs &= ~RTA_NETMASK; | |
229 | if (genmask = rt->rt_genmask) { | |
230 | ADVANCE(len, genmask); | |
231 | rtm->rtm_addrs |= RTA_GENMASK; | |
232 | } else | |
233 | rtm->rtm_addrs &= ~RTA_GENMASK; | |
234 | if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { | |
235 | if (rt->rt_ifp == 0) | |
236 | goto badif; | |
237 | for (ifa = rt->rt_ifp->if_addrlist; | |
238 | ifa && ifa->ifa_addr->sa_family != AF_LINK; | |
239 | ifa = ifa->ifa_next){} | |
240 | if (ifa && rt->rt_ifa) { | |
241 | ifpaddr = ifa->ifa_addr; | |
242 | ADVANCE(len, ifpaddr); | |
243 | ifaaddr = rt->rt_ifa->ifa_addr; | |
244 | ADVANCE(len, ifaaddr); | |
245 | rtm->rtm_addrs |= RTA_IFP | RTA_IFA; | |
246 | } else { | |
247 | badif: ifpaddr = 0; | |
248 | rtm->rtm_addrs &= ~(RTA_IFP | RTA_IFA); | |
249 | } | |
250 | } | |
251 | if (len > rtm->rtm_msglen) { | |
252 | struct rt_msghdr *new_rtm; | |
253 | R_Malloc(new_rtm, struct rt_msghdr *, len); | |
254 | if (new_rtm == 0) | |
255 | senderr(ENOBUFS); | |
256 | Bcopy(rtm, new_rtm, rtm->rtm_msglen); | |
257 | Free(rtm); rtm = new_rtm; | |
258 | } | |
259 | rtm->rtm_msglen = len; | |
260 | rtm->rtm_flags = rt->rt_flags; | |
261 | rtm->rtm_rmx = rt->rt_rmx; | |
262 | cp = (caddr_t) (1 + rtm); | |
263 | len = ROUNDUP(dst->sa_len); | |
264 | Bcopy(dst, cp, len); cp += len; | |
265 | if (gate) { | |
266 | len = ROUNDUP(gate->sa_len); | |
267 | Bcopy(gate, cp, len); cp += len; | |
268 | } | |
269 | if (netmask) { | |
270 | len = ROUNDUP(netmask->sa_len); | |
271 | Bcopy(netmask, cp, len); cp += len; | |
272 | } | |
273 | if (genmask) { | |
274 | len = ROUNDUP(genmask->sa_len); | |
275 | Bcopy(genmask, cp, len); cp += len; | |
276 | } | |
277 | if (ifpaddr) { | |
278 | len = ROUNDUP(ifpaddr->sa_len); | |
279 | Bcopy(ifpaddr, cp, len); cp += len; | |
280 | len = ROUNDUP(ifaaddr->sa_len); | |
281 | Bcopy(ifaaddr, cp, len); cp += len; | |
282 | } | |
283 | break; | |
284 | ||
285 | case RTM_CHANGE: | |
286 | if (gate && | |
287 | (gate->sa_len > (len = rt->rt_gateway->sa_len))) | |
288 | senderr(EDQUOT); | |
289 | /* new gateway could require new ifaddr, ifp; | |
290 | flags may also be different; ifp may be specified | |
291 | by ll sockaddr when protocol address is ambiguous */ | |
292 | if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) && | |
293 | (ifp = ifa->ifa_ifp)) | |
294 | ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, | |
295 | ifp); | |
296 | else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) || | |
297 | (ifa = ifa_ifwithroute(rt->rt_flags, | |
298 | rt_key(rt), gate))) | |
299 | ifp = ifa->ifa_ifp; | |
300 | if (ifa) { | |
301 | register struct ifaddr *oifa = rt->rt_ifa; | |
302 | if (oifa != ifa) { | |
303 | if (oifa && oifa->ifa_rtrequest) | |
304 | oifa->ifa_rtrequest(RTM_DELETE, | |
305 | rt, gate); | |
306 | rt->rt_ifa = ifa; | |
307 | rt->rt_ifp = ifp; | |
308 | } | |
309 | } | |
310 | if (gate) | |
311 | Bcopy(gate, rt->rt_gateway, len); | |
312 | rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, | |
313 | &rt->rt_rmx); | |
314 | if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) | |
315 | rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate); | |
316 | if (genmask) | |
317 | rt->rt_genmask = genmask; | |
318 | /* | |
319 | * Fall into | |
320 | */ | |
321 | case RTM_LOCK: | |
322 | rt->rt_rmx.rmx_locks |= | |
323 | (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); | |
324 | rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); | |
325 | break; | |
326 | } | |
327 | goto cleanup; | |
328 | ||
329 | default: | |
330 | senderr(EOPNOTSUPP); | |
331 | } | |
332 | ||
333 | flush: | |
334 | if (rtm) { | |
335 | if (error) | |
336 | rtm->rtm_errno = error; | |
337 | else | |
338 | rtm->rtm_flags |= RTF_DONE; | |
339 | } | |
340 | cleanup: | |
341 | if (rt) | |
342 | rtfree(rt); | |
343 | { | |
344 | register struct rawcb *rp = 0; | |
345 | /* | |
346 | * Check to see if we don't want our own messages. | |
347 | */ | |
348 | if ((so->so_options & SO_USELOOPBACK) == 0) { | |
349 | if (route_cb.any_count <= 1) { | |
350 | if (rtm) | |
351 | Free(rtm); | |
352 | m_freem(m); | |
353 | return (error); | |
354 | } | |
355 | /* There is another listener, so construct message */ | |
356 | rp = sotorawcb(so); | |
357 | } | |
358 | if (rtm) { | |
359 | m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); | |
360 | Free(rtm); | |
361 | } | |
362 | if (rp) | |
363 | rp->rcb_proto.sp_family = 0; /* Avoid us */ | |
364 | if (dst) | |
365 | route_proto.sp_protocol = dst->sa_family; | |
366 | raw_input(m, &route_proto, &route_src, &route_dst); | |
367 | if (rp) | |
368 | rp->rcb_proto.sp_family = PF_ROUTE; | |
369 | } | |
370 | return (error); | |
371 | } | |
372 | ||
4c45483e | 373 | void |
15637ed4 RG |
374 | rt_setmetrics(which, in, out) |
375 | u_long which; | |
376 | register struct rt_metrics *in, *out; | |
377 | { | |
378 | #define metric(f, e) if (which & (f)) out->e = in->e; | |
379 | metric(RTV_RPIPE, rmx_recvpipe); | |
380 | metric(RTV_SPIPE, rmx_sendpipe); | |
381 | metric(RTV_SSTHRESH, rmx_ssthresh); | |
382 | metric(RTV_RTT, rmx_rtt); | |
383 | metric(RTV_RTTVAR, rmx_rttvar); | |
384 | metric(RTV_HOPCOUNT, rmx_hopcount); | |
385 | metric(RTV_MTU, rmx_mtu); | |
386 | metric(RTV_EXPIRE, rmx_expire); | |
387 | #undef metric | |
388 | } | |
389 | ||
15637ed4 RG |
390 | /* |
391 | * The miss message and losing message are very similar. | |
392 | */ | |
393 | ||
4c45483e | 394 | void |
15637ed4 | 395 | rt_missmsg(type, dst, gate, mask, src, flags, error) |
4c45483e GW |
396 | int type; |
397 | register struct sockaddr *dst; | |
398 | struct sockaddr *gate; | |
399 | struct sockaddr *mask; | |
400 | struct sockaddr *src; | |
401 | int flags; | |
402 | int error; | |
15637ed4 RG |
403 | { |
404 | register struct rt_msghdr *rtm; | |
405 | register struct mbuf *m; | |
406 | int dlen = ROUNDUP(dst->sa_len); | |
407 | int len = dlen + sizeof(*rtm); | |
408 | ||
409 | if (route_cb.any_count == 0) | |
410 | return; | |
411 | m = m_gethdr(M_DONTWAIT, MT_DATA); | |
412 | if (m == 0) | |
413 | return; | |
414 | m->m_pkthdr.len = m->m_len = min(len, MHLEN); | |
415 | m->m_pkthdr.rcvif = 0; | |
416 | rtm = mtod(m, struct rt_msghdr *); | |
417 | bzero((caddr_t)rtm, sizeof(*rtm)); /*XXX assumes sizeof(*rtm) < MHLEN*/ | |
418 | rtm->rtm_flags = RTF_DONE | flags; | |
419 | rtm->rtm_msglen = len; | |
420 | rtm->rtm_version = RTM_VERSION; | |
421 | rtm->rtm_type = type; | |
422 | rtm->rtm_addrs = RTA_DST; | |
423 | if (type == RTM_OLDADD || type == RTM_OLDDEL) { | |
424 | rtm->rtm_pid = curproc->p_pid; | |
425 | } | |
426 | m_copyback(m, sizeof (*rtm), dlen, (caddr_t)dst); | |
427 | if (gate) { | |
428 | dlen = ROUNDUP(gate->sa_len); | |
429 | m_copyback(m, len , dlen, (caddr_t)gate); | |
430 | len += dlen; | |
431 | rtm->rtm_addrs |= RTA_GATEWAY; | |
432 | } | |
433 | if (mask) { | |
434 | dlen = ROUNDUP(mask->sa_len); | |
435 | m_copyback(m, len , dlen, (caddr_t)mask); | |
436 | len += dlen; | |
437 | rtm->rtm_addrs |= RTA_NETMASK; | |
438 | } | |
439 | if (src) { | |
440 | dlen = ROUNDUP(src->sa_len); | |
441 | m_copyback(m, len , dlen, (caddr_t)src); | |
442 | len += dlen; | |
443 | rtm->rtm_addrs |= RTA_AUTHOR; | |
444 | } | |
445 | if (m->m_pkthdr.len != len) { | |
446 | m_freem(m); | |
447 | return; | |
448 | } | |
449 | rtm->rtm_errno = error; | |
450 | rtm->rtm_msglen = len; | |
451 | route_proto.sp_protocol = dst->sa_family; | |
452 | raw_input(m, &route_proto, &route_src, &route_dst); | |
453 | } | |
454 | ||
455 | #include "kinfo.h" | |
456 | struct walkarg { | |
457 | int w_op, w_arg; | |
458 | int w_given, w_needed; | |
459 | caddr_t w_where; | |
460 | struct { | |
461 | struct rt_msghdr m_rtm; | |
462 | char m_sabuf[128]; | |
463 | } w_m; | |
464 | #define w_rtm w_m.m_rtm | |
465 | }; | |
466 | /* | |
467 | * This is used in dumping the kernel table via getkinfo(). | |
468 | */ | |
4c45483e | 469 | int |
15637ed4 RG |
470 | rt_dumpentry(rn, w) |
471 | struct radix_node *rn; | |
472 | register struct walkarg *w; | |
473 | { | |
474 | register struct sockaddr *sa; | |
475 | int n, error; | |
476 | ||
477 | for (; rn; rn = rn->rn_dupedkey) { | |
478 | int count = 0, size = sizeof(w->w_rtm); | |
479 | register struct rtentry *rt = (struct rtentry *)rn; | |
480 | ||
481 | if (rn->rn_flags & RNF_ROOT) | |
482 | continue; | |
483 | if (w->w_op == KINFO_RT_FLAGS && !(rt->rt_flags & w->w_arg)) | |
484 | continue; | |
485 | #define next(a, l) {size += (l); w->w_rtm.rtm_addrs |= (a); } | |
486 | w->w_rtm.rtm_addrs = 0; | |
487 | if (sa = rt_key(rt)) | |
488 | next(RTA_DST, ROUNDUP(sa->sa_len)); | |
489 | if (sa = rt->rt_gateway) | |
490 | next(RTA_GATEWAY, ROUNDUP(sa->sa_len)); | |
491 | if (sa = rt_mask(rt)) | |
492 | next(RTA_NETMASK, ROUNDUP(sa->sa_len)); | |
493 | if (sa = rt->rt_genmask) | |
494 | next(RTA_GENMASK, ROUNDUP(sa->sa_len)); | |
495 | w->w_needed += size; | |
496 | if (w->w_where == NULL || w->w_needed > 0) | |
497 | continue; | |
498 | w->w_rtm.rtm_msglen = size; | |
499 | w->w_rtm.rtm_flags = rt->rt_flags; | |
500 | w->w_rtm.rtm_use = rt->rt_use; | |
501 | w->w_rtm.rtm_rmx = rt->rt_rmx; | |
502 | w->w_rtm.rtm_index = rt->rt_ifp->if_index; | |
503 | #undef next | |
504 | #define next(l) {n = (l); Bcopy(sa, cp, n); cp += n;} | |
505 | if (size <= sizeof(w->w_m)) { | |
506 | register caddr_t cp = (caddr_t)(w->w_m.m_sabuf); | |
507 | if (sa = rt_key(rt)) | |
508 | next(ROUNDUP(sa->sa_len)); | |
509 | if (sa = rt->rt_gateway) | |
510 | next(ROUNDUP(sa->sa_len)); | |
511 | if (sa = rt_mask(rt)) | |
512 | next(ROUNDUP(sa->sa_len)); | |
513 | if (sa = rt->rt_genmask) | |
514 | next(ROUNDUP(sa->sa_len)); | |
515 | #undef next | |
516 | #define next(s, l) {n = (l); \ | |
517 | if (error = copyout((caddr_t)(s), w->w_where, n)) return (error); \ | |
518 | w->w_where += n;} | |
519 | ||
520 | next(&w->w_m, size); /* Copy rtmsg and sockaddrs back */ | |
521 | continue; | |
522 | } | |
523 | next(&w->w_rtm, sizeof(w->w_rtm)); | |
524 | if (sa = rt_key(rt)) | |
525 | next(sa, ROUNDUP(sa->sa_len)); | |
526 | if (sa = rt->rt_gateway) | |
527 | next(sa, ROUNDUP(sa->sa_len)); | |
528 | if (sa = rt_mask(rt)) | |
529 | next(sa, ROUNDUP(sa->sa_len)); | |
530 | if (sa = rt->rt_genmask) | |
531 | next(sa, ROUNDUP(sa->sa_len)); | |
532 | } | |
533 | return (0); | |
534 | #undef next | |
535 | } | |
536 | ||
4c45483e | 537 | int |
15637ed4 RG |
538 | kinfo_rtable(op, where, given, arg, needed) |
539 | int op, arg; | |
540 | caddr_t where; | |
541 | int *given, *needed; | |
542 | { | |
543 | register struct radix_node_head *rnh; | |
544 | int s, error = 0; | |
545 | u_char af = ki_af(op); | |
546 | struct walkarg w; | |
547 | ||
548 | op &= 0xffff; | |
549 | if (op != KINFO_RT_DUMP && op != KINFO_RT_FLAGS) | |
550 | return (EINVAL); | |
551 | ||
552 | Bzero(&w, sizeof(w)); | |
553 | if ((w.w_where = where) && given) | |
554 | w.w_given = *given; | |
555 | w.w_needed = 0 - w.w_given; | |
556 | w.w_arg = arg; | |
557 | w.w_op = op; | |
558 | w.w_rtm.rtm_version = RTM_VERSION; | |
559 | w.w_rtm.rtm_type = RTM_GET; | |
560 | ||
561 | s = splnet(); | |
562 | for (rnh = radix_node_head; rnh; rnh = rnh->rnh_next) { | |
563 | if (rnh->rnh_af == 0) | |
564 | continue; | |
565 | if (af && af != rnh->rnh_af) | |
566 | continue; | |
567 | error = rt_walk(rnh->rnh_treetop, rt_dumpentry, &w); | |
568 | if (error) | |
569 | break; | |
570 | } | |
571 | w.w_needed += w.w_given; | |
572 | if (where && given) | |
573 | *given = w.w_where - where; | |
574 | else | |
575 | w.w_needed = (11 * w.w_needed) / 10; | |
576 | *needed = w.w_needed; | |
577 | splx(s); | |
578 | return (error); | |
579 | } | |
580 | ||
4c45483e | 581 | int |
15637ed4 RG |
582 | rt_walk(rn, f, w) |
583 | register struct radix_node *rn; | |
584 | register int (*f)(); | |
585 | struct walkarg *w; | |
586 | { | |
587 | int error; | |
588 | for (;;) { | |
589 | while (rn->rn_b >= 0) | |
590 | rn = rn->rn_l; /* First time through node, go left */ | |
591 | if (error = (*f)(rn, w)) | |
592 | return (error); /* Process Leaf */ | |
593 | while (rn->rn_p->rn_r == rn) { /* if coming back from right */ | |
594 | rn = rn->rn_p; /* go back up */ | |
595 | if (rn->rn_flags & RNF_ROOT) | |
596 | return 0; | |
597 | } | |
598 | rn = rn->rn_p->rn_r; /* otherwise, go right*/ | |
599 | } | |
600 | } | |
601 | ||
602 | /* | |
603 | * Definitions of protocols supported in the ROUTE domain. | |
604 | */ | |
605 | ||
15637ed4 RG |
606 | extern struct domain routedomain; /* or at least forward */ |
607 | ||
608 | struct protosw routesw[] = { | |
609 | { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, | |
610 | raw_input, route_output, raw_ctlinput, 0, | |
611 | route_usrreq, | |
612 | raw_init, 0, 0, 0, | |
613 | } | |
614 | }; | |
615 | ||
616 | int unp_externalize(), unp_dispose(); | |
617 | ||
618 | struct domain routedomain = | |
619 | { PF_ROUTE, "route", 0, 0, 0, | |
620 | routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; |