Blame view

net/ipv4/ping.c 27.6 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
2
3
4
5
6
7
8
  /*
   * INET		An implementation of the TCP/IP protocol suite for the LINUX
   *		operating system.  INET is implemented using the  BSD Socket
   *		interface as the means of communication with the user level.
   *
   *		"Ping" sockets
   *
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
9
10
11
12
13
14
15
   * Based on ipv4/udp.c code.
   *
   * Authors:	Vasiliy Kulikov / Openwall (for Linux 2.6),
   *		Pavel Kankovsky (for Linux 2.4.32)
   *
   * Pavel gave all rights to bugs to Vasiliy,
   * none of the bugs are Pavel's now.
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
16
   */
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
17
  #include <linux/uaccess.h>
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
18
19
20
21
22
23
24
25
26
27
28
29
  #include <linux/types.h>
  #include <linux/fcntl.h>
  #include <linux/socket.h>
  #include <linux/sockios.h>
  #include <linux/in.h>
  #include <linux/errno.h>
  #include <linux/timer.h>
  #include <linux/mm.h>
  #include <linux/inet.h>
  #include <linux/netdevice.h>
  #include <net/snmp.h>
  #include <net/ip.h>
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
30
31
32
33
  #include <net/icmp.h>
  #include <net/protocol.h>
  #include <linux/skbuff.h>
  #include <linux/proc_fs.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
34
  #include <linux/export.h>
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
35
36
  #include <net/sock.h>
  #include <net/ping.h>
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
37
38
39
40
  #include <net/udp.h>
  #include <net/route.h>
  #include <net/inet_common.h>
  #include <net/checksum.h>
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
41
42
43
44
45
46
47
  #if IS_ENABLED(CONFIG_IPV6)
  #include <linux/in6.h>
  #include <linux/icmpv6.h>
  #include <net/addrconf.h>
  #include <net/ipv6.h>
  #include <net/transp_v6.h>
  #endif
ea074b349   Stephen Hemminger   ipv4: ping make l...
48
49
50
51
  struct ping_table {
  	struct hlist_nulls_head	hash[PING_HTABLE_SIZE];
  	rwlock_t		lock;
  };
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
52

ea074b349   Stephen Hemminger   ipv4: ping make l...
53
  static struct ping_table ping_table;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
54
55
  struct pingv6_ops pingv6_ops;
  EXPORT_SYMBOL_GPL(pingv6_ops);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
56

1b1cb1f78   Eric Dumazet   net: ping: small ...
57
  static u16 ping_port_rover;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
58

6eada0110   Eric Dumazet   netns: constify n...
59
  static inline u32 ping_hashfn(const struct net *net, u32 num, u32 mask)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
