* Copyright (c) 1988 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)rtsock.c 7.3 (Berkeley) %G%
#include "machine/mtpr.h"
struct sockaddr route_dst
= { 0, PF_ROUTE
, };
struct sockaddr route_src
= { 0, PF_ROUTE
, };
struct sockproto route_proto
= { PF_ROUTE
, };
route_usrreq(so
, req
, m
, nam
, rights
, control
)
register struct socket
*so
;
struct mbuf
*m
, *nam
, *rights
, *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
, rights
, control
);
if (req
== PRU_ATTACH
&& rp
) {
int af
= rp
->rcb_proto
.sp_protocol
;
free((caddr_t
)rp
, M_PCB
);
rp
->rcb_faddr
= &route_src
;
#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
register struct rt_msghdr
*rtm
= 0;
register struct rtentry
*rt
= 0;
struct rtentry
*saved_nrt
;
struct sockaddr
*dst
= 0, *gate
= 0, *netmask
= 0, *author
;
struct rt_metrics
*rmm
= 0;
#define FLUSH(e) { error = e; goto flush;}
if (m
== 0 || (m
= m_pullup(m
, sizeof(long))) == 0)
if ((m
->m_flags
& M_PKTHDR
) == 0)
rtm
= mtod(m
, struct rt_msghdr
*);
if (len
< rtm
->rtm_msglen
)
R_Malloc(rtm
, struct rt_msghdr
*, len
);
m_copydata(m
, 0, len
, (caddr_t
)rtm
);
if (rtm
->rtm_version
!= 1)
rtm
->rtm_pid
= u
.u_procp
->p_pid
;
cp
= (caddr_t
) (rtm
+ 1);
case RTM_ADD
: case RTM_CHANGE
: case RTM_GET
:
rmm
= (struct rt_metrics
*)cp
;
cp
= (caddr_t
) (rmm
+ 1);
if (rtm
->rtm_count
> 0) {
dst
= (struct sockaddr
*)cp
;
cp
+= ROUNDUP(dst
->sa_len
);
if (rtm
->rtm_count
> 1) {
gate
= (struct sockaddr
*)cp
;
cp
+= ROUNDUP(gate
->sa_len
);
if (rtm
->rtm_count
> 2) {
netmask
= (struct sockaddr
*)cp
;
cp
+= ROUNDUP(netmask
->sa_len
);
if (rtm
->rtm_count
> 3) {
author
= (struct sockaddr
*)cp
;
error
= rtrequest(RTM_ADD
, dst
, gate
, netmask
,
rtm
->rtm_flags
, &saved_nrt
);
/* XXX -- add metrics !!! */
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
)
+ ROUNDUP(rt
->rt_gateway
->sa_len
);
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
->sa_len
> (len
= rt
->rt_gateway
->sa_len
))
if (gate
->sa_family
!= rt
->rt_gateway
->sa_family
)
Bcopy(gate
, rt
->rt_gateway
, len
);
rt
->rt_gateway
->sa_len
= len
;
#define metric(f, e) if (rtm->rtm_inits & (f)) rt->rt_m.e = rtm->e;
metric(RTM_RPIPE
, rtm_recvpipe
);
metric(RTM_SPIPE
, rtm_sendpipe
);
metric(RTM_SSTHRESH
, rtm_ssthresh
);
metric(RTM_RTT
, rtm_rtt
);
metric(RTM_RTTVAR
, rtm_rttvar
);
metric(RTM_HOPCOUNT
, rtm_hopcount
);
metric(RTM_MTU
, rtm_mtu
);
rt
->rt_locks
|= (rtm
->rtm_inits
& rtm
->rtm_locks
);
rt
->rt_locks
&= ~(rtm
->rtm_inits
);
rtm
->rtm_flags
|= RTF_DONE
;
m_copyback(m
= m0
, 0, len
, cp
);
/*if (m->m_pkthdr.len != len) {
route_proto
.sp_protocol
= dst
->sa_family
;
raw_input(m0
, &route_proto
, &route_src
, &route_dst
);
* 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
;
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
);
dlen
= ROUNDUP(mask
->sa_len
);
m_copyback(m
, len
, dlen
, (caddr_t
)mask
);
dlen
= ROUNDUP(src
->sa_len
);
m_copyback(m
, len
, dlen
, (caddr_t
)src
);
if (m
->m_pkthdr
.len
!= len
) {
route_proto
.sp_protocol
= dst
->sa_family
;
raw_input(m
, &route_proto
, &route_src
, &route_dst
);
* 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,
raw_input
, 0, raw_ctlinput
, 0,
int unp_externalize(), unp_dispose();
struct domain routedomain
=
{ PF_ROUTE
, "route", 0, 0, 0,
routesw
, &routesw
[sizeof(routesw
)/sizeof(routesw
[0])] };