This source file includes following definitions.
- print_icmp
- icmp_send
- icmp_unreach
- icmp_redirect
- icmp_echo
- 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 #include <linux/types.h>
24 #include <linux/sched.h>
25 #include <linux/kernel.h>
26 #include <linux/fcntl.h>
27 #include <linux/socket.h>
28 #include <linux/in.h>
29 #include "inet.h"
30 #include "dev.h"
31 #include "ip.h"
32 #include "route.h"
33 #include "protocol.h"
34 #include "icmp.h"
35 #include "tcp.h"
36 #include "skbuff.h"
37 #include "sock.h"
38 #include <linux/errno.h>
39 #include <linux/timer.h>
40 #include <asm/system.h>
41 #include <asm/segment.h>
42
43
44 #define min(a,b) ((a)<(b)?(a):(b))
45
46
47
48 struct icmp_err icmp_err_convert[] = {
49 { ENETUNREACH, 1 },
50 { EHOSTUNREACH, 1 },
51 { ENOPROTOOPT, 1 },
52 { ECONNREFUSED, 1 },
53 { EOPNOTSUPP, 0 },
54 { EOPNOTSUPP, 0 },
55 { ENETUNREACH, 1 },
56 { EHOSTDOWN, 1 },
57 { ENONET, 1 },
58 { ENETUNREACH, 1 },
59 { EHOSTUNREACH, 1 },
60 { EOPNOTSUPP, 0 },
61 { EOPNOTSUPP, 0 }
62 };
63
64
65
66 static void
67 print_icmp(struct icmphdr *icmph)
68 {
69 if (inet_debug != DBG_ICMP) return;
70
71 printk("ICMP: type = %d, code = %d, checksum = %X\n",
72 icmph->type, icmph->code, icmph->checksum);
73 printk(" gateway = %s\n", in_ntoa(icmph->un.gateway));
74 }
75
76
77
78 void
79 icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
80 {
81 struct sk_buff *skb;
82 struct iphdr *iph;
83 int offset;
84 struct icmphdr *icmph;
85 int len;
86
87 DPRINTF((DBG_ICMP, "icmp_send(skb_in = %X, type = %d, code = %d, dev=%X)\n",
88 skb_in, type, code, dev));
89
90
91 len = sizeof(struct sk_buff) + dev->hard_header_len +
92 sizeof(struct iphdr) + sizeof(struct icmphdr) +
93 sizeof(struct iphdr) + 8;
94
95 skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);
96 if (skb == NULL)
97 return;
98
99 skb->sk = NULL;
100 skb->mem_addr = skb;
101 skb->mem_len = len;
102 len -= sizeof(struct sk_buff);
103
104
105 iph = (struct iphdr *) (skb_in + 1);
106 iph = (struct iphdr *) ((unsigned char *) iph + dev->hard_header_len);
107
108
109 offset = ip_build_header(skb, iph->daddr, iph->saddr,
110 &dev, IPPROTO_ICMP, NULL, len);
111 if (offset < 0) {
112 skb->sk = NULL;
113 kfree_skb(skb, FREE_READ);
114 return;
115 }
116
117
118 skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;
119 icmph = (struct icmphdr *) ((unsigned char *) (skb + 1) + offset);
120 icmph->type = type;
121 icmph->code = code;
122 icmph->checksum = 0;
123 icmph->un.gateway = 0;
124 memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
125
126 icmph->checksum = ip_compute_csum((unsigned char *)icmph,
127 sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
128
129 DPRINTF((DBG_ICMP, ">>\n"));
130 print_icmp(icmph);
131
132
133 ip_queue_xmit(NULL, dev, skb, 1);
134 }
135
136
137
138 static void
139 icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
140 {
141 struct inet_protocol *ipprot;
142 struct iphdr *iph;
143 unsigned char hash;
144 int err;
145
146 err = (icmph->type << 8) | icmph->code;
147 iph = (struct iphdr *) (icmph + 1);
148 switch(icmph->code & 7) {
149 case ICMP_NET_UNREACH:
150 DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n",
151 in_ntoa(iph->daddr)));
152 break;
153 case ICMP_HOST_UNREACH:
154 DPRINTF((DBG_ICMP, "ICMP: %s: host unreachable.\n",
155 in_ntoa(iph->daddr)));
156 break;
157 case ICMP_PROT_UNREACH:
158 printk("ICMP: %s:%d: protocol unreachable.\n",
159 in_ntoa(iph->daddr), ntohs(iph->protocol));
160 break;
161 case ICMP_PORT_UNREACH:
162 DPRINTF((DBG_ICMP, "ICMP: %s:%d: port unreachable.\n",
163 in_ntoa(iph->daddr), -1 ));
164 break;
165 case ICMP_FRAG_NEEDED:
166 printk("ICMP: %s: fragmentation needed and DF set.\n",
167 in_ntoa(iph->daddr));
168 break;
169 case ICMP_SR_FAILED:
170 printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
171 break;
172 default:
173 DPRINTF((DBG_ICMP, "ICMP: Unreachable: CODE=%d from %s\n",
174 (icmph->code & 7), in_ntoa(iph->daddr)));
175 break;
176 }
177
178
179 hash = iph->protocol & (MAX_INET_PROTOS -1);
180
181
182 ipprot = (struct inet_protocol *) inet_protos[hash];
183 while(ipprot != NULL) {
184 struct inet_protocol *nextip;
185
186 nextip = (struct inet_protocol *) ipprot->next;
187
188
189 if (iph->protocol == ipprot->protocol && ipprot->err_handler) {
190 ipprot->err_handler(err, (unsigned char *)(icmph + 1),
191 iph->daddr, iph->saddr, ipprot);
192 }
193
194 ipprot = nextip;
195 }
196 skb->sk = NULL;
197 kfree_skb(skb, FREE_READ);
198 }
199
200
201
202 static void
203 icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev)
204 {
205 struct iphdr *iph;
206 unsigned long ip;
207
208 iph = (struct iphdr *) (icmph + 1);
209 ip = iph->daddr;
210 switch(icmph->code & 7) {
211 case ICMP_REDIR_NET:
212 rt_add((RTF_DYNAMIC | RTF_MODIFIED),
213 ip, icmph->un.gateway, dev);
214 break;
215 case ICMP_REDIR_HOST:
216 rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST),
217 ip, icmph->un.gateway, dev);
218 break;
219 case ICMP_REDIR_NETTOS:
220 case ICMP_REDIR_HOSTTOS:
221 printk("ICMP: cannot handle TOS redirects yet!\n");
222 break;
223 default:
224 DPRINTF((DBG_ICMP, "ICMP: Unreach: CODE=%d\n",
225 (icmph->code & 7)));
226 break;
227 }
228 skb->sk = NULL;
229 kfree_skb(skb, FREE_READ);
230 }
231
232
233
234 static void
235 icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
236 unsigned long saddr, unsigned long daddr, int len,
237 struct options *opt)
238 {
239 struct icmphdr *icmphr;
240 struct sk_buff *skb2;
241 int size, offset;
242
243 size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
244 skb2 = alloc_skb(size, GFP_ATOMIC);
245 if (skb2 == NULL) {
246 skb->sk = NULL;
247 kfree_skb(skb, FREE_READ);
248 return;
249 }
250 skb2->sk = NULL;
251 skb2->mem_addr = skb2;
252 skb2->mem_len = size;
253 skb2->free = 1;
254
255
256 offset = ip_build_header(skb2, daddr, saddr, &dev,
257 IPPROTO_ICMP, opt, len);
258 if (offset < 0) {
259 printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
260 kfree_skb(skb2,FREE_WRITE);
261 skb->sk = NULL;
262 kfree_skb(skb, FREE_READ);
263 return;
264 }
265
266
267 skb2->len = offset + len;
268
269
270 icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
271 memcpy((char *) icmphr, (char *) icmph, len);
272 icmphr->type = ICMP_ECHOREPLY;
273 icmphr->code = 0;
274 icmphr->checksum = 0;
275 icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
276
277
278 ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
279
280 skb->sk = NULL;
281 kfree_skb(skb, FREE_READ);
282 }
283
284
285
286 static void
287 icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
288 unsigned long saddr, unsigned long daddr, int len,
289 struct options *opt)
290 {
291
292 skb->sk = NULL;
293 kfree_skb(skb, FREE_READ);
294 }
295
296
297
298 static void
299 icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
300 unsigned long saddr, unsigned long daddr, int len,
301 struct options *opt)
302 {
303 struct icmphdr *icmphr;
304 struct sk_buff *skb2;
305 int size, offset;
306
307 size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
308 skb2 = alloc_skb(size, GFP_ATOMIC);
309 if (skb2 == NULL) {
310 skb->sk = NULL;
311 kfree_skb(skb, FREE_READ);
312 return;
313 }
314 skb2->sk = NULL;
315 skb2->mem_addr = skb2;
316 skb2->mem_len = size;
317 skb2->free = 1;
318
319
320 offset = ip_build_header(skb2, daddr, saddr, &dev,
321 IPPROTO_ICMP, opt, len);
322 if (offset < 0) {
323 printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
324 kfree_skb(skb2,FREE_WRITE);
325 skb->sk = NULL;
326 kfree_skb(skb, FREE_READ);
327 return;
328 }
329
330
331 skb2->len = offset + len;
332
333
334 icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
335 icmphr->type = ICMP_ADDRESSREPLY;
336 icmphr->code = 0;
337 icmphr->checksum = 0;
338 icmphr->un.echo.id = icmph->un.echo.id;
339 icmphr->un.echo.sequence = icmph->un.echo.sequence;
340 memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
341
342 icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
343
344
345 ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
346
347 skb->sk = NULL;
348 kfree_skb(skb, FREE_READ);
349 }
350
351
352
353 int
354 icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
355 unsigned long daddr, unsigned short len,
356 unsigned long saddr, int redo, struct inet_protocol *protocol)
357 {
358 struct icmphdr *icmph;
359 unsigned char *buff;
360
361
362 if (chk_addr(daddr) == IS_BROADCAST) {
363 DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n",
364 in_ntoa(saddr)));
365 skb1->sk = NULL;
366 kfree_skb(skb1, FREE_READ);
367 return(0);
368 }
369
370 buff = skb1->h.raw;
371 icmph = (struct icmphdr *) buff;
372
373
374 if (ip_compute_csum((unsigned char *) icmph, len)) {
375
376 printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
377 skb1->sk = NULL;
378 kfree_skb(skb1, FREE_READ);
379 return(0);
380 }
381 print_icmp(icmph);
382
383
384 switch(icmph->type) {
385 case ICMP_TIME_EXCEEDED:
386 case ICMP_DEST_UNREACH:
387 case ICMP_SOURCE_QUENCH:
388 icmp_unreach(icmph, skb1);
389 return(0);
390 case ICMP_REDIRECT:
391 icmp_redirect(icmph, skb1, dev);
392 return(0);
393 case ICMP_ECHO:
394 icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
395 return 0;
396 case ICMP_ECHOREPLY:
397 skb1->sk = NULL;
398 kfree_skb(skb1, FREE_READ);
399 return(0);
400 case ICMP_INFO_REQUEST:
401 icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
402 return 0;
403 case ICMP_INFO_REPLY:
404 skb1->sk = NULL;
405 kfree_skb(skb1, FREE_READ);
406 return(0);
407 case ICMP_ADDRESS:
408 icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
409 return 0;
410 case ICMP_ADDRESSREPLY:
411 skb1->sk = NULL;
412 kfree_skb(skb1, FREE_READ);
413 return(0);
414 default:
415 DPRINTF((DBG_ICMP,
416 "ICMP: Unsupported ICMP from %s, type = 0x%X\n",
417 in_ntoa(saddr), icmph->type));
418 skb1->sk = NULL;
419 kfree_skb(skb1, FREE_READ);
420 return(0);
421 }
422
423 skb1->sk = NULL;
424 kfree_skb(skb1, FREE_READ);
425 return(-1);
426 }
427
428
429
430 int
431 icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
432 {
433 switch(cmd) {
434 case DDIOCSDBG:
435 return(dbg_ioctl((void *) arg, DBG_ICMP));
436 default:
437 return(-EINVAL);
438 }
439 return(0);
440 }