|
|
1.1 root 1: /* Internet Control Message Protocol (ICMP) icmp.c */
2:
3: /*
4: Copyright (C) 1992 Bob Harris
5:
6: This program is free software; you can redistribute it and/or modify
7: it under the terms of the GNU General Public License as published by
8: the Free Software Foundation; either version 2, or (at your option)
9: any later version.
10:
11: This program is distributed in the hope that it will be useful,
12: but WITHOUT ANY WARRANTY; without even the implied warranty of
13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: GNU General Public License for more details.
15:
16: You should have received a copy of the GNU General Public License
17: along with this program; if not, write to the Free Software
18: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19:
20: The Author of tcpip package may be reached as [email protected] or
21: C/O Department of Mathematics; Stanford University; Stanford, CA 94305
22:
23: The author of this file may be reached at [email protected] or Sparta, Inc.
24: 7926 Jones Branch Dr. Suite 900, McLean Va 22102.
25: */
26:
27: /* modified by Ross Biro [email protected] to do more than just
28: echo responses. */
29:
30: #include <linux/types.h>
31: #include <linux/sched.h>
32: #include <linux/kernel.h> /* free_s */
33: #include <linux/fcntl.h>
34: #include <linux/socket.h>
35: #include <netinet/in.h>
36: #include "timer.h"
37: #include "ip.h"
38: #include "tcp.h"
39: #include "sock.h"
40: #include <linux/errno.h>
41: #include <linux/timer.h>
42: #include <asm/system.h>
43: #include <asm/segment.h>
44: #include "../kern_sock.h" /* for PRINTK */
45: #include "icmp.h"
46:
47: #define min(a,b) ((a)<(b)?(a):(b))
48:
49: /* an array of errno for error messages from dest unreach. */
50: struct icmp_err icmp_err_convert[]=
51: {
52: {ENETUNREACH, 1},
53: {EHOSTUNREACH, 1},
54: {ENOPROTOOPT, 1},
55: {ECONNREFUSED, 1},
56: {EOPNOTSUPP, 0},
57: {EOPNOTSUPP, 0},
58: {ENETUNREACH, 1},
59: {EHOSTDOWN, 1},
60: {ENONET, 1},
61: {ENETUNREACH, 1},
62: {EHOSTUNREACH, 1},
63: {EOPNOTSUPP, 0},
64: {EOPNOTSUPP, 0}
65: };
66:
67: void
68: print_icmph (struct icmp_header *icmph)
69: {
70: PRINTK (" type = %d, code = %d, checksum = %X\n", icmph->type,
71: icmph->code, icmph->checksum);
72: PRINTK (" gateway = %X\n", icmph->un.gateway);
73: }
74:
75: /* sends an icmp message in response to a packet. */
76: void
77: icmp_reply (struct sk_buff *skb_in, int type, int code, struct device *dev)
78: {
79: struct sk_buff *skb;
80: struct ip_header *iph;
81: int offset;
82: struct icmp_header *icmph;
83:
84: int len;
85: /* get some memory for the replay. */
86: len = sizeof (*skb) + 8 /* amount of header to return. */ +
87: sizeof (struct icmp_header) +
88: 64 /* enough for an ip header. */ +
89: dev->hard_header_len;
90:
91: skb = malloc (len);
92: if (skb == NULL) return;
93:
94: skb->mem_addr = skb;
95: skb->mem_len = len;
96:
97: len -= sizeof (*skb);
98:
99: /* find the ip header. */
100: iph = (struct ip_header *)(skb_in+1);
101: iph = (struct ip_header *)((unsigned char *)iph + dev->hard_header_len);
102:
103: /* Build Layer 2-3 headers for message back to source */
104: offset = ip_build_header( skb, iph->daddr, iph->saddr,
105: &dev, IP_ICMP, NULL, len );
106:
107: if (offset < 0)
108: {
109: skb->sk = NULL;
110: free_skb (skb, FREE_READ);
111: return;
112: }
113:
114: /* Readjust length according to actual IP header size */
115: skb->len = offset + sizeof (struct icmp_header) + 8;
116:
117: icmph = (struct icmp_header *)((unsigned char *)(skb+1) + offset);
118: icmph->type = type;
119: icmph->code = code;
120: icmph->checksum = 0; /* we don't need to compute this. */
121: icmph->un.gateway = 0; /* might as well 0 it. */
122: memcpy (icmph+1, iph+1, 8);
123: /* send it and free it. */
124: ip_queue_xmit (NULL, dev, skb, 1);
125:
126: }
127:
128: /* deals with incoming icmp packets. */
129:
130: int
131: icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
132: unsigned long daddr, unsigned short len,
133: unsigned long saddr, int redo, struct ip_protocol *protocol )
134: {
135: int size, offset;
136: struct icmp_header *icmph, *icmphr;
137: struct sk_buff *skb;
138: unsigned char *buff;
139:
140:
141: /* drop broadcast packets. */
142: if ((daddr & 0xff000000) == 0 || (daddr & 0xff000000) == 0xff000000)
143: {
144: skb1->sk = NULL;
145: free_skb (skb1, FREE_READ);
146: return (0);
147: }
148:
149: buff = skb1->h.raw;
150:
151: icmph = (struct icmp_header *)buff;
152:
153: /* Validate the packet first */
154: if( icmph->checksum )
155: { /* Checksums Enabled? */
156: if( ip_compute_csum( (unsigned char *)icmph, len ) )
157: {
158: /* Failed checksum! */
159: PRINTK("\nICMP ECHO failed checksum!");
160: skb1->sk = NULL;
161: free_skb (skb1, FREE_READ);
162: return (0);
163: }
164: }
165:
166: print_icmph(icmph);
167:
168: /* Parse the ICMP message */
169: switch( icmph->type )
170: {
171: case ICMP_DEST_UNREACH:
172: case ICMP_SOURCE_QUENCH:
173: {
174: struct ip_header *iph;
175: struct ip_protocol *ipprot;
176: unsigned char hash;
177: int err;
178:
179: err = icmph->type << 8 | icmph->code;
180:
181: /* we need to cause the socket to be closed and the error message
182: to be set appropriately. */
183: iph = (struct ip_header *)(icmph+1);
184:
185: /* get the protocol(s) */
186: hash = iph->protocol & (MAX_IP_PROTOS -1 );
187: for (ipprot = ip_protos[hash]; ipprot != NULL; ipprot=ipprot->next)
188: {
189: /* pass it off to everyone who wants it. */
190: ipprot->err_handler (err, (unsigned char *)iph+4*iph->ihl,
191: iph->daddr, iph->saddr, ipprot);
192: }
193: skb1->sk = NULL;
194: free_skb (skb1, FREE_READ);
195: return (0);
196: }
197:
198: case ICMP_REDIRECT:
199: {
200: /* we need to put a new route in the routing table. */
201: struct rtable *rt; /* we will add a new route. */
202: struct ip_header *iph;
203:
204: iph = (struct ip_header *)(icmph+1);
205: rt = malloc (sizeof (*rt));
206: if (rt != NULL)
207: {
208: rt->net = iph->daddr;
209: /* assume class C network. Technically this is incorrect,
210: but will give it a try. */
211: if ((icmph->code & 1) == 0) rt->net &= 0x00ffffff;
212: rt->dev = dev;
213: rt->router = icmph->un.gateway;
214: add_route (rt);
215: }
216: skb1->sk = NULL;
217: free_skb (skb1, FREE_READ);
218: return (0);
219: }
220:
221: case ICMP_ECHO:
222:
223: /* Allocate an sk_buff response buffer (assume 64 byte IP header) */
224:
225: size = sizeof( struct sk_buff ) + dev->hard_header_len + 64 + len;
226: skb = malloc( size );
227: if (skb == NULL)
228: {
229: skb1->sk = NULL;
230: free_skb (skb1, FREE_READ);
231: return (0);
232: }
233: skb->sk = NULL;
234: skb->mem_addr = skb;
235: skb->mem_len = size;
236:
237: /* Build Layer 2-3 headers for message back to source */
238: offset = ip_build_header( skb, daddr, saddr, &dev, IP_ICMP, opt, len );
239: if (offset < 0)
240: {
241: /* Problems building header */
242: PRINTK("\nCould not build IP Header for ICMP ECHO Response");
243: free_s (skb->mem_addr, skb->mem_len);
244: skb1->sk = NULL;
245: free_skb (skb1, FREE_READ);
246: return( 0 ); /* just toss the received packet */
247: }
248:
249: /* Readjust length according to actual IP header size */
250: skb->len = offset + len;
251:
252: /* Build ICMP_ECHO Response message */
253: icmphr = (struct icmp_header *)( (char *)( skb + 1 ) + offset );
254: memcpy( (char *)icmphr, (char *)icmph, len );
255: icmphr->type = ICMP_ECHOREPLY;
256: icmphr->code = 0;
257: icmphr->checksum = 0;
258:
259: if( icmph->checksum )
260: { /* Calculate Checksum */
261: icmphr->checksum = ip_compute_csum( (void *)icmphr, len );
262: }
263:
264: /* Ship it out - free it when done */
265: ip_queue_xmit( (volatile struct sock *)NULL, dev, skb, 1 );
266:
267: skb1->sk = NULL;
268: free_skb (skb1, FREE_READ);
269: return( 0 );
270:
271: default:
272: PRINTK("\nUnsupported ICMP type = x%x", icmph->type );
273: skb1->sk = NULL;
274: free_skb (skb1, FREE_READ);
275: return( 0 ); /* just toss the packet */
276: }
277:
278: /* should be unecessary, but just in case. */
279: skb1->sk = NULL;
280: free_skb (skb1, FREE_READ);
281: return( 0 ); /* just toss the packet */
282: }
283:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.