OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [net/] [ipv6/] [xfrm6_tunnel.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 * Copyright (C)2003,2004 USAGI/WIDE Project
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 2 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software
16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
 *
18
 * Authors      Mitsuru KANDA  <mk@linux-ipv6.org>
19
 *              YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
20
 *
21
 * Based on net/ipv4/xfrm4_tunnel.c
22
 *
23
 */
24
#include <linux/module.h>
25
#include <linux/xfrm.h>
26
#include <linux/list.h>
27
#include <net/ip.h>
28
#include <net/xfrm.h>
29
#include <net/ipv6.h>
30
#include <linux/ipv6.h>
31
#include <linux/icmpv6.h>
32
#include <linux/mutex.h>
33
 
34
/*
35
 * xfrm_tunnel_spi things are for allocating unique id ("spi")
36
 * per xfrm_address_t.
37
 */
38
struct xfrm6_tunnel_spi {
39
        struct hlist_node list_byaddr;
40
        struct hlist_node list_byspi;
41
        xfrm_address_t addr;
42
        u32 spi;
43
        atomic_t refcnt;
44
};
45
 
46
static DEFINE_RWLOCK(xfrm6_tunnel_spi_lock);
47
 
48
static u32 xfrm6_tunnel_spi;
49
 
50
#define XFRM6_TUNNEL_SPI_MIN    1
51
#define XFRM6_TUNNEL_SPI_MAX    0xffffffff
52
 
53
static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly;
54
 
55
#define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256
56
#define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256
57
 
58
static struct hlist_head xfrm6_tunnel_spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE];
59
static struct hlist_head xfrm6_tunnel_spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE];
60
 
61
static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr)
62
{
63
        unsigned h;
64
 
65
        h = (__force u32)(addr->a6[0] ^ addr->a6[1] ^ addr->a6[2] ^ addr->a6[3]);
66
        h ^= h >> 16;
67
        h ^= h >> 8;
68
        h &= XFRM6_TUNNEL_SPI_BYADDR_HSIZE - 1;
69
 
70
        return h;
71
}
72
 
73
static inline unsigned xfrm6_tunnel_spi_hash_byspi(u32 spi)
74
{
75
        return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE;
76
}
77
 
78
 
79
static int xfrm6_tunnel_spi_init(void)
80
{
81
        int i;
82
 
83
        xfrm6_tunnel_spi = 0;
84
        xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi",
85
                                                  sizeof(struct xfrm6_tunnel_spi),
86
                                                  0, SLAB_HWCACHE_ALIGN,
87
                                                  NULL);
88
        if (!xfrm6_tunnel_spi_kmem)
89
                return -ENOMEM;
90
 
91
        for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
92
                INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byaddr[i]);
93
        for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++)
94
                INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byspi[i]);
95
        return 0;
96
}
97
 
98
static void xfrm6_tunnel_spi_fini(void)
99
{
100
        int i;
101
 
102
        for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) {
103
                if (!hlist_empty(&xfrm6_tunnel_spi_byaddr[i]))
104
                        return;
105
        }
106
        for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) {
107
                if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i]))
108
                        return;
109
        }
110
        kmem_cache_destroy(xfrm6_tunnel_spi_kmem);
111
        xfrm6_tunnel_spi_kmem = NULL;
112
}
113
 
114
static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
115
{
116
        struct xfrm6_tunnel_spi *x6spi;
117
        struct hlist_node *pos;
118
 
119
        hlist_for_each_entry(x6spi, pos,
120
                             &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
121
                             list_byaddr) {
122
                if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0)
123
                        return x6spi;
124
        }
125
 
126
        return NULL;
127
}
128
 
129
__be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
130
{
131
        struct xfrm6_tunnel_spi *x6spi;
132
        u32 spi;
133
 
134
        read_lock_bh(&xfrm6_tunnel_spi_lock);
135
        x6spi = __xfrm6_tunnel_spi_lookup(saddr);
136
        spi = x6spi ? x6spi->spi : 0;
137
        read_unlock_bh(&xfrm6_tunnel_spi_lock);
138
        return htonl(spi);
139
}
140
 
