LCOV - code coverage report
Current view: top level - net/netfilter - nf_queue.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 66 0.0 %
Date: 2014-04-07 Functions: 0 6 0.0 %
Branches: 0 56 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Rusty Russell (C)2000 -- This code is GPL.
       3                 :            :  * Patrick McHardy (c) 2006-2012
       4                 :            :  */
       5                 :            : 
       6                 :            : #include <linux/kernel.h>
       7                 :            : #include <linux/slab.h>
       8                 :            : #include <linux/init.h>
       9                 :            : #include <linux/module.h>
      10                 :            : #include <linux/proc_fs.h>
      11                 :            : #include <linux/skbuff.h>
      12                 :            : #include <linux/netfilter.h>
      13                 :            : #include <linux/seq_file.h>
      14                 :            : #include <linux/rcupdate.h>
      15                 :            : #include <net/protocol.h>
      16                 :            : #include <net/netfilter/nf_queue.h>
      17                 :            : #include <net/dst.h>
      18                 :            : 
      19                 :            : #include "nf_internals.h"
      20                 :            : 
      21                 :            : /*
      22                 :            :  * Hook for nfnetlink_queue to register its queue handler.
      23                 :            :  * We do this so that most of the NFQUEUE code can be modular.
      24                 :            :  *
      25                 :            :  * Once the queue is registered it must reinject all packets it
      26                 :            :  * receives, no matter what.
      27                 :            :  */
      28                 :            : static const struct nf_queue_handler __rcu *queue_handler __read_mostly;
      29                 :            : 
      30                 :            : /* return EBUSY when somebody else is registered, return EEXIST if the
      31                 :            :  * same handler is registered, return 0 in case of success. */
      32                 :          0 : void nf_register_queue_handler(const struct nf_queue_handler *qh)
      33                 :            : {
      34                 :            :         /* should never happen, we only have one queueing backend in kernel */
      35         [ #  # ]:          0 :         WARN_ON(rcu_access_pointer(queue_handler));
      36                 :          0 :         rcu_assign_pointer(queue_handler, qh);
      37                 :          0 : }
      38                 :            : EXPORT_SYMBOL(nf_register_queue_handler);
      39                 :            : 
      40                 :            : /* The caller must flush their queue before this */
      41                 :          0 : void nf_unregister_queue_handler(void)
      42                 :            : {
      43                 :          0 :         RCU_INIT_POINTER(queue_handler, NULL);
      44                 :            :         synchronize_rcu();
      45                 :          0 : }
      46                 :            : EXPORT_SYMBOL(nf_unregister_queue_handler);
      47                 :            : 
      48                 :          0 : void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
      49                 :            : {
      50                 :            :         /* Release those devices we held, or Alexey will kill me. */
      51         [ #  # ]:          0 :         if (entry->indev)
      52                 :            :                 dev_put(entry->indev);
      53         [ #  # ]:          0 :         if (entry->outdev)
      54                 :            :                 dev_put(entry->outdev);
      55                 :            : #ifdef CONFIG_BRIDGE_NETFILTER
      56         [ #  # ]:          0 :         if (entry->skb->nf_bridge) {
      57                 :            :                 struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge;
      58                 :            : 
      59         [ #  # ]:          0 :                 if (nf_bridge->physindev)
      60                 :            :                         dev_put(nf_bridge->physindev);
      61         [ #  # ]:          0 :                 if (nf_bridge->physoutdev)
      62                 :            :                         dev_put(nf_bridge->physoutdev);
      63                 :            :         }
      64                 :            : #endif
      65                 :            :         /* Drop reference to owner of hook which queued us. */
      66                 :          0 :         module_put(entry->elem->owner);
      67                 :          0 : }
      68                 :            : EXPORT_SYMBOL_GPL(nf_queue_entry_release_refs);
      69                 :            : 
      70                 :            : /* Bump dev refs so they don't vanish while packet is out */
      71                 :          0 : bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)
      72                 :            : {
      73         [ #  # ]:          0 :         if (!try_module_get(entry->elem->owner))
      74                 :            :                 return false;
      75                 :            : 
      76         [ #  # ]:          0 :         if (entry->indev)
      77                 :            :                 dev_hold(entry->indev);
      78         [ #  # ]:          0 :         if (entry->outdev)
      79                 :            :                 dev_hold(entry->outdev);
      80                 :            : #ifdef CONFIG_BRIDGE_NETFILTER
      81         [ #  # ]:          0 :         if (entry->skb->nf_bridge) {
      82                 :            :                 struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge;
      83                 :            :                 struct net_device *physdev;
      84                 :            : 
      85                 :          0 :                 physdev = nf_bridge->physindev;
      86         [ #  # ]:          0 :                 if (physdev)
      87                 :            :                         dev_hold(physdev);
      88                 :          0 :                 physdev = nf_bridge->physoutdev;
      89         [ #  # ]:          0 :                 if (physdev)
      90                 :            :                         dev_hold(physdev);
      91                 :            :         }
      92                 :            : #endif
      93                 :            : 
      94                 :            :         return true;
      95                 :            : }
      96                 :            : EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs);
      97                 :            : 
      98                 :            : /*
      99                 :            :  * Any packet that leaves via this function must come back
     100                 :            :  * through nf_reinject().
     101                 :            :  */
     102                 :          0 : int nf_queue(struct sk_buff *skb,
     103                 :            :                       struct nf_hook_ops *elem,
     104                 :            :                       u_int8_t pf, unsigned int hook,
     105                 :            :                       struct net_device *indev,
     106                 :            :                       struct net_device *outdev,
     107                 :            :                       int (*okfn)(struct sk_buff *),
     108                 :            :                       unsigned int queuenum)
     109                 :            : {
     110                 :            :         int status = -ENOENT;
     111                 :            :         struct nf_queue_entry *entry = NULL;
     112                 :            :         const struct nf_afinfo *afinfo;
     113                 :            :         const struct nf_queue_handler *qh;
     114                 :            : 
     115                 :            :         /* QUEUE == DROP if no one is waiting, to be safe. */
     116                 :            :         rcu_read_lock();
     117                 :            : 
     118                 :          0 :         qh = rcu_dereference(queue_handler);
     119         [ #  # ]:          0 :         if (!qh) {
     120                 :            :                 status = -ESRCH;
     121                 :            :                 goto err_unlock;
     122                 :            :         }
     123                 :            : 
     124                 :            :         afinfo = nf_get_afinfo(pf);
     125         [ #  # ]:          0 :         if (!afinfo)
     126                 :            :                 goto err_unlock;
     127                 :            : 
     128                 :          0 :         entry = kmalloc(sizeof(*entry) + afinfo->route_key_size, GFP_ATOMIC);
     129         [ #  # ]:          0 :         if (!entry) {
     130                 :            :                 status = -ENOMEM;
     131                 :            :                 goto err_unlock;
     132                 :            :         }
     133                 :            : 
     134                 :          0 :         *entry = (struct nf_queue_entry) {
     135                 :            :                 .skb    = skb,
     136                 :            :                 .elem   = elem,
     137                 :            :                 .pf     = pf,
     138                 :            :                 .hook   = hook,
     139                 :            :                 .indev  = indev,
     140                 :            :                 .outdev = outdev,
     141                 :            :                 .okfn   = okfn,
     142                 :          0 :                 .size   = sizeof(*entry) + afinfo->route_key_size,
     143                 :            :         };
     144                 :            : 
     145         [ #  # ]:          0 :         if (!nf_queue_entry_get_refs(entry)) {
     146                 :            :                 status = -ECANCELED;
     147                 :            :                 goto err_unlock;
     148                 :            :         }
     149                 :            :         skb_dst_force(skb);
     150                 :          0 :         afinfo->saveroute(skb, entry);
     151                 :          0 :         status = qh->outfn(entry, queuenum);
     152                 :            : 
     153                 :            :         rcu_read_unlock();
     154                 :            : 
     155         [ #  # ]:          0 :         if (status < 0) {
     156                 :          0 :                 nf_queue_entry_release_refs(entry);
     157                 :          0 :                 goto err;
     158                 :            :         }
     159                 :            : 
     160                 :            :         return 0;
     161                 :            : 
     162                 :            : err_unlock:
     163                 :            :         rcu_read_unlock();
     164                 :            : err:
     165                 :          0 :         kfree(entry);
     166                 :          0 :         return status;
     167                 :            : }
     168                 :            : 
     169                 :          0 : void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
     170                 :            : {
     171                 :          0 :         struct sk_buff *skb = entry->skb;
     172                 :          0 :         struct nf_hook_ops *elem = entry->elem;
     173                 :            :         const struct nf_afinfo *afinfo;
     174                 :            :         int err;
     175                 :            : 
     176                 :            :         rcu_read_lock();
     177                 :            : 
     178                 :          0 :         nf_queue_entry_release_refs(entry);
     179                 :            : 
     180                 :            :         /* Continue traversal iff userspace said ok... */
     181         [ #  # ]:          0 :         if (verdict == NF_REPEAT) {
     182                 :          0 :                 elem = list_entry(elem->list.prev, struct nf_hook_ops, list);
     183                 :            :                 verdict = NF_ACCEPT;
     184                 :            :         }
     185                 :            : 
     186         [ #  # ]:          0 :         if (verdict == NF_ACCEPT) {
     187                 :          0 :                 afinfo = nf_get_afinfo(entry->pf);
     188 [ #  # ][ #  # ]:          0 :                 if (!afinfo || afinfo->reroute(skb, entry) < 0)
     189                 :            :                         verdict = NF_DROP;
     190                 :            :         }
     191                 :            : 
     192         [ #  # ]:          0 :         if (verdict == NF_ACCEPT) {
     193                 :            :         next_hook:
     194                 :          0 :                 verdict = nf_iterate(&nf_hooks[entry->pf][entry->hook],
     195                 :            :                                      skb, entry->hook,
     196                 :          0 :                                      entry->indev, entry->outdev, &elem,
     197                 :            :                                      entry->okfn, INT_MIN);
     198                 :            :         }
     199                 :            : 
     200   [ #  #  #  # ]:          0 :         switch (verdict & NF_VERDICT_MASK) {
     201                 :            :         case NF_ACCEPT:
     202                 :            :         case NF_STOP:
     203                 :          0 :                 local_bh_disable();
     204                 :          0 :                 entry->okfn(skb);
     205                 :          0 :                 local_bh_enable();
     206                 :          0 :                 break;
     207                 :            :         case NF_QUEUE:
     208                 :          0 :                 err = nf_queue(skb, elem, entry->pf, entry->hook,
     209                 :            :                                 entry->indev, entry->outdev, entry->okfn,
     210                 :            :                                 verdict >> NF_VERDICT_QBITS);
     211         [ #  # ]:          0 :                 if (err < 0) {
     212         [ #  # ]:          0 :                         if (err == -ECANCELED)
     213                 :            :                                 goto next_hook;
     214 [ #  # ][ #  # ]:          0 :                         if (err == -ESRCH &&
     215                 :          0 :                            (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS))
     216                 :            :                                 goto next_hook;
     217                 :          0 :                         kfree_skb(skb);
     218                 :            :                 }
     219                 :            :                 break;
     220                 :            :         case NF_STOLEN:
     221                 :            :                 break;
     222                 :            :         default:
     223                 :          0 :                 kfree_skb(skb);
     224                 :            :         }
     225                 :            :         rcu_read_unlock();
     226                 :          0 :         kfree(entry);
     227                 :          0 : }
     228                 :            : EXPORT_SYMBOL(nf_reinject);

Generated by: LCOV version 1.9