patch-2.1.100 linux/net/ipv6/icmp.c
Next file: linux/net/ipv6/ip6_input.c
Previous file: linux/net/ipv6/exthdrs.c
Back to the patch index
Back to the overall index
- Lines: 257
- Date:
Sat May 2 14:22:30 1998
- Orig file:
v2.1.99/linux/net/ipv6/icmp.c
- Orig date:
Thu Mar 26 15:57:13 1998
diff -u --recursive --new-file v2.1.99/linux/net/ipv6/icmp.c linux/net/ipv6/icmp.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: icmp.c,v 1.15 1998/03/21 07:28:03 davem Exp $
+ * $Id: icmp.c,v 1.17 1998/05/01 10:31:41 davem Exp $
*
* Based on net/ipv4/icmp.c
*
@@ -21,6 +21,8 @@
* Changes:
*
* Andi Kleen : exception handling
+ * Andi Kleen add rate limits. never reply to a icmp.
+ * add more length checks and other fixes.
*/
#define __NO_VERSION__
@@ -51,6 +53,7 @@
#include <net/transp_v6.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
+#include <net/icmp.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -129,6 +132,62 @@
return 0;
}
+
+/*
+ * Slightly more convenient version of icmpv6_send.
+ */
+void icmpv6_param_prob(struct sk_buff *skb, int code, void *pos)
+{
+ int offset = (u8*)pos - (u8*)skb->nh.ipv6h;
+
+ icmpv6_send(skb, ICMPV6_PARAMPROB, code, offset, skb->dev);
+ kfree_skb(skb);
+}
+
+static inline int is_icmp(struct ipv6hdr *hdr, int len)
+{
+ __u8 nexthdr = hdr->nexthdr;
+
+ if (!ipv6_skip_exthdr((struct ipv6_opt_hdr *)(hdr+1), &nexthdr, len))
+ return 0;
+ return nexthdr == IPPROTO_ICMP;
+}
+
+int sysctl_icmpv6_time = 1*HZ;
+
+/*
+ * Check the ICMP output rate limit
+ */
+static inline int icmpv6_xrlim_allow(struct sock *sk, int type,
+ struct flowi *fl)
+{
+#if 0
+ struct dst_entry *dst;
+ int allow = 0;
+#endif
+ /* Informational messages are not limited. */
+ if (type & 0x80)
+ return 1;
+
+#if 0 /* not yet, first fix routing COW */
+
+ /*
+ * Look up the output route.
+ * XXX: perhaps the expire for routing entries cloned by
+ * this lookup should be more aggressive (not longer than timeout).
+ */
+ dst = ip6_route_output(sk, fl, 1);
+ if (dst->error)
+ ipv6_statistics.Ip6OutNoRoutes++;
+ else
+ allow = xrlim_allow(dst, sysctl_icmpv6_time);
+ dst_release(dst);
+ return allow;
+#else
+ return 1;
+#endif
+}
+
/*
* an inline helper for the "simple" if statement below
* checks if parameter problem report is caused by an
@@ -214,6 +273,24 @@
return;
}
+ /*
+ * Never answer to a ICMP packet.
+ */
+ if (is_icmp(hdr, (u8*)skb->tail - (u8*)hdr)) {
+ printk(KERN_DEBUG "icmpv6_send: no reply to icmp\n");
+ return;
+ }
+
+ fl.proto = IPPROTO_ICMPV6;
+ fl.nl_u.ip6_u.daddr = &hdr->saddr;
+ fl.nl_u.ip6_u.saddr = saddr;
+ fl.oif = iif;
+ fl.uli_u.icmpt.type = type;
+ fl.uli_u.icmpt.code = code;
+
+ if (!icmpv6_xrlim_allow(sk, type, &fl))
+ return;
+
/*
* ok. kick it. checksum will be provided by the
* getfrag_t callback.
@@ -248,13 +325,6 @@
msg.len = len;
- fl.proto = IPPROTO_ICMPV6;
- fl.nl_u.ip6_u.daddr = &hdr->saddr;
- fl.nl_u.ip6_u.saddr = saddr;
- fl.oif = iif;
- fl.uli_u.icmpt.type = type;
- fl.uli_u.icmpt.code = code;
-
ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
MSG_DONTWAIT);
@@ -312,21 +382,6 @@
dst_release(xchg(&sk->dst_cache, NULL));
}
-static __inline__ int ipv6_ext_hdr(u8 nexthdr)
-{
- /*
- * find out if nexthdr is an extension header or a protocol
- */
- return ( (nexthdr == NEXTHDR_HOP) ||
- (nexthdr == NEXTHDR_ROUTING) ||
- (nexthdr == NEXTHDR_FRAGMENT) ||
- (nexthdr == NEXTHDR_ESP) ||
- (nexthdr == NEXTHDR_AUTH) ||
- (nexthdr == NEXTHDR_NONE) ||
- (nexthdr == NEXTHDR_DEST) );
-
-}
-
static void icmpv6_notify(struct sk_buff *skb,
int type, int code, unsigned char *buff, int len,
struct in6_addr *saddr, struct in6_addr *daddr,
@@ -335,39 +390,22 @@
struct ipv6hdr *hdr = (struct ipv6hdr *) buff;
struct inet6_protocol *ipprot;
struct sock *sk;
- char * pbuff;
+ struct ipv6_opt_hdr *pb;
__u32 info = 0;
int hash;
u8 nexthdr;
- /* now skip over extension headers */
-
nexthdr = hdr->nexthdr;
- pbuff = (char *) (hdr + 1);
+ pb = (struct ipv6_opt_hdr *) (hdr + 1);
len -= sizeof(struct ipv6hdr);
+ if (len < 0)
+ return;
- while (ipv6_ext_hdr(nexthdr)) {
- int hdrlen;
-
- if (nexthdr == NEXTHDR_NONE)
- return;
-
- nexthdr = *pbuff;
-
- /* Header length is size in 8-octet units, not
- * including the first 8 octets.
- */
- hdrlen = *(pbuff+1);
- hdrlen = (hdrlen + 1) << 3;
-
- if (hdrlen > len)
- return;
-
- /* Now this is right. */
- pbuff += hdrlen;
- len -= hdrlen;
- }
+ /* now skip over extension headers */
+ pb = ipv6_skip_exthdr(pb, &nexthdr, len);
+ if (!pb)
+ return;
hash = nexthdr & (MAX_INET_PROTOS - 1);
@@ -378,7 +416,7 @@
continue;
if (ipprot->err_handler)
- ipprot->err_handler(skb, type, code, pbuff, info,
+ ipprot->err_handler(skb, type, code, (u8*)pb, info,
saddr, daddr, ipprot);
return;
}
@@ -391,7 +429,7 @@
return;
while((sk = raw_v6_lookup(sk, nexthdr, daddr, saddr))) {
- rawv6_err(sk, type, code, pbuff, saddr, daddr);
+ rawv6_err(sk, type, code, (char*)pb, saddr, daddr);
sk = sk->next;
}
}
@@ -514,7 +552,7 @@
return 0;
}
-__initfunc(void icmpv6_init(struct net_proto_family *ops))
+__initfunc(int icmpv6_init(struct net_proto_family *ops))
{
struct sock *sk;
int err;
@@ -528,11 +566,11 @@
icmpv6_socket->state = SS_UNCONNECTED;
icmpv6_socket->type=SOCK_RAW;
- if((err=ops->create(icmpv6_socket, IPPROTO_ICMPV6))<0)
+ if((err=ops->create(icmpv6_socket, IPPROTO_ICMPV6))<0) {
printk(KERN_DEBUG
"Failed to create the ICMP6 control socket.\n");
-
- MOD_DEC_USE_COUNT;
+ return 1;
+ }
sk = icmpv6_socket->sk;
sk->allocation = GFP_ATOMIC;
@@ -542,6 +580,16 @@
ndisc_init(ops);
igmp6_init(ops);
+ return 0;
+}
+
+void icmpv6_cleanup(void)
+{
+ inet6_del_protocol(&icmpv6_protocol);
+#if 0
+ ndisc_cleanup();
+#endif
+ igmp6_cleanup();
}
static struct icmp6_err {
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov