2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
5 * Copyright (C) 2005 - 2007 The AROS Dev Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
24 * Copyright (c) 1988, 1991 Regents of the University of California.
25 * All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * @(#)rtsock.c 7.18 (Berkeley) 6/27/91
60 #include <sys/param.h>
61 #include <sys/malloc.h>
63 #include <sys/socket.h>
64 #include <sys/socketvar.h>
65 #include <sys/domain.h>
66 #include <sys/protosw.h>
67 #include <sys/synch.h>
70 #include <net/route.h>
71 #include <net/raw_cb.h>
73 #include <kern/amiga_subr.h>
75 #include <net/rtsock_protos.h>
76 #include <net/raw_usrreq_protos.h>
78 struct sockaddr route_dst
= { 2, PF_ROUTE
, };
79 struct sockaddr route_src
= { 2, PF_ROUTE
, };
80 struct sockproto route_proto
= { PF_ROUTE
, };
81 extern struct route_cb route_cb
;
84 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
85 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
89 route_usrreq(so
, req
, m
, nam
, control
)
90 register struct socket
*so
;
92 struct mbuf
*m
, *nam
, *control
;
94 register int error
= 0;
95 register struct rawcb
*rp
= sotorawcb(so
);
98 if (req
== PRU_ATTACH
) {
99 MALLOC(rp
, struct rawcb
*, sizeof(*rp
), M_PCB
, M_WAITOK
);
100 if (so
->so_pcb
= (caddr_t
)rp
)
101 aligned_bzero_const(so
->so_pcb
, sizeof(*rp
));
104 if (req
== PRU_DETACH
&& rp
) {
105 int af
= rp
->rcb_proto
.sp_protocol
;
108 else if (af
== AF_NS
)
110 else if (af
== AF_ISO
)
111 route_cb
.iso_count
--;
112 route_cb
.any_count
--;
115 error
= raw_usrreq(so
, req
, m
, nam
, control
);
117 if (req
== PRU_ATTACH
&& rp
) {
118 int af
= rp
->rcb_proto
.sp_protocol
;
120 bsd_free((caddr_t
)rp
, M_PCB
);
126 else if (af
== AF_NS
)
128 else if (af
== AF_ISO
)
129 route_cb
.iso_count
++;
130 rp
->rcb_faddr
= &route_src
;
131 route_cb
.any_count
++;
133 so
->so_options
|= SO_USELOOPBACK
;
141 register struct mbuf
*m
;
144 register struct rt_msghdr
*rtm
= 0;
145 register struct rtentry
*rt
= 0;
146 struct rtentry
*saved_nrt
= 0;
147 struct sockaddr
*dst
= 0, *gate
= 0, *netmask
= 0, *genmask
= 0;
148 struct sockaddr
*ifpaddr
= 0, *ifaaddr
= 0;
151 struct ifnet
*ifp
= 0;
152 struct ifaddr
*ifa
= 0;
153 struct ifaddr
*ifaof_ifpforaddr(), *ifa_ifwithroute();
155 struct proc
*curproc
= (struct proc
*)cthread_data(cthread_self());
158 #define senderr(e) { error = e; goto flush;}
159 if (m
== 0 || m
->m_len
< sizeof(long))
161 if ((m
= m_pullup(m
, sizeof(long))) == 0)
163 if ((m
->m_flags
& M_PKTHDR
) == 0)
164 panic("route_output");
165 len
= m
->m_pkthdr
.len
;
166 if (len
< sizeof(*rtm
) ||
167 len
!= mtod(m
, struct rt_msghdr
*)->rtm_msglen
)
169 R_Malloc(rtm
, struct rt_msghdr
*, len
);
172 m_copydata(m
, 0, len
, (caddr_t
)rtm
);
173 if (rtm
->rtm_version
!= RTM_VERSION
)
174 senderr(EPROTONOSUPPORT
);
175 rtm
->rtm_pid
= (pid_t
)FindTask(NULL
);
176 lim
= len
+ (caddr_t
) rtm
;
177 cp
= (caddr_t
) (rtm
+ 1);
178 if (rtm
->rtm_addrs
& RTA_DST
) {
179 dst
= (struct sockaddr
*)cp
;
183 if ((rtm
->rtm_addrs
& RTA_GATEWAY
) && cp
< lim
) {
184 gate
= (struct sockaddr
*)cp
;
187 if ((rtm
->rtm_addrs
& RTA_NETMASK
) && cp
< lim
) {
188 netmask
= (struct sockaddr
*)cp
;
189 ADVANCE(cp
, netmask
);
191 if ((rtm
->rtm_addrs
& RTA_GENMASK
) && cp
< lim
) {
192 struct radix_node
*t
, *rn_addmask();
193 genmask
= (struct sockaddr
*)cp
;
194 ADVANCE(cp
, genmask
);
195 t
= rn_addmask(genmask
, 1, 2);
196 if (t
&& Bcmp(genmask
, t
->rn_key
, *(u_char
*)genmask
) == 0)
197 genmask
= (struct sockaddr
*)(t
->rn_key
);
201 if ((rtm
->rtm_addrs
& RTA_IFP
) && cp
< lim
) {
202 ifpaddr
= (struct sockaddr
*)cp
;
203 ADVANCE(cp
, ifpaddr
);
205 if ((rtm
->rtm_addrs
& RTA_IFA
) && cp
< lim
) {
206 ifaaddr
= (struct sockaddr
*)cp
;
208 switch (rtm
->rtm_type
) {
212 error
= rtrequest(RTM_ADD
, dst
, gate
, netmask
,
213 rtm
->rtm_flags
, &saved_nrt
);
214 if (error
== 0 && saved_nrt
) {
215 rt_setmetrics(rtm
->rtm_inits
,
216 &rtm
->rtm_rmx
, &saved_nrt
->rt_rmx
);
217 saved_nrt
->rt_refcnt
--;
218 saved_nrt
->rt_genmask
= genmask
;
223 error
= rtrequest(RTM_DELETE
, dst
, gate
, netmask
,
224 rtm
->rtm_flags
, (struct rtentry
**)0);
230 rt
= rtalloc1(dst
, 0);
233 if (rtm
->rtm_type
!= RTM_GET
) {
234 if (Bcmp(dst
, rt_key(rt
), dst
->sa_len
) != 0)
236 if (rt
->rt_nodes
->rn_dupedkey
&&
238 Bcmp(netmask
, rt_mask(rt
), netmask
->sa_len
)))
239 senderr(ETOOMANYREFS
);
241 switch(rtm
->rtm_type
) {
244 dst
= rt_key(rt
); len
= sizeof(*rtm
);
246 rtm
->rtm_addrs
|= RTA_DST
;
247 if (gate
= rt
->rt_gateway
) {
249 rtm
->rtm_addrs
|= RTA_GATEWAY
;
251 rtm
->rtm_addrs
&= ~RTA_GATEWAY
;
252 if (netmask
= rt_mask(rt
)) {
253 ADVANCE(len
, netmask
);
254 rtm
->rtm_addrs
|= RTA_NETMASK
;
256 rtm
->rtm_addrs
&= ~RTA_NETMASK
;
257 if (genmask
= rt
->rt_genmask
) {
258 ADVANCE(len
, genmask
);
259 rtm
->rtm_addrs
|= RTA_GENMASK
;
261 rtm
->rtm_addrs
&= ~RTA_GENMASK
;
262 if (rtm
->rtm_addrs
& (RTA_IFP
| RTA_IFA
)) {
265 for (ifa
= rt
->rt_ifp
->if_addrlist
;
266 ifa
&& ifa
->ifa_addr
->sa_family
!= AF_LINK
;
267 ifa
= ifa
->ifa_next
){}
268 if (ifa
&& rt
->rt_ifa
) {
269 ifpaddr
= ifa
->ifa_addr
;
270 ADVANCE(len
, ifpaddr
);
271 ifaaddr
= rt
->rt_ifa
->ifa_addr
;
272 ADVANCE(len
, ifaaddr
);
273 rtm
->rtm_addrs
|= RTA_IFP
| RTA_IFA
;
276 rtm
->rtm_addrs
&= ~(RTA_IFP
| RTA_IFA
);
279 if (len
> rtm
->rtm_msglen
) {
280 struct rt_msghdr
*new_rtm
;
281 R_Malloc(new_rtm
, struct rt_msghdr
*, len
);
284 Bcopy(rtm
, new_rtm
, rtm
->rtm_msglen
);
285 Free(rtm
); rtm
= new_rtm
;
287 rtm
->rtm_msglen
= len
;
288 rtm
->rtm_flags
= rt
->rt_flags
;
289 rtm
->rtm_rmx
= rt
->rt_rmx
;
290 cp
= (caddr_t
) (1 + rtm
);
291 len
= ROUNDUP(dst
->sa_len
);
292 Bcopy(dst
, cp
, len
); cp
+= len
;
294 len
= ROUNDUP(gate
->sa_len
);
295 Bcopy(gate
, cp
, len
); cp
+= len
;
298 len
= ROUNDUP(netmask
->sa_len
);
299 Bcopy(netmask
, cp
, len
); cp
+= len
;
302 len
= ROUNDUP(genmask
->sa_len
);
303 Bcopy(genmask
, cp
, len
); cp
+= len
;
306 len
= ROUNDUP(ifpaddr
->sa_len
);
307 Bcopy(ifpaddr
, cp
, len
); cp
+= len
;
308 len
= ROUNDUP(ifaaddr
->sa_len
);
309 Bcopy(ifaaddr
, cp
, len
); cp
+= len
;
315 (gate
->sa_len
> (len
= rt
->rt_gateway
->sa_len
)))
317 /* new gateway could require new ifaddr, ifp;
318 flags may also be different; ifp may be specified
319 by ll sockaddr when protocol address is ambiguous */
320 if (ifpaddr
&& (ifa
= ifa_ifwithnet(ifpaddr
)) &&
321 (ifp
= ifa
->ifa_ifp
))
322 ifa
= ifaof_ifpforaddr(ifaaddr
? ifaaddr
: gate
,
324 else if ((ifaaddr
&& (ifa
= ifa_ifwithaddr(ifaaddr
))) ||
325 (ifa
= ifa_ifwithroute(rt
->rt_flags
,
329 register struct ifaddr
*oifa
= rt
->rt_ifa
;
331 if (oifa
&& oifa
->ifa_rtrequest
)
332 oifa
->ifa_rtrequest(RTM_DELETE
,
339 Bcopy(gate
, rt
->rt_gateway
, len
);
340 rt_setmetrics(rtm
->rtm_inits
, &rtm
->rtm_rmx
,
342 if (rt
->rt_ifa
&& rt
->rt_ifa
->ifa_rtrequest
)
343 rt
->rt_ifa
->ifa_rtrequest(RTM_ADD
, rt
, gate
);
345 rt
->rt_genmask
= genmask
;
350 rt
->rt_rmx
.rmx_locks
|=
351 (rtm
->rtm_inits
& rtm
->rtm_rmx
.rmx_locks
);
352 rt
->rt_rmx
.rmx_locks
&= ~(rtm
->rtm_inits
);
364 rtm
->rtm_errno
= error
;
366 rtm
->rtm_flags
|= RTF_DONE
;
372 register struct rawcb
*rp
= 0;
374 * Check to see if we don't want our own messages.
376 if ((so
->so_options
& SO_USELOOPBACK
) == 0) {
377 if (route_cb
.any_count
<= 1) {
383 /* There is another listener, so construct message */
387 m_copyback(m
, 0, rtm
->rtm_msglen
, (caddr_t
)rtm
);
391 rp
->rcb_proto
.sp_family
= 0; /* Avoid us */
393 route_proto
.sp_protocol
= dst
->sa_family
;
394 raw_input(m
, &route_proto
, &route_src
, &route_dst
);
396 rp
->rcb_proto
.sp_family
= PF_ROUTE
;
403 rt_setmetrics(which
, in
, out
)
405 register struct rt_metrics
*in
, *out
;
407 #define metric(f, e) if (which & (f)) out->e = in->e;
408 metric(RTV_RPIPE
, rmx_recvpipe
);
409 metric(RTV_SPIPE
, rmx_sendpipe
);
410 metric(RTV_SSTHRESH
, rmx_ssthresh
);
411 metric(RTV_RTT
, rmx_rtt
);
412 metric(RTV_RTTVAR
, rmx_rttvar
);
413 metric(RTV_HOPCOUNT
, rmx_hopcount
);
414 metric(RTV_MTU
, rmx_mtu
);
415 metric(RTV_EXPIRE
, rmx_expire
);
420 * Copy data from a buffer back into the indicated mbuf chain,
421 * starting "off" bytes from the beginning, extending the mbuf
422 * chain if necessary.
425 m_copyback(m0
, off
, len
, cp
)
433 register struct mbuf
*m
= m0
, *n
;
438 while (off
> (mlen
= m
->m_len
)) {
441 if (m
->m_next
== 0) {
442 n
= m_getclr(M_DONTWAIT
, m
->m_type
);
445 n
->m_len
= MIN(MLEN
, len
+ off
);
451 mlen
= MIN(m
->m_len
- off
, len
);
452 bcopy(cp
, off
+ mtod(m
, caddr_t
), (unsigned)mlen
);
460 if (m
->m_next
== 0) {
461 n
= m_get(M_DONTWAIT
, m
->m_type
);
464 n
->m_len
= MIN(MLEN
, len
);
469 out
: if (((m
= m0
)->m_flags
& M_PKTHDR
) && (m
->m_pkthdr
.len
< totlen
))
470 m
->m_pkthdr
.len
= totlen
;
474 * The miss message and losing message are very similar.
478 rt_missmsg(type
, dst
, gate
, mask
, src
, flags
, error
)
480 register struct sockaddr
*dst
;
481 struct sockaddr
*gate
, *mask
, *src
;
485 register struct rt_msghdr
*rtm
;
486 register struct mbuf
*m
;
487 int dlen
= ROUNDUP(dst
->sa_len
);
488 int len
= dlen
+ sizeof(*rtm
);
490 struct proc
*curproc
= (struct proc
*)cthread_data(cthread_self());
492 if (route_cb
.any_count
== 0)
494 m
= m_gethdr(M_DONTWAIT
, MT_DATA
);
497 m
->m_pkthdr
.len
= m
->m_len
= MIN(len
, MHLEN
);
498 m
->m_pkthdr
.rcvif
= 0;
499 rtm
= mtod(m
, struct rt_msghdr
*);
500 aligned_bzero_const((caddr_t
)rtm
, sizeof(*rtm
)); /*XXX assumes sizeof(*rtm) < MHLEN*/
501 rtm
->rtm_flags
= RTF_DONE
| flags
;
502 rtm
->rtm_msglen
= len
;
503 rtm
->rtm_version
= RTM_VERSION
;
504 rtm
->rtm_type
= type
;
505 rtm
->rtm_addrs
= RTA_DST
;
506 if (type
== RTM_OLDADD
|| type
== RTM_OLDDEL
) {
507 rtm
->rtm_pid
= (pid_t
)FindTask(NULL
);
509 m_copyback(m
, sizeof (*rtm
), dlen
, (caddr_t
)dst
);
511 dlen
= ROUNDUP(gate
->sa_len
);
512 m_copyback(m
, len
, dlen
, (caddr_t
)gate
);
514 rtm
->rtm_addrs
|= RTA_GATEWAY
;
517 dlen
= ROUNDUP(mask
->sa_len
);
518 m_copyback(m
, len
, dlen
, (caddr_t
)mask
);
520 rtm
->rtm_addrs
|= RTA_NETMASK
;
523 dlen
= ROUNDUP(src
->sa_len
);
524 m_copyback(m
, len
, dlen
, (caddr_t
)src
);
526 rtm
->rtm_addrs
|= RTA_AUTHOR
;
528 if (m
->m_pkthdr
.len
!= len
) {
532 rtm
->rtm_errno
= error
;
533 rtm
->rtm_msglen
= len
;
534 route_proto
.sp_protocol
= dst
->sa_family
;
535 raw_input(m
, &route_proto
, &route_src
, &route_dst
);
539 #ifndef AMITCP /* this mechanism must be implemented differently */
540 #include <sys/kinfo.h>
543 int w_given
, w_needed
;
546 struct rt_msghdr m_rtm
;
549 #define w_rtm w_m.m_rtm
552 * This is used in dumping the kernel table via getkinfo().
555 struct radix_node
*rn
;
556 register struct walkarg
*w
;
558 register struct sockaddr
*sa
;
561 for (; rn
; rn
= rn
->rn_dupedkey
) {
562 int count
= 0, size
= sizeof(w
->w_rtm
);
563 register struct rtentry
*rt
= (struct rtentry
*)rn
;
565 if (rn
->rn_flags
& RNF_ROOT
)
567 if (w
->w_op
== KINFO_RT_FLAGS
&& !(rt
->rt_flags
& w
->w_arg
))
569 #define next(a, l) {size += (l); w->w_rtm.rtm_addrs |= (a); }
570 w
->w_rtm
.rtm_addrs
= 0;
572 next(RTA_DST
, ROUNDUP(sa
->sa_len
));
573 if (sa
= rt
->rt_gateway
)
574 next(RTA_GATEWAY
, ROUNDUP(sa
->sa_len
));
575 if (sa
= rt_mask(rt
))
576 next(RTA_NETMASK
, ROUNDUP(sa
->sa_len
));
577 if (sa
= rt
->rt_genmask
)
578 next(RTA_GENMASK
, ROUNDUP(sa
->sa_len
));
580 if (w
->w_where
== NULL
|| w
->w_needed
> 0)
582 w
->w_rtm
.rtm_msglen
= size
;
583 w
->w_rtm
.rtm_flags
= rt
->rt_flags
;
584 w
->w_rtm
.rtm_use
= rt
->rt_use
;
585 w
->w_rtm
.rtm_rmx
= rt
->rt_rmx
;
586 w
->w_rtm
.rtm_index
= rt
->rt_ifp
->if_index
;
588 #define next(l) {n = (l); Bcopy(sa, cp, n); cp += n;}
589 if (size
<= sizeof(w
->w_m
)) {
590 register caddr_t cp
= (caddr_t
)(w
->w_m
.m_sabuf
);
592 next(ROUNDUP(sa
->sa_len
));
593 if (sa
= rt
->rt_gateway
)
594 next(ROUNDUP(sa
->sa_len
));
595 if (sa
= rt_mask(rt
))
596 next(ROUNDUP(sa
->sa_len
));
597 if (sa
= rt
->rt_genmask
)
598 next(ROUNDUP(sa
->sa_len
));
600 #define next(s, l) {n = (l); \
601 if (error = copyout((caddr_t)(s), w->w_where, n)) return (error); \
604 next(&w
->w_m
, size
); /* Copy rtmsg and sockaddrs back */
607 next(&w
->w_rtm
, sizeof(w
->w_rtm
));
609 next(sa
, ROUNDUP(sa
->sa_len
));
610 if (sa
= rt
->rt_gateway
)
611 next(sa
, ROUNDUP(sa
->sa_len
));
612 if (sa
= rt_mask(rt
))
613 next(sa
, ROUNDUP(sa
->sa_len
));
614 if (sa
= rt
->rt_genmask
)
615 next(sa
, ROUNDUP(sa
->sa_len
));
621 kinfo_rtable(op
, where
, given
, arg
, needed
)
626 register struct radix_node_head
*rnh
;
629 u_char af
= ki_af(op
);
633 if (op
!= KINFO_RT_DUMP
&& op
!= KINFO_RT_FLAGS
)
636 Bzero(&w
, sizeof(w
));
637 if ((w
.w_where
= where
) && given
)
639 w
.w_needed
= 0 - w
.w_given
;
642 w
.w_rtm
.rtm_version
= RTM_VERSION
;
643 w
.w_rtm
.rtm_type
= RTM_GET
;
646 for (rnh
= radix_node_head
; rnh
; rnh
= rnh
->rnh_next
) {
647 if (rnh
->rnh_af
== 0)
649 if (af
&& af
!= rnh
->rnh_af
)
651 error
= rt_walk(rnh
->rnh_treetop
, rt_dumpentry
, &w
);
655 w
.w_needed
+= w
.w_given
;
657 *given
= w
.w_where
- where
;
659 w
.w_needed
= (11 * w
.w_needed
) / 10;
660 *needed
= w
.w_needed
;
668 register struct radix_node
*rn
;
669 register int (*f
)(struct radix_node
*, struct walkarg
*);
674 while (rn
->rn_b
>= 0)
675 rn
= rn
->rn_l
; /* First time through node, go left */
676 if (error
= (*f
)(rn
, w
))
677 return (error
); /* Process Leaf */
678 while (rn
->rn_p
->rn_r
== rn
) { /* if coming back from right */
679 rn
= rn
->rn_p
; /* go back up */
680 if (rn
->rn_flags
& RNF_ROOT
)
683 rn
= rn
->rn_p
->rn_r
; /* otherwise, go right*/
688 * Definitions of protocols supported in the ROUTE domain.
692 * Actually, we are only initializing the raw control blocks...
694 #define route_output NULL
695 #define route_usrreq NULL
697 int raw_init(),raw_usrreq(),raw_input(),raw_ctlinput();
699 extern struct domain routedomain
; /* or at least forward */
701 struct protosw routesw
[] = {
702 { SOCK_RAW
, &routedomain
, 0, PR_ATOMIC
|PR_ADDR
,
703 (void (*)(APTR args
, ...))raw_input
, route_output
, (APTR
)raw_ctlinput
, 0,
709 int unp_externalize(), unp_dispose();
711 struct domain routedomain
=
712 { PF_ROUTE
, "route", NULL
, NULL
, NULL
,
713 routesw
, &routesw
[sizeof(routesw
)/sizeof(routesw
[0])], NULL
};