Commit 178c49d9 authored by Willem de Bruijn's avatar Willem de Bruijn Committed by David S. Miller

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: default avatarWillem de Bruijn <willemb@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c4e9e09f
...@@ -37,6 +37,7 @@ static inline bool icmp_is_err(int type) ...@@ -37,6 +37,7 @@ static inline bool icmp_is_err(int type)
} }
void ip_icmp_error_rfc4884(const struct sk_buff *skb, 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 */ #endif /* _LINUX_ICMP_H */
...@@ -1151,24 +1151,15 @@ static bool ip_icmp_error_rfc4884_validate(const struct sk_buff *skb, int off) ...@@ -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, 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; int hlen;
switch (icmp_hdr(skb)->type) {
case ICMP_DEST_UNREACH:
case ICMP_TIME_EXCEEDED:
case ICMP_PARAMETERPROB:
break;
default:
return;
}
/* original datagram headers: end of icmph to payload (skb->data) */ /* 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 */ /* per rfc 4884: minimal datagram length of 128 bytes */
off = icmp_hdr(skb)->un.reserved[1] * sizeof(u32);
if (off < 128 || off < hlen) if (off < 128 || off < hlen)
return; return;
......
...@@ -390,6 +390,18 @@ int ip_ra_control(struct sock *sk, unsigned char on, ...@@ -390,6 +390,18 @@ int ip_ra_control(struct sock *sk, unsigned char on,
return 0; 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, void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
__be16 port, u32 info, u8 *payload) __be16 port, u32 info, u8 *payload)
{ {
...@@ -413,7 +425,7 @@ void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err, ...@@ -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 (skb_pull(skb, payload - skb->data)) {
if (inet_sk(sk)->recverr_rfc4884) 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); skb_reset_transport_header(skb);
if (sock_queue_err_skb(sk, skb) == 0) if (sock_queue_err_skb(sk, skb) == 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment