@ -291,17 +291,6 @@ static void pppol2tp_session_sock_put(struct l2tp_session *session)
* Transmit handling
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Tell how big L2TP headers are for a particular session. This
* depends on whether sequence numbers are being used .
*/
static inline int pppol2tp_l2tp_header_len ( struct l2tp_session * session )
{
if ( session - > send_seq )
return PPPOL2TP_L2TP_HDR_SIZE_SEQ ;
return PPPOL2TP_L2TP_HDR_SIZE_NOSEQ ;
}
/* This is the sendmsg for the PPPoL2TP pppol2tp_session socket. We come here
* when a user application does a sendmsg ( ) on the session socket . L2TP and
* PPP headers must be inserted into the user ' s data .
@ -394,7 +383,6 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
static const u8 ppph [ 2 ] = { 0xff , 0x03 } ;
struct sock * sk = ( struct sock * ) chan - > private ;
struct sock * sk_tun ;
int hdr_len ;
struct l2tp_session * session ;
struct l2tp_tunnel * tunnel ;
struct pppol2tp_session * ps ;
@ -417,9 +405,6 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
if ( tunnel = = NULL )
goto abort_put_sess ;
/* What header length is configured for this session? */
hdr_len = pppol2tp_l2tp_header_len ( session ) ;
old_headroom = skb_headroom ( skb ) ;
if ( skb_cow_head ( skb , sizeof ( ppph ) ) )
goto abort_put_sess_tun ;
@ -432,7 +417,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
skb - > data [ 0 ] = ppph [ 0 ] ;
skb - > data [ 1 ] = ppph [ 1 ] ;
l2tp_xmit_skb ( session , skb , hdr_len ) ;
l2tp_xmit_skb ( session , skb , session - > hdr_len ) ;
sock_put ( sk_tun ) ;
sock_put ( sk ) ;
@ -615,6 +600,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
{
struct sock * sk = sock - > sk ;
struct sockaddr_pppol2tp * sp = ( struct sockaddr_pppol2tp * ) uservaddr ;
struct sockaddr_pppol2tpv3 * sp3 = ( struct sockaddr_pppol2tpv3 * ) uservaddr ;
struct pppox_sock * po = pppox_sk ( sk ) ;
struct l2tp_session * session = NULL ;
struct l2tp_tunnel * tunnel ;
@ -622,6 +608,10 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
struct dst_entry * dst ;
struct l2tp_session_cfg cfg = { 0 , } ;
int error = 0 ;
u32 tunnel_id , peer_tunnel_id ;
u32 session_id , peer_session_id ;
int ver = 2 ;
int fd ;
lock_sock ( sk ) ;
@ -639,21 +629,40 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
if ( sk - > sk_user_data )
goto end ; /* socket is already attached */
/* Don't bind if s_tunnel is 0 */
/* Get params from socket address. Handle L2TPv2 and L2TPv3 */
if ( sockaddr_len = = sizeof ( struct sockaddr_pppol2tp ) ) {
fd = sp - > pppol2tp . fd ;
tunnel_id = sp - > pppol2tp . s_tunnel ;
peer_tunnel_id = sp - > pppol2tp . d_tunnel ;
session_id = sp - > pppol2tp . s_session ;
peer_session_id = sp - > pppol2tp . d_session ;
} else if ( sockaddr_len = = sizeof ( struct sockaddr_pppol2tpv3 ) ) {
ver = 3 ;
fd = sp3 - > pppol2tp . fd ;
tunnel_id = sp3 - > pppol2tp . s_tunnel ;
peer_tunnel_id = sp3 - > pppol2tp . d_tunnel ;
session_id = sp3 - > pppol2tp . s_session ;
peer_session_id = sp3 - > pppol2tp . d_session ;
} else {
error = - EINVAL ;
goto end ; /* bad socket address */
}
/* Don't bind if tunnel_id is 0 */
error = - EINVAL ;
if ( sp - > pppol2tp . s_tunnel = = 0 )
if ( tunnel_id = = 0 )
goto end ;
/* Special case: create tunnel context if s_session and
* d_session is 0. Otherwise look up tunnel using supplied
/* Special case: create tunnel context if session_id and
* peer_session_id is 0. Otherwise look up tunnel using supplied
* tunnel id .
*/
if ( ( sp - > pppol2tp . s_session = = 0 ) & & ( sp - > pppol2tp . d_session = = 0 ) ) {
error = l2tp_tunnel_create ( sock_net ( sk ) , sp - > pppol2tp . fd , 2 , sp - > pppol2tp . s_tunnel , sp - > pppol2tp . d_tunnel , NULL , & tunnel ) ;
if ( ( session_id = = 0 ) & & ( peer_session_id = = 0 ) ) {
error = l2tp_tunnel_create ( sock_net ( sk ) , fd , ver , tunnel_id , peer_tunnel_id , NULL , & tunnel ) ;
if ( error < 0 )
goto end ;
} else {
tunnel = l2tp_tunnel_find ( sock_net ( sk ) , sp - > pppol2tp . s_tunnel ) ;
tunnel = l2tp_tunnel_find ( sock_net ( sk ) , tunnel_id ) ;
/* Error if we can't find the tunnel */
error = - ENOENT ;
@ -670,20 +679,21 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
/* Check that this session doesn't already exist */
error = - EEXIST ;
session = l2tp_session_find ( sock_net ( sk ) , tunnel , sp - > pppol2tp . s_s ession ) ;
session = l2tp_session_find ( sock_net ( sk ) , tunnel , session_id ) ;
if ( session ! = NULL )
goto end ;
/* Default MTU must allow space for UDP/L2TP/PPP
* headers .
*/
cfg . mtu = cfg . mru = 1500 - PPPOL2TP_HEADER_OVERHEAD ;
/* Default MTU values. */
if ( cfg . mtu = = 0 )
cfg . mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD ;
if ( cfg . mru = = 0 )
cfg . mru = cfg . mtu ;
cfg . debug = tunnel - > debug ;
/* Allocate and initialize a new session context. */
session = l2tp_session_create ( sizeof ( struct pppol2tp_session ) ,
tunnel , sp - > pppol2tp . s_s ession ,
sp - > pppol2tp . d_session , & cfg ) ;
tunnel , session_id ,
peer_session_id , & cfg ) ;
if ( session = = NULL ) {
error = - ENOMEM ;
goto end ;
@ -756,8 +766,7 @@ end:
static int pppol2tp_getname ( struct socket * sock , struct sockaddr * uaddr ,
int * usockaddr_len , int peer )
{
int len = sizeof ( struct sockaddr_pppol2tp ) ;
struct sockaddr_pppol2tp sp ;
int len = 0 ;
int error = 0 ;
struct l2tp_session * session ;
struct l2tp_tunnel * tunnel ;
@ -783,21 +792,40 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
goto end_put_sess ;
}
memset ( & sp , 0 , len ) ;
sp . sa_family = AF_PPPOX ;
sp . sa_protocol = PX_PROTO_OL2TP ;
sp . pppol2tp . fd = tunnel - > fd ;
sp . pppol2tp . pid = pls - > owner ;
sp . pppol2tp . s_tunnel = tunnel - > tunnel_id ;
sp . pppol2tp . d_tunnel = tunnel - > peer_tunnel_id ;
sp . pppol2tp . s_session = session - > session_id ;
sp . pppol2tp . d_session = session - > peer_session_id ;
inet = inet_sk ( sk ) ;
sp . pppol2tp . addr . sin_family = AF_INET ;
sp . pppol2tp . addr . sin_port = inet - > inet_dport ;
sp . pppol2tp . addr . sin_addr . s_addr = inet - > inet_daddr ;
memcpy ( uaddr , & sp , len ) ;
if ( tunnel - > version = = 2 ) {
struct sockaddr_pppol2tp sp ;
len = sizeof ( sp ) ;
memset ( & sp , 0 , len ) ;
sp . sa_family = AF_PPPOX ;
sp . sa_protocol = PX_PROTO_OL2TP ;
sp . pppol2tp . fd = tunnel - > fd ;
sp . pppol2tp . pid = pls - > owner ;
sp . pppol2tp . s_tunnel = tunnel - > tunnel_id ;
sp . pppol2tp . d_tunnel = tunnel - > peer_tunnel_id ;
sp . pppol2tp . s_session = session - > session_id ;
sp . pppol2tp . d_session = session - > peer_session_id ;
sp . pppol2tp . addr . sin_family = AF_INET ;
sp . pppol2tp . addr . sin_port = inet - > inet_dport ;
sp . pppol2tp . addr . sin_addr . s_addr = inet - > inet_daddr ;
memcpy ( uaddr , & sp , len ) ;
} else if ( tunnel - > version = = 3 ) {
struct sockaddr_pppol2tpv3 sp ;
len = sizeof ( sp ) ;
memset ( & sp , 0 , len ) ;
sp . sa_family = AF_PPPOX ;
sp . sa_protocol = PX_PROTO_OL2TP ;
sp . pppol2tp . fd = tunnel - > fd ;
sp . pppol2tp . pid = pls - > owner ;
sp . pppol2tp . s_tunnel = tunnel - > tunnel_id ;
sp . pppol2tp . d_tunnel = tunnel - > peer_tunnel_id ;
sp . pppol2tp . s_session = session - > session_id ;
sp . pppol2tp . d_session = session - > peer_session_id ;
sp . pppol2tp . addr . sin_family = AF_INET ;
sp . pppol2tp . addr . sin_port = inet - > inet_dport ;
sp . pppol2tp . addr . sin_addr . s_addr = inet - > inet_daddr ;
memcpy ( uaddr , & sp , len ) ;
}
* usockaddr_len = len ;