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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [ipv6/] [af_inet6.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      PF_INET6 socket protocol family
3
 *      Linux INET6 implementation
4
 *
5
 *      Authors:
6
 *      Pedro Roque             <roque@di.fc.ul.pt>
7
 *
8
 *      Adapted from linux/net/ipv4/af_inet.c
9
 *
10
 *      $Id: af_inet6.c,v 1.1.1.1 2004-04-15 01:14:39 phoenix Exp $
11
 *
12
 *      Fixes:
13
 *      piggy, Karl Knutson     :       Socket protocol table
14
 *      Hideaki YOSHIFUJI       :       sin6_scope_id support
15
 *      Arnaldo Melo            :       check proc_net_create return, cleanups
16
 *
17
 *      This program is free software; you can redistribute it and/or
18
 *      modify it under the terms of the GNU General Public License
19
 *      as published by the Free Software Foundation; either version
20
 *      2 of the License, or (at your option) any later version.
21
 */
22
 
23
 
24
#include <linux/module.h>
25
#include <linux/config.h>
26
#include <linux/errno.h>
27
#include <linux/types.h>
28
#include <linux/socket.h>
29
#include <linux/in.h>
30
#include <linux/kernel.h>
31
#include <linux/major.h>
32
#include <linux/sched.h>
33
#include <linux/timer.h>
34
#include <linux/string.h>
35
#include <linux/sockios.h>
36
#include <linux/net.h>
37
#include <linux/fcntl.h>
38
#include <linux/mm.h>
39
#include <linux/interrupt.h>
40
#include <linux/proc_fs.h>
41
#include <linux/stat.h>
42
#include <linux/init.h>
43
#include <linux/version.h>
44
 
45
#include <linux/inet.h>
46
#include <linux/netdevice.h>
47
#include <linux/icmpv6.h>
48
#include <linux/brlock.h>
49
#include <linux/smp_lock.h>
50
 
51
#include <net/ip.h>
52
#include <net/ipv6.h>
53
#include <net/udp.h>
54
#include <net/tcp.h>
55
#include <net/ipip.h>
56
#include <net/protocol.h>
57
#include <net/inet_common.h>
58
#include <net/transp_v6.h>
59
#include <net/ip6_route.h>
60
#include <net/addrconf.h>
61
 
62
#include <asm/uaccess.h>
63
#include <asm/system.h>
64
 
65
#ifdef MODULE
66
static int unloadable = 0; /* XX: Turn to one when all is ok within the
67
                              module for allowing unload */
68
#endif
69
 
70
#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
71
MODULE_AUTHOR("Cast of dozens");
72
MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
73
MODULE_PARM(unloadable, "i");
74
#endif
75
 
76
/* IPv6 procfs goodies... */
77
 
78
#ifdef CONFIG_PROC_FS
79
extern int anycast6_get_info(char *, char **, off_t, int);
80
extern int raw6_get_info(char *, char **, off_t, int);
81
extern int tcp6_get_info(char *, char **, off_t, int);
82
extern int udp6_get_info(char *, char **, off_t, int);
83
extern int afinet6_get_info(char *, char **, off_t, int);
84
extern int afinet6_get_snmp(char *, char **, off_t, int);
85
#endif
86
 
87
#ifdef CONFIG_SYSCTL
88
extern void ipv6_sysctl_register(void);
89
extern void ipv6_sysctl_unregister(void);
90
#endif
91
 
92
int sysctl_ipv6_bindv6only;
93
 
94
#ifdef INET_REFCNT_DEBUG
95
atomic_t inet6_sock_nr;
96
#endif
97
 
98
/* The inetsw table contains everything that inet_create needs to
99
 * build a new socket.
100
 */
101
struct list_head inetsw6[SOCK_MAX];
102
 
103
static void inet6_sock_destruct(struct sock *sk)
104
{
105
        inet_sock_destruct(sk);
106
 
107
#ifdef INET_REFCNT_DEBUG
108
        atomic_dec(&inet6_sock_nr);
109
#endif
110
        MOD_DEC_USE_COUNT;
111
}
112
 
113
static int inet6_create(struct socket *sock, int protocol)
114
{
115
        struct sock *sk;
116
        struct list_head *p;
117
        struct inet_protosw *answer;
118
 
119
        sk = sk_alloc(PF_INET6, GFP_KERNEL, 1);
120
        if (sk == NULL)
121
                goto do_oom;
122
 
123
        /* Look for the requested type/protocol pair. */
124
        answer = NULL;
125
        br_read_lock_bh(BR_NETPROTO_LOCK);
126
        list_for_each(p, &inetsw6[sock->type]) {
127
                answer = list_entry(p, struct inet_protosw, list);
128
 
129
                /* Check the non-wild match. */
130
                if (protocol == answer->protocol) {
131
                        if (protocol != IPPROTO_IP)
132
                                break;
133
                } else {
134
                        /* Check for the two wild cases. */
135
                        if (IPPROTO_IP == protocol) {
136
                                protocol = answer->protocol;
137
                                break;
138
                        }
139
                        if (IPPROTO_IP == answer->protocol)
140
                                break;
141
                }
142
                answer = NULL;
143
        }
144
        br_read_unlock_bh(BR_NETPROTO_LOCK);
145
 
146
        if (!answer)
147
                goto free_and_badtype;
148
        if (answer->capability > 0 && !capable(answer->capability))
149
                goto free_and_badperm;
150
        if (!protocol)
151
                goto free_and_noproto;
152
 
153
        sock->ops = answer->ops;
154
        sock_init_data(sock, sk);
155
 
156
        sk->prot = answer->prot;
157
        sk->no_check = answer->no_check;
158
        if (INET_PROTOSW_REUSE & answer->flags)
159
                sk->reuse = 1;
160
 
161
        if (SOCK_RAW == sock->type) {
162
                sk->num = protocol;
163
                if (IPPROTO_RAW == protocol)
164
                        sk->protinfo.af_inet.hdrincl = 1;
165
        }
166
 
167
        sk->destruct            = inet6_sock_destruct;
168
        sk->zapped              = 0;
169
        sk->family              = PF_INET6;
170
        sk->protocol            = protocol;
171
 
172
        sk->backlog_rcv         = answer->prot->backlog_rcv;
173
 
174
        sk->net_pinfo.af_inet6.hop_limit  = -1;
175
        sk->net_pinfo.af_inet6.mcast_hops = -1;
176
        sk->net_pinfo.af_inet6.mc_loop    = 1;
177
        sk->net_pinfo.af_inet6.pmtudisc   = IPV6_PMTUDISC_WANT;
178
 
179
        sk->net_pinfo.af_inet6.ipv6only = sysctl_ipv6_bindv6only;
180
 
181
        /* Init the ipv4 part of the socket since we can have sockets
182
         * using v6 API for ipv4.
183
         */
184
        sk->protinfo.af_inet.ttl        = 64;
185
 
186
        sk->protinfo.af_inet.mc_loop    = 1;
187
        sk->protinfo.af_inet.mc_ttl     = 1;
188
        sk->protinfo.af_inet.mc_index   = 0;
189
        sk->protinfo.af_inet.mc_list    = NULL;
190
 
191
        if (ipv4_config.no_pmtu_disc)
192
                sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_DONT;
193
        else
194
                sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_WANT;
195
 
196
 
197
#ifdef INET_REFCNT_DEBUG
198
        atomic_inc(&inet6_sock_nr);
199
        atomic_inc(&inet_sock_nr);
200
#endif
201
        MOD_INC_USE_COUNT;
202
 
203
        if (sk->num) {
204
                /* It assumes that any protocol which allows
205
                 * the user to assign a number at socket
206
                 * creation time automatically shares.
207
                 */
208
                sk->sport = ntohs(sk->num);
209
                sk->prot->hash(sk);
210
        }
211
        if (sk->prot->init) {
212
                int err = sk->prot->init(sk);
213
                if (err != 0) {
214
                        MOD_DEC_USE_COUNT;
215
                        inet_sock_release(sk);
216
                        return err;
217
                }
218
        }
219
        return 0;
220
 
221
free_and_badtype:
222
        sk_free(sk);
223
        return -ESOCKTNOSUPPORT;
224
free_and_badperm:
225
        sk_free(sk);
226
        return -EPERM;
227
free_and_noproto:
228
        sk_free(sk);
229
        return -EPROTONOSUPPORT;
230
do_oom:
231
        return -ENOBUFS;
232
}
233
 
234
 
235
/* bind for INET6 API */
236
int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
237
{
238
        struct sockaddr_in6 *addr=(struct sockaddr_in6 *)uaddr;
239
        struct sock *sk = sock->sk;
240
        __u32 v4addr = 0;
241
        unsigned short snum;
242
        int addr_type = 0;
243
 
244
        /* If the socket has its own bind function then use it. */
245
        if(sk->prot->bind)
246
                return sk->prot->bind(sk, uaddr, addr_len);
247
 
248
        if (addr_len < SIN6_LEN_RFC2133)
249
                return -EINVAL;
250
        addr_type = ipv6_addr_type(&addr->sin6_addr);
251
        if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM)
252
                return -EINVAL;
253
 
254
        /* Check if the address belongs to the host. */
255
        if (addr_type == IPV6_ADDR_MAPPED) {
256
                v4addr = addr->sin6_addr.s6_addr32[3];
257
                if (inet_addr_type(v4addr) != RTN_LOCAL)
258
                        return -EADDRNOTAVAIL;
259
        } else {
260
                if (addr_type != IPV6_ADDR_ANY) {
261
                        /* ipv4 addr of the socket is invalid.  Only the
262
                         * unspecified and mapped address have a v4 equivalent.
263
                         */
264
                        v4addr = LOOPBACK4_IPV6;
265
                        if (!(addr_type & IPV6_ADDR_MULTICAST)) {
266
                                if (!ipv6_chk_addr(&addr->sin6_addr, NULL))
267
                                        return -EADDRNOTAVAIL;
268
                        }
269
                }
270
        }
271
 
272
        snum = ntohs(addr->sin6_port);
273
        if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
274
                return -EACCES;
275
 
276
        lock_sock(sk);
277
 
278
        /* Check these errors (active socket, double bind). */
279
        if ((sk->state != TCP_CLOSE)                    ||
280
            (sk->num != 0)) {
281
                release_sock(sk);
282
                return -EINVAL;
283
        }
284
 
285
        if (addr_type & IPV6_ADDR_LINKLOCAL) {
286
                if (addr_len >= sizeof(struct sockaddr_in6) &&
287
                    addr->sin6_scope_id) {
288
                        /* Override any existing binding, if another one
289
                         * is supplied by user.
290
                         */
291
                        sk->bound_dev_if = addr->sin6_scope_id;
292
                }
293
 
294
                /* Binding to link-local address requires an interface */
295
                if (sk->bound_dev_if == 0) {
296
                        release_sock(sk);
297
                        return -EINVAL;
298
                }
299
        }
300
 
301
        sk->rcv_saddr = v4addr;
302
        sk->saddr = v4addr;
303
 
304
        ipv6_addr_copy(&sk->net_pinfo.af_inet6.rcv_saddr, &addr->sin6_addr);
305
 
306
        if (!(addr_type & IPV6_ADDR_MULTICAST))
307
                ipv6_addr_copy(&sk->net_pinfo.af_inet6.saddr, &addr->sin6_addr);
308
 
309
        /* Make sure we are allowed to bind here. */
310
        if (sk->prot->get_port(sk, snum) != 0) {
311
                sk->rcv_saddr = 0;
312
                sk->saddr = 0;
313
                memset(&sk->net_pinfo.af_inet6.rcv_saddr, 0, sizeof(struct in6_addr));
314
                memset(&sk->net_pinfo.af_inet6.saddr, 0, sizeof(struct in6_addr));
315
 
316
                release_sock(sk);
317
                return -EADDRINUSE;
318
        }
319
 
320
        if (addr_type != IPV6_ADDR_ANY)
321
                sk->userlocks |= SOCK_BINDADDR_LOCK;
322
        if (snum)
323
                sk->userlocks |= SOCK_BINDPORT_LOCK;
324
        sk->sport = ntohs(sk->num);
325
        sk->dport = 0;
326
        sk->daddr = 0;
327
        release_sock(sk);
328
 
329
        return 0;
330
}
331
 
