LCOV - code coverage report
Current view: top level - net/ipv6 - exthdrs.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_qemu_modules_combined.info Lines: 13 324 4.0 %
Date: 2020-09-30 20:25:01 Functions: 3 23 13.0 %
Branches: 5 227 2.2 %

           Branch data     Line data    Source code
       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                 :            : 
      52                 :            : #include <linux/uaccess.h>
      53                 :            : 
      54                 :            : /*
      55                 :            :  *      Parsing tlv encoded headers.
      56                 :            :  *
      57                 :            :  *      Parsing function "func" returns true, if parsing succeed
      58                 :            :  *      and false, if it failed.
      59                 :            :  *      It MUST NOT touch skb->h.
      60                 :            :  */
      61                 :            : 
      62                 :            : struct tlvtype_proc {
      63                 :            :         int     type;
      64                 :            :         bool    (*func)(struct sk_buff *skb, int offset);
      65                 :            : };
      66                 :            : 
      67                 :            : /*********************
      68                 :            :   Generic functions
      69                 :            :  *********************/
      70                 :            : 
      71                 :            : /* An unknown option is detected, decide what to do */
      72                 :            : 
      73                 :          0 : static bool ip6_tlvopt_unknown(struct sk_buff *skb, int optoff,
      74                 :            :                                bool disallow_unknowns)
      75                 :            : {
      76         [ #  # ]:          0 :         if (disallow_unknowns) {
      77                 :            :                 /* If unknown TLVs are disallowed by configuration
      78                 :            :                  * then always silently drop packet. Note this also
      79                 :            :                  * means no ICMP parameter problem is sent which
      80                 :            :                  * could be a good property to mitigate a reflection DOS
      81                 :            :                  * attack.
      82                 :            :                  */
      83                 :            : 
      84                 :            :                 goto drop;
      85                 :            :         }
      86                 :            : 
      87   [ #  #  #  # ]:          0 :         switch ((skb_network_header(skb)[optoff] & 0xC0) >> 6) {
      88                 :            :         case 0: /* ignore */
      89                 :            :                 return true;
      90                 :            : 
      91                 :            :         case 1: /* drop packet */
      92                 :            :                 break;
      93                 :            : 
      94                 :            :         case 3: /* Send ICMP if not a multicast address and drop packet */
      95                 :            :                 /* Actually, it is redundant check. icmp_send
      96                 :            :                    will recheck in any case.
      97                 :            :                  */
      98         [ #  # ]:          0 :                 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr))
      99                 :            :                         break;
     100                 :            :                 /* fall through */
     101                 :            :         case 2: /* send ICMP PARM PROB regardless and drop packet */
     102                 :          0 :                 icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
     103                 :          0 :                 return false;
     104                 :            :         }
     105                 :            : 
     106                 :            : drop:
     107                 :          0 :         kfree_skb(skb);
     108                 :          0 :         return false;
     109                 :            : }
     110                 :            : 
     111                 :            : /* Parse tlv encoded option header (hop-by-hop or destination) */
     112                 :            : 
     113                 :          0 : static bool ip6_parse_tlv(const struct tlvtype_proc *procs,
     114                 :            :                           struct sk_buff *skb,
     115                 :            :                           int max_count)
     116                 :            : {
     117                 :          0 :         int len = (skb_transport_header(skb)[1] + 1) << 3;
     118                 :            :         const unsigned char *nh = skb_network_header(skb);
     119                 :            :         int off = skb_network_header_len(skb);
     120                 :            :         const struct tlvtype_proc *curr;
     121                 :            :         bool disallow_unknowns = false;
     122                 :            :         int tlv_count = 0;
     123                 :            :         int padlen = 0;
     124                 :            : 
     125         [ #  # ]:          0 :         if (unlikely(max_count < 0)) {
     126                 :            :                 disallow_unknowns = true;
     127                 :          0 :                 max_count = -max_count;
     128                 :            :         }
     129                 :            : 
     130         [ #  # ]:          0 :         if (skb_transport_offset(skb) + len > skb_headlen(skb))
     131                 :            :                 goto bad;
     132                 :            : 
     133                 :          0 :         off += 2;
     134                 :          0 :         len -= 2;
     135                 :            : 
     136         [ #  # ]:          0 :         while (len > 0) {
     137                 :          0 :                 int optlen = nh[off + 1] + 2;
     138                 :            :                 int i;
     139                 :            : 
     140      [ #  #  # ]:          0 :                 switch (nh[off]) {
     141                 :            :                 case IPV6_TLV_PAD1:
     142                 :            :                         optlen = 1;
     143                 :          0 :                         padlen++;
     144         [ #  # ]:          0 :                         if (padlen > 7)
     145                 :            :                                 goto bad;
     146                 :            :                         break;
     147                 :            : 
     148                 :            :                 case IPV6_TLV_PADN:
     149                 :            :                         /* RFC 2460 states that the purpose of PadN is
     150                 :            :                          * to align the containing header to multiples
     151                 :            :                          * of 8. 7 is therefore the highest valid value.
     152                 :            :                          * See also RFC 4942, Section 2.1.9.5.
     153                 :            :                          */
     154                 :          0 :                         padlen += optlen;
     155         [ #  # ]:          0 :                         if (padlen > 7)
     156                 :            :                                 goto bad;
     157                 :            :                         /* RFC 4942 recommends receiving hosts to
     158                 :            :                          * actively check PadN payload to contain
     159                 :            :                          * only zeroes.
     160                 :            :                          */
     161         [ #  # ]:          0 :                         for (i = 2; i < optlen; i++) {
     162         [ #  # ]:          0 :                                 if (nh[off + i] != 0)
     163                 :            :                                         goto bad;
     164                 :            :                         }
     165                 :            :                         break;
     166                 :            : 
     167                 :            :                 default: /* Other TLV code so scan list */
     168         [ #  # ]:          0 :                         if (optlen > len)
     169                 :            :                                 goto bad;
     170                 :            : 
     171                 :          0 :                         tlv_count++;
     172         [ #  # ]:          0 :                         if (tlv_count > max_count)
     173                 :            :                                 goto bad;
     174                 :            : 
     175         [ #  # ]:          0 :                         for (curr = procs; curr->type >= 0; curr++) {
     176         [ #  # ]:          0 :                                 if (curr->type == nh[off]) {
     177                 :            :                                         /* type specific length/alignment
     178                 :            :                                            checks will be performed in the
     179                 :            :                                            func(). */
     180         [ #  # ]:          0 :                                         if (curr->func(skb, off) == false)
     181                 :            :                                                 return false;
     182                 :            :                                         break;
     183                 :            :                                 }
     184                 :            :                         }
     185   [ #  #  #  # ]:          0 :                         if (curr->type < 0 &&
     186                 :          0 :                             !ip6_tlvopt_unknown(skb, off, disallow_unknowns))
     187                 :            :                                 return false;
     188                 :            : 
     189                 :            :                         padlen = 0;
     190                 :            :                         break;
     191                 :            :                 }
     192                 :          0 :                 off += optlen;
     193                 :          0 :                 len -= optlen;
     194                 :            :         }
     195                 :            : 
     196         [ #  # ]:          0 :         if (len == 0)
     197                 :            :                 return true;
     198                 :            : bad:
     199                 :          0 :         kfree_skb(skb);
     200                 :          0 :         return false;
     201                 :            : }
     202                 :            : 
     203                 :            : /*****************************
     204                 :            :   Destination options header.
     205                 :            :  *****************************/
     206                 :            : 
     207                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     208                 :            : static bool ipv6_dest_hao(struct sk_buff *skb, int optoff)
     209                 :            : {
     210                 :            :         struct ipv6_destopt_hao *hao;
     211                 :            :         struct inet6_skb_parm *opt = IP6CB(skb);
     212                 :            :         struct ipv6hdr *ipv6h = ipv6_hdr(skb);
     213                 :            :         int ret;
     214                 :            : 
     215                 :            :         if (opt->dsthao) {
     216                 :            :                 net_dbg_ratelimited("hao duplicated\n");
     217                 :            :                 goto discard;
     218                 :            :         }
     219                 :            :         opt->dsthao = opt->dst1;
     220                 :            :         opt->dst1 = 0;
     221                 :            : 
     222                 :            :         hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) + optoff);
     223                 :            : 
     224                 :            :         if (hao->length != 16) {
     225                 :            :                 net_dbg_ratelimited("hao invalid option length = %d\n",
     226                 :            :                                     hao->length);
     227                 :            :                 goto discard;
     228                 :            :         }
     229                 :            : 
     230                 :            :         if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
     231                 :            :                 net_dbg_ratelimited("hao is not an unicast addr: %pI6\n",
     232                 :            :                                     &hao->addr);
     233                 :            :                 goto discard;
     234                 :            :         }
     235                 :            : 
     236                 :            :         ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr,
     237                 :            :                                (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS);
     238                 :            :         if (unlikely(ret < 0))
     239                 :            :                 goto discard;
     240                 :            : 
     241                 :            :         if (skb_cloned(skb)) {
     242                 :            :                 if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
     243                 :            :                         goto discard;
     244                 :            : 
     245                 :            :                 /* update all variable using below by copied skbuff */
     246                 :            :                 hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) +
     247                 :            :                                                   optoff);
     248                 :            :                 ipv6h = ipv6_hdr(skb);
     249                 :            :         }
     250                 :            : 
     251                 :            :         if (skb->ip_summed == CHECKSUM_COMPLETE)
     252                 :            :                 skb->ip_summed = CHECKSUM_NONE;
     253                 :            : 
     254                 :            :         swap(ipv6h->saddr, hao->addr);
     255                 :            : 
     256                 :            :         if (skb->tstamp == 0)
     257                 :            :                 __net_timestamp(skb);
     258                 :            : 
     259                 :            :         return true;
     260                 :            : 
     261                 :            :  discard:
     262                 :            :         kfree_skb(skb);
     263                 :            :         return false;
     264                 :            : }
     265                 :            : #endif
     266                 :            : 
     267                 :            : static const struct tlvtype_proc tlvprocdestopt_lst[] = {
     268                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     269                 :            :         {
     270                 :            :                 .type   = IPV6_TLV_HAO,
     271                 :            :                 .func   = ipv6_dest_hao,
     272                 :            :         },
     273                 :            : #endif
     274                 :            :         {-1,                    NULL}
     275                 :            : };
     276                 :            : 
     277                 :          0 : static int ipv6_destopt_rcv(struct sk_buff *skb)
     278                 :            : {
     279                 :          0 :         struct inet6_dev *idev = __in6_dev_get(skb->dev);
     280                 :            :         struct inet6_skb_parm *opt = IP6CB(skb);
     281                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     282                 :            :         __u16 dstbuf;
     283                 :            : #endif
     284                 :            :         struct dst_entry *dst = skb_dst(skb);
     285                 :            :         struct net *net = dev_net(skb->dev);
     286                 :            :         int extlen;
     287                 :            : 
     288   [ #  #  #  # ]:          0 :         if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
     289                 :          0 :             !pskb_may_pull(skb, (skb_transport_offset(skb) +
     290                 :          0 :                                  ((skb_transport_header(skb)[1] + 1) << 3)))) {
     291         [ #  # ]:          0 :                 __IP6_INC_STATS(dev_net(dst->dev), idev,
     292                 :            :                                 IPSTATS_MIB_INHDRERRORS);
     293                 :            : fail_and_free:
     294                 :          0 :                 kfree_skb(skb);
     295                 :          0 :                 return -1;
     296                 :            :         }
     297                 :            : 
     298                 :          0 :         extlen = (skb_transport_header(skb)[1] + 1) << 3;
     299         [ #  # ]:          0 :         if (extlen > net->ipv6.sysctl.max_dst_opts_len)
     300                 :            :                 goto fail_and_free;
     301                 :            : 
     302                 :          0 :         opt->lastopt = opt->dst1 = skb_network_header_len(skb);
     303                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     304                 :            :         dstbuf = opt->dst1;
     305                 :            : #endif
     306                 :            : 
     307         [ #  # ]:          0 :         if (ip6_parse_tlv(tlvprocdestopt_lst, skb,
     308                 :            :                           init_net.ipv6.sysctl.max_dst_opts_cnt)) {
     309                 :          0 :                 skb->transport_header += extlen;
     310                 :            :                 opt = IP6CB(skb);
     311                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     312                 :            :                 opt->nhoff = dstbuf;
     313                 :            : #else
     314                 :          0 :                 opt->nhoff = opt->dst1;
     315                 :            : #endif
     316                 :          0 :                 return 1;
     317                 :            :         }
     318                 :            : 
     319         [ #  # ]:          0 :         __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
     320                 :          0 :         return -1;
     321                 :            : }
     322                 :            : 
     323                 :          0 : static void seg6_update_csum(struct sk_buff *skb)
     324                 :            : {
     325                 :            :         struct ipv6_sr_hdr *hdr;
     326                 :            :         struct in6_addr *addr;
     327                 :            :         __be32 from, to;
     328                 :            : 
     329                 :            :         /* srh is at transport offset and seg_left is already decremented
     330                 :            :          * but daddr is not yet updated with next segment
     331                 :            :          */
     332                 :            : 
     333                 :            :         hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
     334                 :          0 :         addr = hdr->segments + hdr->segments_left;
     335                 :            : 
     336                 :          0 :         hdr->segments_left++;
     337                 :          0 :         from = *(__be32 *)hdr;
     338                 :            : 
     339                 :          0 :         hdr->segments_left--;
     340                 :          0 :         to = *(__be32 *)hdr;
     341                 :            : 
     342                 :            :         /* update skb csum with diff resulting from seg_left decrement */
     343                 :            : 
     344                 :          0 :         update_csum_diff4(skb, from, to);
     345                 :            : 
     346                 :            :         /* compute csum diff between current and next segment and update */
     347                 :            : 
     348                 :          0 :         update_csum_diff16(skb, (__be32 *)(&ipv6_hdr(skb)->daddr),
     349                 :            :                            (__be32 *)addr);
     350                 :          0 : }
     351                 :            : 
     352                 :          0 : static int ipv6_srh_rcv(struct sk_buff *skb)
     353                 :            : {
     354                 :            :         struct inet6_skb_parm *opt = IP6CB(skb);
     355                 :          0 :         struct net *net = dev_net(skb->dev);
     356                 :            :         struct ipv6_sr_hdr *hdr;
     357                 :            :         struct inet6_dev *idev;
     358                 :            :         struct in6_addr *addr;
     359                 :            :         int accept_seg6;
     360                 :            : 
     361                 :            :         hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
     362                 :            : 
     363                 :            :         idev = __in6_dev_get(skb->dev);
     364                 :            : 
     365                 :          0 :         accept_seg6 = net->ipv6.devconf_all->seg6_enabled;
     366         [ #  # ]:          0 :         if (accept_seg6 > idev->cnf.seg6_enabled)
     367                 :            :                 accept_seg6 = idev->cnf.seg6_enabled;
     368                 :            : 
     369         [ #  # ]:          0 :         if (!accept_seg6) {
     370                 :          0 :                 kfree_skb(skb);
     371                 :          0 :                 return -1;
     372                 :            :         }
     373                 :            : 
     374                 :            : #ifdef CONFIG_IPV6_SEG6_HMAC
     375                 :            :         if (!seg6_hmac_validate_skb(skb)) {
     376                 :            :                 kfree_skb(skb);
     377                 :            :                 return -1;
     378                 :            :         }
     379                 :            : #endif
     380                 :            : 
     381                 :            : looped_back:
     382         [ #  # ]:          0 :         if (hdr->segments_left == 0) {
     383         [ #  # ]:          0 :                 if (hdr->nexthdr == NEXTHDR_IPV6) {
     384                 :          0 :                         int offset = (hdr->hdrlen + 1) << 3;
     385                 :            : 
     386                 :          0 :                         skb_postpull_rcsum(skb, skb_network_header(skb),
     387                 :            :                                            skb_network_header_len(skb));
     388                 :            : 
     389         [ #  # ]:          0 :                         if (!pskb_pull(skb, offset)) {
     390                 :          0 :                                 kfree_skb(skb);
     391                 :          0 :                                 return -1;
     392                 :            :                         }
     393                 :          0 :                         skb_postpull_rcsum(skb, skb_transport_header(skb),
     394                 :            :                                            offset);
     395                 :            : 
     396                 :            :                         skb_reset_network_header(skb);
     397                 :            :                         skb_reset_transport_header(skb);
     398                 :          0 :                         skb->encapsulation = 0;
     399                 :            : 
     400                 :          0 :                         __skb_tunnel_rx(skb, skb->dev, net);
     401                 :            : 
     402                 :          0 :                         netif_rx(skb);
     403                 :          0 :                         return -1;
     404                 :            :                 }
     405                 :            : 
     406                 :          0 :                 opt->srcrt = skb_network_header_len(skb);
     407                 :          0 :                 opt->lastopt = opt->srcrt;
     408                 :          0 :                 skb->transport_header += (hdr->hdrlen + 1) << 3;
     409                 :          0 :                 opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb);
     410                 :            : 
     411                 :          0 :                 return 1;
     412                 :            :         }
     413                 :            : 
     414         [ #  # ]:          0 :         if (hdr->segments_left >= (hdr->hdrlen >> 1)) {
     415         [ #  # ]:          0 :                 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
     416                 :          0 :                 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
     417                 :          0 :                                   ((&hdr->segments_left) -
     418                 :            :                                    skb_network_header(skb)));
     419                 :          0 :                 return -1;
     420                 :            :         }
     421                 :            : 
     422         [ #  # ]:          0 :         if (skb_cloned(skb)) {
     423         [ #  # ]:          0 :                 if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
     424         [ #  # ]:          0 :                         __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
     425                 :            :                                         IPSTATS_MIB_OUTDISCARDS);
     426                 :          0 :                         kfree_skb(skb);
     427                 :          0 :                         return -1;
     428                 :            :                 }
     429                 :            :         }
     430                 :            : 
     431                 :            :         hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
     432                 :            : 
     433                 :          0 :         hdr->segments_left--;
     434                 :          0 :         addr = hdr->segments + hdr->segments_left;
     435                 :            : 
     436                 :          0 :         skb_push(skb, sizeof(struct ipv6hdr));
     437                 :            : 
     438         [ #  # ]:          0 :         if (skb->ip_summed == CHECKSUM_COMPLETE)
     439                 :          0 :                 seg6_update_csum(skb);
     440                 :            : 
     441                 :          0 :         ipv6_hdr(skb)->daddr = *addr;
     442                 :            : 
     443                 :          0 :         skb_dst_drop(skb);
     444                 :            : 
     445                 :          0 :         ip6_route_input(skb);
     446                 :            : 
     447         [ #  # ]:          0 :         if (skb_dst(skb)->error) {
     448                 :            :                 dst_input(skb);
     449                 :          0 :                 return -1;
     450                 :            :         }
     451                 :            : 
     452         [ #  # ]:          0 :         if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) {
     453         [ #  # ]:          0 :                 if (ipv6_hdr(skb)->hop_limit <= 1) {
     454         [ #  # ]:          0 :                         __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
     455                 :          0 :                         icmpv6_send(skb, ICMPV6_TIME_EXCEED,
     456                 :            :                                     ICMPV6_EXC_HOPLIMIT, 0);
     457                 :          0 :                         kfree_skb(skb);
     458                 :          0 :                         return -1;
     459                 :            :                 }
     460                 :          0 :                 ipv6_hdr(skb)->hop_limit--;
     461                 :            : 
     462                 :          0 :                 skb_pull(skb, sizeof(struct ipv6hdr));
     463                 :          0 :                 goto looped_back;
     464                 :            :         }
     465                 :            : 
     466                 :            :         dst_input(skb);
     467                 :            : 
     468                 :          0 :         return -1;
     469                 :            : }
     470                 :            : 
     471                 :            : /********************************
     472                 :            :   Routing header.
     473                 :            :  ********************************/
     474                 :            : 
     475                 :            : /* called with rcu_read_lock() */
     476                 :          0 : static int ipv6_rthdr_rcv(struct sk_buff *skb)
     477                 :            : {
     478                 :          0 :         struct inet6_dev *idev = __in6_dev_get(skb->dev);
     479                 :            :         struct inet6_skb_parm *opt = IP6CB(skb);
     480                 :            :         struct in6_addr *addr = NULL;
     481                 :            :         struct in6_addr daddr;
     482                 :            :         int n, i;
     483                 :            :         struct ipv6_rt_hdr *hdr;
     484                 :            :         struct rt0_hdr *rthdr;
     485                 :            :         struct net *net = dev_net(skb->dev);
     486                 :            :         int accept_source_route = net->ipv6.devconf_all->accept_source_route;
     487                 :            : 
     488                 :            :         idev = __in6_dev_get(skb->dev);
     489                 :            :         if (idev && accept_source_route > idev->cnf.accept_source_route)
     490                 :            :                 accept_source_route = idev->cnf.accept_source_route;
     491                 :            : 
     492   [ #  #  #  # ]:          0 :         if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
     493                 :          0 :             !pskb_may_pull(skb, (skb_transport_offset(skb) +
     494                 :          0 :                                  ((skb_transport_header(skb)[1] + 1) << 3)))) {
     495         [ #  # ]:          0 :                 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
     496                 :          0 :                 kfree_skb(skb);
     497                 :          0 :                 return -1;
     498                 :            :         }
     499                 :            : 
     500                 :            :         hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
     501                 :            : 
     502   [ #  #  #  # ]:          0 :         if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
     503                 :          0 :             skb->pkt_type != PACKET_HOST) {
     504         [ #  # ]:          0 :                 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
     505                 :          0 :                 kfree_skb(skb);
     506                 :          0 :                 return -1;
     507                 :            :         }
     508                 :            : 
     509                 :            :         /* segment routing */
     510         [ #  # ]:          0 :         if (hdr->type == IPV6_SRCRT_TYPE_4)
     511                 :          0 :                 return ipv6_srh_rcv(skb);
     512                 :            : 
     513                 :            : looped_back:
     514         [ #  # ]:          0 :         if (hdr->segments_left == 0) {
     515                 :            :                 switch (hdr->type) {
     516                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     517                 :            :                 case IPV6_SRCRT_TYPE_2:
     518                 :            :                         /* Silently discard type 2 header unless it was
     519                 :            :                          * processed by own
     520                 :            :                          */
     521                 :            :                         if (!addr) {
     522                 :            :                                 __IP6_INC_STATS(net, idev,
     523                 :            :                                                 IPSTATS_MIB_INADDRERRORS);
     524                 :            :                                 kfree_skb(skb);
     525                 :            :                                 return -1;
     526                 :            :                         }
     527                 :            :                         break;
     528                 :            : #endif
     529                 :            :                 default:
     530                 :            :                         break;
     531                 :            :                 }
     532                 :            : 
     533                 :          0 :                 opt->lastopt = opt->srcrt = skb_network_header_len(skb);
     534                 :          0 :                 skb->transport_header += (hdr->hdrlen + 1) << 3;
     535                 :          0 :                 opt->dst0 = opt->dst1;
     536                 :          0 :                 opt->dst1 = 0;
     537                 :          0 :                 opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb);
     538                 :          0 :                 return 1;
     539                 :            :         }
     540                 :            : 
     541                 :            :         switch (hdr->type) {
     542                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     543                 :            :         case IPV6_SRCRT_TYPE_2:
     544                 :            :                 if (accept_source_route < 0)
     545                 :            :                         goto unknown_rh;
     546                 :            :                 /* Silently discard invalid RTH type 2 */
     547                 :            :                 if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
     548                 :            :                         __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
     549                 :            :                         kfree_skb(skb);
     550                 :            :                         return -1;
     551                 :            :                 }
     552                 :            :                 break;
     553                 :            : #endif
     554                 :            :         default:
     555                 :            :                 goto unknown_rh;
     556                 :            :         }
     557                 :            : 
     558                 :            :         /*
     559                 :            :          *      This is the routing header forwarding algorithm from
     560                 :            :          *      RFC 2460, page 16.
     561                 :            :          */
     562                 :            : 
     563                 :            :         n = hdr->hdrlen >> 1;
     564                 :            : 
     565                 :            :         if (hdr->segments_left > n) {
     566                 :            :                 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
     567                 :            :                 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
     568                 :            :                                   ((&hdr->segments_left) -
     569                 :            :                                    skb_network_header(skb)));
     570                 :            :                 return -1;
     571                 :            :         }
     572                 :            : 
     573                 :            :         /* We are about to mangle packet header. Be careful!
     574                 :            :            Do not damage packets queued somewhere.
     575                 :            :          */
     576                 :            :         if (skb_cloned(skb)) {
     577                 :            :                 /* the copy is a forwarded packet */
     578                 :            :                 if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
     579                 :            :                         __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
     580                 :            :                                         IPSTATS_MIB_OUTDISCARDS);
     581                 :            :                         kfree_skb(skb);
     582                 :            :                         return -1;
     583                 :            :                 }
     584                 :            :                 hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
     585                 :            :         }
     586                 :            : 
     587                 :            :         if (skb->ip_summed == CHECKSUM_COMPLETE)
     588                 :            :                 skb->ip_summed = CHECKSUM_NONE;
     589                 :            : 
     590                 :            :         i = n - --hdr->segments_left;
     591                 :            : 
     592                 :            :         rthdr = (struct rt0_hdr *) hdr;
     593                 :            :         addr = rthdr->addr;
     594                 :            :         addr += i - 1;
     595                 :            : 
     596                 :            :         switch (hdr->type) {
     597                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     598                 :            :         case IPV6_SRCRT_TYPE_2:
     599                 :            :                 if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
     600                 :            :                                      (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
     601                 :            :                                      IPPROTO_ROUTING) < 0) {
     602                 :            :                         __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
     603                 :            :                         kfree_skb(skb);
     604                 :            :                         return -1;
     605                 :            :                 }
     606                 :            :                 if (!ipv6_chk_home_addr(dev_net(skb_dst(skb)->dev), addr)) {
     607                 :            :                         __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
     608                 :            :                         kfree_skb(skb);
     609                 :            :                         return -1;
     610                 :            :                 }
     611                 :            :                 break;
     612                 :            : #endif
     613                 :            :         default:
     614                 :            :                 break;
     615                 :            :         }
     616                 :            : 
     617                 :            :         if (ipv6_addr_is_multicast(addr)) {
     618                 :            :                 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
     619                 :            :                 kfree_skb(skb);
     620                 :            :                 return -1;
     621                 :            :         }
     622                 :            : 
     623                 :            :         daddr = *addr;
     624                 :            :         *addr = ipv6_hdr(skb)->daddr;
     625                 :            :         ipv6_hdr(skb)->daddr = daddr;
     626                 :            : 
     627                 :            :         skb_dst_drop(skb);
     628                 :            :         ip6_route_input(skb);
     629                 :            :         if (skb_dst(skb)->error) {
     630                 :            :                 skb_push(skb, skb->data - skb_network_header(skb));
     631                 :            :                 dst_input(skb);
     632                 :            :                 return -1;
     633                 :            :         }
     634                 :            : 
     635                 :            :         if (skb_dst(skb)->dev->flags&IFF_LOOPBACK) {
     636                 :            :                 if (ipv6_hdr(skb)->hop_limit <= 1) {
     637                 :            :                         __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
     638                 :            :                         icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
     639                 :            :                                     0);
     640                 :            :                         kfree_skb(skb);
     641                 :            :                         return -1;
     642                 :            :                 }
     643                 :            :                 ipv6_hdr(skb)->hop_limit--;
     644                 :            :                 goto looped_back;
     645                 :            :         }
     646                 :            : 
     647                 :            :         skb_push(skb, skb->data - skb_network_header(skb));
     648                 :            :         dst_input(skb);
     649                 :            :         return -1;
     650                 :            : 
     651                 :            : unknown_rh:
     652         [ #  # ]:          0 :         __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
     653                 :          0 :         icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
     654                 :          0 :                           (&hdr->type) - skb_network_header(skb));
     655                 :          0 :         return -1;
     656                 :            : }
     657                 :            : 
     658                 :            : static const struct inet6_protocol rthdr_protocol = {
     659                 :            :         .handler        =       ipv6_rthdr_rcv,
     660                 :            :         .flags          =       INET6_PROTO_NOPOLICY,
     661                 :            : };
     662                 :            : 
     663                 :            : static const struct inet6_protocol destopt_protocol = {
     664                 :            :         .handler        =       ipv6_destopt_rcv,
     665                 :            :         .flags          =       INET6_PROTO_NOPOLICY,
     666                 :            : };
     667                 :            : 
     668                 :            : static const struct inet6_protocol nodata_protocol = {
     669                 :            :         .handler        =       dst_discard,
     670                 :            :         .flags          =       INET6_PROTO_NOPOLICY,
     671                 :            : };
     672                 :            : 
     673                 :        404 : int __init ipv6_exthdrs_init(void)
     674                 :            : {
     675                 :            :         int ret;
     676                 :            : 
     677                 :        404 :         ret = inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING);
     678         [ +  - ]:        404 :         if (ret)
     679                 :            :                 goto out;
     680                 :            : 
     681                 :        404 :         ret = inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
     682         [ +  - ]:        404 :         if (ret)
     683                 :            :                 goto out_rthdr;
     684                 :            : 
     685                 :        404 :         ret = inet6_add_protocol(&nodata_protocol, IPPROTO_NONE);
     686         [ +  - ]:        404 :         if (ret)
     687                 :            :                 goto out_destopt;
     688                 :            : 
     689                 :            : out:
     690                 :        404 :         return ret;
     691                 :            : out_destopt:
     692                 :          0 :         inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
     693                 :            : out_rthdr:
     694                 :          0 :         inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
     695                 :          0 :         goto out;
     696                 :            : };
     697                 :            : 
     698                 :          0 : void ipv6_exthdrs_exit(void)
     699                 :            : {
     700                 :          0 :         inet6_del_protocol(&nodata_protocol, IPPROTO_NONE);
     701                 :          0 :         inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
     702                 :          0 :         inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
     703                 :          0 : }
     704                 :            : 
     705                 :            : /**********************************
     706                 :            :   Hop-by-hop options.
     707                 :            :  **********************************/
     708                 :            : 
     709                 :            : /*
     710                 :            :  * Note: we cannot rely on skb_dst(skb) before we assign it in ip6_route_input().
     711                 :            :  */
     712                 :            : static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb)
     713                 :            : {
     714                 :            :         return skb_dst(skb) ? ip6_dst_idev(skb_dst(skb)) : __in6_dev_get(skb->dev);
     715                 :            : }
     716                 :            : 
     717                 :            : static inline struct net *ipv6_skb_net(struct sk_buff *skb)
     718                 :            : {
     719         [ #  # ]:          0 :         return skb_dst(skb) ? dev_net(skb_dst(skb)->dev) : dev_net(skb->dev);
     720                 :            : }
     721                 :            : 
     722                 :            : /* Router Alert as of RFC 2711 */
     723                 :            : 
     724                 :          0 : static bool ipv6_hop_ra(struct sk_buff *skb, int optoff)
     725                 :            : {
     726                 :            :         const unsigned char *nh = skb_network_header(skb);
     727                 :            : 
     728         [ #  # ]:          0 :         if (nh[optoff + 1] == 2) {
     729                 :          0 :                 IP6CB(skb)->flags |= IP6SKB_ROUTERALERT;
     730                 :          0 :                 memcpy(&IP6CB(skb)->ra, nh + optoff + 2, sizeof(IP6CB(skb)->ra));
     731                 :          0 :                 return true;
     732                 :            :         }
     733                 :            :         net_dbg_ratelimited("ipv6_hop_ra: wrong RA length %d\n",
     734                 :            :                             nh[optoff + 1]);
     735                 :          0 :         kfree_skb(skb);
     736                 :          0 :         return false;
     737                 :            : }
     738                 :            : 
     739                 :            : /* Jumbo payload */
     740                 :            : 
     741                 :          0 : static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
     742                 :            : {
     743                 :            :         const unsigned char *nh = skb_network_header(skb);
     744                 :          0 :         struct inet6_dev *idev = __in6_dev_get_safely(skb->dev);
     745                 :            :         struct net *net = ipv6_skb_net(skb);
     746                 :            :         u32 pkt_len;
     747                 :            : 
     748   [ #  #  #  # ]:          0 :         if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
     749                 :            :                 net_dbg_ratelimited("ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
     750                 :            :                                     nh[optoff+1]);
     751         [ #  # ]:          0 :                 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
     752                 :            :                 goto drop;
     753                 :            :         }
     754                 :            : 
     755                 :          0 :         pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
     756         [ #  # ]:          0 :         if (pkt_len <= IPV6_MAXPLEN) {
     757         [ #  # ]:          0 :                 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
     758                 :          0 :                 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
     759                 :          0 :                 return false;
     760                 :            :         }
     761         [ #  # ]:          0 :         if (ipv6_hdr(skb)->payload_len) {
     762         [ #  # ]:          0 :                 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
     763                 :          0 :                 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
     764                 :          0 :                 return false;
     765                 :            :         }
     766                 :            : 
     767         [ #  # ]:          0 :         if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
     768         [ #  # ]:          0 :                 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INTRUNCATEDPKTS);
     769                 :            :                 goto drop;
     770                 :            :         }
     771                 :            : 
     772         [ #  # ]:          0 :         if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
     773                 :            :                 goto drop;
     774                 :            : 
     775                 :          0 :         IP6CB(skb)->flags |= IP6SKB_JUMBOGRAM;
     776                 :          0 :         return true;
     777                 :            : 
     778                 :            : drop:
     779                 :          0 :         kfree_skb(skb);
     780                 :          0 :         return false;
     781                 :            : }
     782                 :            : 
     783                 :            : /* CALIPSO RFC 5570 */
     784                 :            : 
     785                 :          0 : static bool ipv6_hop_calipso(struct sk_buff *skb, int optoff)
     786                 :            : {
     787                 :            :         const unsigned char *nh = skb_network_header(skb);
     788                 :            : 
     789         [ #  # ]:          0 :         if (nh[optoff + 1] < 8)
     790                 :            :                 goto drop;
     791                 :            : 
     792         [ #  # ]:          0 :         if (nh[optoff + 6] * 4 + 8 > nh[optoff + 1])
     793                 :            :                 goto drop;
     794                 :            : 
     795                 :            :         if (!calipso_validate(skb, nh + optoff))
     796                 :            :                 goto drop;
     797                 :            : 
     798                 :            :         return true;
     799                 :            : 
     800                 :            : drop:
     801                 :          0 :         kfree_skb(skb);
     802                 :          0 :         return false;
     803                 :            : }
     804                 :            : 
     805                 :            : static const struct tlvtype_proc tlvprochopopt_lst[] = {
     806                 :            :         {
     807                 :            :                 .type   = IPV6_TLV_ROUTERALERT,
     808                 :            :                 .func   = ipv6_hop_ra,
     809                 :            :         },
     810                 :            :         {
     811                 :            :                 .type   = IPV6_TLV_JUMBO,
     812                 :            :                 .func   = ipv6_hop_jumbo,
     813                 :            :         },
     814                 :            :         {
     815                 :            :                 .type   = IPV6_TLV_CALIPSO,
     816                 :            :                 .func   = ipv6_hop_calipso,
     817                 :            :         },
     818                 :            :         { -1, }
     819                 :            : };
     820                 :            : 
     821                 :          0 : int ipv6_parse_hopopts(struct sk_buff *skb)
     822                 :            : {
     823                 :            :         struct inet6_skb_parm *opt = IP6CB(skb);
     824                 :          0 :         struct net *net = dev_net(skb->dev);
     825                 :            :         int extlen;
     826                 :            : 
     827                 :            :         /*
     828                 :            :          * skb_network_header(skb) is equal to skb->data, and
     829                 :            :          * skb_network_header_len(skb) is always equal to
     830                 :            :          * sizeof(struct ipv6hdr) by definition of
     831                 :            :          * hop-by-hop options.
     832                 :            :          */
     833   [ #  #  #  # ]:          0 :         if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) ||
     834                 :          0 :             !pskb_may_pull(skb, (sizeof(struct ipv6hdr) +
     835                 :          0 :                                  ((skb_transport_header(skb)[1] + 1) << 3)))) {
     836                 :            : fail_and_free:
     837                 :          0 :                 kfree_skb(skb);
     838                 :          0 :                 return -1;
     839                 :            :         }
     840                 :            : 
     841                 :          0 :         extlen = (skb_transport_header(skb)[1] + 1) << 3;
     842         [ #  # ]:          0 :         if (extlen > net->ipv6.sysctl.max_hbh_opts_len)
     843                 :            :                 goto fail_and_free;
     844                 :            : 
     845                 :          0 :         opt->flags |= IP6SKB_HOPBYHOP;
     846         [ #  # ]:          0 :         if (ip6_parse_tlv(tlvprochopopt_lst, skb,
     847                 :            :                           init_net.ipv6.sysctl.max_hbh_opts_cnt)) {
     848                 :          0 :                 skb->transport_header += extlen;
     849                 :            :                 opt = IP6CB(skb);
     850                 :          0 :                 opt->nhoff = sizeof(struct ipv6hdr);
     851                 :          0 :                 return 1;
     852                 :            :         }
     853                 :            :         return -1;
     854                 :            : }
     855                 :            : 
     856                 :            : /*
     857                 :            :  *      Creating outbound headers.
     858                 :            :  *
     859                 :            :  *      "build" functions work when skb is filled from head to tail (datagram)
     860                 :            :  *      "push"        functions work when headers are added from tail to head (tcp)
     861                 :            :  *
     862                 :            :  *      In both cases we assume, that caller reserved enough room
     863                 :            :  *      for headers.
     864                 :            :  */
     865                 :            : 
     866                 :          0 : static void ipv6_push_rthdr0(struct sk_buff *skb, u8 *proto,
     867                 :            :                              struct ipv6_rt_hdr *opt,
     868                 :            :                              struct in6_addr **addr_p, struct in6_addr *saddr)
     869                 :            : {
     870                 :            :         struct rt0_hdr *phdr, *ihdr;
     871                 :            :         int hops;
     872                 :            : 
     873                 :            :         ihdr = (struct rt0_hdr *) opt;
     874                 :            : 
     875                 :          0 :         phdr = skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
     876                 :          0 :         memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
     877                 :            : 
     878                 :          0 :         hops = ihdr->rt_hdr.hdrlen >> 1;
     879                 :            : 
     880         [ #  # ]:          0 :         if (hops > 1)
     881                 :          0 :                 memcpy(phdr->addr, ihdr->addr + 1,
     882                 :          0 :                        (hops - 1) * sizeof(struct in6_addr));
     883                 :            : 
     884                 :          0 :         phdr->addr[hops - 1] = **addr_p;
     885                 :          0 :         *addr_p = ihdr->addr;
     886                 :            : 
     887                 :          0 :         phdr->rt_hdr.nexthdr = *proto;
     888                 :          0 :         *proto = NEXTHDR_ROUTING;
     889                 :          0 : }
     890                 :            : 
     891                 :          0 : static void ipv6_push_rthdr4(struct sk_buff *skb, u8 *proto,
     892                 :            :                              struct ipv6_rt_hdr *opt,
     893                 :            :                              struct in6_addr **addr_p, struct in6_addr *saddr)
     894                 :            : {
     895                 :            :         struct ipv6_sr_hdr *sr_phdr, *sr_ihdr;
     896                 :            :         int plen, hops;
     897                 :            : 
     898                 :            :         sr_ihdr = (struct ipv6_sr_hdr *)opt;
     899                 :          0 :         plen = (sr_ihdr->hdrlen + 1) << 3;
     900                 :            : 
     901                 :          0 :         sr_phdr = skb_push(skb, plen);
     902                 :          0 :         memcpy(sr_phdr, sr_ihdr, sizeof(struct ipv6_sr_hdr));
     903                 :            : 
     904                 :          0 :         hops = sr_ihdr->first_segment + 1;
     905                 :          0 :         memcpy(sr_phdr->segments + 1, sr_ihdr->segments + 1,
     906                 :            :                (hops - 1) * sizeof(struct in6_addr));
     907                 :            : 
     908                 :          0 :         sr_phdr->segments[0] = **addr_p;
     909                 :          0 :         *addr_p = &sr_ihdr->segments[sr_ihdr->segments_left];
     910                 :            : 
     911         [ #  # ]:          0 :         if (sr_ihdr->hdrlen > hops * 2) {
     912                 :            :                 int tlvs_offset, tlvs_length;
     913                 :            : 
     914                 :          0 :                 tlvs_offset = (1 + hops * 2) << 3;
     915                 :          0 :                 tlvs_length = (sr_ihdr->hdrlen - hops * 2) << 3;
     916                 :          0 :                 memcpy((char *)sr_phdr + tlvs_offset,
     917                 :            :                        (char *)sr_ihdr + tlvs_offset, tlvs_length);
     918                 :            :         }
     919                 :            : 
     920                 :            : #ifdef CONFIG_IPV6_SEG6_HMAC
     921                 :            :         if (sr_has_hmac(sr_phdr)) {
     922                 :            :                 struct net *net = NULL;
     923                 :            : 
     924                 :            :                 if (skb->dev)
     925                 :            :                         net = dev_net(skb->dev);
     926                 :            :                 else if (skb->sk)
     927                 :            :                         net = sock_net(skb->sk);
     928                 :            : 
     929                 :            :                 WARN_ON(!net);
     930                 :            : 
     931                 :            :                 if (net)
     932                 :            :                         seg6_push_hmac(net, saddr, sr_phdr);
     933                 :            :         }
     934                 :            : #endif
     935                 :            : 
     936                 :          0 :         sr_phdr->nexthdr = *proto;
     937                 :          0 :         *proto = NEXTHDR_ROUTING;
     938                 :          0 : }
     939                 :            : 
     940                 :          0 : static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
     941                 :            :                             struct ipv6_rt_hdr *opt,
     942                 :            :                             struct in6_addr **addr_p, struct in6_addr *saddr)
     943                 :            : {
     944      [ #  #  # ]:          0 :         switch (opt->type) {
     945                 :            :         case IPV6_SRCRT_TYPE_0:
     946                 :            :         case IPV6_SRCRT_STRICT:
     947                 :            :         case IPV6_SRCRT_TYPE_2:
     948                 :          0 :                 ipv6_push_rthdr0(skb, proto, opt, addr_p, saddr);
     949                 :          0 :                 break;
     950                 :            :         case IPV6_SRCRT_TYPE_4:
     951                 :          0 :                 ipv6_push_rthdr4(skb, proto, opt, addr_p, saddr);
     952                 :          0 :                 break;
     953                 :            :         default:
     954                 :            :                 break;
     955                 :            :         }
     956                 :          0 : }
     957                 :            : 
     958                 :          0 : static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
     959                 :            : {
     960                 :          0 :         struct ipv6_opt_hdr *h = skb_push(skb, ipv6_optlen(opt));
     961                 :            : 
     962                 :          0 :         memcpy(h, opt, ipv6_optlen(opt));
     963                 :          0 :         h->nexthdr = *proto;
     964                 :          0 :         *proto = type;
     965                 :          0 : }
     966                 :            : 
     967                 :          0 : void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
     968                 :            :                           u8 *proto,
     969                 :            :                           struct in6_addr **daddr, struct in6_addr *saddr)
     970                 :            : {
     971         [ #  # ]:          0 :         if (opt->srcrt) {
     972                 :          0 :                 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr, saddr);
     973                 :            :                 /*
     974                 :            :                  * IPV6_RTHDRDSTOPTS is ignored
     975                 :            :                  * unless IPV6_RTHDR is set (RFC3542).
     976                 :            :                  */
     977         [ #  # ]:          0 :                 if (opt->dst0opt)
     978                 :          0 :                         ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
     979                 :            :         }
     980         [ #  # ]:          0 :         if (opt->hopopt)
     981                 :          0 :                 ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
     982                 :          0 : }
     983                 :            : 
     984                 :          0 : void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
     985                 :            : {
     986         [ #  # ]:          0 :         if (opt->dst1opt)
     987                 :          0 :                 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
     988                 :          0 : }
     989                 :            : EXPORT_SYMBOL(ipv6_push_frag_opts);
     990                 :            : 
     991                 :            : struct ipv6_txoptions *
     992                 :          0 : ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
     993                 :            : {
     994                 :            :         struct ipv6_txoptions *opt2;
     995                 :            : 
     996                 :          0 :         opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
     997         [ #  # ]:          0 :         if (opt2) {
     998                 :          0 :                 long dif = (char *)opt2 - (char *)opt;
     999                 :          0 :                 memcpy(opt2, opt, opt->tot_len);
    1000         [ #  # ]:          0 :                 if (opt2->hopopt)
    1001                 :          0 :                         *((char **)&opt2->hopopt) += dif;
    1002         [ #  # ]:          0 :                 if (opt2->dst0opt)
    1003                 :          0 :                         *((char **)&opt2->dst0opt) += dif;
    1004         [ #  # ]:          0 :                 if (opt2->dst1opt)
    1005                 :          0 :                         *((char **)&opt2->dst1opt) += dif;
    1006         [ #  # ]:          0 :                 if (opt2->srcrt)
    1007                 :          0 :                         *((char **)&opt2->srcrt) += dif;
    1008                 :            :                 refcount_set(&opt2->refcnt, 1);
    1009                 :            :         }
    1010                 :          0 :         return opt2;
    1011                 :            : }
    1012                 :            : EXPORT_SYMBOL_GPL(ipv6_dup_options);
    1013                 :            : 
    1014                 :          0 : static void ipv6_renew_option(int renewtype,
    1015                 :            :                               struct ipv6_opt_hdr **dest,
    1016                 :            :                               struct ipv6_opt_hdr *old,
    1017                 :            :                               struct ipv6_opt_hdr *new,
    1018                 :            :                               int newtype, char **p)
    1019                 :            : {
    1020                 :            :         struct ipv6_opt_hdr *src;
    1021                 :            : 
    1022         [ #  # ]:          0 :         src = (renewtype == newtype ? new : old);
    1023         [ #  # ]:          0 :         if (!src)
    1024                 :          0 :                 return;
    1025                 :            : 
    1026                 :          0 :         memcpy(*p, src, ipv6_optlen(src));
    1027                 :          0 :         *dest = (struct ipv6_opt_hdr *)*p;
    1028                 :          0 :         *p += CMSG_ALIGN(ipv6_optlen(*dest));
    1029                 :            : }
    1030                 :            : 
    1031                 :            : /**
    1032                 :            :  * ipv6_renew_options - replace a specific ext hdr with a new one.
    1033                 :            :  *
    1034                 :            :  * @sk: sock from which to allocate memory
    1035                 :            :  * @opt: original options
    1036                 :            :  * @newtype: option type to replace in @opt
    1037                 :            :  * @newopt: new option of type @newtype to replace (user-mem)
    1038                 :            :  * @newoptlen: length of @newopt
    1039                 :            :  *
    1040                 :            :  * Returns a new set of options which is a copy of @opt with the
    1041                 :            :  * option type @newtype replaced with @newopt.
    1042                 :            :  *
    1043                 :            :  * @opt may be NULL, in which case a new set of options is returned
    1044                 :            :  * containing just @newopt.
    1045                 :            :  *
    1046                 :            :  * @newopt may be NULL, in which case the specified option type is
    1047                 :            :  * not copied into the new set of options.
    1048                 :            :  *
    1049                 :            :  * The new set of options is allocated from the socket option memory
    1050                 :            :  * buffer of @sk.
    1051                 :            :  */
    1052                 :            : struct ipv6_txoptions *
    1053                 :          0 : ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
    1054                 :            :                    int newtype, struct ipv6_opt_hdr *newopt)
    1055                 :            : {
    1056                 :            :         int tot_len = 0;
    1057                 :            :         char *p;
    1058                 :            :         struct ipv6_txoptions *opt2;
    1059                 :            : 
    1060         [ #  # ]:          0 :         if (opt) {
    1061   [ #  #  #  # ]:          0 :                 if (newtype != IPV6_HOPOPTS && opt->hopopt)
    1062                 :          0 :                         tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
    1063   [ #  #  #  # ]:          0 :                 if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
    1064                 :          0 :                         tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
    1065   [ #  #  #  # ]:          0 :                 if (newtype != IPV6_RTHDR && opt->srcrt)
    1066                 :          0 :                         tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
    1067   [ #  #  #  # ]:          0 :                 if (newtype != IPV6_DSTOPTS && opt->dst1opt)
    1068                 :          0 :                         tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
    1069                 :            :         }
    1070                 :            : 
    1071         [ #  # ]:          0 :         if (newopt)
    1072                 :          0 :                 tot_len += CMSG_ALIGN(ipv6_optlen(newopt));
    1073                 :            : 
    1074         [ #  # ]:          0 :         if (!tot_len)
    1075                 :            :                 return NULL;
    1076                 :            : 
    1077                 :          0 :         tot_len += sizeof(*opt2);
    1078                 :          0 :         opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
    1079         [ #  # ]:          0 :         if (!opt2)
    1080                 :            :                 return ERR_PTR(-ENOBUFS);
    1081                 :            : 
    1082                 :          0 :         memset(opt2, 0, tot_len);
    1083                 :            :         refcount_set(&opt2->refcnt, 1);
    1084                 :          0 :         opt2->tot_len = tot_len;
    1085                 :          0 :         p = (char *)(opt2 + 1);
    1086                 :            : 
    1087         [ #  # ]:          0 :         ipv6_renew_option(IPV6_HOPOPTS, &opt2->hopopt,
    1088                 :            :                           (opt ? opt->hopopt : NULL),
    1089                 :            :                           newopt, newtype, &p);
    1090         [ #  # ]:          0 :         ipv6_renew_option(IPV6_RTHDRDSTOPTS, &opt2->dst0opt,
    1091                 :            :                           (opt ? opt->dst0opt : NULL),
    1092                 :            :                           newopt, newtype, &p);
    1093         [ #  # ]:          0 :         ipv6_renew_option(IPV6_RTHDR,
    1094                 :          0 :                           (struct ipv6_opt_hdr **)&opt2->srcrt,
    1095                 :            :                           (opt ? (struct ipv6_opt_hdr *)opt->srcrt : NULL),
    1096                 :            :                           newopt, newtype, &p);
    1097         [ #  # ]:          0 :         ipv6_renew_option(IPV6_DSTOPTS, &opt2->dst1opt,
    1098                 :            :                           (opt ? opt->dst1opt : NULL),
    1099                 :            :                           newopt, newtype, &p);
    1100                 :            : 
    1101   [ #  #  #  #  :          0 :         opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
                   #  # ]
    1102                 :          0 :                           (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
    1103                 :          0 :                           (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);
    1104         [ #  # ]:          0 :         opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);
    1105                 :            : 
    1106                 :          0 :         return opt2;
    1107                 :            : }
    1108                 :            : 
    1109                 :       2050 : struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
    1110                 :            :                                           struct ipv6_txoptions *opt)
    1111                 :            : {
    1112                 :            :         /*
    1113                 :            :          * ignore the dest before srcrt unless srcrt is being included.
    1114                 :            :          * --yoshfuji
    1115                 :            :          */
    1116   [ -  +  #  #  :       2050 :         if (opt && opt->dst0opt && !opt->srcrt) {
                   #  # ]
    1117         [ #  # ]:          0 :                 if (opt_space != opt) {
    1118                 :          0 :                         memcpy(opt_space, opt, sizeof(*opt_space));
    1119                 :            :                         opt = opt_space;
    1120                 :            :                 }
    1121                 :          0 :                 opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
    1122                 :          0 :                 opt->dst0opt = NULL;
    1123                 :            :         }
    1124                 :            : 
    1125                 :       2050 :         return opt;
    1126                 :            : }
    1127                 :            : EXPORT_SYMBOL_GPL(ipv6_fixup_options);
    1128                 :            : 
    1129                 :            : /**
    1130                 :            :  * fl6_update_dst - update flowi destination address with info given
    1131                 :            :  *                  by srcrt option, if any.
    1132                 :            :  *
    1133                 :            :  * @fl6: flowi6 for which daddr is to be updated
    1134                 :            :  * @opt: struct ipv6_txoptions in which to look for srcrt opt
    1135                 :            :  * @orig: copy of original daddr address if modified
    1136                 :            :  *
    1137                 :            :  * Returns NULL if no txoptions or no srcrt, otherwise returns orig
    1138                 :            :  * and initial value of fl6->daddr set in orig
    1139                 :            :  */
    1140                 :       2340 : struct in6_addr *fl6_update_dst(struct flowi6 *fl6,
    1141                 :            :                                 const struct ipv6_txoptions *opt,
    1142                 :            :                                 struct in6_addr *orig)
    1143                 :            : {
    1144   [ -  +  #  # ]:       2340 :         if (!opt || !opt->srcrt)
    1145                 :            :                 return NULL;
    1146                 :            : 
    1147                 :          0 :         *orig = fl6->daddr;
    1148                 :            : 
    1149      [ #  #  # ]:          0 :         switch (opt->srcrt->type) {
    1150                 :            :         case IPV6_SRCRT_TYPE_0:
    1151                 :            :         case IPV6_SRCRT_STRICT:
    1152                 :            :         case IPV6_SRCRT_TYPE_2:
    1153                 :          0 :                 fl6->daddr = *((struct rt0_hdr *)opt->srcrt)->addr;
    1154                 :          0 :                 break;
    1155                 :            :         case IPV6_SRCRT_TYPE_4:
    1156                 :            :         {
    1157                 :            :                 struct ipv6_sr_hdr *srh = (struct ipv6_sr_hdr *)opt->srcrt;
    1158                 :            : 
    1159                 :          0 :                 fl6->daddr = srh->segments[srh->segments_left];
    1160                 :          0 :                 break;
    1161                 :            :         }
    1162                 :            :         default:
    1163                 :            :                 return NULL;
    1164                 :            :         }
    1165                 :            : 
    1166                 :          0 :         return orig;
    1167                 :            : }
    1168                 :            : EXPORT_SYMBOL_GPL(fl6_update_dst);

Generated by: LCOV version 1.14