[PATCH] sockreg2.4.5-06 inet[6]_create() register/unregister table

La Monte H.P. Yarroll (piggy@em.cig.mot.com)
Mon, 11 Jun 2001 13:26:31 -0500 (CDT)


Here is the register/unregister inet[6]_create() table patch revised
to disable deregistration and overriding of TCP and UDP.

DESCRIPTION
This patch adds a mechanism for registering new IP transport protocols
for the socket() system call. It replaces the hard-coded switch
tables in inet_create() and inet6_create() with explicit data
structures.

The new calls are:
void inet_register_protosw(struct inet_protosw *p);
void inet_unregister_protosw(struct inet_protosw *p);
void inet6_register_protosw(struct inet_protosw *p);
void inet6_unregister_protosw(struct inet_protosw *p);

This is the first of a series of proposed changes to support IP
transport modules.

MOTIVATION
As part of the effort to create the Linux Kernel implementation of
SCTP <www.sourceforge.net/projects/lksctp>, we seek to make it
possible to load a new IP transport protocol as a kernel module.

It is already possible to register new address families. It is even
possible to register new transport protocols with IP. However, in
order to be able to open a socket with a new transport protocol, you
must replace the whole AF_INET address family.

In addition to SCTP, there are other protocols which could find it
useful to be in a kernel module. For example, TCP extensions like TCP
framing and TCP over satellite, multicast protocols, and RTP/ROHC
(robust header compression). In general, support for IP transport
modules makes transport layer experimentation easier.

CHANGES SINCE sockreg2.4.5-05

Due to concerns about permitting non-GPL'd replacements for TCP, we
have added the concept of a "permanent" protocol. These protocols can
only be registered once, and then they can not be overridden or
unregistered.

CHANGES SINCE sockreg2.4.3-04

We noticed that inet6_protocol_base went away in 2.4.5, so we changed
our v6 initialization to parallel the inet6_protocol initialization.
We now call inet6_register_protosw() from *v6_init() instead of having
a static array of struct protosw's. Since other protocols depend on
raw sockets (e.g. ICMP, IGMP, NDISC) we still register rawv6_protosw
in inet6_init().

piggy (La Monte H.P. Yarroll)
Karl O. Knutson

PATCH FOLLOWS
diff -r -u linux-2.4.5-dist/include/asm-alpha/socket.h linux/include/asm-alpha/socket.h
--- linux-2.4.5-dist/include/asm-alpha/socket.h Sat Feb 3 13:26:44 2001
+++ linux/include/asm-alpha/socket.h Mon Jun 11 12:14:34 2001
@@ -66,6 +66,7 @@
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
+#define SOCK_MAX (SOCK_PACKET+1)
#endif

#endif /* _ASM_SOCKET_H */
diff -r -u linux-2.4.5-dist/include/asm-arm/socket.h linux/include/asm-arm/socket.h
--- linux-2.4.5-dist/include/asm-arm/socket.h Sat Feb 3 13:26:44 2001
+++ linux/include/asm-arm/socket.h Mon Jun 11 12:14:34 2001
@@ -58,6 +58,7 @@
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
+#define SOCK_MAX (SOCK_PACKET+1)
#endif

#endif /* _ASM_SOCKET_H */
diff -r -u linux-2.4.5-dist/include/asm-cris/socket.h linux/include/asm-cris/socket.h
--- linux-2.4.5-dist/include/asm-cris/socket.h Fri Apr 6 12:51:19 2001
+++ linux/include/asm-cris/socket.h Mon Jun 11 12:14:34 2001
@@ -59,6 +59,7 @@
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
+#define SOCK_MAX (SOCK_PACKET+1)
#endif

#endif /* _ASM_SOCKET_H */
diff -r -u linux-2.4.5-dist/include/asm-i386/socket.h linux/include/asm-i386/socket.h
--- linux-2.4.5-dist/include/asm-i386/socket.h Sat Feb 3 13:26:44 2001
+++ linux/include/asm-i386/socket.h Mon Jun 11 12:14:34 2001
@@ -58,6 +58,7 @@
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
+#define SOCK_MAX (SOCK_PACKET+1)
#endif

