This source file includes following definitions.
- icmp_send
- icmp_unreach
- icmp_redirect
- icmp_echo
- icmp_timestamp
- icmp_info
- icmp_address
- icmp_rcv
- icmp_ioctl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 #include <linux/types.h>
42 #include <linux/sched.h>
43 #include <linux/kernel.h>
44 #include <linux/fcntl.h>
45 #include <linux/socket.h>
46 #include <linux/in.h>
47 #include <linux/inet.h>
48 #include <linux/netdevice.h>
49 #include <linux/string.h>
50 #include "snmp.h"
51 #include "ip.h"
52 #include "route.h"
53 #include "protocol.h"
54 #include "icmp.h"
55 #include "tcp.h"
56 #include "snmp.h"
57 #include <linux/skbuff.h>
58 #include "sock.h"
59 #include <linux/errno.h>
60 #include <linux/timer.h>
61 #include <asm/system.h>
62 #include <asm/segment.h>
63
64
65 #define min(a,b) ((a)<(b)?(a):(b))
66
67
68
69
70
71
72 struct icmp_mib icmp_statistics={0,};
73
74
75
76 struct icmp_err icmp_err_convert[] = {
77 { ENETUNREACH, 0 },
78 { EHOSTUNREACH, 0 },
79 { ENOPROTOOPT, 1 },
80 { ECONNREFUSED, 1 },
81 { EOPNOTSUPP, 0 },
82 { EOPNOTSUPP, 0 },
83 { ENETUNREACH, 1 },
84 { EHOSTDOWN, 1 },
85 { ENONET, 1 },
86 { ENETUNREACH, 1 },
87 { EHOSTUNREACH, 1 },
88 { EOPNOTSUPP, 0 },
89 { EOPNOTSUPP, 0 }
90 };
91
92
93
94
95
96
97
98
99 void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info, struct device *dev)
100 {
101 struct sk_buff *skb;
102 struct iphdr *iph;
103 int offset;
104 struct icmphdr *icmph;
105 int len;
106 struct device *ndev=NULL;
107 unsigned long our_addr;
108 int atype;
109
110
111
112
113
114 iph = (struct iphdr *) (skb_in->data + dev->hard_header_len);
115
116
117
118
119
120 if(skb_in->pkt_type!=PACKET_HOST)
121 return;
122
123
124
125
126
127 atype=ip_chk_addr(iph->daddr);
128 if(atype==IS_BROADCAST || IN_MULTICAST(iph->daddr))
129 return;
130
131
132
133
134
135 if(ntohs(iph->frag_off)&IP_OFFSET)
136 return;
137
138
139
140
141
142 if(type==ICMP_DEST_UNREACH||type==ICMP_REDIRECT||type==ICMP_SOURCE_QUENCH||type==ICMP_TIME_EXCEEDED)
143 {
144
145
146
147
148
149 if(iph->protocol==IPPROTO_ICMP)
150 {
151 icmph = (struct icmphdr *) ((char *) iph +
152 4 * iph->ihl);
153
154
155
156
157
158 if (icmph->type == ICMP_DEST_UNREACH ||
159 icmph->type == ICMP_SOURCE_QUENCH ||
160 icmph->type == ICMP_REDIRECT ||
161 icmph->type == ICMP_TIME_EXCEEDED ||
162 icmph->type == ICMP_PARAMETERPROB)
163 return;
164 }
165
166 return;
167
168 }
169 icmp_statistics.IcmpOutMsgs++;
170
171
172
173
174
175 switch(type)
176 {
177 case ICMP_DEST_UNREACH:
178 icmp_statistics.IcmpOutDestUnreachs++;
179 break;
180 case ICMP_SOURCE_QUENCH:
181 icmp_statistics.IcmpOutSrcQuenchs++;
182 break;
183 case ICMP_REDIRECT:
184 icmp_statistics.IcmpOutRedirects++;
185 break;
186 case ICMP_ECHO:
187 icmp_statistics.IcmpOutEchos++;
188 break;
189 case ICMP_ECHOREPLY:
190 icmp_statistics.IcmpOutEchoReps++;
191 break;
192 case ICMP_TIME_EXCEEDED:
193 icmp_statistics.IcmpOutTimeExcds++;
194 break;
195 case ICMP_PARAMETERPROB:
196 icmp_statistics.IcmpOutParmProbs++;
197 break;
198 case ICMP_TIMESTAMP:
199 icmp_statistics.IcmpOutTimestamps++;
200 break;
201 case ICMP_TIMESTAMPREPLY:
202 icmp_statistics.IcmpOutTimestampReps++;
203 break;
204 case ICMP_ADDRESS:
205 icmp_statistics.IcmpOutAddrMasks++;
206 break;
207 case ICMP_ADDRESSREPLY:
208 icmp_statistics.IcmpOutAddrMaskReps++;
209 break;
210 }
211
212
213
214
215 len = dev->hard_header_len + sizeof(struct iphdr) + sizeof(struct icmphdr) +
216 sizeof(struct iphdr) + 8;
217
218 skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);
219 if (skb == NULL)
220 {
221 icmp_statistics.IcmpOutErrors++;
222 return;
223 }
224 skb->free = 1;
225
226
227
228
229
230 our_addr = dev->pa_addr;
231 if (iph->daddr != our_addr && ip_chk_addr(iph->daddr) == IS_MYADDR)
232 our_addr = iph->daddr;
233 offset = ip_build_header(skb, our_addr, iph->saddr,
234 &ndev, IPPROTO_ICMP, NULL, len,
235 skb_in->ip_hdr->tos,255);
236 if (offset < 0)
237 {
238 icmp_statistics.IcmpOutErrors++;
239 skb->sk = NULL;
240 kfree_skb(skb, FREE_READ);
241 return;
242 }
243
244
245
246
247
248 skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;
249
250
251
252
253
254 icmph = (struct icmphdr *) (skb->data + offset);
255 icmph->type = type;
256 icmph->code = code;
257 icmph->checksum = 0;
258 icmph->un.gateway = info;
259
260
261 memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
262
263 icmph->checksum = ip_compute_csum((unsigned char *)icmph,
264 sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
265
266
267
268
269 ip_queue_xmit(NULL, ndev, skb, 1);
270 }
271
272
273
274
275
276
277 static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
278 {
279 struct inet_protocol *ipprot;
280 struct iphdr *iph;
281 unsigned char hash;
282 int err;
283
284 err = (icmph->type << 8) | icmph->code;
285 iph = (struct iphdr *) (icmph + 1);
286
287 switch(icmph->code & 7)
288 {
289 case ICMP_NET_UNREACH:
290 break;
291 case ICMP_HOST_UNREACH:
292 break;
293 case ICMP_PROT_UNREACH:
294 printk("ICMP: %s:%d: protocol unreachable.\n",
295 in_ntoa(iph->daddr), ntohs(iph->protocol));
296 break;
297 case ICMP_PORT_UNREACH:
298 break;
299 case ICMP_FRAG_NEEDED:
300 printk("ICMP: %s: fragmentation needed and DF set.\n",
301 in_ntoa(iph->daddr));
302 break;
303 case ICMP_SR_FAILED:
304 printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
305 break;
306 default:
307 break;
308 }
309
310
311
312
313
314 hash = iph->protocol & (MAX_INET_PROTOS -1);
315
316
317
318
319
320 ipprot = (struct inet_protocol *) inet_protos[hash];
321 while(ipprot != NULL)
322 {
323 struct inet_protocol *nextip;
324
325 nextip = (struct inet_protocol *) ipprot->next;
326
327
328
329
330 if (iph->protocol == ipprot->protocol && ipprot->err_handler)
331 {
332 ipprot->err_handler(err, (unsigned char *)(icmph + 1),
333 iph->daddr, iph->saddr, ipprot);
334 }
335
336 ipprot = nextip;
337 }
338 kfree_skb(skb, FREE_READ);
339 }
340
341
342
343
344
345
346 static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb,
347 struct device *dev, unsigned long source)
348 {
349 struct rtable *rt;
350 struct iphdr *iph;
351 unsigned long ip;
352
353
354
355
356
357 iph = (struct iphdr *) (icmph + 1);
358 ip = iph->daddr;
359
360 switch(icmph->code & 7)
361 {
362 case ICMP_REDIR_NET:
363
364
365
366
367
368 #ifdef not_a_good_idea
369 ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
370 ip, 0, icmph->un.gateway, dev,0, 0);
371 break;
372 #endif
373 case ICMP_REDIR_HOST:
374
375
376
377
378
379 rt = ip_rt_route(ip, NULL, NULL);
380 if (!rt)
381 break;
382 if (rt->rt_gateway != source)
383 break;
384 printk("redirect from %s\n", in_ntoa(source));
385 ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
386 ip, 0, icmph->un.gateway, dev,0, 0);
387 break;
388 case ICMP_REDIR_NETTOS:
389 case ICMP_REDIR_HOSTTOS:
390 printk("ICMP: cannot handle TOS redirects yet!\n");
391 break;
392 default:
393 break;
394 }
395
396
397
398
399
400 kfree_skb(skb, FREE_READ);
401 }
402
403
404
405
406
407
408 static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
409 unsigned long saddr, unsigned long daddr, int len,
410 struct options *opt)
411 {
412 struct icmphdr *icmphr;
413 struct sk_buff *skb2;
414 struct device *ndev=NULL;
415 int size, offset;
416
417 icmp_statistics.IcmpOutEchoReps++;
418 icmp_statistics.IcmpOutMsgs++;
419
420 size = dev->hard_header_len + 64 + len;
421 skb2 = alloc_skb(size, GFP_ATOMIC);
422
423 if (skb2 == NULL)
424 {
425 icmp_statistics.IcmpOutErrors++;
426 kfree_skb(skb, FREE_READ);
427 return;
428 }
429 skb2->free = 1;
430
431
432 offset = ip_build_header(skb2, daddr, saddr, &ndev,
433 IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
434 if (offset < 0)
435 {
436 icmp_statistics.IcmpOutErrors++;
437 printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
438 kfree_skb(skb2,FREE_WRITE);
439 kfree_skb(skb, FREE_READ);
440 return;
441 }
442
443
444
445
446
447 skb2->len = offset + len;
448
449
450
451
452 icmphr = (struct icmphdr *) (skb2->data + offset);
453 memcpy((char *) icmphr, (char *) icmph, len);
454 icmphr->type = ICMP_ECHOREPLY;
455 icmphr->code = 0;
456 icmphr->checksum = 0;
457 icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
458
459
460
461
462 ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
463
464
465
466
467
468 kfree_skb(skb, FREE_READ);
469 }
470
471
472
473
474
475 static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
476 unsigned long saddr, unsigned long daddr, int len,
477 struct options *opt)
478 {
479 struct icmphdr *icmphr;
480 struct sk_buff *skb2;
481 int size, offset;
482 unsigned long *timeptr, midtime;
483 struct device *ndev=NULL;
484
485 if (len != 20)
486 {
487 printk(
488 "ICMP: Size (%d) of ICMP_TIMESTAMP request should be 20!\n",
489 len);
490 icmp_statistics.IcmpInErrors++;
491 #if 1
492
493 if (len < 12)
494 #endif
495 return;
496 }
497
498 size = dev->hard_header_len + 84;
499
500 if (! (skb2 = alloc_skb(size, GFP_ATOMIC)))
501 {
502 skb->sk = NULL;
503 kfree_skb(skb, FREE_READ);
504 icmp_statistics.IcmpOutErrors++;
505 return;
506 }
507 skb2->free = 1;
508
509
510
511
512
513 offset = ip_build_header(skb2, daddr, saddr, &ndev, IPPROTO_ICMP, opt, len,
514 skb->ip_hdr->tos, 255);
515 if (offset < 0)
516 {
517 printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n");
518 kfree_skb(skb2, FREE_WRITE);
519 kfree_skb(skb, FREE_READ);
520 icmp_statistics.IcmpOutErrors++;
521 return;
522 }
523
524
525
526
527 skb2->len = offset + 20;
528
529
530
531
532
533 icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
534 memcpy((char *) icmphr, (char *) icmph, 12);
535 icmphr->type = ICMP_TIMESTAMPREPLY;
536 icmphr->code = icmphr->checksum = 0;
537
538
539 midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000;
540 timeptr = (unsigned long *) (icmphr + 1);
541
542
543
544 timeptr [1] = timeptr [2] = htonl(midtime);
545
546 icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, 20);
547
548
549
550
551
552 ip_queue_xmit((struct sock *) NULL, ndev, skb2, 1);
553 icmp_statistics.IcmpOutTimestampReps++;
554 kfree_skb(skb, FREE_READ);
555 }
556
557
558
559
560
561
562
563
564 static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
565 unsigned long saddr, unsigned long daddr, int len,
566 struct options *opt)
567 {
568
569 kfree_skb(skb, FREE_READ);
570 }
571
572
573
574
575
576
577 static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
578 unsigned long saddr, unsigned long daddr, int len,
579 struct options *opt)
580 {
581 struct icmphdr *icmphr;
582 struct sk_buff *skb2;
583 int size, offset;
584 struct device *ndev=NULL;
585
586 icmp_statistics.IcmpOutMsgs++;
587 icmp_statistics.IcmpOutAddrMaskReps++;
588
589 size = dev->hard_header_len + 64 + len;
590 skb2 = alloc_skb(size, GFP_ATOMIC);
591 if (skb2 == NULL)
592 {
593 icmp_statistics.IcmpOutErrors++;
594 kfree_skb(skb, FREE_READ);
595 return;
596 }
597 skb2->free = 1;
598
599
600
601
602
603 offset = ip_build_header(skb2, daddr, saddr, &ndev,
604 IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
605 if (offset < 0)
606 {
607 icmp_statistics.IcmpOutErrors++;
608 printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
609 kfree_skb(skb2,FREE_WRITE);
610 kfree_skb(skb, FREE_READ);
611 return;
612 }
613
614
615
616
617
618 skb2->len = offset + len;
619
620
621
622
623
624 icmphr = (struct icmphdr *) (skb2->data + offset);
625 icmphr->type = ICMP_ADDRESSREPLY;
626 icmphr->code = 0;
627 icmphr->checksum = 0;
628 icmphr->un.echo.id = icmph->un.echo.id;
629 icmphr->un.echo.sequence = icmph->un.echo.sequence;
630 memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
631
632 icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
633
634
635 ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
636
637 skb->sk = NULL;
638 kfree_skb(skb, FREE_READ);
639 }
640
641
642
643
644
645
646 int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
647 unsigned long daddr, unsigned short len,
648 unsigned long saddr, int redo, struct inet_protocol *protocol)
649 {
650 struct icmphdr *icmph;
651 unsigned char *buff;
652
653
654
655
656
657
658 icmp_statistics.IcmpInMsgs++;
659
660
661
662
663
664
665 buff = skb1->h.raw;
666 icmph = (struct icmphdr *) buff;
667
668
669
670
671
672 if (ip_compute_csum((unsigned char *) icmph, len))
673 {
674
675 icmp_statistics.IcmpInErrors++;
676 printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
677 kfree_skb(skb1, FREE_READ);
678 return(0);
679 }
680
681
682
683
684
685 if (ip_chk_addr(daddr) != IS_MYADDR)
686 {
687 if (icmph->type != ICMP_ECHO)
688 {
689 icmp_statistics.IcmpInErrors++;
690 kfree_skb(skb1, FREE_READ);
691 return(0);
692 }
693 daddr=dev->pa_addr;
694 }
695
696 switch(icmph->type)
697 {
698 case ICMP_TIME_EXCEEDED:
699 icmp_statistics.IcmpInTimeExcds++;
700 icmp_unreach(icmph, skb1);
701 return 0;
702 case ICMP_DEST_UNREACH:
703 icmp_statistics.IcmpInDestUnreachs++;
704 icmp_unreach(icmph, skb1);
705 return 0;
706 case ICMP_SOURCE_QUENCH:
707 icmp_statistics.IcmpInSrcQuenchs++;
708 icmp_unreach(icmph, skb1);
709 return(0);
710 case ICMP_REDIRECT:
711 icmp_statistics.IcmpInRedirects++;
712 icmp_redirect(icmph, skb1, dev, saddr);
713 return(0);
714 case ICMP_ECHO:
715 icmp_statistics.IcmpInEchos++;
716 icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
717 return 0;
718 case ICMP_ECHOREPLY:
719 icmp_statistics.IcmpInEchoReps++;
720 kfree_skb(skb1, FREE_READ);
721 return(0);
722 case ICMP_TIMESTAMP:
723 icmp_statistics.IcmpInTimestamps++;
724 icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt);
725 return 0;
726 case ICMP_TIMESTAMPREPLY:
727 icmp_statistics.IcmpInTimestampReps++;
728 kfree_skb(skb1,FREE_READ);
729 return 0;
730
731 case ICMP_INFO_REQUEST:
732 icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
733 return 0;
734 case ICMP_INFO_REPLY:
735 skb1->sk = NULL;
736 kfree_skb(skb1, FREE_READ);
737 return(0);
738 case ICMP_ADDRESS:
739 icmp_statistics.IcmpInAddrMasks++;
740 icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
741 return 0;
742 case ICMP_ADDRESSREPLY:
743
744
745
746
747 icmp_statistics.IcmpInAddrMaskReps++;
748 kfree_skb(skb1, FREE_READ);
749 return(0);
750 default:
751 icmp_statistics.IcmpInErrors++;
752 kfree_skb(skb1, FREE_READ);
753 return(0);
754 }
755
756 kfree_skb(skb1, FREE_READ);
757 return(-1);
758 }
759
760
761
762
763
764
765
766 int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
767 {
768 switch(cmd)
769 {
770 default:
771 return(-EINVAL);
772 }
773 return(0);
774 }