patch-2.1.15 linux/net/ipv4/ip_input.c

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

diff -u --recursive --new-file v2.1.14/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c
@@ -109,8 +109,6 @@
  *		output should probably do its own fragmentation at the UDP/RAW layer. TCP shouldn't cause
  *		fragmentation anyway.
  *
- *		FIXME: copy frag 0 iph to qp->iph
- *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
  *		as published by the Free Software Foundation; either version
@@ -160,20 +158,12 @@
 #include <linux/net_alias.h>
 #endif
 
-extern int last_retran;
-extern void sort_send(struct sock *sk);
-
-#define min(a,b)	((a)<(b)?(a):(b))
-
 /*
  *	SNMP management statistics
  */
 
-#ifdef CONFIG_IP_FORWARD
-struct ip_mib ip_statistics={1,64,};	/* Forwarding=Yes, Default TTL=64 */
-#else
-struct ip_mib ip_statistics={2,64,};	/* Forwarding=No, Default TTL=64 */
-#endif
+struct ip_mib ip_statistics={2,IPDEFTTL,};	/* Forwarding=No, Default TTL=64 */
+
 
 /*
  *	Handle the issuing of an ioctl() request
@@ -190,548 +180,287 @@
 	}
 }
 
-#ifdef CONFIG_IP_TRANSPARENT_PROXY
-/*
- *	Check the packet against our socket administration to see
- *	if it is related to a connection on our system.
- *	Needed for transparent proxying.
- */
 
-int ip_chksock(struct sk_buff *skb)
-{
-	switch (skb->h.iph->protocol) {
-	case IPPROTO_ICMP:
-		return icmp_chkaddr(skb);
-	case IPPROTO_TCP:
-		return tcp_chkaddr(skb);
-	case IPPROTO_UDP:
-		return udp_chkaddr(skb);
-	default:
-		return 0;
-	}
-}
+#if defined(CONFIG_IP_TRANSPARENT_PROXY) && !defined(CONFIG_IP_ALWAYS_DEFRAG)
+#define CONFIG_IP_ALWAYS_DEFRAG 1
 #endif
 
 
-/*
- *	This function receives all incoming IP datagrams.
- *
- *	On entry skb->data points to the start of the IP header and
- *	the MAC header has been removed.
- */
-
-int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+int ip_local_deliver(struct sk_buff *skb)
 {
-	struct iphdr *iph = skb->h.iph;
+	struct iphdr *iph = skb->nh.iph;
+#ifdef CONFIG_IP_MASQUERADE
+	struct device *dev = skb->dev;
+#endif
+	struct inet_protocol *ipprot;
 	struct sock *raw_sk=NULL;
 	unsigned char hash;
-	unsigned char flag = 0;
-	struct inet_protocol *ipprot;
-	int brd=IS_MYADDR;
-	struct options * opt = NULL;
-	int is_frag=0;
-	__u32 daddr;
-
-#ifdef CONFIG_FIREWALL
-	int fwres;
-	__u16 rport;
-#endif	
-#ifdef CONFIG_IP_MROUTE
-	int mroute_pkt=0;
-#endif	
-
-#ifdef CONFIG_NET_IPV6
-	/* 
-	 *	Intercept IPv6 frames. We dump ST-II and invalid types just below..
-	 */
-	 
-	if(iph->version == 6)
-		return ipv6_rcv(skb,dev,pt);
-#endif		
-
-	ip_statistics.IpInReceives++;
+	int flag = 0;
 
+#ifndef CONFIG_IP_ALWAYS_DEFRAG
 	/*
-	 *	Account for the packet (even if the packet is
-	 *	not accepted by the firewall!).
+	 *	Reassemble IP fragments.
 	 */
 
-#ifdef CONFIG_IP_ACCT
-	ip_fw_chk(iph,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_IN);
-#endif	
+	if (iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+		skb = ip_defrag(skb);
+		if (!skb)
+			return 0;
+		iph = skb->nh.iph;
+	}
+#endif
 
+#ifdef CONFIG_IP_MASQUERADE
 	/*
-	 *	Tag the ip header of this packet so we can find it
+	 * Do we need to de-masquerade this packet?
 	 */
+        {
+		int ret = ip_fw_demasquerade(&skb, dev);
+		if (ret < 0) {
+			kfree_skb(skb, FREE_WRITE);
+			return 0;
+		}
 
-	skb->ip_hdr = iph;
+		if (ret) {
+			iph=skb->nh.iph;
+			IPCB(skb)->flags |= IPSKB_MASQUERADED;
+			dst_release(skb->dst);
+			skb->dst = NULL;
+			if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev)) {
+				kfree_skb(skb, FREE_WRITE);
+				return 0;
+			}
+			return skb->dst->input(skb);
+		}
+        }
+#endif
 
