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
- Lines: 276
- Date:
Wed Jun 20 21:00:55 2001
- Orig file:
v2.4.5/linux/net/ipv4/af_inet.c
- Orig date:
Tue May 1 20:59:24 2001
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)