LCOV - code coverage report
Current view: top level - net/ipv6 - exthdrs.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 226 0.4 %
Date: 2014-04-07 Functions: 1 18 5.6 %
Branches: 1 205 0.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  *      Extension Header handling for IPv6
       3                 :            :  *      Linux INET6 implementation
       4                 :            :  *
       5                 :            :  *      Authors:
       6                 :            :  *      Pedro Roque             <roque@di.fc.ul.pt>
       7                 :            :  *      Andi Kleen              <ak@muc.de>
       8                 :            :  *      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.
      14                 :            :  */
      15                 :            : 
      16                 :            : /* Changes:
      17                 :            :  *      yoshfuji                : ensure not to overrun while parsing
      18                 :            :  *                                tlv options.
      19                 :            :  *      Mitsuru KANDA @USAGI and: Remove ipv6_parse_exthdrs().
      20                 :            :  *      YOSHIFUJI Hideaki @USAGI  Register inbound extension header
      21                 :            :  *                                handlers as inet6_protocol{}.
      22                 :            :  */
      23                 :            : 
      24                 :            : #include <linux/errno.h>
      25                 :            : #include <linux/types.h>
      26                 :            : #include <linux/socket.h>
      27                 :            : #include <linux/sockios.h>
      28                 :            : #include <linux/net.h>
      29                 :            : #include <linux/netdevice.h>
      30                 :            : #include <linux/in6.h>
      31                 :            : #include <linux/icmpv6.h>
      32                 :            : #include <linux/slab.h>
      33                 :            : #include <linux/export.h>
      34                 :            : 
      35                 :            : #include <net/dst.h>
      36                 :            : #include <net/sock.h>
      37                 :            : #include <net/snmp.h>
      38                 :            : 
      39                 :            : #include <net/ipv6.h>
      40                 :            : #include <net/protocol.h>
      41                 :            : #include <net/transp_v6.h>
      42                 :            : #include <net/rawv6.h>
      43                 :            : #include <net/ndisc.h>
      44                 :            : #include <net/ip6_route.h>
      45                 :            : #include <net/addrconf.h>
      46                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
      47                 :            : #include <net/xfrm.h>
      48                 :            : #endif
      49                 :            : 
      50                 :            : #include <asm/uaccess.h>
      51                 :            : 
      52                 :            : /*
      53                 :            :  *      Parsing tlv encoded headers.
      54                 :            :  *
      55                 :            :  *      Parsing function "func" returns true, if parsing succeed
      56                 :            :  *      and false, if it failed.
      57                 :            :  *      It MUST NOT touch skb->h.
      58                 :            :  */
      59                 :            : 
      60                 :            : struct tlvtype_proc {
      61                 :            :         int     type;
      62                 :            :         bool    (*func)(struct sk_buff *skb, int offset);
      63                 :            : };
      64                 :            : 
      65                 :            : /*********************
      66                 :            :   Generic functions
      67                 :            :  *********************/
      68                 :            : 
      69                 :            : /* An unknown option is detected, decide what to do */
      70                 :            : 
      71                 :          0 : static bool ip6_tlvopt_unknown(struct sk_buff *skb, int optoff)
      72                 :            : {
      73   [ #  #  #  # ]:          0 :         switch ((skb_network_header(skb)[optoff] & 0xC0) >> 6) {
      74                 :            :         case 0: /* ignore */
      75                 :            :                 return true;
      76                 :            : 
      77                 :            :         case 1: /* drop packet */
      78                 :            :                 break;
      79                 :            : 
      80                 :            :         case 3: /* Send ICMP if not a multicast address and drop packet */
      81                 :            :                 /* Actually, it is redundant check. icmp_send
      82                 :            :                    will recheck in any case.
      83                 :            :                  */
      84         [ #  # ]:          0 :                 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr))
      85                 :            :                         break;
      86                 :            :         case 2: /* send ICMP PARM PROB regardless and drop packet */
      87                 :          0 :                 icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
      88                 :          0 :                 return false;
      89                 :            :         }
      90                 :            : 
      91                 :          0 :         kfree_skb(skb);
      92                 :          0 :         return false;
      93                 :            : }
      94                 :            : 
      95                 :            : /* Parse tlv encoded option header (hop-by-hop or destination) */
      96                 :            : 
      97                 :          0 : static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb)
      98                 :            : {
      99                 :            :         const struct tlvtype_proc *curr;
     100                 :            :         const unsigned char *nh = skb_network_header(skb);
     101                 :            :         int off = skb_network_header_len(skb);
     102                 :          0 :         int len = (skb_transport_header(skb)[1] + 1) << 3;
     103                 :            :         int padlen = 0;
     104                 :            : 
     105         [ #  # ]:          0 :         if (skb_transport_offset(skb) + len > skb_headlen(skb))
     106                 :            :                 goto bad;
     107                 :            : 
     108                 :          0 :         off += 2;
     109                 :          0 :         len -= 2;
     110                 :            : 
     111         [ #  # ]:          0 :         while (len > 0) {
     112                 :          0 :                 int optlen = nh[off + 1] + 2;
     113                 :            :                 int i;
     114                 :            : 
     115      [ #  #  # ]:          0 :                 switch (nh[off]) {
     116                 :            :                 case IPV6_TLV_PAD1:
     117                 :            :                         optlen = 1;
     118                 :          0 :                         padlen++;
     119         [ #  # ]:          0 :                         if (padlen > 7)
     120                 :            :                                 goto bad;
     121                 :            :                         break;
     122                 :            : 
     123                 :            :                 case IPV6_TLV_PADN:
     124                 :            :                         /* RFC 2460 states that the purpose of PadN is
     125                 :            :                          * to align the containing header to multiples
     126                 :            :                          * of 8. 7 is therefore the highest valid value.
     127                 :            :                          * See also RFC 4942, Section 2.1.9.5.
     128                 :            :                          */
     129                 :          0 :                         padlen += optlen;
     130         [ #  # ]:          0 :                         if (padlen > 7)
     131                 :            :                                 goto bad;
     132                 :            :                         /* RFC 4942 recommends receiving hosts to
     133                 :            :                          * actively check PadN payload to contain
     134                 :            :                          * only zeroes.
     135                 :            :                          */
     136         [ #  # ]:          0 :                         for (i = 2; i < optlen; i++) {
     137         [ #  # ]:          0 :                                 if (nh[off + i] != 0)
     138                 :            :                                         goto bad;
     139                 :            :                         }
     140                 :            :                         break;
     141                 :            : 
     142                 :            :                 default: /* Other TLV code so scan list */
     143         [ #  # ]:          0 :                         if (optlen > len)
     144                 :            :                                 goto bad;
     145         [ #  # ]:          0 :                         for (curr=procs; curr->type >= 0; curr++) {
     146         [ #  # ]:          0 :                                 if (curr->type == nh[off]) {
     147                 :            :                                         /* type specific length/alignment
     148                 :            :                                            checks will be performed in the
     149                 :            :                                            func(). */
     150         [ #  # ]:          0 :                                         if (curr->func(skb, off) == false)
     151                 :            :                                                 return false;
     152                 :            :                                         break;
     153                 :            :                                 }
     154                 :            :                         }
     155         [ #  # ]:          0 :                         if (curr->type < 0) {
     156         [ #  # ]:          0 :                                 if (ip6_tlvopt_unknown(skb, off) == 0)
     157                 :            :                                         return false;
     158                 :            :                         }
     159                 :            :                         padlen = 0;
     160                 :            :                         break;
     161                 :            :                 }
     162                 :          0 :                 off += optlen;
     163                 :          0 :                 len -= optlen;
     164                 :            :         }
     165                 :            : 
     166         [ #  # ]:          0 :         if (len == 0)
     167                 :            :                 return true;
     168                 :            : bad:
     169                 :          0 :         kfree_skb(skb);
     170                 :          0 :         return false;
     171                 :            : }
     172                 :            : 
     173                 :            : /*****************************
     174                 :            :   Destination options header.
     175                 :            :  *****************************/
     176                 :            : 
     177                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     178                 :            : static bool ipv6_dest_hao(struct sk_buff *skb, int optoff)
     179                 :            : {
     180                 :            :         struct ipv6_destopt_hao *hao;
     181                 :            :         struct inet6_skb_parm *opt = IP6CB(skb);
     182                 :            :         struct ipv6hdr *ipv6h = ipv6_hdr(skb);
     183                 :            :         struct in6_addr tmp_addr;
     184                 :            :         int ret;
     185                 :            : 
     186                 :            :         if (opt->dsthao) {
     187                 :            :                 LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n");
     188                 :            :                 goto discard;
     189                 :            :         }
     190                 :            :         opt->dsthao = opt->dst1;
     191                 :            :         opt->dst1 = 0;
     192                 :            : 
     193                 :            :         hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) + optoff);
     194                 :            : 
     195                 :            :         if (hao->length != 16) {
     196                 :            :                 LIMIT_NETDEBUG(
     197                 :            :                         KERN_DEBUG "hao invalid option length = %d\n", hao->length);
     198                 :            :                 goto discard;
     199                 :            :         }
     200                 :            : 
     201                 :            :         if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
     202                 :            :                 LIMIT_NETDEBUG(
     203                 :            :                         KERN_DEBUG "hao is not an unicast addr: %pI6\n", &hao->addr);
     204                 :            :                 goto discard;
     205                 :            :         }
     206                 :            : 
     207                 :            :         ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr,
     208                 :            :                                (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS);
     209                 :            :         if (unlikely(ret < 0))
     210                 :            :                 goto discard;
     211                 :            : 
     212                 :            :         if (skb_cloned(skb)) {
     213                 :            :                 if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
     214                 :            :                         goto discard;
     215                 :            : 
     216                 :            :                 /* update all variable using below by copied skbuff */
     217                 :            :                 hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) +
     218                 :            :                                                   optoff);
     219                 :            :                 ipv6h = ipv6_hdr(skb);
     220                 :            :         }
     221                 :            : 
     222                 :            :         if (skb->ip_summed == CHECKSUM_COMPLETE)
     223                 :            :                 skb->ip_summed = CHECKSUM_NONE;
     224                 :            : 
     225                 :            :         tmp_addr = ipv6h->saddr;
     226                 :            :         ipv6h->saddr = hao->addr;
     227                 :            :         hao->addr = tmp_addr;
     228                 :            : 
     229                 :            :         if (skb->tstamp.tv64 == 0)
     230                 :            :                 __net_timestamp(skb);
     231                 :            : 
     232                 :            :         return true;
     233                 :            : 
     234                 :            :  discard:
     235                 :            :         kfree_skb(skb);
     236                 :            :         return false;
     237                 :            : }
     238                 :            : #endif
     239                 :            : 
     240                 :            : static const struct tlvtype_proc tlvprocdestopt_lst[] = {
     241                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     242                 :            :         {
     243                 :            :                 .type   = IPV6_TLV_HAO,
     244                 :            :                 .func   = ipv6_dest_hao,
     245                 :            :         },
     246                 :            : #endif
     247                 :            :         {-1,                    NULL}
     248                 :            : };
     249                 :            : 
     250                 :          0 : static int ipv6_destopt_rcv(struct sk_buff *skb)
     251                 :            : {
     252                 :            :         struct inet6_skb_parm *opt = IP6CB(skb);
     253                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     254                 :            :         __u16 dstbuf;
     255                 :            : #endif
     256                 :            :         struct dst_entry *dst = skb_dst(skb);
     257                 :            : 
     258 [ #  # ][ #  # ]:          0 :         if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
     259                 :          0 :             !pskb_may_pull(skb, (skb_transport_offset(skb) +
     260                 :          0 :                                  ((skb_transport_header(skb)[1] + 1) << 3)))) {
     261         [ #  # ]:          0 :                 IP6_INC_STATS_BH(dev_net(dst->dev), ip6_dst_idev(dst),
     262                 :            :                                  IPSTATS_MIB_INHDRERRORS);
     263                 :          0 :                 kfree_skb(skb);
     264                 :          0 :                 return -1;
     265                 :            :         }
     266                 :            : 
     267                 :          0 :         opt->lastopt = opt->dst1 = skb_network_header_len(skb);
     268                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     269                 :            :         dstbuf = opt->dst1;
     270                 :            : #endif
     271                 :            : 
     272         [ #  # ]:          0 :         if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
     273                 :          0 :                 skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
     274                 :            :                 opt = IP6CB(skb);
     275                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     276                 :            :                 opt->nhoff = dstbuf;
     277                 :            : #else
     278                 :          0 :                 opt->nhoff = opt->dst1;
     279                 :            : #endif
     280                 :          0 :                 return 1;
     281                 :            :         }
     282                 :            : 
     283         [ #  # ]:          0 :         IP6_INC_STATS_BH(dev_net(dst->dev),
     284                 :            :                          ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
     285                 :          0 :         return -1;
     286                 :            : }
     287                 :            : 
     288                 :            : /********************************
     289                 :            :   Routing header.
     290                 :            :  ********************************/
     291                 :            : 
     292                 :            : /* called with rcu_read_lock() */
     293                 :          0 : static int ipv6_rthdr_rcv(struct sk_buff *skb)
     294                 :            : {
     295                 :            :         struct inet6_skb_parm *opt = IP6CB(skb);
     296                 :            :         struct in6_addr *addr = NULL;
     297                 :            :         struct in6_addr daddr;
     298                 :            :         struct inet6_dev *idev;
     299                 :            :         int n, i;
     300                 :            :         struct ipv6_rt_hdr *hdr;
     301                 :            :         struct rt0_hdr *rthdr;
     302                 :            :         struct net *net = dev_net(skb->dev);
     303                 :            :         int accept_source_route = net->ipv6.devconf_all->accept_source_route;
     304                 :            : 
     305                 :            :         idev = __in6_dev_get(skb->dev);
     306                 :            :         if (idev && accept_source_route > idev->cnf.accept_source_route)
     307                 :            :                 accept_source_route = idev->cnf.accept_source_route;
     308                 :            : 
     309 [ #  # ][ #  # ]:          0 :         if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
     310                 :          0 :             !pskb_may_pull(skb, (skb_transport_offset(skb) +
     311                 :          0 :                                  ((skb_transport_header(skb)[1] + 1) << 3)))) {
     312         [ #  # ]:          0 :                 IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
     313                 :            :                                  IPSTATS_MIB_INHDRERRORS);
     314                 :          0 :                 kfree_skb(skb);
     315                 :          0 :                 return -1;
     316                 :            :         }
     317                 :            : 
     318                 :            :         hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
     319                 :            : 
     320 [ #  # ][ #  # ]:          0 :         if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
     321                 :          0 :             skb->pkt_type != PACKET_HOST) {
     322         [ #  # ]:          0 :                 IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
     323                 :            :                                  IPSTATS_MIB_INADDRERRORS);
     324                 :          0 :                 kfree_skb(skb);
     325                 :          0 :                 return -1;
     326                 :            :         }
     327                 :            : 
     328                 :            : looped_back:
     329         [ #  # ]:          0 :         if (hdr->segments_left == 0) {
     330                 :            :                 switch (hdr->type) {
     331                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     332                 :            :                 case IPV6_SRCRT_TYPE_2:
     333                 :            :                         /* Silently discard type 2 header unless it was
     334                 :            :                          * processed by own
     335                 :            :                          */
     336                 :            :                         if (!addr) {
     337                 :            :                                 IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
     338                 :            :                                                  IPSTATS_MIB_INADDRERRORS);
     339                 :            :                                 kfree_skb(skb);
     340                 :            :                                 return -1;
     341                 :            :                         }
     342                 :            :                         break;
     343                 :            : #endif
     344                 :            :                 default:
     345                 :            :                         break;
     346                 :            :                 }
     347                 :            : 
     348                 :          0 :                 opt->lastopt = opt->srcrt = skb_network_header_len(skb);
     349                 :          0 :                 skb->transport_header += (hdr->hdrlen + 1) << 3;
     350                 :          0 :                 opt->dst0 = opt->dst1;
     351                 :          0 :                 opt->dst1 = 0;
     352                 :          0 :                 opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb);
     353                 :          0 :                 return 1;
     354                 :            :         }
     355                 :            : 
     356                 :            :         switch (hdr->type) {
     357                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     358                 :            :         case IPV6_SRCRT_TYPE_2:
     359                 :            :                 if (accept_source_route < 0)
     360                 :            :                         goto unknown_rh;
     361                 :            :                 /* Silently discard invalid RTH type 2 */
     362                 :            :                 if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
     363                 :            :                         IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
     364                 :            :                                          IPSTATS_MIB_INHDRERRORS);
     365                 :            :                         kfree_skb(skb);
     366                 :            :                         return -1;
     367                 :            :                 }
     368                 :            :                 break;
     369                 :            : #endif
     370                 :            :         default:
     371                 :            :                 goto unknown_rh;
     372                 :            :         }
     373                 :            : 
     374                 :            :         /*
     375                 :            :          *      This is the routing header forwarding algorithm from
     376                 :            :          *      RFC 2460, page 16.
     377                 :            :          */
     378                 :            : 
     379                 :            :         n = hdr->hdrlen >> 1;
     380                 :            : 
     381                 :            :         if (hdr->segments_left > n) {
     382                 :            :                 IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
     383                 :            :                                  IPSTATS_MIB_INHDRERRORS);
     384                 :            :                 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
     385                 :            :                                   ((&hdr->segments_left) -
     386                 :            :                                    skb_network_header(skb)));
     387                 :            :                 return -1;
     388                 :            :         }
     389                 :            : 
     390                 :            :         /* We are about to mangle packet header. Be careful!
     391                 :            :            Do not damage packets queued somewhere.
     392                 :            :          */
     393                 :            :         if (skb_cloned(skb)) {
     394                 :            :                 /* the copy is a forwarded packet */
     395                 :            :                 if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
     396                 :            :                         IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
     397                 :            :                                          IPSTATS_MIB_OUTDISCARDS);
     398                 :            :                         kfree_skb(skb);
     399                 :            :                         return -1;
     400                 :            :                 }
     401                 :            :                 hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
     402                 :            :         }
     403                 :            : 
     404                 :            :         if (skb->ip_summed == CHECKSUM_COMPLETE)
     405                 :            :                 skb->ip_summed = CHECKSUM_NONE;
     406                 :            : 
     407                 :            :         i = n - --hdr->segments_left;
     408                 :            : 
     409                 :            :         rthdr = (struct rt0_hdr *) hdr;
     410                 :            :         addr = rthdr->addr;
     411                 :            :         addr += i - 1;
     412                 :            : 
     413                 :            :         switch (hdr->type) {
     414                 :            : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     415                 :            :         case IPV6_SRCRT_TYPE_2:
     416                 :            :                 if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
     417                 :            :                                      (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
     418                 :            :                                      IPPROTO_ROUTING) < 0) {
     419                 :            :                         IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
     420                 :            :                                          IPSTATS_MIB_INADDRERRORS);
     421                 :            :                         kfree_skb(skb);
     422                 :            :                         return -1;
     423                 :            :                 }
     424                 :            :                 if (!ipv6_chk_home_addr(dev_net(skb_dst(skb)->dev), addr)) {
     425                 :            :                         IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
     426                 :            :                                          IPSTATS_MIB_INADDRERRORS);
     427                 :            :                         kfree_skb(skb);
     428                 :            :                         return -1;
     429                 :            :                 }
     430                 :            :                 break;
     431                 :            : #endif
     432                 :            :         default:
     433                 :            :                 break;
     434                 :            :         }
     435                 :            : 
     436                 :            :         if (ipv6_addr_is_multicast(addr)) {
     437                 :            :                 IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
     438                 :            :                                  IPSTATS_MIB_INADDRERRORS);
     439                 :            :                 kfree_skb(skb);
     440                 :            :                 return -1;
     441                 :            :         }
     442                 :            : 
     443                 :            :         daddr = *addr;
     444                 :            :         *addr = ipv6_hdr(skb)->daddr;
     445                 :            :         ipv6_hdr(skb)->daddr = daddr;
     446                 :            : 
     447                 :            :         skb_dst_drop(skb);
     448                 :            :         ip6_route_input(skb);
     449                 :            :         if (skb_dst(skb)->error) {
     450                 :            :                 skb_push(skb, skb->data - skb_network_header(skb));
     451                 :            :                 dst_input(skb);
     452                 :            :                 return -1;
     453                 :            :         }
     454                 :            : 
     455                 :            :         if (skb_dst(skb)->dev->flags&IFF_LOOPBACK) {
     456                 :            :                 if (ipv6_hdr(skb)->hop_limit <= 1) {
     457                 :            :                         IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
     458                 :            :                                          IPSTATS_MIB_INHDRERRORS);
     459                 :            :                         icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
     460                 :            :                                     0);
     461                 :            :                         kfree_skb(skb);
     462                 :            :                         return -1;
     463                 :            :                 }
     464                 :            :                 ipv6_hdr(skb)->hop_limit--;
     465                 :            :                 goto looped_back;
     466                 :            :         }
     467                 :            : 
     468                 :            :         skb_push(skb, skb->data - skb_network_header(skb));
     469                 :            :         dst_input(skb);
     470                 :            :         return -1;
     471                 :            : 
     472                 :            : unknown_rh:
     473         [ #  # ]:          0 :         IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS);
     474                 :          0 :         icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
     475                 :          0 :                           (&hdr->type) - skb_network_header(skb));
     476                 :          0 :         return -1;
     477                 :            : }
     478                 :            : 
     479                 :            : static const struct inet6_protocol rthdr_protocol = {
     480                 :            :         .handler        =       ipv6_rthdr_rcv,
     481                 :            :         .flags          =       INET6_PROTO_NOPOLICY,
     482                 :            : };
     483                 :            : 
     484                 :            : static const struct inet6_protocol destopt_protocol = {
     485                 :            :         .handler        =       ipv6_destopt_rcv,
     486                 :            :         .flags          =       INET6_PROTO_NOPOLICY,
     487                 :            : };
     488                 :            : 
     489                 :            : static const struct inet6_protocol nodata_protocol = {
     490                 :            :         .handler        =       dst_discard,
     491                 :            :         .flags          =       INET6_PROTO_NOPOLICY,
     492                 :            : };
     493                 :            : 
     494                 :          0 : int __init ipv6_exthdrs_init(void)
     495                 :            : {
     496                 :            :         int ret;
     497                 :            : 
     498                 :          0 :         ret = inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING);
     499         [ #  # ]:          0 :         if (ret)
     500                 :            :                 goto out;
     501                 :            : 
     502                 :          0 :         ret = inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
     503         [ #  # ]:          0 :         if (ret)
     504                 :            :                 goto out_rthdr;
     505                 :            : 
     506                 :          0 :         ret = inet6_add_protocol(&nodata_protocol, IPPROTO_NONE);
     507         [ #  # ]:          0 :         if (ret)
     508                 :            :                 goto out_destopt;
     509                 :            : 
     510                 :            : out:
     511                 :          0 :         return ret;
     512                 :            : out_destopt:
     513                 :          0 :         inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
     514                 :            : out_rthdr:
     515                 :          0 :         inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
     516                 :          0 :         goto out;
     517                 :            : };
     518                 :            : 
     519                 :          0 : void ipv6_exthdrs_exit(void)
     520                 :            : {
     521                 :          0 :         inet6_del_protocol(&nodata_protocol, IPPROTO_NONE);
     522                 :          0 :         inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
     523                 :          0 :         inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
     524                 :          0 : }
     525                 :            : 
     526                 :            : /**********************************
     527                 :            :   Hop-by-hop options.
     528                 :            :  **********************************/
     529                 :            : 
     530                 :            : /*
     531                 :            :  * Note: we cannot rely on skb_dst(skb) before we assign it in ip6_route_input().
     532                 :            :  */
     533                 :          0 : static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb)
     534                 :            : {
     535 [ #  # ][ #  # ]:          0 :         return skb_dst(skb) ? ip6_dst_idev(skb_dst(skb)) : __in6_dev_get(skb->dev);
         [ #  # ][ #  # ]
     536                 :            : }
     537                 :            : 
     538                 :            : static inline struct net *ipv6_skb_net(struct sk_buff *skb)
     539                 :            : {
     540                 :            :         return skb_dst(skb) ? dev_net(skb_dst(skb)->dev) : dev_net(skb->dev);
     541                 :            : }
     542                 :            : 
     543                 :            : /* Router Alert as of RFC 2711 */
     544                 :            : 
     545                 :          0 : static bool ipv6_hop_ra(struct sk_buff *skb, int optoff)
     546                 :            : {
     547                 :            :         const unsigned char *nh = skb_network_header(skb);
     548                 :            : 
     549         [ #  # ]:          0 :         if (nh[optoff + 1] == 2) {
     550                 :          0 :                 IP6CB(skb)->flags |= IP6SKB_ROUTERALERT;
     551                 :          0 :                 memcpy(&IP6CB(skb)->ra, nh + optoff + 2, sizeof(IP6CB(skb)->ra));
     552                 :          0 :                 return true;
     553                 :            :         }
     554 [ #  # ][ #  # ]:          0 :         LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
     555                 :            :                        nh[optoff + 1]);
     556                 :          0 :         kfree_skb(skb);
     557                 :          0 :         return false;
     558                 :            : }
     559                 :            : 
     560                 :            : /* Jumbo payload */
     561                 :            : 
     562                 :          0 : static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
     563                 :            : {
     564                 :            :         const unsigned char *nh = skb_network_header(skb);
     565                 :            :         struct net *net = ipv6_skb_net(skb);
     566                 :            :         u32 pkt_len;
     567                 :            : 
     568 [ #  # ][ #  # ]:          0 :         if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
     569 [ #  # ][ #  # ]:          0 :                 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
     570                 :            :                                nh[optoff+1]);
     571         [ #  # ]:          0 :                 IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
     572                 :            :                                  IPSTATS_MIB_INHDRERRORS);
     573                 :            :                 goto drop;
     574                 :            :         }
     575                 :            : 
     576         [ #  # ]:          0 :         pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
     577         [ #  # ]:          0 :         if (pkt_len <= IPV6_MAXPLEN) {
     578         [ #  # ]:          0 :                 IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
     579                 :            :                                  IPSTATS_MIB_INHDRERRORS);
     580                 :          0 :                 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
     581                 :          0 :                 return false;
     582                 :            :         }
     583         [ #  # ]:          0 :         if (ipv6_hdr(skb)->payload_len) {
     584         [ #  # ]:          0 :                 IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
     585                 :            :                                  IPSTATS_MIB_INHDRERRORS);
     586                 :          0 :                 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
     587                 :          0 :                 return false;
     588                 :            :         }
     589                 :            : 
     590         [ #  # ]:          0 :         if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
     591         [ #  # ]:          0 :                 IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
     592                 :            :                                  IPSTATS_MIB_INTRUNCATEDPKTS);
     593                 :            :                 goto drop;
     594                 :            :         }
     595                 :            : 
     596         [ #  # ]:          0 :         if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
     597                 :            :                 goto drop;
     598                 :            : 
     599                 :            :         return true;
     600                 :            : 
     601                 :            : drop:
     602                 :          0 :         kfree_skb(skb);
     603                 :          0 :         return false;
     604                 :            : }
     605                 :            : 
     606                 :            : static const struct tlvtype_proc tlvprochopopt_lst[] = {
     607                 :            :         {
     608                 :            :                 .type   = IPV6_TLV_ROUTERALERT,
     609                 :            :                 .func   = ipv6_hop_ra,
     610                 :            :         },
     611                 :            :         {
     612                 :            :                 .type   = IPV6_TLV_JUMBO,
     613                 :            :                 .func   = ipv6_hop_jumbo,
     614                 :            :         },
     615                 :            :         { -1, }
     616                 :            : };
     617                 :            : 
     618                 :          0 : int ipv6_parse_hopopts(struct sk_buff *skb)
     619                 :            : {
     620                 :            :         struct inet6_skb_parm *opt = IP6CB(skb);
     621                 :            : 
     622                 :            :         /*
     623                 :            :          * skb_network_header(skb) is equal to skb->data, and
     624                 :            :          * skb_network_header_len(skb) is always equal to
     625                 :            :          * sizeof(struct ipv6hdr) by definition of
     626                 :            :          * hop-by-hop options.
     627                 :            :          */
     628 [ #  # ][ #  # ]:          0 :         if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) ||
     629                 :          0 :             !pskb_may_pull(skb, (sizeof(struct ipv6hdr) +
     630                 :          0 :                                  ((skb_transport_header(skb)[1] + 1) << 3)))) {
     631                 :          0 :                 kfree_skb(skb);
     632                 :          0 :                 return -1;
     633                 :            :         }
     634                 :            : 
     635                 :          0 :         opt->hop = sizeof(struct ipv6hdr);
     636         [ #  # ]:          0 :         if (ip6_parse_tlv(tlvprochopopt_lst, skb)) {
     637                 :          0 :                 skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
     638                 :            :                 opt = IP6CB(skb);
     639                 :          0 :                 opt->nhoff = sizeof(struct ipv6hdr);
     640                 :          0 :                 return 1;
     641                 :            :         }
     642                 :            :         return -1;
     643                 :            : }
     644                 :            : 
     645                 :            : /*
     646                 :            :  *      Creating outbound headers.
     647                 :            :  *
     648                 :            :  *      "build" functions work when skb is filled from head to tail (datagram)
     649                 :            :  *      "push"        functions work when headers are added from tail to head (tcp)
     650                 :            :  *
     651                 :            :  *      In both cases we assume, that caller reserved enough room
     652                 :            :  *      for headers.
     653                 :            :  */
     654                 :            : 
     655                 :          0 : static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
     656                 :            :                             struct ipv6_rt_hdr *opt,
     657                 :            :                             struct in6_addr **addr_p)
     658                 :            : {
     659                 :            :         struct rt0_hdr *phdr, *ihdr;
     660                 :            :         int hops;
     661                 :            : 
     662                 :            :         ihdr = (struct rt0_hdr *) opt;
     663                 :            : 
     664                 :          0 :         phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
     665                 :          0 :         memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
     666                 :            : 
     667                 :          0 :         hops = ihdr->rt_hdr.hdrlen >> 1;
     668                 :            : 
     669         [ #  # ]:          0 :         if (hops > 1)
     670                 :          0 :                 memcpy(phdr->addr, ihdr->addr + 1,
     671                 :          0 :                        (hops - 1) * sizeof(struct in6_addr));
     672                 :            : 
     673                 :          0 :         phdr->addr[hops - 1] = **addr_p;
     674                 :          0 :         *addr_p = ihdr->addr;
     675                 :            : 
     676                 :          0 :         phdr->rt_hdr.nexthdr = *proto;
     677                 :          0 :         *proto = NEXTHDR_ROUTING;
     678                 :          0 : }
     679                 :            : 
     680                 :          0 : static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
     681                 :            : {
     682                 :          0 :         struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
     683                 :            : 
     684                 :          0 :         memcpy(h, opt, ipv6_optlen(opt));
     685                 :          0 :         h->nexthdr = *proto;
     686                 :          0 :         *proto = type;
     687                 :          0 : }
     688                 :            : 
     689                 :          0 : void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
     690                 :            :                           u8 *proto,
     691                 :            :                           struct in6_addr **daddr)
     692                 :            : {
     693         [ #  # ]:          0 :         if (opt->srcrt) {
     694                 :          0 :                 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
     695                 :            :                 /*
     696                 :            :                  * IPV6_RTHDRDSTOPTS is ignored
     697                 :            :                  * unless IPV6_RTHDR is set (RFC3542).
     698                 :            :                  */
     699         [ #  # ]:          0 :                 if (opt->dst0opt)
     700                 :          0 :                         ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
     701                 :            :         }
     702         [ #  # ]:          0 :         if (opt->hopopt)
     703                 :          0 :                 ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
     704                 :          0 : }
     705                 :            : EXPORT_SYMBOL(ipv6_push_nfrag_opts);
     706                 :            : 
     707                 :          0 : void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
     708                 :            : {
     709         [ #  # ]:          0 :         if (opt->dst1opt)
     710                 :          0 :                 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
     711                 :          0 : }
     712                 :            : 
     713                 :            : struct ipv6_txoptions *
     714                 :          0 : ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
     715                 :            : {
     716                 :            :         struct ipv6_txoptions *opt2;
     717                 :            : 
     718                 :          0 :         opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
     719         [ #  # ]:          0 :         if (opt2) {
     720                 :          0 :                 long dif = (char *)opt2 - (char *)opt;
     721                 :          0 :                 memcpy(opt2, opt, opt->tot_len);
     722         [ #  # ]:          0 :                 if (opt2->hopopt)
     723                 :          0 :                         *((char **)&opt2->hopopt) += dif;
     724         [ #  # ]:          0 :                 if (opt2->dst0opt)
     725                 :          0 :                         *((char **)&opt2->dst0opt) += dif;
     726         [ #  # ]:          0 :                 if (opt2->dst1opt)
     727                 :          0 :                         *((char **)&opt2->dst1opt) += dif;
     728         [ #  # ]:          0 :                 if (opt2->srcrt)
     729                 :          0 :                         *((char **)&opt2->srcrt) += dif;
     730                 :            :         }
     731                 :          0 :         return opt2;
     732                 :            : }
     733                 :            : EXPORT_SYMBOL_GPL(ipv6_dup_options);
     734                 :            : 
     735                 :          0 : static int ipv6_renew_option(void *ohdr,
     736                 :            :                              struct ipv6_opt_hdr __user *newopt, int newoptlen,
     737                 :            :                              int inherit,
     738                 :            :                              struct ipv6_opt_hdr **hdr,
     739                 :            :                              char **p)
     740                 :            : {
     741         [ #  # ]:          0 :         if (inherit) {
     742         [ #  # ]:          0 :                 if (ohdr) {
     743                 :          0 :                         memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr));
     744                 :          0 :                         *hdr = (struct ipv6_opt_hdr *)*p;
     745                 :          0 :                         *p += CMSG_ALIGN(ipv6_optlen(*hdr));
     746                 :            :                 }
     747                 :            :         } else {
     748         [ #  # ]:          0 :                 if (newopt) {
     749         [ #  # ]:          0 :                         if (copy_from_user(*p, newopt, newoptlen))
     750                 :            :                                 return -EFAULT;
     751                 :          0 :                         *hdr = (struct ipv6_opt_hdr *)*p;
     752         [ #  # ]:          0 :                         if (ipv6_optlen(*hdr) > newoptlen)
     753                 :            :                                 return -EINVAL;
     754                 :          0 :                         *p += CMSG_ALIGN(newoptlen);
     755                 :            :                 }
     756                 :            :         }
     757                 :            :         return 0;
     758                 :            : }
     759                 :            : 
     760                 :            : struct ipv6_txoptions *
     761                 :          0 : ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
     762                 :            :                    int newtype,
     763                 :            :                    struct ipv6_opt_hdr __user *newopt, int newoptlen)
     764                 :            : {
     765                 :            :         int tot_len = 0;
     766                 :            :         char *p;
     767                 :            :         struct ipv6_txoptions *opt2;
     768                 :            :         int err;
     769                 :            : 
     770         [ #  # ]:          0 :         if (opt) {
     771 [ #  # ][ #  # ]:          0 :                 if (newtype != IPV6_HOPOPTS && opt->hopopt)
     772                 :          0 :                         tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
     773 [ #  # ][ #  # ]:          0 :                 if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
     774                 :          0 :                         tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
     775 [ #  # ][ #  # ]:          0 :                 if (newtype != IPV6_RTHDR && opt->srcrt)
     776                 :          0 :                         tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
     777 [ #  # ][ #  # ]:          0 :                 if (newtype != IPV6_DSTOPTS && opt->dst1opt)
     778                 :          0 :                         tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
     779                 :            :         }
     780                 :            : 
     781         [ #  # ]:          0 :         if (newopt && newoptlen)
     782                 :          0 :                 tot_len += CMSG_ALIGN(newoptlen);
     783                 :            : 
     784         [ #  # ]:          0 :         if (!tot_len)
     785                 :            :                 return NULL;
     786                 :            : 
     787                 :          0 :         tot_len += sizeof(*opt2);
     788                 :          0 :         opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
     789         [ #  # ]:          0 :         if (!opt2)
     790                 :            :                 return ERR_PTR(-ENOBUFS);
     791                 :            : 
     792         [ #  # ]:          0 :         memset(opt2, 0, tot_len);
     793                 :            : 
     794                 :          0 :         opt2->tot_len = tot_len;
     795                 :          0 :         p = (char *)(opt2 + 1);
     796                 :            : 
     797         [ #  # ]:          0 :         err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen,
     798                 :            :                                 newtype != IPV6_HOPOPTS,
     799                 :            :                                 &opt2->hopopt, &p);
     800         [ #  # ]:          0 :         if (err)
     801                 :            :                 goto out;
     802                 :            : 
     803         [ #  # ]:          0 :         err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,
     804                 :            :                                 newtype != IPV6_RTHDRDSTOPTS,
     805                 :            :                                 &opt2->dst0opt, &p);
     806         [ #  # ]:          0 :         if (err)
     807                 :            :                 goto out;
     808                 :            : 
     809         [ #  # ]:          0 :         err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,
     810                 :            :                                 newtype != IPV6_RTHDR,
     811                 :          0 :                                 (struct ipv6_opt_hdr **)&opt2->srcrt, &p);
     812         [ #  # ]:          0 :         if (err)
     813                 :            :                 goto out;
     814                 :            : 
     815         [ #  # ]:          0 :         err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,
     816                 :            :                                 newtype != IPV6_DSTOPTS,
     817                 :            :                                 &opt2->dst1opt, &p);
     818         [ #  # ]:          0 :         if (err)
     819                 :            :                 goto out;
     820                 :            : 
     821 [ #  # ][ #  # ]:          0 :         opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
                 [ #  # ]
     822                 :          0 :                           (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
     823                 :          0 :                           (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);
     824         [ #  # ]:          0 :         opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);
     825                 :            : 
     826                 :          0 :         return opt2;
     827                 :            : out:
     828                 :          0 :         sock_kfree_s(sk, opt2, opt2->tot_len);
     829                 :          0 :         return ERR_PTR(err);
     830                 :            : }
     831                 :            : 
     832                 :          0 : struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
     833                 :            :                                           struct ipv6_txoptions *opt)
     834                 :            : {
     835                 :            :         /*
     836                 :            :          * ignore the dest before srcrt unless srcrt is being included.
     837                 :            :          * --yoshfuji
     838                 :            :          */
     839 [ #  # ][ #  # ]:          0 :         if (opt && opt->dst0opt && !opt->srcrt) {
                 [ #  # ]
     840         [ #  # ]:          0 :                 if (opt_space != opt) {
     841                 :          0 :                         memcpy(opt_space, opt, sizeof(*opt_space));
     842                 :            :                         opt = opt_space;
     843                 :            :                 }
     844                 :          0 :                 opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
     845                 :          0 :                 opt->dst0opt = NULL;
     846                 :            :         }
     847                 :            : 
     848                 :          0 :         return opt;
     849                 :            : }
     850                 :            : EXPORT_SYMBOL_GPL(ipv6_fixup_options);
     851                 :            : 
     852                 :            : /**
     853                 :            :  * fl6_update_dst - update flowi destination address with info given
     854                 :            :  *                  by srcrt option, if any.
     855                 :            :  *
     856                 :            :  * @fl6: flowi6 for which daddr is to be updated
     857                 :            :  * @opt: struct ipv6_txoptions in which to look for srcrt opt
     858                 :            :  * @orig: copy of original daddr address if modified
     859                 :            :  *
     860                 :            :  * Returns NULL if no txoptions or no srcrt, otherwise returns orig
     861                 :            :  * and initial value of fl6->daddr set in orig
     862                 :            :  */
     863                 :          0 : struct in6_addr *fl6_update_dst(struct flowi6 *fl6,
     864                 :            :                                 const struct ipv6_txoptions *opt,
     865                 :            :                                 struct in6_addr *orig)
     866                 :            : {
     867 [ -  + ][ #  # ]:          4 :         if (!opt || !opt->srcrt)
     868                 :            :                 return NULL;
     869                 :            : 
     870                 :          0 :         *orig = fl6->daddr;
     871                 :          0 :         fl6->daddr = *((struct rt0_hdr *)opt->srcrt)->addr;
     872                 :          0 :         return orig;
     873                 :            : }
     874                 :            : EXPORT_SYMBOL_GPL(fl6_update_dst);

Generated by: LCOV version 1.9