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
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.
22 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
25 Check if two IP addresses are on the same subnet.
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.
32 @retval TRUE IP addresses are on the same subnet.
33 @retval FALSE IP addresses are on different subnets.
39 IN EFI_IP_ADDRESS
*Ip1
,
40 IN EFI_IP_ADDRESS
*Ip2
,
41 IN EFI_IP_ADDRESS
*SubnetMask
44 if (IpLength
== 0 || Ip1
== NULL
|| Ip2
== NULL
|| SubnetMask
== NULL
) {
48 while (IpLength
-- != 0) {
49 if ((Ip1
->v6
.Addr
[IpLength
] ^ Ip2
->v6
.Addr
[IpLength
]) & SubnetMask
->v6
.Addr
[IpLength
]) {
57 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
60 Add router to router table.
62 @param Private Pointer PxeBc instance data.
63 @param RouterIpPtr Pointer to router IP address.
70 IN PXE_BASECODE_DEVICE
*Private
,
71 IN EFI_IP_ADDRESS
*RouterIpPtr
74 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
77 if (Private
== NULL
|| RouterIpPtr
== NULL
) {
81 PxeBcMode
= Private
->EfiBc
.Mode
;
84 // if we are filled up or this is not on the same subnet, forget it
86 if ((PxeBcMode
->RouteTableEntries
== PXE_ROUTER_TABLE_SIZE
) ||
87 !OnSameSubnet(Private
->IpLength
, &PxeBcMode
->StationIp
, RouterIpPtr
, &PxeBcMode
->SubnetMask
)) {
91 // make sure we don't already have it
93 for (Index
= 0; Index
< PxeBcMode
->RouteTableEntries
; ++Index
) {
95 &PxeBcMode
->RouteTable
[Index
].GwAddr
,
106 &PxeBcMode
->RouteTable
[PxeBcMode
->RouteTableEntries
],
107 sizeof (EFI_PXE_BASE_CODE_ROUTE_ENTRY
)
111 &PxeBcMode
->RouteTable
[PxeBcMode
->RouteTableEntries
++].GwAddr
,
117 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
120 // return router ip to use for DestIp (0 if none)
125 PXE_BASECODE_DEVICE
*Private
,
126 EFI_IP_ADDRESS
*DestIpPtr
129 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
132 if (Private
== NULL
|| DestIpPtr
== NULL
) {
136 PxeBcMode
= Private
->EfiBc
.Mode
;
138 for (Index
= 0; Index
< PxeBcMode
->RouteTableEntries
; ++Index
) {
141 &PxeBcMode
->RouteTable
[Index
].IpAddr
,
143 &PxeBcMode
->RouteTable
[Index
].SubnetMask
145 return &PxeBcMode
->RouteTable
[Index
].GwAddr
;
152 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
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
160 #define IP_TX_BUFFER ((IPV4_BUFFER *) Private->TransmitBufferPtr)
161 #define IP_TX_HEADER IP_TX_BUFFER->IpHeader
165 PXE_BASECODE_DEVICE
*Private
,
167 UINTN IpHeaderLength
,
168 UINTN TotalHeaderLength
,
171 EFI_PXE_BASE_CODE_FUNCTION Function
174 EFI_MAC_ADDRESS DestMac
;
175 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
176 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
180 Snp
= Private
->SimpleNetwork
;
181 PxeBcMode
= Private
->EfiBc
.Mode
;
182 StatCode
= EFI_SUCCESS
;
183 PacketLength
= TotalHeaderLength
+ DataLength
;
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
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
);
200 &PxeBcMode
->StationIp
,
201 (EFI_IP_ADDRESS
*) &IP_TX_HEADER
.DestAddr
,
202 &PxeBcMode
->SubnetMask
204 Ip
= IP_TX_HEADER
.DestAddr
.L
;
205 } else if (GatewayIp
!= 0) {
208 EFI_IP_ADDRESS
*TmpIp
;
210 TmpIp
= GetRouterIp (Private
, (EFI_IP_ADDRESS
*) &IP_TX_HEADER
.DestAddr
);
215 "\nIpv4Xmit() Exit #1 %xh (%r)",
220 return EFI_NO_RESPONSE
;
231 (EFI_IP_ADDRESS
*) &Ip
,
232 (EFI_MAC_ADDRESS
*) &DestMac
234 if (!PxeBcMode
->AutoArp
) {
237 "\nIpv4Xmit() Exit #2 %xh (%r)",
242 return EFI_DEVICE_ERROR
;
246 (EFI_IP_ADDRESS
*) &Ip
,
247 (EFI_MAC_ADDRESS
*) &DestMac
253 if (EFI_ERROR (StatCode
)) {
254 DEBUG ((DEBUG_WARN
, "\nIpv4Xmit() Exit #3 %xh (%r)", StatCode
, StatCode
));
258 // fill in packet info
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
);
270 (UINT8
*) &IP_TX_HEADER
- Snp
->Mode
->MediaHeaderSize
,
274 PXE_PROTOCOL_ETHERNET_IP
,
279 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
282 // send ipv4 packet with option
286 PXE_BASECODE_DEVICE
*Private
,
294 EFI_PXE_BASE_CODE_FUNCTION Function
297 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
300 PxeBcMode
= Private
->EfiBc
.Mode
;
301 HdrLth
= sizeof (IPV4_HEADER
) + OptionLength
;
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
);
322 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
325 // send MessageLength message at MessagePtr - higher level protocol header already in TransmitBufferPtr, length HdrSize
329 PXE_BASECODE_DEVICE
*Private
, // pointer to instance data
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
343 TotDataLength
= HdrSize
+ MessageLength
;
345 if (TotDataLength
> MAX_IPV4_DATA_SIZE
) {
348 "\nIp4Send() Exit #1 %xh (%r)",
353 return EFI_BAD_BUFFER_SIZE
;
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
);
364 *(UINT8
*) (&IP_TX_HEADER
.FragmentFields
) = IP_NO_FRAG
>> 8;
367 // check for need to fragment
369 if (TotDataLength
> MAX_IPV4_FRAME_DATA_SIZE
) {
370 UINTN DataLengthSent
;
371 UINT16 FragmentOffset
;
373 FragmentOffset
= IP_MORE_FRAG
;
380 "\nIp4Send() Exit #2 %xh (%r)",
385 return EFI_BAD_BUFFER_SIZE
;
388 // send out in fragments - first includes upper level header
389 // all are max and include more frag bit except last
391 * (UINT8
*) (&IP_TX_HEADER
.FragmentFields
) = IP_MORE_FRAG
>> 8;
393 #define IPV4_FRAG_SIZE (MAX_IPV4_FRAME_DATA_SIZE & 0xfff8)
394 #define IPV4_FRAG_OFF_INC (IPV4_FRAG_SIZE >> 3)
396 DataLengthSent
= IPV4_FRAG_SIZE
- HdrSize
;
401 sizeof (IPV4_HEADER
),
402 sizeof (IPV4_HEADER
) + HdrSize
,
408 if (EFI_ERROR (StatCode
)) {
411 "\nIp4Send() Exit #3 %xh (%r)",
419 MessagePtr
+= DataLengthSent
;
420 MessageLength
-= DataLengthSent
;
421 FragmentOffset
+= IPV4_FRAG_OFF_INC
;
422 IP_TX_HEADER
.FragmentFields
= HTONS (FragmentOffset
);
424 while (MessageLength
> IPV4_FRAG_SIZE
) {
428 sizeof (IPV4_HEADER
),
429 sizeof (IPV4_HEADER
),
435 if (EFI_ERROR (StatCode
)) {
438 "\nIp4Send() Exit #3 %xh (%r)",
446 MessagePtr
+= IPV4_FRAG_SIZE
;
447 MessageLength
-= IPV4_FRAG_SIZE
;
448 FragmentOffset
+= IPV4_FRAG_OFF_INC
;
449 IP_TX_HEADER
.FragmentFields
= HTONS (FragmentOffset
);
452 * (UINT8
*) (&IP_TX_HEADER
.FragmentFields
) &= ~(IP_MORE_FRAG
>> 8);
461 sizeof (IPV4_HEADER
),
462 sizeof (IPV4_HEADER
) + HdrSize
,
469 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
472 // return true if dst IP in receive header matched with what's enabled
477 PXE_BASECODE_DEVICE
*Private
,
478 IPV4_HEADER
*IpHeader
481 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
484 PxeBcMode
= Private
->EfiBc
.Mode
;
486 if (PxeBcMode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS
) {
490 if ((PxeBcMode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST
) &&
491 IS_MULTICAST (&IpHeader
->DestAddr
)
496 if ((PxeBcMode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
) &&
497 PxeBcMode
->StationIp
.Addr
[0] == IpHeader
->DestAddr
.L
502 if ((PxeBcMode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST
) && IpHeader
->DestAddr
.L
== BROADCAST_IPv4
) {
506 for (Index
= 0; Index
< PxeBcMode
->IpFilter
.IpCnt
; ++Index
) {
507 if (IpHeader
->DestAddr
.L
== PxeBcMode
->IpFilter
.IpList
[Index
].Addr
[0]) {
515 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
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.
524 PXE_BASECODE_DEVICE
*Private
,
526 EFI_IP_ADDRESS
*SrcIpPtr
,
527 EFI_IP_ADDRESS
*DestIpPtr
,
532 UINTN
*MessageLengthPtr
,
533 EFI_EVENT TimeoutEvent
536 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
540 UINTN ExpectedPacketLength
;
542 BOOLEAN GotFirstFragment
;
543 BOOLEAN GotLastFragment
;
547 "\nIpReceive() Hdr=%Xh HdrSz=%d Data=%Xh DataSz=%d",
554 PxeBcMode
= Private
->EfiBc
.Mode
;
555 PxeBcMode
->IcmpErrorReceived
= FALSE
;
557 ExpectedPacketLength
= 0;
558 GotFirstFragment
= FALSE
;
559 GotLastFragment
= FALSE
;
568 UINTN FragmentOffset
;
571 UINTN IpHeaderLength
;
577 StatCode
= WaitForReceive (
586 if (EFI_ERROR (StatCode
)) {
590 PacketPtr
= Private
->ReceiveBufferPtr
+ HeaderSize
;
592 if (Protocol
== PXE_PROTOCOL_ETHERNET_ARP
) {
595 (ARP_PACKET
*) PacketPtr
,
596 Private
->ReceiveBufferPtr
602 if (Protocol
!= PXE_PROTOCOL_ETHERNET_IP
) {
606 #define IpRxHeader ((IPV4_HEADER *) PacketPtr)
609 // filter for version & check sum
611 IpHeaderLength
= IPV4_HEADER_LENGTH (IpRxHeader
);
613 if ((IpRxHeader
->VersionIhl
>> 4) != IPVER4
) {
617 if (IpChecksum ((UINT16
*) IpRxHeader
, IpHeaderLength
)) {
621 CopyMem (&IpHdr
, IpRxHeader
, sizeof (IpHdr
));
622 TotalLength
= NTOHS (IpHdr
.TotalLength
);
624 if (IpHdr
.Protocol
== PROT_TCP
) {
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.
630 DataLength
= TotalLength
;
631 NextHdrPtr
= PacketPtr
;
633 DataLength
= TotalLength
- IpHeaderLength
;
634 NextHdrPtr
= PacketPtr
+ IpHeaderLength
;
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.
643 if (IpHdr
.Protocol
== PROT_ICMP
) {
644 ICMPV4_HEADER
*Icmpv4
;
646 Icmpv4
= (ICMPV4_HEADER
*) NextHdrPtr
;
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.
653 switch (Icmpv4
->Type
) {
656 case ICMP_ROUTER_ADV
:
657 case ICMP_ROUTER_SOLICIT
:
659 case ICMP_TIMESTAMP_REPLY
:
661 case ICMP_INFO_REQ_REPLY
:
662 case ICMP_SUBNET_MASK_REQ
:
663 case ICMP_SUBNET_MASK_REPLY
:
668 // %%TBD - This should be implemented.
670 case ICMP_ECHO_REPLY
:
673 case ICMP_DEST_UNREACHABLE
:
674 case ICMP_TIME_EXCEEDED
:
675 case ICMP_PARAMETER_PROBLEM
:
676 case ICMP_SOURCE_QUENCH
:
677 PxeBcMode
->IcmpErrorReceived
= TRUE
;
680 &PxeBcMode
->IcmpError
,
682 sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)
687 "\nIpReceive() Exit #1 %Xh (%r)",
693 return EFI_ICMP_ERROR
;
696 if (IpHdr
.Protocol
== PROT_IGMP
) {
697 HandleIgmp (Private
, (IGMPV2_MESSAGE
*) NextHdrPtr
, DataLength
);
699 DEBUG ((DEBUG_NET
, "\n IGMP"));
703 // check for protocol
705 if (IpHdr
.Protocol
!= Prot
) {
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."));
716 if (OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER
) {
717 if (!IPgood (Private
, &IpHdr
)) {
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
) {
725 } else if (DestIpPtr
->Addr
[0] != IpHdr
.DestAddr
.L
) {
730 // get some data we need
732 FFlds
= NTOHS (IpHdr
.FragmentFields
);
733 FragmentOffset
= ((FFlds
& IP_FRAG_OFF_MSK
) << 3);
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.
740 if (FragmentCount
== 0) {
743 if (DestIpPtr
!= NULL
) {
744 DestIpPtr
->Addr
[0] = IpHdr
.DestAddr
.L
;
747 if (SrcIpPtr
!= NULL
) {
748 SrcIpPtr
->Addr
[0] = IpHdr
.SrcAddr
.L
;
751 if (IpHdr
.Id
!= Id
) {
758 /* Fragment management.
760 if (FragmentOffset
== 0) {
761 /* This is the first fragment (may also be the
764 GotFirstFragment
= TRUE
;
766 /* If there is a separate protocol header buffer,
767 * copy the header, adjust the data pointer and
771 CopyMem (HeaderPtr
, NextHdrPtr
, HdrSize
);
773 NextHdrPtr
+= HdrSize
;
774 DataLength
-= HdrSize
;
777 /* If there is a separate protocol header buffer,
778 * adjust the fragment offset.
780 FragmentOffset
-= HdrSize
;
783 /* See if this is the last fragment.
785 if (!(FFlds
& IP_MORE_FRAG
)) {
787 // This is the last fragment (may also be the only fragment).
789 GotLastFragment
= TRUE
;
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.
795 ExpectedPacketLength
= FragmentOffset
+ DataLength
;
800 "\n ID = %Xh Off = %d Len = %d",
806 /* Check for receive buffer overflow.
808 if (FragmentOffset
+ DataLength
> *MessageLengthPtr
) {
809 /* There is not enough space in the receive
810 * buffer for the fragment.
814 "\nIpReceive() Exit #3 %Xh (%r)",
815 EFI_BUFFER_TOO_SMALL
,
816 EFI_BUFFER_TOO_SMALL
)
819 return EFI_BUFFER_TOO_SMALL
;
822 /* Copy data into receive buffer.
824 if (DataLength
!= 0) {
825 DEBUG ((DEBUG_NET
, " To = %Xh", MessagePtr
+ FragmentOffset
));
827 CopyMem (MessagePtr
+ FragmentOffset
, NextHdrPtr
, DataLength
);
828 ByteCount
+= DataLength
;
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.
835 * We could be tricked by receiving a fragment twice
836 * but the upper level protocol should figure this
839 if (GotFirstFragment
&& GotLastFragment
&& ByteCount
>= ExpectedPacketLength
) {
840 *MessageLengthPtr
= ExpectedPacketLength
;
846 /* eof - pxe_bc_ip.c */