}\r
\r
Instance = DHCP_INSTANCE_FROM_THIS (This);\r
-\r
- if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
+ \r
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
DhcpSb = Instance->Service;\r
\r
);\r
}\r
\r
+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
\r
/**\r
Transmit and receive a packet through this DHCP service.\r
IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token\r
)\r
{\r
+ DHCP_PROTOCOL *Instance;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+ NET_FRAGMENT Frag;\r
+ NET_BUF *Wrap;\r
+ UDP_POINTS EndPoint;\r
+ IP4_ADDR Ip;\r
+ DHCP_SERVICE *DhcpSb;\r
+ IP4_ADDR Gateway;\r
+ IP4_ADDR SubnetMask;\r
+\r
+ if ((This == NULL) || (Token == NULL) || (Token->Packet == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = DHCP_INSTANCE_FROM_THIS (This);\r
+ DhcpSb = Instance->Service;\r
+\r
+ if (Instance->Token != NULL) {\r
+ //\r
+ // The previous call to TransmitReceive is not finished.\r
+ //\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ if ((Token->Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
+ (NTOHL (Token->Packet->Dhcp4.Header.Xid) == Instance->Service->Xid) ||\r
+ (Token->TimeoutValue == 0) ||\r
+ ((Token->ListenPointCount != 0) && (Token->ListenPoints == NULL)) ||\r
+ EFI_ERROR (DhcpValidateOptions (Token->Packet, NULL)) ||\r
+ EFI_IP4_EQUAL (&Token->RemoteAddress, &mZeroIp4Addr)) {\r
+ //\r
+ // The DHCP packet isn't well-formed, the Transaction ID is already used\r
+ // , the timeout value is zero, the ListenPoint is invalid,\r
+ // or the RemoteAddress is zero.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (DhcpSb->ClientAddr == 0) {\r
+\r
+ return EFI_NO_MAPPING;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ //\r
+ // Save the token and the timeout value.\r
+ //\r
+ Instance->Token = Token;\r
+ Instance->Timeout = Token->TimeoutValue;\r
+\r
+ //\r
+ // Create a UDP IO for this transmit receive transaction.\r
+ //\r
+ Status = Dhcp4InstanceCreateUdpIo (Instance);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
//\r
- // This function is for PXE, leave it for now\r
+ // Wrap the DHCP packet into a net buffer.\r
//\r
- return EFI_UNSUPPORTED;\r
+ Frag.Bulk = (UINT8 *) &Token->Packet->Dhcp4;\r
+ Frag.Len = Token->Packet->Length;\r
+ Wrap = NetbufFromExt (&Frag, 1, 0, 0, DhcpDummyExtFree, NULL);\r
+ if (Wrap == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ //\r
+ // Set the local address and local port.\r
+ //\r
+ EndPoint.LocalAddr = 0;\r
+ EndPoint.LocalPort = 0;\r
+\r
+ //\r
+ // Set the destination address and destination port.\r
+ //\r
+ NetCopyMem (&Ip, &Token->RemoteAddress, sizeof (EFI_IPv4_ADDRESS));\r
+ EndPoint.RemoteAddr = NTOHL (Ip);\r
+\r
+ if (Token->RemotePort == 0) {\r
+ EndPoint.RemotePort = DHCP_SERVER_PORT;\r
+ } else {\r
+ EndPoint.RemotePort = Token->RemotePort;\r
+ }\r
+\r
+ //\r
+ // Get the gateway.\r
+ //\r
+ SubnetMask = DhcpSb->Netmask;\r
+ Gateway = 0;\r
+ if (!IP4_NET_EQUAL (DhcpSb->ClientAddr, EndPoint.RemoteAddr, SubnetMask)) {\r
+ NetCopyMem (&Gateway, &Token->GatewayAddress, sizeof (EFI_IPv4_ADDRESS));\r
+ Gateway = NTOHL (Gateway);\r
+ }\r
+\r
+ //\r
+ // Transmit the DHCP packet.\r
+ //\r
+ Status = UdpIoSendDatagram (Instance->UdpIo, Wrap, &EndPoint, Gateway, DhcpOnPacketSent, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ NetbufFree (Wrap);\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ //\r
+ // Start to receive the DHCP response.\r
+ //\r
+ Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ON_ERROR:\r
+\r
+ if (EFI_ERROR (Status) && (Instance->UdpIo != NULL)) {\r
+ UdpIoCleanPort (Instance->UdpIo);\r
+ UdpIoFreePort (Instance->UdpIo);\r
+ Instance->UdpIo = NULL;\r
+ Instance->Token = NULL;\r
+ }\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ if (!EFI_ERROR (Status) && (Token->CompletionEvent == NULL)) {\r
+ //\r
+ // Keep polling until timeout if no error happens and the CompletionEvent\r
+ // is NULL.\r
+ //\r
+ while (Instance->Timeout != 0) {\r
+ Instance->UdpIo->Udp->Poll (Instance->UdpIo->Udp);\r
+ }\r
+ }\r
+\r
+ return Status;\r
}\r
\r
\r
EfiDhcp4TransmitReceive,\r
EfiDhcp4Parse\r
};\r
+\r