diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2012-01-17 02:57:56 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-01-17 15:49:03 -0500 |
commit | 36c92474498ad6cc3afb24b91a67a444d79978fe (patch) | |
tree | 6e847f5256b6ef429ca1a8ea85ede022d0c53cbe /net | |
parent | 4144cb2ade46d97b9c41682fd2e9064a59f23a98 (diff) |
net: WARN if skb_checksum_help() is called on skb requiring segmentation
skb_checksum_help() has never done anything useful with skbs that
require segmentation. Setting skb->ip_summed = CHECKSUM_NONE makes
them invalid and provokes a later WARNing in skb_gso_segment().
Passing such an skb to skb_checksum_help() indicates a bug, so we
should warn about it immediately. Move the warning from
skb_gso_segment() into a shared function, and add gso_type and
gso_size to it.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/dev.c | 31 |
1 files changed, 19 insertions, 12 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 7e6b7dcaacde..17db2f2e5236 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -1887,6 +1887,22 @@ void skb_set_dev(struct sk_buff *skb, struct net_device *dev) | |||
1887 | EXPORT_SYMBOL(skb_set_dev); | 1887 | EXPORT_SYMBOL(skb_set_dev); |
1888 | #endif /* CONFIG_NET_NS */ | 1888 | #endif /* CONFIG_NET_NS */ |
1889 | 1889 | ||
1890 | static void skb_warn_bad_offload(const struct sk_buff *skb) | ||
1891 | { | ||
1892 | struct net_device *dev = skb->dev; | ||
1893 | const char *driver = ""; | ||
1894 | |||
1895 | if (dev && dev->dev.parent) | ||
1896 | driver = dev_driver_string(dev->dev.parent); | ||
1897 | |||
1898 | WARN(1, "%s: caps=(%pNF, %pNF) len=%d data_len=%d gso_size=%d " | ||
1899 | "gso_type=%d ip_summed=%d\n", | ||
1900 | driver, dev ? &dev->features : NULL, | ||
1901 | skb->sk ? &skb->sk->sk_route_caps : NULL, | ||
1902 | skb->len, skb->data_len, skb_shinfo(skb)->gso_size, | ||
1903 | skb_shinfo(skb)->gso_type, skb->ip_summed); | ||
1904 | } | ||
1905 | |||
1890 | /* | 1906 | /* |
1891 | * Invalidate hardware checksum when packet is to be mangled, and | 1907 | * Invalidate hardware checksum when packet is to be mangled, and |
1892 | * complete checksum manually on outgoing path. | 1908 | * complete checksum manually on outgoing path. |
@@ -1900,8 +1916,8 @@ int skb_checksum_help(struct sk_buff *skb) | |||
1900 | goto out_set_summed; | 1916 | goto out_set_summed; |
1901 | 1917 | ||
1902 | if (unlikely(skb_shinfo(skb)->gso_size)) { | 1918 | if (unlikely(skb_shinfo(skb)->gso_size)) { |
1903 | /* Let GSO fix up the checksum. */ | 1919 | skb_warn_bad_offload(skb); |
1904 | goto out_set_summed; | 1920 | return -EINVAL; |
1905 | } | 1921 | } |
1906 | 1922 | ||
1907 | offset = skb_checksum_start_offset(skb); | 1923 | offset = skb_checksum_start_offset(skb); |
@@ -1961,16 +1977,7 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, | |||
1961 | __skb_pull(skb, skb->mac_len); | 1977 | __skb_pull(skb, skb->mac_len); |
1962 | 1978 | ||
1963 | if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) { | 1979 | if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) { |
1964 | struct net_device *dev = skb->dev; | 1980 | skb_warn_bad_offload(skb); |
1965 | const char *driver = ""; | ||
1966 | |||
1967 | if (dev && dev->dev.parent) | ||
1968 | driver = dev_driver_string(dev->dev.parent); | ||
1969 | |||
1970 | WARN(1, "%s: caps=(%pNF, %pNF) len=%d data_len=%d ip_summed=%d\n", | ||
1971 | driver, dev ? &dev->features : NULL, | ||
1972 | skb->sk ? &skb->sk->sk_route_caps : NULL, | ||
1973 | skb->len, skb->data_len, skb->ip_summed); | ||
1974 | 1981 | ||
1975 | if (skb_header_cloned(skb) && | 1982 | if (skb_header_cloned(skb) && |
1976 | (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) | 1983 | (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) |