Skip to content

Commit e0d4435

Browse files
j-c-hdavem330
authored andcommitted
l2tp: Update PPP-over-L2TP driver to work over L2TPv3
This patch makes changes to the L2TP PPP code for L2TPv3. The existing code has some assumptions about the L2TP header which are broken by L2TPv3. Also the sockaddr_pppol2tp structure of the original code is too small to support the increased size of the L2TPv3 tunnel and session id, so a new sockaddr_pppol2tpv3 structure is needed. In the socket calls, the size of this structure is used to tell if the operation is for L2TPv2 or L2TPv3. Signed-off-by: James Chapman <[email protected]> Reviewed-by: Randy Dunlap <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f7faffa commit e0d4435

File tree

3 files changed

+97
-46
lines changed

3 files changed

+97
-46
lines changed

include/linux/if_pppol2tp.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,20 @@ struct pppol2tp_addr {
3535
__u16 d_tunnel, d_session; /* For sending outgoing packets */
3636
};
3737

38+
/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32
39+
* bits. So we need a different sockaddr structure.
40+
*/
41+
struct pppol2tpv3_addr {
42+
pid_t pid; /* pid that owns the fd.
43+
* 0 => current */
44+
int fd; /* FD of UDP or IP socket to use */
45+
46+
struct sockaddr_in addr; /* IP address and port to send to */
47+
48+
__u32 s_tunnel, s_session; /* For matching incoming packets */
49+
__u32 d_tunnel, d_session; /* For sending outgoing packets */
50+
};
51+
3852
/* Socket options:
3953
* DEBUG - bitmask of debug message categories
4054
* SENDSEQ - 0 => don't send packets with sequence numbers

include/linux/if_pppox.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,15 @@ struct sockaddr_pppol2tp {
7272
struct pppol2tp_addr pppol2tp;
7373
}__attribute__ ((packed));
7474

75+
/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32
76+
* bits. So we need a different sockaddr structure.
77+
*/
78+
struct sockaddr_pppol2tpv3 {
79+
sa_family_t sa_family; /* address family, AF_PPPOX */
80+
unsigned int sa_protocol; /* protocol identifier */
81+
struct pppol2tpv3_addr pppol2tp;
82+
} __attribute__ ((packed));
83+
7584
/*********************************************************************
7685
*
7786
* ioctl interface for defining forwarding of connections

net/l2tp/l2tp_ppp.c

Lines changed: 74 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -291,17 +291,6 @@ static void pppol2tp_session_sock_put(struct l2tp_session *session)
291291
* Transmit handling
292292
***********************************************************************/
293293

294-
/* Tell how big L2TP headers are for a particular session. This
295-
* depends on whether sequence numbers are being used.
296-
*/
297-
static inline int pppol2tp_l2tp_header_len(struct l2tp_session *session)
298-
{
299-
if (session->send_seq)
300-
return PPPOL2TP_L2TP_HDR_SIZE_SEQ;
301-
302-
return PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
303-
}
304-
305294
/* This is the sendmsg for the PPPoL2TP pppol2tp_session socket. We come here
306295
* when a user application does a sendmsg() on the session socket. L2TP and
307296
* 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)
394383
static const u8 ppph[2] = { 0xff, 0x03 };
395384
struct sock *sk = (struct sock *) chan->private;
396385
struct sock *sk_tun;
397-
int hdr_len;
398386
struct l2tp_session *session;
399387
struct l2tp_tunnel *tunnel;
400388
struct pppol2tp_session *ps;
@@ -417,9 +405,6 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
417405
if (tunnel == NULL)
418406
goto abort_put_sess;
419407

420-
/* What header length is configured for this session? */
421-
hdr_len = pppol2tp_l2tp_header_len(session);
422-
423408
old_headroom = skb_headroom(skb);
424409
if (skb_cow_head(skb, sizeof(ppph)))
425410
goto abort_put_sess_tun;
@@ -432,7 +417,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
432417
skb->data[0] = ppph[0];
433418
skb->data[1] = ppph[1];
434419

435-
l2tp_xmit_skb(session, skb, hdr_len);
420+
l2tp_xmit_skb(session, skb, session->hdr_len);
436421

