root/net/netfilter/utils.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nf_ip_checksum
  2. nf_ip_checksum_partial
  3. nf_ip6_checksum
  4. nf_ip6_checksum_partial
  5. nf_checksum
  6. nf_checksum_partial
  7. nf_route
  8. nf_ip_reroute
  9. nf_reroute

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <linux/kernel.h>
   3 #include <linux/netfilter.h>
   4 #include <linux/netfilter_ipv4.h>
   5 #include <linux/netfilter_ipv6.h>
   6 #include <net/netfilter/nf_queue.h>
   7 #include <net/ip6_checksum.h>
   8 
   9 #ifdef CONFIG_INET
  10 __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
  11                        unsigned int dataoff, u8 protocol)
  12 {
  13         const struct iphdr *iph = ip_hdr(skb);
  14         __sum16 csum = 0;
  15 
  16         switch (skb->ip_summed) {
  17         case CHECKSUM_COMPLETE:
  18                 if (hook != NF_INET_PRE_ROUTING && hook != NF_INET_LOCAL_IN)
  19                         break;
  20                 if ((protocol != IPPROTO_TCP && protocol != IPPROTO_UDP &&
  21                     !csum_fold(skb->csum)) ||
  22                     !csum_tcpudp_magic(iph->saddr, iph->daddr,
  23                                        skb->len - dataoff, protocol,
  24                                        skb->csum)) {
  25                         skb->ip_summed = CHECKSUM_UNNECESSARY;
  26                         break;
  27                 }
  28                 /* fall through */
  29         case CHECKSUM_NONE:
  30                 if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
  31                         skb->csum = 0;
  32                 else
  33                         skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
  34                                                        skb->len - dataoff,
  35                                                        protocol, 0);
  36                 csum = __skb_checksum_complete(skb);
  37         }
  38         return csum;
  39 }
  40 EXPORT_SYMBOL(nf_ip_checksum);
  41 #endif
  42 
  43 static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook,
  44                                       unsigned int dataoff, unsigned int len,
  45                                       u8 protocol)
  46 {
  47         const struct iphdr *iph = ip_hdr(skb);
  48         __sum16 csum = 0;
  49 
  50         switch (skb->ip_summed) {
  51         case CHECKSUM_COMPLETE:
  52                 if (len == skb->len - dataoff)
  53                         return nf_ip_checksum(skb, hook, dataoff, protocol);
  54                 /* fall through */
  55         case CHECKSUM_NONE:
  56                 skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, protocol,
  57                                                skb->len - dataoff, 0);
  58                 skb->ip_summed = CHECKSUM_NONE;
  59                 return __skb_checksum_complete_head(skb, dataoff + len);
  60         }
  61         return csum;
  62 }
  63 
  64 __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,
  65                         unsigned int dataoff, u8 protocol)
  66 {
  67         const struct ipv6hdr *ip6h = ipv6_hdr(skb);
  68         __sum16 csum = 0;
  69 
  70         switch (skb->ip_summed) {
  71         case CHECKSUM_COMPLETE:
  72                 if (hook != NF_INET_PRE_ROUTING && hook != NF_INET_LOCAL_IN)
  73                         break;
  74                 if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
  75                                      skb->len - dataoff, protocol,
  76                                      csum_sub(skb->csum,
  77                                               skb_checksum(skb, 0,
  78                                                            dataoff, 0)))) {
  79                         skb->ip_summed = CHECKSUM_UNNECESSARY;
  80                         break;
  81                 }
  82                 /* fall through */
  83         case CHECKSUM_NONE:
  84                 skb->csum = ~csum_unfold(
  85                                 csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
  86                                              skb->len - dataoff,
  87                                              protocol,
  88                                              csum_sub(0,
  89                                                       skb_checksum(skb, 0,
  90                                                                    dataoff, 0))));
  91                 csum = __skb_checksum_complete(skb);
  92         }
  93         return csum;
  94 }
  95 EXPORT_SYMBOL(nf_ip6_checksum);
  96 
  97 static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook,
  98                                        unsigned int dataoff, unsigned int len,
  99                                        u8 protocol)
 100 {
 101         const struct ipv6hdr *ip6h = ipv6_hdr(skb);
 102         __wsum hsum;
 103         __sum16 csum = 0;
 104 
 105         switch (skb->ip_summed) {
 106         case CHECKSUM_COMPLETE:
 107                 if (len == skb->len - dataoff)
 108                         return nf_ip6_checksum(skb, hook, dataoff, protocol);
 109                 /* fall through */
 110         case CHECKSUM_NONE:
 111                 hsum = skb_checksum(skb, 0, dataoff, 0);
 112                 skb->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr,
 113                                                          &ip6h->daddr,
 114                                                          skb->len - dataoff,
 115                                                          protocol,
 116                                                          csum_sub(0, hsum)));
 117                 skb->ip_summed = CHECKSUM_NONE;
 118                 return __skb_checksum_complete_head(skb, dataoff + len);
 119         }
 120         return csum;
 121 };
 122 
 123 __sum16 nf_checksum(struct sk_buff *skb, unsigned int hook,
 124                     unsigned int dataoff, u8 protocol,
 125                     unsigned short family)
 126 {
 127         __sum16 csum = 0;
 128 
 129         switch (family) {
 130         case AF_INET:
 131                 csum = nf_ip_checksum(skb, hook, dataoff, protocol);
 132                 break;
 133         case AF_INET6:
 134                 csum = nf_ip6_checksum(skb, hook, dataoff, protocol);
 135                 break;
 136         }
 137 
 138         return csum;
 139 }
 140 EXPORT_SYMBOL_GPL(nf_checksum);
 141 
 142 __sum16 nf_checksum_partial(struct sk_buff *skb, unsigned int hook,
 143                             unsigned int dataoff, unsigned int len,
 144                             u8 protocol, unsigned short family)
 145 {
 146         __sum16 csum = 0;
 147 
 148         switch (family) {
 149         case AF_INET:
 150                 csum = nf_ip_checksum_partial(skb, hook, dataoff, len,
 151                                               protocol);
 152                 break;
 153         case AF_INET6:
 154                 csum = nf_ip6_checksum_partial(skb, hook, dataoff, len,
 155                                                protocol);
 156                 break;
 157         }
 158 
 159         return csum;
 160 }
 161 EXPORT_SYMBOL_GPL(nf_checksum_partial);
 162 
 163 int nf_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
 164              bool strict, unsigned short family)
 165 {
 166         const struct nf_ipv6_ops *v6ops __maybe_unused;
 167         int ret = 0;
 168 
 169         switch (family) {
 170         case AF_INET:
 171                 ret = nf_ip_route(net, dst, fl, strict);
 172                 break;
 173         case AF_INET6:
 174                 ret = nf_ip6_route(net, dst, fl, strict);
 175                 break;
 176         }
 177 
 178         return ret;
 179 }
 180 EXPORT_SYMBOL_GPL(nf_route);
 181 
 182 static int nf_ip_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry)
 183 {
 184 #ifdef CONFIG_INET
 185         const struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry);
 186 
 187         if (entry->state.hook == NF_INET_LOCAL_OUT) {
 188                 const struct iphdr *iph = ip_hdr(skb);
 189 
 190                 if (!(iph->tos == rt_info->tos &&
 191                       skb->mark == rt_info->mark &&
 192                       iph->daddr == rt_info->daddr &&
 193                       iph->saddr == rt_info->saddr))
 194                         return ip_route_me_harder(entry->state.net, skb,
 195                                                   RTN_UNSPEC);
 196         }
 197 #endif
 198         return 0;
 199 }
 200 
 201 int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry)
 202 {
 203         const struct nf_ipv6_ops *v6ops;
 204         int ret = 0;
 205 
 206         switch (entry->state.pf) {
 207         case AF_INET:
 208                 ret = nf_ip_reroute(skb, entry);
 209                 break;
 210         case AF_INET6:
 211                 v6ops = rcu_dereference(nf_ipv6_ops);
 212                 if (v6ops)
 213                         ret = v6ops->reroute(skb, entry);
 214                 break;
 215         }
 216         return ret;
 217 }

/* [<][>][^][v][top][bottom][index][help] */