patch-2.4.6 linux/net/ipv4/af_inet.c

Next file: linux/net/ipv4/fib_frontend.c
Previous file: linux/net/econet/af_econet.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.5/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
@@ -5,7 +5,7 @@
  *
  *		PF_INET protocol family socket handler.
  *
- * Version:	$Id: af_inet.c,v 1.130 2001/04/29 08:21:32 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.131 2001/06/13 16:25:03 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -14,6 +14,8 @@
  *
  * Changes (see also sock.c)
  *
+ *		piggy,
+ *		Karl Knutson	:	Socket protocol table
  *		A.N.Kuznetsov	:	Socket death error in accept().
  *		John Richardson :	Fix non blocking error in connect()
  *					so sockets that fail to connect
@@ -88,6 +90,7 @@
 #include <linux/smp_lock.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
+#include <linux/brlock.h>
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <net/arp.h>
@@ -142,6 +145,11 @@
 int (*br_ioctl_hook)(unsigned long);
 #endif
 
+/* The inetsw table contains everything that inet_create needs to
+ * build a new socket.
+ */
+struct list_head inetsw[SOCK_MAX];
+
 /* New destruction routine */
 
 void inet_sock_destruct(struct sock *sk)
@@ -309,45 +317,54 @@
 static int inet_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
-	struct proto *prot;
+        struct list_head *p;
+        struct inet_protosw *answer;
 
 	sock->state = SS_UNCONNECTED;
 	sk = sk_alloc(PF_INET, GFP_KERNEL, 1);
 	if (sk == NULL) 
 		goto do_oom;
+  
+	/* Look for the requested type/protocol pair. */
+	answer = NULL;
+	br_read_lock_bh(BR_NETPROTO_LOCK);
+	list_for_each(p, &inetsw[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);
 
-	switch (sock->type) {
-	case SOCK_STREAM:
-		if (protocol && protocol != IPPROTO_TCP)
-			goto free_and_noproto;
-		protocol = IPPROTO_TCP;
-		prot = &tcp_prot;
-		sock->ops = &inet_stream_ops;
-		break;
-	case SOCK_SEQPACKET:
+	if (!answer)
 		goto free_and_badtype;
-	case SOCK_DGRAM:
-		if (protocol && protocol != IPPROTO_UDP)
-			goto free_and_noproto;
-		protocol = IPPROTO_UDP;
-		sk->no_check = UDP_CSUM_DEFAULT;
-		prot=&udp_prot;
-		sock->ops = &inet_dgram_ops;
-		break;
-	case SOCK_RAW:
-		if (!capable(CAP_NET_RAW))
-			goto free_and_badperm;
-		if (!protocol)
-			goto free_and_noproto;
-		prot = &raw_prot;
+	if (answer->capability > 0 && !capable(answer->capability))
+		goto free_and_badperm;
+	if (!protocol)
+		goto free_and_noproto;
+
+	sock->ops = answer->ops;
+	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;
-		sock->ops = &inet_dgram_ops;
-		if (protocol == IPPROTO_RAW)
+		if (IPPROTO_RAW == protocol)
 			sk->protinfo.af_inet.hdrincl = 1;
-		break;
-	default:
-		goto free_and_badtype;
 	}
 
 	if (ipv4_config.no_pmtu_disc)
@@ -365,8 +382,7 @@
 	sk->family	= PF_INET;
 	sk->protocol	= protocol;
 
-	sk->prot	= prot;
-	sk->backlog_rcv = prot->backlog_rcv;
+	sk->backlog_rcv = sk->prot->backlog_rcv;
 
 	sk->protinfo.af_inet.ttl	= sysctl_ip_default_ttl;
 
@@ -395,10 +411,10 @@
 		int err = sk->prot->init(sk);
 		if (err != 0) {
 			inet_sock_release(sk);
-			return(err);
+			return err;
 		}
 	}
-	return(0);
+	return 0;
 
 free_and_badtype:
 	sk_free(sk);
@@ -969,6 +985,107 @@
 extern void tcp_init(void);
 extern void tcp_v4_init(struct net_proto_family *);
 
+/* Upon startup we insert all the elements in inetsw_array[] into
+ * the linked list inetsw.
+ */
+static struct inet_protosw inetsw_array[] =
+{
+        {
+                type:        SOCK_STREAM,
+                protocol:    IPPROTO_TCP,
+                prot:        &tcp_prot,
+                ops:         &inet_stream_ops,
+                capability:  -1,
+                no_check:    0,
+                flags:       INET_PROTOSW_PERMANENT,
+        },
+
+        {
+                type:        SOCK_DGRAM,
+                protocol:    IPPROTO_UDP,
+                prot:        &udp_prot,
+                ops:         &inet_dgram_ops,
+                capability:  -1,
+                no_check:    UDP_CSUM_DEFAULT,
+                flags:       INET_PROTOSW_PERMANENT,
+       },
+        
+
+       {
+               type:        SOCK_RAW,
+               protocol:    IPPROTO_IP,	/* wild card */
+               prot:        &raw_prot,
+               ops:         &inet_dgram_ops,
+               capability:  CAP_NET_RAW,
+               no_check:    UDP_CSUM_DEFAULT,
+               flags:       INET_PROTOSW_REUSE,
+       }
+};
+
+#define INETSW_ARRAY_LEN (sizeof(inetsw_array) / sizeof(struct inet_protosw))
+
+void
+inet_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, &inetsw[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, &inetsw[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
+inet_unregister_protosw(struct inet_protosw *p)
+{
+	if (INET_PROTOSW_PERMANENT & p->flags) {
+		printk(KERN_ERR
+		       "Attempt to unregister permanent protocol %d.\n",
+		       p->protocol);
+	} else {
+		br_write_lock_bh(BR_NETPROTO_LOCK);
+		list_del(&p->list);
+		br_write_unlock_bh(BR_NETPROTO_LOCK);
+	}
+}
+
 
 /*
  *	Called by socket.c on kernel startup.  
@@ -978,6 +1095,8 @@
 {
 	struct sk_buff *dummy_skb;
 	struct inet_protocol *p;
+	struct inet_protosw *q;
+	struct list_head *r;
 
 	printk(KERN_INFO "NET4: Linux TCP/IP 1.0 for NET4.0\n");
 
@@ -1003,6 +1122,13 @@
 		printk("%s%s",p->name,tmp?", ":"\n");
 		p = tmp;
 	}
+
+	/* Register the socket-side information for inet_create. */
+	for(r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
+		INIT_LIST_HEAD(r);
+
+	for(q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
+		inet_register_protosw(q);
 
 	/*
 	 *	Set the ARP module up

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)