332
int inet6_release(struct socket *sock)
333
{
334
        struct sock *sk = sock->sk;
335
 
336
        if (sk == NULL)
337
                return -EINVAL;
338
 
339
        /* Free mc lists */
340
        ipv6_sock_mc_close(sk);
341
 
342
        /* Free ac lists */
343
        ipv6_sock_ac_close(sk);
344
 
345
        return inet_release(sock);
346
}
347
 
348
int inet6_destroy_sock(struct sock *sk)
349
{
350
        struct sk_buff *skb;
351
        struct ipv6_txoptions *opt;
352
 
353
        /*
354
         *      Release destination entry
355
         */
356
 
357
        sk_dst_reset(sk);
358
 
359
        /* Release rx options */
360
 
361
        if ((skb = xchg(&sk->net_pinfo.af_inet6.pktoptions, NULL)) != NULL)
362
                kfree_skb(skb);
363
 
364
        /* Free flowlabels */
365
        fl6_free_socklist(sk);
366
 
367
        /* Free tx options */
368
 
369
        if ((opt = xchg(&sk->net_pinfo.af_inet6.opt, NULL)) != NULL)
370
                sock_kfree_s(sk, opt, opt->tot_len);
371
 
372
        return 0;
373
}
374
 
375
/*
376
 *      This does both peername and sockname.
377
 */
