]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_ip.c
1. Sync the latest network stack. Add NetLibCreateIPv4DPathNode () in netlib library.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / PxeBcDxe / Pxe_bc_ip.c
CommitLineData
772db4bb 1/** @file\r
2\r
3Copyright (c) 2004, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13 pxe_bc_ip.c\r
14\r
15Abstract:\r
16\r
17\r
18**/\r
19\r
20#include "Bc.h"\r
21\r
22/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
23\r
24/**\r
25 Check if two IP addresses are on the same subnet.\r
26\r
27 @param IpLength Length of IP address in bytes.\r
28 @param Ip1 IP address to check.\r
29 @param Ip2 IP address to check.\r
30 @param SubnetMask Subnet mask to check with.\r
31\r
32 @retval TRUE IP addresses are on the same subnet.\r
33 @retval FALSE IP addresses are on different subnets.\r
34\r
35**/\r
36BOOLEAN\r
37OnSameSubnet (\r
38 IN UINTN IpLength,\r
39 IN EFI_IP_ADDRESS *Ip1,\r
40 IN EFI_IP_ADDRESS *Ip2,\r
41 IN EFI_IP_ADDRESS *SubnetMask\r
42 )\r
43{\r
44 if (IpLength == 0 || Ip1 == NULL || Ip2 == NULL || SubnetMask == NULL) {\r
45 return FALSE;\r
46 }\r
47\r
48 while (IpLength-- != 0) {\r
49 if ((Ip1->v6.Addr[IpLength] ^ Ip2->v6.Addr[IpLength]) & SubnetMask->v6.Addr[IpLength]) {\r
50 return FALSE;\r
51 }\r
52 }\r
53\r
54 return TRUE;\r
55}\r
56\r
57/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
58\r
59/**\r
60 Add router to router table.\r
61\r
62 @param Private Pointer PxeBc instance data.\r
63 @param RouterIpPtr Pointer to router IP address.\r
64\r
65 @return Nothing\r
66\r
67**/\r
68VOID\r
69IpAddRouter (\r
70 IN PXE_BASECODE_DEVICE *Private,\r
71 IN EFI_IP_ADDRESS *RouterIpPtr\r
72 )\r
73{\r
74 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
75 UINTN Index;\r
76\r
77 if (Private == NULL || RouterIpPtr == NULL) {\r
78 return ;\r
79 }\r
80\r
81 PxeBcMode = Private->EfiBc.Mode;\r
82\r
83 //\r
84 // if we are filled up or this is not on the same subnet, forget it\r
85 //\r
86 if ((PxeBcMode->RouteTableEntries == PXE_ROUTER_TABLE_SIZE) ||\r
87 !OnSameSubnet(Private->IpLength, &PxeBcMode->StationIp, RouterIpPtr, &PxeBcMode->SubnetMask)) {\r
88 return ;\r
89 }\r
90 //\r
91 // make sure we don't already have it\r
92 //\r
93 for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {\r
94 if (!CompareMem (\r
95 &PxeBcMode->RouteTable[Index].GwAddr,\r
96 RouterIpPtr,\r
97 Private->IpLength\r
98 )) {\r
99 return ;\r
100 }\r
101 }\r
102 //\r
103 // keep it\r
104 //\r
105 ZeroMem (\r
106 &PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries],\r
107 sizeof (EFI_PXE_BASE_CODE_ROUTE_ENTRY)\r
108 );\r
109\r
110 CopyMem (\r
111 &PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries++].GwAddr,\r
112 RouterIpPtr,\r
113 Private->IpLength\r
114 );\r
115}\r
116\r
117/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
118\r
119//\r
120// return router ip to use for DestIp (0 if none)\r
121//\r
122STATIC\r
123EFI_IP_ADDRESS *\r
124GetRouterIp (\r
125 PXE_BASECODE_DEVICE *Private,\r
126 EFI_IP_ADDRESS *DestIpPtr\r
127 )\r
128{\r
129 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
130 UINTN Index;\r
131\r
132 if (Private == NULL || DestIpPtr == NULL) {\r
133 return NULL;\r
134 }\r
135\r
136 PxeBcMode = Private->EfiBc.Mode;\r
137\r
138 for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {\r
139 if (OnSameSubnet (\r
140 Private->IpLength,\r
141 &PxeBcMode->RouteTable[Index].IpAddr,\r
142 DestIpPtr,\r
143 &PxeBcMode->RouteTable[Index].SubnetMask\r
144 )) {\r
145 return &PxeBcMode->RouteTable[Index].GwAddr;\r
146 }\r
147 }\r
148\r
149 return NULL;\r
150}\r
151\r
152/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
153\r
154//\r
155// routine to send ipv4 packet\r
156// ipv4 header of length HdrLth in TransmitBufferPtr\r
157// routine fills in ipv4hdr Ver_Hdl, TotalLength, and Checksum, moves in Data\r
158// and gets dest MAC address\r
159//\r
160#define IP_TX_BUFFER ((IPV4_BUFFER *) Private->TransmitBufferPtr)\r
161#define IP_TX_HEADER IP_TX_BUFFER->IpHeader\r
162\r
163EFI_STATUS\r
164Ipv4Xmt (\r
165 PXE_BASECODE_DEVICE *Private,\r
166 UINT32 GatewayIp,\r
167 UINTN IpHeaderLength,\r
168 UINTN TotalHeaderLength,\r
169 VOID *Data,\r
170 UINTN DataLength,\r
171 EFI_PXE_BASE_CODE_FUNCTION Function\r
172 )\r
173{\r
174 EFI_MAC_ADDRESS DestMac;\r
175 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
176 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
177 EFI_STATUS StatCode;\r
178 UINTN PacketLength;\r
179\r
180 Snp = Private->SimpleNetwork;\r
181 PxeBcMode = Private->EfiBc.Mode;\r
182 StatCode = EFI_SUCCESS;\r
183 PacketLength = TotalHeaderLength + DataLength;\r
184\r
185 //\r
186 // get dest MAC address\r
187 // multicast - convert to hw equiv\r
188 // unicast on same net, use arp\r
189 // on different net, arp for router\r
190 //\r
191 if (IP_TX_HEADER.DestAddr.L == BROADCAST_IPv4) {\r
192 CopyMem (&DestMac, &Snp->Mode->BroadcastAddress, sizeof (DestMac));\r
193 } else if (IS_MULTICAST (&IP_TX_HEADER.DestAddr)) {\r
194 StatCode = (*Snp->MCastIpToMac) (Snp, PxeBcMode->UsingIpv6, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr, &DestMac);\r
195 } else {\r
196 UINT32 Ip;\r
197\r
198 if (OnSameSubnet (\r
199 Private->IpLength,\r
200 &PxeBcMode->StationIp,\r
201 (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr,\r
202 &PxeBcMode->SubnetMask\r
203 )) {\r
204 Ip = IP_TX_HEADER.DestAddr.L;\r
205 } else if (GatewayIp != 0) {\r
206 Ip = GatewayIp;\r
207 } else {\r
208 EFI_IP_ADDRESS *TmpIp;\r
209\r
210 TmpIp = GetRouterIp (Private, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr);\r
211\r
212 if (TmpIp == NULL) {\r
213 DEBUG (\r
214 (DEBUG_WARN,\r
215 "\nIpv4Xmit() Exit #1 %xh (%r)",\r
216 EFI_NO_RESPONSE,\r
217 EFI_NO_RESPONSE)\r
218 );\r
219\r
220 return EFI_NO_RESPONSE;\r
221 //\r
222 // no router\r
223 //\r
224 }\r
225\r
226 Ip = TmpIp->Addr[0];\r
227 }\r
228\r
229 if (!GetHwAddr (\r
230 Private,\r
231 (EFI_IP_ADDRESS *) &Ip,\r
232 (EFI_MAC_ADDRESS *) &DestMac\r
233 )) {\r
234 if (!PxeBcMode->AutoArp) {\r
235 DEBUG (\r
236 (DEBUG_WARN,\r
237 "\nIpv4Xmit() Exit #2 %xh (%r)",\r
238 EFI_DEVICE_ERROR,\r
239 EFI_DEVICE_ERROR)\r
240 );\r
241\r
242 return EFI_DEVICE_ERROR;\r
243 } else {\r
244 StatCode = DoArp (\r
245 Private,\r
246 (EFI_IP_ADDRESS *) &Ip,\r
247 (EFI_MAC_ADDRESS *) &DestMac\r
248 );\r
249 }\r
250 }\r
251 }\r
252\r
253 if (EFI_ERROR (StatCode)) {\r
254 DEBUG ((DEBUG_WARN, "\nIpv4Xmit() Exit #3 %xh (%r)", StatCode, StatCode));\r
255 return StatCode;\r
256 }\r
257 //\r
258 // fill in packet info\r
259 //\r
260 SET_IPV4_VER_HDL (&IP_TX_HEADER, IpHeaderLength);\r
261 IP_TX_HEADER.TotalLength = HTONS (PacketLength);\r
262 IP_TX_HEADER.HeaderChecksum = IpChecksum ((UINT16 *) &IP_TX_HEADER, IpHeaderLength);\r
263 CopyMem (((UINT8 *) &IP_TX_HEADER) + TotalHeaderLength, Data, DataLength);\r
264\r
265 //\r
266 // send it\r
267 //\r
268 return SendPacket (\r
269 Private,\r
270 (UINT8 *) &IP_TX_HEADER - Snp->Mode->MediaHeaderSize,\r
271 &IP_TX_HEADER,\r
272 PacketLength,\r
273 &DestMac,\r
274 PXE_PROTOCOL_ETHERNET_IP,\r
275 Function\r
276 );\r
277}\r
278\r
279/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
280\r
281//\r
282// send ipv4 packet with option\r
283//\r
284EFI_STATUS\r
285Ipv4SendWOp (\r
286 PXE_BASECODE_DEVICE *Private,\r
287 UINT32 GatewayIp,\r
288 UINT8 *Msg,\r
289 UINTN MessageLength,\r
290 UINT8 Prot,\r
291 UINT8 *Option,\r
292 UINTN OptionLength,\r
293 UINT32 DestIp,\r
294 EFI_PXE_BASE_CODE_FUNCTION Function\r
295 )\r
296{\r
297 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
298 UINTN HdrLth;\r
299\r
300 PxeBcMode = Private->EfiBc.Mode;\r
301 HdrLth = sizeof (IPV4_HEADER) + OptionLength;\r
302\r
303 ZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));\r
304 IP_TX_HEADER.TimeToLive = PxeBcMode->TTL;\r
305 IP_TX_HEADER.TypeOfService = PxeBcMode->ToS;\r
306 IP_TX_HEADER.Protocol = Prot;\r
307 IP_TX_HEADER.SrcAddr.L = *(UINT32 *) &PxeBcMode->StationIp;\r
308 IP_TX_HEADER.DestAddr.L = DestIp;\r
309 IP_TX_HEADER.Id = Random (Private);\r
310 CopyMem (IP_TX_BUFFER->u.Data, Option, OptionLength);\r
311 return Ipv4Xmt (\r
312 Private,\r
313 GatewayIp,\r
314 HdrLth,\r
315 HdrLth,\r
316 Msg,\r
317 MessageLength,\r
318 Function\r
319 );\r
320}\r
321\r
322/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
323\r
324//\r
325// send MessageLength message at MessagePtr - higher level protocol header already in TransmitBufferPtr, length HdrSize\r
326//\r
327EFI_STATUS\r
328Ip4Send (\r
329 PXE_BASECODE_DEVICE *Private, // pointer to instance data\r
330 UINTN MayFrag, //\r
331 UINT8 Prot, // protocol\r
332 UINT32 SrcIp, // Source IP address\r
333 UINT32 DestIp, // Destination IP address\r
334 UINT32 GatewayIp, // used if not NULL and needed\r
335 UINTN HdrSize, // protocol header byte length\r
336 UINT8 *MessagePtr, // pointer to data\r
337 UINTN MessageLength // data byte length\r
338 )\r
339{\r
340 EFI_STATUS StatCode;\r
341 UINTN TotDataLength;\r
342\r
343 TotDataLength = HdrSize + MessageLength;\r
344\r
345 if (TotDataLength > MAX_IPV4_DATA_SIZE) {\r
346 DEBUG (\r
347 (DEBUG_WARN,\r
348 "\nIp4Send() Exit #1 %xh (%r)",\r
349 EFI_BAD_BUFFER_SIZE,\r
350 EFI_BAD_BUFFER_SIZE)\r
351 );\r
352\r
353 return EFI_BAD_BUFFER_SIZE;\r
354 }\r
355\r
356 ZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));\r
357 IP_TX_HEADER.TimeToLive = DEFAULT_TTL;\r
358 IP_TX_HEADER.Protocol = Prot;\r
359 IP_TX_HEADER.SrcAddr.L = SrcIp;\r
360 IP_TX_HEADER.DestAddr.L = DestIp;\r
361 IP_TX_HEADER.Id = Random (Private);\r
362\r
363 if (!MayFrag) {\r
364 *(UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_NO_FRAG >> 8;\r
365 }\r
366 //\r
367 // check for need to fragment\r
368 //\r
369 if (TotDataLength > MAX_IPV4_FRAME_DATA_SIZE) {\r
370 UINTN DataLengthSent;\r
371 UINT16 FragmentOffset;\r
372\r
373 FragmentOffset = IP_MORE_FRAG;\r
374 //\r
375 // frag offset field\r
376 //\r
377 if (!MayFrag) {\r
378 DEBUG (\r
379 (DEBUG_WARN,\r
380 "\nIp4Send() Exit #2 %xh (%r)",\r
381 EFI_BAD_BUFFER_SIZE,\r
382 EFI_BAD_BUFFER_SIZE)\r
383 );\r
384\r
385 return EFI_BAD_BUFFER_SIZE;\r
386 }\r
387 //\r
388 // send out in fragments - first includes upper level header\r
389 // all are max and include more frag bit except last\r
390 //\r
391 * (UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_MORE_FRAG >> 8;\r
392\r
393#define IPV4_FRAG_SIZE (MAX_IPV4_FRAME_DATA_SIZE & 0xfff8)\r
394#define IPV4_FRAG_OFF_INC (IPV4_FRAG_SIZE >> 3)\r
395\r
396 DataLengthSent = IPV4_FRAG_SIZE - HdrSize;\r
397\r
398 StatCode = Ipv4Xmt (\r
399 Private,\r
400 GatewayIp,\r
401 sizeof (IPV4_HEADER),\r
402 sizeof (IPV4_HEADER) + HdrSize,\r
403 MessagePtr,\r
404 DataLengthSent,\r
405 Private->Function\r
406 );\r
407\r
408 if (EFI_ERROR (StatCode)) {\r
409 DEBUG (\r
410 (DEBUG_WARN,\r
411 "\nIp4Send() Exit #3 %xh (%r)",\r
412 StatCode,\r
413 StatCode)\r
414 );\r
415\r
416 return StatCode;\r
417 }\r
418\r
419 MessagePtr += DataLengthSent;\r
420 MessageLength -= DataLengthSent;\r
421 FragmentOffset += IPV4_FRAG_OFF_INC;\r
422 IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset);\r
423\r
424 while (MessageLength > IPV4_FRAG_SIZE) {\r
425 StatCode = Ipv4Xmt (\r
426 Private,\r
427 GatewayIp,\r
428 sizeof (IPV4_HEADER),\r
429 sizeof (IPV4_HEADER),\r
430 MessagePtr,\r
431 IPV4_FRAG_SIZE,\r
432 Private->Function\r
433 );\r
434\r
435 if (EFI_ERROR (StatCode)) {\r
436 DEBUG (\r
437 (DEBUG_WARN,\r
438 "\nIp4Send() Exit #3 %xh (%r)",\r
439 StatCode,\r
440 StatCode)\r
441 );\r
442\r
443 return StatCode;\r
444 }\r
445\r
446 MessagePtr += IPV4_FRAG_SIZE;\r
447 MessageLength -= IPV4_FRAG_SIZE;\r
448 FragmentOffset += IPV4_FRAG_OFF_INC;\r
449 IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset);\r
450 }\r
451\r
452 * (UINT8 *) (&IP_TX_HEADER.FragmentFields) &= ~(IP_MORE_FRAG >> 8);\r
453 HdrSize = 0;\r
454 }\r
455 //\r
456 // transmit\r
457 //\r
458 return Ipv4Xmt (\r
459 Private,\r
460 GatewayIp,\r
461 sizeof (IPV4_HEADER),\r
462 sizeof (IPV4_HEADER) + HdrSize,\r
463 MessagePtr,\r
464 MessageLength,\r
465 Private->Function\r
466 );\r
467}\r
468\r
469/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
470\r
471//\r
472// return true if dst IP in receive header matched with what's enabled\r
473//\r
474STATIC\r
475BOOLEAN\r
476IPgood (\r
477 PXE_BASECODE_DEVICE *Private,\r
478 IPV4_HEADER *IpHeader\r
479 )\r
480{\r
481 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
482 UINTN Index;\r
483\r
484 PxeBcMode = Private->EfiBc.Mode;\r
485\r
486 if (PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) {\r
487 return TRUE;\r
488 }\r
489\r
490 if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) &&\r
491 IS_MULTICAST (&IpHeader->DestAddr)\r
492 ) {\r
493 return TRUE;\r
494 }\r
495\r
496 if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) &&\r
497 PxeBcMode->StationIp.Addr[0] == IpHeader->DestAddr.L\r
498 ) {\r
499 return TRUE;\r
500 }\r
501\r
502 if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) && IpHeader->DestAddr.L == BROADCAST_IPv4) {\r
503 return TRUE;\r
504 }\r
505\r
506 for (Index = 0; Index < PxeBcMode->IpFilter.IpCnt; ++Index) {\r
507 if (IpHeader->DestAddr.L == PxeBcMode->IpFilter.IpList[Index].Addr[0]) {\r
508 return TRUE;\r
509 }\r
510 }\r
511\r
512 return FALSE;\r
513}\r
514\r
515/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
516\r
517//\r
518// receive up to MessageLength message into MessagePtr for protocol Prot\r
519// return message length, src/dest ips if select any, and pointer to protocol\r
520// header routine will filter based on source and/or dest ip if OpFlags set.\r
521//\r
522EFI_STATUS\r
523IpReceive (\r
524 PXE_BASECODE_DEVICE *Private,\r
525 PXE_OPFLAGS OpFlags,\r
526 EFI_IP_ADDRESS *SrcIpPtr,\r
527 EFI_IP_ADDRESS *DestIpPtr,\r
528 UINT8 Prot,\r
529 VOID *HeaderPtr,\r
530 UINTN HdrSize,\r
531 UINT8 *MessagePtr,\r
532 UINTN *MessageLengthPtr,\r
533 EFI_EVENT TimeoutEvent\r
534 )\r
535{\r
536 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
537 EFI_STATUS StatCode;\r
538 UINTN ByteCount;\r
539 UINTN FragmentCount;\r
540 UINTN ExpectedPacketLength;\r
541 UINTN Id;\r
542 BOOLEAN GotFirstFragment;\r
543 BOOLEAN GotLastFragment;\r
544\r
545 DEBUG (\r
546 (DEBUG_NET,\r
547 "\nIpReceive() Hdr=%Xh HdrSz=%d Data=%Xh DataSz=%d",\r
548 HeaderPtr,\r
549 HdrSize,\r
550 MessagePtr,\r
551 *MessageLengthPtr)\r
552 );\r
553\r
554 PxeBcMode = Private->EfiBc.Mode;\r
555 PxeBcMode->IcmpErrorReceived = FALSE;\r
556\r
557 ExpectedPacketLength = 0;\r
558 GotFirstFragment = FALSE;\r
559 GotLastFragment = FALSE;\r
560 FragmentCount = 0;\r
561 ByteCount = 0;\r
562 Id = 0;\r
563\r
564 for (;;) {\r
565 IPV4_HEADER IpHdr;\r
566 UINTN FFlds;\r
567 UINTN TotalLength;\r
568 UINTN FragmentOffset;\r
569 UINTN HeaderSize;\r
570 UINTN BufferSize;\r
571 UINTN IpHeaderLength;\r
572 UINTN DataLength;\r
573 UINT16 Protocol;\r
574 UINT8 *NextHdrPtr;\r
575 UINT8 *PacketPtr;\r
576\r
577 StatCode = WaitForReceive (\r
578 Private,\r
579 Private->Function,\r
580 TimeoutEvent,\r
581 &HeaderSize,\r
582 &BufferSize,\r
583 &Protocol\r
584 );\r
585\r
586 if (EFI_ERROR (StatCode)) {\r
587 return StatCode;\r
588 }\r
589\r
590 PacketPtr = Private->ReceiveBufferPtr + HeaderSize;\r
591\r
592 if (Protocol == PXE_PROTOCOL_ETHERNET_ARP) {\r
593 HandleArpReceive (\r
594 Private,\r
595 (ARP_PACKET *) PacketPtr,\r
596 Private->ReceiveBufferPtr\r
597 );\r
598\r
599 continue;\r
600 }\r
601\r
602 if (Protocol != PXE_PROTOCOL_ETHERNET_IP) {\r
603 continue;\r
604 }\r
605\r
606#define IpRxHeader ((IPV4_HEADER *) PacketPtr)\r
607\r
608 //\r
609 // filter for version & check sum\r
610 //\r
611 IpHeaderLength = IPV4_HEADER_LENGTH (IpRxHeader);\r
612\r
613 if ((IpRxHeader->VersionIhl >> 4) != IPVER4) {\r
614 continue;\r
615 }\r
616\r
617 if (IpChecksum ((UINT16 *) IpRxHeader, IpHeaderLength)) {\r
618 continue;\r
619 }\r
620\r
621 CopyMem (&IpHdr, IpRxHeader, sizeof (IpHdr));\r
622 TotalLength = NTOHS (IpHdr.TotalLength);\r
623\r
624 if (IpHdr.Protocol == PROT_TCP) {\r
625 //\r
626 // The NextHdrPtr is used to seed the header buffer we are passing back.\r
627 // That being the case, we want to see everything in pPkt which contains\r
628 // everything but the ethernet (or whatever) frame. IP + TCP in this case.\r
629 //\r
630 DataLength = TotalLength;\r
631 NextHdrPtr = PacketPtr;\r
632 } else {\r
633 DataLength = TotalLength - IpHeaderLength;\r
634 NextHdrPtr = PacketPtr + IpHeaderLength;\r
635 }\r
636 //\r
637 // If this is an ICMP, it might not be for us.\r
638 // Double check the state of the IP stack and the\r
639 // packet fields before assuming it is an ICMP\r
640 // error. ICMP requests are not supported by the\r
641 // PxeBc IP stack and should be ignored.\r
642 //\r
643 if (IpHdr.Protocol == PROT_ICMP) {\r
644 ICMPV4_HEADER *Icmpv4;\r
645\r
646 Icmpv4 = (ICMPV4_HEADER *) NextHdrPtr;\r
647\r
648 //\r
649 // For now only obvious ICMP error replies will be accepted by\r
650 // this stack. This still makes us vulnerable to DoS attacks.\r
651 // But at least we will not be killed by DHCP daemons.\r
652 //\r
653 switch (Icmpv4->Type) {\r
654 case ICMP_REDIRECT:\r
655 case ICMP_ECHO:\r
656 case ICMP_ROUTER_ADV:\r
657 case ICMP_ROUTER_SOLICIT:\r
658 case ICMP_TIMESTAMP:\r
659 case ICMP_TIMESTAMP_REPLY:\r
660 case ICMP_INFO_REQ:\r
661 case ICMP_INFO_REQ_REPLY:\r
662 case ICMP_SUBNET_MASK_REQ:\r
663 case ICMP_SUBNET_MASK_REPLY:\r
664 default:\r
665 continue;\r
666\r
667 //\r
668 // %%TBD - This should be implemented.\r
669 //\r
670 case ICMP_ECHO_REPLY:\r
671 continue;\r
672\r
673 case ICMP_DEST_UNREACHABLE:\r
674 case ICMP_TIME_EXCEEDED:\r
675 case ICMP_PARAMETER_PROBLEM:\r
676 case ICMP_SOURCE_QUENCH:\r
677 PxeBcMode->IcmpErrorReceived = TRUE;\r
678\r
679 CopyMem (\r
680 &PxeBcMode->IcmpError,\r
681 NextHdrPtr,\r
682 sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)\r
683 );\r
684\r
685 DEBUG (\r
686 (DEBUG_NET,\r
687 "\nIpReceive() Exit #1 %Xh (%r)",\r
688 EFI_ICMP_ERROR,\r
689 EFI_ICMP_ERROR)\r
690 );\r
691 }\r
692\r
693 return EFI_ICMP_ERROR;\r
694 }\r
695\r
696 if (IpHdr.Protocol == PROT_IGMP) {\r
697 HandleIgmp (Private, (IGMPV2_MESSAGE *) NextHdrPtr, DataLength);\r
698\r
699 DEBUG ((DEBUG_NET, "\n IGMP"));\r
700 continue;\r
701 }\r
702 //\r
703 // check for protocol\r
704 //\r
705 if (IpHdr.Protocol != Prot) {\r
706 continue;\r
707 }\r
708 //\r
709 // do filtering\r
710 //\r
711 if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) && SrcIpPtr && SrcIpPtr->Addr[0] != IpHdr.SrcAddr.L) {\r
712 DEBUG ((DEBUG_NET, "\n Not expected source IP address."));\r
713 continue;\r
714 }\r
715\r
716 if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) {\r
717 if (!IPgood (Private, &IpHdr)) {\r
718 continue;\r
719 }\r
720 } else if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP)) {\r
721 if (DestIpPtr == NULL) {\r
722 if (PxeBcMode->StationIp.Addr[0] != IpHdr.DestAddr.L) {\r
723 continue;\r
724 }\r
725 } else if (DestIpPtr->Addr[0] != IpHdr.DestAddr.L) {\r
726 continue;\r
727 }\r
728 }\r
729 //\r
730 // get some data we need\r
731 //\r
732 FFlds = NTOHS (IpHdr.FragmentFields);\r
733 FragmentOffset = ((FFlds & IP_FRAG_OFF_MSK) << 3);\r
734\r
735 /* Keep count of fragments that belong to this session.\r
736 * If we get packets with a different IP ID number,\r
737 * ignore them. Ignored packets should be handled\r
738 * by the upper level protocol.\r
739 */\r
740 if (FragmentCount == 0) {\r
741 Id = IpHdr.Id;\r
742\r
743 if (DestIpPtr != NULL) {\r
744 DestIpPtr->Addr[0] = IpHdr.DestAddr.L;\r
745 }\r
746\r
747 if (SrcIpPtr != NULL) {\r
748 SrcIpPtr->Addr[0] = IpHdr.SrcAddr.L;\r
749 }\r
750 } else {\r
751 if (IpHdr.Id != Id) {\r
752 continue;\r
753 }\r
754 }\r
755\r
756 ++FragmentCount;\r
757\r
758 /* Fragment management.\r
759 */\r
760 if (FragmentOffset == 0) {\r
761 /* This is the first fragment (may also be the\r
762 * only fragment).\r
763 */\r
764 GotFirstFragment = TRUE;\r
765\r
766 /* If there is a separate protocol header buffer,\r
767 * copy the header, adjust the data pointer and\r
768 * the data length.\r
769 */\r
770 if (HdrSize != 0) {\r
771 CopyMem (HeaderPtr, NextHdrPtr, HdrSize);\r
772\r
773 NextHdrPtr += HdrSize;\r
774 DataLength -= HdrSize;\r
775 }\r
776 } else {\r
777 /* If there is a separate protocol header buffer,\r
778 * adjust the fragment offset.\r
779 */\r
780 FragmentOffset -= HdrSize;\r
781 }\r
782\r
783 /* See if this is the last fragment.\r
784 */\r
785 if (!(FFlds & IP_MORE_FRAG)) {\r
786 //\r
787 // This is the last fragment (may also be the only fragment).\r
788 //\r
789 GotLastFragment = TRUE;\r
790\r
791 /* Compute the expected length of the assembled\r
792 * packet. This will be used to decide if we\r
793 * have gotten all of the fragments.\r
794 */\r
795 ExpectedPacketLength = FragmentOffset + DataLength;\r
796 }\r
797\r
798 DEBUG (\r
799 (DEBUG_NET,\r
800 "\n ID = %Xh Off = %d Len = %d",\r
801 Id,\r
802 FragmentOffset,\r
803 DataLength)\r
804 );\r
805\r
806 /* Check for receive buffer overflow.\r
807 */\r
808 if (FragmentOffset + DataLength > *MessageLengthPtr) {\r
809 /* There is not enough space in the receive\r
810 * buffer for the fragment.\r
811 */\r
812 DEBUG (\r
813 (DEBUG_NET,\r
814 "\nIpReceive() Exit #3 %Xh (%r)",\r
815 EFI_BUFFER_TOO_SMALL,\r
816 EFI_BUFFER_TOO_SMALL)\r
817 );\r
818\r
819 return EFI_BUFFER_TOO_SMALL;\r
820 }\r
821\r
822 /* Copy data into receive buffer.\r
823 */\r
824 if (DataLength != 0) {\r
825 DEBUG ((DEBUG_NET, " To = %Xh", MessagePtr + FragmentOffset));\r
826\r
827 CopyMem (MessagePtr + FragmentOffset, NextHdrPtr, DataLength);\r
828 ByteCount += DataLength;\r
829 }\r
830\r
831 /* If we have seen the first and last fragments and\r
832 * the receive byte count is at least as large as the\r
833 * expected byte count, return SUCCESS.\r
834 *\r
835 * We could be tricked by receiving a fragment twice\r
836 * but the upper level protocol should figure this\r
837 * out.\r
838 */\r
839 if (GotFirstFragment && GotLastFragment && ByteCount >= ExpectedPacketLength) {\r
840 *MessageLengthPtr = ExpectedPacketLength;\r
841 return EFI_SUCCESS;\r
842 }\r
843 }\r
844}\r
845\r
846/* eof - pxe_bc_ip.c */\r