diff options
Diffstat (limited to 'net/l2tp')
-rw-r--r-- | net/l2tp/l2tp_core.c | 28 | ||||
-rw-r--r-- | net/l2tp/l2tp_ip.c | 52 | ||||
-rw-r--r-- | net/l2tp/l2tp_netlink.c | 3 |
3 files changed, 56 insertions, 27 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index c64ce0a0bb03..ed8a2335442f 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c | |||
@@ -954,7 +954,7 @@ static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf) | |||
954 | } | 954 | } |
955 | 955 | ||
956 | static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, | 956 | static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, |
957 | size_t data_len) | 957 | struct flowi *fl, size_t data_len) |
958 | { | 958 | { |
959 | struct l2tp_tunnel *tunnel = session->tunnel; | 959 | struct l2tp_tunnel *tunnel = session->tunnel; |
960 | unsigned int len = skb->len; | 960 | unsigned int len = skb->len; |
@@ -987,7 +987,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, | |||
987 | 987 | ||
988 | /* Queue the packet to IP for output */ | 988 | /* Queue the packet to IP for output */ |
989 | skb->local_df = 1; | 989 | skb->local_df = 1; |
990 | error = ip_queue_xmit(skb); | 990 | error = ip_queue_xmit(skb, fl); |
991 | 991 | ||
992 | /* Update stats */ | 992 | /* Update stats */ |
993 | if (error >= 0) { | 993 | if (error >= 0) { |
@@ -1028,6 +1028,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len | |||
1028 | int data_len = skb->len; | 1028 | int data_len = skb->len; |
1029 | struct l2tp_tunnel *tunnel = session->tunnel; | 1029 | struct l2tp_tunnel *tunnel = session->tunnel; |
1030 | struct sock *sk = tunnel->sock; | 1030 | struct sock *sk = tunnel->sock; |
1031 | struct flowi *fl; | ||
1031 | struct udphdr *uh; | 1032 | struct udphdr *uh; |
1032 | struct inet_sock *inet; | 1033 | struct inet_sock *inet; |
1033 | __wsum csum; | 1034 | __wsum csum; |
@@ -1060,14 +1061,21 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len | |||
1060 | IPSKB_REROUTED); | 1061 | IPSKB_REROUTED); |
1061 | nf_reset(skb); | 1062 | nf_reset(skb); |
1062 | 1063 | ||
1064 | bh_lock_sock(sk); | ||
1065 | if (sock_owned_by_user(sk)) { | ||
1066 | dev_kfree_skb(skb); | ||
1067 | goto out_unlock; | ||
1068 | } | ||
1069 | |||
1063 | /* Get routing info from the tunnel socket */ | 1070 | /* Get routing info from the tunnel socket */ |
1064 | skb_dst_drop(skb); | 1071 | skb_dst_drop(skb); |
1065 | skb_dst_set(skb, dst_clone(__sk_dst_get(sk))); | 1072 | skb_dst_set(skb, dst_clone(__sk_dst_get(sk))); |
1066 | 1073 | ||
1074 | inet = inet_sk(sk); | ||
1075 | fl = &inet->cork.fl; | ||
1067 | switch (tunnel->encap) { | 1076 | switch (tunnel->encap) { |
1068 | case L2TP_ENCAPTYPE_UDP: | 1077 | case L2TP_ENCAPTYPE_UDP: |
1069 | /* Setup UDP header */ | 1078 | /* Setup UDP header */ |
1070 | inet = inet_sk(sk); | ||
1071 | __skb_push(skb, sizeof(*uh)); | 1079 | __skb_push(skb, sizeof(*uh)); |
1072 | skb_reset_transport_header(skb); | 1080 | skb_reset_transport_header(skb); |
1073 | uh = udp_hdr(skb); | 1081 | uh = udp_hdr(skb); |
@@ -1105,7 +1113,9 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len | |||
1105 | 1113 | ||
1106 | l2tp_skb_set_owner_w(skb, sk); | 1114 | l2tp_skb_set_owner_w(skb, sk); |
1107 | 1115 | ||
1108 | l2tp_xmit_core(session, skb, data_len); | 1116 | l2tp_xmit_core(session, skb, fl, data_len); |
1117 | out_unlock: | ||
1118 | bh_unlock_sock(sk); | ||
1109 | 1119 | ||
1110 | abort: | 1120 | abort: |
1111 | return 0; | 1121 | return 0; |
@@ -1425,16 +1435,15 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 | |||
1425 | 1435 | ||
1426 | /* Add tunnel to our list */ | 1436 | /* Add tunnel to our list */ |
1427 | INIT_LIST_HEAD(&tunnel->list); | 1437 | INIT_LIST_HEAD(&tunnel->list); |
1428 | spin_lock_bh(&pn->l2tp_tunnel_list_lock); | ||
1429 | list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list); | ||
1430 | spin_unlock_bh(&pn->l2tp_tunnel_list_lock); | ||
1431 | synchronize_rcu(); | ||
1432 | atomic_inc(&l2tp_tunnel_count); | 1438 | atomic_inc(&l2tp_tunnel_count); |
1433 | 1439 | ||
1434 | /* Bump the reference count. The tunnel context is deleted | 1440 | /* Bump the reference count. The tunnel context is deleted |
1435 | * only when this drops to zero. | 1441 | * only when this drops to zero. Must be done before list insertion |
1436 | */ | 1442 | */ |
1437 | l2tp_tunnel_inc_refcount(tunnel); | 1443 | l2tp_tunnel_inc_refcount(tunnel); |
1444 | spin_lock_bh(&pn->l2tp_tunnel_list_lock); | ||
1445 | list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list); | ||
1446 | spin_unlock_bh(&pn->l2tp_tunnel_list_lock); | ||
1438 | 1447 | ||
1439 | err = 0; | 1448 | err = 0; |
1440 | err: | 1449 | err: |
@@ -1626,7 +1635,6 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn | |||
1626 | hlist_add_head_rcu(&session->global_hlist, | 1635 | hlist_add_head_rcu(&session->global_hlist, |
1627 | l2tp_session_id_hash_2(pn, session_id)); | 1636 | l2tp_session_id_hash_2(pn, session_id)); |
1628 | spin_unlock_bh(&pn->l2tp_session_hlist_lock); | 1637 | spin_unlock_bh(&pn->l2tp_session_hlist_lock); |
1629 | synchronize_rcu(); | ||
1630 | } | 1638 | } |
1631 | 1639 | ||
1632 | /* Ignore management session in session count value */ | 1640 | /* Ignore management session in session count value */ |
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 5c04f3e42704..b6466e71f5e1 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c | |||
@@ -296,12 +296,12 @@ out_in_use: | |||
296 | 296 | ||
297 | static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | 297 | static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) |
298 | { | 298 | { |
299 | int rc; | ||
300 | struct inet_sock *inet = inet_sk(sk); | ||
301 | struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr; | 299 | struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr; |
300 | struct inet_sock *inet = inet_sk(sk); | ||
301 | struct flowi4 *fl4; | ||
302 | struct rtable *rt; | 302 | struct rtable *rt; |
303 | __be32 saddr; | 303 | __be32 saddr; |
304 | int oif; | 304 | int oif, rc; |
305 | 305 | ||
306 | rc = -EINVAL; | 306 | rc = -EINVAL; |
307 | if (addr_len < sizeof(*lsa)) | 307 | if (addr_len < sizeof(*lsa)) |
@@ -311,6 +311,8 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len | |||
311 | if (lsa->l2tp_family != AF_INET) | 311 | if (lsa->l2tp_family != AF_INET) |
312 | goto out; | 312 | goto out; |
313 | 313 | ||
314 | lock_sock(sk); | ||
315 | |||
314 | sk_dst_reset(sk); | 316 | sk_dst_reset(sk); |
315 | 317 | ||
316 | oif = sk->sk_bound_dev_if; | 318 | oif = sk->sk_bound_dev_if; |
@@ -320,7 +322,8 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len | |||
320 | if (ipv4_is_multicast(lsa->l2tp_addr.s_addr)) | 322 | if (ipv4_is_multicast(lsa->l2tp_addr.s_addr)) |
321 | goto out; | 323 | goto out; |
322 | 324 | ||
323 | rt = ip_route_connect(lsa->l2tp_addr.s_addr, saddr, | 325 | fl4 = &inet->cork.fl.u.ip4; |
326 | rt = ip_route_connect(fl4, lsa->l2tp_addr.s_addr, saddr, | ||
324 | RT_CONN_FLAGS(sk), oif, | 327 | RT_CONN_FLAGS(sk), oif, |
325 | IPPROTO_L2TP, | 328 | IPPROTO_L2TP, |
326 | 0, 0, sk, true); | 329 | 0, 0, sk, true); |
@@ -340,10 +343,10 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len | |||
340 | l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id; | 343 | l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id; |
341 | 344 | ||
342 | if (!inet->inet_saddr) | 345 | if (!inet->inet_saddr) |
343 | inet->inet_saddr = rt->rt_src; | 346 | inet->inet_saddr = fl4->saddr; |
344 | if (!inet->inet_rcv_saddr) | 347 | if (!inet->inet_rcv_saddr) |
345 | inet->inet_rcv_saddr = rt->rt_src; | 348 | inet->inet_rcv_saddr = fl4->saddr; |
346 | inet->inet_daddr = rt->rt_dst; | 349 | inet->inet_daddr = fl4->daddr; |
347 | sk->sk_state = TCP_ESTABLISHED; | 350 | sk->sk_state = TCP_ESTABLISHED; |
348 | inet->inet_id = jiffies; | 351 | inet->inet_id = jiffies; |
349 | 352 | ||
@@ -356,6 +359,7 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len | |||
356 | 359 | ||
357 | rc = 0; | 360 | rc = 0; |
358 | out: | 361 | out: |
362 | release_sock(sk); | ||
359 | return rc; | 363 | return rc; |
360 | } | 364 | } |
361 | 365 | ||
@@ -416,23 +420,28 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m | |||
416 | int rc; | 420 | int rc; |
417 | struct l2tp_ip_sock *lsa = l2tp_ip_sk(sk); | 421 | struct l2tp_ip_sock *lsa = l2tp_ip_sk(sk); |
418 | struct inet_sock *inet = inet_sk(sk); | 422 | struct inet_sock *inet = inet_sk(sk); |
419 | struct ip_options *opt = inet->opt; | ||
420 | struct rtable *rt = NULL; | 423 | struct rtable *rt = NULL; |
424 | struct flowi4 *fl4; | ||
421 | int connected = 0; | 425 | int connected = 0; |
422 | __be32 daddr; | 426 | __be32 daddr; |
423 | 427 | ||
428 | lock_sock(sk); | ||
429 | |||
430 | rc = -ENOTCONN; | ||
424 | if (sock_flag(sk, SOCK_DEAD)) | 431 | if (sock_flag(sk, SOCK_DEAD)) |
425 | return -ENOTCONN; | 432 | goto out; |
426 | 433 | ||
427 | /* Get and verify the address. */ | 434 | /* Get and verify the address. */ |
428 | if (msg->msg_name) { | 435 | if (msg->msg_name) { |
429 | struct sockaddr_l2tpip *lip = (struct sockaddr_l2tpip *) msg->msg_name; | 436 | struct sockaddr_l2tpip *lip = (struct sockaddr_l2tpip *) msg->msg_name; |
437 | rc = -EINVAL; | ||
430 | if (msg->msg_namelen < sizeof(*lip)) | 438 | if (msg->msg_namelen < sizeof(*lip)) |
431 | return -EINVAL; | 439 | goto out; |
432 | 440 | ||
433 | if (lip->l2tp_family != AF_INET) { | 441 | if (lip->l2tp_family != AF_INET) { |
442 | rc = -EAFNOSUPPORT; | ||
434 | if (lip->l2tp_family != AF_UNSPEC) | 443 | if (lip->l2tp_family != AF_UNSPEC) |
435 | return -EAFNOSUPPORT; | 444 | goto out; |
436 | } | 445 | } |
437 | 446 | ||
438 | daddr = lip->l2tp_addr.s_addr; | 447 | daddr = lip->l2tp_addr.s_addr; |
@@ -467,19 +476,27 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m | |||
467 | goto error; | 476 | goto error; |
468 | } | 477 | } |
469 | 478 | ||
479 | fl4 = &inet->cork.fl.u.ip4; | ||
470 | if (connected) | 480 | if (connected) |
471 | rt = (struct rtable *) __sk_dst_check(sk, 0); | 481 | rt = (struct rtable *) __sk_dst_check(sk, 0); |
472 | 482 | ||
473 | if (rt == NULL) { | 483 | if (rt == NULL) { |
484 | struct ip_options_rcu *inet_opt; | ||
485 | |||
486 | rcu_read_lock(); | ||
487 | inet_opt = rcu_dereference(inet->inet_opt); | ||
488 | |||
474 | /* Use correct destination address if we have options. */ | 489 | /* Use correct destination address if we have options. */ |
475 | if (opt && opt->srr) | 490 | if (inet_opt && inet_opt->opt.srr) |
476 | daddr = opt->faddr; | 491 | daddr = inet_opt->opt.faddr; |
492 | |||
493 | rcu_read_unlock(); | ||
477 | 494 | ||
478 | /* If this fails, retransmit mechanism of transport layer will | 495 | /* If this fails, retransmit mechanism of transport layer will |
479 | * keep trying until route appears or the connection times | 496 | * keep trying until route appears or the connection times |
480 | * itself out. | 497 | * itself out. |
481 | */ | 498 | */ |
482 | rt = ip_route_output_ports(sock_net(sk), sk, | 499 | rt = ip_route_output_ports(sock_net(sk), fl4, sk, |
483 | daddr, inet->inet_saddr, | 500 | daddr, inet->inet_saddr, |
484 | inet->inet_dport, inet->inet_sport, | 501 | inet->inet_dport, inet->inet_sport, |
485 | sk->sk_protocol, RT_CONN_FLAGS(sk), | 502 | sk->sk_protocol, RT_CONN_FLAGS(sk), |
@@ -491,7 +508,7 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m | |||
491 | skb_dst_set(skb, dst_clone(&rt->dst)); | 508 | skb_dst_set(skb, dst_clone(&rt->dst)); |
492 | 509 | ||
493 | /* Queue the packet to IP for output */ | 510 | /* Queue the packet to IP for output */ |
494 | rc = ip_queue_xmit(skb); | 511 | rc = ip_queue_xmit(skb, &inet->cork.fl); |
495 | 512 | ||
496 | error: | 513 | error: |
497 | /* Update stats */ | 514 | /* Update stats */ |
@@ -503,12 +520,15 @@ error: | |||
503 | lsa->tx_errors++; | 520 | lsa->tx_errors++; |
504 | } | 521 | } |
505 | 522 | ||
523 | out: | ||
524 | release_sock(sk); | ||
506 | return rc; | 525 | return rc; |
507 | 526 | ||
508 | no_route: | 527 | no_route: |
509 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); | 528 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); |
510 | kfree_skb(skb); | 529 | kfree_skb(skb); |
511 | return -EHOSTUNREACH; | 530 | rc = -EHOSTUNREACH; |
531 | goto out; | ||
512 | } | 532 | } |
513 | 533 | ||
514 | static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 534 | static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index 4c1e540732d7..93a41a09458b 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c | |||
@@ -795,11 +795,12 @@ int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops | |||
795 | goto out; | 795 | goto out; |
796 | 796 | ||
797 | l2tp_nl_cmd_ops[pw_type] = ops; | 797 | l2tp_nl_cmd_ops[pw_type] = ops; |
798 | ret = 0; | ||
798 | 799 | ||
799 | out: | 800 | out: |
800 | genl_unlock(); | 801 | genl_unlock(); |
801 | err: | 802 | err: |
802 | return 0; | 803 | return ret; |
803 | } | 804 | } |
804 | EXPORT_SYMBOL_GPL(l2tp_nl_register_ops); | 805 | EXPORT_SYMBOL_GPL(l2tp_nl_register_ops); |
805 | 806 | ||