* Copyright (c) 1988 Regents of the University of California.
* %sccs.include.redist.c%
* @(#)rtsock.c 7.13 (Berkeley) %G%
#include "machine/mtpr.h"
struct sockaddr route_dst
= { 2, PF_ROUTE
, };
struct sockaddr route_src
= { 2, PF_ROUTE
, };
struct sockproto route_proto
= { PF_ROUTE
, };
route_usrreq(so
, req
, m
, nam
, control
)
register struct socket
*so
;
struct mbuf
*m
, *nam
, *control
;
register struct rawcb
*rp
= sotorawcb(so
);
MALLOC(rp
, struct rawcb
*, sizeof(*rp
), M_PCB
, M_WAITOK
);
if (so
->so_pcb
= (caddr_t
)rp
)
bzero(so
->so_pcb
, sizeof(*rp
));
if (req
== PRU_DETACH
&& rp
) {
int af
= rp
->rcb_proto
.sp_protocol
;
error
= raw_usrreq(so
, req
, m
, nam
, control
);
if (req
== PRU_ATTACH
&& rp
) {
int af
= rp
->rcb_proto
.sp_protocol
;
free((caddr_t
)rp
, M_PCB
);
rp
->rcb_faddr
= &route_src
;
so
->so_options
|= SO_USELOOPBACK
;
#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
register struct rt_msghdr
*rtm
= 0;
register struct rtentry
*rt
= 0;
struct rtentry
*saved_nrt
= 0;
struct sockaddr
*dst
= 0, *gate
= 0, *netmask
= 0, *genmask
= 0;
struct sockaddr
*ifpaddr
= 0;
extern struct ifaddr
*ifaof_ifpforaddr(), *ifa_ifwithroute();
#define senderr(e) { error = e; goto flush;}
if (m
== 0 || m
->m_len
< sizeof(long))
if ((m
= m_pullup(m
, sizeof(long))) == 0)
if ((m
->m_flags
& M_PKTHDR
) == 0)
if (len
< sizeof(*rtm
) ||
len
!= mtod(m
, struct rt_msghdr
*)->rtm_msglen
)
R_Malloc(rtm
, struct rt_msghdr
*, len
);
m_copydata(m
, 0, len
, (caddr_t
)rtm
);
if (rtm
->rtm_version
!= RTM_VERSION
)
senderr(EPROTONOSUPPORT
);
rtm
->rtm_pid
= u
.u_procp
->p_pid
;
lim
= len
+ (caddr_t
) rtm
;
cp
= (caddr_t
) (rtm
+ 1);
if (rtm
->rtm_addrs
& RTA_DST
) {
dst
= (struct sockaddr
*)cp
;
cp
+= ROUNDUP(dst
->sa_len
);
if ((rtm
->rtm_addrs
& RTA_GATEWAY
) && cp
< lim
) {
gate
= (struct sockaddr
*)cp
;
cp
+= ROUNDUP(gate
->sa_len
);
if ((rtm
->rtm_addrs
& RTA_NETMASK
) && cp
< lim
) {
netmask
= (struct sockaddr
*)cp
;
cp
+= ROUNDUP(netmask
->sa_len
);
if ((rtm
->rtm_addrs
& RTA_GENMASK
) && cp
< lim
) {
struct radix_node
*t
, *rn_addmask();
genmask
= (struct sockaddr
*)cp
;
cp
+= ROUNDUP(netmask
->sa_len
);
t
= rn_addmask(genmask
, 1, 2);
if (t
&& Bcmp(genmask
, t
->rn_key
, *(u_char
*)genmask
) == 0)
genmask
= (struct sockaddr
*)(t
->rn_key
);
if ((rtm
->rtm_addrs
& RTA_IFP
) && cp
< lim
) {
ifpaddr
= (struct sockaddr
*)cp
;
error
= rtrequest(RTM_ADD
, dst
, gate
, netmask
,
rtm
->rtm_flags
, &saved_nrt
);
if (error
== 0 && saved_nrt
) {
rt_setmetrics(rtm
->rtm_inits
,
&rtm
->rtm_rmx
, &saved_nrt
->rt_rmx
);
saved_nrt
->rt_genmask
= genmask
;
error
= rtrequest(RTM_DELETE
, dst
, gate
, netmask
,
rtm
->rtm_flags
, (struct rtentry
**)0);
struct sockaddr
*outmask
;
len
= sizeof(*rtm
) + ROUNDUP(rt_key(rt
)->sa_len
);
rtm
->rtm_addrs
= RTA_DST
;
len
+= ROUNDUP(rt
->rt_gateway
->sa_len
);
rtm
->rtm_addrs
|= RTA_GATEWAY
;
rtm
->rtm_addrs
|= RTA_NETMASK
;
if (len
> rtm
->rtm_msglen
) {
struct rt_msghdr
*new_rtm
;
R_Malloc(new_rtm
, struct rt_msghdr
*, len
);
Bcopy(rtm
, new_rtm
, rtm
->rtm_msglen
);
Free(rtm
); rtm
= new_rtm
;
gate
= (struct sockaddr
*)
(ROUNDUP(rt
->rt_gateway
->sa_len
)
Bcopy(&rt
->rt_gateway
, gate
,
rtm
->rtm_flags
= rt
->rt_flags
;
outmask
= (struct sockaddr
*)
(ROUNDUP(netmask
->sa_len
)+(char *)gate
);
Bcopy(netmask
, outmask
, netmask
->sa_len
);
if (gate
== 0 || netmask
!= 0)
if (gate
->sa_len
> (len
= rt
->rt_gateway
->sa_len
))
if (rt
->rt_ifa
&& rt
->rt_ifa
->ifa_rtrequest
)
rt
->rt_ifa
->ifa_rtrequest(RTM_DELETE
, rt
, gate
);
/* new gateway could require new ifaddr, ifp;
flags may also be different; ifp may be specified
by ll sockaddr when protocol address is ambiguous */
(ifa
= ifa_ifwithnet(ifpaddr
)) &&
(ifa
= ifaof_ifpforaddr(gate
, ifp
))) {
Bcopy(gate
, rt
->rt_gateway
, len
);
rt
->rt_gateway
->sa_len
= len
;
rt_setmetrics(rtm
->rtm_inits
,
&rtm
->rtm_rmx
, &rt
->rt_rmx
);
ifa
= ifa_ifwithroute(rt
->rt_flags
, rt_key(rt
),
rt
->rt_ifp
= ifa
->ifa_ifp
;
if (rt
->rt_ifa
&& rt
->rt_ifa
->ifa_rtrequest
)
rt
->rt_ifa
->ifa_rtrequest(RTM_ADD
, rt
, gate
);
rt
->rt_genmask
= genmask
;
(rtm
->rtm_inits
& rtm
->rtm_rmx
.rmx_locks
);
rt
->rt_rmx
.rmx_locks
&= ~(rtm
->rtm_inits
);
rtm
->rtm_flags
|= RTF_DONE
;
register struct rawcb
*rp
= 0;
* Check to see if we don't want our own messages.
if ((so
->so_options
& SO_USELOOPBACK
) == 0) {
if (route_cb
.any_count
<= 1) {
/* There is another listener, so construct message */
m_copyback(m
, 0, len
, cp
);
rp
->rcb_proto
.sp_family
= 0; /* Avoid us */
route_proto
.sp_protocol
= dst
->sa_family
;
raw_input(m
, &route_proto
, &route_src
, &route_dst
);
rp
->rcb_proto
.sp_family
= PF_ROUTE
;
rt_setmetrics(which
, in
, out
)
register struct rt_metrics
*in
, *out
;
#define metric(f, e) if (which & (f)) out->e = in->e;
metric(RTV_RPIPE
, rmx_recvpipe
);
metric(RTV_SPIPE
, rmx_sendpipe
);
metric(RTV_SSTHRESH
, rmx_ssthresh
);
metric(RTV_RTT
, rmx_rtt
);
metric(RTV_RTTVAR
, rmx_rttvar
);
metric(RTV_HOPCOUNT
, rmx_hopcount
);
metric(RTV_MTU
, rmx_mtu
);
* Copy data from a buffer back into the indicated mbuf chain,
* starting "off" bytes from the beginning, extending the mbuf
m_copyback(m0
, off
, len
, cp
)
register struct mbuf
*m
= m0
, *n
;
while (off
>= (mlen
= m
->m_len
)) {
n
= m_getclr(M_DONTWAIT
, m
->m_type
);
n
->m_len
= min(MLEN
, len
+ off
);
mlen
= min (m
->m_len
- off
, len
);
bcopy(cp
, off
+ mtod(m
, caddr_t
), (unsigned)mlen
);
n
= m_get(M_DONTWAIT
, m
->m_type
);
n
->m_len
= min(MLEN
, len
);
out
: if (((m
= m0
)->m_flags
& M_PKTHDR
) && (m
->m_pkthdr
.len
< totlen
))
m
->m_pkthdr
.len
= totlen
;
* The miss message and losing message are very similar.
rt_missmsg(type
, dst
, gate
, mask
, src
, flags
, error
)
register struct sockaddr
*dst
;
struct sockaddr
*gate
, *mask
, *src
;
register struct rt_msghdr
*rtm
;
int dlen
= ROUNDUP(dst
->sa_len
);
int len
= dlen
+ sizeof(*rtm
);
if (route_cb
.any_count
== 0)
m
= m_gethdr(M_DONTWAIT
, MT_DATA
);
m
->m_pkthdr
.len
= m
->m_len
= min(len
, MHLEN
);
rtm
= mtod(m
, struct rt_msghdr
*);
bzero((caddr_t
)rtm
, sizeof(*rtm
)); /*XXX assumes sizeof(*rtm) < MHLEN*/
rtm
->rtm_flags
= RTF_DONE
| flags
;
rtm
->rtm_version
= RTM_VERSION
;
rtm
->rtm_addrs
= RTA_DST
;
if (type
== RTM_OLDADD
|| type
== RTM_OLDDEL
) {
rtm
->rtm_pid
= u
.u_procp
->p_pid
;
m_copyback(m
, sizeof (*rtm
), dlen
, (caddr_t
)dst
);
dlen
= ROUNDUP(gate
->sa_len
);
m_copyback(m
, len
, dlen
, (caddr_t
)gate
);
rtm
->rtm_addrs
|= RTA_GATEWAY
;
dlen
= ROUNDUP(mask
->sa_len
);
m_copyback(m
, len
, dlen
, (caddr_t
)mask
);
rtm
->rtm_addrs
|= RTA_NETMASK
;
dlen
= ROUNDUP(src
->sa_len
);
m_copyback(m
, len
, dlen
, (caddr_t
)src
);
rtm
->rtm_addrs
|= RTA_AUTHOR
;
if (m
->m_pkthdr
.len
!= len
) {
route_proto
.sp_protocol
= dst
->sa_family
;
raw_input(m
, &route_proto
, &route_src
, &route_dst
);
* This is used in dumping the kernel table via getkinfo().
register struct walkarg
*w
;
register struct sockaddr
*sa
;
for (; rn
; rn
= rn
->rn_dupedkey
) {
int count
= 0, size
= sizeof(w
->w_rtm
);
register struct rtentry
*rt
= (struct rtentry
*)rn
;
if (rn
->rn_flags
& RNF_ROOT
)
if (w
->w_op
== KINFO_RT_FLAGS
&& !(rt
->rt_flags
& w
->w_arg
))
#define next(a, l) {size += (l); w->w_rtm.rtm_addrs |= (a); }
next(RTA_DST
, ROUNDUP(sa
->sa_len
));
next(RTA_GATEWAY
, ROUNDUP(sa
->sa_len
));
sa
->sa_len
? ROUNDUP(sa
->sa_len
) : sizeof(long));
next(RTA_GENMASK
, ROUNDUP(sa
->sa_len
));
if (w
->w_where
== NULL
|| w
->w_needed
> 0)
w
->w_rtm
.rtm_msglen
= size
;
w
->w_rtm
.rtm_flags
= rt
->rt_flags
;
w
->w_rtm
.rtm_use
= rt
->rt_use
;
w
->w_rtm
.rtm_rmx
= rt
->rt_rmx
;
w
->w_rtm
.rtm_index
= rt
->rt_ifp
->if_index
;
#define next(l) {n = (l); Bcopy(sa, cp, n); cp += n;}
if (size
<= sizeof(w
->w_m
)) {
register caddr_t cp
= (caddr_t
)(w
->w_m
.m_sabuf
);
next(ROUNDUP(sa
->sa_len
));
next(ROUNDUP(sa
->sa_len
));
next(sa
->sa_len
? ROUNDUP(sa
->sa_len
) : sizeof(long));
next(ROUNDUP(sa
->sa_len
));
#define next(s, l) {n = (l); \
if (error = copyout((caddr_t)(s), w->w_where, n)) return (error); \
next(&w
->w_m
, size
); /* Copy rtmsg and sockaddrs back */
next(&w
->w_rtm
, sizeof(w
->w_rtm
));
next(sa
, ROUNDUP(sa
->sa_len
));
next(sa
, ROUNDUP(sa
->sa_len
));
next(sa
, sa
->sa_len
? ROUNDUP(sa
->sa_len
) : sizeof(long));
next(sa
, ROUNDUP(sa
->sa_len
));
kinfo_rtable(op
, where
, given
, arg
, needed
)
register struct radix_node_head
*rnh
;
if (op
!= KINFO_RT_DUMP
&& op
!= KINFO_RT_FLAGS
)
if ((w
.w_where
= where
) && given
)
w
.w_needed
= 0 - w
.w_given
;
w
.w_rtm
.rtm_version
= RTM_VERSION
;
w
.w_rtm
.rtm_type
= RTM_GET
;
for (rnh
= radix_node_head
; rnh
; rnh
= rnh
->rnh_next
) {
if (af
&& af
!= rnh
->rnh_af
)
error
= rt_walk(rnh
->rnh_treetop
, rt_dumpentry
, &w
);
*given
= w
.w_where
- where
;
w
.w_needed
= (11 * w
.w_needed
) / 10;
register struct radix_node
*rn
;
rn
= rn
->rn_l
; /* First time through node, go left */
return (error
); /* Process Leaf */
while (rn
->rn_p
->rn_r
== rn
) { /* if coming back from right */
rn
= rn
->rn_p
; /* go back up */
if (rn
->rn_flags
& RNF_ROOT
)
rn
= rn
->rn_p
->rn_r
; /* otherwise, go right*/
* Definitions of protocols supported in the ROUTE domain.
int raw_init(),raw_usrreq(),raw_input(),raw_ctlinput();
extern struct domain routedomain
; /* or at least forward */
struct protosw routesw
[] = {
{ SOCK_RAW
, &routedomain
, 0, PR_ATOMIC
|PR_ADDR
,
raw_input
, route_output
, raw_ctlinput
, 0,
int unp_externalize(), unp_dispose();
struct domain routedomain
=
{ PF_ROUTE
, "route", 0, 0, 0,
routesw
, &routesw
[sizeof(routesw
)/sizeof(routesw
[0])] };