60
  {
6eada0110   Eric Dumazet   netns: constify n...
61
  	u32 res = (num + net_hash_mix(net)) & mask;
95c961747   Eric Dumazet   net: cleanup unsi...
62

6eada0110   Eric Dumazet   netns: constify n...
63
64
  	pr_debug("hash(%u) = %u
  ", num, res);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
65
66
  	return res;
  }
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
67
  EXPORT_SYMBOL_GPL(ping_hash);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
68
69
  
  static inline struct hlist_nulls_head *ping_hashslot(struct ping_table *table,
95c961747   Eric Dumazet   net: cleanup unsi...
70
  					     struct net *net, unsigned int num)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
71
72
73
  {
  	return &table->hash[ping_hashfn(net, num, PING_HTABLE_MASK)];
  }
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
74
  int ping_get_port(struct sock *sk, unsigned short ident)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  {
  	struct hlist_nulls_node *node;
  	struct hlist_nulls_head *hlist;
  	struct inet_sock *isk, *isk2;
  	struct sock *sk2 = NULL;
  
  	isk = inet_sk(sk);
  	write_lock_bh(&ping_table.lock);
  	if (ident == 0) {
  		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);
  			ping_portaddr_for_each_entry(sk2, node, hlist) {
  				isk2 = inet_sk(sk2);
  
  				if (isk2->inet_num == result)
  					goto next_port;
  			}
  
  			/* found */
  			ping_port_rover = ident = result;
  			break;
  next_port:
  			;
  		}
  		if (i >= (1L << 16))
  			goto fail;
  	} else {
  		hlist = ping_hashslot(&ping_table, sock_net(sk), ident);
  		ping_portaddr_for_each_entry(sk2, node, hlist) {
  			isk2 = inet_sk(sk2);
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
111
112
113
114
  			/* BUG? Why is this reuse and not reuseaddr? ping.c
  			 * doesn't turn off SO_REUSEADDR, and it doesn't expect
  			 * that other ping processes can steal its packets.
  			 */
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  			if ((isk2->inet_num == ident) &&
  			    (sk2 != sk) &&
  			    (!sk2->sk_reuse || !sk->sk_reuse))
  				goto fail;
  		}
  	}
  
  	pr_debug("found port/ident = %d
  ", ident);
  	isk->inet_num = ident;
  	if (sk_unhashed(sk)) {
  		pr_debug("was not hashed
  ");
  		sock_hold(sk);
  		hlist_nulls_add_head(&sk->sk_nulls_node, hlist);
  		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
  	}
  	write_unlock_bh(&ping_table.lock);
  	return 0;
  
  fail:
  	write_unlock_bh(&ping_table.lock);
  	return 1;
  }
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
139
  EXPORT_SYMBOL_GPL(ping_get_port);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
140

086c653f5   Craig Gallek   sock: struct prot...
141
  int ping_hash(struct sock *sk)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
142
  {
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
143
144
  	pr_debug("ping_hash(sk->port=%u)
  ", inet_sk(sk)->inet_num);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
145
  	BUG(); /* "Please do not press this button again." */
086c653f5   Craig Gallek   sock: struct prot...
146
147
  
  	return 0;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
148
  }
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
149
  void ping_unhash(struct sock *sk)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
150
151
  {
  	struct inet_sock *isk = inet_sk(sk);
43a668451   Eric Dumazet   ping: implement p...
152

6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
153
154
  	pr_debug("ping_unhash(isk=%p,isk->num=%u)
  ", isk, isk->inet_num);
43a668451   Eric Dumazet   ping: implement p...
155
  	write_lock_bh(&ping_table.lock);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
156
  	if (sk_hashed(sk)) {
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
157
  		hlist_nulls_del(&sk->sk_nulls_node);
a134f083e   David S. Miller   ipv4: Missing sk_...
158
  		sk_nulls_node_init(&sk->sk_nulls_node);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
159
  		sock_put(sk);
747465ef7   Eric Dumazet   net: fix some spa...
160
161
  		isk->inet_num = 0;
  		isk->inet_sport = 0;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
162
  		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
163
  	}
43a668451   Eric Dumazet   ping: implement p...
164
  	write_unlock_bh(&ping_table.lock);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
165
  }
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
166
  EXPORT_SYMBOL_GPL(ping_unhash);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
167

6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
168
  static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
169
170
171
172
173
  {
  	struct hlist_nulls_head *hslot = ping_hashslot(&ping_table, net, ident);
  	struct sock *sk = NULL;
  	struct inet_sock *isk;
  	struct hlist_nulls_node *hnode;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
174
175
176
177
178
179
180
181
182
183
184
185
186
  	int dif = skb->dev->ifindex;
  
  	if (skb->protocol == htons(ETH_P_IP)) {
  		pr_debug("try to find: num = %d, daddr = %pI4, dif = %d
  ",
  			 (int)ident, &ip_hdr(skb)->daddr, dif);
  #if IS_ENABLED(CONFIG_IPV6)
  	} else if (skb->protocol == htons(ETH_P_IPV6)) {
  		pr_debug("try to find: num = %d, daddr = %pI6c, dif = %d
  ",
  			 (int)ident, &ipv6_hdr(skb)->daddr, dif);
  #endif
  	}
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
187

c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
188
189
190
191
  	read_lock_bh(&ping_table.lock);
  
  	ping_portaddr_for_each_entry(sk, hnode, hslot) {
  		isk = inet_sk(sk);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
192
193
194
195
  		pr_debug("iterate
  ");
  		if (isk->inet_num != ident)
  			continue;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  
  		if (skb->protocol == htons(ETH_P_IP) &&
  		    sk->sk_family == AF_INET) {
  			pr_debug("found: %p: num=%d, daddr=%pI4, dif=%d
  ", sk,
  				 (int) isk->inet_num, &isk->inet_rcv_saddr,
  				 sk->sk_bound_dev_if);
  
  			if (isk->inet_rcv_saddr &&
  			    isk->inet_rcv_saddr != ip_hdr(skb)->daddr)
  				continue;
  #if IS_ENABLED(CONFIG_IPV6)
  		} else if (skb->protocol == htons(ETH_P_IPV6) &&
  			   sk->sk_family == AF_INET6) {
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
210
211
212
213
  
  			pr_debug("found: %p: num=%d, daddr=%pI6c, dif=%d
  ", sk,
  				 (int) isk->inet_num,
efe4208f4   Eric Dumazet   ipv6: make lookup...
214
  				 &sk->sk_v6_rcv_saddr,
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
215
  				 sk->sk_bound_dev_if);
efe4208f4   Eric Dumazet   ipv6: make lookup...
216
217
  			if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr) &&
  			    !ipv6_addr_equal(&sk->sk_v6_rcv_saddr,
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
218
219
220
  					     &ipv6_hdr(skb)->daddr))
  				continue;
  #endif
91a0b6034   Jane Zhou   net/ping: handle ...
221
222
  		} else {
  			continue;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
223
  		}
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
224
225
226
227
228
229
230
231
232
233
234
235
236
  		if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)
  			continue;
  
  		sock_hold(sk);
  		goto exit;
  	}
  
  	sk = NULL;
  exit:
  	read_unlock_bh(&ping_table.lock);
  
  	return sk;
  }
7064d16e1   Eric W. Biederman   userns: Use kgids...
237
238
  static void inet_get_ping_group_range_net(struct net *net, kgid_t *low,
  					  kgid_t *high)
f56e03e8d   Vasiliy Kulikov   net: ping: fix bu...
239
  {
ba6b918ab   Cong Wang   ping: move ping_g...
240
  	kgid_t *data = net->ipv4.ping_group_range.range;
95c961747   Eric Dumazet   net: cleanup unsi...
241
  	unsigned int seq;
f56e03e8d   Vasiliy Kulikov   net: ping: fix bu...
242
  	do {
ba6b918ab   Cong Wang   ping: move ping_g...
243
  		seq = read_seqbegin(&net->ipv4.ping_group_range.lock);
f56e03e8d   Vasiliy Kulikov   net: ping: fix bu...
244
245
246
  
  		*low = data[0];
  		*high = data[1];
ba6b918ab   Cong Wang   ping: move ping_g...
247
  	} while (read_seqretry(&net->ipv4.ping_group_range.lock, seq));
f56e03e8d   Vasiliy Kulikov   net: ping: fix bu...
248
  }
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
249
  int ping_init_sock(struct sock *sk)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
250
251
  {
  	struct net *net = sock_net(sk);
7064d16e1   Eric W. Biederman   userns: Use kgids...
252
  	kgid_t group = current_egid();
b04c46190   Wang, Xiaoming   net: ipv4: curren...
253
  	struct group_info *group_info;
81243eacf   Alexey Dobriyan   cred: simpler, 1D...
254
  	int i;
ae2975bc3   Eric W. Biederman   userns: Convert g...
255
  	kgid_t low, high;
b04c46190   Wang, Xiaoming   net: ipv4: curren...
256
  	int ret = 0;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
257

9145736d4   Lorenzo Colitti   net: ping: Return...
258
259
  	if (sk->sk_family == AF_INET6)
  		sk->sk_ipv6only = 1;
7064d16e1   Eric W. Biederman   userns: Use kgids...
260
261
  	inet_get_ping_group_range_net(net, &low, &high);
  	if (gid_lte(low, group) && gid_lte(group, high))
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
262
  		return 0;
b04c46190   Wang, Xiaoming   net: ipv4: curren...
263
  	group_info = get_current_groups();
81243eacf   Alexey Dobriyan   cred: simpler, 1D...
264
265
  	for (i = 0; i < group_info->ngroups; i++) {
  		kgid_t gid = group_info->gid[i];
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
266

81243eacf   Alexey Dobriyan   cred: simpler, 1D...
267
268
  		if (gid_lte(low, gid) && gid_lte(gid, high))
  			goto out_release_group;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
269
  	}
b04c46190   Wang, Xiaoming   net: ipv4: curren...
270
271
272
273
274
  	ret = -EACCES;
  
  out_release_group:
  	put_group_info(group_info);
  	return ret;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
275
  }
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
276
  EXPORT_SYMBOL_GPL(ping_init_sock);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
277

6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
278
  void ping_close(struct sock *sk, long timeout)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
279
280
281
  {
  	pr_debug("ping_close(sk=%p,sk->num=%u)
  ",
058bd4d2a   Joe Perches   net: Convert prin...
282
  		 inet_sk(sk), inet_sk(sk)->inet_num);
41c6d650f   Reshetova, Elena   net: convert sock...
283
284
  	pr_debug("isk->refcnt = %d
  ", refcount_read(&sk->sk_refcnt));
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
285
286
287
  
  	sk_common_release(sk);
  }
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
288
289
290
  EXPORT_SYMBOL_GPL(ping_close);
  
  /* Checks the bind address and possibly modifies sk->sk_bound_dev_if. */
a06a2d378   Wu Fengguang   net: ping_check_b...
291
  static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
5af68891d   Miaohe Lin   net: clean up cod...
292
293
  				struct sockaddr *uaddr, int addr_len)
  {
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
294
295
296
297
298
299
300
  	struct net *net = sock_net(sk);
  	if (sk->sk_family == AF_INET) {
  		struct sockaddr_in *addr = (struct sockaddr_in *) uaddr;
  		int chk_addr_ret;
  
  		if (addr_len < sizeof(*addr))
  			return -EINVAL;
9145736d4   Lorenzo Colitti   net: ping: Return...
301
302
303
304
  		if (addr->sin_family != AF_INET &&
  		    !(addr->sin_family == AF_UNSPEC &&
  		      addr->sin_addr.s_addr == htonl(INADDR_ANY)))
  			return -EAFNOSUPPORT;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
305
306
307
  		pr_debug("ping_check_bind_addr(sk=%p,addr=%pI4,port=%d)
  ",
  			 sk, &addr->sin_addr.s_addr, ntohs(addr->sin_port));
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
308
309
  		if (addr->sin_addr.s_addr == htonl(INADDR_ANY))
  			chk_addr_ret = RTN_LOCAL;
0ce779a9f   Miaohe Lin   net: Avoid unnece...
310
311
  		else
  			chk_addr_ret = inet_addr_type(net, addr->sin_addr.s_addr);
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
312

83ba46451   Vincent Bernat   net: add helpers ...
313
  		if ((!inet_can_nonlocal_bind(net, isk) &&
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
314
315
316
317
318
319
320
321
322
323
324
325
326
  		     chk_addr_ret != RTN_LOCAL) ||
  		    chk_addr_ret == RTN_MULTICAST ||
  		    chk_addr_ret == RTN_BROADCAST)
  			return -EADDRNOTAVAIL;
  
  #if IS_ENABLED(CONFIG_IPV6)
  	} else if (sk->sk_family == AF_INET6) {
  		struct sockaddr_in6 *addr = (struct sockaddr_in6 *) uaddr;
  		int addr_type, scoped, has_addr;
  		struct net_device *dev = NULL;
  
  		if (addr_len < sizeof(*addr))
  			return -EINVAL;
82b276cd2   Hannes Frederic Sowa   ipv6: protect pro...
327
  		if (addr->sin6_family != AF_INET6)
9145736d4   Lorenzo Colitti   net: ping: Return...
328
  			return -EAFNOSUPPORT;
82b276cd2   Hannes Frederic Sowa   ipv6: protect pro...
329

6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
  		pr_debug("ping_check_bind_addr(sk=%p,addr=%pI6c,port=%d)
  ",
  			 sk, addr->sin6_addr.s6_addr, ntohs(addr->sin6_port));
  
  		addr_type = ipv6_addr_type(&addr->sin6_addr);
  		scoped = __ipv6_addr_needs_scope_id(addr_type);
  		if ((addr_type != IPV6_ADDR_ANY &&
  		     !(addr_type & IPV6_ADDR_UNICAST)) ||
  		    (scoped && !addr->sin6_scope_id))
  			return -EINVAL;
  
  		rcu_read_lock();
  		if (addr->sin6_scope_id) {
  			dev = dev_get_by_index_rcu(net, addr->sin6_scope_id);
  			if (!dev) {
  				rcu_read_unlock();
  				return -ENODEV;
  			}
  		}
  		has_addr = pingv6_ops.ipv6_chk_addr(net, &addr->sin6_addr, dev,
  						    scoped);
  		rcu_read_unlock();
83ba46451   Vincent Bernat   net: add helpers ...
352
  		if (!(ipv6_can_nonlocal_bind(net, isk) || has_addr ||
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
353
354
355
356
357
358
359
360
361
362
363
  		      addr_type == IPV6_ADDR_ANY))
  			return -EADDRNOTAVAIL;
  
  		if (scoped)
  			sk->sk_bound_dev_if = addr->sin6_scope_id;
  #endif
  	} else {
  		return -EAFNOSUPPORT;
  	}
  	return 0;
  }
a06a2d378   Wu Fengguang   net: ping_check_b...
364
  static void ping_set_saddr(struct sock *sk, struct sockaddr *saddr)
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
365
366
367
368
369
370
371
372
373
  {
  	if (saddr->sa_family == AF_INET) {
  		struct inet_sock *isk = inet_sk(sk);
  		struct sockaddr_in *addr = (struct sockaddr_in *) saddr;
  		isk->inet_rcv_saddr = isk->inet_saddr = addr->sin_addr.s_addr;
  #if IS_ENABLED(CONFIG_IPV6)
  	} else if (saddr->sa_family == AF_INET6) {
  		struct sockaddr_in6 *addr = (struct sockaddr_in6 *) saddr;
  		struct ipv6_pinfo *np = inet6_sk(sk);
efe4208f4   Eric Dumazet   ipv6: make lookup...
374
  		sk->sk_v6_rcv_saddr = np->saddr = addr->sin6_addr;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
375
376
377
  #endif
  	}
  }
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
378
379
380
381
382
  
  /*
   * We need our own bind because there are no privileged id's == local ports.
   * Moreover, we don't allow binding to multi- and broadcast addresses.
   */
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
383
  int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
384
  {
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
385
386
  	struct inet_sock *isk = inet_sk(sk);
  	unsigned short snum;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
387
  	int err;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
388
  	int dif = sk->sk_bound_dev_if;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
389

6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
390
391
392
  	err = ping_check_bind_addr(sk, isk, uaddr, addr_len);
  	if (err)
  		return err;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
393
394
395
396
397
398
399
400
  
  	lock_sock(sk);
  
  	err = -EINVAL;
  	if (isk->inet_num != 0)
  		goto out;
  
  	err = -EADDRINUSE;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
401
402
  	snum = ntohs(((struct sockaddr_in *)uaddr)->sin_port);
  	if (ping_get_port(sk, snum) != 0) {
0316a2111   Miaohe Lin   net: Set ping sad...
403
404
  		/* Restore possibly modified sk->sk_bound_dev_if by ping_check_bind_addr(). */
  		sk->sk_bound_dev_if = dif;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
405
406
  		goto out;
  	}
0316a2111   Miaohe Lin   net: Set ping sad...
407
  	ping_set_saddr(sk, uaddr);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
408

a7ef6715c   Gao Feng   net: ping: Use ri...
409
410
411
412
  	pr_debug("after bind(): num = %hu, dif = %d
  ",
  		 isk->inet_num,
  		 sk->sk_bound_dev_if);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
413
414
  
  	err = 0;
c2bb06db5   Eric Dumazet   net: fix build er...
415
  	if (sk->sk_family == AF_INET && isk->inet_rcv_saddr)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
416
  		sk->sk_userlocks |= SOCK_BINDADDR_LOCK;
c2bb06db5   Eric Dumazet   net: fix build er...
417
418
419
420
  #if IS_ENABLED(CONFIG_IPV6)
  	if (sk->sk_family == AF_INET6 && !ipv6_addr_any(&sk->sk_v6_rcv_saddr))
  		sk->sk_userlocks |= SOCK_BINDADDR_LOCK;
  #endif
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
421

c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
422
423
424
425
426
  	if (snum)
  		sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
  	isk->inet_sport = htons(isk->inet_num);
  	isk->inet_daddr = 0;
  	isk->inet_dport = 0;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
427
428
429
  
  #if IS_ENABLED(CONFIG_IPV6)
  	if (sk->sk_family == AF_INET6)
efe4208f4   Eric Dumazet   ipv6: make lookup...
430
  		memset(&sk->sk_v6_daddr, 0, sizeof(sk->sk_v6_daddr));
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
431
  #endif
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
432
433
434
435
436
437
438
  	sk_dst_reset(sk);
  out:
  	release_sock(sk);
  	pr_debug("ping_v4_bind -> %d
  ", err);
  	return err;
  }
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
439
  EXPORT_SYMBOL_GPL(ping_bind);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
440
441
442
443
  
  /*
   * Is this a supported type of ICMP message?
   */
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
444
  static inline int ping_supported(int family, int type, int code)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
445
  {
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
446
447
  	return (family == AF_INET && type == ICMP_ECHO && code == 0) ||
  	       (family == AF_INET6 && type == ICMPV6_ECHO_REQUEST && code == 0);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
448
449
450
451
452
453
  }
  
  /*
   * This routine is called by the ICMP module when it gets some
   * sort of error condition.
   */
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
454
  void ping_err(struct sk_buff *skb, int offset, u32 info)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
455
  {
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
456
457
  	int family;
  	struct icmphdr *icmph;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
458
  	struct inet_sock *inet_sock;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
459
460
  	int type;
  	int code;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
461
462
463
464
  	struct net *net = dev_net(skb->dev);
  	struct sock *sk;
  	int harderr;
  	int err;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
465
466
467
468
469
470
471
472
473
474
475
476
477
  	if (skb->protocol == htons(ETH_P_IP)) {
  		family = AF_INET;
  		type = icmp_hdr(skb)->type;
  		code = icmp_hdr(skb)->code;
  		icmph = (struct icmphdr *)(skb->data + offset);
  	} else if (skb->protocol == htons(ETH_P_IPV6)) {
  		family = AF_INET6;
  		type = icmp6_hdr(skb)->icmp6_type;
  		code = icmp6_hdr(skb)->icmp6_code;
  		icmph = (struct icmphdr *) (skb->data + offset);
  	} else {
  		BUG();
  	}
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
478
  	/* We assume the packet has already been checked by icmp_unreach */
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
479
  	if (!ping_supported(family, icmph->type, icmph->code))
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
480
  		return;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
481
482
483
484
  	pr_debug("ping_err(proto=0x%x,type=%d,code=%d,id=%04x,seq=%04x)
  ",
  		 skb->protocol, type, code, ntohs(icmph->un.echo.id),
  		 ntohs(icmph->un.echo.sequence));
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
485

6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
486
  	sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id));
51456b291   Ian Morris   ipv4: coding styl...
487
  	if (!sk) {
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
488
489
490
491
492
493
494
495
496
497
  		pr_debug("no socket, dropping
  ");
  		return;	/* No socket for error */
  	}
  	pr_debug("err on socket %p
  ", sk);
  
  	err = 0;
  	harderr = 0;
  	inet_sock = inet_sk(sk);
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
  	if (skb->protocol == htons(ETH_P_IP)) {
  		switch (type) {
  		default:
  		case ICMP_TIME_EXCEEDED:
  			err = EHOSTUNREACH;
  			break;
  		case ICMP_SOURCE_QUENCH:
  			/* This is not a real error but ping wants to see it.
  			 * Report it with some fake errno.
  			 */
  			err = EREMOTEIO;
  			break;
  		case ICMP_PARAMETERPROB:
  			err = EPROTO;
  			harderr = 1;
  			break;
  		case ICMP_DEST_UNREACH:
  			if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
  				ipv4_sk_update_pmtu(skb, sk, info);
  				if (inet_sock->pmtudisc != IP_PMTUDISC_DONT) {
  					err = EMSGSIZE;
  					harderr = 1;
  					break;
  				}
  				goto out;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
523
  			}
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
524
525
526
527
528
529
530
531
532
533
534
  			err = EHOSTUNREACH;
  			if (code <= NR_ICMP_UNREACH) {
  				harderr = icmp_err_convert[code].fatal;
  				err = icmp_err_convert[code].errno;
  			}
  			break;
  		case ICMP_REDIRECT:
  			/* See ICMP_SOURCE_QUENCH */
  			ipv4_sk_redirect(skb, sk);
  			err = EREMOTEIO;
  			break;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
535
  		}
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
536
537
538
539
  #if IS_ENABLED(CONFIG_IPV6)
  	} else if (skb->protocol == htons(ETH_P_IPV6)) {
  		harderr = pingv6_ops.icmpv6_err_convert(type, code, &err);
  #endif
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
540
541
542
543
544
545
  	}
  
  	/*
  	 *      RFC1122: OK.  Passes ICMP errors back to application, as per
  	 *	4.1.3.3.
  	 */
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
546
547
  	if ((family == AF_INET && !inet_sock->recverr) ||
  	    (family == AF_INET6 && !inet6_sk(sk)->recverr)) {
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
548
549
550
  		if (!harderr || sk->sk_state != TCP_ESTABLISHED)
  			goto out;
  	} else {
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
551
552
553
554
555
556
557
558
559
  		if (family == AF_INET) {
  			ip_icmp_error(sk, skb, err, 0 /* no remote port */,
  				      info, (u8 *)icmph);
  #if IS_ENABLED(CONFIG_IPV6)
  		} else if (family == AF_INET6) {
  			pingv6_ops.ipv6_icmp_error(sk, skb, err, 0,
  						   info, (u8 *)icmph);
  #endif
  		}
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
560
561
562
563
564
565
  	}
  	sk->sk_err = err;
  	sk->sk_error_report(sk);
  out:
  	sock_put(sk);
  }
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
566
  EXPORT_SYMBOL_GPL(ping_err);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
567
568
  
  /*
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
569
570
   *	Copy and checksum an ICMP Echo packet from user space into a buffer
   *	starting from the payload.
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
571
   */
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
572
573
  int ping_getfrag(void *from, char *to,
  		 int offset, int fraglen, int odd, struct sk_buff *skb)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
574
575
576
577
  {
  	struct pingfakehdr *pfh = (struct pingfakehdr *)from;
  
  	if (offset == 0) {
21226abb4   Al Viro   net: switch memcp...
578
579
  		fraglen -= sizeof(struct icmphdr);
  		if (fraglen < 0)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
580
  			BUG();
0b62fca26   Al Viro   switch getfrag ca...
581
  		if (!csum_and_copy_from_iter_full(to + sizeof(struct icmphdr),
21226abb4   Al Viro   net: switch memcp...
582
  			    fraglen, &pfh->wcheck,
0b62fca26   Al Viro   switch getfrag ca...
583
  			    &pfh->msg->msg_iter))
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
584
  			return -EFAULT;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
585
586
587
  	} else if (offset < sizeof(struct icmphdr)) {
  			BUG();
  	} else {
0b62fca26   Al Viro   switch getfrag ca...
588
589
  		if (!csum_and_copy_from_iter_full(to, fraglen, &pfh->wcheck,
  					    &pfh->msg->msg_iter))
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
590
591
  			return -EFAULT;
  	}
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
592

6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
593
594
595
596
597
598
599
600
601
  #if IS_ENABLED(CONFIG_IPV6)
  	/* For IPv6, checksum each skb as we go along, as expected by
  	 * icmpv6_push_pending_frames. For IPv4, accumulate the checksum in
  	 * wcheck, it will be finalized in ping_v4_push_pending_frames.
  	 */
  	if (pfh->family == AF_INET6) {
  		skb->csum = pfh->wcheck;
  		skb->ip_summed = CHECKSUM_NONE;
  		pfh->wcheck = 0;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
602
  	}
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
603
  #endif
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
604
605
  	return 0;
  }
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
606
  EXPORT_SYMBOL_GPL(ping_getfrag);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
607

6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
608
609
  static int ping_v4_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh,
  				       struct flowi4 *fl4)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