-	/*
-	 *	RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
-	 *	RFC1122: 3.1.2.3 MUST discard a frame with invalid source address [NEEDS FIXING].
-	 *
-	 *	Is the datagram acceptable?
-	 *
-	 *	1.	Length at least the size of an ip header
-	 *	2.	Version of 4
-	 *	3.	Checksums correctly. [Speed optimisation for later, skip loopback checksums]
-	 *	4.	Doesn't have a bogus length
-	 *	(5.	We ought to check for IP multicast addresses and undefined types.. does this matter ?)
+        /*
+	 *	Point into the IP datagram, just past the header.
 	 */
 
-	if (skb->len<sizeof(struct iphdr) || iph->ihl<5 || iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0
-		|| skb->len < ntohs(iph->tot_len))
-	{
-		ip_statistics.IpInHdrErrors++;
-		kfree_skb(skb, FREE_WRITE);
-		return(0);
-	}
+        skb->h.raw = skb->nh.raw + iph->ihl*4;
 
 	/*
-	 *	Our transport medium may have padded the buffer out. Now we know it
-	 *	is IP we can trim to the true length of the frame.
-	 *	Note this now means skb->len holds ntohs(iph->tot_len).
+	 *	Deliver to raw sockets. This is fun as to avoid copies we want to make no surplus copies.
+	 *
+	 *	RFC 1122: SHOULD pass TOS value up to the transport layer.
 	 */
+ 
+	hash = iph->protocol & (SOCK_ARRAY_SIZE-1);
 
-	skb_trim(skb,ntohs(iph->tot_len));
-
-	/*
-	 *	Try to select closest <src,dst> alias device, if any.
-	 *	net_alias_dev_rcv_sel32 returns main device if it 
-	 *	fails to found other.
+	/* 
+	 *	If there maybe a raw socket we must check - if not we don't care less 
 	 */
-
-#ifdef CONFIG_NET_ALIAS
-	if (iph->daddr != skb->dev->pa_addr && net_alias_has(skb->dev)) 
-		skb->dev = dev = net_alias_dev_rcv_sel32(skb->dev, AF_INET, iph->saddr, iph->daddr);
-#endif
-
-	if (iph->ihl > 5) 
+		 
+	if((raw_sk=raw_prot.sock_array[hash])!=NULL)
 	{
-		skb->ip_summed = 0;
-		if (ip_options_compile(NULL, skb))
-			return(0);
-		opt = (struct options*)skb->proto_priv;
-#ifdef CONFIG_IP_NOSR
-		if (opt->srr) 
+		struct sock *sknext=NULL;
+		struct sk_buff *skb1;
+		raw_sk=get_sock_raw(raw_sk, iph->protocol,  iph->saddr, iph->daddr);
+		if(raw_sk)	/* Any raw sockets */
 		{
-			kfree_skb(skb, FREE_READ);
-			return -EINVAL;
+			do
+			{
+				/* Find the next */
+				sknext=get_sock_raw(raw_sk->next, iph->protocol, iph->saddr, iph->daddr);
+				if(sknext)
+					skb1=skb_clone(skb, GFP_ATOMIC);
+				else
+					break;	/* One pending raw socket left */
+				if(skb1)
+					raw_rcv(raw_sk, skb1);
+				raw_sk=sknext;
+			}
+			while(raw_sk!=NULL);
+				
+			/*
+			 *	Here either raw_sk is the last raw socket, or NULL if none 
+			 */
+			
+			/*
+			 *	We deliver to the last raw socket AFTER the protocol checks as it avoids a surplus copy 
+			 */
 		}
-#endif					
 	}
 	