#endif /* _ASM_SOCKET_H */
diff -r -u linux-2.4.5-dist/include/asm-ia64/socket.h linux/include/asm-ia64/socket.h
--- linux-2.4.5-dist/include/asm-ia64/socket.h Sat Feb 3 13:26:44 2001
+++ linux/include/asm-ia64/socket.h Mon Jun 11 12:14:34 2001
@@ -65,6 +65,7 @@
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
+#define SOCK_MAX (SOCK_PACKET+1)
#endif

#endif /* _ASM_IA64_SOCKET_H */
diff -r -u linux-2.4.5-dist/include/asm-m68k/socket.h linux/include/asm-m68k/socket.h
--- linux-2.4.5-dist/include/asm-m68k/socket.h Sat Feb 3 13:26:44 2001
+++ linux/include/asm-m68k/socket.h Mon Jun 11 12:14:34 2001
@@ -58,6 +58,7 @@
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
+#define SOCK_MAX (SOCK_PACKET+1)
#endif

#endif /* _ASM_SOCKET_H */
diff -r -u linux-2.4.5-dist/include/asm-mips/socket.h linux/include/asm-mips/socket.h
--- linux-2.4.5-dist/include/asm-mips/socket.h Sat Feb 3 13:26:44 2001
+++ linux/include/asm-mips/socket.h Mon Jun 11 12:14:34 2001
@@ -71,6 +71,7 @@
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
+#define SOCK_MAX (SOCK_PACKET+1)
#endif

#endif /* _ASM_SOCKET_H */
diff -r -u linux-2.4.5-dist/include/asm-mips64/socket.h linux/include/asm-mips64/socket.h
--- linux-2.4.5-dist/include/asm-mips64/socket.h Sat Feb 3 13:26:44 2001
+++ linux/include/asm-mips64/socket.h Mon Jun 11 12:14:34 2001
@@ -79,6 +79,7 @@
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
+#define SOCK_MAX (SOCK_PACKET+1)
#endif

#endif /* _ASM_SOCKET_H */
diff -r -u linux-2.4.5-dist/include/asm-parisc/socket.h linux/include/asm-parisc/socket.h
--- linux-2.4.5-dist/include/asm-parisc/socket.h Sat Feb 3 13:26:44 2001
+++ linux/include/asm-parisc/socket.h Mon Jun 11 12:14:34 2001
@@ -56,6 +56,7 @@
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
+#define SOCK_MAX (SOCK_PACKET+1)
#endif

#endif /* _ASM_SOCKET_H */
diff -r -u linux-2.4.5-dist/include/asm-ppc/socket.h linux/include/asm-ppc/socket.h
--- linux-2.4.5-dist/include/asm-ppc/socket.h Mon May 21 17:02:06 2001
+++ linux/include/asm-ppc/socket.h Mon Jun 11 12:14:34 2001
@@ -67,6 +67,7 @@
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
+#define SOCK_MAX (SOCK_PACKET+1)
#endif

#endif /* _ASM_SOCKET_H */
diff -r -u linux-2.4.5-dist/include/asm-s390/socket.h linux/include/asm-s390/socket.h
--- linux-2.4.5-dist/include/asm-s390/socket.h Sat Feb 3 13:26:44 2001
+++ linux/include/asm-s390/socket.h Mon Jun 11 12:14:34 2001
@@ -66,6 +66,7 @@
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
+#define SOCK_MAX (SOCK_PACKET+1)
#endif

#endif /* _ASM_SOCKET_H */
diff -r -u linux-2.4.5-dist/include/asm-s390x/socket.h linux/include/asm-s390x/socket.h
--- linux-2.4.5-dist/include/asm-s390x/socket.h Fri Mar 2 13:12:06 2001
+++ linux/include/asm-s390x/socket.h Mon Jun 11 12:14:34 2001
@@ -65,6 +65,7 @@
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
+#define SOCK_MAX (SOCK_PACKET+1)
#endif

#endif /* _ASM_SOCKET_H */
diff -r -u linux-2.4.5-dist/include/asm-sh/socket.h linux/include/asm-sh/socket.h
--- linux-2.4.5-dist/include/asm-sh/socket.h Sat Feb 3 13:26:44 2001
+++ linux/include/asm-sh/socket.h Mon Jun 11 12:14:34 2001
@@ -58,6 +58,7 @@
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
+#define SOCK_MAX (SOCK_PACKET+1)
#endif

