diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-20 13:43:21 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-20 13:43:21 -0700 |
commit | 06f4e926d256d902dd9a53dcb400fd74974ce087 (patch) | |
tree | 0b438b67f5f0eff6fd617bc497a9dace6164a488 /net/l2tp/l2tp_ip.c | |
parent | 8e7bfcbab3825d1b404d615cb1b54f44ff81f981 (diff) | |
parent | d93515611bbc70c2fe4db232e5feb448ed8e4cc9 (diff) | |
download | linux-06f4e926d256d902dd9a53dcb400fd74974ce087.tar.bz2 |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1446 commits)
macvlan: fix panic if lowerdev in a bond
tg3: Add braces around 5906 workaround.
tg3: Fix NETIF_F_LOOPBACK error
macvlan: remove one synchronize_rcu() call
networking: NET_CLS_ROUTE4 depends on INET
irda: Fix error propagation in ircomm_lmp_connect_response()
irda: Kill set but unused variable 'bytes' in irlan_check_command_param()
irda: Kill set but unused variable 'clen' in ircomm_connect_indication()
rxrpc: Fix set but unused variable 'usage' in rxrpc_get_transport()
be2net: Kill set but unused variable 'req' in lancer_fw_download()
irda: Kill set but unused vars 'saddr' and 'daddr' in irlan_provider_connect_indication()
atl1c: atl1c_resume() is only used when CONFIG_PM_SLEEP is defined.
rxrpc: Fix set but unused variable 'usage' in rxrpc_get_peer().
rxrpc: Kill set but unused variable 'local' in rxrpc_UDP_error_handler()
rxrpc: Kill set but unused variable 'sp' in rxrpc_process_connection()
rxrpc: Kill set but unused variable 'sp' in rxrpc_rotate_tx_window()
pkt_sched: Kill set but unused variable 'protocol' in tc_classify()
isdn: capi: Use pr_debug() instead of ifdefs.
tg3: Update version to 3.119
tg3: Apply rx_discards fix to 5719/5720
...
Fix up trivial conflicts in arch/x86/Kconfig and net/mac80211/agg-tx.c
as per Davem.
Diffstat (limited to 'net/l2tp/l2tp_ip.c')
-rw-r--r-- | net/l2tp/l2tp_ip.c | 52 |
1 files changed, 36 insertions, 16 deletions
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: static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { - int rc; - struct inet_sock *inet = inet_sk(sk); struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr; + struct inet_sock *inet = inet_sk(sk); + struct flowi4 *fl4; struct rtable *rt; __be32 saddr; - int oif; + int oif, rc; rc = -EINVAL; if (addr_len < sizeof(*lsa)) @@ -311,6 +311,8 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len if (lsa->l2tp_family != AF_INET) goto out; + lock_sock(sk); + sk_dst_reset(sk); oif = sk->sk_bound_dev_if; @@ -320,7 +322,8 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len if (ipv4_is_multicast(lsa->l2tp_addr.s_addr)) goto out; - rt = ip_route_connect(lsa->l2tp_addr.s_addr, saddr, + fl4 = &inet->cork.fl.u.ip4; + rt = ip_route_connect(fl4, lsa->l2tp_addr.s_addr, saddr, RT_CONN_FLAGS(sk), oif, IPPROTO_L2TP, 0, 0, sk, true); @@ -340,10 +343,10 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id; if (!inet->inet_saddr) - inet->inet_saddr = rt->rt_src; + inet->inet_saddr = fl4->saddr; if (!inet->inet_rcv_saddr) - inet->inet_rcv_saddr = rt->rt_src; - inet->inet_daddr = rt->rt_dst; + inet->inet_rcv_saddr = fl4->saddr; + inet->inet_daddr = fl4->daddr; sk->sk_state = TCP_ESTABLISHED; inet->inet_id = jiffies; @@ -356,6 +359,7 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len rc = 0; out: + release_sock(sk); return rc; } @@ -416,23 +420,28 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m int rc; struct l2tp_ip_sock *lsa = l2tp_ip_sk(sk); struct inet_sock *inet = inet_sk(sk); - struct ip_options *opt = inet->opt; struct rtable *rt = NULL; + struct flowi4 *fl4; int connected = 0; __be32 daddr; + lock_sock(sk); + + rc = -ENOTCONN; if (sock_flag(sk, SOCK_DEAD)) - return -ENOTCONN; + goto out; /* Get and verify the address. */ if (msg->msg_name) { struct sockaddr_l2tpip *lip = (struct sockaddr_l2tpip *) msg->msg_name; + rc = -EINVAL; if (msg->msg_namelen < sizeof(*lip)) - return -EINVAL; + goto out; if (lip->l2tp_family != AF_INET) { + rc = -EAFNOSUPPORT; if (lip->l2tp_family != AF_UNSPEC) - return -EAFNOSUPPORT; + goto out; } daddr = lip->l2tp_addr.s_addr; @@ -467,19 +476,27 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m goto error; } + fl4 = &inet->cork.fl.u.ip4; if (connected) rt = (struct rtable *) __sk_dst_check(sk, 0); if (rt == NULL) { + struct ip_options_rcu *inet_opt; + + rcu_read_lock(); + inet_opt = rcu_dereference(inet->inet_opt); + /* Use correct destination address if we have options. */ - if (opt && opt->srr) - daddr = opt->faddr; + if (inet_opt && inet_opt->opt.srr) + daddr = inet_opt->opt.faddr; + + rcu_read_unlock(); /* If this fails, retransmit mechanism of transport layer will * keep trying until route appears or the connection times * itself out. */ - rt = ip_route_output_ports(sock_net(sk), sk, + rt = ip_route_output_ports(sock_net(sk), fl4, sk, daddr, inet->inet_saddr, inet->inet_dport, inet->inet_sport, 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 skb_dst_set(skb, dst_clone(&rt->dst)); /* Queue the packet to IP for output */ - rc = ip_queue_xmit(skb); + rc = ip_queue_xmit(skb, &inet->cork.fl); error: /* Update stats */ @@ -503,12 +520,15 @@ error: lsa->tx_errors++; } +out: + release_sock(sk); return rc; no_route: IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); kfree_skb(skb); - return -EHOSTUNREACH; + rc = -EHOSTUNREACH; + goto out; } static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |