#include <asm/uaccess.h>
#include <net/checksum.h>
#include <net/xfrm.h>
+#include <net/inet_common.h>
/*
* Build xmit assembly blocks
},
};
-/* Control parameters for ECHO replies. */
-int sysctl_icmp_echo_ignore_all __read_mostly;
-int sysctl_icmp_echo_ignore_broadcasts __read_mostly = 1;
-
-/* Control parameter - ignore bogus broadcast responses? */
-int sysctl_icmp_ignore_bogus_error_responses __read_mostly = 1;
-
-/*
- * Configurable global rate limit.
- *
- * ratelimit defines tokens/packet consumed for dst->rate_token bucket
- * ratemask defines which icmp types are ratelimited by setting
- * it's bit position.
- *
- * default:
- * dest unreachable (3), source quench (4),
- * time exceeded (11), parameter problem (12)
- */
-
-int sysctl_icmp_ratelimit __read_mostly = 1 * HZ;
-int sysctl_icmp_ratemask __read_mostly = 0x1818;
-int sysctl_icmp_errors_use_inbound_ifaddr __read_mostly;
-
/*
* ICMP control array. This specifies what to do with each ICMP.
*/
*
* On SMP we have one ICMP socket per-cpu.
*/
-static DEFINE_PER_CPU(struct sock *, __icmp_sk) = NULL;
-#define icmp_sk __get_cpu_var(__icmp_sk)
+static struct sock *icmp_sk(struct net *net)
+{
+ return net->ipv4.icmp_sk[smp_processor_id()];
+}
-static inline int icmp_xmit_lock(void)
+static inline int icmp_xmit_lock(struct sock *sk)
{
local_bh_disable();
- if (unlikely(!spin_trylock(&icmp_sk->sk_lock.slock))) {
+ if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
/* This can happen if the output path signals a
* dst_link_failure() for an outgoing ICMP packet.
*/
return 0;
}
-static inline void icmp_xmit_unlock(void)
+static inline void icmp_xmit_unlock(struct sock *sk)
{
- spin_unlock_bh(&icmp_sk->sk_lock.slock);
+ spin_unlock_bh(&sk->sk_lock.slock);
}
/*
return rc;
}
-static inline int icmpv4_xrlim_allow(struct rtable *rt, int type, int code)
+static inline int icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
+ int type, int code)
{
struct dst_entry *dst = &rt->u.dst;
int rc = 1;
goto out;
/* Limit if icmp type is enabled in ratemask. */
- if ((1 << type) & sysctl_icmp_ratemask)
- rc = xrlim_allow(dst, sysctl_icmp_ratelimit);
+ if ((1 << type) & net->ipv4.sysctl_icmp_ratemask)
+ rc = xrlim_allow(dst, net->ipv4.sysctl_icmp_ratelimit);
out:
return rc;
}
struct sock *sk;
struct sk_buff *skb;
- sk = icmp_sk;
+ sk = icmp_sk(dev_net(rt->u.dst.dev));
if (ip_append_data(sk, icmp_glue_bits, icmp_param,
icmp_param->data_len+icmp_param->head_len,
icmp_param->head_len,
static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
{
- struct sock *sk = icmp_sk;
- struct inet_sock *inet = inet_sk(sk);
struct ipcm_cookie ipc;
- struct rtable *rt = (struct rtable *)skb->dst;
+ struct rtable *rt = skb->rtable;
+ struct net *net = dev_net(rt->u.dst.dev);
+ struct sock *sk = icmp_sk(net);
+ struct inet_sock *inet = inet_sk(sk);
__be32 daddr;
if (ip_options_echo(&icmp_param->replyopts, skb))
return;
- if (icmp_xmit_lock())
+ if (icmp_xmit_lock(sk))
return;
icmp_param->data.icmph.checksum = 0;
.tos = RT_TOS(ip_hdr(skb)->tos) } },
.proto = IPPROTO_ICMP };
security_skb_classify_flow(skb, &fl);
- if (ip_route_output_key(rt->u.dst.dev->nd_net, &rt, &fl))
+ if (ip_route_output_key(net, &rt, &fl))
goto out_unlock;
}
- if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type,
+ if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type,
icmp_param->data.icmph.code))
icmp_push_reply(icmp_param, &ipc, rt);
ip_rt_put(rt);
out_unlock:
- icmp_xmit_unlock();
+ icmp_xmit_unlock(sk);
}
struct iphdr *iph;
int room;
struct icmp_bxm icmp_param;
- struct rtable *rt = (struct rtable *)skb_in->dst;
+ struct rtable *rt = skb_in->rtable;
struct ipcm_cookie ipc;
__be32 saddr;
u8 tos;
struct net *net;
+ struct sock *sk;
if (!rt)
goto out;
- net = rt->u.dst.dev->nd_net;
+ net = dev_net(rt->u.dst.dev);
+ sk = icmp_sk(net);
/*
* Find the original header. It is expected to be valid, of course.
}
}
- if (icmp_xmit_lock())
+ if (icmp_xmit_lock(sk))
return;
/*
if (!(rt->rt_flags & RTCF_LOCAL)) {
struct net_device *dev = NULL;
- if (rt->fl.iif && sysctl_icmp_errors_use_inbound_ifaddr)
+ if (rt->fl.iif &&
+ net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr)
dev = dev_get_by_index(net, rt->fl.iif);
if (dev) {
icmp_param.data.icmph.checksum = 0;
icmp_param.skb = skb_in;
icmp_param.offset = skb_network_offset(skb_in);
- inet_sk(icmp_sk)->tos = tos;
+ inet_sk(sk)->tos = tos;
ipc.addr = iph->saddr;
ipc.opt = &icmp_param.replyopts;
}
if (xfrm_decode_session_reverse(skb_in, &fl, AF_INET))
- goto out_unlock;
+ goto ende;
if (inet_addr_type(net, fl.fl4_src) == RTN_LOCAL)
err = __ip_route_output_key(net, &rt2, &fl);
fl2.fl4_dst = fl.fl4_src;
if (ip_route_output_key(net, &rt2, &fl2))
- goto out_unlock;
+ goto ende;
/* Ugh! */
odst = skb_in->dst;
RT_TOS(tos), rt2->u.dst.dev);
dst_release(&rt2->u.dst);
- rt2 = (struct rtable *)skb_in->dst;
+ rt2 = skb_in->rtable;
skb_in->dst = odst;
}
if (err)
- goto out_unlock;
+ goto ende;
err = xfrm_lookup((struct dst_entry **)&rt2, &fl, NULL,
XFRM_LOOKUP_ICMP);
}
route_done:
- if (!icmpv4_xrlim_allow(rt, type, code))
+ if (!icmpv4_xrlim_allow(net, rt, type, code))
goto ende;
/* RFC says return as much as we can without exceeding 576 bytes. */
ende:
ip_rt_put(rt);
out_unlock:
- icmp_xmit_unlock();
+ icmp_xmit_unlock(sk);
out:;
}
u32 info = 0;
struct net *net;
- net = skb->dst->dev->nd_net;
+ net = dev_net(skb->dst->dev);
/*
* Incomplete header ?
* get the other vendor to fix their kit.
*/
- if (!sysctl_icmp_ignore_bogus_error_responses &&
+ if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses &&
inet_addr_type(net, iph->daddr) == RTN_BROADCAST) {
if (net_ratelimit())
printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP "
static void icmp_echo(struct sk_buff *skb)
{
- if (!sysctl_icmp_echo_ignore_all) {
+ struct net *net;
+
+ net = dev_net(skb->dst->dev);
+ if (!net->ipv4.sysctl_icmp_echo_ignore_all) {
struct icmp_bxm icmp_param;
icmp_param.data.icmph = *icmp_hdr(skb);
static void icmp_address_reply(struct sk_buff *skb)
{
- struct rtable *rt = (struct rtable *)skb->dst;
+ struct rtable *rt = skb->rtable;
struct net_device *dev = skb->dev;
struct in_device *in_dev;
struct in_ifaddr *ifa;
int icmp_rcv(struct sk_buff *skb)
{
struct icmphdr *icmph;
- struct rtable *rt = (struct rtable *)skb->dst;
+ struct rtable *rt = skb->rtable;
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
int nh;
*/
if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) {
+ struct net *net;
+
+ net = dev_net(rt->u.dst.dev);
/*
* RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be
* silently ignored (we let user decide with a sysctl).
*/
if ((icmph->type == ICMP_ECHO ||
icmph->type == ICMP_TIMESTAMP) &&
- sysctl_icmp_echo_ignore_broadcasts) {
+ net->ipv4.sysctl_icmp_echo_ignore_broadcasts) {
goto error;
}
if (icmph->type != ICMP_ECHO &&
},
};
-static void __exit icmp_exit(void)
+static void __net_exit icmp_sk_exit(struct net *net)
{
int i;
- for_each_possible_cpu(i) {
- struct sock *sk;
-
- sk = per_cpu(__icmp_sk, i);
- if (sk == NULL)
- continue;
- per_cpu(__icmp_sk, i) = NULL;
- sock_release(sk->sk_socket);
- }
+ for_each_possible_cpu(i)
+ inet_ctl_sock_destroy(net->ipv4.icmp_sk[i]);
+ kfree(net->ipv4.icmp_sk);
+ net->ipv4.icmp_sk = NULL;
}
-int __init icmp_init(void)
+int __net_init icmp_sk_init(struct net *net)
{
int i, err;
+ net->ipv4.icmp_sk =
+ kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL);
+ if (net->ipv4.icmp_sk == NULL)
+ return -ENOMEM;
+
for_each_possible_cpu(i) {
struct sock *sk;
- struct socket *sock;
- struct inet_sock *inet;
- err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_ICMP, &sock);
+ err = inet_ctl_sock_create(&sk, PF_INET,
+ SOCK_RAW, IPPROTO_ICMP, net);
if (err < 0)
goto fail;
- per_cpu(__icmp_sk, i) = sk = sock->sk;
- sk->sk_allocation = GFP_ATOMIC;
+ net->ipv4.icmp_sk[i] = sk;
/* Enough space for 2 64K ICMP packets, including
* sk_buff struct overhead.
sk->sk_sndbuf =
(2 * ((64 * 1024) + sizeof(struct sk_buff)));
- inet = inet_sk(sk);
- inet->uc_ttl = -1;
- inet->pmtudisc = IP_PMTUDISC_DONT;
-
- /* Unhash it so that IP input processing does not even
- * see it, we do not wish this socket to see incoming
- * packets.
- */
- sk->sk_prot->unhash(sk);
+ inet_sk(sk)->pmtudisc = IP_PMTUDISC_DONT;
}
+
+ /* Control parameters for ECHO replies. */
+ net->ipv4.sysctl_icmp_echo_ignore_all = 0;
+ net->ipv4.sysctl_icmp_echo_ignore_broadcasts = 1;
+
+ /* Control parameter - ignore bogus broadcast responses? */
+ net->ipv4.sysctl_icmp_ignore_bogus_error_responses = 1;
+
+ /*
+ * Configurable global rate limit.
+ *
+ * ratelimit defines tokens/packet consumed for dst->rate_token
+ * bucket ratemask defines which icmp types are ratelimited by
+ * setting it's bit position.
+ *
+ * default:
+ * dest unreachable (3), source quench (4),
+ * time exceeded (11), parameter problem (12)
+ */
+
+ net->ipv4.sysctl_icmp_ratelimit = 1 * HZ;
+ net->ipv4.sysctl_icmp_ratemask = 0x1818;
+ net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr = 0;
+
return 0;
fail:
- icmp_exit();
+ for_each_possible_cpu(i)
+ inet_ctl_sock_destroy(net->ipv4.icmp_sk[i]);
+ kfree(net->ipv4.icmp_sk);
return err;
}
+static struct pernet_operations __net_initdata icmp_sk_ops = {
+ .init = icmp_sk_init,
+ .exit = icmp_sk_exit,
+};
+
+int __init icmp_init(void)
+{
+ return register_pernet_device(&icmp_sk_ops);
+}
+
EXPORT_SYMBOL(icmp_err_convert);
EXPORT_SYMBOL(icmp_send);
EXPORT_SYMBOL(icmp_statistics);