1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Extension Header handling for IPv6 |
4 | * Linux INET6 implementation |
5 | * |
6 | * Authors: |
7 | * Pedro Roque <roque@di.fc.ul.pt> |
8 | * Andi Kleen <ak@muc.de> |
9 | * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> |
10 | */ |
11 | |
12 | /* Changes: |
13 | * yoshfuji : ensure not to overrun while parsing |
14 | * tlv options. |
15 | * Mitsuru KANDA @USAGI and: Remove ipv6_parse_exthdrs(). |
16 | * YOSHIFUJI Hideaki @USAGI Register inbound extension header |
17 | * handlers as inet6_protocol{}. |
18 | */ |
19 | |
20 | #include <linux/errno.h> |
21 | #include <linux/types.h> |
22 | #include <linux/socket.h> |
23 | #include <linux/sockios.h> |
24 | #include <linux/net.h> |
25 | #include <linux/netdevice.h> |
26 | #include <linux/in6.h> |
27 | #include <linux/icmpv6.h> |
28 | #include <linux/slab.h> |
29 | #include <linux/export.h> |
30 | |
31 | #include <net/dst.h> |
32 | #include <net/sock.h> |
33 | #include <net/snmp.h> |
34 | |
35 | #include <net/ipv6.h> |
36 | #include <net/protocol.h> |
37 | #include <net/transp_v6.h> |
38 | #include <net/rawv6.h> |
39 | #include <net/ndisc.h> |
40 | #include <net/ip6_route.h> |
41 | #include <net/addrconf.h> |
42 | #include <net/calipso.h> |
43 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
44 | #include <net/xfrm.h> |
45 | #endif |
46 | #include <linux/seg6.h> |
47 | #include <net/seg6.h> |
48 | #ifdef CONFIG_IPV6_SEG6_HMAC |
49 | #include <net/seg6_hmac.h> |
50 | #endif |
51 | #include <net/rpl.h> |
52 | #include <linux/ioam6.h> |
53 | #include <linux/ioam6_genl.h> |
54 | #include <net/ioam6.h> |
55 | #include <net/dst_metadata.h> |
56 | |
57 | #include <linux/uaccess.h> |
58 | |
59 | /********************* |
60 | Generic functions |
61 | *********************/ |
62 | |
63 | /* An unknown option is detected, decide what to do */ |
64 | |
65 | static bool ip6_tlvopt_unknown(struct sk_buff *skb, int optoff, |
66 | bool disallow_unknowns) |
67 | { |
68 | if (disallow_unknowns) { |
69 | /* If unknown TLVs are disallowed by configuration |
70 | * then always silently drop packet. Note this also |
71 | * means no ICMP parameter problem is sent which |
72 | * could be a good property to mitigate a reflection DOS |
73 | * attack. |
74 | */ |
75 | |
76 | goto drop; |
77 | } |
78 | |
79 | switch ((skb_network_header(skb)[optoff] & 0xC0) >> 6) { |
80 | case 0: /* ignore */ |
81 | return true; |
82 | |
83 | case 1: /* drop packet */ |
84 | break; |
85 | |
86 | case 3: /* Send ICMP if not a multicast address and drop packet */ |
87 | /* Actually, it is redundant check. icmp_send |
88 | will recheck in any case. |
89 | */ |
90 | if (ipv6_addr_is_multicast(addr: &ipv6_hdr(skb)->daddr)) |
91 | break; |
92 | fallthrough; |
93 | case 2: /* send ICMP PARM PROB regardless and drop packet */ |
94 | icmpv6_param_prob_reason(skb, ICMPV6_UNK_OPTION, pos: optoff, |
95 | reason: SKB_DROP_REASON_UNHANDLED_PROTO); |
96 | return false; |
97 | } |
98 | |
99 | drop: |
100 | kfree_skb_reason(skb, reason: SKB_DROP_REASON_UNHANDLED_PROTO); |
101 | return false; |
102 | } |
103 | |
104 | static bool ipv6_hop_ra(struct sk_buff *skb, int optoff); |
105 | static bool ipv6_hop_ioam(struct sk_buff *skb, int optoff); |
106 | static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff); |
107 | static bool ipv6_hop_calipso(struct sk_buff *skb, int optoff); |
108 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
109 | static bool ipv6_dest_hao(struct sk_buff *skb, int optoff); |
110 | #endif |
111 | |
112 | /* Parse tlv encoded option header (hop-by-hop or destination) */ |
113 | |
114 | static bool ip6_parse_tlv(bool hopbyhop, |
115 | struct sk_buff *skb, |
116 | int max_count) |
117 | { |
118 | int len = (skb_transport_header(skb)[1] + 1) << 3; |
119 | const unsigned char *nh = skb_network_header(skb); |
120 | int off = skb_network_header_len(skb); |
121 | bool disallow_unknowns = false; |
122 | int tlv_count = 0; |
123 | int padlen = 0; |
124 | |
125 | if (unlikely(max_count < 0)) { |
126 | disallow_unknowns = true; |
127 | max_count = -max_count; |
128 | } |
129 | |
130 | off += 2; |
131 | len -= 2; |
132 | |
133 | while (len > 0) { |
134 | int optlen, i; |
135 | |
136 | if (nh[off] == IPV6_TLV_PAD1) { |
137 | padlen++; |
138 | if (padlen > 7) |
139 | goto bad; |
140 | off++; |
141 | len--; |
142 | continue; |
143 | } |
144 | if (len < 2) |
145 | goto bad; |
146 | optlen = nh[off + 1] + 2; |
147 | if (optlen > len) |
148 | goto bad; |
149 | |
150 | if (nh[off] == IPV6_TLV_PADN) { |
151 | /* RFC 2460 states that the purpose of PadN is |
152 | * to align the containing header to multiples |
153 | * of 8. 7 is therefore the highest valid value. |
154 | * See also RFC 4942, Section 2.1.9.5. |
155 | */ |
156 | padlen += optlen; |
157 | if (padlen > 7) |
158 | goto bad; |
159 | /* RFC 4942 recommends receiving hosts to |
160 | * actively check PadN payload to contain |
161 | * only zeroes. |
162 | */ |
163 | for (i = 2; i < optlen; i++) { |
164 | if (nh[off + i] != 0) |
165 | goto bad; |
166 | } |
167 | } else { |
168 | tlv_count++; |
169 | if (tlv_count > max_count) |
170 | goto bad; |
171 | |
172 | if (hopbyhop) { |
173 | switch (nh[off]) { |
174 | case IPV6_TLV_ROUTERALERT: |
175 | if (!ipv6_hop_ra(skb, optoff: off)) |
176 | return false; |
177 | break; |
178 | case IPV6_TLV_IOAM: |
179 | if (!ipv6_hop_ioam(skb, optoff: off)) |
180 | return false; |
181 | |
182 | nh = skb_network_header(skb); |
183 | break; |
184 | case IPV6_TLV_JUMBO: |
185 | if (!ipv6_hop_jumbo(skb, optoff: off)) |
186 | return false; |
187 | break; |
188 | case IPV6_TLV_CALIPSO: |
189 | if (!ipv6_hop_calipso(skb, optoff: off)) |
190 | return false; |
191 | break; |
192 | default: |
193 | if (!ip6_tlvopt_unknown(skb, optoff: off, |
194 | disallow_unknowns)) |
195 | return false; |
196 | break; |
197 | } |
198 | } else { |
199 | switch (nh[off]) { |
200 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
201 | case IPV6_TLV_HAO: |
202 | if (!ipv6_dest_hao(skb, optoff: off)) |
203 | return false; |
204 | break; |
205 | #endif |
206 | default: |
207 | if (!ip6_tlvopt_unknown(skb, optoff: off, |
208 | disallow_unknowns)) |
209 | return false; |
210 | break; |
211 | } |
212 | } |
213 | padlen = 0; |
214 | } |
215 | off += optlen; |
216 | len -= optlen; |
217 | } |
218 | |
219 | if (len == 0) |
220 | return true; |
221 | bad: |
222 | kfree_skb_reason(skb, reason: SKB_DROP_REASON_IP_INHDR); |
223 | return false; |
224 | } |
225 | |
226 | /***************************** |
227 | Destination options header. |
228 | *****************************/ |
229 | |
230 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
231 | static bool ipv6_dest_hao(struct sk_buff *skb, int optoff) |
232 | { |
233 | struct ipv6_destopt_hao *hao; |
234 | struct inet6_skb_parm *opt = IP6CB(skb); |
235 | struct ipv6hdr *ipv6h = ipv6_hdr(skb); |
236 | SKB_DR(reason); |
237 | int ret; |
238 | |
239 | if (opt->dsthao) { |
240 | net_dbg_ratelimited("hao duplicated\n" ); |
241 | goto discard; |
242 | } |
243 | opt->dsthao = opt->dst1; |
244 | opt->dst1 = 0; |
245 | |
246 | hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) + optoff); |
247 | |
248 | if (hao->length != 16) { |
249 | net_dbg_ratelimited("hao invalid option length = %d\n" , |
250 | hao->length); |
251 | SKB_DR_SET(reason, IP_INHDR); |
252 | goto discard; |
253 | } |
254 | |
255 | if (!(ipv6_addr_type(addr: &hao->addr) & IPV6_ADDR_UNICAST)) { |
256 | net_dbg_ratelimited("hao is not an unicast addr: %pI6\n" , |
257 | &hao->addr); |
258 | SKB_DR_SET(reason, INVALID_PROTO); |
259 | goto discard; |
260 | } |
261 | |
262 | ret = xfrm6_input_addr(skb, daddr: (xfrm_address_t *)&ipv6h->daddr, |
263 | saddr: (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS); |
264 | if (unlikely(ret < 0)) { |
265 | SKB_DR_SET(reason, XFRM_POLICY); |
266 | goto discard; |
267 | } |
268 | |
269 | if (skb_cloned(skb)) { |
270 | if (pskb_expand_head(skb, nhead: 0, ntail: 0, GFP_ATOMIC)) |
271 | goto discard; |
272 | |
273 | /* update all variable using below by copied skbuff */ |
274 | hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) + |
275 | optoff); |
276 | ipv6h = ipv6_hdr(skb); |
277 | } |
278 | |
279 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
280 | skb->ip_summed = CHECKSUM_NONE; |
281 | |
282 | swap(ipv6h->saddr, hao->addr); |
283 | |
284 | if (skb->tstamp == 0) |
285 | __net_timestamp(skb); |
286 | |
287 | return true; |
288 | |
289 | discard: |
290 | kfree_skb_reason(skb, reason); |
291 | return false; |
292 | } |
293 | #endif |
294 | |
295 | static int ipv6_destopt_rcv(struct sk_buff *skb) |
296 | { |
297 | struct inet6_dev *idev = __in6_dev_get(dev: skb->dev); |
298 | struct inet6_skb_parm *opt = IP6CB(skb); |
299 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
300 | __u16 dstbuf; |
301 | #endif |
302 | struct dst_entry *dst = skb_dst(skb); |
303 | struct net *net = dev_net(dev: skb->dev); |
304 | int extlen; |
305 | |
306 | if (!pskb_may_pull(skb, len: skb_transport_offset(skb) + 8) || |
307 | !pskb_may_pull(skb, len: (skb_transport_offset(skb) + |
308 | ((skb_transport_header(skb)[1] + 1) << 3)))) { |
309 | __IP6_INC_STATS(dev_net(dst->dev), idev, |
310 | IPSTATS_MIB_INHDRERRORS); |
311 | fail_and_free: |
312 | kfree_skb(skb); |
313 | return -1; |
314 | } |
315 | |
316 | extlen = (skb_transport_header(skb)[1] + 1) << 3; |
317 | if (extlen > net->ipv6.sysctl.max_dst_opts_len) |
318 | goto fail_and_free; |
319 | |
320 | opt->lastopt = opt->dst1 = skb_network_header_len(skb); |
321 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
322 | dstbuf = opt->dst1; |
323 | #endif |
324 | |
325 | if (ip6_parse_tlv(hopbyhop: false, skb, max_count: net->ipv6.sysctl.max_dst_opts_cnt)) { |
326 | skb->transport_header += extlen; |
327 | opt = IP6CB(skb); |
328 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
329 | opt->nhoff = dstbuf; |
330 | #else |
331 | opt->nhoff = opt->dst1; |
332 | #endif |
333 | return 1; |
334 | } |
335 | |
336 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); |
337 | return -1; |
338 | } |
339 | |
340 | static void seg6_update_csum(struct sk_buff *skb) |
341 | { |
342 | struct ipv6_sr_hdr *hdr; |
343 | struct in6_addr *addr; |
344 | __be32 from, to; |
345 | |
346 | /* srh is at transport offset and seg_left is already decremented |
347 | * but daddr is not yet updated with next segment |
348 | */ |
349 | |
350 | hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb); |
351 | addr = hdr->segments + hdr->segments_left; |
352 | |
353 | hdr->segments_left++; |
354 | from = *(__be32 *)hdr; |
355 | |
356 | hdr->segments_left--; |
357 | to = *(__be32 *)hdr; |
358 | |
359 | /* update skb csum with diff resulting from seg_left decrement */ |
360 | |
361 | update_csum_diff4(skb, from, to); |
362 | |
363 | /* compute csum diff between current and next segment and update */ |
364 | |
365 | update_csum_diff16(skb, from: (__be32 *)(&ipv6_hdr(skb)->daddr), |
366 | to: (__be32 *)addr); |
367 | } |
368 | |
369 | static int ipv6_srh_rcv(struct sk_buff *skb) |
370 | { |
371 | struct inet6_skb_parm *opt = IP6CB(skb); |
372 | struct net *net = dev_net(dev: skb->dev); |
373 | struct ipv6_sr_hdr *hdr; |
374 | struct inet6_dev *idev; |
375 | struct in6_addr *addr; |
376 | int accept_seg6; |
377 | |
378 | hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb); |
379 | |
380 | idev = __in6_dev_get(dev: skb->dev); |
381 | |
382 | accept_seg6 = min(READ_ONCE(net->ipv6.devconf_all->seg6_enabled), |
383 | READ_ONCE(idev->cnf.seg6_enabled)); |
384 | |
385 | if (!accept_seg6) { |
386 | kfree_skb(skb); |
387 | return -1; |
388 | } |
389 | |
390 | #ifdef CONFIG_IPV6_SEG6_HMAC |
391 | if (!seg6_hmac_validate_skb(skb)) { |
392 | kfree_skb(skb); |
393 | return -1; |
394 | } |
395 | #endif |
396 | |
397 | looped_back: |
398 | if (hdr->segments_left == 0) { |
399 | if (hdr->nexthdr == NEXTHDR_IPV6 || hdr->nexthdr == NEXTHDR_IPV4) { |
400 | int offset = (hdr->hdrlen + 1) << 3; |
401 | |
402 | skb_postpull_rcsum(skb, start: skb_network_header(skb), |
403 | len: skb_network_header_len(skb)); |
404 | skb_pull(skb, len: offset); |
405 | skb_postpull_rcsum(skb, start: skb_transport_header(skb), |
406 | len: offset); |
407 | |
408 | skb_reset_network_header(skb); |
409 | skb_reset_transport_header(skb); |
410 | skb->encapsulation = 0; |
411 | if (hdr->nexthdr == NEXTHDR_IPV4) |
412 | skb->protocol = htons(ETH_P_IP); |
413 | __skb_tunnel_rx(skb, dev: skb->dev, net); |
414 | |
415 | netif_rx(skb); |
416 | return -1; |
417 | } |
418 | |
419 | opt->srcrt = skb_network_header_len(skb); |
420 | opt->lastopt = opt->srcrt; |
421 | skb->transport_header += (hdr->hdrlen + 1) << 3; |
422 | opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb); |
423 | |
424 | return 1; |
425 | } |
426 | |
427 | if (hdr->segments_left >= (hdr->hdrlen >> 1)) { |
428 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); |
429 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, |
430 | pos: ((&hdr->segments_left) - |
431 | skb_network_header(skb))); |
432 | return -1; |
433 | } |
434 | |
435 | if (skb_cloned(skb)) { |
436 | if (pskb_expand_head(skb, nhead: 0, ntail: 0, GFP_ATOMIC)) { |
437 | __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
438 | IPSTATS_MIB_OUTDISCARDS); |
439 | kfree_skb(skb); |
440 | return -1; |
441 | } |
442 | |
443 | hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb); |
444 | } |
445 | |
446 | hdr->segments_left--; |
447 | addr = hdr->segments + hdr->segments_left; |
448 | |
449 | skb_push(skb, len: sizeof(struct ipv6hdr)); |
450 | |
451 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
452 | seg6_update_csum(skb); |
453 | |
454 | ipv6_hdr(skb)->daddr = *addr; |
455 | |
456 | ip6_route_input(skb); |
457 | |
458 | if (skb_dst(skb)->error) { |
459 | dst_input(skb); |
460 | return -1; |
461 | } |
462 | |
463 | if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) { |
464 | if (ipv6_hdr(skb)->hop_limit <= 1) { |
465 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); |
466 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, |
467 | ICMPV6_EXC_HOPLIMIT, info: 0); |
468 | kfree_skb(skb); |
469 | return -1; |
470 | } |
471 | ipv6_hdr(skb)->hop_limit--; |
472 | |
473 | skb_pull(skb, len: sizeof(struct ipv6hdr)); |
474 | goto looped_back; |
475 | } |
476 | |
477 | dst_input(skb); |
478 | |
479 | return -1; |
480 | } |
481 | |
482 | static int ipv6_rpl_srh_rcv(struct sk_buff *skb) |
483 | { |
484 | struct ipv6_rpl_sr_hdr *hdr, *ohdr, *chdr; |
485 | struct inet6_skb_parm *opt = IP6CB(skb); |
486 | struct net *net = dev_net(dev: skb->dev); |
487 | struct inet6_dev *idev; |
488 | struct ipv6hdr *oldhdr; |
489 | unsigned char *buf; |
490 | int accept_rpl_seg; |
491 | int i, err; |
492 | u64 n = 0; |
493 | u32 r; |
494 | |
495 | idev = __in6_dev_get(dev: skb->dev); |
496 | |
497 | accept_rpl_seg = net->ipv6.devconf_all->rpl_seg_enabled; |
498 | if (accept_rpl_seg > idev->cnf.rpl_seg_enabled) |
499 | accept_rpl_seg = idev->cnf.rpl_seg_enabled; |
500 | |
501 | if (!accept_rpl_seg) { |
502 | kfree_skb(skb); |
503 | return -1; |
504 | } |
505 | |
506 | looped_back: |
507 | hdr = (struct ipv6_rpl_sr_hdr *)skb_transport_header(skb); |
508 | |
509 | if (hdr->segments_left == 0) { |
510 | if (hdr->nexthdr == NEXTHDR_IPV6) { |
511 | int offset = (hdr->hdrlen + 1) << 3; |
512 | |
513 | skb_postpull_rcsum(skb, start: skb_network_header(skb), |
514 | len: skb_network_header_len(skb)); |
515 | skb_pull(skb, len: offset); |
516 | skb_postpull_rcsum(skb, start: skb_transport_header(skb), |
517 | len: offset); |
518 | |
519 | skb_reset_network_header(skb); |
520 | skb_reset_transport_header(skb); |
521 | skb->encapsulation = 0; |
522 | |
523 | __skb_tunnel_rx(skb, dev: skb->dev, net); |
524 | |
525 | netif_rx(skb); |
526 | return -1; |
527 | } |
528 | |
529 | opt->srcrt = skb_network_header_len(skb); |
530 | opt->lastopt = opt->srcrt; |
531 | skb->transport_header += (hdr->hdrlen + 1) << 3; |
532 | opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb); |
533 | |
534 | return 1; |
535 | } |
536 | |
537 | n = (hdr->hdrlen << 3) - hdr->pad - (16 - hdr->cmpre); |
538 | r = do_div(n, (16 - hdr->cmpri)); |
539 | /* checks if calculation was without remainder and n fits into |
540 | * unsigned char which is segments_left field. Should not be |
541 | * higher than that. |
542 | */ |
543 | if (r || (n + 1) > 255) { |
544 | kfree_skb(skb); |
545 | return -1; |
546 | } |
547 | |
548 | if (hdr->segments_left > n + 1) { |
549 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); |
550 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, |
551 | pos: ((&hdr->segments_left) - |
552 | skb_network_header(skb))); |
553 | return -1; |
554 | } |
555 | |
556 | hdr->segments_left--; |
557 | i = n - hdr->segments_left; |
558 | |
559 | buf = kcalloc(struct_size(hdr, segments.addr, n + 2), size: 2, GFP_ATOMIC); |
560 | if (unlikely(!buf)) { |
561 | kfree_skb(skb); |
562 | return -1; |
563 | } |
564 | |
565 | ohdr = (struct ipv6_rpl_sr_hdr *)buf; |
566 | ipv6_rpl_srh_decompress(outhdr: ohdr, inhdr: hdr, daddr: &ipv6_hdr(skb)->daddr, n); |
567 | chdr = (struct ipv6_rpl_sr_hdr *)(buf + ((ohdr->hdrlen + 1) << 3)); |
568 | |
569 | if (ipv6_addr_is_multicast(addr: &ohdr->rpl_segaddr[i])) { |
570 | kfree_skb(skb); |
571 | kfree(objp: buf); |
572 | return -1; |
573 | } |
574 | |
575 | err = ipv6_chk_rpl_srh_loop(net, segs: ohdr->rpl_segaddr, nsegs: n + 1); |
576 | if (err) { |
577 | icmpv6_send(skb, ICMPV6_PARAMPROB, code: 0, info: 0); |
578 | kfree_skb(skb); |
579 | kfree(objp: buf); |
580 | return -1; |
581 | } |
582 | |
583 | swap(ipv6_hdr(skb)->daddr, ohdr->rpl_segaddr[i]); |
584 | |
585 | ipv6_rpl_srh_compress(outhdr: chdr, inhdr: ohdr, daddr: &ipv6_hdr(skb)->daddr, n); |
586 | |
587 | oldhdr = ipv6_hdr(skb); |
588 | |
589 | skb_pull(skb, len: ((hdr->hdrlen + 1) << 3)); |
590 | skb_postpull_rcsum(skb, start: oldhdr, |
591 | len: sizeof(struct ipv6hdr) + ((hdr->hdrlen + 1) << 3)); |
592 | if (unlikely(!hdr->segments_left)) { |
593 | if (pskb_expand_head(skb, nhead: sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3), ntail: 0, |
594 | GFP_ATOMIC)) { |
595 | __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS); |
596 | kfree_skb(skb); |
597 | kfree(objp: buf); |
598 | return -1; |
599 | } |
600 | |
601 | oldhdr = ipv6_hdr(skb); |
602 | } |
603 | skb_push(skb, len: ((chdr->hdrlen + 1) << 3) + sizeof(struct ipv6hdr)); |
604 | skb_reset_network_header(skb); |
605 | skb_mac_header_rebuild(skb); |
606 | skb_set_transport_header(skb, offset: sizeof(struct ipv6hdr)); |
607 | |
608 | memmove(ipv6_hdr(skb), oldhdr, sizeof(struct ipv6hdr)); |
609 | memcpy(skb_transport_header(skb), chdr, (chdr->hdrlen + 1) << 3); |
610 | |
611 | ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); |
612 | skb_postpush_rcsum(skb, start: ipv6_hdr(skb), |
613 | len: sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3)); |
614 | |
615 | kfree(objp: buf); |
616 | |
617 | ip6_route_input(skb); |
618 | |
619 | if (skb_dst(skb)->error) { |
620 | dst_input(skb); |
621 | return -1; |
622 | } |
623 | |
624 | if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) { |
625 | if (ipv6_hdr(skb)->hop_limit <= 1) { |
626 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); |
627 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, |
628 | ICMPV6_EXC_HOPLIMIT, info: 0); |
629 | kfree_skb(skb); |
630 | return -1; |
631 | } |
632 | ipv6_hdr(skb)->hop_limit--; |
633 | |
634 | skb_pull(skb, len: sizeof(struct ipv6hdr)); |
635 | goto looped_back; |
636 | } |
637 | |
638 | dst_input(skb); |
639 | |
640 | return -1; |
641 | } |
642 | |
643 | /******************************** |
644 | Routing header. |
645 | ********************************/ |
646 | |
647 | /* called with rcu_read_lock() */ |
648 | static int ipv6_rthdr_rcv(struct sk_buff *skb) |
649 | { |
650 | struct inet6_dev *idev = __in6_dev_get(dev: skb->dev); |
651 | struct inet6_skb_parm *opt = IP6CB(skb); |
652 | struct in6_addr *addr = NULL; |
653 | int n, i; |
654 | struct ipv6_rt_hdr *hdr; |
655 | struct rt0_hdr *rthdr; |
656 | struct net *net = dev_net(dev: skb->dev); |
657 | int accept_source_route; |
658 | |
659 | accept_source_route = READ_ONCE(net->ipv6.devconf_all->accept_source_route); |
660 | |
661 | if (idev) |
662 | accept_source_route = min(accept_source_route, |
663 | READ_ONCE(idev->cnf.accept_source_route)); |
664 | |
665 | if (!pskb_may_pull(skb, len: skb_transport_offset(skb) + 8) || |
666 | !pskb_may_pull(skb, len: (skb_transport_offset(skb) + |
667 | ((skb_transport_header(skb)[1] + 1) << 3)))) { |
668 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); |
669 | kfree_skb(skb); |
670 | return -1; |
671 | } |
672 | |
673 | hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb); |
674 | |
675 | if (ipv6_addr_is_multicast(addr: &ipv6_hdr(skb)->daddr) || |
676 | skb->pkt_type != PACKET_HOST) { |
677 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS); |
678 | kfree_skb(skb); |
679 | return -1; |
680 | } |
681 | |
682 | switch (hdr->type) { |
683 | case IPV6_SRCRT_TYPE_4: |
684 | /* segment routing */ |
685 | return ipv6_srh_rcv(skb); |
686 | case IPV6_SRCRT_TYPE_3: |
687 | /* rpl segment routing */ |
688 | return ipv6_rpl_srh_rcv(skb); |
689 | default: |
690 | break; |
691 | } |
692 | |
693 | looped_back: |
694 | if (hdr->segments_left == 0) { |
695 | switch (hdr->type) { |
696 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
697 | case IPV6_SRCRT_TYPE_2: |
698 | /* Silently discard type 2 header unless it was |
699 | * processed by own |
700 | */ |
701 | if (!addr) { |
702 | __IP6_INC_STATS(net, idev, |
703 | IPSTATS_MIB_INADDRERRORS); |
704 | kfree_skb(skb); |
705 | return -1; |
706 | } |
707 | break; |
708 | #endif |
709 | default: |
710 | break; |
711 | } |
712 | |
713 | opt->lastopt = opt->srcrt = skb_network_header_len(skb); |
714 | skb->transport_header += (hdr->hdrlen + 1) << 3; |
715 | opt->dst0 = opt->dst1; |
716 | opt->dst1 = 0; |
717 | opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb); |
718 | return 1; |
719 | } |
720 | |
721 | switch (hdr->type) { |
722 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
723 | case IPV6_SRCRT_TYPE_2: |
724 | if (accept_source_route < 0) |
725 | goto unknown_rh; |
726 | /* Silently discard invalid RTH type 2 */ |
727 | if (hdr->hdrlen != 2 || hdr->segments_left != 1) { |
728 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); |
729 | kfree_skb(skb); |
730 | return -1; |
731 | } |
732 | break; |
733 | #endif |
734 | default: |
735 | goto unknown_rh; |
736 | } |
737 | |
738 | /* |
739 | * This is the routing header forwarding algorithm from |
740 | * RFC 2460, page 16. |
741 | */ |
742 | |
743 | n = hdr->hdrlen >> 1; |
744 | |
745 | if (hdr->segments_left > n) { |
746 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); |
747 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, |
748 | pos: ((&hdr->segments_left) - |
749 | skb_network_header(skb))); |
750 | return -1; |
751 | } |
752 | |
753 | /* We are about to mangle packet header. Be careful! |
754 | Do not damage packets queued somewhere. |
755 | */ |
756 | if (skb_cloned(skb)) { |
757 | /* the copy is a forwarded packet */ |
758 | if (pskb_expand_head(skb, nhead: 0, ntail: 0, GFP_ATOMIC)) { |
759 | __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
760 | IPSTATS_MIB_OUTDISCARDS); |
761 | kfree_skb(skb); |
762 | return -1; |
763 | } |
764 | hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb); |
765 | } |
766 | |
767 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
768 | skb->ip_summed = CHECKSUM_NONE; |
769 | |
770 | i = n - --hdr->segments_left; |
771 | |
772 | rthdr = (struct rt0_hdr *) hdr; |
773 | addr = rthdr->addr; |
774 | addr += i - 1; |
775 | |
776 | switch (hdr->type) { |
777 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
778 | case IPV6_SRCRT_TYPE_2: |
779 | if (xfrm6_input_addr(skb, daddr: (xfrm_address_t *)addr, |
780 | saddr: (xfrm_address_t *)&ipv6_hdr(skb)->saddr, |
781 | IPPROTO_ROUTING) < 0) { |
782 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS); |
783 | kfree_skb(skb); |
784 | return -1; |
785 | } |
786 | if (!ipv6_chk_home_addr(net: dev_net(dev: skb_dst(skb)->dev), addr)) { |
787 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS); |
788 | kfree_skb(skb); |
789 | return -1; |
790 | } |
791 | break; |
792 | #endif |
793 | default: |
794 | break; |
795 | } |
796 | |
797 | if (ipv6_addr_is_multicast(addr)) { |
798 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS); |
799 | kfree_skb(skb); |
800 | return -1; |
801 | } |
802 | |
803 | swap(*addr, ipv6_hdr(skb)->daddr); |
804 | |
805 | ip6_route_input(skb); |
806 | if (skb_dst(skb)->error) { |
807 | skb_push(skb, len: -skb_network_offset(skb)); |
808 | dst_input(skb); |
809 | return -1; |
810 | } |
811 | |
812 | if (skb_dst(skb)->dev->flags&IFF_LOOPBACK) { |
813 | if (ipv6_hdr(skb)->hop_limit <= 1) { |
814 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); |
815 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, |
816 | info: 0); |
817 | kfree_skb(skb); |
818 | return -1; |
819 | } |
820 | ipv6_hdr(skb)->hop_limit--; |
821 | goto looped_back; |
822 | } |
823 | |
824 | skb_push(skb, len: -skb_network_offset(skb)); |
825 | dst_input(skb); |
826 | return -1; |
827 | |
828 | unknown_rh: |
829 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); |
830 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, |
831 | pos: (&hdr->type) - skb_network_header(skb)); |
832 | return -1; |
833 | } |
834 | |
835 | static const struct inet6_protocol rthdr_protocol = { |
836 | .handler = ipv6_rthdr_rcv, |
837 | .flags = INET6_PROTO_NOPOLICY, |
838 | }; |
839 | |
840 | static const struct inet6_protocol destopt_protocol = { |
841 | .handler = ipv6_destopt_rcv, |
842 | .flags = INET6_PROTO_NOPOLICY, |
843 | }; |
844 | |
845 | static const struct inet6_protocol nodata_protocol = { |
846 | .handler = dst_discard, |
847 | .flags = INET6_PROTO_NOPOLICY, |
848 | }; |
849 | |
850 | int __init ipv6_exthdrs_init(void) |
851 | { |
852 | int ret; |
853 | |
854 | ret = inet6_add_protocol(prot: &rthdr_protocol, IPPROTO_ROUTING); |
855 | if (ret) |
856 | goto out; |
857 | |
858 | ret = inet6_add_protocol(prot: &destopt_protocol, IPPROTO_DSTOPTS); |
859 | if (ret) |
860 | goto out_rthdr; |
861 | |
862 | ret = inet6_add_protocol(prot: &nodata_protocol, IPPROTO_NONE); |
863 | if (ret) |
864 | goto out_destopt; |
865 | |
866 | out: |
867 | return ret; |
868 | out_destopt: |
869 | inet6_del_protocol(prot: &destopt_protocol, IPPROTO_DSTOPTS); |
870 | out_rthdr: |
871 | inet6_del_protocol(prot: &rthdr_protocol, IPPROTO_ROUTING); |
872 | goto out; |
873 | }; |
874 | |
875 | void ipv6_exthdrs_exit(void) |
876 | { |
877 | inet6_del_protocol(prot: &nodata_protocol, IPPROTO_NONE); |
878 | inet6_del_protocol(prot: &destopt_protocol, IPPROTO_DSTOPTS); |
879 | inet6_del_protocol(prot: &rthdr_protocol, IPPROTO_ROUTING); |
880 | } |
881 | |
882 | /********************************** |
883 | Hop-by-hop options. |
884 | **********************************/ |
885 | |
886 | /* Router Alert as of RFC 2711 */ |
887 | |
888 | static bool ipv6_hop_ra(struct sk_buff *skb, int optoff) |
889 | { |
890 | const unsigned char *nh = skb_network_header(skb); |
891 | |
892 | if (nh[optoff + 1] == 2) { |
893 | IP6CB(skb)->flags |= IP6SKB_ROUTERALERT; |
894 | memcpy(&IP6CB(skb)->ra, nh + optoff + 2, sizeof(IP6CB(skb)->ra)); |
895 | return true; |
896 | } |
897 | net_dbg_ratelimited("ipv6_hop_ra: wrong RA length %d\n" , |
898 | nh[optoff + 1]); |
899 | kfree_skb_reason(skb, reason: SKB_DROP_REASON_IP_INHDR); |
900 | return false; |
901 | } |
902 | |
903 | /* IOAM */ |
904 | |
905 | static bool ipv6_hop_ioam(struct sk_buff *skb, int optoff) |
906 | { |
907 | struct ioam6_trace_hdr *trace; |
908 | struct ioam6_namespace *ns; |
909 | struct ioam6_hdr *hdr; |
910 | |
911 | /* Bad alignment (must be 4n-aligned) */ |
912 | if (optoff & 3) |
913 | goto drop; |
914 | |
915 | /* Ignore if IOAM is not enabled on ingress */ |
916 | if (!READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_enabled)) |
917 | goto ignore; |
918 | |
919 | /* Truncated Option header */ |
920 | hdr = (struct ioam6_hdr *)(skb_network_header(skb) + optoff); |
921 | if (hdr->opt_len < 2) |
922 | goto drop; |
923 | |
924 | switch (hdr->type) { |
925 | case IOAM6_TYPE_PREALLOC: |
926 | /* Truncated Pre-allocated Trace header */ |
927 | if (hdr->opt_len < 2 + sizeof(*trace)) |
928 | goto drop; |
929 | |
930 | /* Malformed Pre-allocated Trace header */ |
931 | trace = (struct ioam6_trace_hdr *)((u8 *)hdr + sizeof(*hdr)); |
932 | if (hdr->opt_len < 2 + sizeof(*trace) + trace->remlen * 4) |
933 | goto drop; |
934 | |
935 | /* Ignore if the IOAM namespace is unknown */ |
936 | ns = ioam6_namespace(net: dev_net(dev: skb->dev), id: trace->namespace_id); |
937 | if (!ns) |
938 | goto ignore; |
939 | |
940 | if (!skb_valid_dst(skb)) |
941 | ip6_route_input(skb); |
942 | |
943 | /* About to mangle packet header */ |
944 | if (skb_ensure_writable(skb, write_len: optoff + 2 + hdr->opt_len)) |
945 | goto drop; |
946 | |
947 | /* Trace pointer may have changed */ |
948 | trace = (struct ioam6_trace_hdr *)(skb_network_header(skb) |
949 | + optoff + sizeof(*hdr)); |
950 | |
951 | ioam6_fill_trace_data(skb, ns, trace, is_input: true); |
952 | |
953 | ioam6_event(type: IOAM6_EVENT_TRACE, net: dev_net(dev: skb->dev), |
954 | GFP_ATOMIC, opt: (void *)trace, opt_len: hdr->opt_len - 2); |
955 | break; |
956 | default: |
957 | break; |
958 | } |
959 | |
960 | ignore: |
961 | return true; |
962 | |
963 | drop: |
964 | kfree_skb_reason(skb, reason: SKB_DROP_REASON_IP_INHDR); |
965 | return false; |
966 | } |
967 | |
968 | /* Jumbo payload */ |
969 | |
970 | static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff) |
971 | { |
972 | const unsigned char *nh = skb_network_header(skb); |
973 | SKB_DR(reason); |
974 | u32 pkt_len; |
975 | |
976 | if (nh[optoff + 1] != 4 || (optoff & 3) != 2) { |
977 | net_dbg_ratelimited("ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n" , |
978 | nh[optoff+1]); |
979 | SKB_DR_SET(reason, IP_INHDR); |
980 | goto drop; |
981 | } |
982 | |
983 | pkt_len = ntohl(*(__be32 *)(nh + optoff + 2)); |
984 | if (pkt_len <= IPV6_MAXPLEN) { |
985 | icmpv6_param_prob_reason(skb, ICMPV6_HDR_FIELD, pos: optoff + 2, |
986 | reason: SKB_DROP_REASON_IP_INHDR); |
987 | return false; |
988 | } |
989 | if (ipv6_hdr(skb)->payload_len) { |
990 | icmpv6_param_prob_reason(skb, ICMPV6_HDR_FIELD, pos: optoff, |
991 | reason: SKB_DROP_REASON_IP_INHDR); |
992 | return false; |
993 | } |
994 | |
995 | if (pkt_len > skb->len - sizeof(struct ipv6hdr)) { |
996 | SKB_DR_SET(reason, PKT_TOO_SMALL); |
997 | goto drop; |
998 | } |
999 | |
1000 | if (pskb_trim_rcsum(skb, len: pkt_len + sizeof(struct ipv6hdr))) |
1001 | goto drop; |
1002 | |
1003 | IP6CB(skb)->flags |= IP6SKB_JUMBOGRAM; |
1004 | return true; |
1005 | |
1006 | drop: |
1007 | kfree_skb_reason(skb, reason); |
1008 | return false; |
1009 | } |
1010 | |
1011 | /* CALIPSO RFC 5570 */ |
1012 | |
1013 | static bool ipv6_hop_calipso(struct sk_buff *skb, int optoff) |
1014 | { |
1015 | const unsigned char *nh = skb_network_header(skb); |
1016 | |
1017 | if (nh[optoff + 1] < 8) |
1018 | goto drop; |
1019 | |
1020 | if (nh[optoff + 6] * 4 + 8 > nh[optoff + 1]) |
1021 | goto drop; |
1022 | |
1023 | if (!calipso_validate(skb, option: nh + optoff)) |
1024 | goto drop; |
1025 | |
1026 | return true; |
1027 | |
1028 | drop: |
1029 | kfree_skb_reason(skb, reason: SKB_DROP_REASON_IP_INHDR); |
1030 | return false; |
1031 | } |
1032 | |
1033 | int ipv6_parse_hopopts(struct sk_buff *skb) |
1034 | { |
1035 | struct inet6_skb_parm *opt = IP6CB(skb); |
1036 | struct net *net = dev_net(dev: skb->dev); |
1037 | int extlen; |
1038 | |
1039 | /* |
1040 | * skb_network_header(skb) is equal to skb->data, and |
1041 | * skb_network_header_len(skb) is always equal to |
1042 | * sizeof(struct ipv6hdr) by definition of |
1043 | * hop-by-hop options. |
1044 | */ |
1045 | if (!pskb_may_pull(skb, len: sizeof(struct ipv6hdr) + 8) || |
1046 | !pskb_may_pull(skb, len: (sizeof(struct ipv6hdr) + |
1047 | ((skb_transport_header(skb)[1] + 1) << 3)))) { |
1048 | fail_and_free: |
1049 | kfree_skb(skb); |
1050 | return -1; |
1051 | } |
1052 | |
1053 | extlen = (skb_transport_header(skb)[1] + 1) << 3; |
1054 | if (extlen > net->ipv6.sysctl.max_hbh_opts_len) |
1055 | goto fail_and_free; |
1056 | |
1057 | opt->flags |= IP6SKB_HOPBYHOP; |
1058 | if (ip6_parse_tlv(hopbyhop: true, skb, max_count: net->ipv6.sysctl.max_hbh_opts_cnt)) { |
1059 | skb->transport_header += extlen; |
1060 | opt = IP6CB(skb); |
1061 | opt->nhoff = sizeof(struct ipv6hdr); |
1062 | return 1; |
1063 | } |
1064 | return -1; |
1065 | } |
1066 | |
1067 | /* |
1068 | * Creating outbound headers. |
1069 | * |
1070 | * "build" functions work when skb is filled from head to tail (datagram) |
1071 | * "push" functions work when headers are added from tail to head (tcp) |
1072 | * |
1073 | * In both cases we assume, that caller reserved enough room |
1074 | * for headers. |
1075 | */ |
1076 | |
1077 | static void ipv6_push_rthdr0(struct sk_buff *skb, u8 *proto, |
1078 | struct ipv6_rt_hdr *opt, |
1079 | struct in6_addr **addr_p, struct in6_addr *saddr) |
1080 | { |
1081 | struct rt0_hdr *phdr, *ihdr; |
1082 | int hops; |
1083 | |
1084 | ihdr = (struct rt0_hdr *) opt; |
1085 | |
1086 | phdr = skb_push(skb, len: (ihdr->rt_hdr.hdrlen + 1) << 3); |
1087 | memcpy(phdr, ihdr, sizeof(struct rt0_hdr)); |
1088 | |
1089 | hops = ihdr->rt_hdr.hdrlen >> 1; |
1090 | |
1091 | if (hops > 1) |
1092 | memcpy(phdr->addr, ihdr->addr + 1, |
1093 | (hops - 1) * sizeof(struct in6_addr)); |
1094 | |
1095 | phdr->addr[hops - 1] = **addr_p; |
1096 | *addr_p = ihdr->addr; |
1097 | |
1098 | phdr->rt_hdr.nexthdr = *proto; |
1099 | *proto = NEXTHDR_ROUTING; |
1100 | } |
1101 | |
1102 | static void ipv6_push_rthdr4(struct sk_buff *skb, u8 *proto, |
1103 | struct ipv6_rt_hdr *opt, |
1104 | struct in6_addr **addr_p, struct in6_addr *saddr) |
1105 | { |
1106 | struct ipv6_sr_hdr *sr_phdr, *sr_ihdr; |
1107 | int plen, hops; |
1108 | |
1109 | sr_ihdr = (struct ipv6_sr_hdr *)opt; |
1110 | plen = (sr_ihdr->hdrlen + 1) << 3; |
1111 | |
1112 | sr_phdr = skb_push(skb, len: plen); |
1113 | memcpy(sr_phdr, sr_ihdr, sizeof(struct ipv6_sr_hdr)); |
1114 | |
1115 | hops = sr_ihdr->first_segment + 1; |
1116 | memcpy(sr_phdr->segments + 1, sr_ihdr->segments + 1, |
1117 | (hops - 1) * sizeof(struct in6_addr)); |
1118 | |
1119 | sr_phdr->segments[0] = **addr_p; |
1120 | *addr_p = &sr_ihdr->segments[sr_ihdr->segments_left]; |
1121 | |
1122 | if (sr_ihdr->hdrlen > hops * 2) { |
1123 | int tlvs_offset, tlvs_length; |
1124 | |
1125 | tlvs_offset = (1 + hops * 2) << 3; |
1126 | tlvs_length = (sr_ihdr->hdrlen - hops * 2) << 3; |
1127 | memcpy((char *)sr_phdr + tlvs_offset, |
1128 | (char *)sr_ihdr + tlvs_offset, tlvs_length); |
1129 | } |
1130 | |
1131 | #ifdef CONFIG_IPV6_SEG6_HMAC |
1132 | if (sr_has_hmac(sr_phdr)) { |
1133 | struct net *net = NULL; |
1134 | |
1135 | if (skb->dev) |
1136 | net = dev_net(dev: skb->dev); |
1137 | else if (skb->sk) |
1138 | net = sock_net(sk: skb->sk); |
1139 | |
1140 | WARN_ON(!net); |
1141 | |
1142 | if (net) |
1143 | seg6_push_hmac(net, saddr, srh: sr_phdr); |
1144 | } |
1145 | #endif |
1146 | |
1147 | sr_phdr->nexthdr = *proto; |
1148 | *proto = NEXTHDR_ROUTING; |
1149 | } |
1150 | |
1151 | static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto, |
1152 | struct ipv6_rt_hdr *opt, |
1153 | struct in6_addr **addr_p, struct in6_addr *saddr) |
1154 | { |
1155 | switch (opt->type) { |
1156 | case IPV6_SRCRT_TYPE_0: |
1157 | case IPV6_SRCRT_STRICT: |
1158 | case IPV6_SRCRT_TYPE_2: |
1159 | ipv6_push_rthdr0(skb, proto, opt, addr_p, saddr); |
1160 | break; |
1161 | case IPV6_SRCRT_TYPE_4: |
1162 | ipv6_push_rthdr4(skb, proto, opt, addr_p, saddr); |
1163 | break; |
1164 | default: |
1165 | break; |
1166 | } |
1167 | } |
1168 | |
1169 | static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt) |
1170 | { |
1171 | struct ipv6_opt_hdr *h = skb_push(skb, ipv6_optlen(opt)); |
1172 | |
1173 | memcpy(h, opt, ipv6_optlen(opt)); |
1174 | h->nexthdr = *proto; |
1175 | *proto = type; |
1176 | } |
1177 | |
1178 | void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, |
1179 | u8 *proto, |
1180 | struct in6_addr **daddr, struct in6_addr *saddr) |
1181 | { |
1182 | if (opt->srcrt) { |
1183 | ipv6_push_rthdr(skb, proto, opt: opt->srcrt, addr_p: daddr, saddr); |
1184 | /* |
1185 | * IPV6_RTHDRDSTOPTS is ignored |
1186 | * unless IPV6_RTHDR is set (RFC3542). |
1187 | */ |
1188 | if (opt->dst0opt) |
1189 | ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt: opt->dst0opt); |
1190 | } |
1191 | if (opt->hopopt) |
1192 | ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt: opt->hopopt); |
1193 | } |
1194 | |
1195 | void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto) |
1196 | { |
1197 | if (opt->dst1opt) |
1198 | ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt: opt->dst1opt); |
1199 | } |
1200 | EXPORT_SYMBOL(ipv6_push_frag_opts); |
1201 | |
1202 | struct ipv6_txoptions * |
1203 | ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt) |
1204 | { |
1205 | struct ipv6_txoptions *opt2; |
1206 | |
1207 | opt2 = sock_kmalloc(sk, size: opt->tot_len, GFP_ATOMIC); |
1208 | if (opt2) { |
1209 | long dif = (char *)opt2 - (char *)opt; |
1210 | memcpy(opt2, opt, opt->tot_len); |
1211 | if (opt2->hopopt) |
1212 | *((char **)&opt2->hopopt) += dif; |
1213 | if (opt2->dst0opt) |
1214 | *((char **)&opt2->dst0opt) += dif; |
1215 | if (opt2->dst1opt) |
1216 | *((char **)&opt2->dst1opt) += dif; |
1217 | if (opt2->srcrt) |
1218 | *((char **)&opt2->srcrt) += dif; |
1219 | refcount_set(r: &opt2->refcnt, n: 1); |
1220 | } |
1221 | return opt2; |
1222 | } |
1223 | EXPORT_SYMBOL_GPL(ipv6_dup_options); |
1224 | |
1225 | static void ipv6_renew_option(int renewtype, |
1226 | struct ipv6_opt_hdr **dest, |
1227 | struct ipv6_opt_hdr *old, |
1228 | struct ipv6_opt_hdr *new, |
1229 | int newtype, char **p) |
1230 | { |
1231 | struct ipv6_opt_hdr *src; |
1232 | |
1233 | src = (renewtype == newtype ? new : old); |
1234 | if (!src) |
1235 | return; |
1236 | |
1237 | memcpy(*p, src, ipv6_optlen(src)); |
1238 | *dest = (struct ipv6_opt_hdr *)*p; |
1239 | *p += CMSG_ALIGN(ipv6_optlen(*dest)); |
1240 | } |
1241 | |
1242 | /** |
1243 | * ipv6_renew_options - replace a specific ext hdr with a new one. |
1244 | * |
1245 | * @sk: sock from which to allocate memory |
1246 | * @opt: original options |
1247 | * @newtype: option type to replace in @opt |
1248 | * @newopt: new option of type @newtype to replace (user-mem) |
1249 | * |
1250 | * Returns a new set of options which is a copy of @opt with the |
1251 | * option type @newtype replaced with @newopt. |
1252 | * |
1253 | * @opt may be NULL, in which case a new set of options is returned |
1254 | * containing just @newopt. |
1255 | * |
1256 | * @newopt may be NULL, in which case the specified option type is |
1257 | * not copied into the new set of options. |
1258 | * |
1259 | * The new set of options is allocated from the socket option memory |
1260 | * buffer of @sk. |
1261 | */ |
1262 | struct ipv6_txoptions * |
1263 | ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, |
1264 | int newtype, struct ipv6_opt_hdr *newopt) |
1265 | { |
1266 | int tot_len = 0; |
1267 | char *p; |
1268 | struct ipv6_txoptions *opt2; |
1269 | |
1270 | if (opt) { |
1271 | if (newtype != IPV6_HOPOPTS && opt->hopopt) |
1272 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt)); |
1273 | if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt) |
1274 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt)); |
1275 | if (newtype != IPV6_RTHDR && opt->srcrt) |
1276 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt)); |
1277 | if (newtype != IPV6_DSTOPTS && opt->dst1opt) |
1278 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt)); |
1279 | } |
1280 | |
1281 | if (newopt) |
1282 | tot_len += CMSG_ALIGN(ipv6_optlen(newopt)); |
1283 | |
1284 | if (!tot_len) |
1285 | return NULL; |
1286 | |
1287 | tot_len += sizeof(*opt2); |
1288 | opt2 = sock_kmalloc(sk, size: tot_len, GFP_ATOMIC); |
1289 | if (!opt2) |
1290 | return ERR_PTR(error: -ENOBUFS); |
1291 | |
1292 | memset(opt2, 0, tot_len); |
1293 | refcount_set(r: &opt2->refcnt, n: 1); |
1294 | opt2->tot_len = tot_len; |
1295 | p = (char *)(opt2 + 1); |
1296 | |
1297 | ipv6_renew_option(IPV6_HOPOPTS, dest: &opt2->hopopt, |
1298 | old: (opt ? opt->hopopt : NULL), |
1299 | new: newopt, newtype, p: &p); |
1300 | ipv6_renew_option(IPV6_RTHDRDSTOPTS, dest: &opt2->dst0opt, |
1301 | old: (opt ? opt->dst0opt : NULL), |
1302 | new: newopt, newtype, p: &p); |
1303 | ipv6_renew_option(IPV6_RTHDR, |
1304 | dest: (struct ipv6_opt_hdr **)&opt2->srcrt, |
1305 | old: (opt ? (struct ipv6_opt_hdr *)opt->srcrt : NULL), |
1306 | new: newopt, newtype, p: &p); |
1307 | ipv6_renew_option(IPV6_DSTOPTS, dest: &opt2->dst1opt, |
1308 | old: (opt ? opt->dst1opt : NULL), |
1309 | new: newopt, newtype, p: &p); |
1310 | |
1311 | opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) + |
1312 | (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) + |
1313 | (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0); |
1314 | opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0); |
1315 | |
1316 | return opt2; |
1317 | } |
1318 | |
1319 | struct ipv6_txoptions *__ipv6_fixup_options(struct ipv6_txoptions *opt_space, |
1320 | struct ipv6_txoptions *opt) |
1321 | { |
1322 | /* |
1323 | * ignore the dest before srcrt unless srcrt is being included. |
1324 | * --yoshfuji |
1325 | */ |
1326 | if (opt->dst0opt && !opt->srcrt) { |
1327 | if (opt_space != opt) { |
1328 | memcpy(opt_space, opt, sizeof(*opt_space)); |
1329 | opt = opt_space; |
1330 | } |
1331 | opt->opt_nflen -= ipv6_optlen(opt->dst0opt); |
1332 | opt->dst0opt = NULL; |
1333 | } |
1334 | |
1335 | return opt; |
1336 | } |
1337 | EXPORT_SYMBOL_GPL(__ipv6_fixup_options); |
1338 | |
1339 | /** |
1340 | * fl6_update_dst - update flowi destination address with info given |
1341 | * by srcrt option, if any. |
1342 | * |
1343 | * @fl6: flowi6 for which daddr is to be updated |
1344 | * @opt: struct ipv6_txoptions in which to look for srcrt opt |
1345 | * @orig: copy of original daddr address if modified |
1346 | * |
1347 | * Returns NULL if no txoptions or no srcrt, otherwise returns orig |
1348 | * and initial value of fl6->daddr set in orig |
1349 | */ |
1350 | struct in6_addr *fl6_update_dst(struct flowi6 *fl6, |
1351 | const struct ipv6_txoptions *opt, |
1352 | struct in6_addr *orig) |
1353 | { |
1354 | if (!opt || !opt->srcrt) |
1355 | return NULL; |
1356 | |
1357 | *orig = fl6->daddr; |
1358 | |
1359 | switch (opt->srcrt->type) { |
1360 | case IPV6_SRCRT_TYPE_0: |
1361 | case IPV6_SRCRT_STRICT: |
1362 | case IPV6_SRCRT_TYPE_2: |
1363 | fl6->daddr = *((struct rt0_hdr *)opt->srcrt)->addr; |
1364 | break; |
1365 | case IPV6_SRCRT_TYPE_4: |
1366 | { |
1367 | struct ipv6_sr_hdr *srh = (struct ipv6_sr_hdr *)opt->srcrt; |
1368 | |
1369 | fl6->daddr = srh->segments[srh->segments_left]; |
1370 | break; |
1371 | } |
1372 | default: |
1373 | return NULL; |
1374 | } |
1375 | |
1376 | return orig; |
1377 | } |
1378 | EXPORT_SYMBOL_GPL(fl6_update_dst); |
1379 | |