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