* Copyright (c) 1988, 1991 Regents of the University of California.
* %sccs.include.redist.c%
* @(#)rtsock.c 7.32 (Berkeley) %G%
#include <sys/socketvar.h>
struct sockaddr route_dst
= { 2, PF_ROUTE
, };
struct sockaddr route_src
= { 2, PF_ROUTE
, };
struct sockproto route_proto
= { PF_ROUTE
, };
int w_op
, w_arg
, w_given
, w_needed
, w_tmemsize
;
static void rt_xaddrs
__P((caddr_t
, caddr_t
, struct rt_addrinfo
*));
static struct mbuf
*rt_msg1
__P((int, struct rt_addrinfo
*));
static int rt_msg2
__P((int, struct rt_addrinfo
*, caddr_t
,
/* Sleazy use of local variables throughout file, warning!!!! */
#define dst info.rti_info[RTAX_DST]
#define gate info.rti_info[RTAX_GATEWAY]
#define netmask info.rti_info[RTAX_NETMASK]
#define genmask info.rti_info[RTAX_GENMASK]
#define ifpaddr info.rti_info[RTAX_IFP]
#define ifaaddr info.rti_info[RTAX_IFA]
#define brdaddr info.rti_info[RTAX_BRD]
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
;
register struct rt_msghdr
*rtm
= 0;
register struct rtentry
*rt
= 0;
struct rtentry
*saved_nrt
= 0;
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
= curproc
->p_pid
;
info
.rti_addrs
= rtm
->rtm_addrs
;
rt_xaddrs((caddr_t
)(rtm
+ 1), len
+ (caddr_t
)rtm
, &info
);
struct radix_node
*t
, *rn_addmask();
t
= rn_addmask(genmask
, 1, 2);
if (t
&& Bcmp(genmask
, t
->rn_key
, *(u_char
*)genmask
) == 0)
genmask
= (struct sockaddr
*)(t
->rn_key
);
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);
if (rtm
->rtm_type
!= RTM_GET
) {/* XXX: too grotty */
struct radix_node
*rn
, *rn_search();
extern struct radix_node_head
*mask_rnhead
;
if (Bcmp(dst
, rt_key(rt
), dst
->sa_len
) != 0)
if (netmask
&& (rn
= rn_search(netmask
,
mask_rnhead
->rnh_treetop
)))
netmask
= (struct sockaddr
*)rn
->rn_key
;
for (rn
= rt
->rt_nodes
; rn
; rn
= rn
->rn_dupedkey
)
if (netmask
== (struct sockaddr
*)rn
->rn_mask
)
rt
= (struct rtentry
*)rn
;
genmask
= rt
->rt_genmask
;
if (rtm
->rtm_addrs
& (RTA_IFP
| RTA_IFA
)) {
ifpaddr
= ifp
->if_addrlist
->ifa_addr
;
ifaaddr
= rt
->rt_ifa
->ifa_addr
;
rtm
->rtm_index
= ifp
->if_index
;
len
= rt_msg2(RTM_GET
, &info
, (caddr_t
)0,
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
;
(void)rt_msg2(RTM_GET
, &info
, (caddr_t
)rtm
,
rtm
->rtm_flags
= rt
->rt_flags
;
rtm
->rtm_rmx
= rt
->rt_rmx
;
if (gate
&& rt_setgate(rt
, rt_key(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 */
if (ifpaddr
&& (ifa
= ifa_ifwithnet(ifpaddr
)) &&
ifa
= ifaof_ifpforaddr(ifaaddr
? ifaaddr
: gate
,
else if ((ifaaddr
&& (ifa
= ifa_ifwithaddr(ifaaddr
))) ||
(ifa
= ifa_ifwithroute(rt
->rt_flags
,
register struct ifaddr
*oifa
= rt
->rt_ifa
;
if (oifa
&& oifa
->ifa_rtrequest
)
oifa
->ifa_rtrequest(RTM_DELETE
,
rt_setmetrics(rtm
->rtm_inits
, &rtm
->rtm_rmx
,
if (rt
->rt_ifa
&& rt
->rt_ifa
->ifa_rtrequest
)
rt
->rt_ifa
->ifa_rtrequest(RTM_ADD
, rt
, gate
);
rt
->rt_genmask
= genmask
;
rt
->rt_rmx
.rmx_locks
&= ~(rtm
->rtm_inits
);
(rtm
->rtm_inits
& rtm
->rtm_rmx
.rmx_locks
);
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, rtm
->rtm_msglen
, (caddr_t
)rtm
);
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
);
metric(RTV_EXPIRE
, rmx_expire
);
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
rt_xaddrs(cp
, cplim
, rtinfo
)
register caddr_t cp
, cplim
;
register struct rt_addrinfo
*rtinfo
;
register struct sockaddr
*sa
;
bzero(rtinfo
->rti_info
, sizeof(rtinfo
->rti_info
));
for (i
= 0; (i
< RTAX_MAX
) && (cp
< cplim
); i
++) {
if ((rtinfo
->rti_addrs
& (1 << i
)) == 0)
rtinfo
->rti_info
[i
] = sa
= (struct sockaddr
*)cp
;
* 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
;
register struct rt_addrinfo
*rtinfo
;
register struct rt_msghdr
*rtm
;
register struct sockaddr
*sa
;
m
= m_gethdr(M_DONTWAIT
, MT_DATA
);
len
= sizeof(struct ifa_msghdr
);
len
= sizeof(struct if_msghdr
);
len
= sizeof(struct rt_msghdr
);
m
->m_pkthdr
.len
= m
->m_len
= len
;
rtm
= mtod(m
, struct rt_msghdr
*);
bzero((caddr_t
)rtm
, len
);
for (i
= 0; i
< RTAX_MAX
; i
++) {
if ((sa
= rtinfo
->rti_info
[i
]) == NULL
)
rtinfo
->rti_addrs
|= (1 << i
);
dlen
= ROUNDUP(sa
->sa_len
);
m_copyback(m
, len
, dlen
, (caddr_t
)sa
);
if (m
->m_pkthdr
.len
!= len
) {
rtm
->rtm_version
= RTM_VERSION
;
rt_msg2(type
, rtinfo
, cp
, w
)
register struct rt_addrinfo
*rtinfo
;
int len
, dlen
, second_time
= 0;
len
= sizeof(struct ifa_msghdr
);
len
= sizeof(struct if_msghdr
);
len
= sizeof(struct rt_msghdr
);
for (i
= 0; i
< RTAX_MAX
; i
++) {
register struct sockaddr
*sa
;
if ((sa
= rtinfo
->rti_info
[i
]) == 0)
rtinfo
->rti_addrs
|= (1 << i
);
dlen
= ROUNDUP(sa
->sa_len
);
bcopy((caddr_t
)sa
, cp
, (unsigned)dlen
);
if (cp
== 0 && w
!= NULL
&& !second_time
) {
register struct walkarg
*rw
= w
;
if (rw
->w_needed
<= 0 && rw
->w_where
) {
if (rw
->w_tmemsize
< len
) {
free(rw
->w_tmem
, M_RTABLE
);
if (rw
->w_tmem
= (caddr_t
)
malloc(len
, M_RTABLE
, M_NOWAIT
))
register struct rt_msghdr
*rtm
= (struct rt_msghdr
*)cp0
;
rtm
->rtm_version
= RTM_VERSION
;
* This routine is called to generate a message from the routing
* socket indicating that a redirect has occured, a routing lookup
* has failed, or that a protocol has detected timeouts to a particular
rt_missmsg(type
, rtinfo
, flags
, error
)
register struct rt_addrinfo
*rtinfo
;
register struct rt_msghdr
*rtm
;
struct sockaddr
*sa
= rtinfo
->rti_info
[RTAX_DST
];
if (route_cb
.any_count
== 0)
m
= rt_msg1(type
, rtinfo
);
rtm
= mtod(m
, struct rt_msghdr
*);
rtm
->rtm_flags
= RTF_DONE
| flags
;
rtm
->rtm_addrs
= rtinfo
->rti_addrs
;
route_proto
.sp_protocol
= sa
? sa
->sa_family
: 0;
raw_input(m
, &route_proto
, &route_src
, &route_dst
);
* This routine is called to generate a message from the routing
* socket indicating that the status of a network interface has changed.
register struct ifnet
*ifp
;
register struct if_msghdr
*ifm
;
if (route_cb
.any_count
== 0)
bzero((caddr_t
)&info
, sizeof(info
));
m
= rt_msg1(RTM_IFINFO
, &info
);
ifm
= mtod(m
, struct if_msghdr
*);
ifm
->ifm_index
= ifp
->if_index
;
ifm
->ifm_flags
= ifp
->if_flags
;
ifm
->ifm_data
= ifp
->if_data
;
route_proto
.sp_protocol
= 0;
raw_input(m
, &route_proto
, &route_src
, &route_dst
);
* This is called to generate messages from the routing socket
* indicating a network interface has had addresses associated with it.
* if we ever reverse the logic and replace messages TO the routing
* socket indicate a request to configure interfaces, then it will
* be unnecessary as the routing socket will automatically generate
rt_newaddrmsg(cmd
, ifa
, error
, rt
)
register struct ifaddr
*ifa
;
register struct rtentry
*rt
;
struct ifnet
*ifp
= ifa
->ifa_ifp
;
if (route_cb
.any_count
== 0)
for (pass
= 1; pass
< 3; pass
++) {
bzero((caddr_t
)&info
, sizeof(info
));
if ((cmd
== RTM_ADD
&& pass
== 1) ||
(cmd
== RTM_DELETE
&& pass
== 2)) {
register struct ifa_msghdr
*ifam
;
int ncmd
= cmd
== RTM_ADD
? RTM_NEWADDR
: RTM_DELADDR
;
ifaaddr
= sa
= ifa
->ifa_addr
;
ifpaddr
= ifp
->if_addrlist
->ifa_addr
;
netmask
= ifa
->ifa_netmask
;
brdaddr
= ifa
->ifa_dstaddr
;
if ((m
= rt_msg1(ncmd
, &info
)) == NULL
)
ifam
= mtod(m
, struct ifa_msghdr
*);
ifam
->ifam_index
= ifp
->if_index
;
ifam
->ifam_metric
= ifa
->ifa_metric
;
ifam
->ifam_flags
= ifa
->ifa_flags
;
ifam
->ifam_addrs
= info
.rti_addrs
;
if ((cmd
== RTM_ADD
&& pass
== 2) ||
(cmd
== RTM_DELETE
&& pass
== 1)) {
register struct rt_msghdr
*rtm
;
if ((m
= rt_msg1(cmd
, &info
)) == NULL
)
rtm
= mtod(m
, struct rt_msghdr
*);
rtm
->rtm_index
= ifp
->if_index
;
rtm
->rtm_flags
|= rt
->rt_flags
;
rtm
->rtm_addrs
= info
.rti_addrs
;
route_proto
.sp_protocol
= sa
? sa
->sa_family
: 0;
raw_input(m
, &route_proto
, &route_src
, &route_dst
);
* This is used in dumping the kernel table via sysctl().
register struct walkarg
*w
;
register struct sockaddr
*sa
;
register struct rtentry
*rt
= (struct rtentry
*)rn
;
if (w
->w_op
== NET_RT_FLAGS
&& !(rt
->rt_flags
& w
->w_arg
))
bzero((caddr_t
)&info
, sizeof(info
));
genmask
= rt
->rt_genmask
;
size
= rt_msg2(RTM_GET
, &info
, 0, w
);
if (w
->w_where
&& w
->w_tmem
) {
register struct rt_msghdr
*rtm
= (struct rt_msghdr
*)w
->w_tmem
;
rtm
->rtm_flags
= rt
->rt_flags
;
rtm
->rtm_use
= rt
->rt_use
;
rtm
->rtm_rmx
= rt
->rt_rmx
;
rtm
->rtm_index
= rt
->rt_ifp
->if_index
;
rtm
->rtm_errno
= rtm
->rtm_pid
= rtm
->rtm_seq
= 0;
rtm
->rtm_addrs
= info
.rti_addrs
;
if (error
= copyout((caddr_t
)rtm
, w
->w_where
, size
))
register struct walkarg
*w
;
register struct ifnet
*ifp
;
register struct ifaddr
*ifa
;
bzero((caddr_t
)&info
, sizeof(info
));
for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
) {
if (w
->w_arg
&& w
->w_arg
!= ifp
->if_index
)
len
= rt_msg2(RTM_IFINFO
, &info
, (caddr_t
)0, w
);
if (w
->w_where
&& w
->w_tmem
) {
register struct if_msghdr
*ifm
;
ifm
= (struct if_msghdr
*)w
->w_tmem
;
ifm
->ifm_index
= ifp
->if_index
;
ifm
->ifm_flags
= ifp
->if_flags
;
ifm
->ifm_data
= ifp
->if_data
;
ifm
->ifm_addrs
= info
.rti_addrs
;
if (error
= copyout((caddr_t
)ifm
, w
->w_where
, len
))
while (ifa
= ifa
->ifa_next
) {
if (af
&& af
!= ifa
->ifa_addr
->sa_family
)
netmask
= ifa
->ifa_netmask
;
brdaddr
= ifa
->ifa_dstaddr
;
len
= rt_msg2(RTM_NEWADDR
, &info
, 0, w
);
if (w
->w_where
&& w
->w_tmem
) {
register struct ifa_msghdr
*ifam
;
ifam
= (struct ifa_msghdr
*)w
->w_tmem
;
ifam
->ifam_index
= ifa
->ifa_ifp
->if_index
;
ifam
->ifam_flags
= ifa
->ifa_flags
;
ifam
->ifam_metric
= ifa
->ifa_metric
;
ifam
->ifam_addrs
= info
.rti_addrs
;
if (error
= copyout(w
->w_tmem
, w
->w_where
, len
))
ifaaddr
= netmask
= brdaddr
= 0;
sysctl_rtable(name
, namelen
, where
, given
, new, newlen
)
register struct radix_node_head
*rnh
;
int i
, s
, error
= EINVAL
;
w
.w_needed
= 0 - w
.w_given
;
for (i
= 1; i
<= AF_MAX
; i
++)
if ((rnh
= rt_tables
[i
]) && (af
== 0 || af
== i
) &&
(error
= rnh
->rnh_walk(rnh
->rnh_treetop
,
error
= sysctl_iflist(af
, &w
);
free(w
.w_tmem
, M_RTABLE
);
*given
= w
.w_where
- where
;
*given
= (11 * w
.w_needed
) / 10;
* Definitions of protocols supported in the ROUTE domain.
int raw_init(),raw_usrreq(),raw_input(),raw_ctlinput(), route_init();
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", route_init
, 0, 0,
routesw
, &routesw
[sizeof(routesw
)/sizeof(routesw
[0])] };