~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv6/exthdrs.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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(&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, optoff,
 95                                          SKB_DROP_REASON_UNHANDLED_PROTO);
 96                 return false;
 97         }
 98 
 99 drop:
100         kfree_skb_reason(skb, 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, off))
176                                                 return false;
177                                         break;
178                                 case IPV6_TLV_IOAM:
179                                         if (!ipv6_hop_ioam(skb, off))
180                                                 return false;
181 
182                                         nh = skb_network_header(skb);
183                                         break;
184                                 case IPV6_TLV_JUMBO:
185                                         if (!ipv6_hop_jumbo(skb, off))
186                                                 return false;
187                                         break;
188                                 case IPV6_TLV_CALIPSO:
189                                         if (!ipv6_hop_calipso(skb, off))
190                                                 return false;
191                                         break;
192                                 default:
193                                         if (!ip6_tlvopt_unknown(skb, 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, off))
203                                                 return false;
204                                         break;
205 #endif
206                                 default:
207                                         if (!ip6_tlvopt_unknown(skb, 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, 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(&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, (xfrm_address_t *)&ipv6h->daddr,
263                                (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, 0, 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(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(skb->dev);
304         int extlen;
305 
306         if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
307             !pskb_may_pull(skb, (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(false, skb, 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, (__be32 *)(&ipv6_hdr(skb)->daddr),
366                            (__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(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(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, skb_network_header(skb),
403                                            skb_network_header_len(skb));
404                         skb_pull(skb, offset);
405                         skb_postpull_rcsum(skb, skb_transport_header(skb),
406                                            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, 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                                   ((&hdr->segments_left) -
431                                    skb_network_header(skb)));
432                 return -1;
433         }
434 
435         if (skb_cloned(skb)) {
436                 if (pskb_expand_head(skb, 0, 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, 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, 0);
468                         kfree_skb(skb);
469                         return -1;
470                 }
471                 ipv6_hdr(skb)->hop_limit--;
472 
473                 skb_pull(skb, 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(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(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, skb_network_header(skb),
514                                            skb_network_header_len(skb));
515                         skb_pull(skb, offset);
516                         skb_postpull_rcsum(skb, skb_transport_header(skb),
517                                            offset);
518 
519                         skb_reset_network_header(skb);
520                         skb_reset_transport_header(skb);
521                         skb->encapsulation = 0;
522 
523                         __skb_tunnel_rx(skb, 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                                   ((&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), 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(ohdr, hdr, &ipv6_hdr(skb)->daddr, n);
567         chdr = (struct ipv6_rpl_sr_hdr *)(buf + ((ohdr->hdrlen + 1) << 3));
568 
569         if (ipv6_addr_is_multicast(&ohdr->rpl_segaddr[i])) {
570                 kfree_skb(skb);
571                 kfree(buf);
572                 return -1;
573         }
574 
575         err = ipv6_chk_rpl_srh_loop(net, ohdr->rpl_segaddr, n + 1);
576         if (err) {
577                 icmpv6_send(skb, ICMPV6_PARAMPROB, 0, 0);
578                 kfree_skb(skb);
579                 kfree(buf);
580                 return -1;
581         }
582 
583         swap(ipv6_hdr(skb)->daddr, ohdr->rpl_segaddr[i]);
584 
585         ipv6_rpl_srh_compress(chdr, ohdr, &ipv6_hdr(skb)->daddr, n);
586 
587         oldhdr = ipv6_hdr(skb);
588 
589         skb_pull(skb, ((hdr->hdrlen + 1) << 3));
590         skb_postpull_rcsum(skb, oldhdr,
591                            sizeof(struct ipv6hdr) + ((hdr->hdrlen + 1) << 3));
592         if (unlikely(!hdr->segments_left)) {
593                 if (pskb_expand_head(skb, sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3), 0,
594                                      GFP_ATOMIC)) {
595                         __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS);
596                         kfree_skb(skb);
597                         kfree(buf);
598                         return -1;
599                 }
600 
601                 oldhdr = ipv6_hdr(skb);
602         }
603         skb_push(skb, ((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, 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, ipv6_hdr(skb),
613                            sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3));
614 
615         kfree(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, 0);
629                         kfree_skb(skb);
630                         return -1;
631                 }
632                 ipv6_hdr(skb)->hop_limit--;
633 
634                 skb_pull(skb, 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(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(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, skb_transport_offset(skb) + 8) ||
666             !pskb_may_pull(skb, (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(&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                                   ((&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, 0, 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, (xfrm_address_t *)addr,
780                                      (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(dev_net(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, -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                                     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, -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                           (&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(&rthdr_protocol, IPPROTO_ROUTING);
855         if (ret)
856                 goto out;
857 
858         ret = inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
859         if (ret)
860                 goto out_rthdr;
861 
862         ret = inet6_add_protocol(&nodata_protocol, IPPROTO_NONE);
863         if (ret)
864                 goto out_destopt;
865 
866 out:
867         return ret;
868 out_destopt:
869         inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
870 out_rthdr:
871         inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
872         goto out;
873 };
874 
875 void ipv6_exthdrs_exit(void)
876 {
877         inet6_del_protocol(&nodata_protocol, IPPROTO_NONE);
878         inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
879         inet6_del_protocol(&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, 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(dev_net(skb->dev), 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, 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, true);
952 
953                 ioam6_event(IOAM6_EVENT_TRACE, dev_net(skb->dev),
954                             GFP_ATOMIC, (void *)trace, 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, 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, optoff + 2,
986                                          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, optoff,
991                                          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, 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, nh + optoff))
1024                 goto drop;
1025 
1026         return true;
1027 
1028 drop:
1029         kfree_skb_reason(skb, 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(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, sizeof(struct ipv6hdr) + 8) ||
1046             !pskb_may_pull(skb, (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(true, skb, 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, (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, 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(skb->dev);
1137                 else if (skb->sk)
1138                         net = sock_net(skb->sk);
1139 
1140                 WARN_ON(!net);
1141 
1142                 if (net)
1143                         seg6_push_hmac(net, saddr, 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->srcrt, 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->dst0opt);
1190         }
1191         if (opt->hopopt)
1192                 ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, 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->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, 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(&opt2->refcnt, 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, tot_len, GFP_ATOMIC);
1289         if (!opt2)
1290                 return ERR_PTR(-ENOBUFS);
1291 
1292         memset(opt2, 0, tot_len);
1293         refcount_set(&opt2->refcnt, 1);
1294         opt2->tot_len = tot_len;
1295         p = (char *)(opt2 + 1);
1296 
1297         ipv6_renew_option(IPV6_HOPOPTS, &opt2->hopopt,
1298                           (opt ? opt->hopopt : NULL),
1299                           newopt, newtype, &p);
1300         ipv6_renew_option(IPV6_RTHDRDSTOPTS, &opt2->dst0opt,
1301                           (opt ? opt->dst0opt : NULL),
1302                           newopt, newtype, &p);
1303         ipv6_renew_option(IPV6_RTHDR,
1304                           (struct ipv6_opt_hdr **)&opt2->srcrt,
1305                           (opt ? (struct ipv6_opt_hdr *)opt->srcrt : NULL),
1306                           newopt, newtype, &p);
1307         ipv6_renew_option(IPV6_DSTOPTS, &opt2->dst1opt,
1308                           (opt ? opt->dst1opt : NULL),
1309                           newopt, newtype, &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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php