-#if defined(CONFIG_IP_TRANSPARENT_PROXY) && !defined(CONFIG_IP_ALWAYS_DEFRAG)
-#define CONFIG_IP_ALWAYS_DEFRAG 1
-#endif
-#ifdef CONFIG_IP_ALWAYS_DEFRAG
-	/*
-	 * Defragment all incoming traffic before even looking at it.
-	 * If you have forwarding enabled, this makes the system a
-	 * defragmenting router.  Not a common thing.
-	 * You probably DON'T want to enable this unless you have to.
-	 * You NEED to use this if you want to use transparent proxying,
-	 * otherwise, we can't vouch for your sanity.
-	 */
-
 	/*
-	 *	See if the frame is fragmented.
+	 *	skb->h.raw now points at the protocol beyond the IP header.
 	 */
-	 
-	if(iph->frag_off)
+	
+	hash = iph->protocol & (MAX_INET_PROTOS -1);
+	for (ipprot = (struct inet_protocol *)inet_protos[hash];ipprot != NULL;ipprot=(struct inet_protocol *)ipprot->next)
 	{
-		if (iph->frag_off & htons(IP_MF))
-			is_frag|=IPFWD_FRAGMENT;
+		struct sk_buff *skb2;
+	
+		if (ipprot->protocol != iph->protocol)
+			continue;
 		/*
-		 *	Last fragment ?
+		 * 	See if we need to make a copy of it.  This will
+		 * 	only be set if more than one protocol wants it.
+		 * 	and then not for the last one. If there is a pending
+		 *	raw delivery wait for that
 		 */
 	
-		if (iph->frag_off & htons(IP_OFFSET))
-			is_frag|=IPFWD_LASTFRAG;
-	
+		if (ipprot->copy || raw_sk)
+		{
+			skb2 = skb_clone(skb, GFP_ATOMIC);
+			if(skb2==NULL)
+				continue;
+		}
+		else
+		{
+			skb2 = skb;
+		}
+		flag = 1;
+
 		/*
-		 *	Reassemble IP fragments.
+		 *	Pass on the datagram to each protocol that wants it,
+		 *	based on the datagram protocol.  We should really
+		 *	check the protocol handler's return values here...
 		 */
 
-		if(is_frag)
-		{
-			/* Defragment. Obtain the complete packet if there is one */
-			skb=ip_defrag(iph,skb,dev);
-			if(skb==NULL)
-				return 0;
-			skb->dev = dev;
-			iph=skb->h.iph;
-			is_frag = 0;
-			/*
-			 * When the reassembled packet gets forwarded, the ip
-			 * header checksum should be correct.
-			 * For better performance, this should actually only
-			 * be done in that particular case, i.e. set a flag
-			 * here and calculate the checksum in ip_forward.
-			 */
-			ip_send_check(iph);
-		}
+		ipprot->handler(skb2, ntohs(iph->tot_len) - (iph->ihl * 4));
 	}
 
-#endif
 	/*
-	 *	See if the firewall wants to dispose of the packet. 
+	 *	All protocols checked.
+	 *	If this packet was a broadcast, we may *not* reply to it, since that
+	 *	causes (proven, grin) ARP storms and a leakage of memory (i.e. all
+	 *	ICMP reply messages get queued up for transmission...)
 	 */
-	
-#ifdef	CONFIG_FIREWALL
 
