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)