141
EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup);
142
 
143
static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
144
{
145
        u32 spi;
146
        struct xfrm6_tunnel_spi *x6spi;
147
        struct hlist_node *pos;
148
        unsigned index;
149
 
150
        if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN ||
151
            xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX)
152
                xfrm6_tunnel_spi = XFRM6_TUNNEL_SPI_MIN;
153
        else
154
                xfrm6_tunnel_spi++;
155
 
156
        for (spi = xfrm6_tunnel_spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) {
157
                index = xfrm6_tunnel_spi_hash_byspi(spi);
158
                hlist_for_each_entry(x6spi, pos,
159
                                     &xfrm6_tunnel_spi_byspi[index],
160
                                     list_byspi) {
161
                        if (x6spi->spi == spi)
162
                                goto try_next_1;
163
                }
164
                xfrm6_tunnel_spi = spi;
165
                goto alloc_spi;
166
try_next_1:;
167
        }
168
        for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tunnel_spi; spi++) {
169
                index = xfrm6_tunnel_spi_hash_byspi(spi);
170
                hlist_for_each_entry(x6spi, pos,
171
                                     &xfrm6_tunnel_spi_byspi[index],
172
                                     list_byspi) {
173
                        if (x6spi->spi == spi)
174
                                goto try_next_2;
175
                }
176
                xfrm6_tunnel_spi = spi;
177
                goto alloc_spi;
178
try_next_2:;
179
        }
180
        spi = 0;
181
        goto out;
182
alloc_spi:
183
        x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC);
184
        if (!x6spi)
185
                goto out;
186
 
187
        memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr));
188
        x6spi->spi = spi;
189
        atomic_set(&x6spi->refcnt, 1);
190
 
191
        hlist_add_head(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]);
192
 
193
        index = xfrm6_tunnel_spi_hash_byaddr(saddr);
194
        hlist_add_head(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]);
195
out:
196
        return spi;
197
}
198
 
199
__be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
200
{
201
        struct xfrm6_tunnel_spi *x6spi;
202
        u32 spi;
203
 
204
        write_lock_bh(&xfrm6_tunnel_spi_lock);
205
        x6spi = __xfrm6_tunnel_spi_lookup(saddr);
206
        if (x6spi) {
207
                atomic_inc(&x6spi->refcnt);
208
                spi = x6spi->spi;
209
        } else
210
                spi = __xfrm6_tunnel_alloc_spi(saddr);
211
        write_unlock_bh(&xfrm6_tunnel_spi_lock);
212
 
213
        return htonl(spi);
214
}
215
 
216
EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi);
217
 
218
void xfrm6_tunnel_free_spi(xfrm_address_t *saddr)
219
{
220
        struct xfrm6_tunnel_spi *x6spi;
221
        struct hlist_node *pos, *n;
222
 
223
        write_lock_bh(&xfrm6_tunnel_spi_lock);
224
 
225
        hlist_for_each_entry_safe(x6spi, pos, n,
226
                                  &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
227
                                  list_byaddr)
228
        {
229
                if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) {
230
                        if (atomic_dec_and_test(&x6spi->refcnt)) {
231
                                hlist_del(&x6spi->list_byaddr);
232
                                hlist_del(&x6spi->list_byspi);
233
                                kmem_cache_free(xfrm6_tunnel_spi_kmem, x6spi);
234
                                break;
235
                        }
236
                }
237
        }
238
        write_unlock_bh(&xfrm6_tunnel_spi_lock);
239
}
240
 
241
EXPORT_SYMBOL(xfrm6_tunnel_free_spi);
242
 
243
static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
244
{
245
        skb_push(skb, -skb_network_offset(skb));
246
        return 0;
247
}
248
 
249
static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
250
{
251
        return skb_network_header(skb)[IP6CB(skb)->nhoff];
252
}
253
 