#endif /* __ASM_SH_SOCKET_H */
diff -r -u linux-2.4.5-dist/include/asm-sparc/socket.h linux/include/asm-sparc/socket.h
--- linux-2.4.5-dist/include/asm-sparc/socket.h Sat Feb 3 13:26:44 2001
+++ linux/include/asm-sparc/socket.h Mon Jun 11 12:14:34 2001
@@ -63,6 +63,7 @@
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
+#define SOCK_MAX (SOCK_PACKET+1)
#endif

#endif /* _ASM_SOCKET_H */
diff -r -u linux-2.4.5-dist/include/asm-sparc64/socket.h linux/include/asm-sparc64/socket.h
--- linux-2.4.5-dist/include/asm-sparc64/socket.h Sat Feb 3 13:26:44 2001
+++ linux/include/asm-sparc64/socket.h Mon Jun 11 12:14:34 2001
@@ -63,6 +63,7 @@
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
+#define SOCK_MAX (SOCK_PACKET+1)
#endif

#endif /* _ASM_SOCKET_H */
diff -r -u linux-2.4.5-dist/include/net/protocol.h linux/include/net/protocol.h
--- linux-2.4.5-dist/include/net/protocol.h Fri May 25 20:01:27 2001
+++ linux/include/net/protocol.h Mon Jun 11 12:56:56 2001
@@ -63,19 +63,46 @@

#endif

+/* This is used to register socket interfaces for IP protocols. */
+struct inet_protosw {
+ struct list_head list;
+
+ /* These two fields form the lookup key. */
+ unsigned short type; /* This is the 2nd argument to socket(2). */
+ int protocol; /* This is the L4 protocol number. */
+
+ struct proto *prot;
+ struct proto_ops *ops;
+
+ int capability; /* Which (if any) capability do
+ * we need to use this socket
+ * interface?
+ */
+ char no_check; /* checksum on rcv/xmit/none? */
+ unsigned char flags; /* See INET_PROTOSW_* below. */
+};
+#define INET_PROTOSW_REUSE 0x01 /* Are ports automatically reusable? */
+#define INET_PROTOSW_PERMANENT 0x02 /* Permanent protocols are unremovable. */
+
extern struct inet_protocol *inet_protocol_base;
extern struct inet_protocol *inet_protos[MAX_INET_PROTOS];
+extern struct list_head inetsw[SOCK_MAX];

#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
extern struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
+extern struct list_head inetsw6[SOCK_MAX];
#endif

extern void inet_add_protocol(struct inet_protocol *prot);
extern int inet_del_protocol(struct inet_protocol *prot);
+extern void inet_register_protosw(struct inet_protosw *p);
+extern void inet_unregister_protosw(struct inet_protosw *p);

#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
extern void inet6_add_protocol(struct inet6_protocol *prot);
extern int inet6_del_protocol(struct inet6_protocol *prot);
+extern void inet6_register_protosw(struct inet_protosw *p);
+extern void inet6_unregister_protosw(struct inet_protosw *p);
#endif

#endif /* _PROTOCOL_H */
diff -r -u linux-2.4.5-dist/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- linux-2.4.5-dist/net/ipv4/af_inet.c Tue May 1 22:59:24 2001
+++ linux/net/ipv4/af_inet.c Mon Jun 11 12:47:29 2001
@@ -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,46 +317,56 @@
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;
-
- 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:
- 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;
- sk->reuse = 1;
- sk->num = protocol;
- sock->ops = &inet_dgram_ops;
- if (protocol == IPPROTO_RAW)
- sk->protinfo.af_inet.hdrincl = 1;
- break;
- default:
- goto free_and_badtype;
- }
+
+ /* 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);
+
+ 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;
+ 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;
+ if (IPPROTO_RAW == protocol)
+ sk->protinfo.af_inet.hdrincl = 1;
+ }

if (ipv4_config.no_pmtu_disc)
sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_DONT;
@@ -365,8 +383,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;

@@ -969,6 +986,106 @@
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,
+ }
+}; /* struct inet_protosw inetsw_array[] */
+
+#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;
+} /* inet_register_protosw() */
+
+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);
+ }
+} /* inet_unregister_protosw() */
+

