aboutsummaryrefslogtreecommitdiff
path: root/pfinet/linux-inet/icmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'pfinet/linux-inet/icmp.c')
-rw-r--r--pfinet/linux-inet/icmp.c774
1 files changed, 0 insertions, 774 deletions
diff --git a/pfinet/linux-inet/icmp.c b/pfinet/linux-inet/icmp.c
deleted file mode 100644
index c023eab2..00000000
--- a/pfinet/linux-inet/icmp.c
+++ /dev/null
@@ -1,774 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Internet Control Message Protocol (ICMP)
- *
- * Version: @(#)icmp.c 1.0.11 06/02/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Mark Evans, <evansmp@uhura.aston.ac.uk>
- * Alan Cox, <gw4pts@gw4pts.ampr.org>
- * Stefan Becker, <stefanb@yello.ping.de>
- *
- * Fixes:
- * Alan Cox : Generic queue usage.
- * Gerhard Koerting: ICMP addressing corrected
- * Alan Cox : Use tos/ttl settings
- * Alan Cox : Protocol violations
- * Alan Cox : SNMP Statistics
- * Alan Cox : Routing errors
- * Alan Cox : Changes for newer routing code
- * Alan Cox : Removed old debugging junk
- * Alan Cox : Fixed the ICMP error status of net/host unreachable
- * Gerhard Koerting : Fixed broadcast ping properly
- * Ulrich Kunitz : Fixed ICMP timestamp reply
- * A.N.Kuznetsov : Multihoming fixes.
- * Laco Rusnak : Multihoming fixes.
- * Alan Cox : Tightened up icmp_send().
- * Alan Cox : Multicasts.
- * Stefan Becker : ICMP redirects in icmp_send().
- *
- *
- *
- * 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
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/fcntl.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/string.h>
-#include "snmp.h"
-#include "ip.h"
-#include "route.h"
-#include "protocol.h"
-#include "icmp.h"
-#include "tcp.h"
-#include "snmp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-
-
-#define min(a,b) ((a)<(b)?(a):(b))
-
-
-/*
- * Statistics
- */
-
-struct icmp_mib icmp_statistics={0,};
-
-
-/* An array of errno for error messages from dest unreach. */
-struct icmp_err icmp_err_convert[] = {
- { ENETUNREACH, 0 }, /* ICMP_NET_UNREACH */
- { EHOSTUNREACH, 0 }, /* ICMP_HOST_UNREACH */
- { ENOPROTOOPT, 1 }, /* ICMP_PROT_UNREACH */
- { ECONNREFUSED, 1 }, /* ICMP_PORT_UNREACH */
- { EOPNOTSUPP, 0 }, /* ICMP_FRAG_NEEDED */
- { EOPNOTSUPP, 0 }, /* ICMP_SR_FAILED */
- { ENETUNREACH, 1 }, /* ICMP_NET_UNKNOWN */
- { EHOSTDOWN, 1 }, /* ICMP_HOST_UNKNOWN */
- { ENONET, 1 }, /* ICMP_HOST_ISOLATED */
- { ENETUNREACH, 1 }, /* ICMP_NET_ANO */
- { EHOSTUNREACH, 1 }, /* ICMP_HOST_ANO */
- { EOPNOTSUPP, 0 }, /* ICMP_NET_UNR_TOS */
- { EOPNOTSUPP, 0 } /* ICMP_HOST_UNR_TOS */
-};
-
-
-/*
- * Send an ICMP message in response to a situation
- *
- * Fixme: Fragment handling is wrong really.
- */
-
-void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info, struct device *dev)
-{
- struct sk_buff *skb;
- struct iphdr *iph;
- int offset;
- struct icmphdr *icmph;
- int len;
- struct device *ndev=NULL; /* Make this =dev to force replies on the same interface */
- unsigned long our_addr;
- int atype;
-
- /*
- * Find the original IP header.
- */
-
- iph = (struct iphdr *) (skb_in->data + dev->hard_header_len);
-
- /*
- * No replies to MAC multicast
- */
-
- if(skb_in->pkt_type!=PACKET_HOST)
- return;
-
- /*
- * No replies to IP multicasting
- */
-
- atype=ip_chk_addr(iph->daddr);
- if(atype==IS_BROADCAST || IN_MULTICAST(iph->daddr))
- return;
-
- /*
- * Only reply to first fragment.
- */
-
- if(ntohs(iph->frag_off)&IP_OFFSET)
- return;
-
- /*
- * We must NEVER NEVER send an ICMP error to an ICMP error message
- */
-
- if(type==ICMP_DEST_UNREACH||type==ICMP_REDIRECT||type==ICMP_SOURCE_QUENCH||type==ICMP_TIME_EXCEEDED)
- {
-
- /*
- * Is the original packet an ICMP packet?
- */
-
- if(iph->protocol==IPPROTO_ICMP)
- {
- icmph = (struct icmphdr *) ((char *) iph +
- 4 * iph->ihl);
- /*
- * Check for ICMP error packets (Must never reply to
- * an ICMP error).
- */
-
- if (icmph->type == ICMP_DEST_UNREACH ||
- icmph->type == ICMP_SOURCE_QUENCH ||
- icmph->type == ICMP_REDIRECT ||
- icmph->type == ICMP_TIME_EXCEEDED ||
- icmph->type == ICMP_PARAMETERPROB)
- return;
- }
- }
- icmp_statistics.IcmpOutMsgs++;
-
- /*
- * This needs a tidy.
- */
-
- switch(type)
- {
- case ICMP_DEST_UNREACH:
- icmp_statistics.IcmpOutDestUnreachs++;
- break;
- case ICMP_SOURCE_QUENCH:
- icmp_statistics.IcmpOutSrcQuenchs++;
- break;
- case ICMP_REDIRECT:
- icmp_statistics.IcmpOutRedirects++;
- break;
- case ICMP_ECHO:
- icmp_statistics.IcmpOutEchos++;
- break;
- case ICMP_ECHOREPLY:
- icmp_statistics.IcmpOutEchoReps++;
- break;
- case ICMP_TIME_EXCEEDED:
- icmp_statistics.IcmpOutTimeExcds++;
- break;
- case ICMP_PARAMETERPROB:
- icmp_statistics.IcmpOutParmProbs++;
- break;
- case ICMP_TIMESTAMP:
- icmp_statistics.IcmpOutTimestamps++;
- break;
- case ICMP_TIMESTAMPREPLY:
- icmp_statistics.IcmpOutTimestampReps++;
- break;
- case ICMP_ADDRESS:
- icmp_statistics.IcmpOutAddrMasks++;
- break;
- case ICMP_ADDRESSREPLY:
- icmp_statistics.IcmpOutAddrMaskReps++;
- break;
- }
- /*
- * Get some memory for the reply.
- */
-
- len = dev->hard_header_len + sizeof(struct iphdr) + sizeof(struct icmphdr) +
- sizeof(struct iphdr) + 32; /* amount of header to return */
-
- skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);
- if (skb == NULL)
- {
- icmp_statistics.IcmpOutErrors++;
- return;
- }
- skb->free = 1;
-
- /*
- * Build Layer 2-3 headers for message back to source.
- */
-
- our_addr = dev->pa_addr;
- if (iph->daddr != our_addr && ip_chk_addr(iph->daddr) == IS_MYADDR)
- our_addr = iph->daddr;
- offset = ip_build_header(skb, our_addr, iph->saddr,
- &ndev, IPPROTO_ICMP, NULL, len,
- skb_in->ip_hdr->tos,255);
- if (offset < 0)
- {
- icmp_statistics.IcmpOutErrors++;
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /*
- * Re-adjust length according to actual IP header size.
- */
-
- skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;
-
- /*
- * Fill in the frame
- */
-
- icmph = (struct icmphdr *) (skb->data + offset);
- icmph->type = type;
- icmph->code = code;
- icmph->checksum = 0;
- icmph->un.gateway = info; /* This might not be meant for
- this form of the union but it will
- be right anyway */
- memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
-
- icmph->checksum = ip_compute_csum((unsigned char *)icmph,
- sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
-
- /*
- * Send it and free it once sent.
- */
- ip_queue_xmit(NULL, ndev, skb, 1);
-}
-
-
-/*
- * Handle ICMP_UNREACH and ICMP_QUENCH.
- */
-
-static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
-{
- struct inet_protocol *ipprot;
- struct iphdr *iph;
- unsigned char hash;
- int err;
-
- err = (icmph->type << 8) | icmph->code;
- iph = (struct iphdr *) (icmph + 1);
-
- switch(icmph->code & 7)
- {
- case ICMP_NET_UNREACH:
- break;
- case ICMP_HOST_UNREACH:
- break;
- case ICMP_PROT_UNREACH:
- printk("ICMP: %s:%d: protocol unreachable.\n",
- in_ntoa(iph->daddr), ntohs(iph->protocol));
- break;
- case ICMP_PORT_UNREACH:
- break;
- case ICMP_FRAG_NEEDED:
- printk("ICMP: %s: fragmentation needed and DF set.\n",
- in_ntoa(iph->daddr));
- break;
- case ICMP_SR_FAILED:
- printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
- break;
- default:
- break;
- }
-
- /*
- * Get the protocol(s).
- */
-
- hash = iph->protocol & (MAX_INET_PROTOS -1);
-
- /*
- * This can't change while we are doing it.
- */
-
- ipprot = (struct inet_protocol *) inet_protos[hash];
- while(ipprot != NULL)
- {
- struct inet_protocol *nextip;
-
- nextip = (struct inet_protocol *) ipprot->next;
-
- /*
- * Pass it off to everyone who wants it.
- */
- if (iph->protocol == ipprot->protocol && ipprot->err_handler)
- {
- ipprot->err_handler(err, (unsigned char *)(icmph + 1),
- iph->daddr, iph->saddr, ipprot);
- }
-
- ipprot = nextip;
- }
- kfree_skb(skb, FREE_READ);
-}
-
-
-/*
- * Handle ICMP_REDIRECT.
- */
-
-static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb,
- struct device *dev, unsigned long source)
-{
- struct rtable *rt;
- struct iphdr *iph;
- unsigned long ip;
-
- /*
- * Get the copied header of the packet that caused the redirect
- */
-
- iph = (struct iphdr *) (icmph + 1);
- ip = iph->daddr;
-
- switch(icmph->code & 7)
- {
- case ICMP_REDIR_NET:
- /*
- * This causes a problem with subnetted networks. What we should do
- * is use ICMP_ADDRESS to get the subnet mask of the problem route
- * and set both. But we don't..
- */
-#ifdef not_a_good_idea
- ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
- ip, 0, icmph->un.gateway, dev,0, 0);
- break;
-#endif
- case ICMP_REDIR_HOST:
- /*
- * Add better route to host.
- * But first check that the redirect
- * comes from the old gateway..
- * And make sure it's an ok host address
- * (not some confused thing sending our
- * address)
- */
- rt = ip_rt_route(ip, NULL, NULL);
- if (!rt)
- break;
- if (rt->rt_gateway != source || ip_chk_addr(icmph->un.gateway))
- break;
- printk("redirect from %s\n", in_ntoa(source));
- ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
- ip, 0, icmph->un.gateway, dev,0, 0);
- break;
- case ICMP_REDIR_NETTOS:
- case ICMP_REDIR_HOSTTOS:
- printk("ICMP: cannot handle TOS redirects yet!\n");
- break;
- default:
- break;
- }
-
- /*
- * Discard the original packet
- */
-
- kfree_skb(skb, FREE_READ);
-}
-
-
-/*
- * Handle ICMP_ECHO ("ping") requests.
- */
-
-static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
- unsigned long saddr, unsigned long daddr, int len,
- struct options *opt)
-{
- struct icmphdr *icmphr;
- struct sk_buff *skb2;
- struct device *ndev=NULL;
- int size, offset;
-
- icmp_statistics.IcmpOutEchoReps++;
- icmp_statistics.IcmpOutMsgs++;
-
- size = dev->hard_header_len + 64 + len;
- skb2 = alloc_skb(size, GFP_ATOMIC);
-
- if (skb2 == NULL)
- {
- icmp_statistics.IcmpOutErrors++;
- kfree_skb(skb, FREE_READ);
- return;
- }
- skb2->free = 1;
-
- /* Build Layer 2-3 headers for message back to source */
- offset = ip_build_header(skb2, daddr, saddr, &ndev,
- IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
- if (offset < 0)
- {
- icmp_statistics.IcmpOutErrors++;
- printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
- kfree_skb(skb2,FREE_WRITE);
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /*
- * Re-adjust length according to actual IP header size.
- */
-
- skb2->len = offset + len;
-
- /*
- * Build ICMP_ECHO Response message.
- */
- icmphr = (struct icmphdr *) (skb2->data + offset);
- memcpy((char *) icmphr, (char *) icmph, len);
- icmphr->type = ICMP_ECHOREPLY;
- icmphr->code = 0;
- icmphr->checksum = 0;
- icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
-
- /*
- * Ship it out - free it when done
- */
- ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
-
- /*
- * Free the received frame
- */
-
- kfree_skb(skb, FREE_READ);
-}
-
-/*
- * Handle ICMP Timestamp requests.
- */
-
-static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
- unsigned long saddr, unsigned long daddr, int len,
- struct options *opt)
-{
- struct icmphdr *icmphr;
- struct sk_buff *skb2;
- int size, offset;
- unsigned long *timeptr, midtime;
- struct device *ndev=NULL;
-
- if (len != 20)
- {
- printk(
- "ICMP: Size (%d) of ICMP_TIMESTAMP request should be 20!\n",
- len);
- icmp_statistics.IcmpInErrors++;
-#if 1
- /* correct answers are possible for everything >= 12 */
- if (len < 12)
-#endif
- return;
- }
-
- size = dev->hard_header_len + 84;
-
- if (! (skb2 = alloc_skb(size, GFP_ATOMIC)))
- {
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- icmp_statistics.IcmpOutErrors++;
- return;
- }
- skb2->free = 1;
-
-/*
- * Build Layer 2-3 headers for message back to source
- */
-
- offset = ip_build_header(skb2, daddr, saddr, &ndev, IPPROTO_ICMP, opt, len,
- skb->ip_hdr->tos, 255);
- if (offset < 0)
- {
- printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n");
- kfree_skb(skb2, FREE_WRITE);
- kfree_skb(skb, FREE_READ);
- icmp_statistics.IcmpOutErrors++;
- return;
- }
-
- /*
- * Re-adjust length according to actual IP header size.
- */
- skb2->len = offset + 20;
-
- /*
- * Build ICMP_TIMESTAMP Response message.
- */
-
- icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
- memcpy((char *) icmphr, (char *) icmph, 12);
- icmphr->type = ICMP_TIMESTAMPREPLY;
- icmphr->code = icmphr->checksum = 0;
-
- /* fill in the current time as ms since midnight UT: */
- midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000;
- timeptr = (unsigned long *) (icmphr + 1);
- /*
- * the originate timestamp (timeptr [0]) is still in the copy:
- */
- timeptr [1] = timeptr [2] = htonl(midtime);
-
- icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, 20);
-
- /*
- * Ship it out - free it when done
- */
-
- ip_queue_xmit((struct sock *) NULL, ndev, skb2, 1);
- icmp_statistics.IcmpOutTimestampReps++;
- kfree_skb(skb, FREE_READ);
-}
-
-
-
-
-/*
- * Handle the ICMP INFORMATION REQUEST.
- */
-
-static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
- unsigned long saddr, unsigned long daddr, int len,
- struct options *opt)
-{
- /* Obsolete */
- kfree_skb(skb, FREE_READ);
-}
-
-
-/*
- * Handle ICMP_ADDRESS_MASK requests.
- */
-
-static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
- unsigned long saddr, unsigned long daddr, int len,
- struct options *opt)
-{
- struct icmphdr *icmphr;
- struct sk_buff *skb2;
- int size, offset;
- struct device *ndev=NULL;
-
- icmp_statistics.IcmpOutMsgs++;
- icmp_statistics.IcmpOutAddrMaskReps++;
-
- size = dev->hard_header_len + 64 + len;
- skb2 = alloc_skb(size, GFP_ATOMIC);
- if (skb2 == NULL)
- {
- icmp_statistics.IcmpOutErrors++;
- kfree_skb(skb, FREE_READ);
- return;
- }
- skb2->free = 1;
-
- /*
- * Build Layer 2-3 headers for message back to source
- */
-
- offset = ip_build_header(skb2, daddr, saddr, &ndev,
- IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
- if (offset < 0)
- {
- icmp_statistics.IcmpOutErrors++;
- printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
- kfree_skb(skb2,FREE_WRITE);
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /*
- * Re-adjust length according to actual IP header size.
- */
-
- skb2->len = offset + len;
-
- /*
- * Build ICMP ADDRESS MASK Response message.
- */
-
- icmphr = (struct icmphdr *) (skb2->data + offset);
- icmphr->type = ICMP_ADDRESSREPLY;
- icmphr->code = 0;
- icmphr->checksum = 0;
- icmphr->un.echo.id = icmph->un.echo.id;
- icmphr->un.echo.sequence = icmph->un.echo.sequence;
- memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
-
- icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
-
- /* Ship it out - free it when done */
- ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
-
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
-}
-
-
-/*
- * Deal with incoming ICMP packets.
- */
-
-int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
- unsigned long daddr, unsigned short len,
- unsigned long saddr, int redo, struct inet_protocol *protocol)
-{
- struct icmphdr *icmph;
- unsigned char *buff;
-
- /*
- * Drop broadcast packets. IP has done a broadcast check and ought one day
- * to pass on that information.
- */
-
- icmp_statistics.IcmpInMsgs++;
-
-
- /*
- * Grab the packet as an icmp object
- */
-
- buff = skb1->h.raw;
- icmph = (struct icmphdr *) buff;
-
- /*
- * Validate the packet first
- */
-
- if (ip_compute_csum((unsigned char *) icmph, len))
- {
- /* Failed checksum! */
- icmp_statistics.IcmpInErrors++;
- printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
- kfree_skb(skb1, FREE_READ);
- return(0);
- }
-
- /*
- * Parse the ICMP message
- */
-
- if (ip_chk_addr(daddr) != IS_MYADDR)
- {
- if (icmph->type != ICMP_ECHO)
- {
- icmp_statistics.IcmpInErrors++;
- kfree_skb(skb1, FREE_READ);
- return(0);
- }
- daddr=dev->pa_addr;
- }
-
- switch(icmph->type)
- {
- case ICMP_TIME_EXCEEDED:
- icmp_statistics.IcmpInTimeExcds++;
- icmp_unreach(icmph, skb1);
- return 0;
- case ICMP_DEST_UNREACH:
- icmp_statistics.IcmpInDestUnreachs++;
- icmp_unreach(icmph, skb1);
- return 0;
- case ICMP_SOURCE_QUENCH:
- icmp_statistics.IcmpInSrcQuenchs++;
- icmp_unreach(icmph, skb1);
- return(0);
- case ICMP_REDIRECT:
- icmp_statistics.IcmpInRedirects++;
- icmp_redirect(icmph, skb1, dev, saddr);
- return(0);
- case ICMP_ECHO:
- icmp_statistics.IcmpInEchos++;
- icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
- return 0;
- case ICMP_ECHOREPLY:
- icmp_statistics.IcmpInEchoReps++;
- kfree_skb(skb1, FREE_READ);
- return(0);
- case ICMP_TIMESTAMP:
- icmp_statistics.IcmpInTimestamps++;
- icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt);
- return 0;
- case ICMP_TIMESTAMPREPLY:
- icmp_statistics.IcmpInTimestampReps++;
- kfree_skb(skb1,FREE_READ);
- return 0;
- /* INFO is obsolete and doesn't even feature in the SNMP stats */
- case ICMP_INFO_REQUEST:
- icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
- return 0;
- case ICMP_INFO_REPLY:
- skb1->sk = NULL;
- kfree_skb(skb1, FREE_READ);
- return(0);
- case ICMP_ADDRESS:
- icmp_statistics.IcmpInAddrMasks++;
- icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
- return 0;
- case ICMP_ADDRESSREPLY:
- /*
- * We ought to set our netmask on receiving this, but
- * experience shows it's a waste of effort.
- */
- icmp_statistics.IcmpInAddrMaskReps++;
- kfree_skb(skb1, FREE_READ);
- return(0);
- default:
- icmp_statistics.IcmpInErrors++;
- kfree_skb(skb1, FREE_READ);
- return(0);
- }
- /*NOTREACHED*/
- kfree_skb(skb1, FREE_READ);
- return(-1);
-}
-
-
-/*
- * Perform any ICMP-related I/O control requests.
- * [to vanish soon]
- */
-
-int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
-{
- switch(cmd)
- {
- default:
- return(-EINVAL);
- }
- return(0);
-}