-	if ((fwres=call_in_firewall(PF_INET, skb->dev, iph, &rport))<FW_ACCEPT)
+	if(raw_sk!=NULL)	/* Shift to last raw user */
+		raw_rcv(raw_sk, skb);
+	else if (!flag)		/* Free and report errors */
 	{
-		if(fwres==FW_REJECT)
-			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0, dev);
+		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);	
 		kfree_skb(skb, FREE_WRITE);
-		return 0;	
 	}
 
-#ifdef	CONFIG_IP_TRANSPARENT_PROXY
-	if (fwres==FW_REDIRECT)
-		skb->redirport = rport;
-	else
-#endif
-		skb->redirport = 0;
-#endif
-	
-#ifndef CONFIG_IP_ALWAYS_DEFRAG
-	/*
-	 *	Remember if the frame is fragmented.
+	return(0);
+}
+
+int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+{
+	struct iphdr *iph = skb->nh.iph;
+	struct ip_options * opt = NULL;
+	int err;
+
+#ifdef CONFIG_NET_IPV6
+	/* 
+	 *	Intercept IPv6 frames. We dump ST-II and invalid types just below..
 	 */
 	 
-	if(iph->frag_off)
-	{
-		if (iph->frag_off & htons(IP_MF))
-			is_frag|=IPFWD_FRAGMENT;
-		/*
-		 *	Last fragment ?
-		 */
-	
-		if (iph->frag_off & htons(IP_OFFSET))
-			is_frag|=IPFWD_LASTFRAG;
-	}
-	
+	if(iph->version == 6)
+		return ipv6_rcv(skb,dev,pt);
 #endif
+
 	/*
-	 *	Do any IP forwarding required.  chk_addr() is expensive -- avoid it someday.
-	 *
-	 *	This is inefficient. While finding out if it is for us we could also compute
-	 *	the routing table entry. This is where the great unified cache theory comes
-	 *	in as and when someone implements it
-	 *
-	 *	For most hosts over 99% of packets match the first conditional
-	 *	and don't go via ip_chk_addr. Note: brd is set to IS_MYADDR at
-	 *	function entry.
-	 */
-	daddr = iph->daddr;
-#ifdef CONFIG_IP_TRANSPARENT_PROXY
-	/*
-	 *	ip_chksock adds still more overhead for forwarded traffic...
+	 * When interface is in promisc. mode, drop all the crap
+	 * that it receives, do not truing to analyse it.
 	 */