/*
* 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,14 @@
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
diff -r -u linux-2.4.5-dist/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- linux-2.4.5-dist/net/ipv6/af_inet6.c Thu Apr 12 14:11:39 2001
+++ linux/net/ipv6/af_inet6.c Mon Jun 11 12:47:41 2001
@@ -10,6 +10,7 @@
* $Id: af_inet6.c,v 1.63 2001/03/02 03:13:05 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,64 @@
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;
- sk->reuse = 1;
- sk->num = protocol;
- } else {
- goto free_and_badtype;
- }
-
+ /* 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;
+ if (IPPROTO_RAW == protocol)
+ sk->protinfo.af_inet.hdrincl = 1;
+ }
+
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 +196,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,7 +204,6 @@
sk->sport = ntohs(sk->num);
sk->prot->hash(sk);
}
-
if (sk->prot->init) {
int err = sk->prot->init(sk);
if (err != 0) {
@@ -504,9 +521,75 @@
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;
+} /* inet6_register_protosw() */
+
+void
+inet6_unregister_protosw(struct inet_protosw *p)
+{
+ inet_unregister_protosw(p);
+} /* inet6_unregister_protosw() */
+
static int __init inet6_init(void)
{
struct sk_buff *dummy_skb;
+ struct list_head *r;
int err;

#ifdef MODULE
@@ -523,6 +606,16 @@
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
diff -r -u linux-2.4.5-dist/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- linux-2.4.5-dist/net/ipv6/tcp_ipv6.c Wed Apr 25 16:57:39 2001
+++ linux/net/ipv6/tcp_ipv6.c Mon Jun 11 12:14:34 2001
@@ -2125,8 +2125,21 @@
"TCPv6" /* name */
};

+extern struct proto_ops inet6_stream_ops;
+
+static struct inet_protosw tcpv6_protosw = {
+ type: SOCK_STREAM,
+ protocol: IPPROTO_TCP,
+ prot: &tcpv6_prot,
+ ops: &inet6_stream_ops,
+ capability: -1,
+ no_check: 0,
+ flags: INET_PROTOSW_PERMANENT,
+};
+
void __init tcpv6_init(void)
{
/* register inet6 protocol */
inet6_add_protocol(&tcpv6_protocol);
+ inet6_register_protosw(&tcpv6_protosw);
}
diff -r -u linux-2.4.5-dist/net/ipv6/udp.c linux/net/ipv6/udp.c
--- linux-2.4.5-dist/net/ipv6/udp.c Thu Apr 12 14:11:39 2001
+++ linux/net/ipv6/udp.c Mon Jun 11 12:58:40 2001
@@ -992,7 +992,21 @@
get_port: udp_v6_get_port,
};

+extern struct proto_ops inet6_dgram_ops;
+
+static struct inet_protosw udpv6_protosw = {
+ type: SOCK_DGRAM,
+ protocol: IPPROTO_UDP,
+ prot: &udpv6_prot,
+ ops: &inet6_dgram_ops,
+ capability: -1,
+ no_check: UDP_CSUM_DEFAULT,
+ flags: INET_PROTOSW_PERMANENT,
+};
+
+
void __init udpv6_init(void)
{
inet6_add_protocol(&udpv6_protocol);
+ inet6_register_protosw(&udpv6_protosw);
}
diff -r -u linux-2.4.5-dist/net/netsyms.c linux/net/netsyms.c
--- linux-2.4.5-dist/net/netsyms.c Fri Apr 27 16:15:01 2001
+++ linux/net/netsyms.c Mon Jun 11 12:14:34 2001
@@ -234,6 +234,8 @@
EXPORT_SYMBOL(inetdev_lock);
EXPORT_SYMBOL(inet_add_protocol);
EXPORT_SYMBOL(inet_del_protocol);
+EXPORT_SYMBOL(inet_register_protosw);
+EXPORT_SYMBOL(inet_unregister_protosw);
EXPORT_SYMBOL(ip_route_output_key);
EXPORT_SYMBOL(ip_route_input);
EXPORT_SYMBOL(icmp_send);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/