aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/l2tp/l2tp_core.c70
-rw-r--r--net/l2tp/l2tp_eth.c10
-rw-r--r--net/l2tp/l2tp_ppp.c60
3 files changed, 84 insertions, 56 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 8a067536d15c..46b450a1bc21 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -374,6 +374,48 @@ struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname)
374} 374}
375EXPORT_SYMBOL_GPL(l2tp_session_find_by_ifname); 375EXPORT_SYMBOL_GPL(l2tp_session_find_by_ifname);
376 376
377static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel,
378 struct l2tp_session *session)
379{
380 struct l2tp_session *session_walk;
381 struct hlist_head *g_head;
382 struct hlist_head *head;
383 struct l2tp_net *pn;
384
385 head = l2tp_session_id_hash(tunnel, session->session_id);
386
387 write_lock_bh(&tunnel->hlist_lock);
388 hlist_for_each_entry(session_walk, head, hlist)
389 if (session_walk->session_id == session->session_id)
390 goto exist;
391
392 if (tunnel->version == L2TP_HDR_VER_3) {
393 pn = l2tp_pernet(tunnel->l2tp_net);
394 g_head = l2tp_session_id_hash_2(l2tp_pernet(tunnel->l2tp_net),
395 session->session_id);
396
397 spin_lock_bh(&pn->l2tp_session_hlist_lock);
398 hlist_for_each_entry(session_walk, g_head, global_hlist)
399 if (session_walk->session_id == session->session_id)
400 goto exist_glob;
401
402 hlist_add_head_rcu(&session->global_hlist, g_head);
403 spin_unlock_bh(&pn->l2tp_session_hlist_lock);
404 }
405
406 hlist_add_head(&session->hlist, head);
407 write_unlock_bh(&tunnel->hlist_lock);
408
409 return 0;
410
411exist_glob:
412 spin_unlock_bh(&pn->l2tp_session_hlist_lock);
413exist:
414 write_unlock_bh(&tunnel->hlist_lock);
415
416 return -EEXIST;
417}
418
377/* Lookup a tunnel by id 419/* Lookup a tunnel by id
378 */ 420 */
379struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id) 421struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id)
@@ -1785,6 +1827,7 @@ EXPORT_SYMBOL_GPL(l2tp_session_set_header_len);
1785struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) 1827struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
1786{ 1828{
1787 struct l2tp_session *session; 1829 struct l2tp_session *session;
1830 int err;
1788 1831
1789 session = kzalloc(sizeof(struct l2tp_session) + priv_size, GFP_KERNEL); 1832 session = kzalloc(sizeof(struct l2tp_session) + priv_size, GFP_KERNEL);
1790 if (session != NULL) { 1833 if (session != NULL) {
@@ -1840,6 +1883,13 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn
1840 1883
1841 l2tp_session_set_header_len(session, tunnel->version); 1884 l2tp_session_set_header_len(session, tunnel->version);
1842 1885
1886 err = l2tp_session_add_to_tunnel(tunnel, session);
1887 if (err) {
1888 kfree(session);
1889
1890 return ERR_PTR(err);
1891 }
1892
1843 /* Bump the reference count. The session context is deleted 1893 /* Bump the reference count. The session context is deleted
1844 * only when this drops to zero. 1894 * only when this drops to zero.
1845 */ 1895 */
@@ -1849,28 +1899,14 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn
1849 /* Ensure tunnel socket isn't deleted */ 1899 /* Ensure tunnel socket isn't deleted */
1850 sock_hold(tunnel->sock); 1900 sock_hold(tunnel->sock);
1851 1901
1852 /* Add session to the tunnel's hash list */
1853 write_lock_bh(&tunnel->hlist_lock);
1854 hlist_add_head(&session->hlist,
1855 l2tp_session_id_hash(tunnel, session_id));
1856 write_unlock_bh(&tunnel->hlist_lock);
1857
1858 /* And to the global session list if L2TPv3 */
1859 if (tunnel->version != L2TP_HDR_VER_2) {
1860 struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
1861
1862 spin_lock_bh(&pn->l2tp_session_hlist_lock);
1863 hlist_add_head_rcu(&session->global_hlist,
1864 l2tp_session_id_hash_2(pn, session_id));
1865 spin_unlock_bh(&pn->l2tp_session_hlist_lock);
1866 }
1867
1868 /* Ignore management session in session count value */ 1902 /* Ignore management session in session count value */
1869 if (session->session_id != 0) 1903 if (session->session_id != 0)
1870 atomic_inc(&l2tp_session_count); 1904 atomic_inc(&l2tp_session_count);
1905
1906 return session;
1871 } 1907 }
1872 1908
1873 return session; 1909 return ERR_PTR(-ENOMEM);
1874} 1910}
1875EXPORT_SYMBOL_GPL(l2tp_session_create); 1911EXPORT_SYMBOL_GPL(l2tp_session_create);
1876 1912
diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c
index 8bf18a5f66e0..6fd41d7afe1e 100644
--- a/net/l2tp/l2tp_eth.c
+++ b/net/l2tp/l2tp_eth.c
@@ -221,12 +221,6 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p
221 goto out; 221 goto out;
222 } 222 }
223 223
224 session = l2tp_session_find(net, tunnel, session_id);
225 if (session) {
226 rc = -EEXIST;
227 goto out;
228 }
229
230 if (cfg->ifname) { 224 if (cfg->ifname) {
231 dev = dev_get_by_name(net, cfg->ifname); 225 dev = dev_get_by_name(net, cfg->ifname);
232 if (dev) { 226 if (dev) {
@@ -240,8 +234,8 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p
240 234
241 session = l2tp_session_create(sizeof(*spriv), tunnel, session_id, 235 session = l2tp_session_create(sizeof(*spriv), tunnel, session_id,
242 peer_session_id, cfg); 236 peer_session_id, cfg);
243 if (!session) { 237 if (IS_ERR(session)) {
244 rc = -ENOMEM; 238 rc = PTR_ERR(session);
245 goto out; 239 goto out;
246 } 240 }
247 241
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 827e55c41ba2..26501902d1a7 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -583,6 +583,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
583 int error = 0; 583 int error = 0;
584 u32 tunnel_id, peer_tunnel_id; 584 u32 tunnel_id, peer_tunnel_id;
585 u32 session_id, peer_session_id; 585 u32 session_id, peer_session_id;
586 bool drop_refcnt = false;
586 int ver = 2; 587 int ver = 2;
587 int fd; 588 int fd;
588 589
@@ -684,36 +685,36 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
684 if (tunnel->peer_tunnel_id == 0) 685 if (tunnel->peer_tunnel_id == 0)
685 tunnel->peer_tunnel_id = peer_tunnel_id; 686 tunnel->peer_tunnel_id = peer_tunnel_id;
686 687
687 /* Create session if it doesn't already exist. We handle the 688 session = l2tp_session_get(sock_net(sk), tunnel, session_id, false);
688 * case where a session was previously created by the netlink 689 if (session) {
689 * interface by checking that the session doesn't already have 690 drop_refcnt = true;
690 * a socket and its tunnel socket are what we expect. If any 691 ps = l2tp_session_priv(session);
691 * of those checks fail, return EEXIST to the caller. 692
692 */ 693 /* Using a pre-existing session is fine as long as it hasn't
693 session = l2tp_session_find(sock_net(sk), tunnel, session_id); 694 * been connected yet.
694 if (session == NULL) {
695 /* Default MTU must allow space for UDP/L2TP/PPP
696 * headers.
697 */ 695 */
698 cfg.mtu = cfg.mru = 1500 - PPPOL2TP_HEADER_OVERHEAD; 696 if (ps->sock) {
697 error = -EEXIST;
698 goto end;
699 }
699 700
700 /* Allocate and initialize a new session context. */ 701 /* consistency checks */
701 session = l2tp_session_create(sizeof(struct pppol2tp_session), 702 if (ps->tunnel_sock != tunnel->sock) {
702 tunnel, session_id, 703 error = -EEXIST;
703 peer_session_id, &cfg);
704 if (session == NULL) {
705 error = -ENOMEM;
706 goto end; 704 goto end;
707 } 705 }
708 } else { 706 } else {
709 ps = l2tp_session_priv(session); 707 /* Default MTU must allow space for UDP/L2TP/PPP headers */
710 error = -EEXIST; 708 cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD;
711 if (ps->sock != NULL) 709 cfg.mru = cfg.mtu;
712 goto end;
713 710
714 /* consistency checks */ 711 session = l2tp_session_create(sizeof(struct pppol2tp_session),
715 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);
716 goto end; 716 goto end;
717 }
717 } 718 }
718 719
719 /* Associate session with its PPPoL2TP socket */ 720 /* Associate session with its PPPoL2TP socket */
@@ -778,6 +779,8 @@ out_no_ppp:
778 session->name); 779 session->name);
779 780
780end: 781end:
782 if (drop_refcnt)
783 l2tp_session_dec_refcount(session);
781 release_sock(sk); 784 release_sock(sk);
782 785
783 return error; 786 return error;
@@ -805,12 +808,6 @@ static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_i
805 if (tunnel->sock == NULL) 808 if (tunnel->sock == NULL)
806 goto out; 809 goto out;
807 810
808 /* Check that this session doesn't already exist */
809 error = -EEXIST;
810 session = l2tp_session_find(net, tunnel, session_id);
811 if (session != NULL)
812 goto out;
813
814 /* Default MTU values. */ 811 /* Default MTU values. */
815 if (cfg->mtu == 0) 812 if (cfg->mtu == 0)
816 cfg->mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; 813 cfg->mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD;
@@ -818,12 +815,13 @@ static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_i
818 cfg->mru = cfg->mtu; 815 cfg->mru = cfg->mtu;
819 816
820 /* Allocate and initialize a new session context. */ 817 /* Allocate and initialize a new session context. */
821 error = -ENOMEM;
822 session = l2tp_session_create(sizeof(struct pppol2tp_session), 818 session = l2tp_session_create(sizeof(struct pppol2tp_session),
823 tunnel, session_id, 819 tunnel, session_id,
824 peer_session_id, cfg); 820 peer_session_id, cfg);
825 if (session == NULL) 821 if (IS_ERR(session)) {
822 error = PTR_ERR(session);
826 goto out; 823 goto out;
824 }
827 825
828 ps = l2tp_session_priv(session); 826 ps = l2tp_session_priv(session);
829 ps->tunnel_sock = tunnel->sock; 827 ps->tunnel_sock = tunnel->sock;