~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv6/af_inet6.c

Version: ~ [ linux-5.15-rc5 ] ~ [ linux-5.14.11 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.72 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.152 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.210 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.250 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.286 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.288 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *      PF_INET6 socket protocol family
  3  *      Linux INET6 implementation 
  4  *
  5  *      Authors:
  6  *      Pedro Roque             <pedro_m@yahoo.com>     
  7  *
  8  *      Adapted from linux/net/ipv4/af_inet.c
  9  *
 10  *      $Id: af_inet6.c,v 1.65 2001/10/02 02:22:36 davem 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:           udp_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 proto_ops inet6_sockraw_ops = {
513         family:         PF_INET6,
514 
515         release:        inet6_release,
516         bind:           inet6_bind,
517         connect:        inet_dgram_connect,             /* ok           */
518         socketpair:     sock_no_socketpair,             /* a do nothing */
519         accept:         sock_no_accept,                 /* a do nothing */
520         getname:        inet6_getname, 
521         poll:           datagram_poll,                  /* ok           */
522         ioctl:          inet6_ioctl,                    /* must change  */
523         listen:         sock_no_listen,                 /* ok           */
524         shutdown:       inet_shutdown,                  /* ok           */
525         setsockopt:     inet_setsockopt,                /* ok           */
526         getsockopt:     inet_getsockopt,                /* ok           */
527         sendmsg:        inet_sendmsg,                   /* ok           */
528         recvmsg:        inet_recvmsg,                   /* ok           */
529         mmap:           sock_no_mmap,
530         sendpage:       sock_no_sendpage,
531 };
532 
533 struct net_proto_family inet6_family_ops = {
534         PF_INET6,
535         inet6_create
536 };
537 
538 #ifdef MODULE
539 int ipv6_unload(void)
540 {
541         if (!unloadable) return 1;
542         /* We keep internally 3 raw sockets */
543         return atomic_read(&(__this_module.uc.usecount)) - 3;
544 }
545 #endif
546 
547 #if defined(MODULE) && defined(CONFIG_SYSCTL)
548 extern void ipv6_sysctl_register(void);
549 extern void ipv6_sysctl_unregister(void);
550 #endif
551 
552 static struct inet_protosw rawv6_protosw = {
553         type:        SOCK_RAW,
554         protocol:    IPPROTO_IP,        /* wild card */
555         prot:        &rawv6_prot,
556         ops:         &inet6_sockraw_ops,
557         capability:  CAP_NET_RAW,
558         no_check:    UDP_CSUM_DEFAULT,
559         flags:       INET_PROTOSW_REUSE,
560 };
561 
562 #define INETSW6_ARRAY_LEN (sizeof(inetsw6_array) / sizeof(struct inet_protosw))
563 
564 void
565 inet6_register_protosw(struct inet_protosw *p)
566 {
567         struct list_head *lh;
568         struct inet_protosw *answer;
569         int protocol = p->protocol;
570         struct list_head *last_perm;
571 
572         br_write_lock_bh(BR_NETPROTO_LOCK);
573 
574         if (p->type >= SOCK_MAX)
575                 goto out_illegal;
576 
577         /* If we are trying to override a permanent protocol, bail. */
578         answer = NULL;
579         last_perm = &inetsw6[p->type];
580         list_for_each(lh, &inetsw6[p->type]) {
581                 answer = list_entry(lh, struct inet_protosw, list);
582 
583                 /* Check only the non-wild match. */
584                 if (INET_PROTOSW_PERMANENT & answer->flags) {
585                         if (protocol == answer->protocol)
586                                 break;
587                         last_perm = lh;
588                 }
589 
590                 answer = NULL;
591         }
592         if (answer)
593                 goto out_permanent;
594 
595         /* Add the new entry after the last permanent entry if any, so that
596          * the new entry does not override a permanent entry when matched with
597          * a wild-card protocol. But it is allowed to override any existing
598          * non-permanent entry.  This means that when we remove this entry, the 
599          * system automatically returns to the old behavior.
600          */
601         list_add(&p->list, last_perm);
602 out:
603         br_write_unlock_bh(BR_NETPROTO_LOCK);
604         return;
605 
606 out_permanent:
607         printk(KERN_ERR "Attempt to override permanent protocol %d.\n",
608                protocol);
609         goto out;
610 
611 out_illegal:
612         printk(KERN_ERR
613                "Ignoring attempt to register illegal socket type %d.\n",
614                p->type);
615         goto out;
616 }
617 
618 void
619 inet6_unregister_protosw(struct inet_protosw *p)
620 {
621         inet_unregister_protosw(p);
622 }
623 
624 static int __init inet6_init(void)
625 {
626         struct sk_buff *dummy_skb;
627         struct list_head *r;
628         int err;
629 
630 #ifdef MODULE
631         if (!mod_member_present(&__this_module, can_unload))
632           return -EINVAL;
633 
634         __this_module.can_unload = &ipv6_unload;
635 #endif
636 
637         printk(KERN_INFO "IPv6 v0.8 for NET4.0\n");
638 
639         if (sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb))
640         {
641                 printk(KERN_CRIT "inet6_proto_init: size fault\n");
642                 return -EINVAL;
643         }
644 
645         /* Register the socket-side information for inet6_create.  */
646         for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r)
647                 INIT_LIST_HEAD(r);
648 
649         /* We MUST register RAW sockets before we create the ICMP6,
650          * IGMP6, or NDISC control sockets.
651          */
652         inet6_register_protosw(&rawv6_protosw);
653 
654         /*
655          *      ipngwg API draft makes clear that the correct semantics
656          *      for TCP and UDP is to consider one TCP and UDP instance
657          *      in a host available by both INET and INET6 APIs and
658          *      able to communicate via both network protocols.
659          */
660 
661 #if defined(MODULE) && defined(CONFIG_SYSCTL)
662         ipv6_sysctl_register();
663 #endif
664         err = icmpv6_init(&inet6_family_ops);
665         if (err)
666                 goto icmp_fail;
667         err = ndisc_init(&inet6_family_ops);
668         if (err)
669                 goto ndisc_fail;
670         err = igmp6_init(&inet6_family_ops);
671         if (err)
672                 goto igmp_fail;
673         /* Create /proc/foo6 entries. */
674 #ifdef CONFIG_PROC_FS
675         err = -ENOMEM;
676         if (!proc_net_create("raw6", 0, raw6_get_info))
677                 goto proc_raw6_fail;
678         if (!proc_net_create("tcp6", 0, tcp6_get_info))
679                 goto proc_tcp6_fail;
680         if (!proc_net_create("udp6", 0, udp6_get_info))
681                 goto proc_udp6_fail;
682         if (!proc_net_create("sockstat6", 0, afinet6_get_info))
683                 goto proc_sockstat6_fail;
684         if (!proc_net_create("snmp6", 0, afinet6_get_snmp))
685                 goto proc_snmp6_fail;
686         if (!proc_net_create("anycast6", 0, anycast6_get_info))
687                 goto proc_anycast6_fail;
688 #endif
689         ipv6_netdev_notif_init();
690         ipv6_packet_init();
691         ip6_route_init();
692         ip6_flowlabel_init();
693         addrconf_init();
694         sit_init();
695         ipv6_frag_init();
696 
697         /* Init v6 transport protocols. */
698         udpv6_init();
699         tcpv6_init();
700 
701         /* Now the userspace is allowed to create INET6 sockets. */
702         (void) sock_register(&inet6_family_ops);
703         
704         return 0;
705 
706 #ifdef CONFIG_PROC_FS
707 proc_anycast6_fail:
708         proc_net_remove("anycast6");
709 proc_snmp6_fail:
710         proc_net_remove("sockstat6");
711 proc_sockstat6_fail:
712         proc_net_remove("udp6");
713 proc_udp6_fail:
714         proc_net_remove("tcp6");
715 proc_tcp6_fail:
716         proc_net_remove("raw6");
717 proc_raw6_fail:
718         igmp6_cleanup();
719 #endif
720 igmp_fail:
721         ndisc_cleanup();
722 ndisc_fail:
723         icmpv6_cleanup();
724 icmp_fail:
725 #if defined(MODULE) && defined(CONFIG_SYSCTL)
726         ipv6_sysctl_unregister();
727 #endif
728         return err;
729 }
730 module_init(inet6_init);
731 
732 
733 #ifdef MODULE
734 static void inet6_exit(void)
735 {
736         /* First of all disallow new sockets creation. */
737         sock_unregister(PF_INET6);
738 #ifdef CONFIG_PROC_FS
739         proc_net_remove("raw6");
740         proc_net_remove("tcp6");
741         proc_net_remove("udp6");
742         proc_net_remove("sockstat6");
743         proc_net_remove("snmp6");
744         proc_net_remove("anycast6");
745 #endif
746         /* Cleanup code parts. */
747         sit_cleanup();
748         ipv6_netdev_notif_cleanup();
749         ip6_flowlabel_cleanup();
750         addrconf_cleanup();
751         ip6_route_cleanup();
752         ipv6_packet_cleanup();
753         igmp6_cleanup();
754         ndisc_cleanup();
755         icmpv6_cleanup();
756 #ifdef CONFIG_SYSCTL
757         ipv6_sysctl_unregister();       
758 #endif
759 }
760 module_exit(inet6_exit);
761 #endif /* MODULE */
762 MODULE_LICENSE("GPL");
763 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp