patch-2.4.4 linux/net/ipv4/icmp.c
Next file: linux/net/ipv4/igmp.c
Previous file: linux/net/ipv4/arp.c
Back to the patch index
Back to the overall index
- Lines: 774
- Date:
Thu Apr 19 08:38:50 2001
- Orig file:
v2.4.3/linux/net/ipv4/icmp.c
- Orig date:
Fri Aug 4 18:18:49 2000
diff -u --recursive --new-file v2.4.3/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.71 2000/08/02 06:01:48 davem Exp $
+ * Version: $Id: icmp.c,v 1.74 2001/04/16 23:58:51 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -58,197 +58,6 @@
* - Should use skb_pull() instead of all the manual checking.
* This would also greatly simply some upper layer error handlers. --AK
*
- * RFC1122 (Host Requirements -- Comm. Layer) Status:
- * (boy, are there a lot of rules for ICMP)
- * 3.2.2 (Generic ICMP stuff)
- * MUST discard messages of unknown type. (OK)
- * MUST copy at least the first 8 bytes from the offending packet
- * when sending ICMP errors. (OBSOLETE -- see RFC1812)
- * MUST pass received ICMP errors up to protocol level. (OK)
- * SHOULD send ICMP errors with TOS == 0. (OBSOLETE -- see RFC1812)
- * MUST NOT send ICMP errors in reply to:
- * ICMP errors (OK)
- * Broadcast/multicast datagrams (OK)
- * MAC broadcasts (OK)
- * Non-initial fragments (OK)
- * Datagram with a source address that isn't a single host. (OK)
- * 3.2.2.1 (Destination Unreachable)
- * All the rules govern the IP layer, and are dealt with in ip.c, not here.
- * 3.2.2.2 (Redirect)
- * Host SHOULD NOT send ICMP_REDIRECTs. (OK)
- * MUST update routing table in response to host or network redirects.
- * (host OK, network OBSOLETE)
- * SHOULD drop redirects if they're not from directly connected gateway
- * (OK -- we drop it if it's not from our old gateway, which is close
- * enough)
- * 3.2.2.3 (Source Quench)
- * MUST pass incoming SOURCE_QUENCHs to transport layer (OK)
- * Other requirements are dealt with at the transport layer.
- * 3.2.2.4 (Time Exceeded)
- * MUST pass TIME_EXCEEDED to transport layer (OK)
- * Other requirements dealt with at IP (generating TIME_EXCEEDED).
- * 3.2.2.5 (Parameter Problem)
- * SHOULD generate these (OK)
- * MUST pass received PARAMPROBLEM to transport layer (NOT YET)
- * [Solaris 2.X seems to assert EPROTO when this occurs] -- AC
- * 3.2.2.6 (Echo Request/Reply)
- * MUST reply to ECHO_REQUEST, and give app to do ECHO stuff (OK, OK)
- * MAY discard broadcast ECHO_REQUESTs. (Configurable with a sysctl.)
- * MUST reply using same source address as the request was sent to.
- * We're OK for unicast ECHOs, and it doesn't say anything about
- * how to handle broadcast ones, since it's optional.
- * MUST copy data from REQUEST to REPLY (OK)
- * unless it would require illegal fragmentation (OK)
- * MUST pass REPLYs to transport/user layer (OK)
- * MUST use any provided source route (reversed) for REPLY. (NOT YET)
- * 3.2.2.7 (Information Request/Reply)
- * MUST NOT implement this. (I guess that means silently discard...?) (OK)
- * 3.2.2.8 (Timestamp Request/Reply)
- * MAY implement (OK)
- * SHOULD be in-kernel for "minimum variability" (OK)
- * MAY discard broadcast REQUESTs. (OK, but see source for inconsistency)
- * MUST reply using same source address as the request was sent to. (OK)
- * MUST reverse source route, as per ECHO (NOT YET)
- * MUST pass REPLYs to transport/user layer (requires RAW, just like
- * ECHO) (OK)
- * MUST update clock for timestamp at least 15 times/sec (OK)
- * MUST be "correct within a few minutes" (OK)
- * 3.2.2.9 (Address Mask Request/Reply)
- * MAY implement (OK)
- * MUST send a broadcast REQUEST if using this system to set netmask
- * (OK... we don't use it)
- * MUST discard received REPLYs if not using this system (OK)
- * MUST NOT send replies unless specifically made agent for this sort
- * of thing. (OK)
- *
- *
- * RFC 1812 (IPv4 Router Requirements) Status (even longer):
- * 4.3.2.1 (Unknown Message Types)
- * MUST pass messages of unknown type to ICMP user iface or silently discard
- * them (OK)
- * 4.3.2.2 (ICMP Message TTL)
- * MUST initialize TTL when originating an ICMP message (OK)
- * 4.3.2.3 (Original Message Header)
- * SHOULD copy as much data from the offending packet as possible without
- * the length of the ICMP datagram exceeding 576 bytes (OK)
- * MUST leave original IP header of the offending packet, but we're not
- * required to undo modifications made (OK)
- * 4.3.2.4 (Original Message Source Address)
- * MUST use one of addresses for the interface the orig. packet arrived as
- * source address (OK)
- * 4.3.2.5 (TOS and Precedence)
- * SHOULD leave TOS set to the same value unless the packet would be
- * discarded for that reason (OK)
- * MUST use TOS=0 if not possible to leave original value (OK)
- * MUST leave IP Precedence for Source Quench messages (OK -- not sent
- * at all)
- * SHOULD use IP Precedence = 6 (Internetwork Control) or 7 (Network Control)
- * for all other error messages (OK, we use 6)
- * MAY allow configuration of IP Precedence (OK -- not done)
- * MUST leave IP Precedence and TOS for reply messages (OK)
- * 4.3.2.6 (Source Route)
- * SHOULD use reverse source route UNLESS sending Parameter Problem on source
- * routing and UNLESS the packet would be immediately discarded (NOT YET)
- * 4.3.2.7 (When Not to Send ICMP Errors)
- * MUST NOT send ICMP errors in reply to:
- * ICMP errors (OK)
- * Packets failing IP header validation tests unless otherwise noted (OK)
- * Broadcast/multicast datagrams (OK)
- * MAC broadcasts (OK)
- * Non-initial fragments (OK)
- * Datagram with a source address that isn't a single host. (OK)
- * 4.3.2.8 (Rate Limiting)
- * SHOULD be able to limit error message rate (OK)
- * SHOULD allow setting of rate limits (OK, in the source)
- * 4.3.3.1 (Destination Unreachable)
- * All the rules govern the IP layer, and are dealt with in ip.c, not here.
- * 4.3.3.2 (Redirect)
- * MAY ignore ICMP Redirects if running a routing protocol or if forwarding
- * is enabled on the interface (OK -- ignores)
- * 4.3.3.3 (Source Quench)
- * SHOULD NOT originate SQ messages (OK)
- * MUST be able to limit SQ rate if originates them (OK as we don't
- * send them)
- * MAY ignore SQ messages it receives (OK -- we don't)
- * 4.3.3.4 (Time Exceeded)
- * Requirements dealt with at IP (generating TIME_EXCEEDED).
- * 4.3.3.5 (Parameter Problem)
- * MUST generate these for all errors not covered by other messages (OK)
- * MUST include original value of the value pointed by (OK)
- * 4.3.3.6 (Echo Request)
- * MUST implement echo server function (OK)
- * MUST process at ER of at least max(576, MTU) (OK)
- * MAY reject broadcast/multicast ER's (We don't, but that's OK)
- * SHOULD have a config option for silently ignoring ER's (OK)
- * MUST have a default value for the above switch = NO (OK)
- * MUST have application layer interface for Echo Request/Reply (OK)
- * MUST reply using same source address as the request was sent to.
- * We're OK for unicast ECHOs, and it doesn't say anything about
- * how to handle broadcast ones, since it's optional.
- * MUST copy data from Request to Reply (OK)
- * SHOULD update Record Route / Timestamp options (??)
- * MUST use reversed Source Route for Reply if possible (NOT YET)
- * 4.3.3.7 (Information Request/Reply)
- * SHOULD NOT originate or respond to these (OK)
- * 4.3.3.8 (Timestamp / Timestamp Reply)
- * MAY implement (OK)
- * MUST reply to every Timestamp message received (OK)
- * MAY discard broadcast REQUESTs. (OK, but see source for inconsistency)
- * MUST reply using same source address as the request was sent to. (OK)
- * MUST use reversed Source Route if possible (NOT YET)
- * SHOULD update Record Route / Timestamp options (??)
- * MUST pass REPLYs to transport/user layer (requires RAW, just like
- * ECHO) (OK)
- * MUST update clock for timestamp at least 16 times/sec (OK)
- * MUST be "correct within a few minutes" (OK)
- * 4.3.3.9 (Address Mask Request/Reply)
- * MUST have support for receiving AMRq and responding with AMRe (OK,
- * but only as a compile-time option)
- * SHOULD have option for each interface for AMRe's, MUST default to
- * NO (NOT YET)
- * MUST NOT reply to AMRq before knows the correct AM (OK)
- * MUST NOT respond to AMRq with source address 0.0.0.0 on physical
- * interfaces having multiple logical i-faces with different masks
- * (NOT YET)
- * SHOULD examine all AMRe's it receives and check them (NOT YET)
- * SHOULD log invalid AMRe's (AM+sender) (NOT YET)
- * MUST NOT use contents of AMRe to determine correct AM (OK)
- * MAY broadcast AMRe's after having configured address masks (OK -- doesn't)
- * MUST NOT do broadcast AMRe's if not set by extra option (OK, no option)
- * MUST use the { <NetPrefix>, -1 } form of broadcast addresses (OK)
- * 4.3.3.10 (Router Advertisement and Solicitations)
- * MUST support router part of Router Discovery Protocol on all networks we
- * support broadcast or multicast addressing. (OK -- done by gated)
- * MUST have all config parameters with the respective defaults (OK)
- * 5.2.7.1 (Destination Unreachable)
- * MUST generate DU's (OK)
- * SHOULD choose a best-match response code (OK)
- * SHOULD NOT generate Host Isolated codes (OK)
- * SHOULD use Communication Administratively Prohibited when administratively
- * filtering packets (NOT YET -- bug-to-bug compatibility)
- * MAY include config option for not generating the above and silently
- * discard the packets instead (OK)
- * MAY include config option for not generating Precedence Violation and
- * Precedence Cutoff messages (OK as we don't generate them at all)
- * MUST use Host Unreachable or Dest. Host Unknown codes whenever other hosts
- * on the same network might be reachable (OK -- no net unreach's at all)
- * MUST use new form of Fragmentation Needed and DF Set messages (OK)
- * 5.2.7.2 (Redirect)
- * MUST NOT generate network redirects (OK)
- * MUST be able to generate host redirects (OK)
- * SHOULD be able to generate Host+TOS redirects (NO as we don't use TOS)
- * MUST have an option to use Host redirects instead of Host+TOS ones (OK as
- * no Host+TOS Redirects are used)
- * MUST NOT generate redirects unless forwarding to the same i-face and the
- * dest. address is on the same subnet as the src. address and no source
- * routing is in use. (OK)
- * MUST NOT follow redirects when using a routing protocol (OK)
- * MAY use redirects if not using a routing protocol (OK, compile-time option)
- * MUST comply to Host Requirements when not acting as a router (OK)
- * 5.2.7.3 (Time Exceeded)
- * MUST generate Time Exceeded Code 0 when discarding packet due to TTL=0 (OK)
- * MAY have a per-interface option to disable origination of TE messages, but
- * it MUST default to "originate" (OK -- we don't support it)
*/
#include <linux/config.h>
@@ -282,6 +91,26 @@
#define min(a,b) ((a)<(b)?(a):(b))
/*
+ * Build xmit assembly blocks
+ */
+
+struct icmp_bxm
+{
+ struct sk_buff *skb;
+ int offset;
+ int data_len;
+
+ unsigned int csum;
+ struct {
+ struct icmphdr icmph;
+ __u32 times[3];
+ } data;
+ int head_len;
+ struct ip_options replyopts;
+ unsigned char optbuf[40];
+};
+
+/*
* Statistics
*/
@@ -324,7 +153,7 @@
{
unsigned long *output; /* Address to increment on output */
unsigned long *input; /* Address to increment on input */
- void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, int len);
+ void (*handler)(struct sk_buff *skb);
short error; /* This ICMP is classed as an error message */
int *timeout; /* Rate limit */
};
@@ -466,11 +295,12 @@
{
struct icmp_bxm *icmp_param = (struct icmp_bxm *)p;
struct icmphdr *icmph;
- unsigned long csum;
+ unsigned int csum;
if (offset) {
- icmp_param->csum=csum_partial_copy_nocheck(icmp_param->data_ptr+offset-sizeof(struct icmphdr),
- to, fraglen,icmp_param->csum);
+ icmp_param->csum=skb_copy_and_csum_bits(icmp_param->skb,
+ icmp_param->offset+(offset-icmp_param->head_len),
+ to, fraglen,icmp_param->csum);
return 0;
}
@@ -479,22 +309,24 @@
* the other fragments first, so that we get the checksum
* for the whole packet here.
*/
- csum = csum_partial_copy_nocheck((void *)&icmp_param->icmph,
- to, sizeof(struct icmphdr),
+ csum = csum_partial_copy_nocheck((void *)&icmp_param->data,
+ to, icmp_param->head_len,
icmp_param->csum);
- csum = csum_partial_copy_nocheck(icmp_param->data_ptr,
- to+sizeof(struct icmphdr),
- fraglen-sizeof(struct icmphdr), csum);
+ csum=skb_copy_and_csum_bits(icmp_param->skb,
+ icmp_param->offset,
+ to+icmp_param->head_len,
+ fraglen-icmp_param->head_len,
+ csum);
icmph=(struct icmphdr *)to;
icmph->checksum = csum_fold(csum);
return 0;
}
-
+
/*
* Driving logic for building and sending ICMP messages.
*/
-void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
+static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
{
struct sock *sk=icmp_socket->sk;
struct ipcm_cookie ipc;
@@ -507,9 +339,9 @@
if (icmp_xmit_lock_bh())
return;
- icmp_param->icmph.checksum=0;
+ icmp_param->data.icmph.checksum=0;
icmp_param->csum=0;
- icmp_out_count(icmp_param->icmph.type);
+ icmp_out_count(icmp_param->data.icmph.type);
sk->protinfo.af_inet.tos = skb->nh.iph->tos;
daddr = ipc.addr = rt->rt_src;
@@ -521,10 +353,10 @@
}
if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0))
goto out;
- if (icmpv4_xrlim_allow(rt, icmp_param->icmph.type,
- icmp_param->icmph.code)) {
+ if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type,
+ icmp_param->data.icmph.code)) {
ip_build_xmit(sk, icmp_glue_bits, icmp_param,
- icmp_param->data_len+sizeof(struct icmphdr),
+ icmp_param->data_len+icmp_param->head_len,
&ipc, rt, MSG_DONTWAIT);
}
ip_rt_put(rt);
@@ -543,10 +375,9 @@
* MUST reply to only the first fragment.
*/
-void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info)
+void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
{
struct iphdr *iph;
- struct icmphdr *icmph;
int room;
struct icmp_bxm icmp_param;
struct rtable *rt = (struct rtable*)skb_in->dst;
@@ -558,10 +389,15 @@
return;
/*
- * Find the original header
+ * Find the original header. It is expected to be valid, of course.
+ * Check this, icmp_send is called from the most obscure devices
+ * sometimes.
*/
iph = skb_in->nh.iph;
+ if ((u8*)iph < skb_in->head || (u8*)(iph+1) > skb_in->tail)
+ return;
+
/*
* No replies to physical multicast/broadcast
*/
@@ -589,17 +425,24 @@
* We are an error, check if we are replying to an ICMP error
*/
if (iph->protocol==IPPROTO_ICMP) {
- icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
+ u8 inner_type;
+
+ if (skb_copy_bits(skb_in,
+ skb_in->nh.raw + (iph->ihl<<2)
+ + offsetof(struct icmphdr, type)
+ - skb_in->data,
+ &inner_type, 1))
+ return;
+
/*
* Assume any unknown ICMP type is an error. This isn't
* specified by the RFC, but think about it..
*/
- if (icmph->type>NR_ICMP_TYPES || icmp_pointers[icmph->type].error)
+ if (inner_type>NR_ICMP_TYPES || icmp_pointers[inner_type].error)
return;
}
}
-
if (icmp_xmit_lock())
return;
@@ -625,12 +468,6 @@
((iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL) :
iph->tos;
- /* XXX: use a more aggressive expire for routes created by
- * this call (not longer than the rate limit timeout).
- * It could be also worthwhile to not put them into ipv4
- * fast routing cache at first. Otherwise an attacker can
- * grow the routing table.
- */
if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0))
goto out;
@@ -642,13 +479,14 @@
* Prepare data for ICMP header.
*/
- icmp_param.icmph.type=type;
- icmp_param.icmph.code=code;
- icmp_param.icmph.un.gateway = info;
- icmp_param.icmph.checksum=0;
+ icmp_param.data.icmph.type=type;
+ icmp_param.data.icmph.code=code;
+ icmp_param.data.icmph.un.gateway = info;
+ icmp_param.data.icmph.checksum=0;
icmp_param.csum=0;
- icmp_param.data_ptr=iph;
- icmp_out_count(icmp_param.icmph.type);
+ icmp_param.skb=skb_in;
+ icmp_param.offset=skb_in->nh.raw - skb_in->data;
+ icmp_out_count(icmp_param.data.icmph.type);
icmp_socket->sk->protinfo.af_inet.tos = tos;
ipc.addr = iph->saddr;
ipc.opt = &icmp_param.replyopts;
@@ -669,10 +507,11 @@
room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen;
room -= sizeof(struct icmphdr);
- icmp_param.data_len=(skb_in->tail-(u8*)iph);
+ icmp_param.data_len=skb_in->len-icmp_param.offset;
if (icmp_param.data_len > room)
icmp_param.data_len = room;
-
+ icmp_param.head_len = sizeof(struct icmphdr);
+
ip_build_xmit(icmp_socket->sk, icmp_glue_bits, &icmp_param,
icmp_param.data_len+sizeof(struct icmphdr),
&ipc, rt, MSG_DONTWAIT);
@@ -688,28 +527,35 @@
* Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, and ICMP_QUENCH.
*/
-static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, int len)
+static void icmp_unreach(struct sk_buff *skb)
{
struct iphdr *iph;
- int hash;
+ struct icmphdr *icmph;
+ int hash, protocol;
struct inet_protocol *ipprot;
- unsigned char *dp;
struct sock *raw_sk;
-
+ u32 info = 0;
+
/*
* Incomplete header ?
* Only checks for the IP header, there should be an
* additional check for longer headers in upper levels.
*/
- if(len<sizeof(struct iphdr)) {
+ if (!pskb_may_pull(skb, sizeof(struct iphdr))) {
ICMP_INC_STATS_BH(IcmpInErrors);
return;
}
-
- iph = (struct iphdr *) (icmph + 1);
- dp = (unsigned char*)iph;
-
+
+ icmph = skb->h.icmph;
+ iph = (struct iphdr *) skb->data;
+
+ if (iph->ihl<5) {
+ /* Mangled header, drop. */
+ ICMP_INC_STATS_BH(IcmpInErrors);
+ return;
+ }
+
if(icmph->type==ICMP_DEST_UNREACH) {
switch(icmph->code & 15) {
case ICMP_NET_UNREACH:
@@ -726,11 +572,9 @@
printk(KERN_INFO "ICMP: %u.%u.%u.%u: fragmentation needed and DF set.\n",
NIPQUAD(iph->daddr));
} else {
- unsigned short new_mtu;
- new_mtu = ip_rt_frag_needed(iph, ntohs(icmph->un.frag.mtu));
- if (!new_mtu)
- return;
- icmph->un.frag.mtu = htons(new_mtu);
+ info = ip_rt_frag_needed(iph, ntohs(icmph->un.frag.mtu));
+ if (!info)
+ goto out;
}
break;
case ICMP_SR_FAILED:
@@ -740,10 +584,12 @@
default:
break;
}
- if (icmph->code>NR_ICMP_UNREACH)
- return;
+ if (icmph->code>NR_ICMP_UNREACH)
+ goto out;
+ } else if (icmph->type == ICMP_PARAMETERPROB) {
+ info = ntohl(icmph->un.gateway)>>24;
}
-
+
/*
* Throw it at our lower layers
*
@@ -751,7 +597,7 @@
* RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the transport layer.
* RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to transport layer.
*/
-
+
/*
* Check the other end isnt violating RFC 1122. Some routers send
* bogus responses to broadcast frames. If you see this message
@@ -767,23 +613,33 @@
if (net_ratelimit())
printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP error to a broadcast.\n",
NIPQUAD(skb->nh.iph->saddr));
- return;
+ goto out;
}
}
+ /* Checkin full IP header plus 8 bytes of protocol to
+ * avoid additional coding at protocol handlers.
+ */
+ if (!pskb_may_pull(skb, iph->ihl*4+8))
+ goto out;
+
+ iph = (struct iphdr *) skb->data;
+ protocol = iph->protocol;
+
/*
* Deliver ICMP message to raw sockets. Pretty useless feature?
*/
/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
- hash = iph->protocol & (MAX_INET_PROTOS - 1);
+ hash = 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,
+ while ((raw_sk = __raw_v4_lookup(raw_sk, protocol, iph->saddr,
iph->daddr, skb->dev->ifindex)) != NULL) {
- raw_err(raw_sk, skb);
+ raw_err(raw_sk, skb, info);
raw_sk = raw_sk->next;
+ iph = (struct iphdr *)skb->data;
}
}
read_unlock(&raw_v4_lock);
@@ -807,11 +663,12 @@
/* RFC1122: OK. Passes appropriate ICMP errors to the */
/* appropriate protocol layer (MUST), as per 3.2.2. */
- if (iph->protocol == ipprot->protocol && ipprot->err_handler)
- ipprot->err_handler(skb, dp, len);
+ if (protocol == ipprot->protocol && ipprot->err_handler)
+ ipprot->err_handler(skb, info);
ipprot = nextip;
}
+out:;
}
@@ -819,24 +676,26 @@
* Handle ICMP_REDIRECT.
*/
-static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, int len)
+static void icmp_redirect(struct sk_buff *skb)
{
struct iphdr *iph;
unsigned long ip;
- if (len < sizeof(struct iphdr)) {
+ if (skb->len < sizeof(struct iphdr)) {
ICMP_INC_STATS_BH(IcmpInErrors);
return;
}
-
+
/*
* Get the copied header of the packet that caused the redirect
*/
-
- iph = (struct iphdr *) (icmph + 1);
+ if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ return;
+
+ iph = (struct iphdr *) skb->data;
ip = iph->daddr;
- switch(icmph->code & 7) {
+ switch(skb->h.icmph->code & 7) {
case ICMP_REDIR_NET:
case ICMP_REDIR_NETTOS:
/*
@@ -846,7 +705,7 @@
case ICMP_REDIR_HOST:
case ICMP_REDIR_HOSTTOS:
- ip_rt_redirect(skb->nh.iph->saddr, ip, icmph->un.gateway, iph->saddr, iph->tos, skb->dev);
+ ip_rt_redirect(skb->nh.iph->saddr, ip, skb->h.icmph->un.gateway, iph->saddr, iph->tos, skb->dev);
break;
default:
break;
@@ -862,15 +721,17 @@
* See also WRT handling of options once they are done and working.
*/
-static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, int len)
+static void icmp_echo(struct sk_buff *skb)
{
if (!sysctl_icmp_echo_ignore_all) {
struct icmp_bxm icmp_param;
- icmp_param.icmph=*icmph;
- icmp_param.icmph.type=ICMP_ECHOREPLY;
- icmp_param.data_ptr=(icmph+1);
- icmp_param.data_len=len;
+ icmp_param.data.icmph=*skb->h.icmph;
+ icmp_param.data.icmph.type=ICMP_ECHOREPLY;
+ icmp_param.skb=skb;
+ icmp_param.offset=0;
+ icmp_param.data_len=skb->len;
+ icmp_param.head_len=sizeof(struct icmphdr);
icmp_reply(&icmp_param, skb);
}
}
@@ -883,34 +744,35 @@
* MUST be updated at least at 15Hz.
*/
-static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, int len)
+static void icmp_timestamp(struct sk_buff *skb)
{
struct timeval tv;
- __u32 times[3]; /* So the new timestamp works on ALPHA's.. */
struct icmp_bxm icmp_param;
/*
* Too short.
*/
- if(len<12) {
+ if(skb->len<4) {
ICMP_INC_STATS_BH(IcmpInErrors);
return;
}
-
+
/*
* Fill in the current time as ms since midnight UT:
*/
-
do_gettimeofday(&tv);
- times[1] = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
- times[2] = times[1];
- memcpy((void *)×[0], icmph+1, 4); /* Incoming stamp */
- icmp_param.icmph=*icmph;
- icmp_param.icmph.type=ICMP_TIMESTAMPREPLY;
- icmp_param.icmph.code=0;
- icmp_param.data_ptr=×
- icmp_param.data_len=12;
+ icmp_param.data.times[1] = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
+ icmp_param.data.times[2] = icmp_param.data.times[1];
+ if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4))
+ BUG();
+ icmp_param.data.icmph=*skb->h.icmph;
+ icmp_param.data.icmph.type=ICMP_TIMESTAMPREPLY;
+ icmp_param.data.icmph.code=0;
+ icmp_param.skb=skb;
+ icmp_param.offset=0;
+ icmp_param.data_len=0;
+ icmp_param.head_len=sizeof(struct icmphdr)+12;
icmp_reply(&icmp_param, skb);
}
@@ -948,7 +810,7 @@
* anyway...
*/
-static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, int len)
+static void icmp_address(struct sk_buff *skb)
{
#if 0
if (net_ratelimit())
@@ -961,7 +823,7 @@
* loudly if an inconsistency is found.
*/
-static void icmp_address_reply(struct icmphdr *icmph, struct sk_buff *skb, int len)
+static void icmp_address_reply(struct sk_buff *skb)
{
struct rtable *rt = (struct rtable*)skb->dst;
struct net_device *dev = skb->dev;
@@ -969,7 +831,7 @@
struct in_ifaddr *ifa;
u32 mask;
- if (len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC))
+ if (skb->len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC))
return;
in_dev = in_dev_get(dev);
@@ -979,8 +841,8 @@
if (in_dev->ifa_list &&
IN_DEV_LOG_MARTIANS(in_dev) &&
IN_DEV_FORWARD(in_dev)) {
-
- mask = *(u32*)&icmph[1];
+ if (skb_copy_bits(skb, 0, &mask, 4))
+ BUG();
for (ifa=in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
if (mask == ifa->ifa_mask && inet_ifa_match(rt->rt_src, ifa))
break;
@@ -994,7 +856,7 @@
in_dev_put(in_dev);
}
-static void icmp_discard(struct icmphdr *icmph, struct sk_buff *skb, int len)
+static void icmp_discard(struct sk_buff *skb)
{
}
@@ -1002,23 +864,36 @@
* Deal with incoming ICMP packets.
*/
-int icmp_rcv(struct sk_buff *skb, unsigned short len)
+int icmp_rcv(struct sk_buff *skb)
{
struct icmphdr *icmph = skb->h.icmph;
struct rtable *rt = (struct rtable*)skb->dst;
ICMP_INC_STATS_BH(IcmpInMsgs);
+ switch (skb->ip_summed) {
+ case CHECKSUM_HW:
+ if ((u16)csum_fold(skb->csum) == 0)
+ break;
+ NETDEBUG(printk(KERN_DEBUG "icmp v4 hw csum failure\n"));
+ case CHECKSUM_NONE:
+ if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0)))
+ goto error;
+ default:;
+ }
+
+ if (!pskb_pull(skb, sizeof(struct icmphdr)))
+ goto error;
+
/*
* 18 is the highest 'known' ICMP type. Anything else is a mystery
*
* RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently discarded.
*/
- if(len < sizeof(struct icmphdr) ||
- ip_compute_csum((unsigned char *) icmph, len) ||
- icmph->type > NR_ICMP_TYPES)
+ if (icmph->type > NR_ICMP_TYPES)
goto error;
-
+
+
/*
* Parse the ICMP message
*/
@@ -1042,9 +917,8 @@
}
}
- len -= sizeof(struct icmphdr);
icmp_pointers[icmph->type].input[smp_processor_id()*2*sizeof(struct icmp_mib)/sizeof(unsigned long)]++;
- (icmp_pointers[icmph->type].handler)(icmph, skb, len);
+ (icmp_pointers[icmph->type].handler)(skb);
drop:
kfree_skb(skb);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)