437422
sock_put(sk_tun);
438423
sock_put(sk);
@@ -615,13 +600,18 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
615600
{
616601
struct sock *sk = sock->sk;
617602
struct sockaddr_pppol2tp *sp = (struct sockaddr_pppol2tp *) uservaddr;
603+
struct sockaddr_pppol2tpv3 *sp3 = (struct sockaddr_pppol2tpv3 *) uservaddr;
618604
struct pppox_sock *po = pppox_sk(sk);
619605
struct l2tp_session *session = NULL;
620606
struct l2tp_tunnel *tunnel;
621607
struct pppol2tp_session *ps;
622608
struct dst_entry *dst;
623609
struct l2tp_session_cfg cfg = { 0, };
624610
int error = 0;
611+
u32 tunnel_id, peer_tunnel_id;
612+
u32 session_id, peer_session_id;
613+
int ver = 2;
614+
int fd;
625615

626616
lock_sock(sk);
627617

@@ -639,21 +629,40 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
639629
if (sk->sk_user_data)
640630
goto end; /* socket is already attached */
641631

642-
/* Don't bind if s_tunnel is 0 */
632+
/* Get params from socket address. Handle L2TPv2 and L2TPv3 */
633+
if (sockaddr_len == sizeof(struct sockaddr_pppol2tp)) {
634+
fd = sp->pppol2tp.fd;
635+
tunnel_id = sp->pppol2tp.s_tunnel;
636+
peer_tunnel_id = sp->pppol2tp.d_tunnel;
637+
session_id = sp->pppol2tp.s_session;
638+
peer_session_id = sp->pppol2tp.d_session;
639+
} else if (sockaddr_len == sizeof(struct sockaddr_pppol2tpv3)) {
640+
ver = 3;
641+
fd = sp3->pppol2tp.fd;
642+
tunnel_id = sp3->pppol2tp.s_tunnel;
643+
peer_tunnel_id = sp3->pppol2tp.d_tunnel;
644+
session_id = sp3->pppol2tp.s_session;
645+
peer_session_id = sp3->pppol2tp.d_session;
646+
} else {
647+
error = -EINVAL;
648+
goto end; /* bad socket address */
649+
}
650+
651+
/* Don't bind if tunnel_id is 0 */
643652
error = -EINVAL;
644-
if (sp->pppol2tp.s_tunnel == 0)
653+
if (tunnel_id == 0)
645654
goto end;
646655

647-
/* Special case: create tunnel context if s_session and
648-
* d_session is 0. Otherwise look up tunnel using supplied
656+
/* Special case: create tunnel context if session_id and
657+
* peer_session_id is 0. Otherwise look up tunnel using supplied
649658
* tunnel id.
650659
*/
651-
if ((sp->pppol2tp.s_session == 0) && (sp->pppol2tp.d_session == 0)) {
652-
error = l2tp_tunnel_create(sock_net(sk), sp->pppol2tp.fd, 2, sp->pppol2tp.s_tunnel, sp->pppol2tp.d_tunnel, NULL, &tunnel);
660+
if ((session_id == 0) && (peer_session_id == 0)) {
661+
error = l2tp_tunnel_create(sock_net(sk), fd, ver, tunnel_id, peer_tunnel_id, NULL, &tunnel);
653662
if (error < 0)
654663
goto end;
655664
} else {
656-
tunnel = l2tp_tunnel_find(sock_net(sk), sp->pppol2tp.s_tunnel);
665+
tunnel = l2tp_tunnel_find(sock_net(sk), tunnel_id);
657666

658667
/* Error if we can't find the tunnel */
659668
error = -ENOENT;
@@ -670,20 +679,21 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
670679

671680
/* Check that this session doesn't already exist */
672681
error = -EEXIST;
673-
session = l2tp_session_find(sock_net(sk), tunnel, sp->pppol2tp.s_session);
682+
session = l2tp_session_find(sock_net(sk), tunnel, session_id);
674683
if (session != NULL)
675684
goto end;
676685

677-
/* Default MTU must allow space for UDP/L2TP/PPP
678-
* headers.
679-
*/
680-
cfg.mtu = cfg.mru = 1500 - PPPOL2TP_HEADER_OVERHEAD;
686+
/* Default MTU values. */
687+
if (cfg.mtu == 0)
688+
cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD;
689+
if (cfg.mru == 0)
690+
cfg.mru = cfg.mtu;
681691
cfg.debug = tunnel->debug;
682692

683693
/* Allocate and initialize a new session context. */
684694
session = l2tp_session_create(sizeof(struct pppol2tp_session),
685-
tunnel, sp->pppol2tp.s_session,
686-
sp->pppol2tp.d_session, &cfg);
695+
tunnel, session_id,
696+
peer_session_id, &cfg);
687697
if (session == NULL) {
688698
error = -ENOMEM;
689699
goto end;
@@ -756,8 +766,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
756766
static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
757767
int *usockaddr_len, int peer)
758768
{
759-
int len = sizeof(struct sockaddr_pppol2tp);
760-
struct sockaddr_pppol2tp sp;
769+
int len = 0;
761770
int error = 0;
762771
struct l2tp_session *session;
763772
struct l2tp_tunnel *tunnel;
@@ -783,21 +792,40 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
783792
goto end_put_sess;
784793
}
785794

786-
memset(&sp, 0, len);
787-
sp.sa_family = AF_PPPOX;
788-
sp.sa_protocol = PX_PROTO_OL2TP;
789-
sp.pppol2tp.fd = tunnel->fd;
790-
sp.pppol2tp.pid = pls->owner;
791-
sp.pppol2tp.s_tunnel = tunnel->tunnel_id;
792-
sp.pppol2tp.d_tunnel = tunnel->peer_tunnel_id;
793-
sp.pppol2tp.s_session = session->session_id;
794-
sp.pppol2tp.d_session = session->peer_session_id;
795795
inet = inet_sk(sk);
796-
sp.pppol2tp.addr.sin_family = AF_INET;
797-
sp.pppol2tp.addr.sin_port = inet->inet_dport;
798-
sp.pppol2tp.addr.sin_addr.s_addr = inet->inet_daddr;
799-
800-
memcpy(uaddr, &sp, len);
796+
if (tunnel->version == 2) {
797+
struct sockaddr_pppol2tp sp;
798+
len = sizeof(sp);
799+
memset(&sp, 0, len);
800+
sp.sa_family = AF_PPPOX;
801+
sp.sa_protocol = PX_PROTO_OL2TP;
802+
sp.pppol2tp.fd = tunnel->fd;
803+
sp.pppol2tp.pid = pls->owner;
804+
sp.pppol2tp.s_tunnel = tunnel->tunnel_id;
805+
sp.pppol2tp.d_tunnel = tunnel->peer_tunnel_id;
806+
sp.pppol2tp.s_session = session->session_id;
807+
sp.pppol2tp.d_session = session->peer_session_id;
808+
sp.pppol2tp.addr.sin_family = AF_INET;
809+
sp.pppol2tp.addr.sin_port = inet->inet_dport;
810+
sp.pppol2tp.addr.sin_addr.s_addr = inet->inet_daddr;
811+
memcpy(uaddr, &sp, len);
812+
} else if (tunnel->version == 3) {
813+
struct sockaddr_pppol2tpv3 sp;
814+
len = sizeof(sp);
815+
memset(&sp, 0, len);
816+
sp.sa_family = AF_PPPOX;
817+
sp.sa_protocol = PX_PROTO_OL2TP;
818+
sp.pppol2tp.fd = tunnel->fd;
819+
sp.pppol2tp.pid = pls->owner;
820+
sp.pppol2tp.s_tunnel = tunnel->tunnel_id;
821+
sp.pppol2tp.d_tunnel = tunnel->peer_tunnel_id;
822+
sp.pppol2tp.s_session = session->session_id;
823+
sp.pppol2tp.d_session = session->peer_session_id;
824+
sp.pppol2tp.addr.sin_family = AF_INET;
825+
sp.pppol2tp.addr.sin_port = inet->inet_dport;
826+
sp.pppol2tp.addr.sin_addr.s_addr = inet->inet_daddr;
827+
memcpy(uaddr, &sp, len);
828+
}
801829

802830
*usockaddr_len = len;
803831

0 commit comments

Comments
 (0)