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)
124 PXE_BASECODE_DEVICE
*Private
,
125 EFI_IP_ADDRESS
*DestIpPtr
128 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
131 if (Private
== NULL
|| DestIpPtr
== NULL
) {
135 PxeBcMode
= Private
->EfiBc
.Mode
;
137 for (Index
= 0; Index
< PxeBcMode
->RouteTableEntries
; ++Index
) {
140 &PxeBcMode
->RouteTable
[Index
].IpAddr
,
142 &PxeBcMode
->RouteTable
[Index
].SubnetMask
144 return &PxeBcMode
->RouteTable
[Index
].GwAddr
;
151 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
154 // routine to send ipv4 packet
155 // ipv4 header of length HdrLth in TransmitBufferPtr
156 // routine fills in ipv4hdr Ver_Hdl, TotalLength, and Checksum, moves in Data
157 // and gets dest MAC address
159 #define IP_TX_BUFFER ((IPV4_BUFFER *) Private->TransmitBufferPtr)
160 #define IP_TX_HEADER IP_TX_BUFFER->IpHeader
164 PXE_BASECODE_DEVICE
*Private
,
166 UINTN IpHeaderLength
,
167 UINTN TotalHeaderLength
,
170 EFI_PXE_BASE_CODE_FUNCTION Function
173 EFI_MAC_ADDRESS DestMac
;
174 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
175 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
179 Snp
= Private
->SimpleNetwork
;
180 PxeBcMode
= Private
->EfiBc
.Mode
;
181 StatCode
= EFI_SUCCESS
;
182 PacketLength
= TotalHeaderLength
+ DataLength
;
185 // get dest MAC address
186 // multicast - convert to hw equiv
187 // unicast on same net, use arp
188 // on different net, arp for router
190 if (IP_TX_HEADER
.DestAddr
.L
== BROADCAST_IPv4
) {
191 CopyMem (&DestMac
, &Snp
->Mode
->BroadcastAddress
, sizeof (DestMac
));
192 } else if (IS_MULTICAST (&IP_TX_HEADER
.DestAddr
)) {
193 StatCode
= (*Snp
->MCastIpToMac
) (Snp
, PxeBcMode
->UsingIpv6
, (EFI_IP_ADDRESS
*) &IP_TX_HEADER
.DestAddr
, &DestMac
);
199 &PxeBcMode
->StationIp
,
200 (EFI_IP_ADDRESS
*) &IP_TX_HEADER
.DestAddr
,
201 &PxeBcMode
->SubnetMask
203 Ip
= IP_TX_HEADER
.DestAddr
.L
;
204 } else if (GatewayIp
!= 0) {
207 EFI_IP_ADDRESS
*TmpIp
;
209 TmpIp
= GetRouterIp (Private
, (EFI_IP_ADDRESS
*) &IP_TX_HEADER
.DestAddr
);
214 "\nIpv4Xmit() Exit #1 %xh (%r)",
219 return EFI_NO_RESPONSE
;
230 (EFI_IP_ADDRESS
*) &Ip
,
231 (EFI_MAC_ADDRESS
*) &DestMac
233 if (!PxeBcMode
->AutoArp
) {
236 "\nIpv4Xmit() Exit #2 %xh (%r)",
241 return EFI_DEVICE_ERROR
;
245 (EFI_IP_ADDRESS
*) &Ip
,
246 (EFI_MAC_ADDRESS
*) &DestMac
252 if (EFI_ERROR (StatCode
)) {
253 DEBUG ((DEBUG_WARN
, "\nIpv4Xmit() Exit #3 %xh (%r)", StatCode
, StatCode
));
257 // fill in packet info
259 SET_IPV4_VER_HDL (&IP_TX_HEADER
, IpHeaderLength
);
260 IP_TX_HEADER
.TotalLength
= HTONS (PacketLength
);
261 IP_TX_HEADER
.HeaderChecksum
= IpChecksum ((UINT16
*) &IP_TX_HEADER
, IpHeaderLength
);
262 CopyMem (((UINT8
*) &IP_TX_HEADER
) + TotalHeaderLength
, Data
, DataLength
);
269 (UINT8
*) &IP_TX_HEADER
- Snp
->Mode
->MediaHeaderSize
,
273 PXE_PROTOCOL_ETHERNET_IP
,
278 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
281 // send ipv4 packet with option
285 PXE_BASECODE_DEVICE
*Private
,
293 EFI_PXE_BASE_CODE_FUNCTION Function
296 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
299 PxeBcMode
= Private
->EfiBc
.Mode
;
300 HdrLth
= sizeof (IPV4_HEADER
) + OptionLength
;
302 ZeroMem ((VOID
*) &IP_TX_HEADER
, sizeof (IPV4_HEADER
));
303 IP_TX_HEADER
.TimeToLive
= PxeBcMode
->TTL
;
304 IP_TX_HEADER
.TypeOfService
= PxeBcMode
->ToS
;
305 IP_TX_HEADER
.Protocol
= Prot
;
306 IP_TX_HEADER
.SrcAddr
.L
= *(UINT32
*) &PxeBcMode
->StationIp
;
307 IP_TX_HEADER
.DestAddr
.L
= DestIp
;
308 IP_TX_HEADER
.Id
= Random (Private
);
309 CopyMem (IP_TX_BUFFER
->u
.Data
, Option
, OptionLength
);
321 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
324 // send MessageLength message at MessagePtr - higher level protocol header already in TransmitBufferPtr, length HdrSize
328 PXE_BASECODE_DEVICE
*Private
, // pointer to instance data
330 UINT8 Prot
, // protocol
331 UINT32 SrcIp
, // Source IP address
332 UINT32 DestIp
, // Destination IP address
333 UINT32 GatewayIp
, // used if not NULL and needed
334 UINTN HdrSize
, // protocol header byte length
335 UINT8
*MessagePtr
, // pointer to data
336 UINTN MessageLength
// data byte length
342 TotDataLength
= HdrSize
+ MessageLength
;
344 if (TotDataLength
> MAX_IPV4_DATA_SIZE
) {
347 "\nIp4Send() Exit #1 %xh (%r)",
352 return EFI_BAD_BUFFER_SIZE
;
355 ZeroMem ((VOID
*) &IP_TX_HEADER
, sizeof (IPV4_HEADER
));
356 IP_TX_HEADER
.TimeToLive
= DEFAULT_TTL
;
357 IP_TX_HEADER
.Protocol
= Prot
;
358 IP_TX_HEADER
.SrcAddr
.L
= SrcIp
;
359 IP_TX_HEADER
.DestAddr
.L
= DestIp
;
360 IP_TX_HEADER
.Id
= Random (Private
);
363 *(UINT8
*) (&IP_TX_HEADER
.FragmentFields
) = IP_NO_FRAG
>> 8;
366 // check for need to fragment
368 if (TotDataLength
> MAX_IPV4_FRAME_DATA_SIZE
) {
369 UINTN DataLengthSent
;
370 UINT16 FragmentOffset
;
372 FragmentOffset
= IP_MORE_FRAG
;
379 "\nIp4Send() Exit #2 %xh (%r)",
384 return EFI_BAD_BUFFER_SIZE
;
387 // send out in fragments - first includes upper level header
388 // all are max and include more frag bit except last
390 * (UINT8
*) (&IP_TX_HEADER
.FragmentFields
) = IP_MORE_FRAG
>> 8;
392 #define IPV4_FRAG_SIZE (MAX_IPV4_FRAME_DATA_SIZE & 0xfff8)
393 #define IPV4_FRAG_OFF_INC (IPV4_FRAG_SIZE >> 3)
395 DataLengthSent
= IPV4_FRAG_SIZE
- HdrSize
;
400 sizeof (IPV4_HEADER
),
401 sizeof (IPV4_HEADER
) + HdrSize
,
407 if (EFI_ERROR (StatCode
)) {
410 "\nIp4Send() Exit #3 %xh (%r)",
418 MessagePtr
+= DataLengthSent
;
419 MessageLength
-= DataLengthSent
;
420 FragmentOffset
+= IPV4_FRAG_OFF_INC
;
421 IP_TX_HEADER
.FragmentFields
= HTONS (FragmentOffset
);
423 while (MessageLength
> IPV4_FRAG_SIZE
) {
427 sizeof (IPV4_HEADER
),
428 sizeof (IPV4_HEADER
),
434 if (EFI_ERROR (StatCode
)) {
437 "\nIp4Send() Exit #3 %xh (%r)",
445 MessagePtr
+= IPV4_FRAG_SIZE
;
446 MessageLength
-= IPV4_FRAG_SIZE
;
447 FragmentOffset
+= IPV4_FRAG_OFF_INC
;
448 IP_TX_HEADER
.FragmentFields
= HTONS (FragmentOffset
);
451 * (UINT8
*) (&IP_TX_HEADER
.FragmentFields
) &= ~(IP_MORE_FRAG
>> 8);
460 sizeof (IPV4_HEADER
),
461 sizeof (IPV4_HEADER
) + HdrSize
,
468 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
471 // return true if dst IP in receive header matched with what's enabled
475 PXE_BASECODE_DEVICE
*Private
,
476 IPV4_HEADER
*IpHeader
479 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
482 PxeBcMode
= Private
->EfiBc
.Mode
;
484 if (PxeBcMode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS
) {
488 if ((PxeBcMode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST
) &&
489 IS_MULTICAST (&IpHeader
->DestAddr
)
494 if ((PxeBcMode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
) &&
495 PxeBcMode
->StationIp
.Addr
[0] == IpHeader
->DestAddr
.L
500 if ((PxeBcMode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST
) && IpHeader
->DestAddr
.L
== BROADCAST_IPv4
) {
504 for (Index
= 0; Index
< PxeBcMode
->IpFilter
.IpCnt
; ++Index
) {
505 if (IpHeader
->DestAddr
.L
== PxeBcMode
->IpFilter
.IpList
[Index
].Addr
[0]) {
513 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
516 // receive up to MessageLength message into MessagePtr for protocol Prot
517 // return message length, src/dest ips if select any, and pointer to protocol
518 // header routine will filter based on source and/or dest ip if OpFlags set.
522 PXE_BASECODE_DEVICE
*Private
,
524 EFI_IP_ADDRESS
*SrcIpPtr
,
525 EFI_IP_ADDRESS
*DestIpPtr
,
530 UINTN
*MessageLengthPtr
,
531 EFI_EVENT TimeoutEvent
534 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
538 UINTN ExpectedPacketLength
;
540 BOOLEAN GotFirstFragment
;
541 BOOLEAN GotLastFragment
;
545 "\nIpReceive() Hdr=%Xh HdrSz=%d Data=%Xh DataSz=%d",
552 PxeBcMode
= Private
->EfiBc
.Mode
;
553 PxeBcMode
->IcmpErrorReceived
= FALSE
;
555 ExpectedPacketLength
= 0;
556 GotFirstFragment
= FALSE
;
557 GotLastFragment
= FALSE
;
566 UINTN FragmentOffset
;
569 UINTN IpHeaderLength
;
575 StatCode
= WaitForReceive (
584 if (EFI_ERROR (StatCode
)) {
588 PacketPtr
= Private
->ReceiveBufferPtr
+ HeaderSize
;
590 if (Protocol
== PXE_PROTOCOL_ETHERNET_ARP
) {
593 (ARP_PACKET
*) PacketPtr
,
594 Private
->ReceiveBufferPtr
600 if (Protocol
!= PXE_PROTOCOL_ETHERNET_IP
) {
604 #define IpRxHeader ((IPV4_HEADER *) PacketPtr)
607 // filter for version & check sum
609 IpHeaderLength
= IPV4_HEADER_LENGTH (IpRxHeader
);
611 if ((IpRxHeader
->VersionIhl
>> 4) != IPVER4
) {
615 if (IpChecksum ((UINT16
*) IpRxHeader
, IpHeaderLength
)) {
619 CopyMem (&IpHdr
, IpRxHeader
, sizeof (IpHdr
));
620 TotalLength
= NTOHS (IpHdr
.TotalLength
);
622 if (IpHdr
.Protocol
== PROT_TCP
) {
624 // The NextHdrPtr is used to seed the header buffer we are passing back.
625 // That being the case, we want to see everything in pPkt which contains
626 // everything but the ethernet (or whatever) frame. IP + TCP in this case.
628 DataLength
= TotalLength
;
629 NextHdrPtr
= PacketPtr
;
631 DataLength
= TotalLength
- IpHeaderLength
;
632 NextHdrPtr
= PacketPtr
+ IpHeaderLength
;
635 // If this is an ICMP, it might not be for us.
636 // Double check the state of the IP stack and the
637 // packet fields before assuming it is an ICMP
638 // error. ICMP requests are not supported by the
639 // PxeBc IP stack and should be ignored.
641 if (IpHdr
.Protocol
== PROT_ICMP
) {
642 ICMPV4_HEADER
*Icmpv4
;
644 Icmpv4
= (ICMPV4_HEADER
*) NextHdrPtr
;
647 // For now only obvious ICMP error replies will be accepted by
648 // this stack. This still makes us vulnerable to DoS attacks.
649 // But at least we will not be killed by DHCP daemons.
651 switch (Icmpv4
->Type
) {
654 case ICMP_ROUTER_ADV
:
655 case ICMP_ROUTER_SOLICIT
:
657 case ICMP_TIMESTAMP_REPLY
:
659 case ICMP_INFO_REQ_REPLY
:
660 case ICMP_SUBNET_MASK_REQ
:
661 case ICMP_SUBNET_MASK_REPLY
:
666 // %%TBD - This should be implemented.
668 case ICMP_ECHO_REPLY
:
671 case ICMP_DEST_UNREACHABLE
:
672 case ICMP_TIME_EXCEEDED
:
673 case ICMP_PARAMETER_PROBLEM
:
674 case ICMP_SOURCE_QUENCH
:
675 PxeBcMode
->IcmpErrorReceived
= TRUE
;
678 &PxeBcMode
->IcmpError
,
680 sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)
685 "\nIpReceive() Exit #1 %Xh (%r)",
691 return EFI_ICMP_ERROR
;
694 if (IpHdr
.Protocol
== PROT_IGMP
) {
695 HandleIgmp (Private
, (IGMPV2_MESSAGE
*) NextHdrPtr
, DataLength
);
697 DEBUG ((DEBUG_NET
, "\n IGMP"));
701 // check for protocol
703 if (IpHdr
.Protocol
!= Prot
) {
709 if (!(OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
) && SrcIpPtr
&& SrcIpPtr
->Addr
[0] != IpHdr
.SrcAddr
.L
) {
710 DEBUG ((DEBUG_NET
, "\n Not expected source IP address."));
714 if (OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER
) {
715 if (!IPgood (Private
, &IpHdr
)) {
718 } else if (!(OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
)) {
719 if (DestIpPtr
== NULL
) {
720 if (PxeBcMode
->StationIp
.Addr
[0] != IpHdr
.DestAddr
.L
) {
723 } else if (DestIpPtr
->Addr
[0] != IpHdr
.DestAddr
.L
) {
728 // get some data we need
730 FFlds
= NTOHS (IpHdr
.FragmentFields
);
731 FragmentOffset
= ((FFlds
& IP_FRAG_OFF_MSK
) << 3);
733 /* Keep count of fragments that belong to this session.
734 * If we get packets with a different IP ID number,
735 * ignore them. Ignored packets should be handled
736 * by the upper level protocol.
738 if (FragmentCount
== 0) {
741 if (DestIpPtr
!= NULL
) {
742 DestIpPtr
->Addr
[0] = IpHdr
.DestAddr
.L
;
745 if (SrcIpPtr
!= NULL
) {
746 SrcIpPtr
->Addr
[0] = IpHdr
.SrcAddr
.L
;
749 if (IpHdr
.Id
!= Id
) {
756 /* Fragment management.
758 if (FragmentOffset
== 0) {
759 /* This is the first fragment (may also be the
762 GotFirstFragment
= TRUE
;
764 /* If there is a separate protocol header buffer,
765 * copy the header, adjust the data pointer and
769 CopyMem (HeaderPtr
, NextHdrPtr
, HdrSize
);
771 NextHdrPtr
+= HdrSize
;
772 DataLength
-= HdrSize
;
775 /* If there is a separate protocol header buffer,
776 * adjust the fragment offset.
778 FragmentOffset
-= HdrSize
;
781 /* See if this is the last fragment.
783 if (!(FFlds
& IP_MORE_FRAG
)) {
785 // This is the last fragment (may also be the only fragment).
787 GotLastFragment
= TRUE
;
789 /* Compute the expected length of the assembled
790 * packet. This will be used to decide if we
791 * have gotten all of the fragments.
793 ExpectedPacketLength
= FragmentOffset
+ DataLength
;
798 "\n ID = %Xh Off = %d Len = %d",
804 /* Check for receive buffer overflow.
806 if (FragmentOffset
+ DataLength
> *MessageLengthPtr
) {
807 /* There is not enough space in the receive
808 * buffer for the fragment.
812 "\nIpReceive() Exit #3 %Xh (%r)",
813 EFI_BUFFER_TOO_SMALL
,
814 EFI_BUFFER_TOO_SMALL
)
817 return EFI_BUFFER_TOO_SMALL
;
820 /* Copy data into receive buffer.
822 if (DataLength
!= 0) {
823 DEBUG ((DEBUG_NET
, " To = %Xh", MessagePtr
+ FragmentOffset
));
825 CopyMem (MessagePtr
+ FragmentOffset
, NextHdrPtr
, DataLength
);
826 ByteCount
+= DataLength
;
829 /* If we have seen the first and last fragments and
830 * the receive byte count is at least as large as the
831 * expected byte count, return SUCCESS.
833 * We could be tricked by receiving a fragment twice
834 * but the upper level protocol should figure this
837 if (GotFirstFragment
&& GotLastFragment
&& ByteCount
>= ExpectedPacketLength
) {
838 *MessageLengthPtr
= ExpectedPacketLength
;
844 /* eof - pxe_bc_ip.c */