forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-09 95099d4622f8cb224d94e314c7a8e0df60b13f87
kernel/net/ipv6/exthdrs.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Extension Header handling for IPv6
34 * Linux INET6 implementation
....@@ -6,11 +7,6 @@
67 * Pedro Roque <roque@di.fc.ul.pt>
78 * Andi Kleen <ak@muc.de>
89 * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
9
- *
10
- * This program is free software; you can redistribute it and/or
11
- * modify it under the terms of the GNU General Public License
12
- * as published by the Free Software Foundation; either version
13
- * 2 of the License, or (at your option) any later version.
1410 */
1511
1612 /* Changes:
....@@ -52,6 +48,7 @@
5248 #ifdef CONFIG_IPV6_SEG6_HMAC
5349 #include <net/seg6_hmac.h>
5450 #endif
51
+#include <net/rpl.h>
5552
5653 #include <linux/uaccess.h>
5754
....@@ -101,7 +98,7 @@
10198 */
10299 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr))
103100 break;
104
- /* fall through */
101
+ fallthrough;
105102 case 2: /* send ICMP PARM PROB regardless and drop packet */
106103 icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
107104 return false;
....@@ -471,6 +468,195 @@
471468 return -1;
472469 }
473470
471
+static int ipv6_rpl_srh_rcv(struct sk_buff *skb)
472
+{
473
+ struct ipv6_rpl_sr_hdr *hdr, *ohdr, *chdr;
474
+ struct inet6_skb_parm *opt = IP6CB(skb);
475
+ struct net *net = dev_net(skb->dev);
476
+ struct inet6_dev *idev;
477
+ struct ipv6hdr *oldhdr;
478
+ struct in6_addr addr;
479
+ unsigned char *buf;
480
+ int accept_rpl_seg;
481
+ int i, err;
482
+ u64 n = 0;
483
+ u32 r;
484
+
485
+ idev = __in6_dev_get(skb->dev);
486
+
487
+ accept_rpl_seg = net->ipv6.devconf_all->rpl_seg_enabled;
488
+ if (accept_rpl_seg > idev->cnf.rpl_seg_enabled)
489
+ accept_rpl_seg = idev->cnf.rpl_seg_enabled;
490
+
491
+ if (!accept_rpl_seg) {
492
+ kfree_skb(skb);
493
+ return -1;
494
+ }
495
+
496
+looped_back:
497
+ hdr = (struct ipv6_rpl_sr_hdr *)skb_transport_header(skb);
498
+
499
+ if (hdr->segments_left == 0) {
500
+ if (hdr->nexthdr == NEXTHDR_IPV6) {
501
+ int offset = (hdr->hdrlen + 1) << 3;
502
+
503
+ skb_postpull_rcsum(skb, skb_network_header(skb),
504
+ skb_network_header_len(skb));
505
+
506
+ if (!pskb_pull(skb, offset)) {
507
+ kfree_skb(skb);
508
+ return -1;
509
+ }
510
+ skb_postpull_rcsum(skb, skb_transport_header(skb),
511
+ offset);
512
+
513
+ skb_reset_network_header(skb);
514
+ skb_reset_transport_header(skb);
515
+ skb->encapsulation = 0;
516
+
517
+ __skb_tunnel_rx(skb, skb->dev, net);
518
+
519
+ netif_rx(skb);
520
+ return -1;
521
+ }
522
+
523
+ opt->srcrt = skb_network_header_len(skb);
524
+ opt->lastopt = opt->srcrt;
525
+ skb->transport_header += (hdr->hdrlen + 1) << 3;
526
+ opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb);
527
+
528
+ return 1;
529
+ }
530
+
531
+ if (!pskb_may_pull(skb, sizeof(*hdr))) {
532
+ kfree_skb(skb);
533
+ return -1;
534
+ }
535
+
536
+ n = (hdr->hdrlen << 3) - hdr->pad - (16 - hdr->cmpre);
537
+ r = do_div(n, (16 - hdr->cmpri));
538
+ /* checks if calculation was without remainder and n fits into
539
+ * unsigned char which is segments_left field. Should not be
540
+ * higher than that.
541
+ */
542
+ if (r || (n + 1) > 255) {
543
+ kfree_skb(skb);
544
+ return -1;
545
+ }
546
+
547
+ if (hdr->segments_left > n + 1) {
548
+ __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
549
+ icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
550
+ ((&hdr->segments_left) -
551
+ skb_network_header(skb)));
552
+ return -1;
553
+ }
554
+
555
+ if (skb_cloned(skb)) {
556
+ if (pskb_expand_head(skb, IPV6_RPL_SRH_WORST_SWAP_SIZE, 0,
557
+ GFP_ATOMIC)) {
558
+ __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
559
+ IPSTATS_MIB_OUTDISCARDS);
560
+ kfree_skb(skb);
561
+ return -1;
562
+ }
563
+ } else {
564
+ err = skb_cow_head(skb, IPV6_RPL_SRH_WORST_SWAP_SIZE);
565
+ if (unlikely(err)) {
566
+ kfree_skb(skb);
567
+ return -1;
568
+ }
569
+ }
570
+
571
+ hdr = (struct ipv6_rpl_sr_hdr *)skb_transport_header(skb);
572
+
573
+ if (!pskb_may_pull(skb, ipv6_rpl_srh_size(n, hdr->cmpri,
574
+ hdr->cmpre))) {
575
+ kfree_skb(skb);
576
+ return -1;
577
+ }
578
+
579
+ hdr->segments_left--;
580
+ i = n - hdr->segments_left;
581
+
582
+ buf = kcalloc(struct_size(hdr, segments.addr, n + 2), 2, GFP_ATOMIC);
583
+ if (unlikely(!buf)) {
584
+ kfree_skb(skb);
585
+ return -1;
586
+ }
587
+
588
+ ohdr = (struct ipv6_rpl_sr_hdr *)buf;
589
+ ipv6_rpl_srh_decompress(ohdr, hdr, &ipv6_hdr(skb)->daddr, n);
590
+ chdr = (struct ipv6_rpl_sr_hdr *)(buf + ((ohdr->hdrlen + 1) << 3));
591
+
592
+ if ((ipv6_addr_type(&ipv6_hdr(skb)->daddr) & IPV6_ADDR_MULTICAST) ||
593
+ (ipv6_addr_type(&ohdr->rpl_segaddr[i]) & IPV6_ADDR_MULTICAST)) {
594
+ kfree_skb(skb);
595
+ kfree(buf);
596
+ return -1;
597
+ }
598
+
599
+ err = ipv6_chk_rpl_srh_loop(net, ohdr->rpl_segaddr, n + 1);
600
+ if (err) {
601
+ icmpv6_send(skb, ICMPV6_PARAMPROB, 0, 0);
602
+ kfree_skb(skb);
603
+ kfree(buf);
604
+ return -1;
605
+ }
606
+
607
+ addr = ipv6_hdr(skb)->daddr;
608
+ ipv6_hdr(skb)->daddr = ohdr->rpl_segaddr[i];
609
+ ohdr->rpl_segaddr[i] = addr;
610
+
611
+ ipv6_rpl_srh_compress(chdr, ohdr, &ipv6_hdr(skb)->daddr, n);
612
+
613
+ oldhdr = ipv6_hdr(skb);
614
+
615
+ skb_pull(skb, ((hdr->hdrlen + 1) << 3));
616
+ skb_postpull_rcsum(skb, oldhdr,
617
+ sizeof(struct ipv6hdr) + ((hdr->hdrlen + 1) << 3));
618
+ skb_push(skb, ((chdr->hdrlen + 1) << 3) + sizeof(struct ipv6hdr));
619
+ skb_reset_network_header(skb);
620
+ skb_mac_header_rebuild(skb);
621
+ skb_set_transport_header(skb, sizeof(struct ipv6hdr));
622
+
623
+ memmove(ipv6_hdr(skb), oldhdr, sizeof(struct ipv6hdr));
624
+ memcpy(skb_transport_header(skb), chdr, (chdr->hdrlen + 1) << 3);
625
+
626
+ ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
627
+ skb_postpush_rcsum(skb, ipv6_hdr(skb),
628
+ sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3));
629
+
630
+ kfree(buf);
631
+
632
+ skb_dst_drop(skb);
633
+
634
+ ip6_route_input(skb);
635
+
636
+ if (skb_dst(skb)->error) {
637
+ dst_input(skb);
638
+ return -1;
639
+ }
640
+
641
+ if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) {
642
+ if (ipv6_hdr(skb)->hop_limit <= 1) {
643
+ __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
644
+ icmpv6_send(skb, ICMPV6_TIME_EXCEED,
645
+ ICMPV6_EXC_HOPLIMIT, 0);
646
+ kfree_skb(skb);
647
+ return -1;
648
+ }
649
+ ipv6_hdr(skb)->hop_limit--;
650
+
651
+ skb_pull(skb, sizeof(struct ipv6hdr));
652
+ goto looped_back;
653
+ }
654
+
655
+ dst_input(skb);
656
+
657
+ return -1;
658
+}
659
+
474660 /********************************
475661 Routing header.
476662 ********************************/
....@@ -509,9 +695,16 @@
509695 return -1;
510696 }
511697
512
- /* segment routing */
513
- if (hdr->type == IPV6_SRCRT_TYPE_4)
698
+ switch (hdr->type) {
699
+ case IPV6_SRCRT_TYPE_4:
700
+ /* segment routing */
514701 return ipv6_srh_rcv(skb);
702
+ case IPV6_SRCRT_TYPE_3:
703
+ /* rpl segment routing */
704
+ return ipv6_rpl_srh_rcv(skb);
705
+ default:
706
+ break;
707
+ }
515708
516709 looped_back:
517710 if (hdr->segments_left == 0) {
....@@ -1038,7 +1231,6 @@
10381231 * @opt: original options
10391232 * @newtype: option type to replace in @opt
10401233 * @newopt: new option of type @newtype to replace (user-mem)
1041
- * @newoptlen: length of @newopt
10421234 *
10431235 * Returns a new set of options which is a copy of @opt with the
10441236 * option type @newtype replaced with @newopt.