Commit | Line | Data |
---|---|---|
e831d540 KS |
1 | /* |
2 | * Copyright (c) 1988 Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
6 | * provided that the above copyright notice and this paragraph are | |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
16 | * | |
79e0ea5d | 17 | * @(#)rtsock.c 7.8 (Berkeley) %G% |
e831d540 KS |
18 | */ |
19 | ||
e831d540 KS |
20 | #include "param.h" |
21 | #include "mbuf.h" | |
e831d540 KS |
22 | #include "user.h" |
23 | #include "proc.h" | |
24 | #include "socket.h" | |
25 | #include "socketvar.h" | |
26 | #include "domain.h" | |
27 | #include "protosw.h" | |
28 | #include "errno.h" | |
29 | ||
30 | #include "af.h" | |
a0d75f26 | 31 | #include "if.h" |
e831d540 KS |
32 | #include "route.h" |
33 | #include "raw_cb.h" | |
34 | ||
d301d150 | 35 | #include "machine/mtpr.h" |
e831d540 | 36 | |
b72a6efb KS |
37 | struct sockaddr route_dst = { 0, PF_ROUTE, }; |
38 | struct sockaddr route_src = { 0, PF_ROUTE, }; | |
39 | struct sockproto route_proto = { PF_ROUTE, }; | |
40 | ||
e831d540 | 41 | /*ARGSUSED*/ |
a0d75f26 | 42 | route_usrreq(so, req, m, nam, control) |
e831d540 KS |
43 | register struct socket *so; |
44 | int req; | |
a0d75f26 | 45 | struct mbuf *m, *nam, *control; |
e831d540 KS |
46 | { |
47 | register int error = 0; | |
48 | register struct rawcb *rp = sotorawcb(so); | |
b72a6efb KS |
49 | if (req == PRU_ATTACH) { |
50 | MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); | |
51 | if (so->so_pcb = (caddr_t)rp) | |
52 | bzero(so->so_pcb, sizeof(*rp)); | |
53 | ||
54 | } | |
e831d540 KS |
55 | if (req == PRU_DETACH && rp) { |
56 | int af = rp->rcb_proto.sp_protocol; | |
57 | if (af == AF_INET) | |
58 | route_cb.ip_count--; | |
59 | else if (af == AF_NS) | |
60 | route_cb.ns_count--; | |
e831d540 KS |
61 | else if (af == AF_ISO) |
62 | route_cb.iso_count--; | |
e831d540 KS |
63 | route_cb.any_count--; |
64 | } | |
a0d75f26 | 65 | error = raw_usrreq(so, req, m, nam, control); |
e831d540 | 66 | rp = sotorawcb(so); |
b72a6efb | 67 | if (req == PRU_ATTACH && rp) { |
e831d540 | 68 | int af = rp->rcb_proto.sp_protocol; |
b72a6efb KS |
69 | if (error) { |
70 | free((caddr_t)rp, M_PCB); | |
71 | return (error); | |
72 | } | |
e831d540 KS |
73 | if (af == AF_INET) |
74 | route_cb.ip_count++; | |
75 | else if (af == AF_NS) | |
76 | route_cb.ns_count++; | |
e831d540 KS |
77 | else if (af == AF_ISO) |
78 | route_cb.iso_count++; | |
b72a6efb | 79 | rp->rcb_faddr = &route_src; |
e831d540 KS |
80 | route_cb.any_count++; |
81 | soisconnected(so); | |
82 | } | |
83 | return (error); | |
84 | } | |
85 | #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) | |
86 | ||
b72a6efb | 87 | /*ARGSUSED*/ |
e831d540 KS |
88 | route_output(m, so) |
89 | register struct mbuf *m; | |
90 | struct socket *so; | |
91 | { | |
92 | register struct rt_msghdr *rtm = 0; | |
93 | register struct rtentry *rt = 0; | |
a0d75f26 | 94 | struct rtentry *saved_nrt = 0; |
79e0ea5d KS |
95 | struct sockaddr *dst = 0, *gate = 0, *netmask = 0, *genmask = 0; |
96 | caddr_t cp, lim; | |
b72a6efb | 97 | int len, error = 0; |
e831d540 | 98 | |
a0d75f26 | 99 | #define senderr(e) { error = e; goto flush;} |
79e0ea5d KS |
100 | if (m == 0 || m->m_len < sizeof(long)) |
101 | return (ENOBUFS); | |
102 | if ((m = m_pullup(m, sizeof(long))) == 0) | |
32dfe9ab | 103 | return (ENOBUFS); |
e831d540 | 104 | if ((m->m_flags & M_PKTHDR) == 0) |
32dfe9ab | 105 | panic("route_output"); |
e831d540 KS |
106 | len = m->m_pkthdr.len; |
107 | rtm = mtod(m, struct rt_msghdr *); | |
108 | if (len < rtm->rtm_msglen) | |
a0d75f26 | 109 | senderr(EINVAL); |
e831d540 KS |
110 | R_Malloc(rtm, struct rt_msghdr *, len); |
111 | if (rtm == 0) | |
a0d75f26 | 112 | senderr(ENOBUFS); |
e831d540 | 113 | m_copydata(m, 0, len, (caddr_t)rtm); |
79e0ea5d | 114 | if (rtm->rtm_version != RTM_VERSION) |
a0d75f26 | 115 | senderr(EPROTONOSUPPORT); |
e831d540 | 116 | rtm->rtm_pid = u.u_procp->p_pid; |
79e0ea5d | 117 | lim = len + (caddr_t) rtm; |
e831d540 | 118 | cp = (caddr_t) (rtm + 1); |
79e0ea5d | 119 | if (rtm->rtm_addrs & RTA_DST) { |
e831d540 KS |
120 | dst = (struct sockaddr *)cp; |
121 | cp += ROUNDUP(dst->sa_len); | |
79e0ea5d KS |
122 | } else |
123 | senderr(EINVAL); | |
124 | if ((rtm->rtm_addrs & RTA_GATEWAY) && cp < lim) { | |
e831d540 KS |
125 | gate = (struct sockaddr *)cp; |
126 | cp += ROUNDUP(gate->sa_len); | |
127 | } | |
79e0ea5d | 128 | if ((rtm->rtm_addrs & RTA_NETMASK) && cp < lim) { |
e831d540 | 129 | netmask = (struct sockaddr *)cp; |
b72a6efb KS |
130 | if (*cp) |
131 | cp += ROUNDUP(netmask->sa_len); | |
132 | else | |
133 | cp += sizeof(long); | |
134 | ||
e831d540 | 135 | } |
79e0ea5d KS |
136 | if ((rtm->rtm_addrs & RTA_GENMASK) && cp < lim) { |
137 | genmask = (struct sockaddr *)cp; | |
e831d540 KS |
138 | } |
139 | switch (rtm->rtm_type) { | |
140 | case RTM_ADD: | |
79e0ea5d KS |
141 | if (gate == 0) |
142 | senderr(EINVAL); | |
e831d540 KS |
143 | error = rtrequest(RTM_ADD, dst, gate, netmask, |
144 | rtm->rtm_flags, &saved_nrt); | |
79e0ea5d KS |
145 | if (error == 0 && saved_nrt) { |
146 | rt_setmetrics(rtm->rtm_inits, | |
147 | &rtm->rtm_rmx, &saved_nrt->rt_rmx); | |
a0d75f26 | 148 | saved_nrt->rt_refcnt--; |
79e0ea5d | 149 | } |
e831d540 KS |
150 | break; |
151 | ||
152 | case RTM_DELETE: | |
153 | error = rtrequest(RTM_DELETE, dst, gate, netmask, | |
b72a6efb | 154 | rtm->rtm_flags, (struct rtentry **)0); |
e831d540 KS |
155 | break; |
156 | ||
157 | case RTM_GET: | |
158 | case RTM_CHANGE: | |
159 | case RTM_LOCK: | |
160 | rt = rtalloc1(dst, 0); | |
161 | if (rt == 0) | |
a0d75f26 | 162 | senderr(ESRCH); |
e831d540 KS |
163 | switch(rtm->rtm_type) { |
164 | struct sockaddr *outmask; | |
165 | ||
166 | case RTM_GET: | |
167 | netmask = rt_mask(rt); | |
79e0ea5d KS |
168 | len = sizeof(*rtm) + ROUNDUP(rt_key(rt)->sa_len); |
169 | rtm->rtm_addrs = RTA_DST; | |
170 | if (rt->rt_gateway) { | |
171 | len += ROUNDUP(rt->rt_gateway->sa_len); | |
172 | rtm->rtm_addrs |= RTA_GATEWAY; | |
173 | } | |
174 | if (netmask) { | |
b72a6efb | 175 | len += netmask->sa_len; |
79e0ea5d KS |
176 | rtm->rtm_addrs |= RTA_NETMASK; |
177 | } | |
e831d540 KS |
178 | if (len > rtm->rtm_msglen) { |
179 | struct rt_msghdr *new_rtm; | |
180 | R_Malloc(new_rtm, struct rt_msghdr *, len); | |
181 | if (new_rtm == 0) | |
a0d75f26 | 182 | senderr(ENOBUFS); |
e831d540 KS |
183 | Bcopy(rtm, new_rtm, rtm->rtm_msglen); |
184 | Free(rtm); rtm = new_rtm; | |
185 | gate = (struct sockaddr *) | |
186 | (ROUNDUP(rt->rt_gateway->sa_len) | |
187 | + (char *)dst); | |
188 | Bcopy(&rt->rt_gateway, gate, | |
189 | rt->rt_gateway->sa_len); | |
190 | rtm->rtm_flags = rt->rt_flags; | |
e831d540 KS |
191 | if (netmask) { |
192 | outmask = (struct sockaddr *) | |
193 | (ROUNDUP(netmask->sa_len)+(char *)gate); | |
194 | Bcopy(netmask, outmask, netmask->sa_len); | |
e831d540 KS |
195 | } |
196 | } | |
197 | break; | |
198 | ||
199 | case RTM_CHANGE: | |
79e0ea5d KS |
200 | if (gate == 0) |
201 | senderr(EINVAL); | |
e831d540 | 202 | if (gate->sa_len > (len = rt->rt_gateway->sa_len)) |
a0d75f26 KS |
203 | senderr(EDQUOT); |
204 | if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) | |
205 | rt->rt_ifa->ifa_rtrequest(RTM_CHANGE, rt, gate); | |
e831d540 KS |
206 | Bcopy(gate, rt->rt_gateway, len); |
207 | rt->rt_gateway->sa_len = len; | |
208 | ||
79e0ea5d KS |
209 | rt_setmetrics(rtm->rtm_inits, |
210 | &rtm->rtm_rmx, &rt->rt_rmx); | |
e831d540 KS |
211 | /* |
212 | * Fall into | |
213 | */ | |
79e0ea5d KS |
214 | case RTM_LOCK: |
215 | rt->rt_rmx.rmx_locks |= | |
216 | (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); | |
217 | rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); | |
e831d540 | 218 | break; |
e831d540 KS |
219 | } |
220 | goto cleanup; | |
221 | ||
222 | default: | |
a0d75f26 | 223 | senderr(EOPNOTSUPP); |
e831d540 KS |
224 | } |
225 | ||
226 | flush: | |
227 | if (rtm) { | |
228 | if (error) | |
229 | rtm->rtm_errno = error; | |
230 | else | |
231 | rtm->rtm_flags |= RTF_DONE; | |
232 | } | |
233 | cleanup: | |
234 | if (rt) | |
235 | rtfree(rt); | |
32dfe9ab KS |
236 | if (cp = (caddr_t)rtm) { |
237 | m_copyback(m, 0, len, cp); | |
238 | Free(rtm); | |
239 | } | |
e831d540 | 240 | route_proto.sp_protocol = dst->sa_family; |
32dfe9ab | 241 | raw_input(m, &route_proto, &route_src, &route_dst); |
e831d540 KS |
242 | return (error); |
243 | } | |
244 | ||
79e0ea5d KS |
245 | static rt_setmetrics(which, in, out) |
246 | u_long which; | |
247 | register struct rt_metrics *in, *out; | |
248 | { | |
249 | #define metric(f, e) if (which & (f)) out->e = in->e; | |
250 | metric(RTV_RPIPE, rmx_recvpipe); | |
251 | metric(RTV_SPIPE, rmx_sendpipe); | |
252 | metric(RTV_SSTHRESH, rmx_ssthresh); | |
253 | metric(RTV_RTT, rmx_rtt); | |
254 | metric(RTV_RTTVAR, rmx_rttvar); | |
255 | metric(RTV_HOPCOUNT, rmx_hopcount); | |
256 | metric(RTV_MTU, rmx_mtu); | |
257 | #undef metric | |
258 | } | |
259 | ||
e831d540 KS |
260 | /* |
261 | * Copy data from a buffer back into the indicated mbuf chain, | |
262 | * starting "off" bytes from the beginning, extending the mbuf | |
263 | * chain if necessary. | |
264 | */ | |
265 | m_copyback(m0, off, len, cp) | |
266 | struct mbuf *m0; | |
267 | register int off; | |
268 | register int len; | |
269 | caddr_t cp; | |
270 | ||
271 | { | |
272 | register int mlen; | |
273 | register struct mbuf *m = m0, *n; | |
274 | int totlen = 0; | |
275 | ||
276 | if (m0 == 0) | |
277 | return; | |
278 | while (off >= (mlen = m->m_len)) { | |
279 | off -= mlen; | |
280 | totlen += mlen; | |
281 | if (m->m_next == 0) { | |
282 | n = m_getclr(M_DONTWAIT, m->m_type); | |
283 | if (n == 0) | |
284 | goto out; | |
285 | n->m_len = min(MLEN, len + off); | |
286 | m->m_next = n; | |
287 | } | |
288 | m = m->m_next; | |
289 | } | |
290 | while (len > 0) { | |
291 | mlen = min (m->m_len - off, len); | |
b72a6efb | 292 | bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); |
e831d540 KS |
293 | cp += mlen; |
294 | len -= mlen; | |
295 | mlen += off; | |
296 | off = 0; | |
297 | totlen += mlen; | |
298 | if (len == 0) | |
299 | break; | |
300 | if (m->m_next == 0) { | |
301 | n = m_get(M_DONTWAIT, m->m_type); | |
302 | if (n == 0) | |
303 | break; | |
304 | n->m_len = min(MLEN, len); | |
305 | m->m_next = n; | |
306 | } | |
307 | m = m->m_next; | |
308 | } | |
309 | out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) | |
310 | m->m_pkthdr.len = totlen; | |
311 | } | |
312 | ||
313 | /* | |
314 | * The miss message and losing message are very similar. | |
315 | */ | |
316 | ||
b72a6efb | 317 | rt_missmsg(type, dst, gate, mask, src, flags, error) |
e831d540 KS |
318 | register struct sockaddr *dst; |
319 | struct sockaddr *gate, *mask, *src; | |
320 | { | |
321 | register struct rt_msghdr *rtm; | |
322 | register struct mbuf *m; | |
323 | int dlen = ROUNDUP(dst->sa_len); | |
324 | int len = dlen + sizeof(*rtm); | |
e831d540 KS |
325 | |
326 | if (route_cb.any_count == 0) | |
327 | return; | |
328 | m = m_gethdr(M_DONTWAIT, MT_DATA); | |
329 | if (m == 0) | |
330 | return; | |
331 | m->m_pkthdr.len = m->m_len = min(len, MHLEN); | |
332 | m->m_pkthdr.rcvif = 0; | |
333 | rtm = mtod(m, struct rt_msghdr *); | |
334 | bzero((caddr_t)rtm, sizeof(*rtm)); /*XXX assumes sizeof(*rtm) < MHLEN*/ | |
335 | rtm->rtm_flags = RTF_DONE | flags; | |
336 | rtm->rtm_msglen = len; | |
79e0ea5d | 337 | rtm->rtm_version = RTM_VERSION; |
e831d540 | 338 | rtm->rtm_type = type; |
79e0ea5d | 339 | rtm->rtm_addrs = RTA_DST; |
e831d540 | 340 | if (type == RTM_OLDADD || type == RTM_OLDDEL) { |
e831d540 | 341 | rtm->rtm_pid = u.u_procp->p_pid; |
e831d540 KS |
342 | } |
343 | m_copyback(m, sizeof (*rtm), dlen, (caddr_t)dst); | |
344 | if (gate) { | |
345 | dlen = ROUNDUP(gate->sa_len); | |
346 | m_copyback(m, len , dlen, (caddr_t)gate); | |
347 | len += dlen; | |
79e0ea5d | 348 | rtm->rtm_addrs |= RTA_GATEWAY; |
e831d540 KS |
349 | } |
350 | if (mask) { | |
b72a6efb KS |
351 | if (mask->sa_len) |
352 | dlen = ROUNDUP(mask->sa_len); | |
353 | else | |
354 | dlen = sizeof(long); | |
e831d540 KS |
355 | m_copyback(m, len , dlen, (caddr_t)mask); |
356 | len += dlen; | |
79e0ea5d | 357 | rtm->rtm_addrs |= RTA_NETMASK; |
e831d540 KS |
358 | } |
359 | if (src) { | |
360 | dlen = ROUNDUP(src->sa_len); | |
361 | m_copyback(m, len , dlen, (caddr_t)src); | |
362 | len += dlen; | |
79e0ea5d | 363 | rtm->rtm_addrs |= RTA_AUTHOR; |
e831d540 KS |
364 | } |
365 | if (m->m_pkthdr.len != len) { | |
366 | m_freem(m); | |
367 | return; | |
368 | } | |
b72a6efb | 369 | rtm->rtm_errno = error; |
e831d540 KS |
370 | rtm->rtm_msglen = len; |
371 | route_proto.sp_protocol = dst->sa_family; | |
372 | raw_input(m, &route_proto, &route_src, &route_dst); | |
373 | } | |
374 | ||
a0d75f26 | 375 | #include "kinfo.h" |
a0d75f26 KS |
376 | struct walkarg { |
377 | int w_op, w_arg; | |
378 | int w_given, w_needed; | |
379 | caddr_t w_where; | |
380 | struct { | |
381 | struct rt_msghdr m_rtm; | |
382 | char m_sabuf[128]; | |
383 | } w_m; | |
384 | #define w_rtm w_m.m_rtm | |
385 | }; | |
386 | /* | |
387 | * This is used in dumping the kernel table via getkinfo(). | |
388 | */ | |
389 | rt_dumpentry(rn, w) | |
390 | struct radix_node *rn; | |
391 | register struct walkarg *w; | |
392 | { | |
393 | register struct sockaddr *sa; | |
394 | int n, error; | |
395 | ||
396 | for (; rn && !(rn->rn_flags & RNF_ROOT); rn = rn->rn_dupedkey) { | |
397 | int count = 0, size = sizeof(w->w_rtm); | |
398 | register struct rtentry *rt = (struct rtentry *)rn; | |
399 | ||
400 | if (w->w_op == KINFO_RT_FLAGS && !(rt->rt_flags & w->w_arg)) | |
401 | continue; | |
79e0ea5d KS |
402 | #define next(a, l) {size += (l); w->w_rtm.rtm_addrs |= (a); } |
403 | w->w_rtm.rtm_addrs = 0; | |
a0d75f26 | 404 | if (sa = rt_key(rt)) |
79e0ea5d | 405 | next(RTA_DST, ROUNDUP(sa->sa_len)); |
a0d75f26 | 406 | if (sa = rt->rt_gateway) |
79e0ea5d KS |
407 | next(RTA_GATEWAY, ROUNDUP(sa->sa_len)); |
408 | if (sa = rt_mask(rt)) | |
409 | next(RTA_NETMASK, | |
410 | sa->sa_len ? ROUNDUP(sa->sa_len) : sizeof(long)); | |
a0d75f26 | 411 | if (sa = rt->rt_genmask) |
79e0ea5d | 412 | next(RTA_GENMASK, ROUNDUP(sa->sa_len)); |
a0d75f26 KS |
413 | w->w_needed += size; |
414 | if (w->w_where == NULL || w->w_needed > 0) | |
415 | continue; | |
416 | w->w_rtm.rtm_msglen = size; | |
a0d75f26 | 417 | w->w_rtm.rtm_flags = rt->rt_flags; |
79e0ea5d KS |
418 | w->w_rtm.rtm_use = rt->rt_use; |
419 | w->w_rtm.rtm_rmx = rt->rt_rmx; | |
420 | w->w_rtm.rtm_index = rt->rt_ifp->if_index; | |
421 | #undef next | |
422 | #define next(l) {n = (l); Bcopy(sa, cp, n); cp += n;} | |
a0d75f26 KS |
423 | if (size <= sizeof(w->w_m)) { |
424 | register caddr_t cp = (caddr_t)(w->w_m.m_sabuf); | |
a0d75f26 | 425 | if (sa = rt_key(rt)) |
79e0ea5d | 426 | next(ROUNDUP(sa->sa_len)); |
a0d75f26 | 427 | if (sa = rt->rt_gateway) |
79e0ea5d KS |
428 | next(ROUNDUP(sa->sa_len)); |
429 | if (sa = rt_mask(rt)) | |
430 | next(sa->sa_len ? ROUNDUP(sa->sa_len) : sizeof(long)); | |
a0d75f26 | 431 | if (sa = rt->rt_genmask) |
79e0ea5d | 432 | next(ROUNDUP(sa->sa_len)); |
a0d75f26 | 433 | #undef next |
79e0ea5d KS |
434 | #define next(s, l) {n = (l); \ |
435 | if (error = copyout((caddr_t)(s), w->w_where, n)) return (error); \ | |
436 | w->w_where += n;} | |
a0d75f26 KS |
437 | |
438 | next(&w->w_m, size); /* Copy rtmsg and sockaddrs back */ | |
439 | continue; | |
440 | } | |
441 | next(&w->w_rtm, sizeof(w->w_rtm)); | |
442 | if (sa = rt_key(rt)) | |
443 | next(sa, ROUNDUP(sa->sa_len)); | |
444 | if (sa = rt->rt_gateway) | |
445 | next(sa, ROUNDUP(sa->sa_len)); | |
79e0ea5d KS |
446 | if (sa = rt_mask(rt)) |
447 | next(sa, sa->sa_len ? ROUNDUP(sa->sa_len) : sizeof(long)); | |
a0d75f26 KS |
448 | if (sa = rt->rt_genmask) |
449 | next(sa, ROUNDUP(sa->sa_len)); | |
450 | } | |
451 | return (0); | |
452 | #undef next | |
453 | } | |
454 | ||
455 | kinfo_rtable(op, where, given, arg, needed) | |
456 | int op, arg; | |
457 | caddr_t where; | |
458 | int *given, *needed; | |
459 | { | |
460 | register struct radix_node_head *rnh; | |
461 | int s, error = 0; | |
462 | u_char af = ki_af(op); | |
463 | struct walkarg w; | |
464 | ||
465 | op &= 0xffff; | |
466 | if (op != KINFO_RT_DUMP && op != KINFO_RT_FLAGS) | |
467 | return (EINVAL); | |
468 | ||
469 | Bzero(&w, sizeof(w)); | |
470 | if ((w.w_where = where) && given) | |
471 | w.w_given = *given; | |
472 | w.w_needed = 0 - w.w_given; | |
473 | w.w_arg = arg; | |
474 | w.w_op = op; | |
79e0ea5d | 475 | w.w_rtm.rtm_version = RTM_VERSION; |
a0d75f26 KS |
476 | w.w_rtm.rtm_type = RTM_GET; |
477 | ||
478 | s = splnet(); | |
479 | for (rnh = radix_node_head; rnh; rnh = rnh->rnh_next) { | |
480 | if (rnh->rnh_af == 0) | |
481 | continue; | |
482 | if (af && af != rnh->rnh_af) | |
483 | continue; | |
484 | error = rt_walk(rnh->rnh_treetop, rt_dumpentry, &w); | |
485 | if (error) | |
486 | break; | |
487 | } | |
488 | w.w_needed += w.w_given; | |
489 | if (where && given) | |
490 | *given = w.w_where - where; | |
491 | else | |
492 | w.w_needed = (11 * w.w_needed) / 10; | |
493 | *needed = w.w_needed; | |
494 | splx(s); | |
495 | return (error); | |
496 | } | |
497 | ||
498 | rt_walk(rn, f, w) | |
499 | register struct radix_node *rn; | |
500 | register int (*f)(); | |
501 | struct walkarg *w; | |
502 | { | |
503 | int error; | |
504 | for (;;) { | |
505 | while (rn->rn_b >= 0) | |
506 | rn = rn->rn_l; /* First time through node, go left */ | |
507 | if (error = (*f)(rn, w)) | |
508 | return (error); /* Process Leaf */ | |
509 | while (rn->rn_p->rn_r == rn) { /* if coming back from right */ | |
510 | rn = rn->rn_p; /* go back up */ | |
511 | if (rn->rn_flags & RNF_ROOT) | |
512 | return 0; | |
513 | } | |
514 | rn = rn->rn_p->rn_r; /* otherwise, go right*/ | |
515 | } | |
516 | } | |
517 | ||
e831d540 KS |
518 | /* |
519 | * Definitions of protocols supported in the ROUTE domain. | |
520 | */ | |
521 | ||
522 | int route_output(); | |
523 | int raw_init(),raw_usrreq(),raw_input(),raw_ctlinput(); | |
524 | extern struct domain routedomain; /* or at least forward */ | |
525 | ||
526 | struct protosw routesw[] = { | |
527 | { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, | |
528 | raw_input, route_output, raw_ctlinput, 0, | |
529 | route_usrreq, | |
530 | raw_init, 0, 0, 0, | |
531 | }, | |
532 | { 0, 0, 0, 0, | |
533 | raw_input, 0, raw_ctlinput, 0, | |
534 | raw_usrreq, | |
535 | raw_init, 0, 0, 0, | |
536 | } | |
537 | }; | |
538 | ||
539 | int unp_externalize(), unp_dispose(); | |
540 | ||
541 | struct domain routedomain = | |
542 | { PF_ROUTE, "route", 0, 0, 0, | |
543 | routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; |