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