610
611
  {
  	struct sk_buff *skb = skb_peek(&sk->sk_write_queue);
73d2c6678   WANG Cong   ping: fix a null ...
612
613
  	if (!skb)
  		return 0;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
614
615
616
617
618
619
620
  	pfh->wcheck = csum_partial((char *)&pfh->icmph,
  		sizeof(struct icmphdr), pfh->wcheck);
  	pfh->icmph.checksum = csum_fold(pfh->wcheck);
  	memcpy(icmp_hdr(skb), &pfh->icmph, sizeof(struct icmphdr));
  	skb->ip_summed = CHECKSUM_NONE;
  	return ip_push_pending_frames(sk, fl4);
  }
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
621
  int ping_common_sendmsg(int family, struct msghdr *msg, size_t len,
5af68891d   Miaohe Lin   net: clean up cod...
622
623
  			void *user_icmph, size_t icmph_len)
  {
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
624
  	u8 type, code;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
625
626
627
  
  	if (len > 0xFFFF)
  		return -EMSGSIZE;
0eab121ef   Kees Cook   net: ping: check ...
628
629
630
  	/* Must have at least a full ICMP header. */
  	if (len < icmph_len)
  		return -EINVAL;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
631
632
633
634
635
636
637
638
639
640
  	/*
  	 *	Check the flags.
  	 */
  
  	/* Mirror BSD error message compatibility */
  	if (msg->msg_flags & MSG_OOB)
  		return -EOPNOTSUPP;
  
  	/*
  	 *	Fetch the ICMP header provided by the userland.
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
641
  	 *	iovec is modified! The ICMP header is consumed.
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
642
  	 */
6ce8e9ce5   Al Viro   new helper: memcp...
643
  	if (memcpy_from_msg(user_icmph, msg, icmph_len))
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
644
  		return -EFAULT;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
645
646
647
648
649
650
651
652
653
654
655
656
657
658
  
  	if (family == AF_INET) {
  		type = ((struct icmphdr *) user_icmph)->type;
  		code = ((struct icmphdr *) user_icmph)->code;
  #if IS_ENABLED(CONFIG_IPV6)
  	} else if (family == AF_INET6) {
  		type = ((struct icmp6hdr *) user_icmph)->icmp6_type;
  		code = ((struct icmp6hdr *) user_icmph)->icmp6_code;
  #endif
  	} else {
  		BUG();
  	}
  
  	if (!ping_supported(family, type, code))
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
659
  		return -EINVAL;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
660
661
662
  	return 0;
  }
  EXPORT_SYMBOL_GPL(ping_common_sendmsg);
