diff options
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
| -rw-r--r-- | net/xfrm/xfrm_policy.c | 66 |
1 files changed, 36 insertions, 30 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 41a91d27d3ea..b1932a629ef8 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
| @@ -1735,19 +1735,36 @@ error: | |||
| 1735 | return ERR_PTR(err); | 1735 | return ERR_PTR(err); |
| 1736 | } | 1736 | } |
| 1737 | 1737 | ||
| 1738 | static struct dst_entry *make_blackhole(struct net *net, u16 family, | ||
| 1739 | struct dst_entry *dst_orig) | ||
| 1740 | { | ||
| 1741 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | ||
| 1742 | struct dst_entry *ret; | ||
| 1743 | |||
| 1744 | if (!afinfo) { | ||
| 1745 | dst_release(dst_orig); | ||
| 1746 | ret = ERR_PTR(-EINVAL); | ||
| 1747 | } else { | ||
| 1748 | ret = afinfo->blackhole_route(net, dst_orig); | ||
| 1749 | } | ||
| 1750 | xfrm_policy_put_afinfo(afinfo); | ||
| 1751 | |||
| 1752 | return ret; | ||
| 1753 | } | ||
| 1754 | |||
| 1738 | /* Main function: finds/creates a bundle for given flow. | 1755 | /* Main function: finds/creates a bundle for given flow. |
| 1739 | * | 1756 | * |
| 1740 | * At the moment we eat a raw IP route. Mostly to speed up lookups | 1757 | * At the moment we eat a raw IP route. Mostly to speed up lookups |
| 1741 | * on interfaces with disabled IPsec. | 1758 | * on interfaces with disabled IPsec. |
| 1742 | */ | 1759 | */ |
| 1743 | int __xfrm_lookup(struct net *net, struct dst_entry **dst_p, | 1760 | struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, |
| 1744 | const struct flowi *fl, | 1761 | const struct flowi *fl, |
| 1745 | struct sock *sk, int flags) | 1762 | struct sock *sk, int flags) |
| 1746 | { | 1763 | { |
| 1747 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | 1764 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; |
| 1748 | struct flow_cache_object *flo; | 1765 | struct flow_cache_object *flo; |
| 1749 | struct xfrm_dst *xdst; | 1766 | struct xfrm_dst *xdst; |
| 1750 | struct dst_entry *dst, *dst_orig = *dst_p, *route; | 1767 | struct dst_entry *dst, *route; |
| 1751 | u16 family = dst_orig->ops->family; | 1768 | u16 family = dst_orig->ops->family; |
| 1752 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); | 1769 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); |
| 1753 | int i, err, num_pols, num_xfrms = 0, drop_pols = 0; | 1770 | int i, err, num_pols, num_xfrms = 0, drop_pols = 0; |
| @@ -1829,9 +1846,10 @@ restart: | |||
| 1829 | dst_release(dst); | 1846 | dst_release(dst); |
| 1830 | xfrm_pols_put(pols, drop_pols); | 1847 | xfrm_pols_put(pols, drop_pols); |
| 1831 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); | 1848 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); |
| 1832 | return -EREMOTE; | 1849 | |
| 1850 | return make_blackhole(net, family, dst_orig); | ||
| 1833 | } | 1851 | } |
| 1834 | if (flags & XFRM_LOOKUP_WAIT) { | 1852 | if (fl->flags & FLOWI_FLAG_CAN_SLEEP) { |
| 1835 | DECLARE_WAITQUEUE(wait, current); | 1853 | DECLARE_WAITQUEUE(wait, current); |
| 1836 | 1854 | ||
| 1837 | add_wait_queue(&net->xfrm.km_waitq, &wait); | 1855 | add_wait_queue(&net->xfrm.km_waitq, &wait); |
| @@ -1873,43 +1891,28 @@ no_transform: | |||
| 1873 | goto error; | 1891 | goto error; |
| 1874 | } else if (num_xfrms > 0) { | 1892 | } else if (num_xfrms > 0) { |
| 1875 | /* Flow transformed */ | 1893 | /* Flow transformed */ |
| 1876 | *dst_p = dst; | ||
| 1877 | dst_release(dst_orig); | 1894 | dst_release(dst_orig); |
| 1878 | } else { | 1895 | } else { |
| 1879 | /* Flow passes untransformed */ | 1896 | /* Flow passes untransformed */ |
| 1880 | dst_release(dst); | 1897 | dst_release(dst); |
| 1898 | dst = dst_orig; | ||
| 1881 | } | 1899 | } |
| 1882 | ok: | 1900 | ok: |
| 1883 | xfrm_pols_put(pols, drop_pols); | 1901 | xfrm_pols_put(pols, drop_pols); |
| 1884 | return 0; | 1902 | return dst; |
| 1885 | 1903 | ||
| 1886 | nopol: | 1904 | nopol: |
| 1887 | if (!(flags & XFRM_LOOKUP_ICMP)) | 1905 | if (!(flags & XFRM_LOOKUP_ICMP)) { |
| 1906 | dst = dst_orig; | ||
| 1888 | goto ok; | 1907 | goto ok; |
| 1908 | } | ||
| 1889 | err = -ENOENT; | 1909 | err = -ENOENT; |
| 1890 | error: | 1910 | error: |
| 1891 | dst_release(dst); | 1911 | dst_release(dst); |
| 1892 | dropdst: | 1912 | dropdst: |
| 1893 | dst_release(dst_orig); | 1913 | dst_release(dst_orig); |
| 1894 | *dst_p = NULL; | ||
| 1895 | xfrm_pols_put(pols, drop_pols); | 1914 | xfrm_pols_put(pols, drop_pols); |
| 1896 | return err; | 1915 | return ERR_PTR(err); |
| 1897 | } | ||
| 1898 | EXPORT_SYMBOL(__xfrm_lookup); | ||
| 1899 | |||
| 1900 | int xfrm_lookup(struct net *net, struct dst_entry **dst_p, | ||
| 1901 | const struct flowi *fl, | ||
| 1902 | struct sock *sk, int flags) | ||
| 1903 | { | ||
| 1904 | int err = __xfrm_lookup(net, dst_p, fl, sk, flags); | ||
| 1905 | |||
| 1906 | if (err == -EREMOTE) { | ||
| 1907 | dst_release(*dst_p); | ||
| 1908 | *dst_p = NULL; | ||
| 1909 | err = -EAGAIN; | ||
| 1910 | } | ||
| 1911 | |||
| 1912 | return err; | ||
| 1913 | } | 1916 | } |
| 1914 | EXPORT_SYMBOL(xfrm_lookup); | 1917 | EXPORT_SYMBOL(xfrm_lookup); |
| 1915 | 1918 | ||
| @@ -2169,7 +2172,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) | |||
| 2169 | struct net *net = dev_net(skb->dev); | 2172 | struct net *net = dev_net(skb->dev); |
| 2170 | struct flowi fl; | 2173 | struct flowi fl; |
| 2171 | struct dst_entry *dst; | 2174 | struct dst_entry *dst; |
| 2172 | int res; | 2175 | int res = 0; |
| 2173 | 2176 | ||
| 2174 | if (xfrm_decode_session(skb, &fl, family) < 0) { | 2177 | if (xfrm_decode_session(skb, &fl, family) < 0) { |
| 2175 | XFRM_INC_STATS(net, LINUX_MIB_XFRMFWDHDRERROR); | 2178 | XFRM_INC_STATS(net, LINUX_MIB_XFRMFWDHDRERROR); |
| @@ -2177,9 +2180,12 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) | |||
| 2177 | } | 2180 | } |
| 2178 | 2181 | ||
| 2179 | skb_dst_force(skb); | 2182 | skb_dst_force(skb); |
| 2180 | dst = skb_dst(skb); | ||
| 2181 | 2183 | ||
| 2182 | res = xfrm_lookup(net, &dst, &fl, NULL, 0) == 0; | 2184 | dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, 0); |
| 2185 | if (IS_ERR(dst)) { | ||
| 2186 | res = 1; | ||
| 2187 | dst = NULL; | ||
| 2188 | } | ||
| 2183 | skb_dst_set(skb, dst); | 2189 | skb_dst_set(skb, dst); |
| 2184 | return res; | 2190 | return res; |
| 2185 | } | 2191 | } |