378
 
379
int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
380
                 int *uaddr_len, int peer)
381
{
382
        struct sockaddr_in6 *sin=(struct sockaddr_in6 *)uaddr;
383
        struct sock *sk = sock->sk;
384
 
385
        sin->sin6_family = AF_INET6;
386
        sin->sin6_flowinfo = 0;
387
        sin->sin6_scope_id = 0;
388
        if (peer) {
389
                if (!sk->dport)
390
                        return -ENOTCONN;
391
                if (((1<<sk->state)&(TCPF_CLOSE|TCPF_SYN_SENT)) && peer == 1)
392
                        return -ENOTCONN;
393
                sin->sin6_port = sk->dport;
394
                memcpy(&sin->sin6_addr, &sk->net_pinfo.af_inet6.daddr,
395
                       sizeof(struct in6_addr));
396
                if (sk->net_pinfo.af_inet6.sndflow)
397
                        sin->sin6_flowinfo = sk->net_pinfo.af_inet6.flow_label;
398
        } else {
399
                if (ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr) == IPV6_ADDR_ANY)
400
                        memcpy(&sin->sin6_addr,
401
                               &sk->net_pinfo.af_inet6.saddr,
402
                               sizeof(struct in6_addr));
403
                else
404
                        memcpy(&sin->sin6_addr,
405
                               &sk->net_pinfo.af_inet6.rcv_saddr,
406
                               sizeof(struct in6_addr));
407
 
408
                sin->sin6_port = sk->sport;
409
        }
