LCOV - code coverage report
Current view: top level - net/ipv4 - xfrm4_policy.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 25 96 26.0 %
Date: 2022-04-01 14:17:54 Functions: 4 13 30.8 %
Branches: 4 28 14.3 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * xfrm4_policy.c
       4                 :            :  *
       5                 :            :  * Changes:
       6                 :            :  *      Kazunori MIYAZAWA @USAGI
       7                 :            :  *      YOSHIFUJI Hideaki @USAGI
       8                 :            :  *              Split up af-specific portion
       9                 :            :  *
      10                 :            :  */
      11                 :            : 
      12                 :            : #include <linux/err.h>
      13                 :            : #include <linux/kernel.h>
      14                 :            : #include <linux/inetdevice.h>
      15                 :            : #include <net/dst.h>
      16                 :            : #include <net/xfrm.h>
      17                 :            : #include <net/ip.h>
      18                 :            : #include <net/l3mdev.h>
      19                 :            : 
      20                 :            : static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
      21                 :            :                                             int tos, int oif,
      22                 :            :                                             const xfrm_address_t *saddr,
      23                 :            :                                             const xfrm_address_t *daddr,
      24                 :            :                                             u32 mark)
      25                 :            : {
      26                 :            :         struct rtable *rt;
      27                 :            : 
      28                 :            :         memset(fl4, 0, sizeof(*fl4));
      29                 :            :         fl4->daddr = daddr->a4;
      30                 :            :         fl4->flowi4_tos = tos;
      31                 :            :         fl4->flowi4_oif = l3mdev_master_ifindex_by_index(net, oif);
      32                 :            :         fl4->flowi4_mark = mark;
      33                 :            :         if (saddr)
      34                 :            :                 fl4->saddr = saddr->a4;
      35                 :            : 
      36                 :            :         fl4->flowi4_flags = FLOWI_FLAG_SKIP_NH_OIF;
      37                 :            : 
      38                 :            :         rt = __ip_route_output_key(net, fl4);
      39                 :            :         if (!IS_ERR(rt))
      40                 :            :                 return &rt->dst;
      41                 :            : 
      42                 :            :         return ERR_CAST(rt);
      43                 :            : }
      44                 :            : 
      45                 :          0 : static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, int oif,
      46                 :            :                                           const xfrm_address_t *saddr,
      47                 :            :                                           const xfrm_address_t *daddr,
      48                 :            :                                           u32 mark)
      49                 :            : {
      50                 :          0 :         struct flowi4 fl4;
      51                 :            : 
      52                 :          0 :         return __xfrm4_dst_lookup(net, &fl4, tos, oif, saddr, daddr, mark);
      53                 :            : }
      54                 :            : 
      55                 :          0 : static int xfrm4_get_saddr(struct net *net, int oif,
      56                 :            :                            xfrm_address_t *saddr, xfrm_address_t *daddr,
      57                 :            :                            u32 mark)
      58                 :            : {
      59                 :          0 :         struct dst_entry *dst;
      60                 :          0 :         struct flowi4 fl4;
      61                 :            : 
      62                 :          0 :         dst = __xfrm4_dst_lookup(net, &fl4, 0, oif, NULL, daddr, mark);
      63         [ #  # ]:          0 :         if (IS_ERR(dst))
      64                 :            :                 return -EHOSTUNREACH;
      65                 :            : 
      66                 :          0 :         saddr->a4 = fl4.saddr;
      67                 :          0 :         dst_release(dst);
      68                 :          0 :         return 0;
      69                 :            : }
      70                 :            : 
      71                 :          0 : static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
      72                 :            :                           const struct flowi *fl)
      73                 :            : {
      74                 :          0 :         struct rtable *rt = (struct rtable *)xdst->route;
      75                 :          0 :         const struct flowi4 *fl4 = &fl->u.ip4;
      76                 :            : 
      77                 :          0 :         xdst->u.rt.rt_iif = fl4->flowi4_iif;
      78                 :            : 
      79                 :          0 :         xdst->u.dst.dev = dev;
      80                 :          0 :         dev_hold(dev);
      81                 :            : 
      82                 :            :         /* Sheit... I remember I did this right. Apparently,
      83                 :            :          * it was magically lost, so this code needs audit */
      84                 :          0 :         xdst->u.rt.rt_is_input = rt->rt_is_input;
      85                 :          0 :         xdst->u.rt.rt_flags = rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST |
      86                 :            :                                               RTCF_LOCAL);
      87                 :          0 :         xdst->u.rt.rt_type = rt->rt_type;
      88                 :          0 :         xdst->u.rt.rt_uses_gateway = rt->rt_uses_gateway;
      89                 :          0 :         xdst->u.rt.rt_gw_family = rt->rt_gw_family;
      90         [ #  # ]:          0 :         if (rt->rt_gw_family == AF_INET)
      91                 :          0 :                 xdst->u.rt.rt_gw4 = rt->rt_gw4;
      92         [ #  # ]:          0 :         else if (rt->rt_gw_family == AF_INET6)
      93                 :          0 :                 xdst->u.rt.rt_gw6 = rt->rt_gw6;
      94                 :          0 :         xdst->u.rt.rt_pmtu = rt->rt_pmtu;
      95                 :          0 :         xdst->u.rt.rt_mtu_locked = rt->rt_mtu_locked;
      96                 :          0 :         INIT_LIST_HEAD(&xdst->u.rt.rt_uncached);
      97                 :          0 :         rt_add_uncached_list(&xdst->u.rt);
      98                 :            : 
      99                 :          0 :         return 0;
     100                 :            : }
     101                 :            : 
     102                 :          0 : static void xfrm4_update_pmtu(struct dst_entry *dst, struct sock *sk,
     103                 :            :                               struct sk_buff *skb, u32 mtu,
     104                 :            :                               bool confirm_neigh)
     105                 :            : {
     106                 :          0 :         struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
     107                 :          0 :         struct dst_entry *path = xdst->route;
     108                 :            : 
     109                 :          0 :         path->ops->update_pmtu(path, sk, skb, mtu, confirm_neigh);
     110                 :          0 : }
     111                 :            : 
     112                 :          0 : static void xfrm4_redirect(struct dst_entry *dst, struct sock *sk,
     113                 :            :                            struct sk_buff *skb)
     114                 :            : {
     115                 :          0 :         struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
     116                 :          0 :         struct dst_entry *path = xdst->route;
     117                 :            : 
     118                 :          0 :         path->ops->redirect(path, sk, skb);
     119                 :          0 : }
     120                 :            : 
     121                 :          0 : static void xfrm4_dst_destroy(struct dst_entry *dst)
     122                 :            : {
     123                 :          0 :         struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
     124                 :            : 
     125         [ #  # ]:          0 :         dst_destroy_metrics_generic(dst);
     126         [ #  # ]:          0 :         if (xdst->u.rt.rt_uncached_list)
     127                 :          0 :                 rt_del_uncached_list(&xdst->u.rt);
     128                 :          0 :         xfrm_dst_destroy(xdst);
     129                 :          0 : }
     130                 :            : 
     131                 :          0 : static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
     132                 :            :                              int unregister)
     133                 :            : {
     134         [ #  # ]:          0 :         if (!unregister)
     135                 :            :                 return;
     136                 :            : 
     137                 :          0 :         xfrm_dst_ifdown(dst, dev);
     138                 :            : }
     139                 :            : 
     140                 :            : static struct dst_ops xfrm4_dst_ops_template = {
     141                 :            :         .family =               AF_INET,
     142                 :            :         .update_pmtu =          xfrm4_update_pmtu,
     143                 :            :         .redirect =             xfrm4_redirect,
     144                 :            :         .cow_metrics =          dst_cow_metrics_generic,
     145                 :            :         .destroy =              xfrm4_dst_destroy,
     146                 :            :         .ifdown =               xfrm4_dst_ifdown,
     147                 :            :         .local_out =            __ip_local_out,
     148                 :            :         .gc_thresh =            32768,
     149                 :            : };
     150                 :            : 
     151                 :            : static const struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
     152                 :            :         .dst_ops =              &xfrm4_dst_ops_template,
     153                 :            :         .dst_lookup =           xfrm4_dst_lookup,
     154                 :            :         .get_saddr =            xfrm4_get_saddr,
     155                 :            :         .fill_dst =             xfrm4_fill_dst,
     156                 :            :         .blackhole_route =      ipv4_blackhole_route,
     157                 :            : };
     158                 :            : 
     159                 :            : #ifdef CONFIG_SYSCTL
     160                 :            : static struct ctl_table xfrm4_policy_table[] = {
     161                 :            :         {
     162                 :            :                 .procname       = "xfrm4_gc_thresh",
     163                 :            :                 .data           = &init_net.xfrm.xfrm4_dst_ops.gc_thresh,
     164                 :            :                 .maxlen         = sizeof(int),
     165                 :            :                 .mode           = 0644,
     166                 :            :                 .proc_handler   = proc_dointvec,
     167                 :            :         },
     168                 :            :         { }
     169                 :            : };
     170                 :            : 
     171                 :         11 : static __net_init int xfrm4_net_sysctl_init(struct net *net)
     172                 :            : {
     173                 :         11 :         struct ctl_table *table;
     174                 :         11 :         struct ctl_table_header *hdr;
     175                 :            : 
     176                 :         11 :         table = xfrm4_policy_table;
     177         [ -  + ]:         11 :         if (!net_eq(net, &init_net)) {
     178                 :          0 :                 table = kmemdup(table, sizeof(xfrm4_policy_table), GFP_KERNEL);
     179         [ #  # ]:          0 :                 if (!table)
     180                 :          0 :                         goto err_alloc;
     181                 :            : 
     182                 :          0 :                 table[0].data = &net->xfrm.xfrm4_dst_ops.gc_thresh;
     183                 :            :         }
     184                 :            : 
     185                 :         11 :         hdr = register_net_sysctl(net, "net/ipv4", table);
     186         [ -  + ]:         11 :         if (!hdr)
     187                 :          0 :                 goto err_reg;
     188                 :            : 
     189                 :         11 :         net->ipv4.xfrm4_hdr = hdr;
     190                 :         11 :         return 0;
     191                 :            : 
     192                 :            : err_reg:
     193         [ #  # ]:          0 :         if (!net_eq(net, &init_net))
     194                 :          0 :                 kfree(table);
     195                 :          0 : err_alloc:
     196                 :            :         return -ENOMEM;
     197                 :            : }
     198                 :            : 
     199                 :          0 : static __net_exit void xfrm4_net_sysctl_exit(struct net *net)
     200                 :            : {
     201                 :          0 :         struct ctl_table *table;
     202                 :            : 
     203         [ #  # ]:          0 :         if (!net->ipv4.xfrm4_hdr)
     204                 :            :                 return;
     205                 :            : 
     206                 :          0 :         table = net->ipv4.xfrm4_hdr->ctl_table_arg;
     207                 :          0 :         unregister_net_sysctl_table(net->ipv4.xfrm4_hdr);
     208         [ #  # ]:          0 :         if (!net_eq(net, &init_net))
     209                 :          0 :                 kfree(table);
     210                 :            : }
     211                 :            : #else /* CONFIG_SYSCTL */
     212                 :            : static inline int xfrm4_net_sysctl_init(struct net *net)
     213                 :            : {
     214                 :            :         return 0;
     215                 :            : }
     216                 :            : 
     217                 :            : static inline void xfrm4_net_sysctl_exit(struct net *net)
     218                 :            : {
     219                 :            : }
     220                 :            : #endif
     221                 :            : 
     222                 :         11 : static int __net_init xfrm4_net_init(struct net *net)
     223                 :            : {
     224                 :         11 :         int ret;
     225                 :            : 
     226                 :         11 :         memcpy(&net->xfrm.xfrm4_dst_ops, &xfrm4_dst_ops_template,
     227                 :            :                sizeof(xfrm4_dst_ops_template));
     228                 :         11 :         ret = dst_entries_init(&net->xfrm.xfrm4_dst_ops);
     229         [ +  - ]:         11 :         if (ret)
     230                 :            :                 return ret;
     231                 :            : 
     232                 :         11 :         ret = xfrm4_net_sysctl_init(net);
     233         [ -  + ]:         11 :         if (ret)
     234                 :          0 :                 dst_entries_destroy(&net->xfrm.xfrm4_dst_ops);
     235                 :            : 
     236                 :            :         return ret;
     237                 :            : }
     238                 :            : 
     239                 :          0 : static void __net_exit xfrm4_net_exit(struct net *net)
     240                 :            : {
     241                 :          0 :         xfrm4_net_sysctl_exit(net);
     242                 :          0 :         dst_entries_destroy(&net->xfrm.xfrm4_dst_ops);
     243                 :          0 : }
     244                 :            : 
     245                 :            : static struct pernet_operations __net_initdata xfrm4_net_ops = {
     246                 :            :         .init   = xfrm4_net_init,
     247                 :            :         .exit   = xfrm4_net_exit,
     248                 :            : };
     249                 :            : 
     250                 :         11 : static void __init xfrm4_policy_init(void)
     251                 :            : {
     252                 :         11 :         xfrm_policy_register_afinfo(&xfrm4_policy_afinfo, AF_INET);
     253                 :         11 : }
     254                 :            : 
     255                 :         11 : void __init xfrm4_init(void)
     256                 :            : {
     257                 :         11 :         xfrm4_state_init();
     258                 :         11 :         xfrm4_policy_init();
     259                 :         11 :         xfrm4_protocol_init();
     260                 :         11 :         register_pernet_subsys(&xfrm4_net_ops);
     261                 :         11 : }

Generated by: LCOV version 1.14