|
|
|
|
@@ -56,9 +56,7 @@ struct ping_table {
|
|
|
|
|
|
|
|
|
|
static struct ping_table ping_table;
|
|
|
|
|
struct pingv6_ops pingv6_ops;
|
|
|
|
|
EXPORT_SYMBOL_GPL(pingv6_ops);
|
|
|
|
|
|
|
|
|
|
static u16 ping_port_rover;
|
|
|
|
|
EXPORT_IPV6_MOD_GPL(pingv6_ops);
|
|
|
|
|
|
|
|
|
|
static inline u32 ping_hashfn(const struct net *net, u32 num, u32 mask)
|
|
|
|
|
{
|
|
|
|
|
@@ -67,7 +65,6 @@ static inline u32 ping_hashfn(const struct net *net, u32 num, u32 mask)
|
|
|
|
|
pr_debug("hash(%u) = %u\n", num, res);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(ping_hash);
|
|
|
|
|
|
|
|
|
|
static inline struct hlist_head *ping_hashslot(struct ping_table *table,
|
|
|
|
|
struct net *net, unsigned int num)
|
|
|
|
|
@@ -77,6 +74,7 @@ static inline struct hlist_head *ping_hashslot(struct ping_table *table,
|
|
|
|
|
|
|
|
|
|
int ping_get_port(struct sock *sk, unsigned short ident)
|
|
|
|
|
{
|
|
|
|
|
struct net *net = sock_net(sk);
|
|
|
|
|
struct inet_sock *isk, *isk2;
|
|
|
|
|
struct hlist_head *hlist;
|
|
|
|
|
struct sock *sk2 = NULL;
|
|
|
|
|
@@ -84,15 +82,16 @@ int ping_get_port(struct sock *sk, unsigned short ident)
|
|
|
|
|
isk = inet_sk(sk);
|
|
|
|
|
spin_lock(&ping_table.lock);
|
|
|
|
|
if (ident == 0) {
|
|
|
|
|
u16 result = net->ipv4.ping_port_rover + 1;
|
|
|
|
|
u32 i;
|
|
|
|
|
u16 result = ping_port_rover + 1;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < (1L << 16); i++, result++) {
|
|
|
|
|
if (!result)
|
|
|
|
|
result++; /* avoid zero */
|
|
|
|
|
hlist = ping_hashslot(&ping_table, sock_net(sk),
|
|
|
|
|
result);
|
|
|
|
|
continue; /* avoid zero */
|
|
|
|
|
hlist = ping_hashslot(&ping_table, net, result);
|
|
|
|
|
sk_for_each(sk2, hlist) {
|
|
|
|
|
if (!net_eq(sock_net(sk2), net))
|
|
|
|
|
continue;
|
|
|
|
|
isk2 = inet_sk(sk2);
|
|
|
|
|
|
|
|
|
|
if (isk2->inet_num == result)
|
|
|
|
|
@@ -100,7 +99,7 @@ int ping_get_port(struct sock *sk, unsigned short ident)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* found */
|
|
|
|
|
ping_port_rover = ident = result;
|
|
|
|
|
net->ipv4.ping_port_rover = ident = result;
|
|
|
|
|
break;
|
|
|
|
|
next_port:
|
|
|
|
|
;
|
|
|
|
|
@@ -108,8 +107,10 @@ next_port:
|
|
|
|
|
if (i >= (1L << 16))
|
|
|
|
|
goto fail;
|
|
|
|
|
} else {
|
|
|
|
|
hlist = ping_hashslot(&ping_table, sock_net(sk), ident);
|
|
|
|
|
hlist = ping_hashslot(&ping_table, net, ident);
|
|
|
|
|
sk_for_each(sk2, hlist) {
|
|
|
|
|
if (!net_eq(sock_net(sk2), net))
|
|
|
|
|
continue;
|
|
|
|
|
isk2 = inet_sk(sk2);
|
|
|
|
|
|
|
|
|
|
/* BUG? Why is this reuse and not reuseaddr? ping.c
|
|
|
|
|
@@ -129,7 +130,7 @@ next_port:
|
|
|
|
|
pr_debug("was not hashed\n");
|
|
|
|
|
sk_add_node_rcu(sk, hlist);
|
|
|
|
|
sock_set_flag(sk, SOCK_RCU_FREE);
|
|
|
|
|
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
|
|
|
|
|
sock_prot_inuse_add(net, sk->sk_prot, 1);
|
|
|
|
|
}
|
|
|
|
|
spin_unlock(&ping_table.lock);
|
|
|
|
|
return 0;
|
|
|
|
|
@@ -138,15 +139,7 @@ fail:
|
|
|
|
|
spin_unlock(&ping_table.lock);
|
|
|
|
|
return -EADDRINUSE;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(ping_get_port);
|
|
|
|
|
|
|
|
|
|
int ping_hash(struct sock *sk)
|
|
|
|
|
{
|
|
|
|
|
pr_debug("ping_hash(sk->port=%u)\n", inet_sk(sk)->inet_num);
|
|
|
|
|
BUG(); /* "Please do not press this button again." */
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_IPV6_MOD_GPL(ping_get_port);
|
|
|
|
|
|
|
|
|
|
void ping_unhash(struct sock *sk)
|
|
|
|
|
{
|
|
|
|
|
@@ -161,7 +154,7 @@ void ping_unhash(struct sock *sk)
|
|
|
|
|
}
|
|
|
|
|
spin_unlock(&ping_table.lock);
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(ping_unhash);
|
|
|
|
|
EXPORT_IPV6_MOD_GPL(ping_unhash);
|
|
|
|
|
|
|
|
|
|
/* Called under rcu_read_lock() */
|
|
|
|
|
static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
|
|
|
|
|
@@ -188,6 +181,8 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sk_for_each_rcu(sk, hslot) {
|
|
|
|
|
if (!net_eq(sock_net(sk), net))
|
|
|
|
|
continue;
|
|
|
|
|
isk = inet_sk(sk);
|
|
|
|
|
|
|
|
|
|
pr_debug("iterate\n");
|
|
|
|
|
@@ -279,7 +274,7 @@ out_release_group:
|
|
|
|
|
put_group_info(group_info);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(ping_init_sock);
|
|
|
|
|
EXPORT_IPV6_MOD_GPL(ping_init_sock);
|
|
|
|
|
|
|
|
|
|
void ping_close(struct sock *sk, long timeout)
|
|
|
|
|
{
|
|
|
|
|
@@ -289,7 +284,7 @@ void ping_close(struct sock *sk, long timeout)
|
|
|
|
|
|
|
|
|
|
sk_common_release(sk);
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(ping_close);
|
|
|
|
|
EXPORT_IPV6_MOD_GPL(ping_close);
|
|
|
|
|
|
|
|
|
|
static int ping_pre_connect(struct sock *sk, struct sockaddr *uaddr,
|
|
|
|
|
int addr_len)
|
|
|
|
|
@@ -467,7 +462,7 @@ out:
|
|
|
|
|
pr_debug("ping_v4_bind -> %d\n", err);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(ping_bind);
|
|
|
|
|
EXPORT_IPV6_MOD_GPL(ping_bind);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Is this a supported type of ICMP message?
|
|
|
|
|
@@ -600,7 +595,7 @@ void ping_err(struct sk_buff *skb, int offset, u32 info)
|
|
|
|
|
out:
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(ping_err);
|
|
|
|
|
EXPORT_IPV6_MOD_GPL(ping_err);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Copy and checksum an ICMP Echo packet from user space into a buffer
|
|
|
|
|
@@ -630,7 +625,7 @@ int ping_getfrag(void *from, char *to,
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(ping_getfrag);
|
|
|
|
|
EXPORT_IPV6_MOD_GPL(ping_getfrag);
|
|
|
|
|
|
|
|
|
|
static int ping_v4_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh,
|
|
|
|
|
struct flowi4 *fl4)
|
|
|
|
|
@@ -691,7 +686,7 @@ int ping_common_sendmsg(int family, struct msghdr *msg, size_t len,
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(ping_common_sendmsg);
|
|
|
|
|
EXPORT_IPV6_MOD_GPL(ping_common_sendmsg);
|
|
|
|
|
|
|
|
|
|
static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
|
|
|
|
{
|
|
|
|
|
@@ -936,7 +931,7 @@ out:
|
|
|
|
|
pr_debug("ping_recvmsg -> %d\n", err);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(ping_recvmsg);
|
|
|
|
|
EXPORT_IPV6_MOD_GPL(ping_recvmsg);
|
|
|
|
|
|
|
|
|
|
static enum skb_drop_reason __ping_queue_rcv_skb(struct sock *sk,
|
|
|
|
|
struct sk_buff *skb)
|
|
|
|
|
@@ -957,7 +952,7 @@ int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
|
|
|
|
{
|
|
|
|
|
return __ping_queue_rcv_skb(sk, skb) ? -1 : 0;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(ping_queue_rcv_skb);
|
|
|
|
|
EXPORT_IPV6_MOD_GPL(ping_queue_rcv_skb);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
@@ -985,7 +980,7 @@ enum skb_drop_reason ping_rcv(struct sk_buff *skb)
|
|
|
|
|
kfree_skb_reason(skb, SKB_DROP_REASON_NO_SOCKET);
|
|
|
|
|
return SKB_DROP_REASON_NO_SOCKET;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(ping_rcv);
|
|
|
|
|
EXPORT_IPV6_MOD_GPL(ping_rcv);
|
|
|
|
|
|
|
|
|
|
struct proto ping_prot = {
|
|
|
|
|
.name = "PING",
|
|
|
|
|
@@ -1002,13 +997,12 @@ struct proto ping_prot = {
|
|
|
|
|
.bind = ping_bind,
|
|
|
|
|
.backlog_rcv = ping_queue_rcv_skb,
|
|
|
|
|
.release_cb = ip4_datagram_release_cb,
|
|
|
|
|
.hash = ping_hash,
|
|
|
|
|
.unhash = ping_unhash,
|
|
|
|
|
.get_port = ping_get_port,
|
|
|
|
|
.put_port = ping_unhash,
|
|
|
|
|
.obj_size = sizeof(struct inet_sock),
|
|
|
|
|
};
|
|
|
|
|
EXPORT_SYMBOL(ping_prot);
|
|
|
|
|
EXPORT_IPV6_MOD(ping_prot);
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_PROC_FS
|
|
|
|
|
|
|
|
|
|
@@ -1073,7 +1067,7 @@ void *ping_seq_start(struct seq_file *seq, loff_t *pos, sa_family_t family)
|
|
|
|
|
|
|
|
|
|
return *pos ? ping_get_idx(seq, *pos-1) : SEQ_START_TOKEN;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(ping_seq_start);
|
|
|
|
|
EXPORT_IPV6_MOD_GPL(ping_seq_start);
|
|
|
|
|
|
|
|
|
|
static void *ping_v4_seq_start(struct seq_file *seq, loff_t *pos)
|
|
|
|
|
{
|
|
|
|
|
@@ -1092,14 +1086,14 @@ void *ping_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
|
|
|
|
++*pos;
|
|
|
|
|
return sk;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(ping_seq_next);
|
|
|
|
|
EXPORT_IPV6_MOD_GPL(ping_seq_next);
|
|
|
|
|
|
|
|
|
|
void ping_seq_stop(struct seq_file *seq, void *v)
|
|
|
|
|
__releases(ping_table.lock)
|
|
|
|
|
{
|
|
|
|
|
spin_unlock(&ping_table.lock);
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(ping_seq_stop);
|
|
|
|
|
EXPORT_IPV6_MOD_GPL(ping_seq_stop);
|
|
|
|
|
|
|
|
|
|
static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
|
|
|
|
|
int bucket)
|
|
|
|
|
@@ -1150,6 +1144,8 @@ static int __net_init ping_v4_proc_init_net(struct net *net)
|
|
|
|
|
if (!proc_create_net("icmp", 0444, net->proc_net, &ping_v4_seq_ops,
|
|
|
|
|
sizeof(struct ping_iter_state)))
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
net->ipv4.ping_port_rover = get_random_u16();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|