linux/net/ipv6/xfrm6_state.c
<<
>>
Prefs
   1/*
   2 * xfrm6_state.c: based on xfrm4_state.c
   3 *
   4 * Authors:
   5 *      Mitsuru KANDA @USAGI
   6 *      Kazunori MIYAZAWA @USAGI
   7 *      Kunihiro Ishiguro <kunihiro@ipinfusion.com>
   8 *              IPv6 support
   9 *      YOSHIFUJI Hideaki @USAGI
  10 *              Split up af-specific portion
  11 *
  12 */
  13
  14#include <net/xfrm.h>
  15#include <linux/pfkeyv2.h>
  16#include <linux/ipsec.h>
  17#include <linux/netfilter_ipv6.h>
  18#include <net/dsfield.h>
  19#include <net/ipv6.h>
  20#include <net/addrconf.h>
  21
  22static void
  23__xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl,
  24                     struct xfrm_tmpl *tmpl,
  25                     xfrm_address_t *daddr, xfrm_address_t *saddr)
  26{
  27        /* Initialize temporary selector matching only
  28         * to current session. */
  29        ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst);
  30        ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src);
  31        x->sel.dport = xfrm_flowi_dport(fl);
  32        x->sel.dport_mask = htons(0xffff);
  33        x->sel.sport = xfrm_flowi_sport(fl);
  34        x->sel.sport_mask = htons(0xffff);
  35        x->sel.family = AF_INET6;
  36        x->sel.prefixlen_d = 128;
  37        x->sel.prefixlen_s = 128;
  38        x->sel.proto = fl->proto;
  39        x->sel.ifindex = fl->oif;
  40        x->id = tmpl->id;
  41        if (ipv6_addr_any((struct in6_addr*)&x->id.daddr))
  42                memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr));
  43        memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
  44        if (ipv6_addr_any((struct in6_addr*)&x->props.saddr))
  45                memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr));
  46        x->props.mode = tmpl->mode;
  47        x->props.reqid = tmpl->reqid;
  48        x->props.family = AF_INET6;
  49}
  50
  51/* distribution counting sort function for xfrm_state and xfrm_tmpl */
  52static int
  53__xfrm6_sort(void **dst, void **src, int n, int (*cmp)(void *p), int maxclass)
  54{
  55        int i;
  56        int class[XFRM_MAX_DEPTH];
  57        int count[maxclass];
  58
  59        memset(count, 0, sizeof(count));
  60
  61        for (i = 0; i < n; i++) {
  62                int c;
  63                class[i] = c = cmp(src[i]);
  64                count[c]++;
  65        }
  66
  67        for (i = 2; i < maxclass; i++)
  68                count[i] += count[i - 1];
  69
  70        for (i = 0; i < n; i++) {
  71                dst[count[class[i] - 1]++] = src[i];
  72                src[i] = NULL;
  73        }
  74
  75        return 0;
  76}
  77
  78/*
  79 * Rule for xfrm_state:
  80 *
  81 * rule 1: select IPsec transport except AH
  82 * rule 2: select MIPv6 RO or inbound trigger
  83 * rule 3: select IPsec transport AH
  84 * rule 4: select IPsec tunnel
  85 * rule 5: others
  86 */
  87static int __xfrm6_state_sort_cmp(void *p)
  88{
  89        struct xfrm_state *v = p;
  90
  91        switch (v->props.mode) {
  92        case XFRM_MODE_TRANSPORT:
  93                if (v->id.proto != IPPROTO_AH)
  94                        return 1;
  95                else
  96                        return 3;
  97#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
  98        case XFRM_MODE_ROUTEOPTIMIZATION:
  99        case XFRM_MODE_IN_TRIGGER:
 100                return 2;
 101#endif
 102        case XFRM_MODE_TUNNEL:
 103        case XFRM_MODE_BEET:
 104                return 4;
 105        }
 106        return 5;
 107}
 108
 109static int
 110__xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n)
 111{
 112        return __xfrm6_sort((void **)dst, (void **)src, n,
 113                            __xfrm6_state_sort_cmp, 6);
 114}
 115
 116/*
 117 * Rule for xfrm_tmpl:
 118 *
 119 * rule 1: select IPsec transport
 120 * rule 2: select MIPv6 RO or inbound trigger
 121 * rule 3: select IPsec tunnel
 122 * rule 4: others
 123 */
 124static int __xfrm6_tmpl_sort_cmp(void *p)
 125{
 126        struct xfrm_tmpl *v = p;
 127        switch (v->mode) {
 128        case XFRM_MODE_TRANSPORT:
 129                return 1;
 130#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
 131        case XFRM_MODE_ROUTEOPTIMIZATION:
 132        case XFRM_MODE_IN_TRIGGER:
 133                return 2;
 134#endif
 135        case XFRM_MODE_TUNNEL:
 136        case XFRM_MODE_BEET:
 137                return 3;
 138        }
 139        return 4;
 140}
 141
 142static int
 143__xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n)
 144{
 145        return __xfrm6_sort((void **)dst, (void **)src, n,
 146                            __xfrm6_tmpl_sort_cmp, 5);
 147}
 148
 149int xfrm6_extract_header(struct sk_buff *skb)
 150{
 151        struct ipv6hdr *iph = ipv6_hdr(skb);
 152
 153        XFRM_MODE_SKB_CB(skb)->ihl = sizeof(*iph);
 154        XFRM_MODE_SKB_CB(skb)->id = 0;
 155        XFRM_MODE_SKB_CB(skb)->frag_off = htons(IP_DF);
 156        XFRM_MODE_SKB_CB(skb)->tos = ipv6_get_dsfield(iph);
 157        XFRM_MODE_SKB_CB(skb)->ttl = iph->hop_limit;
 158        XFRM_MODE_SKB_CB(skb)->optlen = 0;
 159        memcpy(XFRM_MODE_SKB_CB(skb)->flow_lbl, iph->flow_lbl,
 160               sizeof(XFRM_MODE_SKB_CB(skb)->flow_lbl));
 161
 162        return 0;
 163}
 164
 165static struct xfrm_state_afinfo xfrm6_state_afinfo = {
 166        .family                 = AF_INET6,
 167        .proto                  = IPPROTO_IPV6,
 168        .eth_proto              = htons(ETH_P_IPV6),
 169        .owner                  = THIS_MODULE,
 170        .init_tempsel           = __xfrm6_init_tempsel,
 171        .tmpl_sort              = __xfrm6_tmpl_sort,
 172        .state_sort             = __xfrm6_state_sort,
 173        .output                 = xfrm6_output,
 174        .extract_input          = xfrm6_extract_input,
 175        .extract_output         = xfrm6_extract_output,
 176        .transport_finish       = xfrm6_transport_finish,
 177};
 178
 179int __init xfrm6_state_init(void)
 180{
 181        return xfrm_state_register_afinfo(&xfrm6_state_afinfo);
 182}
 183
 184void xfrm6_state_fini(void)
 185{
 186        xfrm_state_unregister_afinfo(&xfrm6_state_afinfo);
 187}
 188
 189