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