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