1b7841404   Ying Xue   net: Remove iocb ...
663
  static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
  {
  	struct net *net = sock_net(sk);
  	struct flowi4 fl4;
  	struct inet_sock *inet = inet_sk(sk);
  	struct ipcm_cookie ipc;
  	struct icmphdr user_icmph;
  	struct pingfakehdr pfh;
  	struct rtable *rt = NULL;
  	struct ip_options_data opt_copy;
  	int free = 0;
  	__be32 saddr, daddr, faddr;
  	u8  tos;
  	int err;
  
  	pr_debug("ping_v4_sendmsg(sk=%p,sk->num=%u)
  ", inet, inet->inet_num);
  
  	err = ping_common_sendmsg(AF_INET, msg, len, &user_icmph,
  				  sizeof(user_icmph));
  	if (err)
  		return err;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
685
686
687
688
689
  	/*
  	 *	Get and verify the address.
  	 */
  
  	if (msg->msg_name) {
342dfc306   Steffen Hurrle   net: add build-ti...
690
  		DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
691
692
693
  		if (msg->msg_namelen < sizeof(*usin))
  			return -EINVAL;
  		if (usin->sin_family != AF_INET)
9145736d4   Lorenzo Colitti   net: ping: Return...
694
  			return -EAFNOSUPPORT;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
695
696
697
698
699
700
701
702
  		daddr = usin->sin_addr.s_addr;
  		/* no remote port */
  	} else {
  		if (sk->sk_state != TCP_ESTABLISHED)
  			return -EDESTADDRREQ;
  		daddr = inet->inet_daddr;
  		/* no remote port */
  	}
351782067   Willem de Bruijn   ipv4: ipcm_cookie...
703
  	ipcm_init_sk(&ipc, inet);
bf84a0106   Daniel Borkmann   net: sock: make s...
704

c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
705
  	if (msg->msg_controllen) {
24025c465   Soheil Hassas Yeganeh   ipv4: process soc...
706
  		err = ip_cmsg_send(sk, msg, &ipc, false);
919483096   Eric Dumazet   ipv4: fix memory ...
707
708
  		if (unlikely(err)) {
  			kfree(ipc.opt);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
709
  			return err;
919483096   Eric Dumazet   ipv4: fix memory ...
710
  		}
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
  		if (ipc.opt)
  			free = 1;
  	}
  	if (!ipc.opt) {
  		struct ip_options_rcu *inet_opt;
  
  		rcu_read_lock();
  		inet_opt = rcu_dereference(inet->inet_opt);
  		if (inet_opt) {
  			memcpy(&opt_copy, inet_opt,
  			       sizeof(*inet_opt) + inet_opt->opt.optlen);
  			ipc.opt = &opt_copy.opt;
  		}
  		rcu_read_unlock();
  	}
  
  	saddr = ipc.addr;
  	ipc.addr = faddr = daddr;
  
  	if (ipc.opt && ipc.opt->opt.srr) {
1b97013bf   Andrey Ignatov   ipv4: fix memory ...
731
732
733
734
  		if (!daddr) {
  			err = -EINVAL;
  			goto out_free;
  		}
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
735
736
  		faddr = ipc.opt->opt.faddr;
  	}
aa6615814   Francesco Fusco   ipv4: processing ...
737
  	tos = get_rttos(&ipc, inet);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
738
739
740
741
742
743
744
  	if (sock_flag(sk, SOCK_LOCALROUTE) ||
  	    (msg->msg_flags & MSG_DONTROUTE) ||
  	    (ipc.opt && ipc.opt->opt.is_strictroute)) {
  		tos |= RTO_ONLINK;
  	}
  
  	if (ipv4_is_multicast(daddr)) {
854da9917   Robert Shearman   ipv4: Allow sendi...
745
  		if (!ipc.oif || netif_index_is_l3_master(sock_net(sk), ipc.oif))
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
746
747
748
  			ipc.oif = inet->mc_index;
  		if (!saddr)
  			saddr = inet->mc_addr;
76e21053b   Erich E. Hoover   ipv4: Implement I...
749
750
  	} else if (!ipc.oif)
  		ipc.oif = inet->uc_index;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
751

c6af0c227   Willem de Bruijn   ip: support SO_MA...
752
  	flowi4_init_output(&fl4, ipc.oif, ipc.sockc.mark, tos,
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
753
  			   RT_SCOPE_UNIVERSE, sk->sk_protocol,
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
754
755
  			   inet_sk_flowi_flags(sk), faddr, saddr, 0, 0,
  			   sk->sk_uid);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
756

5eff06902   Sabrina Dubroca   ipv4: fill fl4_ic...
757
758
  	fl4.fl4_icmp_type = user_icmph.type;
  	fl4.fl4_icmp_code = user_icmph.code;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
759
760
761
762
763
764
  	security_sk_classify_flow(sk, flowi4_to_flowi(&fl4));
  	rt = ip_route_output_flow(net, &fl4, sk);
  	if (IS_ERR(rt)) {
  		err = PTR_ERR(rt);
  		rt = NULL;
  		if (err == -ENETUNREACH)
f1d8cba61   Eric Dumazet   inet: fix possibl...
765
  			IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
  		goto out;
  	}
  
  	err = -EACCES;
  	if ((rt->rt_flags & RTCF_BROADCAST) &&
  	    !sock_flag(sk, SOCK_BROADCAST))
  		goto out;
  
  	if (msg->msg_flags & MSG_CONFIRM)
  		goto do_confirm;
  back_from_confirm:
  
  	if (!ipc.addr)
  		ipc.addr = fl4.daddr;
  
  	lock_sock(sk);
  
  	pfh.icmph.type = user_icmph.type; /* already checked */
  	pfh.icmph.code = user_icmph.code; /* ditto */
  	pfh.icmph.checksum = 0;
  	pfh.icmph.un.echo.id = inet->inet_sport;
  	pfh.icmph.un.echo.sequence = user_icmph.un.echo.sequence;
cacdc7d2f   Al Viro   ip: stash a point...
788
  	pfh.msg = msg;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
789
  	pfh.wcheck = 0;
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
790
  	pfh.family = AF_INET;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
791
792
793
794
795
796
  
  	err = ip_append_data(sk, &fl4, ping_getfrag, &pfh, len,
  			0, &ipc, &rt, msg->msg_flags);
  	if (err)
  		ip_flush_pending_frames(sk);
  	else
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
797
  		err = ping_v4_push_pending_frames(sk, &pfh, &fl4);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
798
799
800
801
  	release_sock(sk);
  
  out:
  	ip_rt_put(rt);
1b97013bf   Andrey Ignatov   ipv4: fix memory ...
802
  out_free:
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
803
804
805
806
807
808
809
810
811
  	if (free)
  		kfree(ipc.opt);
  	if (!err) {
  		icmp_out_count(sock_net(sk), user_icmph.type);
  		return len;
  	}
  	return err;
  
  do_confirm:
0dec879f6   Julian Anastasov   net: use dst_conf...
812
813
  	if (msg->msg_flags & MSG_PROBE)
  		dst_confirm_neigh(&rt->dst, &fl4.daddr);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
814
815
816
817
818
  	if (!(msg->msg_flags & MSG_PROBE) || len)
  		goto back_from_confirm;
  	err = 0;
  	goto out;
  }
1b7841404   Ying Xue   net: Remove iocb ...
819
820
  int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock,
  		 int flags, int *addr_len)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