410
        if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
411
                sin->sin6_scope_id = sk->bound_dev_if;
412
        *uaddr_len = sizeof(*sin);
413
        return(0);
414
}
415
 
416
int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
417
{
418
        struct sock *sk = sock->sk;
419
        int err = -EINVAL;
420
        int pid;
421
 
422
        switch(cmd)
423
        {
424
        case FIOSETOWN:
425
        case SIOCSPGRP:
426
                if (get_user(pid, (int *) arg))
427
                        return -EFAULT;
428
                /* see sock_no_fcntl */
429
                if (current->pid != pid && current->pgrp != -pid &&
430
                    !capable(CAP_NET_ADMIN))
431
                        return -EPERM;
432
                sk->proc = pid;
433
                return(0);
434
        case FIOGETOWN:
435
        case SIOCGPGRP:
436
                return put_user(sk->proc,(int *)arg);
437
        case SIOCGSTAMP:
438
                if(sk->stamp.tv_sec==0)
439
                        return -ENOENT;
440
                err = copy_to_user((void *)arg, &sk->stamp,
441
                                   sizeof(struct timeval));
442
                if (err)
443
                        return -EFAULT;
444
                return 0;
445
 
446
        case SIOCADDRT:
447
        case SIOCDELRT:
448
 
449
                return(ipv6_route_ioctl(cmd,(void *)arg));
450
 
451
        case SIOCSIFADDR:
452
                return addrconf_add_ifaddr((void *) arg);
453
        case SIOCDIFADDR:
454
                return addrconf_del_ifaddr((void *) arg);
455
        case SIOCSIFDSTADDR:
456
                return addrconf_set_dstaddr((void *) arg);
457
        default:
458
                if ((cmd >= SIOCDEVPRIVATE) &&
459
                    (cmd <= (SIOCDEVPRIVATE + 15)))
460
                        return(dev_ioctl(cmd,(void *) arg));
461
 
462
                if(sk->prot->ioctl==0 || (err=sk->prot->ioctl(sk, cmd, arg))==-ENOIOCTLCMD)
463
                        return(dev_ioctl(cmd,(void *) arg));
464
                return err;
465
        }
466
        /*NOTREACHED*/
467
        return(0);
468
}
469
 
