[PATCH 3.16 076/204] IPv4: early demux can return an error code

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



3.16.52-rc1 review patch.  If anyone has any objections, please let me know.

------------------

From: Paolo Abeni <pabeni@xxxxxxxxxx>

commit 7487449c86c65202b3b725c4524cb48dd65e4e6f upstream.

Currently no error is emitted, but this infrastructure will
used by the next patch to allow source address validation
for mcast sockets.
Since early demux can do a route lookup and an ipv4 route
lookup can return an error code this is consistent with the
current ipv4 route infrastructure.

Signed-off-by: Paolo Abeni <pabeni@xxxxxxxxxx>
Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
[bwh: Backported to 3.16:
 - Drop change to net_protocol::early_demux_handler
 - Keep using NET_INC_STATS_BH() in ip_rcv_finish()
 - Fix up additional return statement in udp_v4_early_demux()
 - Adjust context]
Signed-off-by: Ben Hutchings <ben@xxxxxxxxxxxxxxx>
---
--- a/include/net/protocol.h
+++ b/include/net/protocol.h
@@ -39,7 +39,7 @@
 
 /* This is used to register protocols. */
 struct net_protocol {
-	void			(*early_demux)(struct sk_buff *skb);
+	int			(*early_demux)(struct sk_buff *skb);
 	int			(*handler)(struct sk_buff *skb);
 	void			(*err_handler)(struct sk_buff *skb, u32 info);
 	unsigned int		no_policy:1,
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -350,7 +350,7 @@ void tcp_v4_err(struct sk_buff *skb, u32
 
 void tcp_shutdown(struct sock *sk, int how);
 
-void tcp_v4_early_demux(struct sk_buff *skb);
+int tcp_v4_early_demux(struct sk_buff *skb);
 int tcp_v4_rcv(struct sk_buff *skb);
 
 int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -177,7 +177,7 @@ int udp_lib_get_port(struct sock *sk, un
 		     unsigned int hash2_nulladdr);
 
 /* net/ipv4/udp.c */
-void udp_v4_early_demux(struct sk_buff *skb);
+int udp_v4_early_demux(struct sk_buff *skb);
 int udp_get_port(struct sock *sk, unsigned short snum,
 		 int (*saddr_cmp)(const struct sock *,
 				  const struct sock *));
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -313,6 +313,7 @@ static int ip_rcv_finish(struct sk_buff
 {
 	const struct iphdr *iph = ip_hdr(skb);
 	struct rtable *rt;
+	int err;
 
 	if (sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) {
 		const struct net_protocol *ipprot;
@@ -320,7 +321,9 @@ static int ip_rcv_finish(struct sk_buff
 
 		ipprot = rcu_dereference(inet_protos[protocol]);
 		if (ipprot && ipprot->early_demux) {
-			ipprot->early_demux(skb);
+			err = ipprot->early_demux(skb);
+			if (unlikely(err))
+				goto drop_error;
 			/* must reload iph, skb->head might have changed */
 			iph = ip_hdr(skb);
 		}
@@ -331,14 +334,10 @@ static int ip_rcv_finish(struct sk_buff
 	 *	how the packet travels inside Linux networking.
 	 */
 	if (!skb_dst(skb)) {
-		int err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
-					       iph->tos, skb->dev);
-		if (unlikely(err)) {
-			if (err == -EXDEV)
-				NET_INC_STATS_BH(dev_net(skb->dev),
-						 LINUX_MIB_IPRPFILTER);
-			goto drop;
-		}
+		err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
+					   iph->tos, skb->dev);
+		if (unlikely(err))
+			goto drop_error;
 	}
 
 #ifdef CONFIG_IP_ROUTE_CLASSID
@@ -368,6 +367,11 @@ static int ip_rcv_finish(struct sk_buff
 drop:
 	kfree_skb(skb);
 	return NET_RX_DROP;
+
+drop_error:
+	if (err == -EXDEV)
+		NET_INC_STATS_BH(dev_net(skb->dev), LINUX_MIB_IPRPFILTER);
+	goto drop;
 }
 
 /*
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1616,23 +1616,23 @@ csum_err:
 }
 EXPORT_SYMBOL(tcp_v4_do_rcv);
 
-void tcp_v4_early_demux(struct sk_buff *skb)
+int tcp_v4_early_demux(struct sk_buff *skb)
 {
 	const struct iphdr *iph;
 	const struct tcphdr *th;
 	struct sock *sk;
 
 	if (skb->pkt_type != PACKET_HOST)
-		return;
+		return 0;
 
 	if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct tcphdr)))
-		return;
+		return 0;
 
 	iph = ip_hdr(skb);
 	th = tcp_hdr(skb);
 
 	if (th->doff < sizeof(struct tcphdr) / 4)
-		return;
+		return 0;
 
 	sk = __inet_lookup_established(dev_net(skb->dev), &tcp_hashinfo,
 				       iph->saddr, th->source,
@@ -1651,6 +1651,7 @@ void tcp_v4_early_demux(struct sk_buff *
 				skb_dst_set_noref(skb, dst);
 		}
 	}
+	return 0;
 }
 
 /* Packet is added to VJ-style prequeue for processing in process
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1950,7 +1950,7 @@ static struct sock *__udp4_lib_demux_loo
 	return result;
 }
 
-void udp_v4_early_demux(struct sk_buff *skb)
+int udp_v4_early_demux(struct sk_buff *skb)
 {
 	struct net *net = dev_net(skb->dev);
 	const struct iphdr *iph;
@@ -1962,7 +1962,7 @@ void udp_v4_early_demux(struct sk_buff *
 
 	/* validate the packet */
 	if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct udphdr)))
-		return;
+		return 0;
 
 	iph = ip_hdr(skb);
 	uh = udp_hdr(skb);
@@ -1972,14 +1972,14 @@ void udp_v4_early_demux(struct sk_buff *
 		struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
 
 		if (!in_dev)
-			return;
+			return 0;
 
 		/* we are supposed to accept bcast packets */
 		if (skb->pkt_type == PACKET_MULTICAST) {
 			ours = ip_check_mc_rcu(in_dev, iph->daddr, iph->saddr,
 					       iph->protocol);
 			if (!ours)
-				return;
+				return 0;
 		}
 
 		sk = __udp4_lib_mcast_demux_lookup(net, uh->dest, iph->daddr,
@@ -1988,11 +1988,11 @@ void udp_v4_early_demux(struct sk_buff *
 		sk = __udp4_lib_demux_lookup(net, uh->dest, iph->daddr,
 					     uh->source, iph->saddr, dif);
 	} else {
-		return;
+		return 0;
 	}
 
 	if (!sk)
-		return;
+		return 0;
 
 	skb->sk = sk;
 	skb->destructor = sock_edemux;
@@ -2009,6 +2009,7 @@ void udp_v4_early_demux(struct sk_buff *
 			skb_dst_set_noref(skb, dst);
 		}
 	}
+	return 0;
 }
 
 int udp_rcv(struct sk_buff *skb)




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]