Merge from vendor branch OPENSSH:
[dragonfly.git] / sys / net / rtsock.c
1 /*
2  * Copyright (c) 1988, 1991, 1993
3  *      The Regents of the University of California.  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  *
33  *      @(#)rtsock.c    8.7 (Berkeley) 10/12/95
34  * $FreeBSD: src/sys/net/rtsock.c,v 1.44.2.11 2002/12/04 14:05:41 ru Exp $
35  * $DragonFly: src/sys/net/rtsock.c,v 1.14 2004/06/03 15:04:51 joerg Exp $
36  */
37
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/sysctl.h>
43 #include <sys/proc.h>
44 #include <sys/malloc.h>
45 #include <sys/mbuf.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/domain.h>
50
51 #include <machine/stdarg.h>
52
53 #include <net/if.h>
54 #include <net/route.h>
55 #include <net/raw_cb.h>
56
57 MALLOC_DEFINE(M_RTABLE, "routetbl", "routing tables");
58
59 static struct   sockaddr route_dst = { 2, PF_ROUTE, };
60 static struct   sockaddr route_src = { 2, PF_ROUTE, };
61 static struct   sockaddr sa_zero   = { sizeof(sa_zero), AF_INET, };
62 static struct   sockproto route_proto = { PF_ROUTE, };
63
64 struct walkarg {
65         int     w_tmemsize;
66         int     w_op, w_arg;
67         caddr_t w_tmem;
68         struct sysctl_req *w_req;
69 };
70
71 static struct mbuf *
72                 rt_msg1 (int, struct rt_addrinfo *);
73 static int      rt_msg2 (int, struct rt_addrinfo *, caddr_t, struct walkarg *);
74 static int      rt_xaddrs (caddr_t, caddr_t, struct rt_addrinfo *);
75 static int      sysctl_dumpentry (struct radix_node *rn, void *vw);
76 static int      sysctl_iflist (int af, struct walkarg *w);
77 static int      route_output(struct mbuf *, struct socket *, ...);
78 static void     rt_setmetrics (u_long, struct rt_metrics *,
79                     struct rt_metrics *);
80
81 /* Sleazy use of local variables throughout file, warning!!!! */
82 #define dst     info.rti_info[RTAX_DST]
83 #define gate    info.rti_info[RTAX_GATEWAY]
84 #define netmask info.rti_info[RTAX_NETMASK]
85 #define genmask info.rti_info[RTAX_GENMASK]
86 #define ifpaddr info.rti_info[RTAX_IFP]
87 #define ifaaddr info.rti_info[RTAX_IFA]
88 #define brdaddr info.rti_info[RTAX_BRD]
89
90 /*
91  * It really doesn't make any sense at all for this code to share much
92  * with raw_usrreq.c, since its functionality is so restricted.  XXX
93  */
94 static int
95 rts_abort(struct socket *so)
96 {
97         int s, error;
98         s = splnet();
99         error = raw_usrreqs.pru_abort(so);
100         splx(s);
101         return error;
102 }
103
104 /* pru_accept is EOPNOTSUPP */
105
106 static int
107 rts_attach(struct socket *so, int proto, struct pru_attach_info *ai)
108 {
109         struct rawcb *rp;
110         int s, error;
111
112         if (sotorawcb(so) != 0)
113                 return EISCONN; /* XXX panic? */
114         MALLOC(rp, struct rawcb *, sizeof *rp, M_PCB, M_WAITOK|M_ZERO);
115         if (rp == 0)
116                 return ENOBUFS;
117
118         /*
119          * The splnet() is necessary to block protocols from sending
120          * error notifications (like RTM_REDIRECT or RTM_LOSING) while
121          * this PCB is extant but incompletely initialized.
122          * Probably we should try to do more of this work beforehand and
123          * eliminate the spl.
124          */
125         s = splnet();
126         so->so_pcb = (caddr_t)rp;
127         error = raw_attach(so, proto, ai->sb_rlimit);
128         rp = sotorawcb(so);
129         if (error) {
130                 splx(s);
131                 free(rp, M_PCB);
132                 return error;
133         }
134         switch(rp->rcb_proto.sp_protocol) {
135         case AF_INET:
136                 route_cb.ip_count++;
137                 break;
138         case AF_INET6:
139                 route_cb.ip6_count++;
140                 break;
141         case AF_IPX:
142                 route_cb.ipx_count++;
143                 break;
144         case AF_NS:
145                 route_cb.ns_count++;
146                 break;
147         }
148         rp->rcb_faddr = &route_src;
149         route_cb.any_count++;
150         soisconnected(so);
151         so->so_options |= SO_USELOOPBACK;
152         splx(s);
153         return 0;
154 }
155
156 static int
157 rts_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
158 {
159         int s, error;
160         s = splnet();
161         error = raw_usrreqs.pru_bind(so, nam, td); /* xxx just EINVAL */
162         splx(s);
163         return error;
164 }
165
166 static int
167 rts_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
168 {
169         int s, error;
170         s = splnet();
171         error = raw_usrreqs.pru_connect(so, nam, td); /* XXX just EINVAL */
172         splx(s);
173         return error;
174 }
175
176 /* pru_connect2 is EOPNOTSUPP */
177 /* pru_control is EOPNOTSUPP */
178
179 static int
180 rts_detach(struct socket *so)
181 {
182         struct rawcb *rp = sotorawcb(so);
183         int s, error;
184
185         s = splnet();
186         if (rp != 0) {
187                 switch(rp->rcb_proto.sp_protocol) {
188                 case AF_INET:
189                         route_cb.ip_count--;
190                         break;
191                 case AF_INET6:
192                         route_cb.ip6_count--;
193                         break;
194                 case AF_IPX:
195                         route_cb.ipx_count--;
196                         break;
197                 case AF_NS:
198                         route_cb.ns_count--;
199                         break;
200                 }
201                 route_cb.any_count--;
202         }
203         error = raw_usrreqs.pru_detach(so);
204         splx(s);
205         return error;
206 }
207
208 static int
209 rts_disconnect(struct socket *so)
210 {
211         int s, error;
212         s = splnet();
213         error = raw_usrreqs.pru_disconnect(so);
214         splx(s);
215         return error;
216 }
217
218 /* pru_listen is EOPNOTSUPP */
219
220 static int
221 rts_peeraddr(struct socket *so, struct sockaddr **nam)
222 {
223         int s, error;
224         s = splnet();
225         error = raw_usrreqs.pru_peeraddr(so, nam);
226         splx(s);
227         return error;
228 }
229
230 /* pru_rcvd is EOPNOTSUPP */
231 /* pru_rcvoob is EOPNOTSUPP */
232
233 static int
234 rts_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
235          struct mbuf *control, struct thread *td)
236 {
237         int s, error;
238         s = splnet();
239         error = raw_usrreqs.pru_send(so, flags, m, nam, control, td);
240         splx(s);
241         return error;
242 }
243
244 /* pru_sense is null */
245
246 static int
247 rts_shutdown(struct socket *so)
248 {
249         int s, error;
250         s = splnet();
251         error = raw_usrreqs.pru_shutdown(so);
252         splx(s);
253         return error;
254 }
255
256 static int
257 rts_sockaddr(struct socket *so, struct sockaddr **nam)
258 {
259         int s, error;
260         s = splnet();
261         error = raw_usrreqs.pru_sockaddr(so, nam);
262         splx(s);
263         return error;
264 }
265
266 static struct pr_usrreqs route_usrreqs = {
267         rts_abort, pru_accept_notsupp, rts_attach, rts_bind, rts_connect,
268         pru_connect2_notsupp, pru_control_notsupp, rts_detach, rts_disconnect,
269         pru_listen_notsupp, rts_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp,
270         rts_send, pru_sense_null, rts_shutdown, rts_sockaddr,
271         sosend, soreceive, sopoll
272 };
273
274 /*ARGSUSED*/
275 static int
276 route_output(struct mbuf *m, struct socket *so, ...)
277 {
278         struct rt_msghdr *rtm = 0;
279         struct rtentry *rt = 0;
280         struct rtentry *saved_nrt = 0;
281         struct radix_node_head *rnh;
282         struct rt_addrinfo info;
283         int len, error = 0;
284         struct ifnet *ifp = 0;
285         struct ifaddr *ifa = 0;
286         struct pr_output_info *oi;
287         __va_list ap;
288
289         __va_start(ap, so);
290         oi = __va_arg(ap, struct pr_output_info *);
291         __va_end(ap);
292
293 #define senderr(e) { error = e; goto flush;}
294         if (m == 0 || ((m->m_len < sizeof(long)) &&
295                        (m = m_pullup(m, sizeof(long))) == 0))
296                 return (ENOBUFS);
297         if ((m->m_flags & M_PKTHDR) == 0)
298                 panic("route_output");
299         len = m->m_pkthdr.len;
300         if (len < sizeof(*rtm) ||
301             len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
302                 dst = 0;
303                 senderr(EINVAL);
304         }
305         R_Malloc(rtm, struct rt_msghdr *, len);
306         if (rtm == 0) {
307                 dst = 0;
308                 senderr(ENOBUFS);
309         }
310         m_copydata(m, 0, len, (caddr_t)rtm);
311         if (rtm->rtm_version != RTM_VERSION) {
312                 dst = 0;
313                 senderr(EPROTONOSUPPORT);
314         }
315         rtm->rtm_pid = oi->p_pid;
316         bzero(&info, sizeof(info));
317         info.rti_addrs = rtm->rtm_addrs;
318         if (rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info)) {
319                 dst = 0;
320                 senderr(EINVAL);
321         }
322         info.rti_flags = rtm->rtm_flags;
323         if (dst == 0 || (dst->sa_family >= AF_MAX)
324             || (gate != 0 && (gate->sa_family >= AF_MAX)))
325                 senderr(EINVAL);
326         if (genmask) {
327                 struct radix_node *t;
328                 t = rn_addmask((caddr_t)genmask, 0, 1);
329                 if (t && Bcmp((caddr_t *)genmask + 1, (caddr_t *)t->rn_key + 1,
330                               *(u_char *)t->rn_key - 1) == 0)
331                         genmask = (struct sockaddr *)(t->rn_key);
332                 else
333                         senderr(ENOBUFS);
334         }
335
336         /*
337          * Verify that the caller has the appropriate privilege; RTM_GET
338          * is the only operation the non-superuser is allowed.
339          */
340         if (rtm->rtm_type != RTM_GET && suser_cred(so->so_cred, 0) != 0)
341                 senderr(EPERM);
342
343         switch (rtm->rtm_type) {
344
345         case RTM_ADD:
346                 if (gate == 0)
347                         senderr(EINVAL);
348                 error = rtrequest1(RTM_ADD, &info, &saved_nrt);
349                 if (error == 0 && saved_nrt) {
350                         rt_setmetrics(rtm->rtm_inits,
351                                 &rtm->rtm_rmx, &saved_nrt->rt_rmx);
352                         saved_nrt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
353                         saved_nrt->rt_rmx.rmx_locks |=
354                                 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
355                         saved_nrt->rt_refcnt--;
356                         saved_nrt->rt_genmask = genmask;
357                 }
358                 break;
359
360         case RTM_DELETE:
361                 error = rtrequest1(RTM_DELETE, &info, &saved_nrt);
362                 if (error == 0) {
363                         if ((rt = saved_nrt))
364                                 rt->rt_refcnt++;
365                         goto report;
366                 }
367                 break;
368
369         case RTM_GET:
370         case RTM_CHANGE:
371         case RTM_LOCK:
372                 if ((rnh = rt_tables[dst->sa_family]) == 0) {
373                         senderr(EAFNOSUPPORT);
374                 } else if ((rt = (struct rtentry *)
375                                 rnh->rnh_lookup(dst, netmask, rnh)) != NULL)
376                         rt->rt_refcnt++;
377                 else
378                         senderr(ESRCH);
379                 switch(rtm->rtm_type) {
380
381                 case RTM_GET:
382                 report:
383                         dst = rt_key(rt);
384                         gate = rt->rt_gateway;
385                         netmask = rt_mask(rt);
386                         genmask = rt->rt_genmask;
387                         if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
388                                 ifp = rt->rt_ifp;
389                                 if (ifp) {
390                                         ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
391                                         ifaaddr = rt->rt_ifa->ifa_addr;
392                                         if (ifp->if_flags & IFF_POINTOPOINT)
393                                                 brdaddr = rt->rt_ifa->ifa_dstaddr;
394                                         rtm->rtm_index = ifp->if_index;
395                                 } else {
396                                         ifpaddr = 0;
397                                         ifaaddr = 0;
398                             }
399                         }
400                         len = rt_msg2(rtm->rtm_type, &info, (caddr_t)0,
401                                 (struct walkarg *)0);
402                         if (len > rtm->rtm_msglen) {
403                                 struct rt_msghdr *new_rtm;
404                                 R_Malloc(new_rtm, struct rt_msghdr *, len);
405                                 if (new_rtm == 0)
406                                         senderr(ENOBUFS);
407                                 Bcopy(rtm, new_rtm, rtm->rtm_msglen);
408                                 Free(rtm); rtm = new_rtm;
409                         }
410                         (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm,
411                                 (struct walkarg *)0);
412                         rtm->rtm_flags = rt->rt_flags;
413                         rtm->rtm_rmx = rt->rt_rmx;
414                         rtm->rtm_addrs = info.rti_addrs;
415                         break;
416
417                 case RTM_CHANGE:
418                         /* new gateway could require new ifaddr, ifp;
419                            flags may also be different; ifp may be specified
420                            by ll sockaddr when protocol address is ambiguous */
421 #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
422                         if ((rt->rt_flags & RTF_GATEWAY && gate != NULL) ||
423                             ifpaddr != NULL ||
424                             (ifaaddr != NULL &&
425                             !equal(ifaaddr, rt->rt_ifa->ifa_addr))) {
426                                 if ((error = rt_getifa(&info)) != 0)
427                                         senderr(error);
428                         }
429                         if (gate != NULL &&
430                             (error = rt_setgate(rt, rt_key(rt), gate)) != 0)
431                                 senderr(error);
432                         if ((ifa = info.rti_ifa) != NULL) {
433                                 struct ifaddr *oifa = rt->rt_ifa;
434                                 if (oifa != ifa) {
435                                     if (oifa && oifa->ifa_rtrequest)
436                                         oifa->ifa_rtrequest(RTM_DELETE, rt,
437                                             &info);
438                                     IFAFREE(rt->rt_ifa);
439                                     rt->rt_ifa = ifa;
440                                     ifa->ifa_refcnt++;
441                                     rt->rt_ifp = info.rti_ifp;
442                                 }
443                         }
444                         rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
445                                         &rt->rt_rmx);
446                         if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
447                                rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info);
448                         if (genmask)
449                                 rt->rt_genmask = genmask;
450                         /*
451                          * Fall into
452                          */
453                 case RTM_LOCK:
454                         rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
455                         rt->rt_rmx.rmx_locks |=
456                                 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
457                         break;
458                 }
459                 break;
460
461         default:
462                 senderr(EOPNOTSUPP);
463         }
464
465 flush:
466         if (rtm) {
467                 if (error)
468                         rtm->rtm_errno = error;
469                 else
470                         rtm->rtm_flags |= RTF_DONE;
471         }
472         if (rt)
473                 rtfree(rt);
474     {
475         struct rawcb *rp = 0;
476         /*
477          * Check to see if we don't want our own messages.
478          */
479         if ((so->so_options & SO_USELOOPBACK) == 0) {
480                 if (route_cb.any_count <= 1) {
481                         if (rtm)
482                                 Free(rtm);
483                         m_freem(m);
484                         return (error);
485                 }
486                 /* There is another listener, so construct message */
487                 rp = sotorawcb(so);
488         }
489         if (rtm) {
490                 m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
491                 if (m->m_pkthdr.len < rtm->rtm_msglen) {
492                         m_freem(m);
493                         m = NULL;
494                 } else if (m->m_pkthdr.len > rtm->rtm_msglen)
495                         m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
496                 Free(rtm);
497         }
498         if (rp)
499                 rp->rcb_proto.sp_family = 0; /* Avoid us */
500         if (dst)
501                 route_proto.sp_protocol = dst->sa_family;
502         if (m)
503                 raw_input(m, &route_proto, &route_src, &route_dst);
504         if (rp)
505                 rp->rcb_proto.sp_family = PF_ROUTE;
506     }
507         return (error);
508 }
509
510 static void
511 rt_setmetrics(which, in, out)
512         u_long which;
513         struct rt_metrics *in, *out;
514 {
515 #define metric(f, e) if (which & (f)) out->e = in->e;
516         metric(RTV_RPIPE, rmx_recvpipe);
517         metric(RTV_SPIPE, rmx_sendpipe);
518         metric(RTV_SSTHRESH, rmx_ssthresh);
519         metric(RTV_RTT, rmx_rtt);
520         metric(RTV_RTTVAR, rmx_rttvar);
521         metric(RTV_HOPCOUNT, rmx_hopcount);
522         metric(RTV_MTU, rmx_mtu);
523         metric(RTV_EXPIRE, rmx_expire);
524 #undef metric
525 }
526
527 #define ROUNDUP(a) \
528         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
529 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
530
531
532 /*
533  * Extract the addresses of the passed sockaddrs.
534  * Do a little sanity checking so as to avoid bad memory references.
535  * This data is derived straight from userland.
536  */
537 static int
538 rt_xaddrs(cp, cplim, rtinfo)
539         caddr_t cp, cplim;
540         struct rt_addrinfo *rtinfo;
541 {
542         struct sockaddr *sa;
543         int i;
544
545         for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
546                 if ((rtinfo->rti_addrs & (1 << i)) == 0)
547                         continue;
548                 sa = (struct sockaddr *)cp;
549                 /*
550                  * It won't fit.
551                  */
552                 if ( (cp + sa->sa_len) > cplim ) {
553                         return (EINVAL);
554                 }
555
556                 /*
557                  * there are no more.. quit now
558                  * If there are more bits, they are in error.
559                  * I've seen this. route(1) can evidently generate these. 
560                  * This causes kernel to core dump.
561                  * for compatibility, If we see this, point to a safe address.
562                  */
563                 if (sa->sa_len == 0) {
564                         rtinfo->rti_info[i] = &sa_zero;
565                         return (0); /* should be EINVAL but for compat */
566                 }
567
568                 /* accept it */
569                 rtinfo->rti_info[i] = sa;
570                 ADVANCE(cp, sa);
571         }
572         return (0);
573 }
574
575 static struct mbuf *
576 rt_msg1(type, rtinfo)
577         int type;
578         struct rt_addrinfo *rtinfo;
579 {
580         struct rt_msghdr *rtm;
581         struct mbuf *m;
582         int i;
583         struct sockaddr *sa;
584         int len, dlen;
585
586         switch (type) {
587
588         case RTM_DELADDR:
589         case RTM_NEWADDR:
590                 len = sizeof(struct ifa_msghdr);
591                 break;
592
593         case RTM_DELMADDR:
594         case RTM_NEWMADDR:
595                 len = sizeof(struct ifma_msghdr);
596                 break;
597
598         case RTM_IFINFO:
599                 len = sizeof(struct if_msghdr);
600                 break;
601
602         case RTM_IFANNOUNCE:
603                 len = sizeof(struct if_announcemsghdr);
604                 break;
605
606         default:
607                 len = sizeof(struct rt_msghdr);
608         }
609         if (len > MCLBYTES)
610                 panic("rt_msg1");
611         m = m_gethdr(MB_DONTWAIT, MT_DATA);
612         if (m && len > MHLEN) {
613                 MCLGET(m, MB_DONTWAIT);
614                 if ((m->m_flags & M_EXT) == 0) {
615                         m_free(m);
616                         m = NULL;
617                 }
618         }
619         if (m == 0)
620                 return (m);
621         m->m_pkthdr.len = m->m_len = len;
622         m->m_pkthdr.rcvif = 0;
623         rtm = mtod(m, struct rt_msghdr *);
624         bzero((caddr_t)rtm, len);
625         for (i = 0; i < RTAX_MAX; i++) {
626                 if ((sa = rtinfo->rti_info[i]) == NULL)
627                         continue;
628                 rtinfo->rti_addrs |= (1 << i);
629                 dlen = ROUNDUP(sa->sa_len);
630                 m_copyback(m, len, dlen, (caddr_t)sa);
631                 len += dlen;
632         }
633         if (m->m_pkthdr.len != len) {
634                 m_freem(m);
635                 return (NULL);
636         }
637         rtm->rtm_msglen = len;
638         rtm->rtm_version = RTM_VERSION;
639         rtm->rtm_type = type;
640         return (m);
641 }
642
643 static int
644 rt_msg2(type, rtinfo, cp, w)
645         int type;
646         struct rt_addrinfo *rtinfo;
647         caddr_t cp;
648         struct walkarg *w;
649 {
650         int i;
651         int len, dlen, second_time = 0;
652         caddr_t cp0;
653
654         rtinfo->rti_addrs = 0;
655 again:
656         switch (type) {
657
658         case RTM_DELADDR:
659         case RTM_NEWADDR:
660                 len = sizeof(struct ifa_msghdr);
661                 break;
662
663         case RTM_IFINFO:
664                 len = sizeof(struct if_msghdr);
665                 break;
666
667         default:
668                 len = sizeof(struct rt_msghdr);
669         }
670         cp0 = cp;
671         if (cp0)
672                 cp += len;
673         for (i = 0; i < RTAX_MAX; i++) {
674                 struct sockaddr *sa;
675
676                 if ((sa = rtinfo->rti_info[i]) == 0)
677                         continue;
678                 rtinfo->rti_addrs |= (1 << i);
679                 dlen = ROUNDUP(sa->sa_len);
680                 if (cp) {
681                         bcopy((caddr_t)sa, cp, (unsigned)dlen);
682                         cp += dlen;
683                 }
684                 len += dlen;
685         }
686         len = ALIGN(len);
687         if (cp == 0 && w != NULL && !second_time) {
688                 struct walkarg *rw = w;
689
690                 if (rw->w_req) {
691                         if (rw->w_tmemsize < len) {
692                                 if (rw->w_tmem)
693                                         free(rw->w_tmem, M_RTABLE);
694                                 rw->w_tmem = (caddr_t)malloc(len, M_RTABLE,
695                                                         M_INTWAIT | M_NULLOK);
696                                 if (rw->w_tmem)
697                                         rw->w_tmemsize = len;
698                         }
699                         if (rw->w_tmem) {
700                                 cp = rw->w_tmem;
701                                 second_time = 1;
702                                 goto again;
703                         }
704                 }
705         }
706         if (cp) {
707                 struct rt_msghdr *rtm = (struct rt_msghdr *)cp0;
708
709                 rtm->rtm_version = RTM_VERSION;
710                 rtm->rtm_type = type;
711                 rtm->rtm_msglen = len;
712         }
713         return (len);
714 }
715
716 /*
717  * This routine is called to generate a message from the routing
718  * socket indicating that a redirect has occured, a routing lookup
719  * has failed, or that a protocol has detected timeouts to a particular
720  * destination.
721  */
722 void
723 rt_missmsg(type, rtinfo, flags, error)
724         int type, flags, error;
725         struct rt_addrinfo *rtinfo;
726 {
727         struct rt_msghdr *rtm;
728         struct mbuf *m;
729         struct sockaddr *sa = rtinfo->rti_info[RTAX_DST];
730
731         if (route_cb.any_count == 0)
732                 return;
733         m = rt_msg1(type, rtinfo);
734         if (m == 0)
735                 return;
736         rtm = mtod(m, struct rt_msghdr *);
737         rtm->rtm_flags = RTF_DONE | flags;
738         rtm->rtm_errno = error;
739         rtm->rtm_addrs = rtinfo->rti_addrs;
740         route_proto.sp_protocol = sa ? sa->sa_family : 0;
741         raw_input(m, &route_proto, &route_src, &route_dst);
742 }
743
744 /*
745  * This routine is called to generate a message from the routing
746  * socket indicating that the status of a network interface has changed.
747  */
748 void
749 rt_ifmsg(ifp)
750         struct ifnet *ifp;
751 {
752         struct if_msghdr *ifm;
753         struct mbuf *m;
754         struct rt_addrinfo info;
755
756         if (route_cb.any_count == 0)
757                 return;
758         bzero((caddr_t)&info, sizeof(info));
759         m = rt_msg1(RTM_IFINFO, &info);
760         if (m == 0)
761                 return;
762         ifm = mtod(m, struct if_msghdr *);
763         ifm->ifm_index = ifp->if_index;
764         ifm->ifm_flags = (u_short)ifp->if_flags;
765         ifm->ifm_data = ifp->if_data;
766         ifm->ifm_addrs = 0;
767         route_proto.sp_protocol = 0;
768         raw_input(m, &route_proto, &route_src, &route_dst);
769 }
770
771 static void
772 rt_ifamsg(int cmd, struct ifaddr *ifa)
773 {
774         struct ifa_msghdr *ifam;
775         struct rt_addrinfo info;
776         struct mbuf *m;
777         struct sockaddr *sa;
778         struct ifnet *ifp = ifa->ifa_ifp;
779
780         bzero(&info, sizeof(info));
781         ifaaddr = sa = ifa->ifa_addr;
782         ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
783         netmask = ifa->ifa_netmask;
784         brdaddr = ifa->ifa_dstaddr;
785         if ((m = rt_msg1(cmd, &info)) == NULL)
786                 return;
787         ifam = mtod(m, struct ifa_msghdr *);
788         ifam->ifam_index = ifp->if_index;
789         ifam->ifam_metric = ifa->ifa_metric;
790         ifam->ifam_flags = ifa->ifa_flags;
791         ifam->ifam_addrs = info.rti_addrs;
792
793         route_proto.sp_protocol = sa ? sa->sa_family : 0;
794         raw_input(m, &route_proto, &route_src, &route_dst);
795 }
796
797 static void
798 rt_rtmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
799 {
800         struct rt_msghdr *rtm;
801         struct rt_addrinfo info;
802         struct mbuf *m;
803         struct sockaddr *sa;
804         struct ifnet *ifp = ifa->ifa_ifp;
805
806         if (rt == NULL)
807                 return;
808         bzero(&info, sizeof(info));
809         netmask = rt_mask(rt);
810         dst = sa = rt_key(rt);
811         gate = rt->rt_gateway;
812         if ((m = rt_msg1(cmd, &info)) == NULL)
813                 return;
814         rtm = mtod(m, struct rt_msghdr *);
815         rtm->rtm_index = ifp->if_index;
816         rtm->rtm_flags |= rt->rt_flags;
817         rtm->rtm_errno = error;
818         rtm->rtm_addrs = info.rti_addrs;
819
820         route_proto.sp_protocol = sa ? sa->sa_family : 0;
821         raw_input(m, &route_proto, &route_src, &route_dst);
822 }
823
824 /*
825  * This is called to generate messages from the routing socket
826  * indicating a network interface has had addresses associated with it.
827  * if we ever reverse the logic and replace messages TO the routing
828  * socket indicate a request to configure interfaces, then it will
829  * be unnecessary as the routing socket will automatically generate
830  * copies of it.
831  */
832 void
833 rt_newaddrmsg(cmd, ifa, error, rt)
834         int cmd, error;
835         struct ifaddr *ifa;
836         struct rtentry *rt;
837 {
838         if (route_cb.any_count == 0)
839                 return;
840
841         if (cmd == RTM_ADD) {
842                 rt_ifamsg(RTM_NEWADDR, ifa);
843                 rt_rtmsg(RTM_ADD, ifa, error, rt);
844         } else {
845                 KASSERT((cmd == RTM_DELETE), ("unknown cmd %d", cmd));
846                 rt_rtmsg(RTM_DELETE, ifa, error, rt);
847                 rt_ifamsg(RTM_DELADDR, ifa);
848         }
849 }
850
851 /*
852  * This is the analogue to the rt_newaddrmsg which performs the same
853  * function but for multicast group memberhips.  This is easier since
854  * there is no route state to worry about.
855  */
856 void
857 rt_newmaddrmsg(cmd, ifma)
858         int cmd;
859         struct ifmultiaddr *ifma;
860 {
861         struct rt_addrinfo info;
862         struct mbuf *m = 0;
863         struct ifnet *ifp = ifma->ifma_ifp;
864         struct ifma_msghdr *ifmam;
865
866         if (route_cb.any_count == 0)
867                 return;
868
869         bzero((caddr_t)&info, sizeof(info));
870         ifaaddr = ifma->ifma_addr;
871         if (ifp && TAILQ_FIRST(&ifp->if_addrhead))
872                 ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
873         else
874                 ifpaddr = NULL;
875         /*
876          * If a link-layer address is present, present it as a ``gateway''
877          * (similarly to how ARP entries, e.g., are presented).
878          */
879         gate = ifma->ifma_lladdr;
880         if ((m = rt_msg1(cmd, &info)) == NULL)
881                 return;
882         ifmam = mtod(m, struct ifma_msghdr *);
883         ifmam->ifmam_index = ifp->if_index;
884         ifmam->ifmam_addrs = info.rti_addrs;
885         route_proto.sp_protocol = ifma->ifma_addr->sa_family;
886         raw_input(m, &route_proto, &route_src, &route_dst);
887 }
888
889 /*
890  * This is called to generate routing socket messages indicating
891  * network interface arrival and departure.
892  */
893 void
894 rt_ifannouncemsg(ifp, what)
895         struct ifnet *ifp;
896         int what;
897 {
898         struct if_announcemsghdr *ifan;
899         struct mbuf *m;
900         struct rt_addrinfo info;
901
902         if (route_cb.any_count == 0)
903                 return;
904         bzero((caddr_t)&info, sizeof(info));
905         m = rt_msg1(RTM_IFANNOUNCE, &info);
906         if (m == NULL)
907                 return;
908         ifan = mtod(m, struct if_announcemsghdr *);
909         ifan->ifan_index = ifp->if_index;
910         strlcpy(ifan->ifan_name, ifp->if_xname, sizeof(ifan->ifan_name));
911         ifan->ifan_what = what;
912         route_proto.sp_protocol = 0;
913         raw_input(m, &route_proto, &route_src, &route_dst);
914  }
915
916 /*
917  * This is used in dumping the kernel table via sysctl().
918  */
919 int
920 sysctl_dumpentry(rn, vw)
921         struct radix_node *rn;
922         void *vw;
923 {
924         struct walkarg *w = vw;
925         struct rtentry *rt = (struct rtentry *)rn;
926         int error = 0, size;
927         struct rt_addrinfo info;
928
929         if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
930                 return 0;
931         bzero((caddr_t)&info, sizeof(info));
932         dst = rt_key(rt);
933         gate = rt->rt_gateway;
934         netmask = rt_mask(rt);
935         genmask = rt->rt_genmask;
936         if (rt->rt_ifp) {
937                 ifpaddr = TAILQ_FIRST(&rt->rt_ifp->if_addrhead)->ifa_addr;
938                 ifaaddr = rt->rt_ifa->ifa_addr;
939                 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
940                         brdaddr = rt->rt_ifa->ifa_dstaddr;
941         }
942         size = rt_msg2(RTM_GET, &info, 0, w);
943         if (w->w_req && w->w_tmem) {
944                 struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
945
946                 rtm->rtm_flags = rt->rt_flags;
947                 rtm->rtm_use = rt->rt_use;
948                 rtm->rtm_rmx = rt->rt_rmx;
949                 rtm->rtm_index = rt->rt_ifp->if_index;
950                 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
951                 rtm->rtm_addrs = info.rti_addrs;
952                 error = SYSCTL_OUT(w->w_req, (caddr_t)rtm, size);
953                 return (error);
954         }
955         return (error);
956 }
957
958 int
959 sysctl_iflist(af, w)
960         int     af;
961         struct  walkarg *w;
962 {
963         struct ifnet *ifp;
964         struct ifaddr *ifa;
965         struct  rt_addrinfo info;
966         int     len, error = 0;
967
968         bzero((caddr_t)&info, sizeof(info));
969         TAILQ_FOREACH(ifp, &ifnet, if_link) {
970                 if (w->w_arg && w->w_arg != ifp->if_index)
971                         continue;
972                 ifa = TAILQ_FIRST(&ifp->if_addrhead);
973                 ifpaddr = ifa->ifa_addr;
974                 len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w);
975                 ifpaddr = 0;
976                 if (w->w_req && w->w_tmem) {
977                         struct if_msghdr *ifm;
978
979                         ifm = (struct if_msghdr *)w->w_tmem;
980                         ifm->ifm_index = ifp->if_index;
981                         ifm->ifm_flags = (u_short)ifp->if_flags;
982                         ifm->ifm_data = ifp->if_data;
983                         ifm->ifm_addrs = info.rti_addrs;
984                         error = SYSCTL_OUT(w->w_req,(caddr_t)ifm, len);
985                         if (error)
986                                 return (error);
987                 }
988                 while ((ifa = TAILQ_NEXT(ifa, ifa_link)) != 0) {
989                         if (af && af != ifa->ifa_addr->sa_family)
990                                 continue;
991                         if (curproc->p_ucred->cr_prison && prison_if(curthread, ifa->ifa_addr))
992                                 continue;
993                         ifaaddr = ifa->ifa_addr;
994                         netmask = ifa->ifa_netmask;
995                         brdaddr = ifa->ifa_dstaddr;
996                         len = rt_msg2(RTM_NEWADDR, &info, 0, w);
997                         if (w->w_req && w->w_tmem) {
998                                 struct ifa_msghdr *ifam;
999
1000                                 ifam = (struct ifa_msghdr *)w->w_tmem;
1001                                 ifam->ifam_index = ifa->ifa_ifp->if_index;
1002                                 ifam->ifam_flags = ifa->ifa_flags;
1003                                 ifam->ifam_metric = ifa->ifa_metric;
1004                                 ifam->ifam_addrs = info.rti_addrs;
1005                                 error = SYSCTL_OUT(w->w_req, w->w_tmem, len);
1006                                 if (error)
1007                                         return (error);
1008                         }
1009                 }
1010                 ifaaddr = netmask = brdaddr = 0;
1011         }
1012         return (0);
1013 }
1014
1015 static int
1016 sysctl_rtsock(SYSCTL_HANDLER_ARGS)
1017 {
1018         int     *name = (int *)arg1;
1019         u_int   namelen = arg2;
1020         struct radix_node_head *rnh;
1021         int     i, s, error = EINVAL;
1022         u_char  af;
1023         struct  walkarg w;
1024
1025         name ++;
1026         namelen--;
1027         if (req->newptr)
1028                 return (EPERM);
1029         if (namelen != 3)
1030                 return (EINVAL);
1031         af = name[0];
1032         Bzero(&w, sizeof(w));
1033         w.w_op = name[1];
1034         w.w_arg = name[2];
1035         w.w_req = req;
1036
1037         s = splnet();
1038         switch (w.w_op) {
1039
1040         case NET_RT_DUMP:
1041         case NET_RT_FLAGS:
1042                 for (i = 1; i <= AF_MAX; i++)
1043                         if ((rnh = rt_tables[i]) && (af == 0 || af == i) &&
1044                             (error = rnh->rnh_walktree(rnh,
1045                                                         sysctl_dumpentry, &w)))
1046                                 break;
1047                 break;
1048
1049         case NET_RT_IFLIST:
1050                 error = sysctl_iflist(af, &w);
1051         }
1052         splx(s);
1053         if (w.w_tmem)
1054                 free(w.w_tmem, M_RTABLE);
1055         return (error);
1056 }
1057
1058 SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock, "");
1059
1060 /*
1061  * Definitions of protocols supported in the ROUTE domain.
1062  */
1063
1064 extern struct domain routedomain;               /* or at least forward */
1065
1066 static struct protosw routesw[] = {
1067 { SOCK_RAW,     &routedomain,   0,              PR_ATOMIC|PR_ADDR,
1068   0,            route_output,   raw_ctlinput,   0,
1069   cpu0_soport,
1070   raw_init,     0,              0,              0,
1071   &route_usrreqs
1072 }
1073 };
1074
1075 static struct domain routedomain =
1076     { PF_ROUTE, "route", 0, 0, 0,
1077       routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };
1078
1079 DOMAIN_SET(route);