470
struct proto_ops inet6_stream_ops = {
471
        family:         PF_INET6,
472
 
473
        release:        inet6_release,
474
        bind:           inet6_bind,
475
        connect:        inet_stream_connect,            /* ok           */
476
        socketpair:     sock_no_socketpair,             /* a do nothing */
477
        accept:         inet_accept,                    /* ok           */
478
        getname:        inet6_getname,
479
        poll:           tcp_poll,                       /* ok           */
480
        ioctl:          inet6_ioctl,                    /* must change  */
481
        listen:         inet_listen,                    /* ok           */
482
        shutdown:       inet_shutdown,                  /* ok           */
483
        setsockopt:     inet_setsockopt,                /* ok           */
484
        getsockopt:     inet_getsockopt,                /* ok           */
485
        sendmsg:        inet_sendmsg,                   /* ok           */
486
        recvmsg:        inet_recvmsg,                   /* ok           */
487
        mmap:           sock_no_mmap,
488
        sendpage:       tcp_sendpage
489
};
490
 
491
struct proto_ops inet6_dgram_ops = {
492
        family:         PF_INET6,
493
 
494
        release:        inet6_release,
495
        bind:           inet6_bind,
496
        connect:        inet_dgram_connect,             /* ok           */
497
        socketpair:     sock_no_socketpair,             /* a do nothing */
498
        accept:         sock_no_accept,                 /* a do nothing */
499
        getname:        inet6_getname,
500
        poll:           datagram_poll,                  /* ok           */
501
        ioctl:          inet6_ioctl,                    /* must change  */
502
        listen:         sock_no_listen,                 /* ok           */
503
        shutdown:       inet_shutdown,                  /* ok           */
504
        setsockopt:     inet_setsockopt,                /* ok           */
505
        getsockopt:     inet_getsockopt,                /* ok           */
506
        sendmsg:        inet_sendmsg,                   /* ok           */
507
        recvmsg:        inet_recvmsg,                   /* ok           */
508
        mmap:           sock_no_mmap,
509
        sendpage:       sock_no_sendpage,
510
};
511
 
512
struct net_proto_family inet6_family_ops = {
513
        PF_INET6,
514
        inet6_create
515
};
516
 
517
#ifdef MODULE
518
int ipv6_unload(void)
519
{
520
        if (!unloadable) return 1;
521
        /* We keep internally 3 raw sockets */
522
        return atomic_read(&(__this_module.uc.usecount)) - 3;
523
}
524
#endif
525
 
