+STATIC\r
+EFI_STATUS\r
+Dhcp4InstanceConfigUdpIo (\r
+ IN UDP_IO_PORT *UdpIo,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ DHCP_PROTOCOL *Instance;\r
+ DHCP_SERVICE *DhcpSb;\r
+ EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token;\r
+ EFI_UDP4_CONFIG_DATA UdpConfigData;\r
+ IP4_ADDR Ip;\r
+\r
+ Instance = (DHCP_PROTOCOL *) Context;\r
+ DhcpSb = Instance->Service;\r
+ Token = Instance->Token;\r
+\r
+ NetZeroMem (&UdpConfigData, sizeof (EFI_UDP4_CONFIG_DATA));\r
+\r
+ UdpConfigData.AcceptBroadcast = TRUE;\r
+ UdpConfigData.AllowDuplicatePort = TRUE;\r
+ UdpConfigData.TimeToLive = 64;\r
+ UdpConfigData.DoNotFragment = TRUE;\r
+\r
+ Ip = HTONL (DhcpSb->ClientAddr);\r
+ NetCopyMem (&UdpConfigData.StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+ Ip = HTONL (DhcpSb->Netmask);\r
+ NetCopyMem (&UdpConfigData.SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+ if ((Token->ListenPointCount == 0) || (Token->ListenPoints[0].ListenPort == 0)) {\r
+ UdpConfigData.StationPort = DHCP_CLIENT_PORT;\r
+ } else {\r
+ UdpConfigData.StationPort = Token->ListenPoints[0].ListenPort;\r
+ }\r
+\r
+ return UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfigData);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+Dhcp4InstanceCreateUdpIo (\r
+ IN DHCP_PROTOCOL *Instance\r
+ )\r
+{\r
+ DHCP_SERVICE *DhcpSb;\r
+\r
+ ASSERT (Instance->Token != NULL);\r
+\r
+ DhcpSb = Instance->Service;\r
+ Instance->UdpIo = UdpIoCreatePort (DhcpSb->Controller, DhcpSb->Image, Dhcp4InstanceConfigUdpIo, Instance);\r
+ if (Instance->UdpIo == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\r
+}\r
+\r
+STATIC\r
+VOID\r
+DhcpDummyExtFree (\r
+ IN VOID *Arg\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Release the packet.\r
+\r
+Arguments:\r
+\r
+ Arg - The packet to release\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{ \r
+}\r
+\r
+VOID\r
+PxeDhcpInput (\r
+ NET_BUF *UdpPacket,\r
+ UDP_POINTS *Points,\r
+ EFI_STATUS IoStatus,\r
+ VOID *Context\r
+ )\r
+{\r
+ DHCP_PROTOCOL *Instance;\r
+ DHCP_SERVICE *DhcpSb;\r
+ EFI_DHCP4_HEADER *Head;\r
+ NET_BUF *Wrap;\r
+ EFI_DHCP4_PACKET *Packet;\r
+ EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token;\r
+ UINT32 Len;\r
+ EFI_STATUS Status;\r
+\r
+ Wrap = NULL;\r
+ Instance = (DHCP_PROTOCOL *) Context;\r
+ Token = Instance->Token;\r
+ DhcpSb = Instance->Service;\r
+\r
+ //\r
+ // Don't restart receive if error occurs or DHCP is destoried.\r
+ //\r
+ if (EFI_ERROR (IoStatus)) {\r
+ return ;\r
+ }\r
+\r
+ ASSERT (UdpPacket != NULL);\r
+ \r
+ //\r
+ // Validate the packet received\r
+ //\r
+ if (UdpPacket->TotalSize < sizeof (EFI_DHCP4_HEADER)) {\r
+ goto RESTART;\r
+ }\r
+ \r
+ //\r
+ // Copy the DHCP message to a continuous memory block, make the buffer size\r
+ // of the EFI_DHCP4_PACKET a multiple of 4-byte.\r
+ //\r
+ Len = NET_ROUNDUP (sizeof (EFI_DHCP4_PACKET) + UdpPacket->TotalSize - sizeof (EFI_DHCP4_HEADER), 4);\r
+ Wrap = NetbufAlloc (Len);\r
+\r
+ if (Wrap == NULL) {\r
+ goto RESTART;\r
+ }\r
+\r
+ Packet = (EFI_DHCP4_PACKET *) NetbufAllocSpace (Wrap, Len, NET_BUF_TAIL);\r
+ Packet->Size = Len;\r
+ Head = &Packet->Dhcp4.Header;\r
+ Packet->Length = NetbufCopy (UdpPacket, 0, UdpPacket->TotalSize, (UINT8 *) Head);\r
+\r
+ if (Packet->Length != UdpPacket->TotalSize) {\r
+ goto RESTART;\r
+ }\r
+ \r
+ //\r
+ // Is this packet the answer to our packet?\r
+ //\r
+ if ((Head->OpCode != BOOTP_REPLY) ||\r
+ (Head->Xid != Token->Packet->Dhcp4.Header.Xid) ||\r
+ !NET_MAC_EQUAL (&DhcpSb->Mac, Head->ClientHwAddr, DhcpSb->HwLen)) {\r
+ goto RESTART;\r
+ }\r
+ \r
+ //\r
+ // Validate the options and retrieve the interested options\r
+ //\r
+ if ((Packet->Length > sizeof (EFI_DHCP4_HEADER) + sizeof (UINT32)) &&\r
+ (Packet->Dhcp4.Magik == DHCP_OPTION_MAGIC) &&\r
+ EFI_ERROR (DhcpValidateOptions (Packet, NULL))) {\r
+\r
+ goto RESTART;\r
+ }\r
+\r
+ //\r
+ // Keep this packet in the ResponseQueue.\r
+ //\r
+ NET_GET_REF (Wrap);\r
+ NetbufQueAppend (&Instance->ResponseQueue, Wrap);\r
+\r
+RESTART:\r
+\r
+ NetbufFree (UdpPacket);\r
+\r
+ if (Wrap != NULL) {\r
+ NetbufFree (Wrap);\r
+ }\r
+\r
+ Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0);\r
+ if (EFI_ERROR (Status)) {\r
+ PxeDhcpDone (Instance);\r
+ }\r
+}\r
+\r
+VOID\r
+PxeDhcpDone (\r
+ IN DHCP_PROTOCOL *Instance\r
+ )\r
+{\r
+ EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token;\r
+\r
+ Token = Instance->Token;\r
+\r
+ Token->ResponseCount = Instance->ResponseQueue.BufNum;\r
+ if (Token->ResponseCount != 0) {\r
+ Token->ResponseList = (EFI_DHCP4_PACKET *) NetAllocatePool (Instance->ResponseQueue.BufSize);\r
+ if (Token->ResponseList == NULL) {\r
+ Token->Status = EFI_OUT_OF_RESOURCES;\r
+ goto SIGNAL_USER;\r
+ }\r
+\r
+ //\r
+ // Copy the recieved DHCP responses.\r
+ //\r
+ NetbufQueCopy (&Instance->ResponseQueue, 0, Instance->ResponseQueue.BufSize, (UINT8 *) Token->ResponseList);\r
+ Token->Status = EFI_SUCCESS;\r
+ } else {\r
+ Token->ResponseList = NULL;\r
+ Token->Status = EFI_TIMEOUT;\r
+ }\r
+\r
+SIGNAL_USER:\r
+ //\r
+ // Clean the resources dedicated for this transmit receive transaction.\r
+ //\r
+ NetbufQueFlush (&Instance->ResponseQueue);\r
+ UdpIoCleanPort (Instance->UdpIo);\r
+ UdpIoFreePort (Instance->UdpIo);\r
+ Instance->UdpIo = NULL;\r
+ Instance->Token = NULL;\r
+\r
+ if (Token->CompletionEvent != NULL) {\r
+ gBS->SignalEvent (Token->CompletionEvent);\r
+ } \r
+}\r
+\r