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