icmp: prepare rfc 4884 for ipv6
authorWillem de Bruijn <willemb@google.com>
Fri, 24 Jul 2020 13:03:09 +0000 (09:03 -0400)
committerDavid S. Miller <davem@davemloft.net>
Sat, 25 Jul 2020 00:12:41 +0000 (17:12 -0700)
The RFC 4884 spec is largely the same between IPv4 and IPv6.
Factor out the IPv4 specific parts in preparation for IPv6 support:

- icmp types supported

- icmp header size, and thus offset to original datagram start

- datagram length field offset in icmp(6)hdr.

- datagram length field word size: 4B for IPv4, 8B for IPv6.

Signed-off-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/icmp.h
net/ipv4/icmp.c
net/ipv4/ip_sockglue.c

index 8fc38a3..0af4d21 100644 (file)
@@ -37,6 +37,7 @@ static inline bool icmp_is_err(int type)
 }
 
 void ip_icmp_error_rfc4884(const struct sk_buff *skb,
-                          struct sock_ee_data_rfc4884 *out);
+                          struct sock_ee_data_rfc4884 *out,
+                          int thlen, int off);
 
 #endif /* _LINUX_ICMP_H */
index 8d2654c..7498c58 100644 (file)
@@ -1151,24 +1151,15 @@ static bool ip_icmp_error_rfc4884_validate(const struct sk_buff *skb, int off)
 }
 
 void ip_icmp_error_rfc4884(const struct sk_buff *skb,
-                          struct sock_ee_data_rfc4884 *out)
+                          struct sock_ee_data_rfc4884 *out,
+                          int thlen, int off)
 {
-       int hlen, off;
-
-       switch (icmp_hdr(skb)->type) {
-       case ICMP_DEST_UNREACH:
-       case ICMP_TIME_EXCEEDED:
-       case ICMP_PARAMETERPROB:
-               break;
-       default:
-               return;
-       }
+       int hlen;
 
        /* original datagram headers: end of icmph to payload (skb->data) */
-       hlen = -skb_transport_offset(skb) - sizeof(struct icmphdr);
+       hlen = -skb_transport_offset(skb) - thlen;
 
        /* per rfc 4884: minimal datagram length of 128 bytes */
-       off = icmp_hdr(skb)->un.reserved[1] * sizeof(u32);
        if (off < 128 || off < hlen)
                return;
 
index 8dc027e..d2c2235 100644 (file)
@@ -390,6 +390,18 @@ int ip_ra_control(struct sock *sk, unsigned char on,
        return 0;
 }
 
+static void ipv4_icmp_error_rfc4884(const struct sk_buff *skb,
+                                   struct sock_ee_data_rfc4884 *out)
+{
+       switch (icmp_hdr(skb)->type) {
+       case ICMP_DEST_UNREACH:
+       case ICMP_TIME_EXCEEDED:
+       case ICMP_PARAMETERPROB:
+               ip_icmp_error_rfc4884(skb, out, sizeof(struct icmphdr),
+                                     icmp_hdr(skb)->un.reserved[1] * 4);
+       }
+}
+
 void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
                   __be16 port, u32 info, u8 *payload)
 {
@@ -413,7 +425,7 @@ void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
 
        if (skb_pull(skb, payload - skb->data)) {
                if (inet_sk(sk)->recverr_rfc4884)
-                       ip_icmp_error_rfc4884(skb, &serr->ee.ee_rfc4884);
+                       ipv4_icmp_error_rfc4884(skb, &serr->ee.ee_rfc4884);
 
                skb_reset_transport_header(skb);
                if (sock_queue_err_skb(sk, skb) == 0)