net: Convert protocol error handlers from void to int
We'll need this to handle ICMP errors for tunnels without a sending socket (i.e. FoU and GUE). There, we might have to look up different types of IP tunnels, registered as network protocols, before we get a match, so we want this for the error handlers of IPPROTO_IPIP and IPPROTO_IPV6 in both inet_protos and inet6_protos. These error codes will be used in the next patch. For consistency, return sensible error codes in protocol error handlers whenever handlers can't handle errors because, even if valid, they don't match a protocol or any of its states. This has no effect on existing error handling paths. Signed-off-by: Stefano Brivio <sbrivio@redhat.com> Reviewed-by: Sabrina Dubroca <sd@queasysnail.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
ce7336610c
commit
32bbd8793f
@@ -151,20 +151,25 @@ drop:
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
static void gre_err(struct sk_buff *skb, u32 info)
|
||||
static int gre_err(struct sk_buff *skb, u32 info)
|
||||
{
|
||||
const struct gre_protocol *proto;
|
||||
const struct iphdr *iph = (const struct iphdr *)skb->data;
|
||||
u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f;
|
||||
int err = 0;
|
||||
|
||||
if (ver >= GREPROTO_MAX)
|
||||
return;
|
||||
return -EINVAL;
|
||||
|
||||
rcu_read_lock();
|
||||
proto = rcu_dereference(gre_proto[ver]);
|
||||
if (proto && proto->err_handler)
|
||||
proto->err_handler(skb, info);
|
||||
else
|
||||
err = -EPROTONOSUPPORT;
|
||||
rcu_read_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct net_protocol net_gre_protocol = {
|
||||
|
@@ -1079,7 +1079,7 @@ error:
|
||||
goto drop;
|
||||
}
|
||||
|
||||
void icmp_err(struct sk_buff *skb, u32 info)
|
||||
int icmp_err(struct sk_buff *skb, u32 info)
|
||||
{
|
||||
struct iphdr *iph = (struct iphdr *)skb->data;
|
||||
int offset = iph->ihl<<2;
|
||||
@@ -1094,13 +1094,15 @@ void icmp_err(struct sk_buff *skb, u32 info)
|
||||
*/
|
||||
if (icmph->type != ICMP_ECHOREPLY) {
|
||||
ping_err(skb, offset, info);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
|
||||
ipv4_update_pmtu(skb, net, info, 0, IPPROTO_ICMP);
|
||||
else if (type == ICMP_REDIRECT)
|
||||
ipv4_redirect(skb, net, 0, IPPROTO_ICMP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -121,8 +121,8 @@ static unsigned int ipgre_net_id __read_mostly;
|
||||
static unsigned int gre_tap_net_id __read_mostly;
|
||||
static unsigned int erspan_net_id __read_mostly;
|
||||
|
||||
static void ipgre_err(struct sk_buff *skb, u32 info,
|
||||
const struct tnl_ptk_info *tpi)
|
||||
static int ipgre_err(struct sk_buff *skb, u32 info,
|
||||
const struct tnl_ptk_info *tpi)
|
||||
{
|
||||
|
||||
/* All the routers (except for Linux) return only
|
||||
@@ -146,36 +146,6 @@ static void ipgre_err(struct sk_buff *skb, u32 info,
|
||||
unsigned int data_len = 0;
|
||||
struct ip_tunnel *t;
|
||||
|
||||
switch (type) {
|
||||
default:
|
||||
case ICMP_PARAMETERPROB:
|
||||
return;
|
||||
|
||||
case ICMP_DEST_UNREACH:
|
||||
switch (code) {
|
||||
case ICMP_SR_FAILED:
|
||||
case ICMP_PORT_UNREACH:
|
||||
/* Impossible event. */
|
||||
return;
|
||||
default:
|
||||
/* All others are translated to HOST_UNREACH.
|
||||
rfc2003 contains "deep thoughts" about NET_UNREACH,
|
||||
I believe they are just ether pollution. --ANK
|
||||
*/
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ICMP_TIME_EXCEEDED:
|
||||
if (code != ICMP_EXC_TTL)
|
||||
return;
|
||||
data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */
|
||||
break;
|
||||
|
||||
case ICMP_REDIRECT:
|
||||
break;
|
||||
}
|
||||
|
||||
if (tpi->proto == htons(ETH_P_TEB))
|
||||
itn = net_generic(net, gre_tap_net_id);
|
||||
else if (tpi->proto == htons(ETH_P_ERSPAN) ||
|
||||
@@ -189,27 +159,59 @@ static void ipgre_err(struct sk_buff *skb, u32 info,
|
||||
iph->daddr, iph->saddr, tpi->key);
|
||||
|
||||
if (!t)
|
||||
return;
|
||||
return -ENOENT;
|
||||
|
||||
switch (type) {
|
||||
default:
|
||||
case ICMP_PARAMETERPROB:
|
||||
return 0;
|
||||
|
||||
case ICMP_DEST_UNREACH:
|
||||
switch (code) {
|
||||
case ICMP_SR_FAILED:
|
||||
case ICMP_PORT_UNREACH:
|
||||
/* Impossible event. */
|
||||
return 0;
|
||||
default:
|
||||
/* All others are translated to HOST_UNREACH.
|
||||
rfc2003 contains "deep thoughts" about NET_UNREACH,
|
||||
I believe they are just ether pollution. --ANK
|
||||
*/
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ICMP_TIME_EXCEEDED:
|
||||
if (code != ICMP_EXC_TTL)
|
||||
return 0;
|
||||
data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */
|
||||
break;
|
||||
|
||||
case ICMP_REDIRECT:
|
||||
break;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (tpi->proto == htons(ETH_P_IPV6) &&
|
||||
!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len,
|
||||
type, data_len))
|
||||
return;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if (t->parms.iph.daddr == 0 ||
|
||||
ipv4_is_multicast(t->parms.iph.daddr))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
|
||||
t->err_count++;
|
||||
else
|
||||
t->err_count = 1;
|
||||
t->err_time = jiffies;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gre_err(struct sk_buff *skb, u32 info)
|
||||
|
@@ -140,6 +140,13 @@ static int ipip_err(struct sk_buff *skb, u32 info)
|
||||
struct ip_tunnel *t;
|
||||
int err = 0;
|
||||
|
||||
t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
|
||||
iph->daddr, iph->saddr, 0);
|
||||
if (!t) {
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case ICMP_DEST_UNREACH:
|
||||
switch (code) {
|
||||
@@ -167,13 +174,6 @@ static int ipip_err(struct sk_buff *skb, u32 info)
|
||||
goto out;
|
||||
}
|
||||
|
||||
t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
|
||||
iph->daddr, iph->saddr, 0);
|
||||
if (!t) {
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
|
||||
ipv4_update_pmtu(skb, net, info, t->parms.link, iph->protocol);
|
||||
goto out;
|
||||
|
@@ -423,7 +423,7 @@ EXPORT_SYMBOL(tcp_req_err);
|
||||
*
|
||||
*/
|
||||
|
||||
void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
|
||||
int tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
|
||||
{
|
||||
const struct iphdr *iph = (const struct iphdr *)icmp_skb->data;
|
||||
struct tcphdr *th = (struct tcphdr *)(icmp_skb->data + (iph->ihl << 2));
|
||||
@@ -446,20 +446,21 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
|
||||
inet_iif(icmp_skb), 0);
|
||||
if (!sk) {
|
||||
__ICMP_INC_STATS(net, ICMP_MIB_INERRORS);
|
||||
return;
|
||||
return -ENOENT;
|
||||
}
|
||||
if (sk->sk_state == TCP_TIME_WAIT) {
|
||||
inet_twsk_put(inet_twsk(sk));
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
seq = ntohl(th->seq);
|
||||
if (sk->sk_state == TCP_NEW_SYN_RECV)
|
||||
return tcp_req_err(sk, seq,
|
||||
type == ICMP_PARAMETERPROB ||
|
||||
type == ICMP_TIME_EXCEEDED ||
|
||||
(type == ICMP_DEST_UNREACH &&
|
||||
(code == ICMP_NET_UNREACH ||
|
||||
code == ICMP_HOST_UNREACH)));
|
||||
if (sk->sk_state == TCP_NEW_SYN_RECV) {
|
||||
tcp_req_err(sk, seq, type == ICMP_PARAMETERPROB ||
|
||||
type == ICMP_TIME_EXCEEDED ||
|
||||
(type == ICMP_DEST_UNREACH &&
|
||||
(code == ICMP_NET_UNREACH ||
|
||||
code == ICMP_HOST_UNREACH)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
bh_lock_sock(sk);
|
||||
/* If too many ICMPs get dropped on busy
|
||||
@@ -613,6 +614,7 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
|
||||
out:
|
||||
bh_unlock_sock(sk);
|
||||
sock_put(sk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __tcp_v4_send_check(struct sk_buff *skb, __be32 saddr, __be32 daddr)
|
||||
|
@@ -149,34 +149,40 @@ drop:
|
||||
}
|
||||
#endif
|
||||
|
||||
static void tunnel4_err(struct sk_buff *skb, u32 info)
|
||||
static int tunnel4_err(struct sk_buff *skb, u32 info)
|
||||
{
|
||||
struct xfrm_tunnel *handler;
|
||||
|
||||
for_each_tunnel_rcu(tunnel4_handlers, handler)
|
||||
if (!handler->err_handler(skb, info))
|
||||
break;
|
||||
return 0;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
static void tunnel64_err(struct sk_buff *skb, u32 info)
|
||||
static int tunnel64_err(struct sk_buff *skb, u32 info)
|
||||
{
|
||||
struct xfrm_tunnel *handler;
|
||||
|
||||
for_each_tunnel_rcu(tunnel64_handlers, handler)
|
||||
if (!handler->err_handler(skb, info))
|
||||
break;
|
||||
return 0;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_MPLS)
|
||||
static void tunnelmpls4_err(struct sk_buff *skb, u32 info)
|
||||
static int tunnelmpls4_err(struct sk_buff *skb, u32 info)
|
||||
{
|
||||
struct xfrm_tunnel *handler;
|
||||
|
||||
for_each_tunnel_rcu(tunnelmpls4_handlers, handler)
|
||||
if (!handler->err_handler(skb, info))
|
||||
break;
|
||||
return 0;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@@ -650,7 +650,7 @@ static struct sock *__udp4_lib_err_encap(struct net *net,
|
||||
* to find the appropriate port.
|
||||
*/
|
||||
|
||||
void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
|
||||
int __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
|
||||
{
|
||||
struct inet_sock *inet;
|
||||
const struct iphdr *iph = (const struct iphdr *)skb->data;
|
||||
@@ -673,7 +673,7 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
|
||||
|
||||
if (!sk) {
|
||||
__ICMP_INC_STATS(net, ICMP_MIB_INERRORS);
|
||||
return;
|
||||
return -ENOENT;
|
||||
}
|
||||
tunnel = true;
|
||||
}
|
||||
@@ -731,12 +731,12 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
|
||||
sk->sk_err = err;
|
||||
sk->sk_error_report(sk);
|
||||
out:
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void udp_err(struct sk_buff *skb, u32 info)
|
||||
int udp_err(struct sk_buff *skb, u32 info)
|
||||
{
|
||||
__udp4_lib_err(skb, info, &udp_table);
|
||||
return __udp4_lib_err(skb, info, &udp_table);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -7,7 +7,7 @@
|
||||
#include <net/inet_common.h>
|
||||
|
||||
int __udp4_lib_rcv(struct sk_buff *, struct udp_table *, int);
|
||||
void __udp4_lib_err(struct sk_buff *, u32, struct udp_table *);
|
||||
int __udp4_lib_err(struct sk_buff *, u32, struct udp_table *);
|
||||
|
||||
int udp_v4_get_port(struct sock *sk, unsigned short snum);
|
||||
|
||||
|
@@ -25,9 +25,9 @@ static int udplite_rcv(struct sk_buff *skb)
|
||||
return __udp4_lib_rcv(skb, &udplite_table, IPPROTO_UDPLITE);
|
||||
}
|
||||
|
||||
static void udplite_err(struct sk_buff *skb, u32 info)
|
||||
static int udplite_err(struct sk_buff *skb, u32 info)
|
||||
{
|
||||
__udp4_lib_err(skb, info, &udplite_table);
|
||||
return __udp4_lib_err(skb, info, &udplite_table);
|
||||
}
|
||||
|
||||
static const struct net_protocol udplite_protocol = {
|
||||
|
@@ -106,13 +106,15 @@ static int xfrm4_esp_rcv(struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xfrm4_esp_err(struct sk_buff *skb, u32 info)
|
||||
static int xfrm4_esp_err(struct sk_buff *skb, u32 info)
|
||||
{
|
||||
struct xfrm4_protocol *handler;
|
||||
|
||||
for_each_protocol_rcu(esp4_handlers, handler)
|
||||
if (!handler->err_handler(skb, info))
|
||||
break;
|
||||
return 0;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int xfrm4_ah_rcv(struct sk_buff *skb)
|
||||
@@ -132,13 +134,15 @@ static int xfrm4_ah_rcv(struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xfrm4_ah_err(struct sk_buff *skb, u32 info)
|
||||
static int xfrm4_ah_err(struct sk_buff *skb, u32 info)
|
||||
{
|
||||
struct xfrm4_protocol *handler;
|
||||
|
||||
for_each_protocol_rcu(ah4_handlers, handler)
|
||||
if (!handler->err_handler(skb, info))
|
||||
break;
|
||||
return 0;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int xfrm4_ipcomp_rcv(struct sk_buff *skb)
|
||||
@@ -158,13 +162,15 @@ static int xfrm4_ipcomp_rcv(struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xfrm4_ipcomp_err(struct sk_buff *skb, u32 info)
|
||||
static int xfrm4_ipcomp_err(struct sk_buff *skb, u32 info)
|
||||
{
|
||||
struct xfrm4_protocol *handler;
|
||||
|
||||
for_each_protocol_rcu(ipcomp4_handlers, handler)
|
||||
if (!handler->err_handler(skb, info))
|
||||
break;
|
||||
return 0;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static const struct net_protocol esp4_protocol = {
|
||||
|
Reference in New Issue
Block a user