patch-2.4.6 linux/net/ipv6/af_inet6.c
Next file: linux/net/ipv6/exthdrs.c
Previous file: linux/net/ipv6/addrconf.c
Back to the patch index
Back to the overall index
- Lines: 255
- Date:
Wed Jun 20 21:00:55 2001
- Orig file:
v2.4.5/linux/net/ipv6/af_inet6.c
- Orig date:
Thu Apr 12 12:11:39 2001
diff -u --recursive --new-file v2.4.5/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
@@ -7,9 +7,10 @@
*
* Adapted from linux/net/ipv4/af_inet.c
*
- * $Id: af_inet6.c,v 1.63 2001/03/02 03:13:05 davem Exp $
+ * $Id: af_inet6.c,v 1.64 2001/06/13 16:25:03 davem Exp $
*
* Fixes:
+ * piggy, Karl Knutson : Socket protocol table
* Hideaki YOSHIFUJI : sin6_scope_id support
* Arnaldo Melo : check proc_net_create return, cleanups
*
@@ -44,6 +45,7 @@
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/icmpv6.h>
+#include <linux/brlock.h>
#include <linux/smp_lock.h>
#include <net/ip.h>
@@ -71,9 +73,6 @@
MODULE_PARM(unloadable, "i");
#endif
-extern struct proto_ops inet6_stream_ops;
-extern struct proto_ops inet6_dgram_ops;
-
/* IPv6 procfs goodies... */
#ifdef CONFIG_PROC_FS
@@ -93,6 +92,11 @@
atomic_t inet6_sock_nr;
#endif
+/* The inetsw table contains everything that inet_create needs to
+ * build a new socket.
+ */
+struct list_head inetsw6[SOCK_MAX];
+
static void inet6_sock_destruct(struct sock *sk)
{
inet_sock_destruct(sk);
@@ -106,47 +110,63 @@
static int inet6_create(struct socket *sock, int protocol)
{
struct sock *sk;
- struct proto *prot;
+ struct list_head *p;
+ struct inet_protosw *answer;
sk = sk_alloc(PF_INET6, GFP_KERNEL, 1);
if (sk == NULL)
goto do_oom;
- if(sock->type == SOCK_STREAM || sock->type == SOCK_SEQPACKET) {
- if (protocol && protocol != IPPROTO_TCP)
- goto free_and_noproto;
- protocol = IPPROTO_TCP;
- prot = &tcpv6_prot;
- sock->ops = &inet6_stream_ops;
- } else if(sock->type == SOCK_DGRAM) {
- if (protocol && protocol != IPPROTO_UDP)
- goto free_and_noproto;
- protocol = IPPROTO_UDP;
- sk->no_check = UDP_CSUM_DEFAULT;
- prot=&udpv6_prot;
- sock->ops = &inet6_dgram_ops;
- } else if(sock->type == SOCK_RAW) {
- if (!capable(CAP_NET_RAW))
- goto free_and_badperm;
- if (!protocol)
- goto free_and_noproto;
- prot = &rawv6_prot;
- sock->ops = &inet6_dgram_ops;
+ /* Look for the requested type/protocol pair. */
+ answer = NULL;
+ br_read_lock_bh(BR_NETPROTO_LOCK);
+ list_for_each(p, &inetsw6[sock->type]) {
+ answer = list_entry(p, struct inet_protosw, list);
+
+ /* Check the non-wild match. */
+ if (protocol == answer->protocol) {
+ if (protocol != IPPROTO_IP)
+ break;
+ } else {
+ /* Check for the two wild cases. */
+ if (IPPROTO_IP == protocol) {
+ protocol = answer->protocol;
+ break;
+ }
+ if (IPPROTO_IP == answer->protocol)
+ break;
+ }
+ answer = NULL;
+ }
+ br_read_unlock_bh(BR_NETPROTO_LOCK);
+
+ if (!answer)
+ goto free_and_badtype;
+ if (answer->capability > 0 && !capable(answer->capability))
+ goto free_and_badperm;
+ if (!protocol)
+ goto free_and_noproto;
+
+ sock->ops = answer->ops;
+ sock_init_data(sock, sk);
+
+ sk->prot = answer->prot;
+ sk->no_check = answer->no_check;
+ if (INET_PROTOSW_REUSE & answer->flags)
sk->reuse = 1;
+
+ if (SOCK_RAW == sock->type) {
sk->num = protocol;
- } else {
- goto free_and_badtype;
+ if (IPPROTO_RAW == protocol)
+ sk->protinfo.af_inet.hdrincl = 1;
}
-
- sock_init_data(sock, sk);
sk->destruct = inet6_sock_destruct;
sk->zapped = 0;
sk->family = PF_INET6;
sk->protocol = protocol;
- sk->prot = prot;
- sk->backlog_rcv = prot->backlog_rcv;
+ sk->backlog_rcv = answer->prot->backlog_rcv;
sk->net_pinfo.af_inet6.hop_limit = -1;
sk->net_pinfo.af_inet6.mcast_hops = -1;
@@ -175,9 +195,6 @@
#endif
MOD_INC_USE_COUNT;
- if (sk->type==SOCK_RAW && protocol==IPPROTO_RAW)
- sk->protinfo.af_inet.hdrincl=1;
-
if (sk->num) {
/* It assumes that any protocol which allows
* the user to assign a number at socket
@@ -186,16 +203,15 @@
sk->sport = ntohs(sk->num);
sk->prot->hash(sk);
}
-
if (sk->prot->init) {
int err = sk->prot->init(sk);
if (err != 0) {
MOD_DEC_USE_COUNT;
inet_sock_release(sk);
- return(err);
+ return err;
}
}
- return(0);
+ return 0;
free_and_badtype:
sk_free(sk);
@@ -504,9 +520,76 @@
extern void ipv6_sysctl_unregister(void);
#endif
+static struct inet_protosw rawv6_protosw = {
+ type: SOCK_RAW,
+ protocol: IPPROTO_IP, /* wild card */
+ prot: &rawv6_prot,
+ ops: &inet6_dgram_ops,
+ capability: CAP_NET_RAW,
+ no_check: UDP_CSUM_DEFAULT,
+ flags: INET_PROTOSW_REUSE,
+};
+
+#define INETSW6_ARRAY_LEN (sizeof(inetsw6_array) / sizeof(struct inet_protosw))
+
+void
+inet6_register_protosw(struct inet_protosw *p)
+{
+ struct list_head *lh;
+ struct inet_protosw *answer;
+ int protocol = p->protocol;
+
+ br_write_lock_bh(BR_NETPROTO_LOCK);
+
+ if (p->type > SOCK_MAX)
+ goto out_illegal;
+
+ /* If we are trying to override a permanent protocol, bail. */
+ answer = NULL;
+ list_for_each(lh, &inetsw6[p->type]) {
+ answer = list_entry(lh, struct inet_protosw, list);
+
+ /* Check only the non-wild match. */
+ if (protocol == answer->protocol &&
+ (INET_PROTOSW_PERMANENT & answer->flags))
+ break;
+
+ answer = NULL;
+ }
+ if (answer)
+ goto out_permanent;
+
+ /* Add to the BEGINNING so that we override any existing
+ * entry. This means that when we remove this entry, the
+ * system automatically returns to the old behavior.
+ */
+ list_add(&p->list, &inetsw6[p->type]);
+out:
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
+ return;
+
+out_permanent:
+ printk(KERN_ERR "Attempt to override permanent protocol %d.\n",
+ protocol);
+ goto out;
+
+out_illegal:
+ printk(KERN_ERR
+ "Ignoring attempt to register illegal socket type %d.\n",
+ p->type);
+ goto out;
+}
+
+void
+inet6_unregister_protosw(struct inet_protosw *p)
+{
+ inet_unregister_protosw(p);
+}
+
static int __init inet6_init(void)
{
struct sk_buff *dummy_skb;
+ struct list_head *r;
int err;
#ifdef MODULE
@@ -523,6 +606,15 @@
printk(KERN_CRIT "inet6_proto_init: size fault\n");
return -EINVAL;
}
+
+ /* Register the socket-side information for inet6_create. */
+ for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r)
+ INIT_LIST_HEAD(r);
+
+ /* We MUST register RAW sockets before we create the ICMP6,
+ * IGMP6, or NDISC control sockets.
+ */
+ inet6_register_protosw(&rawv6_protosw);
/*
* ipngwg API draft makes clear that the correct semantics
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)