526
#if defined(MODULE) && defined(CONFIG_SYSCTL)
527
extern void ipv6_sysctl_register(void);
528
extern void ipv6_sysctl_unregister(void);
529
#endif
530
 
531
static struct inet_protosw rawv6_protosw = {
532
        type:        SOCK_RAW,
533
        protocol:    IPPROTO_IP,        /* wild card */
534
        prot:        &rawv6_prot,
535
        ops:         &inet6_dgram_ops,
536
        capability:  CAP_NET_RAW,
537
        no_check:    UDP_CSUM_DEFAULT,
538
        flags:       INET_PROTOSW_REUSE,
539
};
540
 
541
#define INETSW6_ARRAY_LEN (sizeof(inetsw6_array) / sizeof(struct inet_protosw))
542
 
543
void
544
inet6_register_protosw(struct inet_protosw *p)
545
{
546
        struct list_head *lh;
547
        struct inet_protosw *answer;
548
        int protocol = p->protocol;
549
        struct list_head *last_perm;
550
 
551
        br_write_lock_bh(BR_NETPROTO_LOCK);
552
 
553
        if (p->type > SOCK_MAX)
554
                goto out_illegal;
555
 
556
        /* If we are trying to override a permanent protocol, bail. */
557
        answer = NULL;
558
        last_perm = &inetsw6[p->type];
559
        list_for_each(lh, &inetsw6[p->type]) {
560
                answer = list_entry(lh, struct inet_protosw, list);
561
 
562
                /* Check only the non-wild match. */
563
                if (INET_PROTOSW_PERMANENT & answer->flags) {
564
                        if (protocol == answer->protocol)
565
                                break;
566
                        last_perm = lh;
567
                }
568
 
569
                answer = NULL;
570
        }
571
        if (answer)
572
                goto out_permanent;
573
 
574
        /* Add the new entry after the last permanent entry if any, so that
575
         * the new entry does not override a permanent entry when matched with
576
         * a wild-card protocol. But it is allowed to override any existing
577
         * non-permanent entry.  This means that when we remove this entry, the
578
         * system automatically returns to the old behavior.
579
         */
580
        list_add(&p->list, last_perm);
581
out:
582
        br_write_unlock_bh(BR_NETPROTO_LOCK);
583
        return;
584
 
585
out_permanent:
586
        printk(KERN_ERR "Attempt to override permanent protocol %d.\n",
587
               protocol);
588
        goto out;
589
 
590
out_illegal:
591
        printk(KERN_ERR
592
               "Ignoring attempt to register illegal socket type %d.\n",
593
               p->type);
594
        goto out;
595
}
596
 
597
void
598
inet6_unregister_protosw(struct inet_protosw *p)
599
{
600
        inet_unregister_protosw(p);
601
}
602
 
603
static int __init inet6_init(void)
604
{
605
        struct sk_buff *dummy_skb;
606
        struct list_head *r;
607
        int err;
608
 
609
#ifdef MODULE
610
        if (!mod_member_present(&__this_module, can_unload))
611
          return -EINVAL;
612
 
613
        __this_module.can_unload = &ipv6_unload;
614
#endif
615
 
616
        printk(KERN_INFO "IPv6 v0.8 for NET4.0\n");
617
 
618
        if (sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb))
619
        {
620
                printk(KERN_CRIT "inet6_proto_init: size fault\n");
621
                return -EINVAL;
622
        }
623
 
624
        /* Register the socket-side information for inet6_create.  */
625
        for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r)
626
                INIT_LIST_HEAD(r);
627
 
628
        /* We MUST register RAW sockets before we create the ICMP6,
629
         * IGMP6, or NDISC control sockets.
630
         */
631
        inet6_register_protosw(&rawv6_protosw);
632
 
