1 /*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
5 *
6 * Internet Control Message Protocol (ICMP)
7 *
8 * Version: @(#)icmp.c 1.0.11 06/02/93
9 *
10 * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
11 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
12 * Mark Evans, <evansmp@uhura.aston.ac.uk>
13 * Alan Cox, <gw4pts@gw4pts.ampr.org>
14 * Stefan Becker, <stefanb@yello.ping.de>
15 *
16 * Fixes:
17 * Alan Cox : Generic queue usage.
18 * Gerhard Koerting: ICMP addressing corrected
19 * Alan Cox : Use tos/ttl settings
20 * Alan Cox : Protocol violations
21 * Alan Cox : SNMP Statistics
22 * Alan Cox : Routing errors
23 * Alan Cox : Changes for newer routing code
24 * Alan Cox : Removed old debugging junk
25 * Alan Cox : Fixed the ICMP error status of net/host unreachable
26 * Gerhard Koerting : Fixed broadcast ping properly
27 * Ulrich Kunitz : Fixed ICMP timestamp reply
28 * A.N.Kuznetsov : Multihoming fixes.
29 * Laco Rusnak : Multihoming fixes.
30 * Alan Cox : Tightened up icmp_send().
31 * Alan Cox : Multicasts.
32 * Stefan Becker : ICMP redirects in icmp_send().
33 * Peter Belding : Tightened up ICMP redirect handling
34 * Alan Cox : Tightened even more.
35 * Arnt Gulbrandsen: Misplaced #endif with net redirect and break
36 *
37 *
38 *
39 * This program is free software; you can redistribute it and/or
40 * modify it under the terms of the GNU General Public License
41 * as published by the Free Software Foundation; either version
42 * 2 of the License, or (at your option) any later version.
43 */
44 #include <linux/types.h>
45 #include <linux/sched.h>
46 #include <linux/kernel.h>
47 #include <linux/fcntl.h>
48 #include <linux/socket.h>
49 #include <linux/in.h>
50 #include <linux/inet.h>
51 #include <linux/netdevice.h>
52 #include <linux/string.h>
53 #include <net/snmp.h>
54 #include <net/ip.h>
55 #include <net/route.h>
56 #include <net/protocol.h>
57 #include <net/icmp.h>
58 #include <net/tcp.h>
59 #include <net/snmp.h>
60 #include <linux/skbuff.h>
61 #include <net/sock.h>
62 #include <linux/errno.h>
63 #include <linux/timer.h>
64 #include <asm/system.h>
65 #include <asm/segment.h>
66 #include <net/checksum.h>
67
68
69 #define min(a,b) ((a)<(b)?(a):(b))
70
71
72 /*
73 * Statistics
74 */
75
76 struct icmp_mib icmp_statistics={0,};
77
78
79 /* An array of errno for error messages from dest unreach. */
80 struct icmp_err icmp_err_convert[] = {
81 { ENETUNREACH, 0 }, /* ICMP_NET_UNREACH */
82 { EHOSTUNREACH, 0 }, /* ICMP_HOST_UNREACH */
83 { ENOPROTOOPT, 1 }, /* ICMP_PROT_UNREACH */
84 { ECONNREFUSED, 1 }, /* ICMP_PORT_UNREACH */
85 { EOPNOTSUPP, 0 }, /* ICMP_FRAG_NEEDED */
86 { EOPNOTSUPP, 0 }, /* ICMP_SR_FAILED */
87 { ENETUNREACH, 1 }, /* ICMP_NET_UNKNOWN */
88 { EHOSTDOWN, 1 }, /* ICMP_HOST_UNKNOWN */
89 { ENONET, 1 }, /* ICMP_HOST_ISOLATED */
90 { ENETUNREACH, 1 }, /* ICMP_NET_ANO */
91 { EHOSTUNREACH, 1 }, /* ICMP_HOST_ANO */
92 { EOPNOTSUPP, 0 }, /* ICMP_NET_UNR_TOS */
93 { EOPNOTSUPP, 0 } /* ICMP_HOST_UNR_TOS */
94 };
95
96
97 /*
98 * Send an ICMP message in response to a situation
99 */
100
101 void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info, struct device *dev)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
102 {
103 struct sk_buff *skb;
104 struct iphdr *iph;
105 int offset;
106 struct icmphdr *icmph;
107 int len;
108 struct device *ndev=NULL; /* Make this =dev to force replies on the same interface */
109 unsigned long our_addr;
110 int atype;
111
112 /*
113 * Find the original IP header.
114 */
115
116 iph = (struct iphdr *) skb_in->data;
117
118 /*
119 * No replies to MAC multicast
120 */
121
122 if(skb_in->pkt_type!=PACKET_HOST)
123 return;
124
125 /*
126 * No replies to IP multicasting
127 */
128
129 atype=ip_chk_addr(iph->daddr);
130 if(atype==IS_BROADCAST || atype==IS_MULTICAST)
131 return;
132
133 /*
134 * Only reply to first fragment.
135 */
136
137 if(ntohs(iph->frag_off)&IP_OFFSET)
138 return;
139
140 /*
141 * We must NEVER NEVER send an ICMP error to an ICMP error message
142 */
143
144 if(type==ICMP_DEST_UNREACH||type==ICMP_REDIRECT||type==ICMP_SOURCE_QUENCH||type==ICMP_TIME_EXCEEDED)
145 {
146
147 /*
148 * Is the original packet an ICMP packet?
149 */
150
151 if(iph->protocol==IPPROTO_ICMP)
152 {
153 icmph = (struct icmphdr *) ((char *) iph +
154 4 * iph->ihl);
155 /*
156 * Check for ICMP error packets (Must never reply to
157 * an ICMP error).
158 */
159
160 if (icmph->type == ICMP_DEST_UNREACH ||
161 icmph->type == ICMP_SOURCE_QUENCH ||
162 icmph->type == ICMP_REDIRECT ||
163 icmph->type == ICMP_TIME_EXCEEDED ||
164 icmph->type == ICMP_PARAMETERPROB)
165 return;
166 }
167 }
168 icmp_statistics.IcmpOutMsgs++;
169
170 /*
171 * This needs a tidy.
172 */
173
174 switch(type)
175 {
176 case ICMP_DEST_UNREACH:
177 icmp_statistics.IcmpOutDestUnreachs++;
178 break;
179 case ICMP_SOURCE_QUENCH:
180 icmp_statistics.IcmpOutSrcQuenchs++;
181 break;
182 case ICMP_REDIRECT:
183 icmp_statistics.IcmpOutRedirects++;
184 break;
185 case ICMP_ECHO:
186 icmp_statistics.IcmpOutEchos++;
187 break;
188 case ICMP_ECHOREPLY:
189 icmp_statistics.IcmpOutEchoReps++;
190 break;
191 case ICMP_TIME_EXCEEDED:
192 icmp_statistics.IcmpOutTimeExcds++;
193 break;
194 case ICMP_PARAMETERPROB:
195 icmp_statistics.IcmpOutParmProbs++;
196 break;
197 case ICMP_TIMESTAMP:
198 icmp_statistics.IcmpOutTimestamps++;
199 break;
200 case ICMP_TIMESTAMPREPLY:
201 icmp_statistics.IcmpOutTimestampReps++;
202 break;
203 case ICMP_ADDRESS:
204 icmp_statistics.IcmpOutAddrMasks++;
205 break;
206 case ICMP_ADDRESSREPLY:
207 icmp_statistics.IcmpOutAddrMaskReps++;
208 break;
209 }
210 /*
211 * Get some memory for the reply.
212 */
213
214 len = dev->hard_header_len + sizeof(struct iphdr) + sizeof(struct icmphdr) +
215 sizeof(struct iphdr) + 32; /* amount of header to return */
216
217 skb = (struct sk_buff *) alloc_skb(len+15, GFP_ATOMIC);
218 if (skb == NULL)
219 {
220 icmp_statistics.IcmpOutErrors++;
221 return;
222 }
223 skb->free = 1;
224
225 /*
226 * Build Layer 2-3 headers for message back to source.
227 */
228
229 our_addr = dev->pa_addr;
230 if (iph->daddr != our_addr && ip_chk_addr(iph->daddr) == IS_MYADDR)
231 our_addr = iph->daddr;
232 offset = ip_build_header(skb, our_addr, iph->saddr,
233 &ndev, IPPROTO_ICMP, NULL, len,
234 skb_in->ip_hdr->tos,255);
235 if (offset < 0)
236 {
237 icmp_statistics.IcmpOutErrors++;
238 skb->sk = NULL;
239 kfree_skb(skb, FREE_READ);
240 return;
241 }
242
243 /*
244 * Re-adjust length according to actual IP header size.
245 */
246
247 skb_put(skb,sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
248
249 /*
250 * Fill in the frame
251 */
252
253 icmph = (struct icmphdr *) (skb->data + offset);
254 icmph->type = type;
255 icmph->code = code;
256 icmph->checksum = 0;
257 icmph->un.gateway = info; /* This might not be meant for
258 this form of the union but it will
259 be right anyway */
260 memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
261
262 icmph->checksum = ip_compute_csum((unsigned char *)icmph,
263 sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
264
265 /*
266 * Send it and free it once sent.
267 */
268 ip_queue_xmit(NULL, ndev, skb, 1);
269 }
270
271
272 /*
273 * Handle ICMP_UNREACH and ICMP_QUENCH.
274 */
275
276 static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
277 {
278 struct inet_protocol *ipprot;
279 struct iphdr *iph;
280 unsigned char hash;
281 int err;
282
283 err = (icmph->type << 8) | icmph->code;
284 iph = (struct iphdr *) (icmph + 1);
285
286 switch(icmph->code & 7)
287 {
288 case ICMP_NET_UNREACH:
289 break;
290 case ICMP_HOST_UNREACH:
291 break;
292 case ICMP_PROT_UNREACH:
293 #ifdef CONFIG_NET_DEBUG
294 printk("ICMP: %s:%d: protocol unreachable.\n",
295 in_ntoa(iph->daddr), ntohs(iph->protocol));
296 #endif
297 break;
298 case ICMP_PORT_UNREACH:
299 break;
300 case ICMP_FRAG_NEEDED:
301 #ifdef CONFIG_NET_DEBUG
302 printk("ICMP: %s: fragmentation needed and DF set.\n",
303 in_ntoa(iph->daddr));
304 #endif
305 break;
306 case ICMP_SR_FAILED:
307 #ifdef CONFIG_NET_DEBUG
308 printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
309 #endif
310 break;
311 default:
312 break;
313 }
314
315 /*
316 * Get the protocol(s).
317 */
318
319 hash = iph->protocol & (MAX_INET_PROTOS -1);
320
321 /*
322 * This can't change while we are doing it.
323 */
324
325 ipprot = (struct inet_protocol *) inet_protos[hash];
326 while(ipprot != NULL)
327 {
328 struct inet_protocol *nextip;
329
330 nextip = (struct inet_protocol *) ipprot->next;
331
332 /*
333 * Pass it off to everyone who wants it.
334 */
335 if (iph->protocol == ipprot->protocol && ipprot->err_handler)
336 {
337 ipprot->err_handler(err, (unsigned char *)(icmph + 1),
338 iph->daddr, iph->saddr, ipprot);
339 }
340
341 ipprot = nextip;
342 }
343 kfree_skb(skb, FREE_READ);
344 }
345
346
347 /*
348 * Handle ICMP_REDIRECT.
349 */
350
351 static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
352 struct device *dev, unsigned long source)
353 {
354 #ifndef CONFIG_IP_FORWARD
355 struct rtable *rt;
356 #endif
357 struct iphdr *iph;
358 unsigned long ip;
359
360 /*
361 * Get the copied header of the packet that caused the redirect
362 */
363
364 iph = (struct iphdr *) (icmph + 1);
365 ip = iph->daddr;
366
367 #ifdef CONFIG_IP_FORWARD
368 /*
369 * We are a router. Routers should not respond to ICMP_REDIRECT messages.
370 */
371 printk("icmp: ICMP redirect from %s on %s ignored.\n", in_ntoa(source), dev->name);
372 #else
373 switch(icmph->code & 7)
374 {
375 case ICMP_REDIR_NET:
376 /*
377 * This causes a problem with subnetted networks. What we should do
378 * is use ICMP_ADDRESS to get the subnet mask of the problem route
379 * and set both. But we don't..
380 */
381 #ifdef not_a_good_idea
382 ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
383 ip, 0, icmph->un.gateway, dev,0, 0, 0);
384 #endif
385 break;
386 case ICMP_REDIR_HOST:
387 /*
388 * Add better route to host.
389 * But first check that the redirect
390 * comes from the old gateway..
391 * And make sure it's an ok host address
392 * (not some confused thing sending our
393 * address)
394 */
395 rt = ip_rt_route(ip, NULL, NULL);
396 if (!rt)
397 break;
398 if (rt->rt_gateway != source ||
399 ((icmph->un.gateway^dev->pa_addr)&dev->pa_mask) ||
400 ip_chk_addr(icmph->un.gateway))
401 break;
402 printk("ICMP redirect from %s\n", in_ntoa(source));
403 ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
404 ip, 0, icmph->un.gateway, dev,0, 0, 0, 0);
405 break;
406 case ICMP_REDIR_NETTOS:
407 case ICMP_REDIR_HOSTTOS:
408 printk("ICMP: cannot handle TOS redirects yet!\n");
409 break;
410 default:
411 break;
412 }
413 #endif
414 /*
415 * Discard the original packet
416 */
417
418 kfree_skb(skb, FREE_READ);
419 }
420
421
422 /*
423 * Handle ICMP_ECHO ("ping") requests.
424 */
425
426 static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
427 unsigned long saddr, unsigned long daddr, int len,
428 struct options *opt)
429 {
430 struct icmphdr *icmphr;
431 struct sk_buff *skb2;
432 struct device *ndev=NULL;
433 int size, offset;
434
435 icmp_statistics.IcmpOutEchoReps++;
436 icmp_statistics.IcmpOutMsgs++;
437
438 size = dev->hard_header_len + 64 + len + 15;
439 skb2 = alloc_skb(size, GFP_ATOMIC);
440
441 if (skb2 == NULL)
442 {
443 icmp_statistics.IcmpOutErrors++;
444 kfree_skb(skb, FREE_READ);
445 return;
446 }
447 skb2->free = 1;
448
449 /* Build Layer 2-3 headers for message back to source */
450 offset = ip_build_header(skb2, daddr, saddr, &ndev,
451 IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
452 if (offset < 0)
453 {
454 icmp_statistics.IcmpOutErrors++;
455 printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
456 kfree_skb(skb2,FREE_WRITE);
457 kfree_skb(skb, FREE_READ);
458 return;
459 }
460
461 /*
462 * Re-adjust length according to actual IP header size.
463 */
464
465 skb_put(skb2,len);
466
467 /*
468 * Build ICMP_ECHO Response message.
469 */
470 icmphr = (struct icmphdr *) (skb2->data + offset);
471 memcpy((char *) icmphr, (char *) icmph, len);
472 icmphr->type = ICMP_ECHOREPLY;
473 icmphr->code = 0;
474 icmphr->checksum = 0;
475 icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
476
477 /*
478 * Ship it out - free it when done
479 */
480 ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
481
482 /*
483 * Free the received frame
484 */
485
486 kfree_skb(skb, FREE_READ);
487 }
488
489 /*
490 * Handle ICMP Timestamp requests.
491 */
492
493 static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
494 unsigned long saddr, unsigned long daddr, int len,
495 struct options *opt)
496 {
497 struct icmphdr *icmphr;
498 struct sk_buff *skb2;
499 int size, offset;
500 unsigned long *timeptr, midtime;
501 struct device *ndev=NULL;
502
503 if (len < 12)
504 {
505 printk(
506 "ICMP: Size (%d) of ICMP_TIMESTAMP request should be 20!\n",
507 len);
508 icmp_statistics.IcmpInErrors++;
509 /* correct answers are possible for everything >= 12 */
510 }
511
512 size = dev->hard_header_len + 84 + 15;
513
514 if (! (skb2 = alloc_skb(size, GFP_ATOMIC)))
515 {
516 skb->sk = NULL;
517 kfree_skb(skb, FREE_READ);
518 icmp_statistics.IcmpOutErrors++;
519 return;
520 }
521 skb2->free = 1;
522
523 /*
524 * Build Layer 2-3 headers for message back to source
525 */
526
527 offset = ip_build_header(skb2, daddr, saddr, &ndev, IPPROTO_ICMP, opt, len,
528 skb->ip_hdr->tos, 255);
529 if (offset < 0)
530 {
531 printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n");
532 kfree_skb(skb2, FREE_WRITE);
533 kfree_skb(skb, FREE_READ);
534 icmp_statistics.IcmpOutErrors++;
535 return;
536 }
537
538 /*
539 * Re-adjust length according to actual IP header size.
540 */
541 skb_put(skb2,20);
542
543 /*
544 * Build ICMP_TIMESTAMP Response message.
545 */
546
547 icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
548 memcpy((char *) icmphr, (char *) icmph, 12);
549 icmphr->type = ICMP_TIMESTAMPREPLY;
550 icmphr->code = icmphr->checksum = 0;
551
552 /* fill in the current time as ms since midnight UT: */
553 midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000;
554 timeptr = (unsigned long *) (icmphr + 1);
555 /*
556 * the originate timestamp (timeptr [0]) is still in the copy:
557 */
558 timeptr [1] = timeptr [2] = htonl(midtime);
559
560 icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, 20);
561
562 /*
563 * Ship it out - free it when done
564 */
565
566 ip_queue_xmit((struct sock *) NULL, ndev, skb2, 1);
567 icmp_statistics.IcmpOutTimestampReps++;
568 kfree_skb(skb, FREE_READ);
569 }
570
571
572
573
574 /*
575 * Handle the ICMP INFORMATION REQUEST.
576 */
577
578 static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
579 unsigned long saddr, unsigned long daddr, int len,
580 struct options *opt)
581 {
582 /* Obsolete */
583 kfree_skb(skb, FREE_READ);
584 }
585
586
587 /*
588 * Handle ICMP_ADDRESS_MASK requests.
589 */
590
591 static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
592 unsigned long saddr, unsigned long daddr, int len,
593 struct options *opt)
594 {
595 struct icmphdr *icmphr;
596 struct sk_buff *skb2;
597 int size, offset;
598 struct device *ndev=NULL;
599
600 icmp_statistics.IcmpOutMsgs++;
601 icmp_statistics.IcmpOutAddrMaskReps++;
602
603 size = dev->hard_header_len + 64 + len + 15;
604 skb2 = alloc_skb(size, GFP_ATOMIC);
605 if (skb2 == NULL)
606 {
607 icmp_statistics.IcmpOutErrors++;
608 kfree_skb(skb, FREE_READ);
609 return;
610 }
611 skb2->free = 1;
612
613 /*
614 * Build Layer 2-3 headers for message back to source
615 */
616
617 offset = ip_build_header(skb2, daddr, saddr, &ndev,
618 IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
619 if (offset < 0)
620 {
621 icmp_statistics.IcmpOutErrors++;
622 printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
623 kfree_skb(skb2,FREE_WRITE);
624 kfree_skb(skb, FREE_READ);
625 return;
626 }
627
628 /*
629 * Re-adjust length according to actual IP header size.
630 */
631
632 skb_put(skb2,len);
633
634 /*
635 * Build ICMP ADDRESS MASK Response message.
636 */
637
638 icmphr = (struct icmphdr *) (skb2->data + offset);
639 icmphr->type = ICMP_ADDRESSREPLY;
640 icmphr->code = 0;
641 icmphr->checksum = 0;
642 icmphr->un.echo.id = icmph->un.echo.id;
643 icmphr->un.echo.sequence = icmph->un.echo.sequence;
644 memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
645
646 icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
647
648 /* Ship it out - free it when done */
649 ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
650
651 skb->sk = NULL;
652 kfree_skb(skb, FREE_READ);
653 }
654
655
656 /*
657 * Deal with incoming ICMP packets.
658 */
659
660 int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
661 unsigned long daddr, unsigned short len,
662 unsigned long saddr, int redo, struct inet_protocol *protocol)
663 {
664 struct icmphdr *icmph;
665 unsigned char *buff;
666
667 /*
668 * Drop broadcast packets. IP has done a broadcast check and ought one day
669 * to pass on that information.
670 */
671
672 icmp_statistics.IcmpInMsgs++;
673
674
675 /*
676 * Grab the packet as an icmp object
677 */
678
679 buff = skb1->h.raw;
680 icmph = (struct icmphdr *) buff;
681
682 /*
683 * Validate the packet first
684 */
685
686 if (ip_compute_csum((unsigned char *) icmph, len))
687 {
688 /* Failed checksum! */
689 icmp_statistics.IcmpInErrors++;
690 printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
691 kfree_skb(skb1, FREE_READ);
692 return(0);
693 }
694
695 /*
696 * Parse the ICMP message
697 */
698
699 if (ip_chk_addr(daddr) != IS_MYADDR)
700 {
701 if (icmph->type != ICMP_ECHO)
702 {
703 icmp_statistics.IcmpInErrors++;
704 kfree_skb(skb1, FREE_READ);
705 return(0);
706 }
707 daddr=dev->pa_addr;
708 }
709
710 switch(icmph->type)
711 {
712 case ICMP_TIME_EXCEEDED:
713 icmp_statistics.IcmpInTimeExcds++;
714 icmp_unreach(icmph, skb1);
715 return 0;
716 case ICMP_DEST_UNREACH:
717 icmp_statistics.IcmpInDestUnreachs++;
718 icmp_unreach(icmph, skb1);
719 return 0;
720 case ICMP_SOURCE_QUENCH:
721 icmp_statistics.IcmpInSrcQuenchs++;
722 icmp_unreach(icmph, skb1);
723 return(0);
724 case ICMP_REDIRECT:
725 icmp_statistics.IcmpInRedirects++;
726 icmp_redirect(icmph, skb1, dev, saddr);
727 return(0);
728 case ICMP_ECHO:
729 icmp_statistics.IcmpInEchos++;
730 icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
731 return 0;
732 case ICMP_ECHOREPLY:
733 icmp_statistics.IcmpInEchoReps++;
734 kfree_skb(skb1, FREE_READ);
735 return(0);
736 case ICMP_TIMESTAMP:
737 icmp_statistics.IcmpInTimestamps++;
738 icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt);
739 return 0;
740 case ICMP_TIMESTAMPREPLY:
741 icmp_statistics.IcmpInTimestampReps++;
742 kfree_skb(skb1,FREE_READ);
743 return 0;
744 /* INFO is obsolete and doesn't even feature in the SNMP stats */
745 case ICMP_INFO_REQUEST:
746 icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
747 return 0;
748 case ICMP_INFO_REPLY:
749 skb1->sk = NULL;
750 kfree_skb(skb1, FREE_READ);
751 return(0);
752 case ICMP_ADDRESS:
753 icmp_statistics.IcmpInAddrMasks++;
754 icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
755 return 0;
756 case ICMP_ADDRESSREPLY:
757 /*
758 * We ought to set our netmask on receiving this, but
759 * experience shows it's a waste of effort.
760 */
761 icmp_statistics.IcmpInAddrMaskReps++;
762 kfree_skb(skb1, FREE_READ);
763 return(0);
764 default:
765 icmp_statistics.IcmpInErrors++;
766 kfree_skb(skb1, FREE_READ);
767 return(0);
768 }
769 /*NOTREACHED*/
770 kfree_skb(skb1, FREE_READ);
771 return(-1);
772 }
773
774
775 /*
776 * Perform any ICMP-related I/O control requests.
777 * [to vanish soon]
778 */
779
780 int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
781 {
782 switch(cmd)
783 {
784 default:
785 return(-EINVAL);
786 }
787 return(0);
788 }