patch-2.3.15 linux/net/ipv4/icmp.c
Next file: linux/net/ipv4/igmp.c
Previous file: linux/net/ipv4/fib_semantics.c
Back to the patch index
Back to the overall index
- Lines: 326
- Date:
Mon Aug 23 10:01:02 1999
- Orig file:
v2.3.14/linux/net/ipv4/icmp.c
- Orig date:
Wed Aug 18 11:38:48 1999
diff -u --recursive --new-file v2.3.14/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
@@ -3,7 +3,7 @@
*
* Alan Cox, <alan@redhat.com>
*
- * Version: $Id: icmp.c,v 1.57 1999/06/09 10:10:50 davem Exp $
+ * Version: $Id: icmp.c,v 1.60 1999/08/20 11:05:10 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -261,6 +261,7 @@
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/string.h>
+#include <linux/netfilter_ipv4.h>
#include <net/snmp.h>
#include <net/ip.h>
#include <net/route.h>
@@ -278,10 +279,6 @@
#include <asm/uaccess.h>
#include <net/checksum.h>
-#ifdef CONFIG_IP_MASQUERADE
-#include <net/ip_masq.h>
-#endif
-
#define min(a,b) ((a)<(b)?(a):(b))
/*
@@ -357,6 +354,47 @@
struct inode icmp_inode;
struct socket *icmp_socket=&icmp_inode.u.socket_i;
+/* ICMPv4 socket is only a bit non-reenterable (unlike ICMPv6,
+ which is strongly non-reenterable). A bit later it will be made
+ reenterable and the lock may be removed then.
+ */
+
+static int icmp_xmit_holder = -1;
+
+static int icmp_xmit_lock_bh(void)
+{
+ if (!spin_trylock(&icmp_socket->sk->lock.slock)) {
+ if (icmp_xmit_holder == smp_processor_id())
+ return -EAGAIN;
+ spin_lock(&icmp_socket->sk->lock.slock);
+ }
+ icmp_xmit_holder = smp_processor_id();
+ return 0;
+}
+
+static __inline__ int icmp_xmit_lock(void)
+{
+ int ret;
+ local_bh_disable();
+ ret = icmp_xmit_lock_bh();
+ if (ret)
+ local_bh_enable();
+ return ret;
+}
+
+static void icmp_xmit_unlock_bh(void)
+{
+ icmp_xmit_holder = -1;
+ spin_unlock(&icmp_socket->sk->lock.slock);
+}
+
+static __inline__ void icmp_xmit_unlock(void)
+{
+ icmp_xmit_unlock_bh();
+ local_bh_enable();
+}
+
+
/*
* Send an ICMP frame.
*/
@@ -480,21 +518,26 @@
if (ip_options_echo(&icmp_param->replyopts, skb))
return;
+ if (icmp_xmit_lock_bh())
+ return;
+
icmp_param->icmph.checksum=0;
icmp_param->csum=0;
icmp_out_count(icmp_param->icmph.type);
- sk->ip_tos = skb->nh.iph->tos;
+ sk->protinfo.af_inet.tos = skb->nh.iph->tos;
daddr = ipc.addr = rt->rt_src;
ipc.opt = &icmp_param->replyopts;
if (ipc.opt->srr)
daddr = icmp_param->replyopts.faddr;
if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0))
- return;
+ goto out;
ip_build_xmit(sk, icmp_glue_bits, icmp_param,
icmp_param->data_len+sizeof(struct icmphdr),
&ipc, rt, MSG_DONTWAIT);
ip_rt_put(rt);
+out:
+ icmp_xmit_unlock_bh();
}
@@ -536,10 +579,8 @@
* Now check at the protocol level
*/
if (!rt) {
-#ifndef CONFIG_IP_ALWAYS_DEFRAG
if (net_ratelimit())
printk(KERN_DEBUG "icmp_send: destinationless packet\n");
-#endif
return;
}
if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))
@@ -575,6 +616,9 @@
}
+ if (icmp_xmit_lock())
+ return;
+
/*
* Construct source address and options.
*/
@@ -588,11 +632,6 @@
iph->saddr = rt->key.src;
}
#endif
-#ifdef CONFIG_IP_MASQUERADE
- if (type==ICMP_DEST_UNREACH && IPCB(skb_in)->flags&IPSKB_MASQUERADED) {
- ip_fw_unmasq_icmp(skb_in);
- }
-#endif
saddr = iph->daddr;
if (!(rt->rt_flags & RTCF_LOCAL))
@@ -609,7 +648,7 @@
* grow the routing table.
*/
if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0))
- return;
+ goto out;
if (ip_options_echo(&icmp_param.replyopts, skb_in))
goto ende;
@@ -626,13 +665,13 @@
icmp_param.csum=0;
icmp_param.data_ptr=iph;
icmp_out_count(icmp_param.icmph.type);
- icmp_socket->sk->ip_tos = tos;
+ icmp_socket->sk->protinfo.af_inet.tos = tos;
ipc.addr = iph->saddr;
ipc.opt = &icmp_param.replyopts;
if (icmp_param.replyopts.srr) {
ip_rt_put(rt);
if (ip_route_output(&rt, icmp_param.replyopts.faddr, saddr, RT_TOS(tos), 0))
- return;
+ goto out;
}
if (!icmpv4_xrlim_allow(rt, type, code))
@@ -656,6 +695,8 @@
ende:
ip_rt_put(rt);
+out:
+ icmp_xmit_unlock();
}
@@ -752,19 +793,22 @@
/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
hash = iph->protocol & (MAX_INET_PROTOS - 1);
+ read_lock(&raw_v4_lock);
if ((raw_sk = raw_v4_htable[hash]) != NULL)
{
- while ((raw_sk = raw_v4_lookup(raw_sk, iph->protocol, iph->saddr,
- iph->daddr, skb->dev->ifindex)) != NULL) {
+ while ((raw_sk = __raw_v4_lookup(raw_sk, iph->protocol, iph->saddr,
+ iph->daddr, skb->dev->ifindex)) != NULL) {
raw_err(raw_sk, skb);
raw_sk = raw_sk->next;
}
}
+ read_unlock(&raw_v4_lock);
/*
* This can't change while we are doing it.
*/
+ read_lock(&inet_protocol_lock);
ipprot = (struct inet_protocol *) inet_protos[hash];
while(ipprot != NULL) {
struct inet_protocol *nextip;
@@ -783,6 +827,7 @@
ipprot = nextip;
}
+ read_unlock(&inet_protocol_lock);
}
@@ -936,89 +981,40 @@
{
struct rtable *rt = (struct rtable*)skb->dst;
struct net_device *dev = skb->dev;
- struct in_device *in_dev = dev->ip_ptr;
+ struct in_device *in_dev;
struct in_ifaddr *ifa;
u32 mask;
- if (!in_dev || !in_dev->ifa_list ||
- !IN_DEV_LOG_MARTIANS(in_dev) ||
- !IN_DEV_FORWARD(in_dev) ||
- len < 4 ||
- !(rt->rt_flags&RTCF_DIRECTSRC))
+ if (len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC))
return;
- mask = *(u32*)&icmph[1];
- for (ifa=in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
- if (mask == ifa->ifa_mask && inet_ifa_match(rt->rt_src, ifa))
- return;
+ in_dev = in_dev_get(dev);
+ if (!in_dev)
+ return;
+ read_lock(&in_dev->lock);
+ if (in_dev->ifa_list &&
+ IN_DEV_LOG_MARTIANS(in_dev) &&
+ IN_DEV_FORWARD(in_dev)) {
+
+ mask = *(u32*)&icmph[1];
+ for (ifa=in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
+ if (mask == ifa->ifa_mask && inet_ifa_match(rt->rt_src, ifa))
+ break;
+ }
+ if (!ifa && net_ratelimit()) {
+ char b1[16], b2[16];
+ printk(KERN_INFO "Wrong address mask %s from %s/%s\n",
+ in_ntoa2(mask, b1), in_ntoa2(rt->rt_src, b2), dev->name);
+ }
}
- if (net_ratelimit())
- printk(KERN_INFO "Wrong address mask %08lX from %08lX/%s\n",
- ntohl(mask), ntohl(rt->rt_src), dev->name);
+ read_unlock(&in_dev->lock);
+ in_dev_put(in_dev);
}
static void icmp_discard(struct icmphdr *icmph, struct sk_buff *skb, int len)
{
}
-#ifdef CONFIG_IP_TRANSPARENT_PROXY
-/*
- * Check incoming icmp packets not addressed locally, to check whether
- * they relate to a (proxying) socket on our system.
- * Needed for transparent proxying.
- *
- * This code is presently ugly and needs cleanup.
- * Probably should add a chkaddr entry to ipprot to call a chk routine
- * in udp.c or tcp.c...
- */
-
-/* This should work with the new hashes now. -DaveM */
-extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif);
-extern struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif);
-
-int icmp_chkaddr(struct sk_buff *skb)
-{
- struct icmphdr *icmph=(struct icmphdr *)(skb->nh.raw + skb->nh.iph->ihl*4);
- struct iphdr *iph = (struct iphdr *) (icmph + 1);
- void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, int len) = icmp_pointers[icmph->type].handler;
-
- if (handler == icmp_unreach || handler == icmp_redirect) {
- struct sock *sk;
-
- switch (iph->protocol) {
- case IPPROTO_TCP:
- {
- struct tcphdr *th = (struct tcphdr *)(((unsigned char *)iph)+(iph->ihl<<2));
-
- sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, skb->dev->ifindex);
- if (!sk || (sk->state == TCP_LISTEN))
- return 0;
- /*
- * This packet came from us.
- */
- return 1;
- }
- case IPPROTO_UDP:
- {
- struct udphdr *uh = (struct udphdr *)(((unsigned char *)iph)+(iph->ihl<<2));
-
- sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex);
- if (!sk) return 0;
- if (sk->saddr != iph->saddr && inet_addr_type(iph->saddr) != RTN_LOCAL)
- return 0;
- /*
- * This packet may have come from us.
- * Assume it did.
- */
- return 1;
- }
- }
- }
- return 0;
-}
-
-#endif
-
/*
* Deal with incoming ICMP packets.
*/
@@ -1151,7 +1147,7 @@
if ((err=ops->create(icmp_socket, IPPROTO_ICMP))<0)
panic("Failed to create the ICMP control socket.\n");
icmp_socket->sk->allocation=GFP_ATOMIC;
- icmp_socket->sk->ip_ttl = MAXTTL;
+ icmp_socket->sk->protinfo.af_inet.ttl = MAXTTL;
/* Unhash it so that IP input processing does not even
* see it, we do not wish this socket to see incoming
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)