diff options
| -rw-r--r-- | include/net/xfrm.h | 3 | ||||
| -rw-r--r-- | net/ipv4/xfrm4_policy.c | 114 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_policy.c | 106 | ||||
| -rw-r--r-- | net/xfrm/xfrm_policy.c | 231 |
4 files changed, 222 insertions, 232 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index b8de1622141a..18d6b33501b9 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
| @@ -326,9 +326,6 @@ struct xfrm_policy_afinfo { | |||
| 326 | xfrm_address_t *saddr, | 326 | xfrm_address_t *saddr, |
| 327 | xfrm_address_t *daddr, | 327 | xfrm_address_t *daddr, |
| 328 | u32 mark); | 328 | u32 mark); |
| 329 | void (*decode_session)(struct sk_buff *skb, | ||
| 330 | struct flowi *fl, | ||
| 331 | int reverse); | ||
| 332 | int (*fill_dst)(struct xfrm_dst *xdst, | 329 | int (*fill_dst)(struct xfrm_dst *xdst, |
| 333 | struct net_device *dev, | 330 | struct net_device *dev, |
| 334 | const struct flowi *fl); | 331 | const struct flowi *fl); |
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 6e89378668ae..414ab0420604 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | #include <linux/err.h> | 12 | #include <linux/err.h> |
| 13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| 14 | #include <linux/inetdevice.h> | 14 | #include <linux/inetdevice.h> |
| 15 | #include <linux/if_tunnel.h> | ||
| 16 | #include <net/dst.h> | 15 | #include <net/dst.h> |
| 17 | #include <net/xfrm.h> | 16 | #include <net/xfrm.h> |
| 18 | #include <net/ip.h> | 17 | #include <net/ip.h> |
| @@ -96,118 +95,6 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | |||
| 96 | return 0; | 95 | return 0; |
| 97 | } | 96 | } |
| 98 | 97 | ||
| 99 | static void | ||
| 100 | _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) | ||
| 101 | { | ||
| 102 | const struct iphdr *iph = ip_hdr(skb); | ||
| 103 | u8 *xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 104 | struct flowi4 *fl4 = &fl->u.ip4; | ||
| 105 | int oif = 0; | ||
| 106 | |||
| 107 | if (skb_dst(skb)) | ||
| 108 | oif = skb_dst(skb)->dev->ifindex; | ||
| 109 | |||
| 110 | memset(fl4, 0, sizeof(struct flowi4)); | ||
| 111 | fl4->flowi4_mark = skb->mark; | ||
| 112 | fl4->flowi4_oif = reverse ? skb->skb_iif : oif; | ||
| 113 | |||
| 114 | if (!ip_is_fragment(iph)) { | ||
| 115 | switch (iph->protocol) { | ||
| 116 | case IPPROTO_UDP: | ||
| 117 | case IPPROTO_UDPLITE: | ||
| 118 | case IPPROTO_TCP: | ||
| 119 | case IPPROTO_SCTP: | ||
| 120 | case IPPROTO_DCCP: | ||
| 121 | if (xprth + 4 < skb->data || | ||
| 122 | pskb_may_pull(skb, xprth + 4 - skb->data)) { | ||
| 123 | __be16 *ports; | ||
| 124 | |||
| 125 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 126 | ports = (__be16 *)xprth; | ||
| 127 | |||
| 128 | fl4->fl4_sport = ports[!!reverse]; | ||
| 129 | fl4->fl4_dport = ports[!reverse]; | ||
| 130 | } | ||
| 131 | break; | ||
| 132 | |||
| 133 | case IPPROTO_ICMP: | ||
| 134 | if (xprth + 2 < skb->data || | ||
| 135 | pskb_may_pull(skb, xprth + 2 - skb->data)) { | ||
| 136 | u8 *icmp; | ||
| 137 | |||
| 138 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 139 | icmp = xprth; | ||
| 140 | |||
| 141 | fl4->fl4_icmp_type = icmp[0]; | ||
| 142 | fl4->fl4_icmp_code = icmp[1]; | ||
| 143 | } | ||
| 144 | break; | ||
| 145 | |||
| 146 | case IPPROTO_ESP: | ||
| 147 | if (xprth + 4 < skb->data || | ||
| 148 | pskb_may_pull(skb, xprth + 4 - skb->data)) { | ||
| 149 | __be32 *ehdr; | ||
| 150 | |||
| 151 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 152 | ehdr = (__be32 *)xprth; | ||
| 153 | |||
| 154 | fl4->fl4_ipsec_spi = ehdr[0]; | ||
| 155 | } | ||
| 156 | break; | ||
| 157 | |||
| 158 | case IPPROTO_AH: | ||
| 159 | if (xprth + 8 < skb->data || | ||
| 160 | pskb_may_pull(skb, xprth + 8 - skb->data)) { | ||
| 161 | __be32 *ah_hdr; | ||
| 162 | |||
| 163 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 164 | ah_hdr = (__be32 *)xprth; | ||
| 165 | |||
| 166 | fl4->fl4_ipsec_spi = ah_hdr[1]; | ||
| 167 | } | ||
| 168 | break; | ||
| 169 | |||
| 170 | case IPPROTO_COMP: | ||
| 171 | if (xprth + 4 < skb->data || | ||
| 172 | pskb_may_pull(skb, xprth + 4 - skb->data)) { | ||
| 173 | __be16 *ipcomp_hdr; | ||
| 174 | |||
| 175 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 176 | ipcomp_hdr = (__be16 *)xprth; | ||
| 177 | |||
| 178 | fl4->fl4_ipsec_spi = htonl(ntohs(ipcomp_hdr[1])); | ||
| 179 | } | ||
| 180 | break; | ||
| 181 | |||
| 182 | case IPPROTO_GRE: | ||
| 183 | if (xprth + 12 < skb->data || | ||
| 184 | pskb_may_pull(skb, xprth + 12 - skb->data)) { | ||
| 185 | __be16 *greflags; | ||
| 186 | __be32 *gre_hdr; | ||
| 187 | |||
| 188 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 189 | greflags = (__be16 *)xprth; | ||
| 190 | gre_hdr = (__be32 *)xprth; | ||
| 191 | |||
| 192 | if (greflags[0] & GRE_KEY) { | ||
| 193 | if (greflags[0] & GRE_CSUM) | ||
| 194 | gre_hdr++; | ||
| 195 | fl4->fl4_gre_key = gre_hdr[1]; | ||
| 196 | } | ||
| 197 | } | ||
| 198 | break; | ||
| 199 | |||
| 200 | default: | ||
| 201 | fl4->fl4_ipsec_spi = 0; | ||
| 202 | break; | ||
| 203 | } | ||
| 204 | } | ||
| 205 | fl4->flowi4_proto = iph->protocol; | ||
| 206 | fl4->daddr = reverse ? iph->saddr : iph->daddr; | ||
| 207 | fl4->saddr = reverse ? iph->daddr : iph->saddr; | ||
| 208 | fl4->flowi4_tos = iph->tos; | ||
| 209 | } | ||
| 210 | |||
| 211 | static void xfrm4_update_pmtu(struct dst_entry *dst, struct sock *sk, | 98 | static void xfrm4_update_pmtu(struct dst_entry *dst, struct sock *sk, |
| 212 | struct sk_buff *skb, u32 mtu) | 99 | struct sk_buff *skb, u32 mtu) |
| 213 | { | 100 | { |
| @@ -260,7 +147,6 @@ static const struct xfrm_policy_afinfo xfrm4_policy_afinfo = { | |||
| 260 | .dst_ops = &xfrm4_dst_ops_template, | 147 | .dst_ops = &xfrm4_dst_ops_template, |
| 261 | .dst_lookup = xfrm4_dst_lookup, | 148 | .dst_lookup = xfrm4_dst_lookup, |
| 262 | .get_saddr = xfrm4_get_saddr, | 149 | .get_saddr = xfrm4_get_saddr, |
| 263 | .decode_session = _decode_session4, | ||
| 264 | .fill_dst = xfrm4_fill_dst, | 150 | .fill_dst = xfrm4_fill_dst, |
| 265 | .blackhole_route = ipv4_blackhole_route, | 151 | .blackhole_route = ipv4_blackhole_route, |
| 266 | }; | 152 | }; |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 358e834fedce..699e0730ce8e 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
| @@ -22,9 +22,6 @@ | |||
| 22 | #include <net/ipv6.h> | 22 | #include <net/ipv6.h> |
| 23 | #include <net/ip6_route.h> | 23 | #include <net/ip6_route.h> |
| 24 | #include <net/l3mdev.h> | 24 | #include <net/l3mdev.h> |
| 25 | #if IS_ENABLED(CONFIG_IPV6_MIP6) | ||
| 26 | #include <net/mip6.h> | ||
| 27 | #endif | ||
| 28 | 25 | ||
| 29 | static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif, | 26 | static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif, |
| 30 | const xfrm_address_t *saddr, | 27 | const xfrm_address_t *saddr, |
| @@ -100,108 +97,6 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | |||
| 100 | return 0; | 97 | return 0; |
| 101 | } | 98 | } |
| 102 | 99 | ||
| 103 | static inline void | ||
| 104 | _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) | ||
| 105 | { | ||
| 106 | struct flowi6 *fl6 = &fl->u.ip6; | ||
| 107 | int onlyproto = 0; | ||
| 108 | const struct ipv6hdr *hdr = ipv6_hdr(skb); | ||
| 109 | u32 offset = sizeof(*hdr); | ||
| 110 | struct ipv6_opt_hdr *exthdr; | ||
| 111 | const unsigned char *nh = skb_network_header(skb); | ||
| 112 | u16 nhoff = IP6CB(skb)->nhoff; | ||
| 113 | int oif = 0; | ||
| 114 | u8 nexthdr; | ||
| 115 | |||
| 116 | if (!nhoff) | ||
| 117 | nhoff = offsetof(struct ipv6hdr, nexthdr); | ||
| 118 | |||
| 119 | nexthdr = nh[nhoff]; | ||
| 120 | |||
| 121 | if (skb_dst(skb)) | ||
| 122 | oif = skb_dst(skb)->dev->ifindex; | ||
| 123 | |||
| 124 | memset(fl6, 0, sizeof(struct flowi6)); | ||
| 125 | fl6->flowi6_mark = skb->mark; | ||
| 126 | fl6->flowi6_oif = reverse ? skb->skb_iif : oif; | ||
| 127 | |||
| 128 | fl6->daddr = reverse ? hdr->saddr : hdr->daddr; | ||
| 129 | fl6->saddr = reverse ? hdr->daddr : hdr->saddr; | ||
| 130 | |||
| 131 | while (nh + offset + sizeof(*exthdr) < skb->data || | ||
| 132 | pskb_may_pull(skb, nh + offset + sizeof(*exthdr) - skb->data)) { | ||
| 133 | nh = skb_network_header(skb); | ||
| 134 | exthdr = (struct ipv6_opt_hdr *)(nh + offset); | ||
| 135 | |||
| 136 | switch (nexthdr) { | ||
| 137 | case NEXTHDR_FRAGMENT: | ||
| 138 | onlyproto = 1; | ||
| 139 | /* fall through */ | ||
| 140 | case NEXTHDR_ROUTING: | ||
| 141 | case NEXTHDR_HOP: | ||
| 142 | case NEXTHDR_DEST: | ||
| 143 | offset += ipv6_optlen(exthdr); | ||
| 144 | nexthdr = exthdr->nexthdr; | ||
| 145 | exthdr = (struct ipv6_opt_hdr *)(nh + offset); | ||
| 146 | break; | ||
| 147 | |||
| 148 | case IPPROTO_UDP: | ||
| 149 | case IPPROTO_UDPLITE: | ||
| 150 | case IPPROTO_TCP: | ||
| 151 | case IPPROTO_SCTP: | ||
| 152 | case IPPROTO_DCCP: | ||
| 153 | if (!onlyproto && (nh + offset + 4 < skb->data || | ||
| 154 | pskb_may_pull(skb, nh + offset + 4 - skb->data))) { | ||
| 155 | __be16 *ports; | ||
| 156 | |||
| 157 | nh = skb_network_header(skb); | ||
| 158 | ports = (__be16 *)(nh + offset); | ||
| 159 | fl6->fl6_sport = ports[!!reverse]; | ||
| 160 | fl6->fl6_dport = ports[!reverse]; | ||
| 161 | } | ||
| 162 | fl6->flowi6_proto = nexthdr; | ||
| 163 | return; | ||
| 164 | |||
| 165 | case IPPROTO_ICMPV6: | ||
| 166 | if (!onlyproto && (nh + offset + 2 < skb->data || | ||
| 167 | pskb_may_pull(skb, nh + offset + 2 - skb->data))) { | ||
| 168 | u8 *icmp; | ||
| 169 | |||
| 170 | nh = skb_network_header(skb); | ||
| 171 | icmp = (u8 *)(nh + offset); | ||
| 172 | fl6->fl6_icmp_type = icmp[0]; | ||
| 173 | fl6->fl6_icmp_code = icmp[1]; | ||
| 174 | } | ||
| 175 | fl6->flowi6_proto = nexthdr; | ||
| 176 | return; | ||
| 177 | |||
| 178 | #if IS_ENABLED(CONFIG_IPV6_MIP6) | ||
| 179 | case IPPROTO_MH: | ||
| 180 | offset += ipv6_optlen(exthdr); | ||
| 181 | if (!onlyproto && (nh + offset + 3 < skb->data || | ||
| 182 | pskb_may_pull(skb, nh + offset + 3 - skb->data))) { | ||
| 183 | struct ip6_mh *mh; | ||
| 184 | |||
| 185 | nh = skb_network_header(skb); | ||
| 186 | mh = (struct ip6_mh *)(nh + offset); | ||
| 187 | fl6->fl6_mh_type = mh->ip6mh_type; | ||
| 188 | } | ||
| 189 | fl6->flowi6_proto = nexthdr; | ||
| 190 | return; | ||
| 191 | #endif | ||
| 192 | |||
| 193 | /* XXX Why are there these headers? */ | ||
| 194 | case IPPROTO_AH: | ||
| 195 | case IPPROTO_ESP: | ||
| 196 | case IPPROTO_COMP: | ||
| 197 | default: | ||
| 198 | fl6->fl6_ipsec_spi = 0; | ||
| 199 | fl6->flowi6_proto = nexthdr; | ||
| 200 | return; | ||
| 201 | } | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | static void xfrm6_update_pmtu(struct dst_entry *dst, struct sock *sk, | 100 | static void xfrm6_update_pmtu(struct dst_entry *dst, struct sock *sk, |
| 206 | struct sk_buff *skb, u32 mtu) | 101 | struct sk_buff *skb, u32 mtu) |
| 207 | { | 102 | { |
| @@ -273,7 +168,6 @@ static const struct xfrm_policy_afinfo xfrm6_policy_afinfo = { | |||
| 273 | .dst_ops = &xfrm6_dst_ops_template, | 168 | .dst_ops = &xfrm6_dst_ops_template, |
| 274 | .dst_lookup = xfrm6_dst_lookup, | 169 | .dst_lookup = xfrm6_dst_lookup, |
| 275 | .get_saddr = xfrm6_get_saddr, | 170 | .get_saddr = xfrm6_get_saddr, |
| 276 | .decode_session = _decode_session6, | ||
| 277 | .fill_dst = xfrm6_fill_dst, | 171 | .fill_dst = xfrm6_fill_dst, |
| 278 | .blackhole_route = ip6_blackhole_route, | 172 | .blackhole_route = ip6_blackhole_route, |
| 279 | }; | 173 | }; |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 5359c312f016..03b6bf85d70b 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
| @@ -27,10 +27,14 @@ | |||
| 27 | #include <linux/cpu.h> | 27 | #include <linux/cpu.h> |
| 28 | #include <linux/audit.h> | 28 | #include <linux/audit.h> |
| 29 | #include <linux/rhashtable.h> | 29 | #include <linux/rhashtable.h> |
| 30 | #include <linux/if_tunnel.h> | ||
| 30 | #include <net/dst.h> | 31 | #include <net/dst.h> |
| 31 | #include <net/flow.h> | 32 | #include <net/flow.h> |
| 32 | #include <net/xfrm.h> | 33 | #include <net/xfrm.h> |
| 33 | #include <net/ip.h> | 34 | #include <net/ip.h> |
| 35 | #if IS_ENABLED(CONFIG_IPV6_MIP6) | ||
| 36 | #include <net/mip6.h> | ||
| 37 | #endif | ||
| 34 | #ifdef CONFIG_XFRM_STATISTICS | 38 | #ifdef CONFIG_XFRM_STATISTICS |
| 35 | #include <net/snmp.h> | 39 | #include <net/snmp.h> |
| 36 | #endif | 40 | #endif |
| @@ -3256,20 +3260,229 @@ xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int star | |||
| 3256 | return start; | 3260 | return start; |
| 3257 | } | 3261 | } |
| 3258 | 3262 | ||
| 3263 | static void | ||
| 3264 | decode_session4(struct sk_buff *skb, struct flowi *fl, bool reverse) | ||
| 3265 | { | ||
| 3266 | const struct iphdr *iph = ip_hdr(skb); | ||
| 3267 | u8 *xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 3268 | struct flowi4 *fl4 = &fl->u.ip4; | ||
| 3269 | int oif = 0; | ||
| 3270 | |||
| 3271 | if (skb_dst(skb)) | ||
| 3272 | oif = skb_dst(skb)->dev->ifindex; | ||
| 3273 | |||
| 3274 | memset(fl4, 0, sizeof(struct flowi4)); | ||
| 3275 | fl4->flowi4_mark = skb->mark; | ||
| 3276 | fl4->flowi4_oif = reverse ? skb->skb_iif : oif; | ||
| 3277 | |||
| 3278 | if (!ip_is_fragment(iph)) { | ||
| 3279 | switch (iph->protocol) { | ||
| 3280 | case IPPROTO_UDP: | ||
| 3281 | case IPPROTO_UDPLITE: | ||
| 3282 | case IPPROTO_TCP: | ||
| 3283 | case IPPROTO_SCTP: | ||
| 3284 | case IPPROTO_DCCP: | ||
| 3285 | if (xprth + 4 < skb->data || | ||
| 3286 | pskb_may_pull(skb, xprth + 4 - skb->data)) { | ||
| 3287 | __be16 *ports; | ||
| 3288 | |||
| 3289 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 3290 | ports = (__be16 *)xprth; | ||
| 3291 | |||
| 3292 | fl4->fl4_sport = ports[!!reverse]; | ||
| 3293 | fl4->fl4_dport = ports[!reverse]; | ||
| 3294 | } | ||
| 3295 | break; | ||
| 3296 | case IPPROTO_ICMP: | ||
| 3297 | if (xprth + 2 < skb->data || | ||
| 3298 | pskb_may_pull(skb, xprth + 2 - skb->data)) { | ||
| 3299 | u8 *icmp; | ||
| 3300 | |||
| 3301 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 3302 | icmp = xprth; | ||
| 3303 | |||
| 3304 | fl4->fl4_icmp_type = icmp[0]; | ||
| 3305 | fl4->fl4_icmp_code = icmp[1]; | ||
| 3306 | } | ||
| 3307 | break; | ||
| 3308 | case IPPROTO_ESP: | ||
| 3309 | if (xprth + 4 < skb->data || | ||
| 3310 | pskb_may_pull(skb, xprth + 4 - skb->data)) { | ||
| 3311 | __be32 *ehdr; | ||
| 3312 | |||
| 3313 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 3314 | ehdr = (__be32 *)xprth; | ||
| 3315 | |||
| 3316 | fl4->fl4_ipsec_spi = ehdr[0]; | ||
| 3317 | } | ||
| 3318 | break; | ||
| 3319 | case IPPROTO_AH: | ||
| 3320 | if (xprth + 8 < skb->data || | ||
| 3321 | pskb_may_pull(skb, xprth + 8 - skb->data)) { | ||
| 3322 | __be32 *ah_hdr; | ||
| 3323 | |||
| 3324 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 3325 | ah_hdr = (__be32 *)xprth; | ||
| 3326 | |||
| 3327 | fl4->fl4_ipsec_spi = ah_hdr[1]; | ||
| 3328 | } | ||
| 3329 | break; | ||
| 3330 | case IPPROTO_COMP: | ||
| 3331 | if (xprth + 4 < skb->data || | ||
| 3332 | pskb_may_pull(skb, xprth + 4 - skb->data)) { | ||
| 3333 | __be16 *ipcomp_hdr; | ||
| 3334 | |||
| 3335 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 3336 | ipcomp_hdr = (__be16 *)xprth; | ||
| 3337 | |||
| 3338 | fl4->fl4_ipsec_spi = htonl(ntohs(ipcomp_hdr[1])); | ||
| 3339 | } | ||
| 3340 | break; | ||
| 3341 | case IPPROTO_GRE: | ||
| 3342 | if (xprth + 12 < skb->data || | ||
| 3343 | pskb_may_pull(skb, xprth + 12 - skb->data)) { | ||
| 3344 | __be16 *greflags; | ||
| 3345 | __be32 *gre_hdr; | ||
| 3346 | |||
| 3347 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 3348 | greflags = (__be16 *)xprth; | ||
| 3349 | gre_hdr = (__be32 *)xprth; | ||
| 3350 | |||
| 3351 | if (greflags[0] & GRE_KEY) { | ||
| 3352 | if (greflags[0] & GRE_CSUM) | ||
| 3353 | gre_hdr++; | ||
| 3354 | fl4->fl4_gre_key = gre_hdr[1]; | ||
| 3355 | } | ||
| 3356 | } | ||
| 3357 | break; | ||
| 3358 | default: | ||
| 3359 | fl4->fl4_ipsec_spi = 0; | ||
| 3360 | break; | ||
| 3361 | } | ||
| 3362 | } | ||
| 3363 | fl4->flowi4_proto = iph->protocol; | ||
| 3364 | fl4->daddr = reverse ? iph->saddr : iph->daddr; | ||
| 3365 | fl4->saddr = reverse ? iph->daddr : iph->saddr; | ||
| 3366 | fl4->flowi4_tos = iph->tos; | ||
| 3367 | } | ||
| 3368 | |||
| 3369 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 3370 | static void | ||
| 3371 | decode_session6(struct sk_buff *skb, struct flowi *fl, bool reverse) | ||
| 3372 | { | ||
| 3373 | struct flowi6 *fl6 = &fl->u.ip6; | ||
| 3374 | int onlyproto = 0; | ||
| 3375 | const struct ipv6hdr *hdr = ipv6_hdr(skb); | ||
| 3376 | u32 offset = sizeof(*hdr); | ||
| 3377 | struct ipv6_opt_hdr *exthdr; | ||
| 3378 | const unsigned char *nh = skb_network_header(skb); | ||
| 3379 | u16 nhoff = IP6CB(skb)->nhoff; | ||
| 3380 | int oif = 0; | ||
| 3381 | u8 nexthdr; | ||
| 3382 | |||
| 3383 | if (!nhoff) | ||
| 3384 | nhoff = offsetof(struct ipv6hdr, nexthdr); | ||
| 3385 | |||
| 3386 | nexthdr = nh[nhoff]; | ||
| 3387 | |||
| 3388 | if (skb_dst(skb)) | ||
| 3389 | oif = skb_dst(skb)->dev->ifindex; | ||
| 3390 | |||
| 3391 | memset(fl6, 0, sizeof(struct flowi6)); | ||
| 3392 | fl6->flowi6_mark = skb->mark; | ||
| 3393 | fl6->flowi6_oif = reverse ? skb->skb_iif : oif; | ||
| 3394 | |||
| 3395 | fl6->daddr = reverse ? hdr->saddr : hdr->daddr; | ||
| 3396 | fl6->saddr = reverse ? hdr->daddr : hdr->saddr; | ||
| 3397 | |||
| 3398 | while (nh + offset + sizeof(*exthdr) < skb->data || | ||
| 3399 | pskb_may_pull(skb, nh + offset + sizeof(*exthdr) - skb->data)) { | ||
| 3400 | nh = skb_network_header(skb); | ||
| 3401 | exthdr = (struct ipv6_opt_hdr *)(nh + offset); | ||
| 3402 | |||
| 3403 | switch (nexthdr) { | ||
| 3404 | case NEXTHDR_FRAGMENT: | ||
| 3405 | onlyproto = 1; | ||
| 3406 | /* fall through */ | ||
| 3407 | case NEXTHDR_ROUTING: | ||
| 3408 | case NEXTHDR_HOP: | ||
| 3409 | case NEXTHDR_DEST: | ||
| 3410 | offset += ipv6_optlen(exthdr); | ||
| 3411 | nexthdr = exthdr->nexthdr; | ||
| 3412 | exthdr = (struct ipv6_opt_hdr *)(nh + offset); | ||
| 3413 | break; | ||
| 3414 | case IPPROTO_UDP: | ||
| 3415 | case IPPROTO_UDPLITE: | ||
| 3416 | case IPPROTO_TCP: | ||
| 3417 | case IPPROTO_SCTP: | ||
| 3418 | case IPPROTO_DCCP: | ||
| 3419 | if (!onlyproto && (nh + offset + 4 < skb->data || | ||
| 3420 | pskb_may_pull(skb, nh + offset + 4 - skb->data))) { | ||
| 3421 | __be16 *ports; | ||
| 3422 | |||
| 3423 | nh = skb_network_header(skb); | ||
| 3424 | ports = (__be16 *)(nh + offset); | ||
| 3425 | fl6->fl6_sport = ports[!!reverse]; | ||
| 3426 | fl6->fl6_dport = ports[!reverse]; | ||
| 3427 | } | ||
| 3428 | fl6->flowi6_proto = nexthdr; | ||
| 3429 | return; | ||
| 3430 | case IPPROTO_ICMPV6: | ||
| 3431 | if (!onlyproto && (nh + offset + 2 < skb->data || | ||
| 3432 | pskb_may_pull(skb, nh + offset + 2 - skb->data))) { | ||
| 3433 | u8 *icmp; | ||
| 3434 | |||
| 3435 | nh = skb_network_header(skb); | ||
| 3436 | icmp = (u8 *)(nh + offset); | ||
| 3437 | fl6->fl6_icmp_type = icmp[0]; | ||
| 3438 | fl6->fl6_icmp_code = icmp[1]; | ||
| 3439 | } | ||
| 3440 | fl6->flowi6_proto = nexthdr; | ||
| 3441 | return; | ||
| 3442 | #if IS_ENABLED(CONFIG_IPV6_MIP6) | ||
| 3443 | case IPPROTO_MH: | ||
| 3444 | offset += ipv6_optlen(exthdr); | ||
| 3445 | if (!onlyproto && (nh + offset + 3 < skb->data || | ||
| 3446 | pskb_may_pull(skb, nh + offset + 3 - skb->data))) { | ||
| 3447 | struct ip6_mh *mh; | ||
| 3448 | |||
| 3449 | nh = skb_network_header(skb); | ||
| 3450 | mh = (struct ip6_mh *)(nh + offset); | ||
| 3451 | fl6->fl6_mh_type = mh->ip6mh_type; | ||
| 3452 | } | ||
| 3453 | fl6->flowi6_proto = nexthdr; | ||
| 3454 | return; | ||
| 3455 | #endif | ||
| 3456 | /* XXX Why are there these headers? */ | ||
| 3457 | case IPPROTO_AH: | ||
| 3458 | case IPPROTO_ESP: | ||
| 3459 | case IPPROTO_COMP: | ||
| 3460 | default: | ||
| 3461 | fl6->fl6_ipsec_spi = 0; | ||
| 3462 | fl6->flowi6_proto = nexthdr; | ||
| 3463 | return; | ||
| 3464 | } | ||
| 3465 | } | ||
| 3466 | } | ||
| 3467 | #endif | ||
| 3468 | |||
| 3259 | int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, | 3469 | int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, |
| 3260 | unsigned int family, int reverse) | 3470 | unsigned int family, int reverse) |
| 3261 | { | 3471 | { |
| 3262 | const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | 3472 | switch (family) { |
| 3263 | int err; | 3473 | case AF_INET: |
| 3264 | 3474 | decode_session4(skb, fl, reverse); | |
| 3265 | if (unlikely(afinfo == NULL)) | 3475 | break; |
| 3476 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 3477 | case AF_INET6: | ||
| 3478 | decode_session6(skb, fl, reverse); | ||
| 3479 | break; | ||
| 3480 | #endif | ||
| 3481 | default: | ||
| 3266 | return -EAFNOSUPPORT; | 3482 | return -EAFNOSUPPORT; |
| 3483 | } | ||
| 3267 | 3484 | ||
| 3268 | afinfo->decode_session(skb, fl, reverse); | 3485 | return security_xfrm_decode_session(skb, &fl->flowi_secid); |
| 3269 | |||
| 3270 | err = security_xfrm_decode_session(skb, &fl->flowi_secid); | ||
| 3271 | rcu_read_unlock(); | ||
| 3272 | return err; | ||
| 3273 | } | 3486 | } |
| 3274 | EXPORT_SYMBOL(__xfrm_decode_session); | 3487 | EXPORT_SYMBOL(__xfrm_decode_session); |
| 3275 | 3488 | ||
