3 Copyright (c) 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
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 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
26 IN EFI_IP_ADDRESS
*Ip1
,
27 IN EFI_IP_ADDRESS
*Ip2
,
28 IN EFI_IP_ADDRESS
*SubnetMask
33 Check if two IP addresses are on the same subnet.
36 IpLength - Length of IP address in bytes.
37 Ip1 - IP address to check.
38 Ip2 - IP address to check.
39 SubnetMask - Subnet mask to check with.
42 TRUE - IP addresses are on the same subnet.
43 FALSE - IP addresses are on different subnets.
47 if (IpLength
== 0 || Ip1
== NULL
|| Ip2
== NULL
|| SubnetMask
== NULL
) {
51 while (IpLength
-- != 0) {
52 if ((Ip1
->v6
.Addr
[IpLength
] ^ Ip2
->v6
.Addr
[IpLength
]) & SubnetMask
->v6
.Addr
[IpLength
]) {
60 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
63 IN PXE_BASECODE_DEVICE
*Private
,
64 IN EFI_IP_ADDRESS
*RouterIpPtr
69 Add router to router table.
72 Private - Pointer PxeBc instance data.
73 RouterIpPtr - Pointer to router IP address.
80 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
83 if (Private
== NULL
|| RouterIpPtr
== NULL
) {
87 PxeBcMode
= Private
->EfiBc
.Mode
;
90 // if we are filled up or this is not on the same subnet, forget it
92 if ((PxeBcMode
->RouteTableEntries
== PXE_ROUTER_TABLE_SIZE
) ||
93 !OnSameSubnet(Private
->IpLength
, &PxeBcMode
->StationIp
, RouterIpPtr
, &PxeBcMode
->SubnetMask
)) {
97 // make sure we don't already have it
99 for (Index
= 0; Index
< PxeBcMode
->RouteTableEntries
; ++Index
) {
101 &PxeBcMode
->RouteTable
[Index
].GwAddr
,
112 &PxeBcMode
->RouteTable
[PxeBcMode
->RouteTableEntries
],
113 sizeof (EFI_PXE_BASE_CODE_ROUTE_ENTRY
)
117 &PxeBcMode
->RouteTable
[PxeBcMode
->RouteTableEntries
++].GwAddr
,
123 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
126 // return router ip to use for DestIp (0 if none)
131 PXE_BASECODE_DEVICE
*Private
,
132 EFI_IP_ADDRESS
*DestIpPtr
135 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
138 if (Private
== NULL
|| DestIpPtr
== NULL
) {
142 PxeBcMode
= Private
->EfiBc
.Mode
;
144 for (Index
= 0; Index
< PxeBcMode
->RouteTableEntries
; ++Index
) {
147 &PxeBcMode
->RouteTable
[Index
].IpAddr
,
149 &PxeBcMode
->RouteTable
[Index
].SubnetMask
151 return &PxeBcMode
->RouteTable
[Index
].GwAddr
;
158 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
161 // routine to send ipv4 packet
162 // ipv4 header of length HdrLth in TransmitBufferPtr
163 // routine fills in ipv4hdr Ver_Hdl, TotalLength, and Checksum, moves in Data
164 // and gets dest MAC address
166 #define IP_TX_BUFFER ((IPV4_BUFFER *) Private->TransmitBufferPtr)
167 #define IP_TX_HEADER IP_TX_BUFFER->IpHeader
171 PXE_BASECODE_DEVICE
*Private
,
173 UINTN IpHeaderLength
,
174 UINTN TotalHeaderLength
,
177 EFI_PXE_BASE_CODE_FUNCTION Function
180 EFI_MAC_ADDRESS DestMac
;
181 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
182 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
186 Snp
= Private
->SimpleNetwork
;
187 PxeBcMode
= Private
->EfiBc
.Mode
;
188 StatCode
= EFI_SUCCESS
;
189 PacketLength
= TotalHeaderLength
+ DataLength
;
192 // get dest MAC address
193 // multicast - convert to hw equiv
194 // unicast on same net, use arp
195 // on different net, arp for router
197 if (IP_TX_HEADER
.DestAddr
.L
== BROADCAST_IPv4
) {
198 CopyMem (&DestMac
, &Snp
->Mode
->BroadcastAddress
, sizeof (DestMac
));
199 } else if (IS_MULTICAST (&IP_TX_HEADER
.DestAddr
)) {
200 StatCode
= (*Snp
->MCastIpToMac
) (Snp
, PxeBcMode
->UsingIpv6
, (EFI_IP_ADDRESS
*) &IP_TX_HEADER
.DestAddr
, &DestMac
);
206 &PxeBcMode
->StationIp
,
207 (EFI_IP_ADDRESS
*) &IP_TX_HEADER
.DestAddr
,
208 &PxeBcMode
->SubnetMask
210 Ip
= IP_TX_HEADER
.DestAddr
.L
;
211 } else if (GatewayIp
!= 0) {
214 EFI_IP_ADDRESS
*TmpIp
;
216 TmpIp
= GetRouterIp (Private
, (EFI_IP_ADDRESS
*) &IP_TX_HEADER
.DestAddr
);
221 "\nIpv4Xmit() Exit #1 %xh (%r)",
226 return EFI_NO_RESPONSE
;
237 (EFI_IP_ADDRESS
*) &Ip
,
238 (EFI_MAC_ADDRESS
*) &DestMac
240 if (!PxeBcMode
->AutoArp
) {
243 "\nIpv4Xmit() Exit #2 %xh (%r)",
248 return EFI_DEVICE_ERROR
;
252 (EFI_IP_ADDRESS
*) &Ip
,
253 (EFI_MAC_ADDRESS
*) &DestMac
259 if (EFI_ERROR (StatCode
)) {
260 DEBUG ((EFI_D_WARN
, "\nIpv4Xmit() Exit #3 %xh (%r)", StatCode
, StatCode
));
264 // fill in packet info
266 SET_IPV4_VER_HDL (&IP_TX_HEADER
, IpHeaderLength
);
267 IP_TX_HEADER
.TotalLength
= HTONS (PacketLength
);
268 IP_TX_HEADER
.HeaderChecksum
= IpChecksum ((UINT16
*) &IP_TX_HEADER
, IpHeaderLength
);
269 CopyMem (((UINT8
*) &IP_TX_HEADER
) + TotalHeaderLength
, Data
, DataLength
);
276 (UINT8
*) &IP_TX_HEADER
- Snp
->Mode
->MediaHeaderSize
,
280 PXE_PROTOCOL_ETHERNET_IP
,
285 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
288 // send ipv4 packet with option
292 PXE_BASECODE_DEVICE
*Private
,
300 EFI_PXE_BASE_CODE_FUNCTION Function
303 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
306 PxeBcMode
= Private
->EfiBc
.Mode
;
307 HdrLth
= sizeof (IPV4_HEADER
) + OptionLength
;
309 ZeroMem ((VOID
*) &IP_TX_HEADER
, sizeof (IPV4_HEADER
));
310 IP_TX_HEADER
.TimeToLive
= PxeBcMode
->TTL
;
311 IP_TX_HEADER
.TypeOfService
= PxeBcMode
->ToS
;
312 IP_TX_HEADER
.Protocol
= Prot
;
313 IP_TX_HEADER
.SrcAddr
.L
= *(UINT32
*) &PxeBcMode
->StationIp
;
314 IP_TX_HEADER
.DestAddr
.L
= DestIp
;
315 IP_TX_HEADER
.Id
= Random (Private
);
316 CopyMem (IP_TX_BUFFER
->u
.Data
, Option
, OptionLength
);
328 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
331 // send MessageLength message at MessagePtr - higher level protocol header already in TransmitBufferPtr, length HdrSize
335 PXE_BASECODE_DEVICE
*Private
, // pointer to instance data
337 UINT8 Prot
, // protocol
338 UINT32 SrcIp
, // Source IP address
339 UINT32 DestIp
, // Destination IP address
340 UINT32 GatewayIp
, // used if not NULL and needed
341 UINTN HdrSize
, // protocol header byte length
342 UINT8
*MessagePtr
, // pointer to data
343 UINTN MessageLength
// data byte length
349 TotDataLength
= HdrSize
+ MessageLength
;
351 if (TotDataLength
> MAX_IPV4_DATA_SIZE
) {
354 "\nIp4Send() Exit #1 %xh (%r)",
359 return EFI_BAD_BUFFER_SIZE
;
362 ZeroMem ((VOID
*) &IP_TX_HEADER
, sizeof (IPV4_HEADER
));
363 IP_TX_HEADER
.TimeToLive
= DEFAULT_TTL
;
364 IP_TX_HEADER
.Protocol
= Prot
;
365 IP_TX_HEADER
.SrcAddr
.L
= SrcIp
;
366 IP_TX_HEADER
.DestAddr
.L
= DestIp
;
367 IP_TX_HEADER
.Id
= Random (Private
);
370 *(UINT8
*) (&IP_TX_HEADER
.FragmentFields
) = IP_NO_FRAG
>> 8;
373 // check for need to fragment
375 if (TotDataLength
> MAX_IPV4_FRAME_DATA_SIZE
) {
376 UINTN DataLengthSent
;
377 UINT16 FragmentOffset
;
379 FragmentOffset
= IP_MORE_FRAG
;
386 "\nIp4Send() Exit #2 %xh (%r)",
391 return EFI_BAD_BUFFER_SIZE
;
394 // send out in fragments - first includes upper level header
395 // all are max and include more frag bit except last
397 * (UINT8
*) (&IP_TX_HEADER
.FragmentFields
) = IP_MORE_FRAG
>> 8;
399 #define IPV4_FRAG_SIZE (MAX_IPV4_FRAME_DATA_SIZE & 0xfff8)
400 #define IPV4_FRAG_OFF_INC (IPV4_FRAG_SIZE >> 3)
402 DataLengthSent
= IPV4_FRAG_SIZE
- HdrSize
;
407 sizeof (IPV4_HEADER
),
408 sizeof (IPV4_HEADER
) + HdrSize
,
414 if (EFI_ERROR (StatCode
)) {
417 "\nIp4Send() Exit #3 %xh (%r)",
425 MessagePtr
+= DataLengthSent
;
426 MessageLength
-= DataLengthSent
;
427 FragmentOffset
+= IPV4_FRAG_OFF_INC
;
428 IP_TX_HEADER
.FragmentFields
= HTONS (FragmentOffset
);
430 while (MessageLength
> IPV4_FRAG_SIZE
) {
434 sizeof (IPV4_HEADER
),
435 sizeof (IPV4_HEADER
),
441 if (EFI_ERROR (StatCode
)) {
444 "\nIp4Send() Exit #3 %xh (%r)",
452 MessagePtr
+= IPV4_FRAG_SIZE
;
453 MessageLength
-= IPV4_FRAG_SIZE
;
454 FragmentOffset
+= IPV4_FRAG_OFF_INC
;
455 IP_TX_HEADER
.FragmentFields
= HTONS (FragmentOffset
);
458 * (UINT8
*) (&IP_TX_HEADER
.FragmentFields
) &= ~(IP_MORE_FRAG
>> 8);
467 sizeof (IPV4_HEADER
),
468 sizeof (IPV4_HEADER
) + HdrSize
,
475 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
478 // return true if dst IP in receive header matched with what's enabled
483 PXE_BASECODE_DEVICE
*Private
,
484 IPV4_HEADER
*IpHeader
487 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
490 PxeBcMode
= Private
->EfiBc
.Mode
;
492 if (PxeBcMode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS
) {
496 if ((PxeBcMode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST
) &&
497 IS_MULTICAST (&IpHeader
->DestAddr
)
502 if ((PxeBcMode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
) &&
503 PxeBcMode
->StationIp
.Addr
[0] == IpHeader
->DestAddr
.L
508 if ((PxeBcMode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST
) && IpHeader
->DestAddr
.L
== BROADCAST_IPv4
) {
512 for (Index
= 0; Index
< PxeBcMode
->IpFilter
.IpCnt
; ++Index
) {
513 if (IpHeader
->DestAddr
.L
== PxeBcMode
->IpFilter
.IpList
[Index
].Addr
[0]) {
521 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
524 // receive up to MessageLength message into MessagePtr for protocol Prot
525 // return message length, src/dest ips if select any, and pointer to protocol
526 // header routine will filter based on source and/or dest ip if OpFlags set.
530 PXE_BASECODE_DEVICE
*Private
,
532 EFI_IP_ADDRESS
*SrcIpPtr
,
533 EFI_IP_ADDRESS
*DestIpPtr
,
538 UINTN
*MessageLengthPtr
,
539 EFI_EVENT TimeoutEvent
542 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
546 UINTN ExpectedPacketLength
;
548 BOOLEAN GotFirstFragment
;
549 BOOLEAN GotLastFragment
;
553 "\nIpReceive() Hdr=%Xh HdrSz=%d Data=%Xh DataSz=%d",
560 PxeBcMode
= Private
->EfiBc
.Mode
;
561 PxeBcMode
->IcmpErrorReceived
= FALSE
;
563 ExpectedPacketLength
= 0;
564 GotFirstFragment
= FALSE
;
565 GotLastFragment
= FALSE
;
574 UINTN FragmentOffset
;
577 UINTN IpHeaderLength
;
583 StatCode
= WaitForReceive (
592 if (EFI_ERROR (StatCode
)) {
596 PacketPtr
= Private
->ReceiveBufferPtr
+ HeaderSize
;
598 if (Protocol
== PXE_PROTOCOL_ETHERNET_ARP
) {
601 (ARP_PACKET
*) PacketPtr
,
602 Private
->ReceiveBufferPtr
608 if (Protocol
!= PXE_PROTOCOL_ETHERNET_IP
) {
613 if (PxeBcMode
->UsingIpv6
) {
620 #define IpRxHeader ((IPV4_HEADER *) PacketPtr)
623 // filter for version & check sum
625 IpHeaderLength
= IPV4_HEADER_LENGTH (IpRxHeader
);
627 if ((IpRxHeader
->VersionIhl
>> 4) != IPVER4
) {
631 if (IpChecksum ((UINT16
*) IpRxHeader
, IpHeaderLength
)) {
635 CopyMem (&IpHdr
, IpRxHeader
, sizeof (IpHdr
));
636 //IpHdr = *IpRxHeader;
637 TotalLength
= NTOHS (IpHdr
.TotalLength
);
639 if (IpHdr
.Protocol
== PROT_TCP
) {
641 // The NextHdrPtr is used to seed the header buffer we are passing back.
642 // That being the case, we want to see everything in pPkt which contains
643 // everything but the ethernet (or whatever) frame. IP + TCP in this case.
645 DataLength
= TotalLength
;
646 NextHdrPtr
= PacketPtr
;
648 DataLength
= TotalLength
- IpHeaderLength
;
649 NextHdrPtr
= PacketPtr
+ IpHeaderLength
;
652 // If this is an ICMP, it might not be for us.
653 // Double check the state of the IP stack and the
654 // packet fields before assuming it is an ICMP
655 // error. ICMP requests are not supported by the
656 // PxeBc IP stack and should be ignored.
658 if (IpHdr
.Protocol
== PROT_ICMP
) {
659 ICMPV4_HEADER
*Icmpv4
;
661 Icmpv4
= (ICMPV4_HEADER
*) NextHdrPtr
;
664 // For now only obvious ICMP error replies will be accepted by
665 // this stack. This still makes us vulnerable to DoS attacks.
666 // But at least we will not be killed by DHCP daemons.
668 switch (Icmpv4
->Type
) {
671 case ICMP_ROUTER_ADV
:
672 case ICMP_ROUTER_SOLICIT
:
674 case ICMP_TIMESTAMP_REPLY
:
676 case ICMP_INFO_REQ_REPLY
:
677 case ICMP_SUBNET_MASK_REQ
:
678 case ICMP_SUBNET_MASK_REPLY
:
683 // %%TBD - This should be implemented.
685 case ICMP_ECHO_REPLY
:
688 case ICMP_DEST_UNREACHABLE
:
689 case ICMP_TIME_EXCEEDED
:
690 case ICMP_PARAMETER_PROBLEM
:
691 case ICMP_SOURCE_QUENCH
:
692 PxeBcMode
->IcmpErrorReceived
= TRUE
;
695 &PxeBcMode
->IcmpError
,
697 sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)
702 "\nIpReceive() Exit #1 %Xh (%r)",
708 return EFI_ICMP_ERROR
;
711 if (IpHdr
.Protocol
== PROT_IGMP
) {
712 HandleIgmp (Private
, (IGMPV2_MESSAGE
*) NextHdrPtr
, DataLength
);
714 DEBUG ((EFI_D_NET
, "\n IGMP"));
718 // check for protocol
720 if (IpHdr
.Protocol
!= Prot
) {
726 if (!(OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
) && SrcIpPtr
&& SrcIpPtr
->Addr
[0] != IpHdr
.SrcAddr
.L
) {
727 DEBUG ((EFI_D_NET
, "\n Not expected source IP address."));
731 if (OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER
) {
732 if (!IPgood (Private
, &IpHdr
)) {
735 } else if (!(OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
)) {
736 if (DestIpPtr
== NULL
) {
737 if (PxeBcMode
->StationIp
.Addr
[0] != IpHdr
.DestAddr
.L
) {
740 } else if (DestIpPtr
->Addr
[0] != IpHdr
.DestAddr
.L
) {
745 // get some data we need
747 FFlds
= NTOHS (IpHdr
.FragmentFields
);
748 FragmentOffset
= ((FFlds
& IP_FRAG_OFF_MSK
) << 3);
750 /* Keep count of fragments that belong to this session.
751 * If we get packets with a different IP ID number,
752 * ignore them. Ignored packets should be handled
753 * by the upper level protocol.
755 if (FragmentCount
== 0) {
758 if (DestIpPtr
!= NULL
) {
759 DestIpPtr
->Addr
[0] = IpHdr
.DestAddr
.L
;
762 if (SrcIpPtr
!= NULL
) {
763 SrcIpPtr
->Addr
[0] = IpHdr
.SrcAddr
.L
;
766 if (IpHdr
.Id
!= Id
) {
773 /* Fragment management.
775 if (FragmentOffset
== 0) {
776 /* This is the first fragment (may also be the
779 GotFirstFragment
= TRUE
;
781 /* If there is a separate protocol header buffer,
782 * copy the header, adjust the data pointer and
786 CopyMem (HeaderPtr
, NextHdrPtr
, HdrSize
);
788 NextHdrPtr
+= HdrSize
;
789 DataLength
-= HdrSize
;
792 /* If there is a separate protocol header buffer,
793 * adjust the fragment offset.
795 FragmentOffset
-= HdrSize
;
798 /* See if this is the last fragment.
800 if (!(FFlds
& IP_MORE_FRAG
)) {
802 // This is the last fragment (may also be the only fragment).
804 GotLastFragment
= TRUE
;
806 /* Compute the expected length of the assembled
807 * packet. This will be used to decide if we
808 * have gotten all of the fragments.
810 ExpectedPacketLength
= FragmentOffset
+ DataLength
;
815 "\n ID = %Xh Off = %d Len = %d",
821 /* Check for receive buffer overflow.
823 if (FragmentOffset
+ DataLength
> *MessageLengthPtr
) {
824 /* There is not enough space in the receive
825 * buffer for the fragment.
829 "\nIpReceive() Exit #3 %Xh (%r)",
830 EFI_BUFFER_TOO_SMALL
,
831 EFI_BUFFER_TOO_SMALL
)
834 return EFI_BUFFER_TOO_SMALL
;
837 /* Copy data into receive buffer.
839 if (DataLength
!= 0) {
840 DEBUG ((EFI_D_NET
, " To = %Xh", MessagePtr
+ FragmentOffset
));
842 CopyMem (MessagePtr
+ FragmentOffset
, NextHdrPtr
, DataLength
);
843 ByteCount
+= DataLength
;
846 /* If we have seen the first and last fragments and
847 * the receive byte count is at least as large as the
848 * expected byte count, return SUCCESS.
850 * We could be tricked by receiving a fragment twice
851 * but the upper level protocol should figure this
854 if (GotFirstFragment
&& GotLastFragment
&& ByteCount
>= ExpectedPacketLength
) {
855 *MessageLengthPtr
= ExpectedPacketLength
;
861 /* eof - pxe_bc_ip.c */