diff options
Diffstat (limited to 'net/ipv6/raw.c')
| -rw-r--r-- | net/ipv6/raw.c | 33 | 
1 files changed, 21 insertions, 12 deletions
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 84dbe21b71e5..70693bc7ad9d 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later  /*   *	RAW sockets for IPv6   *	Linux INET6 implementation @@ -11,11 +12,6 @@   *	Hideaki YOSHIFUJI	:	sin6_scope_id support   *	YOSHIFUJI,H.@USAGI	:	raw checksum (RFC2292(bis) compliance)   *	Kazunori MIYAZAWA @USAGI:	change process style to use ip6_append_data - * - *	This program is free software; you can redistribute it and/or - *      modify it under the terms of the GNU General Public License - *      as published by the Free Software Foundation; either version - *      2 of the License, or (at your option) any later version.   */  #include <linux/errno.h> @@ -287,7 +283,9 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)  			/* Binding to link-local address requires an interface */  			if (!sk->sk_bound_dev_if)  				goto out_unlock; +		} +		if (sk->sk_bound_dev_if) {  			err = -ENODEV;  			dev = dev_get_by_index_rcu(sock_net(sk),  						   sk->sk_bound_dev_if); @@ -781,6 +779,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)  	struct flowi6 fl6;  	struct ipcm6_cookie ipc6;  	int addr_len = msg->msg_namelen; +	int hdrincl;  	u16 proto;  	int err; @@ -794,6 +793,13 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)  	if (msg->msg_flags & MSG_OOB)  		return -EOPNOTSUPP; +	/* hdrincl should be READ_ONCE(inet->hdrincl) +	 * but READ_ONCE() doesn't work with bit fields. +	 * Doing this indirectly yields the same result. +	 */ +	hdrincl = inet->hdrincl; +	hdrincl = READ_ONCE(hdrincl); +  	/*  	 *	Get and verify the address.  	 */ @@ -885,11 +891,14 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)  	opt = ipv6_fixup_options(&opt_space, opt);  	fl6.flowi6_proto = proto; -	rfv.msg = msg; -	rfv.hlen = 0; -	err = rawv6_probe_proto_opt(&rfv, &fl6); -	if (err) -		goto out; + +	if (!hdrincl) { +		rfv.msg = msg; +		rfv.hlen = 0; +		err = rawv6_probe_proto_opt(&rfv, &fl6); +		if (err) +			goto out; +	}  	if (!ipv6_addr_any(daddr))  		fl6.daddr = *daddr; @@ -906,7 +915,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)  		fl6.flowi6_oif = np->ucast_oif;  	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); -	if (inet->hdrincl) +	if (hdrincl)  		fl6.flowi6_flags |= FLOWI_FLAG_KNOWN_NH;  	if (ipc6.tclass < 0) @@ -929,7 +938,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)  		goto do_confirm;  back_from_confirm: -	if (inet->hdrincl) +	if (hdrincl)  		err = rawv6_send_hdrinc(sk, msg, len, &fl6, &dst,  					msg->msg_flags, &ipc6.sockc);  	else {  |