diff options
Diffstat (limited to 'net/l2tp/l2tp_ppp.c')
| -rw-r--r-- | net/l2tp/l2tp_ppp.c | 94 |
1 files changed, 52 insertions, 42 deletions
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 36cc56fd0418..861b255a2d51 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c | |||
| @@ -450,6 +450,10 @@ static void pppol2tp_session_close(struct l2tp_session *session) | |||
| 450 | static void pppol2tp_session_destruct(struct sock *sk) | 450 | static void pppol2tp_session_destruct(struct sock *sk) |
| 451 | { | 451 | { |
| 452 | struct l2tp_session *session = sk->sk_user_data; | 452 | struct l2tp_session *session = sk->sk_user_data; |
| 453 | |||
| 454 | skb_queue_purge(&sk->sk_receive_queue); | ||
| 455 | skb_queue_purge(&sk->sk_write_queue); | ||
| 456 | |||
| 453 | if (session) { | 457 | if (session) { |
| 454 | sk->sk_user_data = NULL; | 458 | sk->sk_user_data = NULL; |
| 455 | BUG_ON(session->magic != L2TP_SESSION_MAGIC); | 459 | BUG_ON(session->magic != L2TP_SESSION_MAGIC); |
| @@ -488,9 +492,6 @@ static int pppol2tp_release(struct socket *sock) | |||
| 488 | l2tp_session_queue_purge(session); | 492 | l2tp_session_queue_purge(session); |
| 489 | sock_put(sk); | 493 | sock_put(sk); |
| 490 | } | 494 | } |
| 491 | skb_queue_purge(&sk->sk_receive_queue); | ||
| 492 | skb_queue_purge(&sk->sk_write_queue); | ||
| 493 | |||
| 494 | release_sock(sk); | 495 | release_sock(sk); |
| 495 | 496 | ||
| 496 | /* This will delete the session context via | 497 | /* This will delete the session context via |
| @@ -582,6 +583,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
| 582 | int error = 0; | 583 | int error = 0; |
| 583 | u32 tunnel_id, peer_tunnel_id; | 584 | u32 tunnel_id, peer_tunnel_id; |
| 584 | u32 session_id, peer_session_id; | 585 | u32 session_id, peer_session_id; |
| 586 | bool drop_refcnt = false; | ||
| 585 | int ver = 2; | 587 | int ver = 2; |
| 586 | int fd; | 588 | int fd; |
| 587 | 589 | ||
| @@ -683,36 +685,36 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
| 683 | if (tunnel->peer_tunnel_id == 0) | 685 | if (tunnel->peer_tunnel_id == 0) |
| 684 | tunnel->peer_tunnel_id = peer_tunnel_id; | 686 | tunnel->peer_tunnel_id = peer_tunnel_id; |
| 685 | 687 | ||
| 686 | /* Create session if it doesn't already exist. We handle the | 688 | session = l2tp_session_get(sock_net(sk), tunnel, session_id, false); |
| 687 | * case where a session was previously created by the netlink | 689 | if (session) { |
| 688 | * interface by checking that the session doesn't already have | 690 | drop_refcnt = true; |
| 689 | * a socket and its tunnel socket are what we expect. If any | 691 | ps = l2tp_session_priv(session); |
| 690 | * of those checks fail, return EEXIST to the caller. | 692 | |
| 691 | */ | 693 | /* Using a pre-existing session is fine as long as it hasn't |
| 692 | session = l2tp_session_find(sock_net(sk), tunnel, session_id); | 694 | * been connected yet. |
| 693 | if (session == NULL) { | ||
| 694 | /* Default MTU must allow space for UDP/L2TP/PPP | ||
| 695 | * headers. | ||
| 696 | */ | 695 | */ |
| 697 | cfg.mtu = cfg.mru = 1500 - PPPOL2TP_HEADER_OVERHEAD; | 696 | if (ps->sock) { |
| 697 | error = -EEXIST; | ||
| 698 | goto end; | ||
| 699 | } | ||
| 698 | 700 | ||
| 699 | /* Allocate and initialize a new session context. */ | 701 | /* consistency checks */ |
| 700 | session = l2tp_session_create(sizeof(struct pppol2tp_session), | 702 | if (ps->tunnel_sock != tunnel->sock) { |
| 701 | tunnel, session_id, | 703 | error = -EEXIST; |
| 702 | peer_session_id, &cfg); | ||
| 703 | if (session == NULL) { | ||
| 704 | error = -ENOMEM; | ||
| 705 | goto end; | 704 | goto end; |
| 706 | } | 705 | } |
| 707 | } else { | 706 | } else { |
| 708 | ps = l2tp_session_priv(session); | 707 | /* Default MTU must allow space for UDP/L2TP/PPP headers */ |
| 709 | error = -EEXIST; | 708 | cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; |
| 710 | if (ps->sock != NULL) | 709 | cfg.mru = cfg.mtu; |
| 711 | goto end; | ||
| 712 | 710 | ||
| 713 | /* consistency checks */ | 711 | session = l2tp_session_create(sizeof(struct pppol2tp_session), |
| 714 | if (ps->tunnel_sock != tunnel->sock) | 712 | tunnel, session_id, |
| 713 | peer_session_id, &cfg); | ||
| 714 | if (IS_ERR(session)) { | ||
| 715 | error = PTR_ERR(session); | ||
| 715 | goto end; | 716 | goto end; |
| 717 | } | ||
| 716 | } | 718 | } |
| 717 | 719 | ||
| 718 | /* Associate session with its PPPoL2TP socket */ | 720 | /* Associate session with its PPPoL2TP socket */ |
| @@ -777,6 +779,8 @@ out_no_ppp: | |||
| 777 | session->name); | 779 | session->name); |
| 778 | 780 | ||
| 779 | end: | 781 | end: |
| 782 | if (drop_refcnt) | ||
| 783 | l2tp_session_dec_refcount(session); | ||
| 780 | release_sock(sk); | 784 | release_sock(sk); |
| 781 | 785 | ||
| 782 | return error; | 786 | return error; |
| @@ -804,12 +808,6 @@ static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_i | |||
| 804 | if (tunnel->sock == NULL) | 808 | if (tunnel->sock == NULL) |
| 805 | goto out; | 809 | goto out; |
| 806 | 810 | ||
| 807 | /* Check that this session doesn't already exist */ | ||
| 808 | error = -EEXIST; | ||
| 809 | session = l2tp_session_find(net, tunnel, session_id); | ||
| 810 | if (session != NULL) | ||
| 811 | goto out; | ||
| 812 | |||
| 813 | /* Default MTU values. */ | 811 | /* Default MTU values. */ |
| 814 | if (cfg->mtu == 0) | 812 | if (cfg->mtu == 0) |
| 815 | cfg->mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; | 813 | cfg->mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; |
| @@ -817,12 +815,13 @@ static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_i | |||
| 817 | cfg->mru = cfg->mtu; | 815 | cfg->mru = cfg->mtu; |
| 818 | 816 | ||
| 819 | /* Allocate and initialize a new session context. */ | 817 | /* Allocate and initialize a new session context. */ |
| 820 | error = -ENOMEM; | ||
| 821 | session = l2tp_session_create(sizeof(struct pppol2tp_session), | 818 | session = l2tp_session_create(sizeof(struct pppol2tp_session), |
| 822 | tunnel, session_id, | 819 | tunnel, session_id, |
| 823 | peer_session_id, cfg); | 820 | peer_session_id, cfg); |
| 824 | if (session == NULL) | 821 | if (IS_ERR(session)) { |
| 822 | error = PTR_ERR(session); | ||
| 825 | goto out; | 823 | goto out; |
| 824 | } | ||
| 826 | 825 | ||
| 827 | ps = l2tp_session_priv(session); | 826 | ps = l2tp_session_priv(session); |
| 828 | ps->tunnel_sock = tunnel->sock; | 827 | ps->tunnel_sock = tunnel->sock; |
| @@ -1140,11 +1139,18 @@ static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel, | |||
| 1140 | if (stats.session_id != 0) { | 1139 | if (stats.session_id != 0) { |
| 1141 | /* resend to session ioctl handler */ | 1140 | /* resend to session ioctl handler */ |
| 1142 | struct l2tp_session *session = | 1141 | struct l2tp_session *session = |
| 1143 | l2tp_session_find(sock_net(sk), tunnel, stats.session_id); | 1142 | l2tp_session_get(sock_net(sk), tunnel, |
| 1144 | if (session != NULL) | 1143 | stats.session_id, true); |
| 1145 | err = pppol2tp_session_ioctl(session, cmd, arg); | 1144 | |
| 1146 | else | 1145 | if (session) { |
| 1146 | err = pppol2tp_session_ioctl(session, cmd, | ||
| 1147 | arg); | ||
| 1148 | if (session->deref) | ||
| 1149 | session->deref(session); | ||
| 1150 | l2tp_session_dec_refcount(session); | ||
| 1151 | } else { | ||
| 1147 | err = -EBADR; | 1152 | err = -EBADR; |
| 1153 | } | ||
| 1148 | break; | 1154 | break; |
| 1149 | } | 1155 | } |
| 1150 | #ifdef CONFIG_XFRM | 1156 | #ifdef CONFIG_XFRM |
| @@ -1554,7 +1560,7 @@ static void pppol2tp_next_tunnel(struct net *net, struct pppol2tp_seq_data *pd) | |||
| 1554 | 1560 | ||
| 1555 | static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd) | 1561 | static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd) |
| 1556 | { | 1562 | { |
| 1557 | pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx); | 1563 | pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx, true); |
| 1558 | pd->session_idx++; | 1564 | pd->session_idx++; |
| 1559 | 1565 | ||
| 1560 | if (pd->session == NULL) { | 1566 | if (pd->session == NULL) { |
| @@ -1681,10 +1687,14 @@ static int pppol2tp_seq_show(struct seq_file *m, void *v) | |||
| 1681 | 1687 | ||
| 1682 | /* Show the tunnel or session context. | 1688 | /* Show the tunnel or session context. |
| 1683 | */ | 1689 | */ |
| 1684 | if (pd->session == NULL) | 1690 | if (!pd->session) { |
| 1685 | pppol2tp_seq_tunnel_show(m, pd->tunnel); | 1691 | pppol2tp_seq_tunnel_show(m, pd->tunnel); |
| 1686 | else | 1692 | } else { |
| 1687 | pppol2tp_seq_session_show(m, pd->session); | 1693 | pppol2tp_seq_session_show(m, pd->session); |
| 1694 | if (pd->session->deref) | ||
| 1695 | pd->session->deref(pd->session); | ||
| 1696 | l2tp_session_dec_refcount(pd->session); | ||
| 1697 | } | ||
| 1688 | 1698 | ||
| 1689 | out: | 1699 | out: |
| 1690 | return 0; | 1700 | return 0; |
| @@ -1843,4 +1853,4 @@ MODULE_DESCRIPTION("PPP over L2TP over UDP"); | |||
| 1843 | MODULE_LICENSE("GPL"); | 1853 | MODULE_LICENSE("GPL"); |
| 1844 | MODULE_VERSION(PPPOL2TP_DRV_VERSION); | 1854 | MODULE_VERSION(PPPOL2TP_DRV_VERSION); |
| 1845 | MODULE_ALIAS_NET_PF_PROTO(PF_PPPOX, PX_PROTO_OL2TP); | 1855 | MODULE_ALIAS_NET_PF_PROTO(PF_PPPOX, PX_PROTO_OL2TP); |
| 1846 | MODULE_ALIAS_L2TP_PWTYPE(11); | 1856 | MODULE_ALIAS_L2TP_PWTYPE(7); |