821
822
  {
  	struct inet_sock *isk = inet_sk(sk);
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
823
  	int family = sk->sk_family;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
824
825
826
827
828
  	struct sk_buff *skb;
  	int copied, err;
  
  	pr_debug("ping_recvmsg(sk=%p,sk->num=%u)
  ", isk, isk->inet_num);
a5e7424d4   David S. Miller   ipv4: ping: Fix r...
829
  	err = -EOPNOTSUPP;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
830
831
  	if (flags & MSG_OOB)
  		goto out;
f4713a3df   Willem de Bruijn   net-timestamp: ma...
832
833
  	if (flags & MSG_ERRQUEUE)
  		return inet_recv_error(sk, msg, len, addr_len);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
834
835
836
837
838
839
840
841
842
843
844
845
  
  	skb = skb_recv_datagram(sk, flags, noblock, &err);
  	if (!skb)
  		goto out;
  
  	copied = skb->len;
  	if (copied > len) {
  		msg->msg_flags |= MSG_TRUNC;
  		copied = len;
  	}
  
  	/* Don't bother checking the checksum */
51f3d02b9   David S. Miller   net: Add and use ...
846
  	err = skb_copy_datagram_msg(skb, 0, msg, copied);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
847
848
849
850
  	if (err)
  		goto done;
  
  	sock_recv_timestamp(msg, sk, skb);
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
851
852
  	/* Copy the address and add cmsg data. */
  	if (family == AF_INET) {
342dfc306   Steffen Hurrle   net: add build-ti...
853
  		DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name);
bceaa9024   Hannes Frederic Sowa   inet: prevent lea...
854

cf970c002   Hannes Frederic Sowa   ping: prevent NUL...
855
856
857
858
859
860
861
  		if (sin) {
  			sin->sin_family = AF_INET;
  			sin->sin_port = 0 /* skb->h.uh->source */;
  			sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
  			memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
  			*addr_len = sizeof(*sin);
  		}
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
862
863
864
865
866
867
868
869
  
  		if (isk->cmsg_flags)
  			ip_cmsg_recv(msg, skb);
  
  #if IS_ENABLED(CONFIG_IPV6)
  	} else if (family == AF_INET6) {
  		struct ipv6_pinfo *np = inet6_sk(sk);
  		struct ipv6hdr *ip6 = ipv6_hdr(skb);
342dfc306   Steffen Hurrle   net: add build-ti...
870
  		DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
bceaa9024   Hannes Frederic Sowa   inet: prevent lea...
871

cf970c002   Hannes Frederic Sowa   ping: prevent NUL...
872
873
874
875
876
877
878
879
880
  		if (sin6) {
  			sin6->sin6_family = AF_INET6;
  			sin6->sin6_port = 0;
  			sin6->sin6_addr = ip6->saddr;
  			sin6->sin6_flowinfo = 0;
  			if (np->sndflow)
  				sin6->sin6_flowinfo = ip6_flowinfo(ip6);
  			sin6->sin6_scope_id =
  				ipv6_iface_scope_id(&sin6->sin6_addr,
4330487ac   Duan Jiong   net: use inet6_ii...
881
  						    inet6_iif(skb));
cf970c002   Hannes Frederic Sowa   ping: prevent NUL...
882
883
  			*addr_len = sizeof(*sin6);
  		}
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
884
885
  
  		if (inet6_sk(sk)->rxopt.all)
4b261c75a   Hannes Frederic Sowa   ipv6: make IPV6_R...
886
887
888
889
890
891
  			pingv6_ops.ip6_datagram_recv_common_ctl(sk, msg, skb);
  		if (skb->protocol == htons(ETH_P_IPV6) &&
  		    inet6_sk(sk)->rxopt.all)
  			pingv6_ops.ip6_datagram_recv_specific_ctl(sk, msg, skb);
  		else if (skb->protocol == htons(ETH_P_IP) && isk->cmsg_flags)
  			ip_cmsg_recv(msg, skb);
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
892
893
894
  #endif
  	} else {
  		BUG();
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
895
  	}
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
896

c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
897
898
899
900
901
902
903
904
905
  	err = copied;
  
  done:
  	skb_free_datagram(sk, skb);
  out:
  	pr_debug("ping_recvmsg -> %d
  ", err);
  	return err;
  }
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
906
  EXPORT_SYMBOL_GPL(ping_recvmsg);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
907

6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
908
  int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
909
910
911
  {
  	pr_debug("ping_queue_rcv_skb(sk=%p,sk->num=%d,skb=%p)
  ",
058bd4d2a   Joe Perches   net: Convert prin...
912
  		 inet_sk(sk), inet_sk(sk)->inet_num, skb);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
913
  	if (sock_queue_rcv_skb(sk, skb) < 0) {
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
914
915
916
917
918
919
920
  		kfree_skb(skb);
  		pr_debug("ping_queue_rcv_skb -> failed
  ");
  		return -1;
  	}
  	return 0;
  }
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
921
  EXPORT_SYMBOL_GPL(ping_queue_rcv_skb);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
922
923
924
925
926
  
  
  /*
   *	All we need to do is get the socket.
   */
e3e321702   Rick Jones   icmp: Remove some...
927
  bool ping_rcv(struct sk_buff *skb)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
928
929
930
  {
  	struct sock *sk;
  	struct net *net = dev_net(skb->dev);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
931
  	struct icmphdr *icmph = icmp_hdr(skb);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
932
933
934
935
936
  
  	/* We assume the packet has already been checked by icmp_rcv */
  
  	pr_debug("ping_rcv(skb=%p,id=%04x,seq=%04x)
  ",
058bd4d2a   Joe Perches   net: Convert prin...
937
  		 skb, ntohs(icmph->un.echo.id), ntohs(icmph->un.echo.sequence));
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
938
939
940
  
  	/* Push ICMP header back */
  	skb_push(skb, skb->data - (u8 *)icmph);
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
941
  	sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id));
00db41243   Ian Morris   ipv4: coding styl...
942
  	if (sk) {
fc752f1f4   subashab@codeaurora.org   ping: Fix race in...
943
  		struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
944
945
  		pr_debug("rcv on socket %p
  ", sk);
fc752f1f4   subashab@codeaurora.org   ping: Fix race in...
946
947
  		if (skb2)
  			ping_queue_rcv_skb(sk, skb2);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
948
  		sock_put(sk);
e3e321702   Rick Jones   icmp: Remove some...
949
  		return true;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
950
951
952
  	}
  	pr_debug("no socket, dropping
  ");
e3e321702   Rick Jones   icmp: Remove some...
953
  	return false;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
954
  }
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
955
  EXPORT_SYMBOL_GPL(ping_rcv);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
956
957
958
959
960
961
962
  
  struct proto ping_prot = {
  	.name =		"PING",
  	.owner =	THIS_MODULE,
  	.init =		ping_init_sock,
  	.close =	ping_close,
  	.connect =	ip4_datagram_connect,
286c72dea   Eric Dumazet   udp: must lock th...
963
  	.disconnect =	__udp_disconnect,
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
964
965
  	.setsockopt =	ip_setsockopt,
  	.getsockopt =	ip_getsockopt,
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
966
  	.sendmsg =	ping_v4_sendmsg,
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
967
968
969
  	.recvmsg =	ping_recvmsg,
  	.bind =		ping_bind,
  	.backlog_rcv =	ping_queue_rcv_skb,
8141ed9fc   Steffen Klassert   ipv4: Add a socke...
970
  	.release_cb =	ip4_datagram_release_cb,
6d0bfe226   Lorenzo Colitti   net: ipv6: Add IP...
971
972
973
  	.hash =		ping_hash,
  	.unhash =	ping_unhash,
  	.get_port =	ping_get_port,
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
  	.obj_size =	sizeof(struct inet_sock),
  };
  EXPORT_SYMBOL(ping_prot);
  
  #ifdef CONFIG_PROC_FS
  
  static struct sock *ping_get_first(struct seq_file *seq, int start)
  {
  	struct sock *sk;
  	struct ping_iter_state *state = seq->private;
  	struct net *net = seq_file_net(seq);
  
  	for (state->bucket = start; state->bucket < PING_HTABLE_SIZE;
  	     ++state->bucket) {
  		struct hlist_nulls_node *node;
75e308c89   Changli Gao   net: ping: fix th...
989
990
991
  		struct hlist_nulls_head *hslot;
  
  		hslot = &ping_table.hash[state->bucket];
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
992
993
994
995
996
  
  		if (hlist_nulls_empty(hslot))
  			continue;
  
  		sk_nulls_for_each(sk, node, hslot) {
8cc785f6f   Lorenzo Colitti   net: ipv4: make t...
997
998
  			if (net_eq(sock_net(sk), net) &&
  			    sk->sk_family == state->family)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
  				goto found;
  		}
  	}
  	sk = NULL;
  found:
  	return sk;
  }
  
  static struct sock *ping_get_next(struct seq_file *seq, struct sock *sk)
  {
  	struct ping_iter_state *state = seq->private;
  	struct net *net = seq_file_net(seq);
  
  	do {
  		sk = sk_nulls_next(sk);
  	} while (sk && (!net_eq(sock_net(sk), net)));
  
  	if (!sk)
  		return ping_get_first(seq, state->bucket + 1);
  	return sk;
  }
  
  static struct sock *ping_get_idx(struct seq_file *seq, loff_t pos)
  {
  	struct sock *sk = ping_get_first(seq, 0);
  
  	if (sk)
  		while (pos && (sk = ping_get_next(seq, sk)) != NULL)
  			--pos;
  	return pos ? NULL : sk;
  }
d862e5461   Lorenzo Colitti   net: ipv6: Implem...
1030
  void *ping_seq_start(struct seq_file *seq, loff_t *pos, sa_family_t family)
ad64b8be7   Lance Richardson   ipv4: eliminate l...
1031
  	__acquires(ping_table.lock)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1032
1033
1034
  {
  	struct ping_iter_state *state = seq->private;
  	state->bucket = 0;
8cc785f6f   Lorenzo Colitti   net: ipv4: make t...
1035
  	state->family = family;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1036
1037
1038
1039
1040
  
  	read_lock_bh(&ping_table.lock);
  
  	return *pos ? ping_get_idx(seq, *pos-1) : SEQ_START_TOKEN;
  }
d862e5461   Lorenzo Colitti   net: ipv6: Implem...
1041
  EXPORT_SYMBOL_GPL(ping_seq_start);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1042

8cc785f6f   Lorenzo Colitti   net: ipv4: make t...
1043
1044
1045
1046
  static void *ping_v4_seq_start(struct seq_file *seq, loff_t *pos)
  {
  	return ping_seq_start(seq, pos, AF_INET);
  }
d862e5461   Lorenzo Colitti   net: ipv6: Implem...
1047
  void *ping_seq_next(struct seq_file *seq, void *v, loff_t *pos)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
  {
  	struct sock *sk;
  
  	if (v == SEQ_START_TOKEN)
  		sk = ping_get_idx(seq, 0);
  	else
  		sk = ping_get_next(seq, v);
  
  	++*pos;
  	return sk;
  }
d862e5461   Lorenzo Colitti   net: ipv6: Implem...
1059
  EXPORT_SYMBOL_GPL(ping_seq_next);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1060

d862e5461   Lorenzo Colitti   net: ipv6: Implem...
1061
  void ping_seq_stop(struct seq_file *seq, void *v)
ad64b8be7   Lance Richardson   ipv4: eliminate l...
1062
  	__releases(ping_table.lock)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1063
1064
1065
  {
  	read_unlock_bh(&ping_table.lock);
  }
d862e5461   Lorenzo Colitti   net: ipv6: Implem...
1066
  EXPORT_SYMBOL_GPL(ping_seq_stop);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1067

8cc785f6f   Lorenzo Colitti   net: ipv4: make t...
1068
  static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
652586df9   Tetsuo Handa   seq_file: remove ...
1069
  		int bucket)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1070
1071
1072
1073
1074
1075
1076
1077
  {
  	struct inet_sock *inet = inet_sk(sp);
  	__be32 dest = inet->inet_daddr;
  	__be32 src = inet->inet_rcv_saddr;
  	__u16 destp = ntohs(inet->inet_dport);
  	__u16 srcp = ntohs(inet->inet_sport);
  
  	seq_printf(f, "%5d: %08X:%04X %08X:%04X"
ea9a03791   Patrick Talbert   net: Treat sock->...
1078
  		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %u",
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1079
1080
1081
  		bucket, src, srcp, dest, destp, sp->sk_state,
  		sk_wmem_alloc_get(sp),
  		sk_rmem_alloc_get(sp),
a7cb5a49b   Eric W. Biederman   userns: Print out...
1082
1083
1084
  		0, 0L, 0,
  		from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)),
  		0, sock_i_ino(sp),
41c6d650f   Reshetova, Elena   net: convert sock...
1085
  		refcount_read(&sp->sk_refcnt), sp,
652586df9   Tetsuo Handa   seq_file: remove ...
1086
  		atomic_read(&sp->sk_drops));
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1087
  }
