2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2013-05-23 00:17:31 +04:00
/*
* 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
*
* Based on ipv4 / ping . c code .
*
* Authors : Lorenzo Colitti ( IPv6 support )
* Vasiliy Kulikov / Openwall ( IPv4 implementation , for Linux 2.6 ) ,
* Pavel Kankovsky ( IPv4 implementation , for Linux 2.4 .32 )
*/
# include <net/addrconf.h>
# include <net/ipv6.h>
# include <net/ip6_route.h>
# include <net/protocol.h>
# include <net/udp.h>
# include <net/transp_v6.h>
2018-04-10 21:04:20 +03:00
# include <linux/proc_fs.h>
2022-09-09 03:49:39 +03:00
# include <linux/bpf-cgroup.h>
2013-05-23 00:17:31 +04:00
# include <net/ping.h>
/* Compatibility glue so we can support IPv6 when it's compiled as a module */
2013-11-23 03:46:12 +04:00
static int dummy_ipv6_recv_error ( struct sock * sk , struct msghdr * msg , int len ,
int * addr_len )
2013-05-23 00:17:31 +04:00
{
return - EAFNOSUPPORT ;
}
2014-01-20 06:43:08 +04:00
static void dummy_ip6_datagram_recv_ctl ( struct sock * sk , struct msghdr * msg ,
2013-06-12 17:04:16 +04:00
struct sk_buff * skb )
2013-05-23 00:17:31 +04:00
{
}
2013-06-12 17:04:16 +04:00
static int dummy_icmpv6_err_convert ( u8 type , u8 code , int * err )
2013-05-23 00:17:31 +04:00
{
return - EAFNOSUPPORT ;
}
2013-06-12 17:04:16 +04:00
static void dummy_ipv6_icmp_error ( struct sock * sk , struct sk_buff * skb , int err ,
__be16 port , u32 info , u8 * payload ) { }
static int dummy_ipv6_chk_addr ( struct net * net , const struct in6_addr * addr ,
const struct net_device * dev , int strict )
2013-05-23 00:17:31 +04:00
{
return 0 ;
}
2022-09-09 03:49:39 +03:00
static int ping_v6_pre_connect ( struct sock * sk , struct sockaddr * uaddr ,
int addr_len )
{
/* This check is replicated from __ip6_datagram_connect() and
* intended to prevent BPF program called below from accessing
* bytes that are out of the bound specified by user in addr_len .
*/
if ( addr_len < SIN6_LEN_RFC2133 )
return - EINVAL ;
2023-10-11 21:51:04 +03:00
return BPF_CGROUP_RUN_PROG_INET6_CONNECT_LOCK ( sk , uaddr , & addr_len ) ;
2022-09-09 03:49:39 +03:00
}
2016-03-23 12:59:51 +03:00
static int ping_v6_sendmsg ( struct sock * sk , struct msghdr * msg , size_t len )
2013-05-23 00:17:31 +04:00
{
struct inet_sock * inet = inet_sk ( sk ) ;
struct ipv6_pinfo * np = inet6_sk ( sk ) ;
struct icmp6hdr user_icmph ;
int addr_type ;
struct in6_addr * daddr ;
2016-08-12 19:13:38 +03:00
int oif = 0 ;
2013-05-23 00:17:31 +04:00
struct flowi6 fl6 ;
int err ;
struct dst_entry * dst ;
struct rt6_info * rt ;
struct pingfakehdr pfh ;
2016-05-03 07:40:07 +03:00
struct ipcm6_cookie ipc6 ;
2013-05-23 00:17:31 +04:00
err = ping_common_sendmsg ( AF_INET6 , msg , len , & user_icmph ,
sizeof ( user_icmph ) ) ;
if ( err )
return err ;
2022-07-20 21:13:10 +03:00
memset ( & fl6 , 0 , sizeof ( fl6 ) ) ;
2013-05-23 00:17:31 +04:00
if ( msg - > msg_name ) {
2014-01-18 01:53:15 +04:00
DECLARE_SOCKADDR ( struct sockaddr_in6 * , u , msg - > msg_name ) ;
net: ping: Return EAFNOSUPPORT when appropriate.
1. For an IPv4 ping socket, ping_check_bind_addr does not check
the family of the socket address that's passed in. Instead,
make it behave like inet_bind, which enforces either that the
address family is AF_INET, or that the family is AF_UNSPEC and
the address is 0.0.0.0.
2. For an IPv6 ping socket, ping_check_bind_addr returns EINVAL
if the socket family is not AF_INET6. Return EAFNOSUPPORT
instead, for consistency with inet6_bind.
3. Make ping_v4_sendmsg and ping_v6_sendmsg return EAFNOSUPPORT
instead of EINVAL if an incorrect socket address structure is
passed in.
4. Make IPv6 ping sockets be IPv6-only. The code does not support
IPv4, and it cannot easily be made to support IPv4 because
the protocol numbers for ICMP and ICMPv6 are different. This
makes connect(::ffff:192.0.2.1) fail with EAFNOSUPPORT instead
of making the socket unusable.
Among other things, this fixes an oops that can be triggered by:
int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
struct sockaddr_in6 sin6 = {
.sin6_family = AF_INET6,
.sin6_addr = in6addr_any,
};
bind(s, (struct sockaddr *) &sin6, sizeof(sin6));
Change-Id: If06ca86d9f1e4593c0d6df174caca3487c57a241
Signed-off-by: Lorenzo Colitti <lorenzo@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2015-03-03 17:16:16 +03:00
if ( msg - > msg_namelen < sizeof ( * u ) )
2013-05-23 00:17:31 +04:00
return - EINVAL ;
net: ping: Return EAFNOSUPPORT when appropriate.
1. For an IPv4 ping socket, ping_check_bind_addr does not check
the family of the socket address that's passed in. Instead,
make it behave like inet_bind, which enforces either that the
address family is AF_INET, or that the family is AF_UNSPEC and
the address is 0.0.0.0.
2. For an IPv6 ping socket, ping_check_bind_addr returns EINVAL
if the socket family is not AF_INET6. Return EAFNOSUPPORT
instead, for consistency with inet6_bind.
3. Make ping_v4_sendmsg and ping_v6_sendmsg return EAFNOSUPPORT
instead of EINVAL if an incorrect socket address structure is
passed in.
4. Make IPv6 ping sockets be IPv6-only. The code does not support
IPv4, and it cannot easily be made to support IPv4 because
the protocol numbers for ICMP and ICMPv6 are different. This
makes connect(::ffff:192.0.2.1) fail with EAFNOSUPPORT instead
of making the socket unusable.
Among other things, this fixes an oops that can be triggered by:
int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
struct sockaddr_in6 sin6 = {
.sin6_family = AF_INET6,
.sin6_addr = in6addr_any,
};
bind(s, (struct sockaddr *) &sin6, sizeof(sin6));
Change-Id: If06ca86d9f1e4593c0d6df174caca3487c57a241
Signed-off-by: Lorenzo Colitti <lorenzo@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2015-03-03 17:16:16 +03:00
if ( u - > sin6_family ! = AF_INET6 ) {
return - EAFNOSUPPORT ;
2013-05-23 00:17:31 +04:00
}
daddr = & ( u - > sin6_addr ) ;
2023-09-12 19:02:12 +03:00
if ( inet6_test_bit ( SNDFLOW , sk ) )
2022-07-20 21:13:10 +03:00
fl6 . flowlabel = u - > sin6_flowinfo & IPV6_FLOWINFO_MASK ;
2016-08-12 19:13:38 +03:00
if ( __ipv6_addr_needs_scope_id ( ipv6_addr_type ( daddr ) ) )
oif = u - > sin6_scope_id ;
2013-05-23 00:17:31 +04:00
} else {
if ( sk - > sk_state ! = TCP_ESTABLISHED )
return - EDESTADDRREQ ;
ipv6: make lookups simpler and faster
TCP listener refactoring, part 4 :
To speed up inet lookups, we moved IPv4 addresses from inet to struct
sock_common
Now is time to do the same for IPv6, because it permits us to have fast
lookups for all kind of sockets, including upcoming SYN_RECV.
Getting IPv6 addresses in TCP lookups currently requires two extra cache
lines, plus a dereference (and memory stall).
inet6_sk(sk) does the dereference of inet_sk(__sk)->pinet6
This patch is way bigger than its IPv4 counter part, because for IPv4,
we could add aliases (inet_daddr, inet_rcv_saddr), while on IPv6,
it's not doable easily.
inet6_sk(sk)->daddr becomes sk->sk_v6_daddr
inet6_sk(sk)->rcv_saddr becomes sk->sk_v6_rcv_saddr
And timewait socket also have tw->tw_v6_daddr & tw->tw_v6_rcv_saddr
at the same offset.
We get rid of INET6_TW_MATCH() as INET6_MATCH() is now the generic
macro.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-10-04 02:42:29 +04:00
daddr = & sk - > sk_v6_daddr ;
2022-07-20 21:13:10 +03:00
fl6 . flowlabel = np - > flow_label ;
2013-05-23 00:17:31 +04:00
}
2016-08-12 19:13:38 +03:00
if ( ! oif )
oif = sk - > sk_bound_dev_if ;
if ( ! oif )
oif = np - > sticky_pktinfo . ipi6_ifindex ;
if ( ! oif & & ipv6_addr_is_multicast ( daddr ) )
oif = np - > mcast_oif ;
else if ( ! oif )
oif = np - > ucast_oif ;
2013-05-23 00:17:31 +04:00
addr_type = ipv6_addr_type ( daddr ) ;
2016-08-12 19:13:38 +03:00
if ( ( __ipv6_addr_needs_scope_id ( addr_type ) & & ! oif ) | |
( addr_type & IPV6_ADDR_MAPPED ) | |
2023-06-07 19:05:02 +03:00
( oif & & sk - > sk_bound_dev_if & & oif ! = sk - > sk_bound_dev_if & &
l3mdev_master_ifindex_by_index ( sock_net ( sk ) , oif ) ! = sk - > sk_bound_dev_if ) )
2013-05-23 00:17:31 +04:00
return - EINVAL ;
2023-09-12 19:02:07 +03:00
ipcm6_init_sk ( & ipc6 , sk ) ;
2023-08-31 16:52:11 +03:00
ipc6 . sockc . tsflags = READ_ONCE ( sk - > sk_tsflags ) ;
2023-07-28 18:03:15 +03:00
ipc6 . sockc . mark = READ_ONCE ( sk - > sk_mark ) ;
2022-02-10 03:36:41 +03:00
2022-05-31 11:45:44 +03:00
fl6 . flowi6_oif = oif ;
2022-02-17 04:21:16 +03:00
if ( msg - > msg_controllen ) {
struct ipv6_txoptions opt = { } ;
opt . tot_len = sizeof ( opt ) ;
ipc6 . opt = & opt ;
2022-02-10 03:36:41 +03:00
2022-02-17 04:21:16 +03:00
err = ip6_datagram_send_ctl ( sock_net ( sk ) , sk , msg , & fl6 , & ipc6 ) ;
if ( err < 0 )
return err ;
/* Changes to txoptions and flow info are not implemented, yet.
2022-05-31 11:45:44 +03:00
* Drop the options .
2022-02-17 04:21:16 +03:00
*/
ipc6 . opt = NULL ;
}
2013-05-23 00:17:31 +04:00
fl6 . flowi6_proto = IPPROTO_ICMPV6 ;
fl6 . saddr = np - > saddr ;
fl6 . daddr = * daddr ;
2022-02-10 03:36:41 +03:00
fl6 . flowi6_mark = ipc6 . sockc . mark ;
2016-11-03 20:23:43 +03:00
fl6 . flowi6_uid = sk - > sk_uid ;
2013-05-23 00:17:31 +04:00
fl6 . fl6_icmp_type = user_icmph . icmp6_type ;
fl6 . fl6_icmp_code = user_icmph . icmp6_code ;
2020-09-28 05:38:26 +03:00
security_sk_classify_flow ( sk , flowi6_to_flowi_common ( & fl6 ) ) ;
2013-05-23 00:17:31 +04:00
2016-06-11 21:08:19 +03:00
fl6 . flowlabel = ip6_make_flowinfo ( ipc6 . tclass , fl6 . flowlabel ) ;
2018-04-03 15:00:08 +03:00
dst = ip6_sk_dst_lookup_flow ( sk , & fl6 , daddr , false ) ;
2013-05-23 00:17:31 +04:00
if ( IS_ERR ( dst ) )
return PTR_ERR ( dst ) ;
rt = ( struct rt6_info * ) dst ;
if ( ! fl6 . flowi6_oif & & ipv6_addr_is_multicast ( & fl6 . daddr ) )
fl6 . flowi6_oif = np - > mcast_oif ;
else if ( ! fl6 . flowi6_oif )
fl6 . flowi6_oif = np - > ucast_oif ;
pfh . icmph . type = user_icmph . icmp6_type ;
pfh . icmph . code = user_icmph . icmp6_code ;
pfh . icmph . checksum = 0 ;
pfh . icmph . un . echo . id = inet - > inet_sport ;
pfh . icmph . un . echo . sequence = user_icmph . icmp6_sequence ;
2014-11-28 04:34:16 +03:00
pfh . msg = msg ;
2013-05-23 00:17:31 +04:00
pfh . wcheck = 0 ;
pfh . family = AF_INET6 ;
2022-02-17 04:21:16 +03:00
if ( ipc6 . hlimit < 0 )
ipc6 . hlimit = ip6_sk_dst_hoplimit ( np , & fl6 , dst ) ;
2013-05-23 00:17:31 +04:00
2013-07-03 19:52:49 +04:00
lock_sock ( sk ) ;
2013-05-23 00:17:31 +04:00
err = ip6_append_data ( sk , ping_getfrag , & pfh , len ,
inet: ping: fix recent breakage
Blamed commit broke the assumption used by ping sendmsg() that
allocated skb would have MAX_HEADER bytes in skb->head.
This patch changes the way ping works, by making sure
the skb head contains space for the icmp header,
and adjusting ping_getfrag() which was desperate
about going past the icmp header :/
This is adopting what UDP does, mostly.
syzbot is able to crash a host using both kfence and following repro in a loop.
fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6)
connect(fd, {sa_family=AF_INET6, sin6_port=htons(0), sin6_flowinfo=htonl(0),
inet_pton(AF_INET6, "::1", &sin6_addr), sin6_scope_id=0}, 28
sendmsg(fd, {msg_name=NULL, msg_namelen=0, msg_iov=[
{iov_base="\200\0\0\0\23\0\0\0\0\0\0\0\0\0"..., iov_len=65496}],
msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0
When kfence triggers, skb->head only has 64 bytes, immediately followed
by struct skb_shared_info (no extra headroom based on ksize(ptr))
Then icmpv6_push_pending_frames() is overwriting first bytes
of skb_shinfo(skb), making nr_frags bigger than MAX_SKB_FRAGS,
and/or setting shinfo->gso_size to a non zero value.
If nr_frags is mangled, a crash happens in skb_release_data()
If gso_size is mangled, we have the following report:
lo: caps=(0x00000516401d7c69, 0x00000516401d7c69)
WARNING: CPU: 0 PID: 7548 at net/core/dev.c:3239 skb_warn_bad_offload+0x119/0x230 net/core/dev.c:3239
Modules linked in:
CPU: 0 PID: 7548 Comm: syz-executor268 Not tainted 6.0.0-syzkaller-02754-g557f050166e5 #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/22/2022
RIP: 0010:skb_warn_bad_offload+0x119/0x230 net/core/dev.c:3239
Code: 70 03 00 00 e8 58 c3 24 fa 4c 8d a5 e8 00 00 00 e8 4c c3 24 fa 4c 89 e9 4c 89 e2 4c 89 f6 48 c7 c7 00 53 f5 8a e8 13 ac e7 01 <0f> 0b 5b 5d 41 5c 41 5d 41 5e e9 28 c3 24 fa e8 23 c3 24 fa 48 89
RSP: 0018:ffffc9000366f3e8 EFLAGS: 00010282
RAX: 0000000000000000 RBX: ffff88807a9d9d00 RCX: 0000000000000000
RDX: ffff8880780c0000 RSI: ffffffff8160f6f8 RDI: fffff520006cde6f
RBP: ffff888079952000 R08: 0000000000000005 R09: 0000000000000000
R10: 0000000000000400 R11: 0000000000000000 R12: ffff8880799520e8
R13: ffff88807a9da070 R14: ffff888079952000 R15: 0000000000000000
FS: 0000555556be6300(0000) GS:ffff8880b9a00000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000020010000 CR3: 000000006eb7b000 CR4: 00000000003506f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
<TASK>
gso_features_check net/core/dev.c:3521 [inline]
netif_skb_features+0x83e/0xb90 net/core/dev.c:3554
validate_xmit_skb+0x2b/0xf10 net/core/dev.c:3659
__dev_queue_xmit+0x998/0x3ad0 net/core/dev.c:4248
dev_queue_xmit include/linux/netdevice.h:3008 [inline]
neigh_hh_output include/net/neighbour.h:530 [inline]
neigh_output include/net/neighbour.h:544 [inline]
ip6_finish_output2+0xf97/0x1520 net/ipv6/ip6_output.c:134
__ip6_finish_output net/ipv6/ip6_output.c:195 [inline]
ip6_finish_output+0x690/0x1160 net/ipv6/ip6_output.c:206
NF_HOOK_COND include/linux/netfilter.h:291 [inline]
ip6_output+0x1ed/0x540 net/ipv6/ip6_output.c:227
dst_output include/net/dst.h:445 [inline]
ip6_local_out+0xaf/0x1a0 net/ipv6/output_core.c:161
ip6_send_skb+0xb7/0x340 net/ipv6/ip6_output.c:1966
ip6_push_pending_frames+0xdd/0x100 net/ipv6/ip6_output.c:1986
icmpv6_push_pending_frames+0x2af/0x490 net/ipv6/icmp.c:303
ping_v6_sendmsg+0xc44/0x1190 net/ipv6/ping.c:190
inet_sendmsg+0x99/0xe0 net/ipv4/af_inet.c:819
sock_sendmsg_nosec net/socket.c:714 [inline]
sock_sendmsg+0xcf/0x120 net/socket.c:734
____sys_sendmsg+0x712/0x8c0 net/socket.c:2482
___sys_sendmsg+0x110/0x1b0 net/socket.c:2536
__sys_sendmsg+0xf3/0x1c0 net/socket.c:2565
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x63/0xcd
RIP: 0033:0x7f21aab42b89
Code: 28 00 00 00 75 05 48 83 c4 28 c3 e8 41 15 00 00 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 c0 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007fff1729d038 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007f21aab42b89
RDX: 0000000000000000 RSI: 0000000020000180 RDI: 0000000000000003
RBP: 0000000000000000 R08: 000000000000000d R09: 000000000000000d
R10: 000000000000000d R11: 0000000000000246 R12: 00007fff1729d050
R13: 00000000000f4240 R14: 0000000000021dd1 R15: 00007fff1729d044
</TASK>
Fixes: 47cf88993c91 ("net: unify alloclen calculation for paged requests")
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Pavel Begunkov <asml.silence@gmail.com>
Cc: Lorenzo Colitti <lorenzo@google.com>
Cc: Willem de Bruijn <willemb@google.com>
Cc: Maciej Żenczykowski <maze@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2022-10-12 00:27:29 +03:00
sizeof ( struct icmp6hdr ) , & ipc6 , & fl6 , rt ,
2018-07-06 17:12:57 +03:00
MSG_DONTWAIT ) ;
2013-05-23 00:17:31 +04:00
if ( err ) {
2014-03-31 22:14:10 +04:00
ICMP6_INC_STATS ( sock_net ( sk ) , rt - > rt6i_idev ,
ICMP6_MIB_OUTERRORS ) ;
2013-05-23 00:17:31 +04:00
ip6_flush_pending_frames ( sk ) ;
} else {
2017-10-06 09:46:14 +03:00
icmpv6_push_pending_frames ( sk , & fl6 ,
( struct icmp6hdr * ) & pfh . icmph , len ) ;
2013-05-23 00:17:31 +04:00
}
2013-07-03 19:52:49 +04:00
release_sock ( sk ) ;
2013-05-23 00:17:31 +04:00
2016-09-02 21:39:50 +03:00
dst_release ( dst ) ;
2013-07-03 19:12:40 +04:00
if ( err )
return err ;
return len ;
2013-05-23 00:17:31 +04:00
}
2013-05-31 19:05:50 +04:00
2016-03-23 12:59:51 +03:00
struct proto pingv6_prot = {
. name = " PINGv6 " ,
. owner = THIS_MODULE ,
. init = ping_init_sock ,
. close = ping_close ,
2022-09-09 03:49:39 +03:00
. pre_connect = ping_v6_pre_connect ,
2016-03-23 12:59:51 +03:00
. connect = ip6_datagram_connect_v6_only ,
2016-10-20 19:39:40 +03:00
. disconnect = __udp_disconnect ,
2016-03-23 12:59:51 +03:00
. setsockopt = ipv6_setsockopt ,
. getsockopt = ipv6_getsockopt ,
. sendmsg = ping_v6_sendmsg ,
. recvmsg = ping_recvmsg ,
. bind = ping_bind ,
. backlog_rcv = ping_queue_rcv_skb ,
. hash = ping_hash ,
. unhash = ping_unhash ,
. get_port = ping_get_port ,
net: bpf: Handle return value of BPF_CGROUP_RUN_PROG_INET{4,6}_POST_BIND()
The return value of BPF_CGROUP_RUN_PROG_INET{4,6}_POST_BIND() in
__inet_bind() is not handled properly. While the return value
is non-zero, it will set inet_saddr and inet_rcv_saddr to 0 and
exit:
err = BPF_CGROUP_RUN_PROG_INET4_POST_BIND(sk);
if (err) {
inet->inet_saddr = inet->inet_rcv_saddr = 0;
goto out_release_sock;
}
Let's take UDP for example and see what will happen. For UDP
socket, it will be added to 'udp_prot.h.udp_table->hash' and
'udp_prot.h.udp_table->hash2' after the sk->sk_prot->get_port()
called success. If 'inet->inet_rcv_saddr' is specified here,
then 'sk' will be in the 'hslot2' of 'hash2' that it don't belong
to (because inet_saddr is changed to 0), and UDP packet received
will not be passed to this sock. If 'inet->inet_rcv_saddr' is not
specified here, the sock will work fine, as it can receive packet
properly, which is wired, as the 'bind()' is already failed.
To undo the get_port() operation, introduce the 'put_port' field
for 'struct proto'. For TCP proto, it is inet_put_port(); For UDP
proto, it is udp_lib_unhash(); For icmp proto, it is
ping_unhash().
Therefore, after sys_bind() fail caused by
BPF_CGROUP_RUN_PROG_INET4_POST_BIND(), it will be unbinded, which
means that it can try to be binded to another port.
Signed-off-by: Menglong Dong <imagedong@tencent.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20220106132022.3470772-2-imagedong@tencent.com
2022-01-06 16:20:20 +03:00
. put_port = ping_unhash ,
2016-03-23 12:59:51 +03:00
. obj_size = sizeof ( struct raw6_sock ) ,
2023-07-20 14:09:01 +03:00
. ipv6_pinfo_offset = offsetof ( struct raw6_sock , inet6 ) ,
2016-03-23 12:59:51 +03:00
} ;
EXPORT_SYMBOL_GPL ( pingv6_prot ) ;
static struct inet_protosw pingv6_protosw = {
. type = SOCK_DGRAM ,
. protocol = IPPROTO_ICMPV6 ,
. prot = & pingv6_prot ,
2017-06-03 19:29:25 +03:00
. ops = & inet6_sockraw_ops ,
2016-03-23 12:59:51 +03:00
. flags = INET_PROTOSW_REUSE ,
} ;
2013-05-31 19:05:50 +04:00
# ifdef CONFIG_PROC_FS
static void * ping_v6_seq_start ( struct seq_file * seq , loff_t * pos )
{
return ping_seq_start ( seq , pos , AF_INET6 ) ;
}
2013-06-12 17:04:16 +04:00
static int ping_v6_seq_show ( struct seq_file * seq , void * v )
2013-05-31 19:05:50 +04:00
{
if ( v = = SEQ_START_TOKEN ) {
seq_puts ( seq , IPV6_SEQ_DGRAM_HEADER ) ;
} else {
int bucket = ( ( struct ping_iter_state * ) seq - > private ) - > bucket ;
2023-03-16 18:31:55 +03:00
struct inet_sock * inet = inet_sk ( ( struct sock * ) v ) ;
2013-05-31 19:05:50 +04:00
__u16 srcp = ntohs ( inet - > inet_sport ) ;
__u16 destp = ntohs ( inet - > inet_dport ) ;
ip6_dgram_sock_seq_show ( seq , v , srcp , destp , bucket ) ;
}
return 0 ;
}
2018-04-10 21:04:20 +03:00
static const struct seq_operations ping_v6_seq_ops = {
. start = ping_v6_seq_start ,
. show = ping_v6_seq_show ,
. next = ping_seq_next ,
. stop = ping_seq_stop ,
} ;
2013-05-31 19:05:50 +04:00
static int __net_init ping_v6_proc_init_net ( struct net * net )
{
2018-04-10 20:42:55 +03:00
if ( ! proc_create_net ( " icmp6 " , 0444 , net - > proc_net , & ping_v6_seq_ops ,
sizeof ( struct ping_iter_state ) ) )
2018-04-10 21:04:20 +03:00
return - ENOMEM ;
return 0 ;
2013-05-31 19:05:50 +04:00
}
2019-09-10 14:29:59 +03:00
static void __net_exit ping_v6_proc_exit_net ( struct net * net )
2013-05-31 19:05:50 +04:00
{
2018-04-10 21:04:20 +03:00
remove_proc_entry ( " icmp6 " , net - > proc_net ) ;
2013-05-31 19:05:50 +04:00
}
static struct pernet_operations ping_v6_net_ops = {
. init = ping_v6_proc_init_net ,
. exit = ping_v6_proc_exit_net ,
} ;
# endif
int __init pingv6_init ( void )
{
# ifdef CONFIG_PROC_FS
int ret = register_pernet_subsys ( & ping_v6_net_ops ) ;
if ( ret )
return ret ;
# endif
pingv6_ops . ipv6_recv_error = ipv6_recv_error ;
2014-01-20 06:43:08 +04:00
pingv6_ops . ip6_datagram_recv_common_ctl = ip6_datagram_recv_common_ctl ;
pingv6_ops . ip6_datagram_recv_specific_ctl =
ip6_datagram_recv_specific_ctl ;
2013-05-31 19:05:50 +04:00
pingv6_ops . icmpv6_err_convert = icmpv6_err_convert ;
pingv6_ops . ipv6_icmp_error = ipv6_icmp_error ;
pingv6_ops . ipv6_chk_addr = ipv6_chk_addr ;
return inet6_register_protosw ( & pingv6_protosw ) ;
}
/* This never gets called because it's not possible to unload the ipv6 module,
* but just in case .
*/
void pingv6_exit ( void )
{
pingv6_ops . ipv6_recv_error = dummy_ipv6_recv_error ;
2014-01-20 06:43:08 +04:00
pingv6_ops . ip6_datagram_recv_common_ctl = dummy_ip6_datagram_recv_ctl ;
pingv6_ops . ip6_datagram_recv_specific_ctl = dummy_ip6_datagram_recv_ctl ;
2013-05-31 19:05:50 +04:00
pingv6_ops . icmpv6_err_convert = dummy_icmpv6_err_convert ;
pingv6_ops . ipv6_icmp_error = dummy_ipv6_icmp_error ;
pingv6_ops . ipv6_chk_addr = dummy_ipv6_chk_addr ;
# ifdef CONFIG_PROC_FS
unregister_pernet_subsys ( & ping_v6_net_ops ) ;
# endif
inet6_unregister_protosw ( & pingv6_protosw ) ;
}