LCOV - code coverage report
Current view: top level - net/ipv4 - tunnel4.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 20 79 25.3 %
Date: 2022-04-01 14:35:51 Functions: 2 8 25.0 %
Branches: 6 46 13.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /* tunnel4.c: Generic IP tunnel transformer.
       3                 :            :  *
       4                 :            :  * Copyright (C) 2003 David S. Miller (davem@redhat.com)
       5                 :            :  */
       6                 :            : 
       7                 :            : #include <linux/init.h>
       8                 :            : #include <linux/module.h>
       9                 :            : #include <linux/mutex.h>
      10                 :            : #include <linux/mpls.h>
      11                 :            : #include <linux/netdevice.h>
      12                 :            : #include <linux/skbuff.h>
      13                 :            : #include <linux/slab.h>
      14                 :            : #include <net/icmp.h>
      15                 :            : #include <net/ip.h>
      16                 :            : #include <net/protocol.h>
      17                 :            : #include <net/xfrm.h>
      18                 :            : 
      19                 :            : static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly;
      20                 :            : static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly;
      21                 :            : static struct xfrm_tunnel __rcu *tunnelmpls4_handlers __read_mostly;
      22                 :            : static DEFINE_MUTEX(tunnel4_mutex);
      23                 :            : 
      24                 :         42 : static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family)
      25                 :            : {
      26                 :         42 :         return (family == AF_INET) ? &tunnel4_handlers :
      27   [ -  -  -  + ]:         21 :                 (family == AF_INET6) ? &tunnel64_handlers :
      28                 :            :                 &tunnelmpls4_handlers;
      29                 :            : }
      30                 :            : 
      31                 :         42 : int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
      32                 :            : {
      33                 :         42 :         struct xfrm_tunnel __rcu **pprev;
      34                 :         42 :         struct xfrm_tunnel *t;
      35                 :            : 
      36                 :         42 :         int ret = -EEXIST;
      37                 :         42 :         int priority = handler->priority;
      38                 :            : 
      39                 :         42 :         mutex_lock(&tunnel4_mutex);
      40                 :            : 
      41         [ +  + ]:         42 :         for (pprev = fam_handlers(family);
      42         [ -  + ]:         42 :              (t = rcu_dereference_protected(*pprev,
      43                 :            :                         lockdep_is_held(&tunnel4_mutex))) != NULL;
      44                 :          0 :              pprev = &t->next) {
      45         [ #  # ]:          0 :                 if (t->priority > priority)
      46                 :            :                         break;
      47         [ #  # ]:          0 :                 if (t->priority == priority)
      48                 :          0 :                         goto err;
      49                 :            :         }
      50                 :            : 
      51                 :         42 :         handler->next = *pprev;
      52                 :         42 :         rcu_assign_pointer(*pprev, handler);
      53                 :            : 
      54                 :         42 :         ret = 0;
      55                 :            : 
      56                 :         42 : err:
      57                 :         42 :         mutex_unlock(&tunnel4_mutex);
      58                 :            : 
      59                 :         42 :         return ret;
      60                 :            : }
      61                 :            : EXPORT_SYMBOL(xfrm4_tunnel_register);
      62                 :            : 
      63                 :          0 : int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
      64                 :            : {
      65                 :          0 :         struct xfrm_tunnel __rcu **pprev;
      66                 :          0 :         struct xfrm_tunnel *t;
      67                 :          0 :         int ret = -ENOENT;
      68                 :            : 
      69                 :          0 :         mutex_lock(&tunnel4_mutex);
      70                 :            : 
      71         [ #  # ]:          0 :         for (pprev = fam_handlers(family);
      72         [ #  # ]:          0 :              (t = rcu_dereference_protected(*pprev,
      73                 :            :                         lockdep_is_held(&tunnel4_mutex))) != NULL;
      74                 :          0 :              pprev = &t->next) {
      75         [ #  # ]:          0 :                 if (t == handler) {
      76                 :          0 :                         *pprev = handler->next;
      77                 :          0 :                         ret = 0;
      78                 :          0 :                         break;
      79                 :            :                 }
      80                 :            :         }
      81                 :            : 
      82                 :          0 :         mutex_unlock(&tunnel4_mutex);
      83                 :            : 
      84                 :          0 :         synchronize_net();
      85                 :            : 
      86                 :          0 :         return ret;
      87                 :            : }
      88                 :            : EXPORT_SYMBOL(xfrm4_tunnel_deregister);
      89                 :            : 
      90                 :            : #define for_each_tunnel_rcu(head, handler)              \
      91                 :            :         for (handler = rcu_dereference(head);           \
      92                 :            :              handler != NULL;                           \
      93                 :            :              handler = rcu_dereference(handler->next))       \
      94                 :            : 
      95                 :          0 : static int tunnel4_rcv(struct sk_buff *skb)
      96                 :            : {
      97                 :          0 :         struct xfrm_tunnel *handler;
      98                 :            : 
      99         [ #  # ]:          0 :         if (!pskb_may_pull(skb, sizeof(struct iphdr)))
     100                 :          0 :                 goto drop;
     101                 :            : 
     102         [ #  # ]:          0 :         for_each_tunnel_rcu(tunnel4_handlers, handler)
     103         [ #  # ]:          0 :                 if (!handler->handler(skb))
     104                 :            :                         return 0;
     105                 :            : 
     106                 :          0 :         icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
     107                 :            : 
     108                 :          0 : drop:
     109                 :          0 :         kfree_skb(skb);
     110                 :          0 :         return 0;
     111                 :            : }
     112                 :            : 
     113                 :            : #if IS_ENABLED(CONFIG_IPV6)
     114                 :          0 : static int tunnel64_rcv(struct sk_buff *skb)
     115                 :            : {
     116                 :          0 :         struct xfrm_tunnel *handler;
     117                 :            : 
     118         [ #  # ]:          0 :         if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
     119                 :          0 :                 goto drop;
     120                 :            : 
     121         [ #  # ]:          0 :         for_each_tunnel_rcu(tunnel64_handlers, handler)
     122         [ #  # ]:          0 :                 if (!handler->handler(skb))
     123                 :            :                         return 0;
     124                 :            : 
     125                 :          0 :         icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
     126                 :            : 
     127                 :          0 : drop:
     128                 :          0 :         kfree_skb(skb);
     129                 :          0 :         return 0;
     130                 :            : }
     131                 :            : #endif
     132                 :            : 
     133                 :            : #if IS_ENABLED(CONFIG_MPLS)
     134                 :            : static int tunnelmpls4_rcv(struct sk_buff *skb)
     135                 :            : {
     136                 :            :         struct xfrm_tunnel *handler;
     137                 :            : 
     138                 :            :         if (!pskb_may_pull(skb, sizeof(struct mpls_label)))
     139                 :            :                 goto drop;
     140                 :            : 
     141                 :            :         for_each_tunnel_rcu(tunnelmpls4_handlers, handler)
     142                 :            :                 if (!handler->handler(skb))
     143                 :            :                         return 0;
     144                 :            : 
     145                 :            :         icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
     146                 :            : 
     147                 :            : drop:
     148                 :            :         kfree_skb(skb);
     149                 :            :         return 0;
     150                 :            : }
     151                 :            : #endif
     152                 :            : 
     153                 :          0 : static int tunnel4_err(struct sk_buff *skb, u32 info)
     154                 :            : {
     155                 :          0 :         struct xfrm_tunnel *handler;
     156                 :            : 
     157         [ #  # ]:          0 :         for_each_tunnel_rcu(tunnel4_handlers, handler)
     158         [ #  # ]:          0 :                 if (!handler->err_handler(skb, info))
     159                 :            :                         return 0;
     160                 :            : 
     161                 :            :         return -ENOENT;
     162                 :            : }
     163                 :            : 
     164                 :            : #if IS_ENABLED(CONFIG_IPV6)
     165                 :          0 : static int tunnel64_err(struct sk_buff *skb, u32 info)
     166                 :            : {
     167                 :          0 :         struct xfrm_tunnel *handler;
     168                 :            : 
     169         [ #  # ]:          0 :         for_each_tunnel_rcu(tunnel64_handlers, handler)
     170         [ #  # ]:          0 :                 if (!handler->err_handler(skb, info))
     171                 :            :                         return 0;
     172                 :            : 
     173                 :            :         return -ENOENT;
     174                 :            : }
     175                 :            : #endif
     176                 :            : 
     177                 :            : #if IS_ENABLED(CONFIG_MPLS)
     178                 :            : static int tunnelmpls4_err(struct sk_buff *skb, u32 info)
     179                 :            : {
     180                 :            :         struct xfrm_tunnel *handler;
     181                 :            : 
     182                 :            :         for_each_tunnel_rcu(tunnelmpls4_handlers, handler)
     183                 :            :                 if (!handler->err_handler(skb, info))
     184                 :            :                         return 0;
     185                 :            : 
     186                 :            :         return -ENOENT;
     187                 :            : }
     188                 :            : #endif
     189                 :            : 
     190                 :            : static const struct net_protocol tunnel4_protocol = {
     191                 :            :         .handler        =       tunnel4_rcv,
     192                 :            :         .err_handler    =       tunnel4_err,
     193                 :            :         .no_policy      =       1,
     194                 :            :         .netns_ok       =       1,
     195                 :            : };
     196                 :            : 
     197                 :            : #if IS_ENABLED(CONFIG_IPV6)
     198                 :            : static const struct net_protocol tunnel64_protocol = {
     199                 :            :         .handler        =       tunnel64_rcv,
     200                 :            :         .err_handler    =       tunnel64_err,
     201                 :            :         .no_policy      =       1,
     202                 :            :         .netns_ok       =       1,
     203                 :            : };
     204                 :            : #endif
     205                 :            : 
     206                 :            : #if IS_ENABLED(CONFIG_MPLS)
     207                 :            : static const struct net_protocol tunnelmpls4_protocol = {
     208                 :            :         .handler        =       tunnelmpls4_rcv,
     209                 :            :         .err_handler    =       tunnelmpls4_err,
     210                 :            :         .no_policy      =       1,
     211                 :            :         .netns_ok       =       1,
     212                 :            : };
     213                 :            : #endif
     214                 :            : 
     215                 :         21 : static int __init tunnel4_init(void)
     216                 :            : {
     217         [ -  + ]:         21 :         if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP))
     218                 :          0 :                 goto err;
     219                 :            : #if IS_ENABLED(CONFIG_IPV6)
     220         [ -  + ]:         21 :         if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) {
     221                 :          0 :                 inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP);
     222                 :          0 :                 goto err;
     223                 :            :         }
     224                 :            : #endif
     225                 :            : #if IS_ENABLED(CONFIG_MPLS)
     226                 :            :         if (inet_add_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS)) {
     227                 :            :                 inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP);
     228                 :            : #if IS_ENABLED(CONFIG_IPV6)
     229                 :            :                 inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6);
     230                 :            : #endif
     231                 :            :                 goto err;
     232                 :            :         }
     233                 :            : #endif
     234                 :            :         return 0;
     235                 :            : 
     236                 :          0 : err:
     237                 :          0 :         pr_err("%s: can't add protocol\n", __func__);
     238                 :          0 :         return -EAGAIN;
     239                 :            : }
     240                 :            : 
     241                 :          0 : static void __exit tunnel4_fini(void)
     242                 :            : {
     243                 :            : #if IS_ENABLED(CONFIG_MPLS)
     244                 :            :         if (inet_del_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS))
     245                 :            :                 pr_err("tunnelmpls4 close: can't remove protocol\n");
     246                 :            : #endif
     247                 :            : #if IS_ENABLED(CONFIG_IPV6)
     248         [ #  # ]:          0 :         if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6))
     249                 :          0 :                 pr_err("tunnel64 close: can't remove protocol\n");
     250                 :            : #endif
     251         [ #  # ]:          0 :         if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP))
     252                 :          0 :                 pr_err("tunnel4 close: can't remove protocol\n");
     253                 :          0 : }
     254                 :            : 
     255                 :            : module_init(tunnel4_init);
     256                 :            : module_exit(tunnel4_fini);
     257                 :            : MODULE_LICENSE("GPL");

Generated by: LCOV version 1.14