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