Commit e0d4435f93905f517003cfa7328a36ea19788147

Authored by James Chapman
Committed by David S. Miller
1 parent f7faffa3ff

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 <jchapman@katalix.com>
Reviewed-by: Randy Dunlap <randy.dunlap@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 3 changed files with 97 additions and 46 deletions Side-by-side Diff

include/linux/if_pppol2tp.h
... ... @@ -35,6 +35,20 @@
35 35 __u16 d_tunnel, d_session; /* For sending outgoing packets */
36 36 };
37 37  
  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 +
38 52 /* Socket options:
39 53 * DEBUG - bitmask of debug message categories
40 54 * SENDSEQ - 0 => don't send packets with sequence numbers
include/linux/if_pppox.h
... ... @@ -72,6 +72,15 @@
72 72 struct pppol2tp_addr pppol2tp;
73 73 }__attribute__ ((packed));
74 74  
  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 +
75 84 /*********************************************************************
76 85 *
77 86 * ioctl interface for defining forwarding of connections
... ... @@ -291,17 +291,6 @@
291 291 * Transmit handling
292 292 ***********************************************************************/
293 293  
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   -
305 294 /* This is the sendmsg for the PPPoL2TP pppol2tp_session socket. We come here
306 295 * when a user application does a sendmsg() on the session socket. L2TP and
307 296 * PPP headers must be inserted into the user's data.
... ... @@ -394,7 +383,6 @@
394 383 static const u8 ppph[2] = { 0xff, 0x03 };
395 384 struct sock *sk = (struct sock *) chan->private;
396 385 struct sock *sk_tun;
397   - int hdr_len;
398 386 struct l2tp_session *session;
399 387 struct l2tp_tunnel *tunnel;
400 388 struct pppol2tp_session *ps;
... ... @@ -417,9 +405,6 @@
417 405 if (tunnel == NULL)
418 406 goto abort_put_sess;
419 407  
420   - /* What header length is configured for this session? */
421   - hdr_len = pppol2tp_l2tp_header_len(session);
422   -
423 408 old_headroom = skb_headroom(skb);
424 409 if (skb_cow_head(skb, sizeof(ppph)))
425 410 goto abort_put_sess_tun;
... ... @@ -432,7 +417,7 @@
432 417 skb->data[0] = ppph[0];
433 418 skb->data[1] = ppph[1];
434 419  
435   - l2tp_xmit_skb(session, skb, hdr_len);
  420 + l2tp_xmit_skb(session, skb, session->hdr_len);
436 421  
437 422 sock_put(sk_tun);
438 423 sock_put(sk);
... ... @@ -615,6 +600,7 @@
615 600 {
616 601 struct sock *sk = sock->sk;
617 602 struct sockaddr_pppol2tp *sp = (struct sockaddr_pppol2tp *) uservaddr;
  603 + struct sockaddr_pppol2tpv3 *sp3 = (struct sockaddr_pppol2tpv3 *) uservaddr;
618 604 struct pppox_sock *po = pppox_sk(sk);
619 605 struct l2tp_session *session = NULL;
620 606 struct l2tp_tunnel *tunnel;
... ... @@ -622,6 +608,10 @@
622 608 struct dst_entry *dst;
623 609 struct l2tp_session_cfg cfg = { 0, };
624 610 int error = 0;
  611 + u32 tunnel_id, peer_tunnel_id;
  612 + u32 session_id, peer_session_id;
  613 + int ver = 2;
  614 + int fd;
625 615  
626 616 lock_sock(sk);
627 617  
628 618  
629 619  
630 620  
631 621  
... ... @@ -639,21 +629,40 @@
639 629 if (sk->sk_user_data)
640 630 goto end; /* socket is already attached */
641 631  
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 */
643 652 error = -EINVAL;
644   - if (sp->pppol2tp.s_tunnel == 0)
  653 + if (tunnel_id == 0)
645 654 goto end;
646 655  
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
649 658 * tunnel id.
650 659 */
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);
653 662 if (error < 0)
654 663 goto end;
655 664 } else {
656   - tunnel = l2tp_tunnel_find(sock_net(sk), sp->pppol2tp.s_tunnel);
  665 + tunnel = l2tp_tunnel_find(sock_net(sk), tunnel_id);
657 666  
658 667 /* Error if we can't find the tunnel */
659 668 error = -ENOENT;
660 669  
661 670  
... ... @@ -670,20 +679,21 @@
670 679  
671 680 /* Check that this session doesn't already exist */
672 681 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);
674 683 if (session != NULL)
675 684 goto end;
676 685  
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;
681 691 cfg.debug = tunnel->debug;
682 692  
683 693 /* Allocate and initialize a new session context. */
684 694 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);
687 697 if (session == NULL) {
688 698 error = -ENOMEM;
689 699 goto end;
... ... @@ -756,8 +766,7 @@
756 766 static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
757 767 int *usockaddr_len, int peer)
758 768 {
759   - int len = sizeof(struct sockaddr_pppol2tp);
760   - struct sockaddr_pppol2tp sp;
  769 + int len = 0;
761 770 int error = 0;
762 771 struct l2tp_session *session;
763 772 struct l2tp_tunnel *tunnel;
764 773  
... ... @@ -783,21 +792,40 @@
783 792 goto end_put_sess;
784 793 }
785 794  
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;
795 795 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 + }
801 829  
802 830 *usockaddr_len = len;
803 831