-	if ( iph->daddr == skb->dev->pa_addr || skb->redirport || (brd = ip_chk_addr(iph->daddr)) != 0 || ip_chksock(skb))
-#else
-	if ( iph->daddr == skb->dev->pa_addr || (brd = ip_chk_addr(iph->daddr)) != 0)
-#endif
-	{
-		if (opt && opt->srr) 
-	        {
-			int srrspace, srrptr;
-			__u32 nexthop;
-			unsigned char * optptr = ((unsigned char *)iph) + opt->srr;
-
-			if (brd != IS_MYADDR || skb->pkt_type != PACKET_HOST) 
-			{
-				kfree_skb(skb, FREE_WRITE);
-				return 0;
-			}
-
-			for ( srrptr=optptr[2], srrspace = optptr[1];
-			      srrptr <= srrspace;
-			      srrptr += 4
-			     ) 
-			{
-				int brd2;
-				if (srrptr + 3 > srrspace) 
-				{
-					icmp_send(skb, ICMP_PARAMETERPROB, 0, opt->srr+2,
-						  skb->dev);
-					kfree_skb(skb, FREE_WRITE);
-					return 0;
-				}
-				memcpy(&nexthop, &optptr[srrptr-1], 4);
-				if ((brd2 = ip_chk_addr(nexthop)) == 0)
-					break;
-				if (brd2 != IS_MYADDR) 
-				{
-
-					/*
-					 *	ANK: should we implement weak tunneling of multicasts?
-					 *	Are they obsolete? DVMRP specs (RFC-1075) is old enough...
-					 *	[They are obsolete]
-					 */
-					kfree_skb(skb, FREE_WRITE);
-					return -EINVAL;
-				}
-				memcpy(&daddr, &optptr[srrptr-1], 4);
-			}
-			if (srrptr <= srrspace) 
-			{
-				opt->srr_is_hit = 1;
-				opt->is_changed = 1;
-#ifdef CONFIG_IP_FORWARD
-				if (ip_forward(skb, dev, is_frag, nexthop))
-					kfree_skb(skb, FREE_WRITE);
-#else
-				ip_statistics.IpInAddrErrors++;
-				kfree_skb(skb, FREE_WRITE);
-#endif
-				return 0;
-			}
-		}
+	if (skb->pkt_type == PACKET_OTHERHOST)
+		goto drop;
 
-#ifdef CONFIG_IP_MULTICAST	
-		if(!(dev->flags&IFF_ALLMULTI) && brd==IS_MULTICAST && iph->daddr!=IGMP_ALL_HOSTS && !(dev->flags&IFF_LOOPBACK))
-		{
-			/*
-			 *	Check it is for one of our groups
-			 */
-			struct ip_mc_list *ip_mc=dev->ip_mc_list;
-			do
-			{
-				if(ip_mc==NULL)
-				{	
-					kfree_skb(skb, FREE_WRITE);
-					return 0;
-				}
-				if(ip_mc->multiaddr==iph->daddr)
-					break;
-				ip_mc=ip_mc->next;
-			}
-			while(1);
-		}
-#endif
-
-#ifndef CONFIG_IP_ALWAYS_DEFRAG
-		/*
-		 *	Reassemble IP fragments.
-		 */
+	ip_statistics.IpInReceives++;
 
-		if(is_frag)
-		{
-			/* Defragment. Obtain the complete packet if there is one */
-			skb=ip_defrag(iph,skb,dev);
-			if(skb==NULL)
-				return 0;
-			skb->dev = dev;
-			iph=skb->h.iph;
-		}
+	/*
+	 *	Account for the packet (even if the packet is
+	 *	not accepted by the firewall!).
+	 */
 
-#endif
+#ifdef CONFIG_IP_ACCT
+	ip_fw_chk(iph,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_IN);
+#endif	
 
-#ifdef CONFIG_IP_MASQUERADE
-		/*
-		 * Do we need to de-masquerade this packet?
-		 */
-		{
-			int ret = ip_fw_demasquerade(&skb,dev);
-			if (ret < 0) {
-				kfree_skb(skb, FREE_WRITE);
-				return 0;
-			}
+	/*
+	 *	RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
+	 *
+	 *	Is the datagram acceptable?
+	 *
+	 *	1.	Length at least the size of an ip header
+	 *	2.	Version of 4
+	 *	3.	Checksums correctly. [Speed optimisation for later, skip loopback checksums]
+	 *	4.	Doesn't have a bogus length
+	 */
 
-			if (ret)
-			{
-				struct iphdr *iph=skb->h.iph;
-				if (ip_forward(skb, dev, IPFWD_MASQUERADED, iph->daddr))
-					kfree_skb(skb, FREE_WRITE);
-				return 0;
-			}
-		}
-#endif
+	if (skb->len<sizeof(struct iphdr) || iph->ihl<5 || iph->version != 4
+	    || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0
+		|| skb->len < ntohs(iph->tot_len))
+		goto inhdr_error;
 
-		/*
-		 *	Point into the IP datagram, just past the header.
-		 */
+	/*
+	 *	Our transport medium may have padded the buffer out. Now we know it
+	 *	is IP we can trim to the true length of the frame.
+	 *	Note this now means skb->len holds ntohs(iph->tot_len).
+	 */
 
-		skb->ip_hdr = iph;
-		skb->h.raw += iph->ihl*4;
+	skb_trim(skb, ntohs(iph->tot_len));
 
-#ifdef CONFIG_IP_MROUTE		
-		/*
-		 *	Check the state on multicast routing (multicast and not 224.0.0.z)
-		 */
-		 
-		if(brd==IS_MULTICAST && (iph->daddr&htonl(0xFFFFFF00))!=htonl(0xE0000000))
-			mroute_pkt=1;
+	if (skb->dst == NULL) {
+		err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev);
+		if (err)
+			goto drop;
+	}
 
