?? icmp.c
字號:
1 /*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
5 *
6 * Internet Control Message Protocol (ICMP)
7 *
8 * Version: @(#)icmp.c 1.0.11 06/02/93
9 *
10 * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
11 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
12 * Mark Evans, <evansmp@uhura.aston.ac.uk>
13 *
14 * Fixes:
15 * Alan Cox : Generic queue usage.
16 * Gerhard Koerting: ICMP addressing corrected
17 * Alan Cox : Use tos/ttl settings
18 *
19 *
20 * This program is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU General Public License
22 * as published by the Free Software Foundation; either version
23 * 2 of the License, or (at your option) any later version.
24 */
25 #include <linux/types.h>
26 #include <linux/sched.h>
27 #include <linux/kernel.h>
28 #include <linux/fcntl.h>
29 #include <linux/socket.h>
30 #include <linux/in.h>
31 #include "inet.h"
32 #include "dev.h"
33 #include "ip.h"
34 #include "route.h"
35 #include "protocol.h"
36 #include "icmp.h"
37 #include "tcp.h"
38 #include "skbuff.h"
39 #include "sock.h"
40 #include <linux/errno.h>
41 #include <linux/timer.h>
42 #include <asm/system.h>
43 #include <asm/segment.h>
44
45
46 #define min(a,b) ((a)<(b)?(a):(b))
47
48
49 /* An array of errno for error messages from dest unreach. */
50 struct icmp_err icmp_err_convert[] = {
51 { ENETUNREACH, 1 }, /* ICMP_NET_UNREACH */
52 { EHOSTUNREACH, 1 }, /* ICMP_HOST_UNREACH */
53 { ENOPROTOOPT, 1 }, /* ICMP_PROT_UNREACH */
54 { ECONNREFUSED, 1 }, /* ICMP_PORT_UNREACH */
55 { EOPNOTSUPP, 0 }, /* ICMP_FRAG_NEEDED */
56 { EOPNOTSUPP, 0 }, /* ICMP_SR_FAILED */
57 { ENETUNREACH, 1 }, /* ICMP_NET_UNKNOWN */
58 { EHOSTDOWN, 1 }, /* ICMP_HOST_UNKNOWN */
59 { ENONET, 1 }, /* ICMP_HOST_ISOLATED */
60 { ENETUNREACH, 1 }, /* ICMP_NET_ANO */
61 { EHOSTUNREACH, 1 }, /* ICMP_HOST_ANO */
62 { EOPNOTSUPP, 0 }, /* ICMP_NET_UNR_TOS */
63 { EOPNOTSUPP, 0 } /* ICMP_HOST_UNR_TOS */
64 };
65
66
67 /* Display the contents of an ICMP header. */
68 static void
69 print_icmp(struct icmphdr *icmph)
70 {
71 if (inet_debug != DBG_ICMP) return;
72
73 printk("ICMP: type = %d, code = %d, checksum = %X\n",
74 icmph->type, icmph->code, icmph->checksum);
75 printk(" gateway = %s\n", in_ntoa(icmph->un.gateway));
76 }
77
78
79 /* Send an ICMP message. */
80 void
81 icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
82 {
83 struct sk_buff *skb;
84 struct iphdr *iph;
85 int offset;
86 struct icmphdr *icmph;
87 int len;
88
89 DPRINTF((DBG_ICMP, "icmp_send(skb_in = %X, type = %d, code = %d, dev=%X)\n",
90 skb_in, type, code, dev));
91
92 /* Get some memory for the reply. */
93 len = sizeof(struct sk_buff) + dev->hard_header_len +
94 sizeof(struct iphdr) + sizeof(struct icmphdr) +
95 sizeof(struct iphdr) + 8; /* amount of header to return */
96
97 skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);
98 if (skb == NULL)
99 return;
100
101 skb->sk = NULL;
102 skb->mem_addr = skb;
103 skb->mem_len = len;
104 len -= sizeof(struct sk_buff);
105
106 /* Find the IP header. */
107 iph = (struct iphdr *) (skb_in->data + dev->hard_header_len);
108
109 /* Build Layer 2-3 headers for message back to source. */
110 offset = ip_build_header(skb, dev->pa_addr, iph->saddr,
111 &dev, IPPROTO_ICMP, NULL, len, skb_in->ip_hdr->tos,255);
112 if (offset < 0) {
113 skb->sk = NULL;
114 kfree_skb(skb, FREE_READ);
115 return;
116 }
117
118 /* Re-adjust length according to actual IP header size. */
119 skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;
120 icmph = (struct icmphdr *) (skb->data + offset);
121 icmph->type = type;
122 icmph->code = code;
123 icmph->checksum = 0;
124 icmph->un.gateway = 0;
125 memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
126
127 icmph->checksum = ip_compute_csum((unsigned char *)icmph,
128 sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
129
130 DPRINTF((DBG_ICMP, ">>\n"));
131 print_icmp(icmph);
132
133 /* Send it and free it. */
134 ip_queue_xmit(NULL, dev, skb, 1);
135 }
136
137
138 /* Handle ICMP_UNREACH and ICMP_QUENCH. */
139 static void
140 icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
141 {
142 struct inet_protocol *ipprot;
143 struct iphdr *iph;
144 unsigned char hash;
145 int err;
146
147 err = (icmph->type << 8) | icmph->code;
148 iph = (struct iphdr *) (icmph + 1);
149 switch(icmph->code & 7) {
150 case ICMP_NET_UNREACH:
151 DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n",
152 in_ntoa(iph->daddr)));
153 break;
154 case ICMP_HOST_UNREACH:
155 DPRINTF((DBG_ICMP, "ICMP: %s: host unreachable.\n",
156 in_ntoa(iph->daddr)));
157 break;
158 case ICMP_PROT_UNREACH:
159 printk("ICMP: %s:%d: protocol unreachable.\n",
160 in_ntoa(iph->daddr), ntohs(iph->protocol));
161 break;
162 case ICMP_PORT_UNREACH:
163 DPRINTF((DBG_ICMP, "ICMP: %s:%d: port unreachable.\n",
164 in_ntoa(iph->daddr), -1 /* FIXME: ntohs(iph->port) */));
165 break;
166 case ICMP_FRAG_NEEDED:
167 printk("ICMP: %s: fragmentation needed and DF set.\n",
168 in_ntoa(iph->daddr));
169 break;
170 case ICMP_SR_FAILED:
171 printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
172 break;
173 default:
174 DPRINTF((DBG_ICMP, "ICMP: Unreachable: CODE=%d from %s\n",
175 (icmph->code & 7), in_ntoa(iph->daddr)));
176 break;
177 }
178
179 /* Get the protocol(s). */
180 hash = iph->protocol & (MAX_INET_PROTOS -1);
181
182 /* This can change while we are doing it. */
183 ipprot = (struct inet_protocol *) inet_protos[hash];
184 while(ipprot != NULL) {
185 struct inet_protocol *nextip;
186
187 nextip = (struct inet_protocol *) ipprot->next;
188
189 /* Pass it off to everyone who wants it. */
190 if (iph->protocol == ipprot->protocol && ipprot->err_handler) {
191 ipprot->err_handler(err, (unsigned char *)(icmph + 1),
192 iph->daddr, iph->saddr, ipprot);
193 }
194
195 ipprot = nextip;
196 }
197 skb->sk = NULL;
198 kfree_skb(skb, FREE_READ);
199 }
200
201
202 /* Handle ICMP_REDIRECT. */
203 static void
204 icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev)
205 {
206 struct iphdr *iph;
207 unsigned long ip;
208
209 iph = (struct iphdr *) (icmph + 1);
210 ip = iph->daddr;
211 switch(icmph->code & 7) {
212 case ICMP_REDIR_NET:
213 #ifdef not_a_good_idea
214 rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
215 ip, 0, icmph->un.gateway, dev);
216 break;
217 #endif
218 case ICMP_REDIR_HOST:
219 rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
220 ip, 0, icmph->un.gateway, dev);
221 break;
222 case ICMP_REDIR_NETTOS:
223 case ICMP_REDIR_HOSTTOS:
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -