diff options
author | Willem de Bruijn <willemb@google.com> | 2020-07-24 09:03:09 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2020-07-24 17:12:41 -0700 |
commit | 178c49d9f9a4b5ade00c93480d714708fe971e24 (patch) | |
tree | 715bff01ce3d3520801c36e1a2daf7f3a20273d5 | |
parent | c4e9e09f5589f9afe6b8f8c4fb078e0559bca667 (diff) |
icmp: prepare rfc 4884 for ipv6
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>
-rw-r--r-- | include/linux/icmp.h | 3 | ||||
-rw-r--r-- | net/ipv4/icmp.c | 17 | ||||
-rw-r--r-- | net/ipv4/ip_sockglue.c | 14 |
3 files changed, 19 insertions, 15 deletions
diff --git a/include/linux/icmp.h b/include/linux/icmp.h index 8fc38a34cb20..0af4d210ee31 100644 --- a/include/linux/icmp.h +++ b/include/linux/icmp.h @@ -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 */ diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 8d2654cdbd77..7498c58460a1 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -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; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 8dc027e54c5b..d2c223554ff7 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -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) |