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