diff options
author | Florian Westphal <fw@strlen.de> | 2019-04-16 10:44:39 -0400 |
---|---|---|
committer | Steffen Klassert <steffen.klassert@secunet.com> | 2019-04-23 01:42:20 -0400 |
commit | c53ac41e3720926301c623d6682bb87ce992a3b3 (patch) | |
tree | 8b2e8e306321f3d305e705d5e30f8f9073e8a5dd | |
parent | 2e8b4aa816eaaf480fe68b1086614259caf1bf3c (diff) |
xfrm: remove decode_session indirection from afinfo_policy
No external dependencies, might as well handle this directly.
xfrm_afinfo_policy is now 40 bytes on x86_64.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
-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 | ||