commented early_printk patch because of rejects.
[linux-flexiantxendom0-3.2.10.git] / net / ipv4 / xfrm4_policy.c
1 /* 
2  * xfrm4_policy.c
3  *
4  * Changes:
5  *      Kazunori MIYAZAWA @USAGI
6  *      YOSHIFUJI Hideaki @USAGI
7  *              Split up af-specific portion
8  *      
9  */
10
11 #include <linux/config.h>
12 #include <net/xfrm.h>
13 #include <net/ip.h>
14
15 extern struct dst_ops xfrm4_dst_ops;
16 extern struct xfrm_policy_afinfo xfrm4_policy_afinfo;
17
18 static struct xfrm_type_map xfrm4_type_map = { .lock = RW_LOCK_UNLOCKED };
19
20 static int xfrm4_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
21 {
22         return __ip_route_output_key((struct rtable**)dst, fl);
23 }
24
25 /* Check that the bundle accepts the flow and its components are
26  * still valid.
27  */
28
29 static int __xfrm4_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl)
30 {
31         do {
32                 if (xdst->u.dst.ops != &xfrm4_dst_ops)
33                         return 1;
34
35                 if (!xfrm_selector_match(&xdst->u.dst.xfrm->sel, fl, AF_INET))
36                         return 0;
37                 if (xdst->u.dst.xfrm->km.state != XFRM_STATE_VALID ||
38                     xdst->u.dst.path->obsolete > 0)
39                         return 0;
40                 xdst = (struct xfrm_dst*)xdst->u.dst.child;
41         } while (xdst);
42         return 0;
43 }
44
45 static struct dst_entry *
46 __xfrm4_find_bundle(struct flowi *fl, struct rtable *rt, struct xfrm_policy *policy)
47 {
48         struct dst_entry *dst;
49
50         if (!fl->fl4_src)
51                 fl->fl4_src = rt->rt_src;
52         if (!fl->fl4_dst)
53                 fl->fl4_dst = rt->rt_dst;
54         read_lock_bh(&policy->lock);
55         for (dst = policy->bundles; dst; dst = dst->next) {
56                 struct xfrm_dst *xdst = (struct xfrm_dst*)dst;
57                 if (xdst->u.rt.fl.oif == fl->oif &&     /*XXX*/
58                     xdst->u.rt.fl.fl4_dst == fl->fl4_dst &&
59                     xdst->u.rt.fl.fl4_src == fl->fl4_src &&
60                     __xfrm4_bundle_ok(xdst, fl)) {
61                         dst_clone(dst);
62                         break;
63                 }
64         }
65         read_unlock_bh(&policy->lock);
66         return dst;
67 }
68
69 /* Allocate chain of dst_entry's, attach known xfrm's, calculate
70  * all the metrics... Shortly, bundle a bundle.
71  */
72
73 static int
74 __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
75                       struct flowi *fl, struct dst_entry **dst_p)
76 {
77         struct dst_entry *dst, *dst_prev;
78         struct rtable *rt0 = (struct rtable*)(*dst_p);
79         struct rtable *rt = rt0;
80         u32 remote = fl->fl4_dst;
81         u32 local  = fl->fl4_src;
82         int i;
83         int err;
84         int header_len = 0;
85         int trailer_len = 0;
86
87         dst = dst_prev = NULL;
88
89         for (i = 0; i < nx; i++) {
90                 struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops);
91
92                 if (unlikely(dst1 == NULL)) {
93                         err = -ENOBUFS;
94                         goto error;
95                 }
96
97                 dst1->xfrm = xfrm[i];
98                 if (!dst)
99                         dst = dst1;
100                 else {
101                         dst_prev->child = dst1;
102                         dst1->flags |= DST_NOHASH;
103                         dst_clone(dst1);
104                 }
105                 dst_prev = dst1;
106                 if (xfrm[i]->props.mode) {
107                         remote = xfrm[i]->id.daddr.a4;
108                         local  = xfrm[i]->props.saddr.a4;
109                 }
110                 header_len += xfrm[i]->props.header_len;
111                 trailer_len += xfrm[i]->props.trailer_len;
112         }
113
114         if (remote != fl->fl4_dst) {
115                 struct flowi fl_tunnel = { .nl_u = { .ip4_u =
116                                                      { .daddr = remote,
117                                                        .saddr = local }
118                                                    }
119                                          };
120                 err = xfrm_dst_lookup((struct xfrm_dst**)&rt, &fl_tunnel, AF_INET);
121                 if (err)
122                         goto error;
123         } else {
124                 dst_hold(&rt->u.dst);
125         }
126         dst_prev->child = &rt->u.dst;
127         for (dst_prev = dst; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
128                 struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
129                 x->u.rt.fl = *fl;
130
131                 dst_prev->dev = rt->u.dst.dev;
132                 if (rt->u.dst.dev)
133                         dev_hold(rt->u.dst.dev);
134                 dst_prev->obsolete      = -1;
135                 dst_prev->flags        |= DST_HOST;
136                 dst_prev->lastuse       = jiffies;
137                 dst_prev->header_len    = header_len;
138                 dst_prev->trailer_len   = trailer_len;
139                 memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics));
140                 dst_prev->path          = &rt->u.dst;
141
142                 /* Copy neighbout for reachability confirmation */
143                 dst_prev->neighbour     = neigh_clone(rt->u.dst.neighbour);
144                 dst_prev->input         = rt->u.dst.input;
145                 dst_prev->output        = dst_prev->xfrm->type->output;
146                 if (rt->peer)
147                         atomic_inc(&rt->peer->refcnt);
148                 x->u.rt.peer = rt->peer;
149                 /* Sheit... I remember I did this right. Apparently,
150                  * it was magically lost, so this code needs audit */
151                 x->u.rt.rt_flags = rt0->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL);
152                 x->u.rt.rt_type = rt->rt_type;
153                 x->u.rt.rt_src = rt0->rt_src;
154                 x->u.rt.rt_dst = rt0->rt_dst;
155                 x->u.rt.rt_gateway = rt->rt_gateway;
156                 x->u.rt.rt_spec_dst = rt0->rt_spec_dst;
157                 header_len -= x->u.dst.xfrm->props.header_len;
158                 trailer_len -= x->u.dst.xfrm->props.trailer_len;
159         }
160         *dst_p = dst;
161         return 0;
162
163 error:
164         if (dst)
165                 dst_free(dst);
166         return err;
167 }
168
169 static void
170 _decode_session4(struct sk_buff *skb, struct flowi *fl)
171 {
172         struct iphdr *iph = skb->nh.iph;
173         u8 *xprth = skb->nh.raw + iph->ihl*4;
174
175         memset(fl, 0, sizeof(struct flowi));
176         if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) {
177                 switch (iph->protocol) {
178                 case IPPROTO_UDP:
179                 case IPPROTO_TCP:
180                 case IPPROTO_SCTP:
181                         if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
182                                 u16 *ports = (u16 *)xprth;
183
184                                 fl->fl_ip_sport = ports[0];
185                                 fl->fl_ip_dport = ports[1];
186                         }
187                         break;
188
189                 case IPPROTO_ESP:
190                         if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
191                                 u32 *ehdr = (u32 *)xprth;
192
193                                 fl->fl_ipsec_spi = ehdr[0];
194                         }
195                         break;
196
197                 case IPPROTO_AH:
198                         if (pskb_may_pull(skb, xprth + 8 - skb->data)) {
199                                 u32 *ah_hdr = (u32*)xprth;
200
201                                 fl->fl_ipsec_spi = ah_hdr[1];
202                         }
203                         break;
204
205                 case IPPROTO_COMP:
206                         if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
207                                 u16 *ipcomp_hdr = (u16 *)xprth;
208
209                                 fl->fl_ipsec_spi = ntohl(ntohs(ipcomp_hdr[1]));
210                         }
211                         break;
212                 default:
213                         fl->fl_ipsec_spi = 0;
214                         break;
215                 };
216         }
217         fl->proto = iph->protocol;
218         fl->fl4_dst = iph->daddr;
219         fl->fl4_src = iph->saddr;
220 }
221
222 static inline int xfrm4_garbage_collect(void)
223 {
224         read_lock(&xfrm4_policy_afinfo.lock);
225         xfrm4_policy_afinfo.garbage_collect();
226         read_unlock(&xfrm4_policy_afinfo.lock);
227         return (atomic_read(&xfrm4_dst_ops.entries) > xfrm4_dst_ops.gc_thresh*2);
228 }
229
230 static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu)
231 {
232         struct dst_entry *path = dst->path;
233
234         if (mtu < 68 + dst->header_len)
235                 return;
236
237         path->ops->update_pmtu(path, mtu);
238 }
239
240 struct dst_ops xfrm4_dst_ops = {
241         .family =               AF_INET,
242         .protocol =             __constant_htons(ETH_P_IP),
243         .gc =                   xfrm4_garbage_collect,
244         .update_pmtu =          xfrm4_update_pmtu,
245         .gc_thresh =            1024,
246         .entry_size =           sizeof(struct xfrm_dst),
247 };
248
249 struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
250         .family =               AF_INET,
251         .lock =                 RW_LOCK_UNLOCKED,
252         .type_map =             &xfrm4_type_map,
253         .dst_ops =              &xfrm4_dst_ops,
254         .dst_lookup =           xfrm4_dst_lookup,
255         .find_bundle =          __xfrm4_find_bundle,
256         .bundle_create =        __xfrm4_bundle_create,
257         .decode_session =       _decode_session4,
258 };
259
260 void __init xfrm4_policy_init(void)
261 {
262         xfrm_policy_register_afinfo(&xfrm4_policy_afinfo);
263 }
264
265 void __exit xfrm4_policy_fini(void)
266 {
267         xfrm_policy_unregister_afinfo(&xfrm4_policy_afinfo);
268 }
269
270 void __init xfrm4_init(void)
271 {
272         xfrm4_state_init();
273         xfrm4_policy_init();
274 }
275
276 void __exit xfrm4_fini(void)
277 {
278         //xfrm4_input_fini();
279         xfrm4_policy_fini();
280         xfrm4_state_fini();
281 }
282