254
static int xfrm6_tunnel_rcv(struct sk_buff *skb)
255
{
256
        struct ipv6hdr *iph = ipv6_hdr(skb);
257
        __be32 spi;
258
 
259
        spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr);
260
        return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0;
261
}
262
 
263
static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
264
                            int type, int code, int offset, __be32 info)
265
{
266
        /* xfrm6_tunnel native err handling */
267
        switch (type) {
268
        case ICMPV6_DEST_UNREACH:
269
                switch (code) {
270
                case ICMPV6_NOROUTE:
271
                case ICMPV6_ADM_PROHIBITED:
272
                case ICMPV6_NOT_NEIGHBOUR:
273
                case ICMPV6_ADDR_UNREACH:
274
                case ICMPV6_PORT_UNREACH:
275
                default:
276
                        break;
277
                }
278
                break;
279
        case ICMPV6_PKT_TOOBIG:
280
                break;
281
        case ICMPV6_TIME_EXCEED:
282
                switch (code) {
283
                case ICMPV6_EXC_HOPLIMIT:
284
                        break;
285
                case ICMPV6_EXC_FRAGTIME:
286
                default:
287
                        break;
288
                }
289
                break;
290
        case ICMPV6_PARAMPROB:
291
                switch (code) {
292
                case ICMPV6_HDR_FIELD: break;
293
                case ICMPV6_UNK_NEXTHDR: break;
294
                case ICMPV6_UNK_OPTION: break;
295
                }
296
                break;
297
        default:
298
                break;
299
        }
300
 
301
        return 0;
302
}
303
 
304
static int xfrm6_tunnel_init_state(struct xfrm_state *x)
305
{
306
        if (x->props.mode != XFRM_MODE_TUNNEL)
307
                return -EINVAL;
308
 
309
        if (x->encap)
310
                return -EINVAL;
311
 
312
        x->props.header_len = sizeof(struct ipv6hdr);
313
 
314
        return 0;
315
}
316
 
317
static void xfrm6_tunnel_destroy(struct xfrm_state *x)
318
{
319
        xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr);
320
}
321
 
322
static struct xfrm_type xfrm6_tunnel_type = {
323
        .description    = "IP6IP6",
324
        .owner          = THIS_MODULE,
325
        .proto          = IPPROTO_IPV6,
326
        .init_state     = xfrm6_tunnel_init_state,
327
        .destructor     = xfrm6_tunnel_destroy,
328
        .input          = xfrm6_tunnel_input,
329
        .output         = xfrm6_tunnel_output,
330
};
331
 
332
static struct xfrm6_tunnel xfrm6_tunnel_handler = {
333
        .handler        = xfrm6_tunnel_rcv,
334
        .err_handler    = xfrm6_tunnel_err,
335
        .priority       = 2,
336
};
337
 
338
static struct xfrm6_tunnel xfrm46_tunnel_handler = {
339
        .handler        = xfrm6_tunnel_rcv,
340
        .err_handler    = xfrm6_tunnel_err,
341
        .priority       = 2,
342
};
343
 
344
static int __init xfrm6_tunnel_init(void)
345
{
346
        if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0)
347
                return -EAGAIN;
348
 
349
        if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) {
350
                xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
351
                return -EAGAIN;
352
        }
353
        if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) {
354
                xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
355
                xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
356
                return -EAGAIN;
357
        }
358
        if (xfrm6_tunnel_spi_init() < 0) {
359
                xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
360
                xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
361
                xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
362
                return -EAGAIN;
363
        }
364
        return 0;
365
}
366
 
367
static void __exit xfrm6_tunnel_fini(void)
368
{
369
        xfrm6_tunnel_spi_fini();
370
        xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
371
        xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
372
        xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
373
}
374
 
375
module_init(xfrm6_tunnel_init);
376
module_exit(xfrm6_tunnel_fini);
377
MODULE_LICENSE("GPL");
378
MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_IPV6);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.