LCOV - code coverage report
Current view: top level - net/ipv6 - ip6_input.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 55 83 66.3 %
Date: 2014-04-07 Functions: 5 5 100.0 %
Branches: 42 109 38.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  *      IPv6 input
       3                 :            :  *      Linux INET6 implementation
       4                 :            :  *
       5                 :            :  *      Authors:
       6                 :            :  *      Pedro Roque             <roque@di.fc.ul.pt>
       7                 :            :  *      Ian P. Morris           <I.P.Morris@soton.ac.uk>
       8                 :            :  *
       9                 :            :  *      Based in linux/net/ipv4/ip_input.c
      10                 :            :  *
      11                 :            :  *      This program is free software; you can redistribute it and/or
      12                 :            :  *      modify it under the terms of the GNU General Public License
      13                 :            :  *      as published by the Free Software Foundation; either version
      14                 :            :  *      2 of the License, or (at your option) any later version.
      15                 :            :  */
      16                 :            : /* Changes
      17                 :            :  *
      18                 :            :  *      Mitsuru KANDA @USAGI and
      19                 :            :  *      YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs().
      20                 :            :  */
      21                 :            : 
      22                 :            : #include <linux/errno.h>
      23                 :            : #include <linux/types.h>
      24                 :            : #include <linux/socket.h>
      25                 :            : #include <linux/sockios.h>
      26                 :            : #include <linux/net.h>
      27                 :            : #include <linux/netdevice.h>
      28                 :            : #include <linux/in6.h>
      29                 :            : #include <linux/icmpv6.h>
      30                 :            : #include <linux/mroute6.h>
      31                 :            : #include <linux/slab.h>
      32                 :            : 
      33                 :            : #include <linux/netfilter.h>
      34                 :            : #include <linux/netfilter_ipv6.h>
      35                 :            : 
      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                 :            : #include <net/xfrm.h>
      47                 :            : #include <net/inet_ecn.h>
      48                 :            : 
      49                 :            : 
      50                 :          0 : int ip6_rcv_finish(struct sk_buff *skb)
      51                 :            : {
      52 [ +  - ][ +  - ]:        111 :         if (sysctl_ip_early_demux && !skb_dst(skb)) {
      53                 :            :                 const struct inet6_protocol *ipprot;
      54                 :            : 
      55                 :        111 :                 ipprot = rcu_dereference(inet6_protos[ipv6_hdr(skb)->nexthdr]);
      56 [ +  - ][ -  + ]:        111 :                 if (ipprot && ipprot->early_demux)
      57                 :          0 :                         ipprot->early_demux(skb);
      58                 :            :         }
      59         [ +  - ]:        111 :         if (!skb_dst(skb))
      60                 :        111 :                 ip6_route_input(skb);
      61                 :            : 
      62                 :        111 :         return dst_input(skb);
      63                 :            : }
      64                 :            : 
      65                 :          0 : int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
      66                 :            : {
      67                 :            :         const struct ipv6hdr *hdr;
      68                 :            :         u32             pkt_len;
      69                 :            :         struct inet6_dev *idev;
      70                 :        111 :         struct net *net = dev_net(skb->dev);
      71                 :            : 
      72         [ -  + ]:        111 :         if (skb->pkt_type == PACKET_OTHERHOST) {
      73                 :          0 :                 kfree_skb(skb);
      74                 :          0 :                 return NET_RX_DROP;
      75                 :            :         }
      76                 :            : 
      77                 :            :         rcu_read_lock();
      78                 :            : 
      79                 :        111 :         idev = __in6_dev_get(skb->dev);
      80                 :            : 
      81         [ +  - ]:        111 :         IP6_UPD_PO_STATS_BH(net, idev, IPSTATS_MIB_IN, skb->len);
      82                 :            : 
      83 [ +  - ][ +  - ]:        111 :         if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL ||
      84         [ -  + ]:        111 :             !idev || unlikely(idev->cnf.disable_ipv6)) {
      85         [ #  # ]:          0 :                 IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDISCARDS);
      86                 :            :                 goto drop;
      87                 :            :         }
      88                 :            : 
      89                 :        111 :         memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
      90                 :            : 
      91                 :            :         /*
      92                 :            :          * Store incoming device index. When the packet will
      93                 :            :          * be queued, we cannot refer to skb->dev anymore.
      94                 :            :          *
      95                 :            :          * BTW, when we send a packet for our own local address on a
      96                 :            :          * non-loopback interface (e.g. ethX), it is being delivered
      97                 :            :          * via the loopback interface (lo) here; skb->dev = loopback_dev.
      98                 :            :          * It, however, should be considered as if it is being
      99                 :            :          * arrived via the sending interface (ethX), because of the
     100                 :            :          * nature of scoping architecture. --yoshfuji
     101                 :            :          */
     102         [ -  + ]:        111 :         IP6CB(skb)->iif = skb_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex;
     103                 :            : 
     104         [ +  - ]:        111 :         if (unlikely(!pskb_may_pull(skb, sizeof(*hdr))))
     105                 :            :                 goto err;
     106                 :            : 
     107                 :            :         hdr = ipv6_hdr(skb);
     108                 :            : 
     109         [ +  - ]:        111 :         if (hdr->version != 6)
     110                 :            :                 goto err;
     111                 :            : 
     112 [ +  - ][ -  + ]:        333 :         IP6_ADD_STATS_BH(dev_net(dev), idev,
                 [ -  + ]
     113                 :            :                          IPSTATS_MIB_NOECTPKTS +
     114                 :            :                                 (ipv6_get_dsfield(hdr) & INET_ECN_MASK),
     115                 :            :                          max_t(unsigned short, 1, skb_shinfo(skb)->gso_segs));
     116                 :            :         /*
     117                 :            :          * RFC4291 2.5.3
     118                 :            :          * A packet received on an interface with a destination address
     119                 :            :          * of loopback must be dropped.
     120                 :            :          */
     121 [ +  - ][ +  - ]:        111 :         if (!(dev->flags & IFF_LOOPBACK) &&
     122                 :        222 :             ipv6_addr_loopback(&hdr->daddr))
     123                 :            :                 goto err;
     124                 :            : 
     125                 :            :         /* RFC4291 Errata ID: 3480
     126                 :            :          * Interface-Local scope spans only a single interface on a
     127                 :            :          * node and is useful only for loopback transmission of
     128                 :            :          * multicast.  Packets with interface-local scope received
     129                 :            :          * from another node must be discarded.
     130                 :            :          */
     131 [ +  - ][ +  - ]:        111 :         if (!(skb->pkt_type == PACKET_LOOPBACK ||
     132         [ +  - ]:        111 :               dev->flags & IFF_LOOPBACK) &&
     133         [ +  - ]:        111 :             ipv6_addr_is_multicast(&hdr->daddr) &&
     134                 :        111 :             IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1)
     135                 :            :                 goto err;
     136                 :            : 
     137                 :            :         /* RFC4291 2.7
     138                 :            :          * Nodes must not originate a packet to a multicast address whose scope
     139                 :            :          * field contains the reserved value 0; if such a packet is received, it
     140                 :            :          * must be silently dropped.
     141                 :            :          */
     142 [ +  - ][ +  - ]:        111 :         if (ipv6_addr_is_multicast(&hdr->daddr) &&
     143                 :        111 :             IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0)
     144                 :            :                 goto err;
     145                 :            : 
     146                 :            :         /*
     147                 :            :          * RFC4291 2.7
     148                 :            :          * Multicast addresses must not be used as source addresses in IPv6
     149                 :            :          * packets or appear in any Routing header.
     150                 :            :          */
     151         [ +  - ]:        111 :         if (ipv6_addr_is_multicast(&hdr->saddr))
     152                 :            :                 goto err;
     153                 :            : 
     154                 :        111 :         skb->transport_header = skb->network_header + sizeof(*hdr);
     155                 :        111 :         IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
     156                 :            : 
     157         [ -  + ]:        111 :         pkt_len = ntohs(hdr->payload_len);
     158                 :            : 
     159                 :            :         /* pkt_len may be zero if Jumbo payload option is present */
     160 [ -  + ][ #  # ]:        111 :         if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
     161         [ -  + ]:        111 :                 if (pkt_len + sizeof(struct ipv6hdr) > skb->len) {
     162         [ #  # ]:          0 :                         IP6_INC_STATS_BH(net,
     163                 :            :                                          idev, IPSTATS_MIB_INTRUNCATEDPKTS);
     164                 :            :                         goto drop;
     165                 :            :                 }
     166         [ -  + ]:        111 :                 if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) {
     167         [ #  # ]:          0 :                         IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
     168                 :            :                         goto drop;
     169                 :            :                 }
     170                 :            :                 hdr = ipv6_hdr(skb);
     171                 :            :         }
     172                 :            : 
     173         [ -  + ]:        111 :         if (hdr->nexthdr == NEXTHDR_HOP) {
     174         [ #  # ]:          0 :                 if (ipv6_parse_hopopts(skb) < 0) {
     175         [ #  # ]:          0 :                         IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
     176                 :            :                         rcu_read_unlock();
     177                 :          0 :                         return NET_RX_DROP;
     178                 :            :                 }
     179                 :            :         }
     180                 :            : 
     181                 :            :         rcu_read_unlock();
     182                 :            : 
     183                 :            :         /* Must drop socket now because of tproxy. */
     184                 :            :         skb_orphan(skb);
     185                 :            : 
     186                 :        111 :         return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, dev, NULL,
     187                 :            :                        ip6_rcv_finish);
     188                 :            : err:
     189            [ - ]:          0 :         IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
     190                 :            : drop:
     191                 :            :         rcu_read_unlock();
     192                 :          0 :         kfree_skb(skb);
     193                 :          0 :         return NET_RX_DROP;
     194                 :            : }
     195                 :            : 
     196                 :            : /*
     197                 :            :  *      Deliver the packet to the host
     198                 :            :  */
     199                 :            : 
     200                 :            : 
     201                 :          0 : static int ip6_input_finish(struct sk_buff *skb)
     202                 :            : {
     203                 :            :         struct net *net = dev_net(skb_dst(skb)->dev);
     204                 :            :         const struct inet6_protocol *ipprot;
     205                 :            :         struct inet6_dev *idev;
     206                 :            :         unsigned int nhoff;
     207                 :            :         int nexthdr;
     208                 :            :         bool raw;
     209                 :            : 
     210                 :            :         /*
     211                 :            :          *      Parse extension headers
     212                 :            :          */
     213                 :            : 
     214                 :            :         rcu_read_lock();
     215                 :            : resubmit:
     216                 :            :         idev = ip6_dst_idev(skb_dst(skb));
     217         [ +  - ]:         93 :         if (!pskb_pull(skb, skb_transport_offset(skb)))
     218                 :            :                 goto discard;
     219                 :         93 :         nhoff = IP6CB(skb)->nhoff;
     220                 :         93 :         nexthdr = skb_network_header(skb)[nhoff];
     221                 :            : 
     222                 :         93 :         raw = raw6_local_deliver(skb, nexthdr);
     223         [ +  - ]:         93 :         if ((ipprot = rcu_dereference(inet6_protos[nexthdr])) != NULL) {
     224                 :            :                 int ret;
     225                 :            : 
     226         [ +  - ]:         93 :                 if (ipprot->flags & INET6_PROTO_FINAL) {
     227                 :            :                         const struct ipv6hdr *hdr;
     228                 :            : 
     229                 :            :                         /* Free reference early: we don't need it any more,
     230                 :            :                            and it may hold ip_conntrack module loaded
     231                 :            :                            indefinitely. */
     232                 :            :                         nf_reset(skb);
     233                 :            : 
     234                 :            :                         skb_postpull_rcsum(skb, skb_network_header(skb),
     235                 :            :                                            skb_network_header_len(skb));
     236                 :            :                         hdr = ipv6_hdr(skb);
     237   [ +  -  -  + ]:        186 :                         if (ipv6_addr_is_multicast(&hdr->daddr) &&
     238                 :         93 :                             !ipv6_chk_mcast_addr(skb->dev, &hdr->daddr,
     239         [ #  # ]:          0 :                             &hdr->saddr) &&
     240                 :            :                             !ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb)))
     241                 :            :                                 goto discard;
     242                 :            :                 }
     243 [ -  + ][ #  # ]:         93 :                 if (!(ipprot->flags & INET6_PROTO_NOPOLICY) &&
     244                 :            :                     !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
     245                 :            :                         goto discard;
     246                 :            : 
     247                 :         93 :                 ret = ipprot->handler(skb);
     248         [ -  + ]:         93 :                 if (ret > 0)
     249                 :            :                         goto resubmit;
     250         [ +  - ]:         93 :                 else if (ret == 0)
     251         [ +  - ]:         93 :                         IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS);
     252                 :            :         } else {
     253         [ #  # ]:          0 :                 if (!raw) {
     254         [ #  # ]:          0 :                         if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
     255         [ #  # ]:          0 :                                 IP6_INC_STATS_BH(net, idev,
     256                 :            :                                                  IPSTATS_MIB_INUNKNOWNPROTOS);
     257                 :          0 :                                 icmpv6_send(skb, ICMPV6_PARAMPROB,
     258                 :            :                                             ICMPV6_UNK_NEXTHDR, nhoff);
     259                 :            :                         }
     260                 :          0 :                         kfree_skb(skb);
     261                 :            :                 } else {
     262         [ #  # ]:          0 :                         IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS);
     263                 :          0 :                         consume_skb(skb);
     264                 :            :                 }
     265                 :            :         }
     266                 :            :         rcu_read_unlock();
     267                 :         93 :         return 0;
     268                 :            : 
     269                 :            : discard:
     270         [ #  # ]:          0 :         IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDISCARDS);
     271                 :            :         rcu_read_unlock();
     272                 :          0 :         kfree_skb(skb);
     273                 :          0 :         return 0;
     274                 :            : }
     275                 :            : 
     276                 :            : 
     277                 :          0 : int ip6_input(struct sk_buff *skb)
     278                 :            : {
     279                 :        186 :         return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_IN, skb, skb->dev, NULL,
     280                 :            :                        ip6_input_finish);
     281                 :            : }
     282                 :            : 
     283                 :          0 : int ip6_mc_input(struct sk_buff *skb)
     284                 :            : {
     285                 :            :         const struct ipv6hdr *hdr;
     286                 :            :         bool deliver;
     287                 :            : 
     288         [ +  - ]:        111 :         IP6_UPD_PO_STATS_BH(dev_net(skb_dst(skb)->dev),
     289                 :            :                          ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INMCAST,
     290                 :            :                          skb->len);
     291                 :            : 
     292                 :            :         hdr = ipv6_hdr(skb);
     293                 :        111 :         deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL);
     294                 :            : 
     295                 :            : #ifdef CONFIG_IPV6_MROUTE
     296                 :            :         /*
     297                 :            :          *      IPv6 multicast router mode is now supported ;)
     298                 :            :          */
     299                 :            :         if (dev_net(skb->dev)->ipv6.devconf_all->mc_forwarding &&
     300                 :            :             !(ipv6_addr_type(&hdr->daddr) &
     301                 :            :               (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL)) &&
     302                 :            :             likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) {
     303                 :            :                 /*
     304                 :            :                  * Okay, we try to forward - split and duplicate
     305                 :            :                  * packets.
     306                 :            :                  */
     307                 :            :                 struct sk_buff *skb2;
     308                 :            :                 struct inet6_skb_parm *opt = IP6CB(skb);
     309                 :            : 
     310                 :            :                 /* Check for MLD */
     311                 :            :                 if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) {
     312                 :            :                         /* Check if this is a mld message */
     313                 :            :                         u8 nexthdr = hdr->nexthdr;
     314                 :            :                         __be16 frag_off;
     315                 :            :                         int offset;
     316                 :            : 
     317                 :            :                         /* Check if the value of Router Alert
     318                 :            :                          * is for MLD (0x0000).
     319                 :            :                          */
     320                 :            :                         if (opt->ra == htons(IPV6_OPT_ROUTERALERT_MLD)) {
     321                 :            :                                 deliver = false;
     322                 :            : 
     323                 :            :                                 if (!ipv6_ext_hdr(nexthdr)) {
     324                 :            :                                         /* BUG */
     325                 :            :                                         goto out;
     326                 :            :                                 }
     327                 :            :                                 offset = ipv6_skip_exthdr(skb, sizeof(*hdr),
     328                 :            :                                                           &nexthdr, &frag_off);
     329                 :            :                                 if (offset < 0)
     330                 :            :                                         goto out;
     331                 :            : 
     332                 :            :                                 if (!ipv6_is_mld(skb, nexthdr, offset))
     333                 :            :                                         goto out;
     334                 :            : 
     335                 :            :                                 deliver = true;
     336                 :            :                         }
     337                 :            :                         /* unknown RA - process it normally */
     338                 :            :                 }
     339                 :            : 
     340                 :            :                 if (deliver)
     341                 :            :                         skb2 = skb_clone(skb, GFP_ATOMIC);
     342                 :            :                 else {
     343                 :            :                         skb2 = skb;
     344                 :            :                         skb = NULL;
     345                 :            :                 }
     346                 :            : 
     347                 :            :                 if (skb2) {
     348                 :            :                         ip6_mr_input(skb2);
     349                 :            :                 }
     350                 :            :         }
     351                 :            : out:
     352                 :            : #endif
     353         [ +  + ]:        111 :         if (likely(deliver))
     354                 :         93 :                 ip6_input(skb);
     355                 :            :         else {
     356                 :            :                 /* discard */
     357                 :         18 :                 kfree_skb(skb);
     358                 :            :         }
     359                 :            : 
     360                 :        111 :         return 0;
     361                 :            : }

Generated by: LCOV version 1.9