.. | .. |
---|
651 | 651 | return mtu - PPPOL2TP_HEADER_OVERHEAD; |
---|
652 | 652 | } |
---|
653 | 653 | |
---|
| 654 | +static struct l2tp_tunnel *pppol2tp_tunnel_get(struct net *net, |
---|
| 655 | + const struct l2tp_connect_info *info, |
---|
| 656 | + bool *new_tunnel) |
---|
| 657 | +{ |
---|
| 658 | + struct l2tp_tunnel *tunnel; |
---|
| 659 | + int error; |
---|
| 660 | + |
---|
| 661 | + *new_tunnel = false; |
---|
| 662 | + |
---|
| 663 | + tunnel = l2tp_tunnel_get(net, info->tunnel_id); |
---|
| 664 | + |
---|
| 665 | + /* Special case: create tunnel context if session_id and |
---|
| 666 | + * peer_session_id is 0. Otherwise look up tunnel using supplied |
---|
| 667 | + * tunnel id. |
---|
| 668 | + */ |
---|
| 669 | + if (!info->session_id && !info->peer_session_id) { |
---|
| 670 | + if (!tunnel) { |
---|
| 671 | + struct l2tp_tunnel_cfg tcfg = { |
---|
| 672 | + .encap = L2TP_ENCAPTYPE_UDP, |
---|
| 673 | + }; |
---|
| 674 | + |
---|
| 675 | + /* Prevent l2tp_tunnel_register() from trying to set up |
---|
| 676 | + * a kernel socket. |
---|
| 677 | + */ |
---|
| 678 | + if (info->fd < 0) |
---|
| 679 | + return ERR_PTR(-EBADF); |
---|
| 680 | + |
---|
| 681 | + error = l2tp_tunnel_create(info->fd, |
---|
| 682 | + info->version, |
---|
| 683 | + info->tunnel_id, |
---|
| 684 | + info->peer_tunnel_id, &tcfg, |
---|
| 685 | + &tunnel); |
---|
| 686 | + if (error < 0) |
---|
| 687 | + return ERR_PTR(error); |
---|
| 688 | + |
---|
| 689 | + l2tp_tunnel_inc_refcount(tunnel); |
---|
| 690 | + error = l2tp_tunnel_register(tunnel, net, &tcfg); |
---|
| 691 | + if (error < 0) { |
---|
| 692 | + kfree(tunnel); |
---|
| 693 | + return ERR_PTR(error); |
---|
| 694 | + } |
---|
| 695 | + |
---|
| 696 | + *new_tunnel = true; |
---|
| 697 | + } |
---|
| 698 | + } else { |
---|
| 699 | + /* Error if we can't find the tunnel */ |
---|
| 700 | + if (!tunnel) |
---|
| 701 | + return ERR_PTR(-ENOENT); |
---|
| 702 | + |
---|
| 703 | + /* Error if socket is not prepped */ |
---|
| 704 | + if (!tunnel->sock) { |
---|
| 705 | + l2tp_tunnel_dec_refcount(tunnel); |
---|
| 706 | + return ERR_PTR(-ENOENT); |
---|
| 707 | + } |
---|
| 708 | + } |
---|
| 709 | + |
---|
| 710 | + return tunnel; |
---|
| 711 | +} |
---|
| 712 | + |
---|
654 | 713 | /* connect() handler. Attach a PPPoX socket to a tunnel UDP socket |
---|
655 | 714 | */ |
---|
656 | 715 | static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, |
---|
.. | .. |
---|
664 | 723 | struct pppol2tp_session *ps; |
---|
665 | 724 | struct l2tp_session_cfg cfg = { 0, }; |
---|
666 | 725 | bool drop_refcnt = false; |
---|
667 | | - bool drop_tunnel = false; |
---|
668 | 726 | bool new_session = false; |
---|
669 | 727 | bool new_tunnel = false; |
---|
670 | 728 | int error; |
---|
.. | .. |
---|
672 | 730 | error = pppol2tp_sockaddr_get_info(uservaddr, sockaddr_len, &info); |
---|
673 | 731 | if (error < 0) |
---|
674 | 732 | return error; |
---|
| 733 | + |
---|
| 734 | + /* Don't bind if tunnel_id is 0 */ |
---|
| 735 | + if (!info.tunnel_id) |
---|
| 736 | + return -EINVAL; |
---|
| 737 | + |
---|
| 738 | + tunnel = pppol2tp_tunnel_get(sock_net(sk), &info, &new_tunnel); |
---|
| 739 | + if (IS_ERR(tunnel)) |
---|
| 740 | + return PTR_ERR(tunnel); |
---|
675 | 741 | |
---|
676 | 742 | lock_sock(sk); |
---|
677 | 743 | |
---|
.. | .. |
---|
684 | 750 | error = -EALREADY; |
---|
685 | 751 | if (sk->sk_user_data) |
---|
686 | 752 | goto end; /* socket is already attached */ |
---|
687 | | - |
---|
688 | | - /* Don't bind if tunnel_id is 0 */ |
---|
689 | | - error = -EINVAL; |
---|
690 | | - if (!info.tunnel_id) |
---|
691 | | - goto end; |
---|
692 | | - |
---|
693 | | - tunnel = l2tp_tunnel_get(sock_net(sk), info.tunnel_id); |
---|
694 | | - if (tunnel) |
---|
695 | | - drop_tunnel = true; |
---|
696 | | - |
---|
697 | | - /* Special case: create tunnel context if session_id and |
---|
698 | | - * peer_session_id is 0. Otherwise look up tunnel using supplied |
---|
699 | | - * tunnel id. |
---|
700 | | - */ |
---|
701 | | - if (!info.session_id && !info.peer_session_id) { |
---|
702 | | - if (!tunnel) { |
---|
703 | | - struct l2tp_tunnel_cfg tcfg = { |
---|
704 | | - .encap = L2TP_ENCAPTYPE_UDP, |
---|
705 | | - }; |
---|
706 | | - |
---|
707 | | - /* Prevent l2tp_tunnel_register() from trying to set up |
---|
708 | | - * a kernel socket. |
---|
709 | | - */ |
---|
710 | | - if (info.fd < 0) { |
---|
711 | | - error = -EBADF; |
---|
712 | | - goto end; |
---|
713 | | - } |
---|
714 | | - |
---|
715 | | - error = l2tp_tunnel_create(info.fd, |
---|
716 | | - info.version, |
---|
717 | | - info.tunnel_id, |
---|
718 | | - info.peer_tunnel_id, &tcfg, |
---|
719 | | - &tunnel); |
---|
720 | | - if (error < 0) |
---|
721 | | - goto end; |
---|
722 | | - |
---|
723 | | - l2tp_tunnel_inc_refcount(tunnel); |
---|
724 | | - error = l2tp_tunnel_register(tunnel, sock_net(sk), |
---|
725 | | - &tcfg); |
---|
726 | | - if (error < 0) { |
---|
727 | | - kfree(tunnel); |
---|
728 | | - goto end; |
---|
729 | | - } |
---|
730 | | - drop_tunnel = true; |
---|
731 | | - new_tunnel = true; |
---|
732 | | - } |
---|
733 | | - } else { |
---|
734 | | - /* Error if we can't find the tunnel */ |
---|
735 | | - error = -ENOENT; |
---|
736 | | - if (!tunnel) |
---|
737 | | - goto end; |
---|
738 | | - |
---|
739 | | - /* Error if socket is not prepped */ |
---|
740 | | - if (!tunnel->sock) |
---|
741 | | - goto end; |
---|
742 | | - } |
---|
743 | 753 | |
---|
744 | 754 | if (tunnel->peer_tunnel_id == 0) |
---|
745 | 755 | tunnel->peer_tunnel_id = info.peer_tunnel_id; |
---|
.. | .. |
---|
841 | 851 | } |
---|
842 | 852 | if (drop_refcnt) |
---|
843 | 853 | l2tp_session_dec_refcount(session); |
---|
844 | | - if (drop_tunnel) |
---|
845 | | - l2tp_tunnel_dec_refcount(tunnel); |
---|
| 854 | + l2tp_tunnel_dec_refcount(tunnel); |
---|
846 | 855 | release_sock(sk); |
---|
847 | 856 | |
---|
848 | 857 | return error; |
---|