633
        /*
634
         *      ipngwg API draft makes clear that the correct semantics
635
         *      for TCP and UDP is to consider one TCP and UDP instance
636
         *      in a host available by both INET and INET6 APIs and
637
         *      able to communicate via both network protocols.
638
         */
639
 
640
#if defined(MODULE) && defined(CONFIG_SYSCTL)
641
        ipv6_sysctl_register();
642
#endif
643
        err = icmpv6_init(&inet6_family_ops);
644
        if (err)
645
                goto icmp_fail;
646
        err = ndisc_init(&inet6_family_ops);
647
        if (err)
648
                goto ndisc_fail;
649
        err = igmp6_init(&inet6_family_ops);
650
        if (err)
651
                goto igmp_fail;
652
        /* Create /proc/foo6 entries. */
653
#ifdef CONFIG_PROC_FS
654
        err = -ENOMEM;
655
        if (!proc_net_create("raw6", 0, raw6_get_info))
656
                goto proc_raw6_fail;
657
        if (!proc_net_create("tcp6", 0, tcp6_get_info))
658
                goto proc_tcp6_fail;
659
        if (!proc_net_create("udp6", 0, udp6_get_info))
660
                goto proc_udp6_fail;
661
        if (!proc_net_create("sockstat6", 0, afinet6_get_info))
662
                goto proc_sockstat6_fail;
663
        if (!proc_net_create("snmp6", 0, afinet6_get_snmp))
664
                goto proc_snmp6_fail;
665
        if (!proc_net_create("anycast6", 0, anycast6_get_info))
666
                goto proc_anycast6_fail;
667
#endif
668
        ipv6_netdev_notif_init();
669
        ipv6_packet_init();
670
        ip6_route_init();
671
        ip6_flowlabel_init();
672
        addrconf_init();
673
        sit_init();
674
        ipv6_frag_init();
675
 
676
        /* Init v6 transport protocols. */
677
        udpv6_init();
678
        tcpv6_init();
679
 
680
        /* Now the userspace is allowed to create INET6 sockets. */
681
        (void) sock_register(&inet6_family_ops);
682
 
683
        return 0;
684
 
685
#ifdef CONFIG_PROC_FS
686
proc_anycast6_fail:
687
        proc_net_remove("anycast6");
688
proc_snmp6_fail:
689
        proc_net_remove("sockstat6");
690
proc_sockstat6_fail:
691
        proc_net_remove("udp6");
692
proc_udp6_fail:
693
        proc_net_remove("tcp6");
694
proc_tcp6_fail:
695
        proc_net_remove("raw6");
696
proc_raw6_fail:
697
        igmp6_cleanup();
698
#endif
699
igmp_fail:
700
        ndisc_cleanup();
701
ndisc_fail:
702
        icmpv6_cleanup();
703
icmp_fail:
704
#if defined(MODULE) && defined(CONFIG_SYSCTL)
705
        ipv6_sysctl_unregister();
706
#endif
707
        return err;
708
}
709
module_init(inet6_init);
710
 
711
 
712
#ifdef MODULE
713
static void inet6_exit(void)
714
{
715
        /* First of all disallow new sockets creation. */
716
        sock_unregister(PF_INET6);
717
#ifdef CONFIG_PROC_FS
718
        proc_net_remove("raw6");
719
        proc_net_remove("tcp6");
720
        proc_net_remove("udp6");
721
        proc_net_remove("sockstat6");
722
        proc_net_remove("snmp6");
723
        proc_net_remove("anycast6");
724
#endif
725
        /* Cleanup code parts. */
726
        sit_cleanup();
727
        ipv6_netdev_notif_cleanup();
728
        ip6_flowlabel_cleanup();
729
        addrconf_cleanup();
730
        ip6_route_cleanup();
731
        ipv6_packet_cleanup();
732
        igmp6_cleanup();
733
        ndisc_cleanup();
734
        icmpv6_cleanup();
735
#ifdef CONFIG_SYSCTL
736
        ipv6_sysctl_unregister();
737
#endif
738
}
739
module_exit(inet6_exit);
740
#endif /* MODULE */
741
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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