+#ifdef CONFIG_IP_ALWAYS_DEFRAG
+	if (iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+		skb = ip_defrag(skb);
+		if (!skb)
+			return 0;
+		iph = skb->nh.iph;
+		ip_send_check(iph);
+	}
 #endif
-		/*
-		 *	Deliver to raw sockets. This is fun as to avoid copies we want to make no surplus copies.
-		 *
-		 *	RFC 1122: SHOULD pass TOS value up to the transport layer.
-		 */
- 
-		hash = iph->protocol & (SOCK_ARRAY_SIZE-1);
-
-		/* 
-		 *	If there maybe a raw socket we must check - if not we don't care less 
-		 */
-		 
-		if((raw_sk=raw_prot.sock_array[hash])!=NULL)
-		{
-			struct sock *sknext=NULL;
-			struct sk_buff *skb1;
-			raw_sk=get_sock_raw(raw_sk, iph->protocol,  iph->saddr, iph->daddr);
-			if(raw_sk)	/* Any raw sockets */
-			{
-				do
-				{
-					/* Find the next */
-					sknext=get_sock_raw(raw_sk->next, iph->protocol, iph->saddr, iph->daddr);
-					if(sknext)
-						skb1=skb_clone(skb, GFP_ATOMIC);
-					else
-						break;	/* One pending raw socket left */
-					if(skb1)
-						raw_rcv(raw_sk, skb1, dev, iph->saddr,daddr);
-					raw_sk=sknext;
-				}
-				while(raw_sk!=NULL);
-				
-				/*
-				 *	Here either raw_sk is the last raw socket, or NULL if none 
-				 */
-				 
-				/*
-				 *	We deliver to the last raw socket AFTER the protocol checks as it avoids a surplus copy 
-				 */
-			}
-		}
-	
-		/*
-		 *	skb->h.raw now points at the protocol beyond the IP header.
-		 */
-	
-		hash = iph->protocol & (MAX_INET_PROTOS -1);
-		for (ipprot = (struct inet_protocol *)inet_protos[hash];ipprot != NULL;ipprot=(struct inet_protocol *)ipprot->next)
-		{
-			struct sk_buff *skb2;
-	
-			if (ipprot->protocol != iph->protocol)
-				continue;
-		       /*
-			* 	See if we need to make a copy of it.  This will
-			* 	only be set if more than one protocol wants it.
-			* 	and then not for the last one. If there is a pending
-			*	raw delivery wait for that
-			*/
-	
-#ifdef CONFIG_IP_MROUTE
-			if (ipprot->copy || raw_sk || mroute_pkt)
-#else	
-			if (ipprot->copy || raw_sk)
-#endif			
-			{
-				skb2 = skb_clone(skb, GFP_ATOMIC);
-				if(skb2==NULL)
-					continue;
-			}
-			else
-			{
-				skb2 = skb;
-			}
-			flag = 1;
-
-		       /*
-			*	Pass on the datagram to each protocol that wants it,
-			*	based on the datagram protocol.  We should really
-			*	check the protocol handler's return values here...
-			*/
-
-			ipprot->handler(skb2, dev, opt, daddr,
-				(ntohs(iph->tot_len) - (iph->ihl * 4)),
-				iph->saddr, 0, ipprot);
-		}
 
