Merge branches 'release', 'cpuidle-2.6.25' and 'idle' into release
[linux-2.6] / net / ipv6 / xfrm6_state.c
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
22 static struct xfrm_state_afinfo xfrm6_state_afinfo;
23
24 static void
25 __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl,
26                      struct xfrm_tmpl *tmpl,
27                      xfrm_address_t *daddr, xfrm_address_t *saddr)
28 {
29         /* Initialize temporary selector matching only
30          * to current session. */
31         ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst);
32         ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src);
33         x->sel.dport = xfrm_flowi_dport(fl);
34         x->sel.dport_mask = htons(0xffff);
35         x->sel.sport = xfrm_flowi_sport(fl);
36         x->sel.sport_mask = htons(0xffff);
37         x->sel.prefixlen_d = 128;
38         x->sel.prefixlen_s = 128;
39         x->sel.proto = fl->proto;
40         x->sel.ifindex = fl->oif;
41         x->id = tmpl->id;
42         if (ipv6_addr_any((struct in6_addr*)&x->id.daddr))
43                 memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr));
44         memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
45         if (ipv6_addr_any((struct in6_addr*)&x->props.saddr))
46                 memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr));
47         x->props.mode = tmpl->mode;
48         x->props.reqid = tmpl->reqid;
49         x->props.family = AF_INET6;
50 }
51
52 static int
53 __xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n)
54 {
55         int i;
56         int j = 0;
57
58         /* Rule 1: select IPsec transport except AH */
59         for (i = 0; i < n; i++) {
60                 if (src[i]->props.mode == XFRM_MODE_TRANSPORT &&
61                     src[i]->id.proto != IPPROTO_AH) {
62                         dst[j++] = src[i];
63                         src[i] = NULL;
64                 }
65         }
66         if (j == n)
67                 goto end;
68
69         /* Rule 2: select MIPv6 RO or inbound trigger */
70 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
71         for (i = 0; i < n; i++) {
72                 if (src[i] &&
73                     (src[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION ||
74                      src[i]->props.mode == XFRM_MODE_IN_TRIGGER)) {
75                         dst[j++] = src[i];
76                         src[i] = NULL;
77                 }
78         }
79         if (j == n)
80                 goto end;
81 #endif
82
83         /* Rule 3: select IPsec transport AH */
84         for (i = 0; i < n; i++) {
85                 if (src[i] &&
86                     src[i]->props.mode == XFRM_MODE_TRANSPORT &&
87                     src[i]->id.proto == IPPROTO_AH) {
88                         dst[j++] = src[i];
89                         src[i] = NULL;
90                 }
91         }
92         if (j == n)
93                 goto end;
94
95         /* Rule 4: select IPsec tunnel */
96         for (i = 0; i < n; i++) {
97                 if (src[i] &&
98                     (src[i]->props.mode == XFRM_MODE_TUNNEL ||
99                      src[i]->props.mode == XFRM_MODE_BEET)) {
100                         dst[j++] = src[i];
101                         src[i] = NULL;
102                 }
103         }
104         if (likely(j == n))
105                 goto end;
106
107         /* Final rule */
108         for (i = 0; i < n; i++) {
109                 if (src[i]) {
110                         dst[j++] = src[i];
111                         src[i] = NULL;
112                 }
113         }
114
115  end:
116         return 0;
117 }
118
119 static int
120 __xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n)
121 {
122         int i;
123         int j = 0;
124
125         /* Rule 1: select IPsec transport */
126         for (i = 0; i < n; i++) {
127                 if (src[i]->mode == XFRM_MODE_TRANSPORT) {
128                         dst[j++] = src[i];
129                         src[i] = NULL;
130                 }
131         }
132         if (j == n)
133                 goto end;
134
135         /* Rule 2: select MIPv6 RO or inbound trigger */
136 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
137         for (i = 0; i < n; i++) {
138                 if (src[i] &&
139                     (src[i]->mode == XFRM_MODE_ROUTEOPTIMIZATION ||
140                      src[i]->mode == XFRM_MODE_IN_TRIGGER)) {
141                         dst[j++] = src[i];
142                         src[i] = NULL;
143                 }
144         }
145         if (j == n)
146                 goto end;
147 #endif
148
149         /* Rule 3: select IPsec tunnel */
150         for (i = 0; i < n; i++) {
151                 if (src[i] &&
152                     (src[i]->mode == XFRM_MODE_TUNNEL ||
153                      src[i]->mode == XFRM_MODE_BEET)) {
154                         dst[j++] = src[i];
155                         src[i] = NULL;
156                 }
157         }
158         if (likely(j == n))
159                 goto end;
160
161         /* Final rule */
162         for (i = 0; i < n; i++) {
163                 if (src[i]) {
164                         dst[j++] = src[i];
165                         src[i] = NULL;
166                 }
167         }
168
169  end:
170         return 0;
171 }
172
173 int xfrm6_extract_header(struct sk_buff *skb)
174 {
175         struct ipv6hdr *iph = ipv6_hdr(skb);
176
177         XFRM_MODE_SKB_CB(skb)->id = 0;
178         XFRM_MODE_SKB_CB(skb)->frag_off = htons(IP_DF);
179         XFRM_MODE_SKB_CB(skb)->tos = ipv6_get_dsfield(iph);
180         XFRM_MODE_SKB_CB(skb)->ttl = iph->hop_limit;
181         memcpy(XFRM_MODE_SKB_CB(skb)->flow_lbl, iph->flow_lbl,
182                sizeof(XFRM_MODE_SKB_CB(skb)->flow_lbl));
183
184         return 0;
185 }
186
187 static struct xfrm_state_afinfo xfrm6_state_afinfo = {
188         .family                 = AF_INET6,
189         .proto                  = IPPROTO_IPV6,
190         .eth_proto              = htons(ETH_P_IPV6),
191         .owner                  = THIS_MODULE,
192         .init_tempsel           = __xfrm6_init_tempsel,
193         .tmpl_sort              = __xfrm6_tmpl_sort,
194         .state_sort             = __xfrm6_state_sort,
195         .output                 = xfrm6_output,
196         .extract_input          = xfrm6_extract_input,
197         .extract_output         = xfrm6_extract_output,
198         .transport_finish       = xfrm6_transport_finish,
199 };
200
201 int __init xfrm6_state_init(void)
202 {
203         return xfrm_state_register_afinfo(&xfrm6_state_afinfo);
204 }
205
206 void xfrm6_state_fini(void)
207 {
208         xfrm_state_unregister_afinfo(&xfrm6_state_afinfo);
209 }
210