]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Icmp.c
74bede7a4b8865459525cce4fbd25ac819cfff00
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Icmp.c
1 /** @file
2
3 Copyright (c) 2005 - 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12
13 Module Name:
14
15 Ip4Icmp.c
16
17 Abstract:
18
19
20 **/
21
22 #include "Ip4Impl.h"
23
24 IP4_ICMP_CLASS
25 mIcmpClass[] = {
26 {ICMP_ECHO_REPLY, ICMP_QUERY_MESSAGE },
27 {1, ICMP_INVALID_MESSAGE},
28 {2, ICMP_INVALID_MESSAGE},
29 {ICMP_DEST_UNREACHABLE, ICMP_ERROR_MESSAGE },
30 {ICMP_SOURCE_QUENCH, ICMP_ERROR_MESSAGE },
31 {ICMP_REDIRECT, ICMP_ERROR_MESSAGE },
32 {6, ICMP_INVALID_MESSAGE},
33 {7, ICMP_INVALID_MESSAGE},
34 {ICMP_ECHO_REQUEST, ICMP_QUERY_MESSAGE },
35 {9, ICMP_INVALID_MESSAGE},
36 {10, ICMP_INVALID_MESSAGE},
37 {ICMP_TIME_EXCEEDED, ICMP_ERROR_MESSAGE },
38 {ICMP_PARAMETER_PROBLEM, ICMP_ERROR_MESSAGE },
39 {ICMP_TIMESTAMP , ICMP_QUERY_MESSAGE },
40 {14, ICMP_INVALID_MESSAGE},
41 {ICMP_INFO_REQUEST , ICMP_QUERY_MESSAGE },
42 {ICMP_INFO_REPLY , ICMP_QUERY_MESSAGE },
43 };
44
45 EFI_IP4_ICMP_TYPE
46 mIp4SupportedIcmp [23] = {
47 {ICMP_ECHO_REPLY, ICMP_DEFAULT_CODE },
48
49 {ICMP_DEST_UNREACHABLE, ICMP_NET_UNREACHABLE },
50 {ICMP_DEST_UNREACHABLE, ICMP_HOST_UNREACHABLE },
51 {ICMP_DEST_UNREACHABLE, ICMP_PROTO_UNREACHABLE },
52 {ICMP_DEST_UNREACHABLE, ICMP_PORT_UNREACHABLE },
53 {ICMP_DEST_UNREACHABLE, ICMP_FRAGMENT_FAILED },
54 {ICMP_DEST_UNREACHABLE, ICMP_SOURCEROUTE_FAILED},
55 {ICMP_DEST_UNREACHABLE, ICMP_NET_UNKNOWN },
56 {ICMP_DEST_UNREACHABLE, ICMP_HOST_UNKNOWN },
57 {ICMP_DEST_UNREACHABLE, ICMP_SOURCE_ISOLATED },
58 {ICMP_DEST_UNREACHABLE, ICMP_NET_PROHIBITED },
59 {ICMP_DEST_UNREACHABLE, ICMP_HOST_PROHIBITED },
60 {ICMP_DEST_UNREACHABLE, ICMP_NET_UNREACHABLE_TOS },
61 {ICMP_DEST_UNREACHABLE, ICMP_HOST_UNREACHABLE_TOS},
62
63 {ICMP_SOURCE_QUENCH, ICMP_DEFAULT_CODE },
64
65 {ICMP_REDIRECT, ICMP_NET_REDIRECT },
66 {ICMP_REDIRECT, ICMP_HOST_REDIRECT },
67 {ICMP_REDIRECT, ICMP_NET_TOS_REDIRECT },
68 {ICMP_REDIRECT, ICMP_HOST_TOS_REDIRECT },
69
70 {ICMP_ECHO_REQUEST, ICMP_DEFAULT_CODE },
71
72 {ICMP_TIME_EXCEEDED, ICMP_TIMEOUT_IN_TRANSIT},
73 {ICMP_TIME_EXCEEDED, ICMp_TIMEOUT_REASSEMBLE},
74
75 {ICMP_PARAMETER_PROBLEM, ICMP_DEFAULT_CODE },
76 };
77
78
79
80 /**
81 Process the ICMP redirect. Find the instance then update
82 its route cache.
83 All kinds of redirect is treated as host redirect as
84 specified by RFC1122 3.3.1.2:
85 "Since the subnet mask appropriate to the destination
86 address is generally not known, a Network Redirect
87 message SHOULD be treated identically to a Host Redirect
88 message;"
89
90 @param IpSb The IP4 service binding instance that received the
91 packet
92 @param Head The IP head of the received ICMPpacket.
93 @param Packet The content of the ICMP redirect packet with IP
94 head removed.
95 @param Icmp The buffer to store the ICMP error message if
96 something is wrong.
97
98 @retval EFI_INVALID_PARAMETER The parameter is invalid
99 @retval EFI_SUCCESS Successfully updated the route caches
100
101 **/
102 EFI_STATUS
103 Ip4ProcessIcmpRedirect (
104 IN IP4_SERVICE *IpSb,
105 IN IP4_HEAD *Head,
106 IN NET_BUF *Packet,
107 IN IP4_ICMP_ERROR_HEAD *Icmp
108 )
109 {
110 LIST_ENTRY *Entry;
111 IP4_PROTOCOL *Ip4Instance;
112 IP4_ROUTE_CACHE_ENTRY *CacheEntry;
113 IP4_INTERFACE *IpIf;
114 IP4_ADDR Gateway;
115
116 //
117 // Find the interface whose IP address is the source of the
118 // orgianl IP packet.
119 //
120 IpIf = Ip4FindInterface (IpSb, NTOHL (Icmp->IpHead.Src));
121 Gateway = NTOHL (Icmp->Fourth);
122
123 //
124 // discard the packet if the new gateway address it specifies
125 // is not on the same connected net through which the Redirect
126 // arrived. (RFC1122 3.2.2.2).
127 //
128 if ((IpIf == NULL) || !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask)) {
129 NetbufFree (Packet);
130 return EFI_INVALID_PARAMETER;
131 }
132
133 //
134 // Update each IP child's route cache on the interface.
135 //
136 NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
137 Ip4Instance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);
138
139 if (Ip4Instance->RouteTable == NULL) {
140 continue;
141 }
142
143 CacheEntry = Ip4FindRouteCache (
144 Ip4Instance->RouteTable,
145 NTOHL (Icmp->IpHead.Dst),
146 NTOHL (Icmp->IpHead.Src)
147 );
148
149 //
150 // Only update the route cache's gateway if the source of the
151 // Redirect is the current first-hop gateway
152 //
153 if ((CacheEntry != NULL) && (NTOHL (Head->Src) == CacheEntry->NextHop)) {
154 CacheEntry->NextHop = Gateway;
155 }
156 }
157
158 NetbufFree (Packet);
159 return EFI_SUCCESS;
160 }
161
162
163 /**
164 Process the ICMP error packet. If it is an ICMP redirect packet,
165 update call Ip4ProcessIcmpRedirect to update the IP instance's
166 route cache, otherwise, deliver the packet to upper layer.
167
168 @param IpSb The IP service that received the packet.
169 @param Head The IP head of the ICMP error packet
170 @param Packet The content of the ICMP error with IP head
171 removed.
172
173 @retval EFI_INVALID_PARAMETER The packet is invalid
174 @retval Others Failed to process the packet.
175 @retval EFI_SUCCESS The ICMP error is processed successfully.
176
177 **/
178 EFI_STATUS
179 Ip4ProcessIcmpError (
180 IN IP4_SERVICE *IpSb,
181 IN IP4_HEAD *Head,
182 IN NET_BUF *Packet
183 )
184 {
185 IP4_ICMP_ERROR_HEAD Icmp;
186
187 if (Packet->TotalSize < sizeof (Icmp)) {
188 NetbufFree (Packet);
189 return EFI_INVALID_PARAMETER;
190 }
191
192 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
193
194 //
195 // If it is an ICMP redirect error, update the route cache
196 // as RFC1122. Otherwise, demultiplex it to IP instances.
197 //
198 if (Icmp.Head.Type == ICMP_REDIRECT) {
199 return Ip4ProcessIcmpRedirect (IpSb, Head, Packet, &Icmp);
200 }
201
202 IP4_GET_CLIP_INFO (Packet)->Status = EFI_ICMP_ERROR;
203 return Ip4Demultiplex (IpSb, Head, Packet);
204 }
205
206
207 /**
208 Replay an ICMP echo request.
209
210 @param IpSb The IP service that receivd the packet
211 @param Head The IP head of the ICMP error packet
212 @param Packet The content of the ICMP error with IP head
213 removed.
214
215 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
216 @retval EFI_SUCCESS The ICMP Echo request is successfully answered.
217 @retval Others Failed to answer the ICMP echo request.
218
219 **/
220 EFI_STATUS
221 Ip4IcmpReplyEcho (
222 IN IP4_SERVICE *IpSb,
223 IN IP4_HEAD *Head,
224 IN NET_BUF *Packet
225 )
226 {
227 IP4_ICMP_QUERY_HEAD *Icmp;
228 NET_BUF *Data;
229 EFI_STATUS Status;
230 IP4_HEAD ReplyHead;
231
232 //
233 // make a copy the packet, it is really a bad idea to
234 // send the MNP's buffer back to MNP.
235 //
236 Data = NetbufDuplicate (Packet, NULL, IP4_MAX_HEADLEN);
237
238 if (Data == NULL) {
239 Status = EFI_OUT_OF_RESOURCES;
240 goto ON_EXIT;
241 }
242
243 //
244 // Change the ICMP type to echo reply, exchange the source
245 // and destination, then send it. The source is updated to
246 // use specific destination. See RFC1122. SRR/RR option
247 // update is omitted.
248 //
249 Icmp = (IP4_ICMP_QUERY_HEAD *) NetbufGetByte (Data, 0, NULL);
250 Icmp->Head.Type = ICMP_ECHO_REPLY;
251 Icmp->Head.Checksum = 0;
252 Icmp->Head.Checksum = (UINT16) (~NetblockChecksum ((UINT8 *) Icmp, Data->TotalSize));
253
254 ReplyHead.Tos = 0;
255 ReplyHead.Fragment = 0;
256 ReplyHead.Ttl = 64;
257 ReplyHead.Protocol = IP4_PROTO_ICMP;
258 ReplyHead.Src = 0;
259
260 //
261 // Ip4Output will select a source for us
262 //
263 ReplyHead.Dst = Head->Src;
264
265 Status = Ip4Output (
266 IpSb,
267 NULL,
268 Data,
269 &ReplyHead,
270 NULL,
271 0,
272 IP4_ALLZERO_ADDRESS,
273 Ip4SysPacketSent,
274 NULL
275 );
276
277 ON_EXIT:
278 NetbufFree (Packet);
279 return Status;
280 }
281
282
283 /**
284 Process the ICMP query message. If it is an ICMP echo
285 request, answer it. Otherwise deliver it to upper layer.
286
287 @param IpSb The IP service that receivd the packet
288 @param Head The IP head of the ICMP query packet
289 @param Packet The content of the ICMP query with IP head
290 removed.
291
292 @retval EFI_INVALID_PARAMETER The packet is invalid
293 @retval EFI_SUCCESS The ICMP query message is processed
294
295 **/
296 EFI_STATUS
297 Ip4ProcessIcmpQuery (
298 IN IP4_SERVICE *IpSb,
299 IN IP4_HEAD *Head,
300 IN NET_BUF *Packet
301 )
302 {
303 IP4_ICMP_QUERY_HEAD Icmp;
304
305 if (Packet->TotalSize < sizeof (Icmp)) {
306 NetbufFree (Packet);
307 return EFI_INVALID_PARAMETER;
308 }
309
310 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
311
312 if (Icmp.Head.Type == ICMP_ECHO_REQUEST) {
313 return Ip4IcmpReplyEcho (IpSb, Head, Packet);
314 }
315
316 return Ip4Demultiplex (IpSb, Head, Packet);
317 }
318
319
320 /**
321 Handle the ICMP packet. First validate the message format,
322 then according to the message types, process it as query or
323 error packet.
324
325 @param IpSb The IP service that receivd the packet
326 @param Head The IP head of the ICMP query packet
327 @param Packet The content of the ICMP query with IP head
328 removed.
329
330 @retval EFI_INVALID_PARAMETER The packet is malformated.
331 @retval EFI_SUCCESS The ICMP message is successfully processed.
332
333 **/
334 EFI_STATUS
335 Ip4IcmpHandle (
336 IN IP4_SERVICE *IpSb,
337 IN IP4_HEAD *Head,
338 IN NET_BUF *Packet
339 )
340 {
341 IP4_ICMP_HEAD Icmp;
342 UINT16 Checksum;
343
344 if (Packet->TotalSize < sizeof (Icmp)) {
345 goto DROP;
346 }
347
348 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
349
350 if (Icmp.Type > ICMP_TYPE_MAX) {
351 goto DROP;
352 }
353
354 Checksum = (UINT16) (~NetbufChecksum (Packet));
355 if ((Icmp.Checksum != 0) && (Checksum != 0)) {
356 goto DROP;
357 }
358
359 if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_ERROR_MESSAGE) {
360 return Ip4ProcessIcmpError (IpSb, Head, Packet);
361
362 } else if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_QUERY_MESSAGE) {
363 return Ip4ProcessIcmpQuery (IpSb, Head, Packet);
364
365 }
366
367 DROP:
368 NetbufFree (Packet);
369 return EFI_INVALID_PARAMETER;
370 }