|
@@ -209,19 +209,17 @@ static struct sock *icmp_sk(struct net *net)
|
|
return *this_cpu_ptr(net->ipv4.icmp_sk);
|
|
return *this_cpu_ptr(net->ipv4.icmp_sk);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* Called with BH disabled */
|
|
static inline struct sock *icmp_xmit_lock(struct net *net)
|
|
static inline struct sock *icmp_xmit_lock(struct net *net)
|
|
{
|
|
{
|
|
struct sock *sk;
|
|
struct sock *sk;
|
|
|
|
|
|
- local_bh_disable();
|
|
|
|
-
|
|
|
|
sk = icmp_sk(net);
|
|
sk = icmp_sk(net);
|
|
|
|
|
|
if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
|
|
if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
|
|
/* This can happen if the output path signals a
|
|
/* This can happen if the output path signals a
|
|
* dst_link_failure() for an outgoing ICMP packet.
|
|
* dst_link_failure() for an outgoing ICMP packet.
|
|
*/
|
|
*/
|
|
- local_bh_enable();
|
|
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
return sk;
|
|
return sk;
|
|
@@ -229,7 +227,7 @@ static inline struct sock *icmp_xmit_lock(struct net *net)
|
|
|
|
|
|
static inline void icmp_xmit_unlock(struct sock *sk)
|
|
static inline void icmp_xmit_unlock(struct sock *sk)
|
|
{
|
|
{
|
|
- spin_unlock_bh(&sk->sk_lock.slock);
|
|
|
|
|
|
+ spin_unlock(&sk->sk_lock.slock);
|
|
}
|
|
}
|
|
|
|
|
|
int sysctl_icmp_msgs_per_sec __read_mostly = 1000;
|
|
int sysctl_icmp_msgs_per_sec __read_mostly = 1000;
|
|
@@ -417,14 +415,17 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
|
|
if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb))
|
|
if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb))
|
|
return;
|
|
return;
|
|
|
|
|
|
- sk = icmp_xmit_lock(net);
|
|
|
|
- if (!sk)
|
|
|
|
- return;
|
|
|
|
- inet = inet_sk(sk);
|
|
|
|
|
|
+ /* Needed by both icmp_global_allow and icmp_xmit_lock */
|
|
|
|
+ local_bh_disable();
|
|
|
|
|
|
/* global icmp_msgs_per_sec */
|
|
/* global icmp_msgs_per_sec */
|
|
if (!icmpv4_global_allow(net, type, code))
|
|
if (!icmpv4_global_allow(net, type, code))
|
|
- goto out_unlock;
|
|
|
|
|
|
+ goto out_bh_enable;
|
|
|
|
+
|
|
|
|
+ sk = icmp_xmit_lock(net);
|
|
|
|
+ if (!sk)
|
|
|
|
+ goto out_bh_enable;
|
|
|
|
+ inet = inet_sk(sk);
|
|
|
|
|
|
icmp_param->data.icmph.checksum = 0;
|
|
icmp_param->data.icmph.checksum = 0;
|
|
|
|
|
|
@@ -459,6 +460,8 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
|
|
ip_rt_put(rt);
|
|
ip_rt_put(rt);
|
|
out_unlock:
|
|
out_unlock:
|
|
icmp_xmit_unlock(sk);
|
|
icmp_xmit_unlock(sk);
|
|
|
|
+out_bh_enable:
|
|
|
|
+ local_bh_enable();
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_IP_ROUTE_MULTIPATH
|
|
#ifdef CONFIG_IP_ROUTE_MULTIPATH
|
|
@@ -668,13 +671,16 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- sk = icmp_xmit_lock(net);
|
|
|
|
- if (!sk)
|
|
|
|
- goto out;
|
|
|
|
|
|
+ /* Needed by both icmp_global_allow and icmp_xmit_lock */
|
|
|
|
+ local_bh_disable();
|
|
|
|
|
|
/* Check global sysctl_icmp_msgs_per_sec ratelimit */
|
|
/* Check global sysctl_icmp_msgs_per_sec ratelimit */
|
|
if (!icmpv4_global_allow(net, type, code))
|
|
if (!icmpv4_global_allow(net, type, code))
|
|
- goto out_unlock;
|
|
|
|
|
|
+ goto out_bh_enable;
|
|
|
|
+
|
|
|
|
+ sk = icmp_xmit_lock(net);
|
|
|
|
+ if (!sk)
|
|
|
|
+ goto out_bh_enable;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Construct source address and options.
|
|
* Construct source address and options.
|
|
@@ -750,6 +756,8 @@ ende:
|
|
ip_rt_put(rt);
|
|
ip_rt_put(rt);
|
|
out_unlock:
|
|
out_unlock:
|
|
icmp_xmit_unlock(sk);
|
|
icmp_xmit_unlock(sk);
|
|
|
|
+out_bh_enable:
|
|
|
|
+ local_bh_enable();
|
|
out:;
|
|
out:;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(icmp_send);
|
|
EXPORT_SYMBOL(icmp_send);
|