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