8cc785f6f   Lorenzo Colitti   net: ipv4: make t...
1088
  static int ping_v4_seq_show(struct seq_file *seq, void *v)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1089
  {
652586df9   Tetsuo Handa   seq_file: remove ...
1090
  	seq_setwidth(seq, 127);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1091
  	if (v == SEQ_START_TOKEN)
652586df9   Tetsuo Handa   seq_file: remove ...
1092
  		seq_puts(seq, "  sl  local_address rem_address   st tx_queue "
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1093
1094
1095
1096
  			   "rx_queue tr tm->when retrnsmt   uid  timeout "
  			   "inode ref pointer drops");
  	else {
  		struct ping_iter_state *state = seq->private;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1097

652586df9   Tetsuo Handa   seq_file: remove ...
1098
  		ping_v4_format_sock(v, seq, state->bucket);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1099
  	}
652586df9   Tetsuo Handa   seq_file: remove ...
1100
1101
  	seq_pad(seq, '
  ');
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1102
1103
  	return 0;
  }
f45502216   Christoph Hellwig   ipv{4,6}/ping: si...
1104
1105
1106
1107
1108
1109
  static const struct seq_operations ping_v4_seq_ops = {
  	.start		= ping_v4_seq_start,
  	.show		= ping_v4_seq_show,
  	.next		= ping_seq_next,
  	.stop		= ping_seq_stop,
  };
f45502216   Christoph Hellwig   ipv{4,6}/ping: si...
1110
  static int __net_init ping_v4_proc_init_net(struct net *net)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1111
  {
c35063722   Christoph Hellwig   proc: introduce p...
1112
1113
  	if (!proc_create_net("icmp", 0444, net->proc_net, &ping_v4_seq_ops,
  			sizeof(struct ping_iter_state)))
8cc785f6f   Lorenzo Colitti   net: ipv4: make t...
1114
1115
  		return -ENOMEM;
  	return 0;
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1116
  }
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1117

8cc785f6f   Lorenzo Colitti   net: ipv4: make t...
1118
  static void __net_exit ping_v4_proc_exit_net(struct net *net)
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1119
  {
f45502216   Christoph Hellwig   ipv{4,6}/ping: si...
1120
  	remove_proc_entry("icmp", net->proc_net);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1121
  }
8cc785f6f   Lorenzo Colitti   net: ipv4: make t...
1122
1123
1124
  static struct pernet_operations ping_v4_net_ops = {
  	.init = ping_v4_proc_init_net,
  	.exit = ping_v4_proc_exit_net,
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1125
1126
1127
1128
  };
  
  int __init ping_proc_init(void)
  {
8cc785f6f   Lorenzo Colitti   net: ipv4: make t...
1129
  	return register_pernet_subsys(&ping_v4_net_ops);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1130
1131
1132
1133
  }
  
  void ping_proc_exit(void)
  {
8cc785f6f   Lorenzo Colitti   net: ipv4: make t...
1134
  	unregister_pernet_subsys(&ping_v4_net_ops);
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
  }
  
  #endif
  
  void __init ping_init(void)
  {
  	int i;
  
  	for (i = 0; i < PING_HTABLE_SIZE; i++)
  		INIT_HLIST_NULLS_HEAD(&ping_table.hash[i], i);
  	rwlock_init(&ping_table.lock);
  }