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

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

diff -u --recursive --new-file v2.1.27/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.
  *
  *		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;
+}
+
 /*
  *	Raw_err does not currently get called by the icmp module - FIXME:
  */
@@ -339,12 +417,30 @@
 	destroy_sock(sk);
 }
 
-
-static int raw_init(struct sock *sk)
+/* This gets rid of all the nasties in af_inet. -DaveM */
+static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
-	return(0);
-}
+	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 */
+	dst_release(sk->dst_cache);
+	sk->dst_cache = NULL;
+	return 0;
+}
 
 /*
  *	This should be easy, if there is something there
@@ -406,30 +502,37 @@
 
 
 struct proto raw_prot = {
-	raw_close,
-	udp_connect,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	datagram_poll,
-#ifdef CONFIG_IP_MROUTE	
-	ipmr_ioctl,
+	(struct sock *)&raw_prot,	/* sklist_next */
+	(struct sock *)&raw_prot,	/* sklist_prev */
+	raw_close,			/* close */
+	udp_connect,			/* connect */
+	NULL,				/* accept */
+	NULL,				/* retransmit */
+	NULL,				/* write_wakeup */
+	NULL,				/* read_wakeup */
+	datagram_poll,			/* poll */
+#ifdef CONFIG_IP_MROUTE
+	ipmr_ioctl,			/* ioctl */
 #else
-	NULL,
-#endif		
-	raw_init,
-	NULL,
-	NULL,
-	ip_setsockopt,
-	ip_getsockopt,
-	raw_sendmsg,
-	raw_recvmsg,
-	NULL,		/* No special bind */
-	raw_rcv_skb,
-	128,
-	0,
-	"RAW",
-	0, 0,
-	NULL
+	NULL,				/* ioctl */
+#endif
+	NULL,				/* init */
+	NULL,				/* destroy */
+	NULL,				/* shutdown */
+	ip_setsockopt,			/* setsockopt */
+	ip_getsockopt,			/* getsockopt */
+	raw_sendmsg,			/* sendmsg */
+	raw_recvmsg,			/* recvmsg */
+	raw_bind,			/* bind */
+	raw_rcv_skb,			/* backlog_rcv */
+	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