diff options
Diffstat (limited to 'net/l2tp/l2tp_ppp.c')
-rw-r--r-- | net/l2tp/l2tp_ppp.c | 120 |
1 files changed, 74 insertions, 46 deletions
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index bee5b1413ec0..e5b531266541 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c | |||
@@ -291,17 +291,6 @@ static void pppol2tp_session_sock_put(struct l2tp_session *session) | |||
291 | * Transmit handling | 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 | /* This is the sendmsg for the PPPoL2TP pppol2tp_session socket. We come here | 294 | /* This is the sendmsg for the PPPoL2TP pppol2tp_session socket. We come here |
306 | * when a user application does a sendmsg() on the session socket. L2TP and | 295 | * when a user application does a sendmsg() on the session socket. L2TP and |
307 | * PPP headers must be inserted into the user's data. | 296 | * 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) | |||
394 | static const u8 ppph[2] = { 0xff, 0x03 }; | 383 | static const u8 ppph[2] = { 0xff, 0x03 }; |
395 | struct sock *sk = (struct sock *) chan->private; | 384 | struct sock *sk = (struct sock *) chan->private; |
396 | struct sock *sk_tun; | 385 | struct sock *sk_tun; |
397 | int hdr_len; | ||
398 | struct l2tp_session *session; | 386 | struct l2tp_session *session; |
399 | struct l2tp_tunnel *tunnel; | 387 | struct l2tp_tunnel *tunnel; |
400 | struct pppol2tp_session *ps; | 388 | struct pppol2tp_session *ps; |
@@ -417,9 +405,6 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | |||
417 | if (tunnel == NULL) | 405 | if (tunnel == NULL) |
418 | goto abort_put_sess; | 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 | old_headroom = skb_headroom(skb); | 408 | old_headroom = skb_headroom(skb); |
424 | if (skb_cow_head(skb, sizeof(ppph))) | 409 | if (skb_cow_head(skb, sizeof(ppph))) |
425 | goto abort_put_sess_tun; | 410 | goto abort_put_sess_tun; |
@@ -432,7 +417,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | |||
432 | skb->data[0] = ppph[0]; | 417 | skb->data[0] = ppph[0]; |
433 | skb->data[1] = ppph[1]; | 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 | sock_put(sk_tun); | 422 | sock_put(sk_tun); |
438 | sock_put(sk); | 423 | sock_put(sk); |
@@ -615,6 +600,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
615 | { | 600 | { |
616 | struct sock *sk = sock->sk; | 601 | struct sock *sk = sock->sk; |
617 | struct sockaddr_pppol2tp *sp = (struct sockaddr_pppol2tp *) uservaddr; | 602 | struct sockaddr_pppol2tp *sp = (struct sockaddr_pppol2tp *) uservaddr; |
603 | struct sockaddr_pppol2tpv3 *sp3 = (struct sockaddr_pppol2tpv3 *) uservaddr; | ||
618 | struct pppox_sock *po = pppox_sk(sk); | 604 | struct pppox_sock *po = pppox_sk(sk); |
619 | struct l2tp_session *session = NULL; | 605 | struct l2tp_session *session = NULL; |
620 | struct l2tp_tunnel *tunnel; | 606 | struct l2tp_tunnel *tunnel; |
@@ -622,6 +608,10 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
622 | struct dst_entry *dst; | 608 | struct dst_entry *dst; |
623 | struct l2tp_session_cfg cfg = { 0, }; | 609 | struct l2tp_session_cfg cfg = { 0, }; |
624 | int error = 0; | 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 | lock_sock(sk); | 616 | lock_sock(sk); |
627 | 617 | ||
@@ -639,21 +629,40 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
639 | if (sk->sk_user_data) | 629 | if (sk->sk_user_data) |
640 | goto end; /* socket is already attached */ | 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 | error = -EINVAL; | 652 | error = -EINVAL; |
644 | if (sp->pppol2tp.s_tunnel == 0) | 653 | if (tunnel_id == 0) |
645 | goto end; | 654 | goto end; |
646 | 655 | ||
647 | /* Special case: create tunnel context if s_session and | 656 | /* Special case: create tunnel context if session_id and |
648 | * d_session is 0. Otherwise look up tunnel using supplied | 657 | * peer_session_id is 0. Otherwise look up tunnel using supplied |
649 | * tunnel id. | 658 | * tunnel id. |
650 | */ | 659 | */ |
651 | if ((sp->pppol2tp.s_session == 0) && (sp->pppol2tp.d_session == 0)) { | 660 | if ((session_id == 0) && (peer_session_id == 0)) { |
652 | error = l2tp_tunnel_create(sock_net(sk), sp->pppol2tp.fd, 2, sp->pppol2tp.s_tunnel, sp->pppol2tp.d_tunnel, NULL, &tunnel); | 661 | error = l2tp_tunnel_create(sock_net(sk), fd, ver, tunnel_id, peer_tunnel_id, NULL, &tunnel); |
653 | if (error < 0) | 662 | if (error < 0) |
654 | goto end; | 663 | goto end; |
655 | } else { | 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 | /* Error if we can't find the tunnel */ | 667 | /* Error if we can't find the tunnel */ |
659 | error = -ENOENT; | 668 | error = -ENOENT; |
@@ -670,20 +679,21 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
670 | 679 | ||
671 | /* Check that this session doesn't already exist */ | 680 | /* Check that this session doesn't already exist */ |
672 | error = -EEXIST; | 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 | if (session != NULL) | 683 | if (session != NULL) |
675 | goto end; | 684 | goto end; |
676 | 685 | ||
677 | /* Default MTU must allow space for UDP/L2TP/PPP | 686 | /* Default MTU values. */ |
678 | * headers. | 687 | if (cfg.mtu == 0) |
679 | */ | 688 | cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; |
680 | cfg.mtu = cfg.mru = 1500 - PPPOL2TP_HEADER_OVERHEAD; | 689 | if (cfg.mru == 0) |
690 | cfg.mru = cfg.mtu; | ||
681 | cfg.debug = tunnel->debug; | 691 | cfg.debug = tunnel->debug; |
682 | 692 | ||
683 | /* Allocate and initialize a new session context. */ | 693 | /* Allocate and initialize a new session context. */ |
684 | session = l2tp_session_create(sizeof(struct pppol2tp_session), | 694 | session = l2tp_session_create(sizeof(struct pppol2tp_session), |
685 | tunnel, sp->pppol2tp.s_session, | 695 | tunnel, session_id, |
686 | sp->pppol2tp.d_session, &cfg); | 696 | peer_session_id, &cfg); |
687 | if (session == NULL) { | 697 | if (session == NULL) { |
688 | error = -ENOMEM; | 698 | error = -ENOMEM; |
689 | goto end; | 699 | goto end; |
@@ -756,8 +766,7 @@ end: | |||
756 | static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr, | 766 | static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr, |
757 | int *usockaddr_len, int peer) | 767 | int *usockaddr_len, int peer) |
758 | { | 768 | { |
759 | int len = sizeof(struct sockaddr_pppol2tp); | 769 | int len = 0; |
760 | struct sockaddr_pppol2tp sp; | ||
761 | int error = 0; | 770 | int error = 0; |
762 | struct l2tp_session *session; | 771 | struct l2tp_session *session; |
763 | struct l2tp_tunnel *tunnel; | 772 | struct l2tp_tunnel *tunnel; |
@@ -783,21 +792,40 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr, | |||
783 | goto end_put_sess; | 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 | inet = inet_sk(sk); | 795 | inet = inet_sk(sk); |
796 | sp.pppol2tp.addr.sin_family = AF_INET; | 796 | if (tunnel->version == 2) { |
797 | sp.pppol2tp.addr.sin_port = inet->inet_dport; | 797 | struct sockaddr_pppol2tp sp; |
798 | sp.pppol2tp.addr.sin_addr.s_addr = inet->inet_daddr; | 798 | len = sizeof(sp); |
799 | 799 | memset(&sp, 0, len); | |
800 | memcpy(uaddr, &sp, 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 | *usockaddr_len = len; | 830 | *usockaddr_len = len; |
803 | 831 | ||