root/net/ipv6/ila/ila_common.c

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

DEFINITIONS

This source file includes following definitions.
  1. ila_init_saved_csum
  2. get_csum_diff_iaddr
  3. get_csum_diff
  4. ila_csum_do_neutral_fmt
  5. ila_csum_do_neutral_nofmt
  6. ila_csum_adjust_transport
  7. ila_update_ipv6_locator

   1 #include <linux/errno.h>
   2 #include <linux/ip.h>
   3 #include <linux/kernel.h>
   4 #include <linux/module.h>
   5 #include <linux/skbuff.h>
   6 #include <linux/socket.h>
   7 #include <linux/types.h>
   8 #include <net/checksum.h>
   9 #include <net/ip.h>
  10 #include <net/ip6_fib.h>
  11 #include <net/lwtunnel.h>
  12 #include <net/protocol.h>
  13 #include <uapi/linux/ila.h>
  14 #include "ila.h"
  15 
  16 void ila_init_saved_csum(struct ila_params *p)
  17 {
  18         if (!p->locator_match.v64)
  19                 return;
  20 
  21         p->csum_diff = compute_csum_diff8(
  22                                 (__be32 *)&p->locator,
  23                                 (__be32 *)&p->locator_match);
  24 }
  25 
  26 static __wsum get_csum_diff_iaddr(struct ila_addr *iaddr, struct ila_params *p)
  27 {
  28         if (p->locator_match.v64)
  29                 return p->csum_diff;
  30         else
  31                 return compute_csum_diff8((__be32 *)&p->locator,
  32                                           (__be32 *)&iaddr->loc);
  33 }
  34 
  35 static __wsum get_csum_diff(struct ipv6hdr *ip6h, struct ila_params *p)
  36 {
  37         return get_csum_diff_iaddr(ila_a2i(&ip6h->daddr), p);
  38 }
  39 
  40 static void ila_csum_do_neutral_fmt(struct ila_addr *iaddr,
  41                                     struct ila_params *p)
  42 {
  43         __sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3];
  44         __wsum diff, fval;
  45 
  46         diff = get_csum_diff_iaddr(iaddr, p);
  47 
  48         fval = (__force __wsum)(ila_csum_neutral_set(iaddr->ident) ?
  49                         CSUM_NEUTRAL_FLAG : ~CSUM_NEUTRAL_FLAG);
  50 
  51         diff = csum_add(diff, fval);
  52 
  53         *adjust = ~csum_fold(csum_add(diff, csum_unfold(*adjust)));
  54 
  55         /* Flip the csum-neutral bit. Either we are doing a SIR->ILA
  56          * translation with ILA_CSUM_NEUTRAL_MAP as the csum_method
  57          * and the C-bit is not set, or we are doing an ILA-SIR
  58          * tranlsation and the C-bit is set.
  59          */
  60         iaddr->ident.csum_neutral ^= 1;
  61 }
  62 
  63 static void ila_csum_do_neutral_nofmt(struct ila_addr *iaddr,
  64                                       struct ila_params *p)
  65 {
  66         __sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3];
  67         __wsum diff;
  68 
  69         diff = get_csum_diff_iaddr(iaddr, p);
  70 
  71         *adjust = ~csum_fold(csum_add(diff, csum_unfold(*adjust)));
  72 }
  73 
  74 static void ila_csum_adjust_transport(struct sk_buff *skb,
  75                                       struct ila_params *p)
  76 {
  77         size_t nhoff = sizeof(struct ipv6hdr);
  78         struct ipv6hdr *ip6h = ipv6_hdr(skb);
  79         __wsum diff;
  80 
  81         switch (ip6h->nexthdr) {
  82         case NEXTHDR_TCP:
  83                 if (likely(pskb_may_pull(skb, nhoff + sizeof(struct tcphdr)))) {
  84                         struct tcphdr *th = (struct tcphdr *)
  85                                         (skb_network_header(skb) + nhoff);
  86 
  87                         diff = get_csum_diff(ip6h, p);
  88                         inet_proto_csum_replace_by_diff(&th->check, skb,
  89                                                         diff, true);
  90                 }
  91                 break;
  92         case NEXTHDR_UDP:
  93                 if (likely(pskb_may_pull(skb, nhoff + sizeof(struct udphdr)))) {
  94                         struct udphdr *uh = (struct udphdr *)
  95                                         (skb_network_header(skb) + nhoff);
  96 
  97                         if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
  98                                 diff = get_csum_diff(ip6h, p);
  99                                 inet_proto_csum_replace_by_diff(&uh->check, skb,
 100                                                                 diff, true);
 101                                 if (!uh->check)
 102                                         uh->check = CSUM_MANGLED_0;
 103                         }
 104                 }
 105                 break;
 106         case NEXTHDR_ICMP:
 107                 if (likely(pskb_may_pull(skb,
 108                                          nhoff + sizeof(struct icmp6hdr)))) {
 109                         struct icmp6hdr *ih = (struct icmp6hdr *)
 110                                         (skb_network_header(skb) + nhoff);
 111 
 112                         diff = get_csum_diff(ip6h, p);
 113                         inet_proto_csum_replace_by_diff(&ih->icmp6_cksum, skb,
 114                                                         diff, true);
 115                 }
 116                 break;
 117         }
 118 }
 119 
 120 void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p,
 121                              bool sir2ila)
 122 {
 123         struct ipv6hdr *ip6h = ipv6_hdr(skb);
 124         struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
 125 
 126         switch (p->csum_mode) {
 127         case ILA_CSUM_ADJUST_TRANSPORT:
 128                 ila_csum_adjust_transport(skb, p);
 129                 break;
 130         case ILA_CSUM_NEUTRAL_MAP:
 131                 if (sir2ila) {
 132                         if (WARN_ON(ila_csum_neutral_set(iaddr->ident))) {
 133                                 /* Checksum flag should never be
 134                                  * set in a formatted SIR address.
 135                                  */
 136                                 break;
 137                         }
 138                 } else if (!ila_csum_neutral_set(iaddr->ident)) {
 139                         /* ILA to SIR translation and C-bit isn't
 140                          * set so we're good.
 141                          */
 142                         break;
 143                 }
 144                 ila_csum_do_neutral_fmt(iaddr, p);
 145                 break;
 146         case ILA_CSUM_NEUTRAL_MAP_AUTO:
 147                 ila_csum_do_neutral_nofmt(iaddr, p);
 148                 break;
 149         case ILA_CSUM_NO_ACTION:
 150                 break;
 151         }
 152 
 153         /* Now change destination address */
 154         iaddr->loc = p->locator;
 155 }

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