patch-2.0.30 linux/net/ipv4/raw.c

Next file: linux/net/ipv4/route.c
Previous file: linux/net/ipv4/protocol.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.29/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
@@ -30,6 +30,7 @@
  *		Alan Cox	:	Beginnings of mrouted support.
  *		Alan Cox	:	Added IP_HDRINCL option.
  *		Alan Cox	:	Skip broadcast check if BSDism set.
+ *		David S. Miller	:	New socket lookup architecture for ISS.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -58,12 +59,89 @@
 #include <net/sock.h>
 #include <net/icmp.h>
 #include <net/udp.h>
+#include <net/raw.h>
 #include <net/checksum.h>
 
 #ifdef CONFIG_IP_MROUTE
 struct sock *mroute_socket=NULL;
 #endif
 
+struct sock *raw_v4_htable[RAWV4_HTABLE_SIZE];
+
+static void raw_v4_hash(struct sock *sk)
+{
+	struct sock **skp;
+	int num = sk->num;
+
+	num &= (RAWV4_HTABLE_SIZE - 1);
+	skp = &raw_v4_htable[num];
+	SOCKHASH_LOCK();
+	sk->next = *skp;
+	*skp = sk;
+	sk->hashent = num;
+	SOCKHASH_UNLOCK();
+}
+
+static void raw_v4_unhash(struct sock *sk)
+{
+	struct sock **skp;
+	int num = sk->num;
+
+	num &= (RAWV4_HTABLE_SIZE - 1);
+	skp = &raw_v4_htable[num];
+
+	SOCKHASH_LOCK();
+	while(*skp != NULL) {
+		if(*skp == sk) {
+			*skp = sk->next;
+			break;
+		}
+		skp = &((*skp)->next);
+	}
+	SOCKHASH_UNLOCK();
+}
+
+static void raw_v4_rehash(struct sock *sk)
+{
+	struct sock **skp;
+	int num = sk->num;
+	int oldnum = sk->hashent;
+
+	num &= (RAWV4_HTABLE_SIZE - 1);
+	skp = &raw_v4_htable[oldnum];
+
+	SOCKHASH_LOCK();
+	while(*skp != NULL) {
+		if(*skp == sk) {
+			*skp = sk->next;
+			break;
+		}
+		skp = &((*skp)->next);
+	}
+	sk->next = raw_v4_htable[num];
+	raw_v4_htable[num] = sk;
+	sk->hashent = num;
+	SOCKHASH_UNLOCK();
+}
+
+/* Grumble... icmp and ip_input want to get at this... */
+struct sock *raw_v4_lookup(struct sock *sk, unsigned short num,
+			   unsigned long raddr, unsigned long laddr)
+{
+	struct sock *s = sk;
+
+	SOCKHASH_LOCK();
+	for(s = sk; s; s = s->next) {
+		if((s->num == num) 				&&
+		   !(s->dead && (s->state == TCP_CLOSE))	&&
+		   !(s->daddr && s->daddr != raddr) 		&&
+		   !(s->rcv_saddr && s->rcv_saddr != laddr))
+			break; /* gotcha */
+	}
+	SOCKHASH_UNLOCK();
+	return s;
+}
+
 static inline unsigned long min(unsigned long a, unsigned long b)
 {
 	if (a < b) 
@@ -137,6 +215,31 @@
 	return 0;
 }
 
+/* This gets rid of all the nasties in af_inet. -DaveM */
+static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+	struct sockaddr_in *addr = (struct sockaddr_in *) uaddr;
+	int chk_addr_ret;
+
+	if((sk->state != TCP_CLOSE) || (addr_len < sizeof(struct sockaddr_in)))
+		return -EINVAL;
+	chk_addr_ret = ip_chk_addr(addr->sin_addr.s_addr);
+	if(addr->sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR &&
+	   chk_addr_ret != IS_MULTICAST && chk_addr_ret != IS_BROADCAST) {
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+		/* Superuser may bind to any address to allow transparent proxying. */
+		if(!suser())
+#endif
+			return -EADDRNOTAVAIL;
+	}
+	sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr;
+	if(chk_addr_ret == IS_MULTICAST || chk_addr_ret == IS_BROADCAST)
+		sk->saddr = 0;  /* Use device */
+	ip_rt_put(sk->ip_route_cache);
+	sk->ip_route_cache = NULL;
+	return 0;
+}
+
 /*
  *	This should be the easiest of all, all we do is
  *	copy it into a buffer. All demultiplexing is done
@@ -375,31 +478,38 @@
 
 
 struct proto raw_prot = {
-	raw_close,
-	ip_build_header,
-	udp_connect,
-	NULL,
-	ip_queue_xmit,
-	NULL,
-	NULL,
-	NULL,
-	raw_rcv_redo,
-	datagram_select,
+	(struct sock *)&raw_prot,	/* sklist_next */
+	(struct sock *)&raw_prot,	/* sklist_prev */
+	raw_close,			/* close */
+	ip_build_header,		/* build_header */
+	udp_connect,			/* connect */
+	NULL,				/* accept */
+	ip_queue_xmit,			/* queue_xmit */
+	NULL,				/* retransmit */
+	NULL,				/* write_wakeup */
+	NULL,				/* read_wakeup */
+	raw_rcv_redo,			/* rcv */
+	datagram_select,		/* select */
 #ifdef CONFIG_IP_MROUTE	
-	ipmr_ioctl,
+	ipmr_ioctl,			/* ioctl */
 #else
-	NULL,
+	NULL,				/* ioctl */
 #endif		
-	raw_init,
-	NULL,
-	ip_setsockopt,
-	ip_getsockopt,
-	raw_sendmsg,
-	raw_recvmsg,
-	NULL,		/* No special bind */
-	128,
-	0,
-	"RAW",
-	0, 0,
-	{NULL,}
+	raw_init,			/* init */
+	NULL,				/* shutdown */
+	ip_setsockopt,			/* setsockopt */
+	ip_getsockopt,			/* getsockopt */
+	raw_sendmsg,			/* sendmsg */
+	raw_recvmsg,			/* recvmsg */
+	raw_bind,			/* bind */
+	raw_v4_hash,			/* hash */
+	raw_v4_unhash,			/* unhash */
+	raw_v4_rehash,			/* rehash */
+	NULL,				/* good_socknum */
+	NULL,				/* verify_bind */
+	128,				/* max_header */
+	0,				/* retransmits */
+	"RAW",				/* name */
+	0,				/* inuse */
+	0				/* highestinuse */
 };

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov