xfrm6_state.c 4.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10
/*
 * xfrm6_state.c: based on xfrm4_state.c
 *
 * Authors:
 *	Mitsuru KANDA @USAGI
 * 	Kazunori MIYAZAWA @USAGI
 * 	Kunihiro Ishiguro <kunihiro@ipinfusion.com>
 * 		IPv6 support
 * 	YOSHIFUJI Hideaki @USAGI
 * 		Split up af-specific portion
11
 *
L
Linus Torvalds 已提交
12 13 14 15 16
 */

#include <net/xfrm.h>
#include <linux/pfkeyv2.h>
#include <linux/ipsec.h>
17
#include <linux/netfilter_ipv6.h>
18
#include <net/dsfield.h>
L
Linus Torvalds 已提交
19
#include <net/ipv6.h>
20
#include <net/addrconf.h>
L
Linus Torvalds 已提交
21 22

static void
23
__xfrm6_init_tempsel(struct xfrm_selector *sel, struct flowi *fl)
L
Linus Torvalds 已提交
24 25 26
{
	/* Initialize temporary selector matching only
	 * to current session. */
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
	ipv6_addr_copy((struct in6_addr *)&sel->daddr, &fl->fl6_dst);
	ipv6_addr_copy((struct in6_addr *)&sel->saddr, &fl->fl6_src);
	sel->dport = xfrm_flowi_dport(fl);
	sel->dport_mask = htons(0xffff);
	sel->sport = xfrm_flowi_sport(fl);
	sel->sport_mask = htons(0xffff);
	sel->family = AF_INET6;
	sel->prefixlen_d = 128;
	sel->prefixlen_s = 128;
	sel->proto = fl->proto;
	sel->ifindex = fl->oif;
}

static void
xfrm6_init_temprop(struct xfrm_state *x, struct xfrm_tmpl *tmpl,
		   xfrm_address_t *daddr, xfrm_address_t *saddr)
{
L
Linus Torvalds 已提交
44 45 46 47 48 49 50 51 52 53 54
	x->id = tmpl->id;
	if (ipv6_addr_any((struct in6_addr*)&x->id.daddr))
		memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr));
	memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
	if (ipv6_addr_any((struct in6_addr*)&x->props.saddr))
		memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr));
	x->props.mode = tmpl->mode;
	x->props.reqid = tmpl->reqid;
	x->props.family = AF_INET6;
}

55
/* distribution counting sort function for xfrm_state and xfrm_tmpl */
56
static int
57
__xfrm6_sort(void **dst, void **src, int n, int (*cmp)(void *p), int maxclass)
58 59
{
	int i;
60 61
	int class[XFRM_MAX_DEPTH];
	int count[maxclass];
62

63
	memset(count, 0, sizeof(count));
64

65
	for (i = 0; i < n; i++) {
66 67 68
		int c;
		class[i] = c = cmp(src[i]);
		count[c]++;
69
	}
70

71 72
	for (i = 2; i < maxclass; i++)
		count[i] += count[i - 1];
73 74

	for (i = 0; i < n; i++) {
75
		dst[count[class[i] - 1]++] = src[i];
76
		src[i] = NULL;
77 78 79 80 81
	}

	return 0;
}

82 83 84 85 86 87 88 89 90 91
/*
 * Rule for xfrm_state:
 *
 * rule 1: select IPsec transport except AH
 * rule 2: select MIPv6 RO or inbound trigger
 * rule 3: select IPsec transport AH
 * rule 4: select IPsec tunnel
 * rule 5: others
 */
static int __xfrm6_state_sort_cmp(void *p)
92
{
93 94 95 96 97 98 99 100
	struct xfrm_state *v = p;

	switch (v->props.mode) {
	case XFRM_MODE_TRANSPORT:
		if (v->id.proto != IPPROTO_AH)
			return 1;
		else
			return 3;
101
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
102 103 104
	case XFRM_MODE_ROUTEOPTIMIZATION:
	case XFRM_MODE_IN_TRIGGER:
		return 2;
105
#endif
106 107 108
	case XFRM_MODE_TUNNEL:
	case XFRM_MODE_BEET:
		return 4;
109
	}
110 111
	return 5;
}
112

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
static int
__xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n)
{
	return __xfrm6_sort((void **)dst, (void **)src, n,
			    __xfrm6_state_sort_cmp, 6);
}

/*
 * Rule for xfrm_tmpl:
 *
 * rule 1: select IPsec transport
 * rule 2: select MIPv6 RO or inbound trigger
 * rule 3: select IPsec tunnel
 * rule 4: others
 */
static int __xfrm6_tmpl_sort_cmp(void *p)
{
	struct xfrm_tmpl *v = p;
	switch (v->mode) {
	case XFRM_MODE_TRANSPORT:
		return 1;
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
	case XFRM_MODE_ROUTEOPTIMIZATION:
	case XFRM_MODE_IN_TRIGGER:
		return 2;
#endif
	case XFRM_MODE_TUNNEL:
	case XFRM_MODE_BEET:
		return 3;
142
	}
143 144
	return 4;
}
145

146 147 148 149 150
static int
__xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n)
{
	return __xfrm6_sort((void **)dst, (void **)src, n,
			    __xfrm6_tmpl_sort_cmp, 5);
151 152
}

153 154 155 156
int xfrm6_extract_header(struct sk_buff *skb)
{
	struct ipv6hdr *iph = ipv6_hdr(skb);

H
Herbert Xu 已提交
157
	XFRM_MODE_SKB_CB(skb)->ihl = sizeof(*iph);
158 159 160 161
	XFRM_MODE_SKB_CB(skb)->id = 0;
	XFRM_MODE_SKB_CB(skb)->frag_off = htons(IP_DF);
	XFRM_MODE_SKB_CB(skb)->tos = ipv6_get_dsfield(iph);
	XFRM_MODE_SKB_CB(skb)->ttl = iph->hop_limit;
H
Herbert Xu 已提交
162
	XFRM_MODE_SKB_CB(skb)->optlen = 0;
163 164 165 166 167 168
	memcpy(XFRM_MODE_SKB_CB(skb)->flow_lbl, iph->flow_lbl,
	       sizeof(XFRM_MODE_SKB_CB(skb)->flow_lbl));

	return 0;
}

L
Linus Torvalds 已提交
169 170
static struct xfrm_state_afinfo xfrm6_state_afinfo = {
	.family			= AF_INET6,
171
	.proto			= IPPROTO_IPV6,
172
	.eth_proto		= htons(ETH_P_IPV6),
173
	.owner			= THIS_MODULE,
L
Linus Torvalds 已提交
174
	.init_tempsel		= __xfrm6_init_tempsel,
175
	.init_temprop		= xfrm6_init_temprop,
176 177
	.tmpl_sort		= __xfrm6_tmpl_sort,
	.state_sort		= __xfrm6_state_sort,
178
	.output			= xfrm6_output,
179
	.extract_input		= xfrm6_extract_input,
180
	.extract_output		= xfrm6_extract_output,
181
	.transport_finish	= xfrm6_transport_finish,
L
Linus Torvalds 已提交
182 183
};

184
int __init xfrm6_state_init(void)
L
Linus Torvalds 已提交
185
{
186
	return xfrm_state_register_afinfo(&xfrm6_state_afinfo);
L
Linus Torvalds 已提交
187 188 189 190 191 192 193
}

void xfrm6_state_fini(void)
{
	xfrm_state_unregister_afinfo(&xfrm6_state_afinfo);
}