-		/*
-		 *	All protocols checked.
-		 *	If this packet was a broadcast, we may *not* reply to it, since that
-		 *	causes (proven, grin) ARP storms and a leakage of memory (i.e. all
-		 *	ICMP reply messages get queued up for transmission...)
-		 */
+	if (iph->ihl > 5) {
+		skb->ip_summed = 0;
+		if (ip_options_compile(NULL, skb))
+			goto inhdr_error;
 
-#ifdef CONFIG_IP_MROUTE		 
-		/*
-		 *	Forward the last copy to the multicast router. If
-		 *	there is a pending raw delivery however make a copy
-		 *	and forward that.
-		 */
-		 
-		if(mroute_pkt)
-		{
-			flag=1;
-			if(raw_sk==NULL)
-				ipmr_forward(skb, is_frag);
-			else
-			{
-				struct sk_buff *skb2=skb_clone(skb, GFP_ATOMIC);
-				if(skb2)
-				{
-					skb2->free=1;
-					ipmr_forward(skb2, is_frag);
-				}
+		opt = &(IPCB(skb)->opt);
+		if (opt->srr) {
+			if (!ipv4_config.source_route) {
+				if (ipv4_config.log_martians)
+					printk(KERN_INFO "source route option %08lx -> %08lx\n",
+				       ntohl(iph->saddr), ntohl(iph->daddr));
+				goto drop;
 			}
+			if (RT_LOCALADDR(((struct rtable*)skb->dst)->rt_flags) &&
+			    ip_options_rcv_srr(skb))
+				goto drop;
 		}
-#endif		
-
-		if(raw_sk!=NULL)	/* Shift to last raw user */
-			raw_rcv(raw_sk, skb, dev, iph->saddr, daddr);
-		else if (!flag)		/* Free and report errors */
-		{
-			if (brd != IS_BROADCAST && brd!=IS_MULTICAST)
-				icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0, dev);	
-			kfree_skb(skb, FREE_WRITE);
-		}
-
-		return(0);
 	}
-
-	/*
-	 *	Do any unicast IP forwarding required.
-	 */
 	
 	/*
-	 *	Don't forward multicast or broadcast frames.
+	 *	See if the firewall wants to dispose of the packet. 
 	 */
+	
+#ifdef	CONFIG_FIREWALL
+        {
+		int fwres;
+		u16 rport;
+
+		if ((fwres=call_in_firewall(PF_INET, skb->dev, iph, &rport))<FW_ACCEPT) {
+			if (fwres==FW_REJECT)
+				icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+			goto drop;
+		}
 
-	if(skb->pkt_type!=PACKET_HOST || brd==IS_BROADCAST)
-	{
-		kfree_skb(skb,FREE_WRITE);
-		return 0;
+#ifdef	CONFIG_IP_TRANSPARENT_PROXY
+		if (fwres==FW_REDIRECT && (IPCB(skb)->redirport = rport) != 0)
+			return ip_local_deliver(skb);
+#endif
 	}
+#endif
 
-	/*
-	 *	The packet is for another target. Forward the frame
-	 */
+	return skb->dst->input(skb);
 
-#ifdef CONFIG_IP_FORWARD
-	if (opt && opt->is_strictroute) 
-	{
-	      icmp_send(skb, ICMP_PARAMETERPROB, 0, 16, skb->dev);
-	      kfree_skb(skb, FREE_WRITE);
-	      return -1;
-	}
-	if (ip_forward(skb, dev, is_frag, iph->daddr))
-		kfree_skb(skb, FREE_WRITE);
-#else
-/*	printk("Machine %lx tried to use us as a forwarder to %lx but we have forwarding disabled!\n",
-			iph->saddr,iph->daddr);*/
-	ip_statistics.IpInAddrErrors++;
-	kfree_skb(skb, FREE_WRITE);
-#endif
-	return(0);
+inhdr_error:
+	ip_statistics.IpInHdrErrors++;
+drop:
+        kfree_skb(skb, FREE_WRITE);
+        return(0);
 }
-	
 

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