]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
Clean up the private GUID definition in module Level.
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcDhcp6.c
index 0b7cf1f947f3ac945928870a9e0318300d14ac5b..3e59f3f233441a51aa3fb0370ab6d6eff1434dc1 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Functions implementation related with DHCPv6 for UefiPxeBc Driver.\r
 \r
 /** @file\r
   Functions implementation related with DHCPv6 for UefiPxeBc Driver.\r
 \r
-  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
 \r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
 \r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
@@ -97,7 +97,7 @@ PxeBcBuildDhcp6Options (
   // Append client network device interface option\r
   //\r
   OptList[Index]->OpCode     = HTONS (PXEBC_DHCP6_OPT_UNDI);\r
   // Append client network device interface option\r
   //\r
   OptList[Index]->OpCode     = HTONS (PXEBC_DHCP6_OPT_UNDI);\r
-  OptList[Index]->OpLen      = HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTION_UNDI));\r
+  OptList[Index]->OpLen      = HTONS ((UINT16)3);\r
   OptEnt.Undi                = (PXEBC_DHCP6_OPTION_UNDI *) OptList[Index]->Data;\r
 \r
   if (Private->Nii != NULL) {\r
   OptEnt.Undi                = (PXEBC_DHCP6_OPTION_UNDI *) OptList[Index]->Data;\r
 \r
   if (Private->Nii != NULL) {\r
@@ -110,7 +110,6 @@ PxeBcBuildDhcp6Options (
     OptEnt.Undi->MinorVer    = DEFAULT_UNDI_MINOR;\r
   }\r
 \r
     OptEnt.Undi->MinorVer    = DEFAULT_UNDI_MINOR;\r
   }\r
 \r
-  OptEnt.Undi->Reserved      = 0;\r
   Index++;\r
   OptList[Index]             = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
 \r
   Index++;\r
   OptList[Index]             = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
 \r
@@ -233,12 +232,14 @@ PxeBcExtractBootFileUrl (
   )\r
 {\r
   UINT16                     PrefixLen;\r
   )\r
 {\r
   UINT16                     PrefixLen;\r
-  UINT8                      *BootFileNamePtr;\r
-  UINT8                      *BootFileName;\r
+  CHAR8                      *BootFileNamePtr;\r
+  CHAR8                      *BootFileName;\r
   UINT16                     BootFileNameLen;\r
   CHAR8                      *TmpStr;\r
   UINT16                     BootFileNameLen;\r
   CHAR8                      *TmpStr;\r
+  CHAR8                      TmpChar;\r
   CHAR8                      *ServerAddressOption;\r
   CHAR8                      *ServerAddress;\r
   CHAR8                      *ServerAddressOption;\r
   CHAR8                      *ServerAddress;\r
+  CHAR8                      *ModeStr;\r
   EFI_STATUS                 Status;\r
 \r
   //\r
   EFI_STATUS                 Status;\r
 \r
   //\r
@@ -256,9 +257,8 @@ PxeBcExtractBootFileUrl (
   //\r
 \r
   //\r
   //\r
 \r
   //\r
-  // Based upon RFC 5970 and UEFI errata that will appear in chapter 21.3 of UEFI 2.3\r
-  // specification after 2.3 errata B and future UEFI Specifications after 2.3.\r
-  // tftp://[SERVER_ADDRESS]/BOOTFILE_NAME\r
+  // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile-url format\r
+  // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME\r
   // As an example where the BOOTFILE_NAME is the EFI loader and\r
   // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.\r
   //\r
   // As an example where the BOOTFILE_NAME is the EFI loader and\r
   // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.\r
   //\r
@@ -314,7 +314,7 @@ PxeBcExtractBootFileUrl (
   //\r
   // Get the part of BOOTFILE_NAME string.\r
   //\r
   //\r
   // Get the part of BOOTFILE_NAME string.\r
   //\r
-  BootFileNamePtr = (UINT8*)((UINTN)ServerAddress + 1);\r
+  BootFileNamePtr = (CHAR8*)((UINTN)ServerAddress + 1);\r
   if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) {\r
     FreePool (TmpStr);\r
     return EFI_INVALID_PARAMETER;\r
   if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) {\r
     FreePool (TmpStr);\r
     return EFI_INVALID_PARAMETER;\r
@@ -323,18 +323,47 @@ PxeBcExtractBootFileUrl (
   ++BootFileNamePtr;\r
   BootFileNameLen = (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1);\r
   if (BootFileNameLen != 0 || FileName != NULL) {\r
   ++BootFileNamePtr;\r
   BootFileNameLen = (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1);\r
   if (BootFileNameLen != 0 || FileName != NULL) {\r
-    BootFileName = (UINT8 *) AllocateZeroPool (BootFileNameLen);\r
+    //\r
+    // Remove trailing mode=octet if present and ignore.  All other modes are\r
+    // invalid for netboot6, so reject them.\r
+    //\r
+    ModeStr = AsciiStrStr (BootFileNamePtr, ";mode=octet");\r
+    if (ModeStr != NULL && *(ModeStr + AsciiStrLen (";mode=octet")) == '\0') {\r
+      *ModeStr = '\0';\r
+    } else if (AsciiStrStr (BootFileNamePtr, ";mode=") != NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    //\r
+    // Extract boot file name from URL.\r
+    //\r
+    BootFileName = (CHAR8 *) AllocateZeroPool (BootFileNameLen);\r
     if (BootFileName == NULL) {\r
       FreePool (TmpStr);\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
     if (BootFileName == NULL) {\r
       FreePool (TmpStr);\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
+    *FileName = (UINT8*) BootFileName;\r
 \r
 \r
-    CopyMem (BootFileName, BootFileNamePtr, BootFileNameLen);\r
-    BootFileName[BootFileNameLen - 1] = '\0';\r
-    *FileName = BootFileName;\r
+    //\r
+    // Decode percent-encoding in boot file name.\r
+    //\r
+    while (*BootFileNamePtr != '\0') {\r
+      if (*BootFileNamePtr == '%') {\r
+        TmpChar = *(BootFileNamePtr+ 3);\r
+        *(BootFileNamePtr+ 3) = '\0';\r
+        *BootFileName = (UINT8) AsciiStrHexToUintn ((CHAR8*)(BootFileNamePtr + 1));\r
+        BootFileName++;\r
+        *(BootFileNamePtr+ 3) = TmpChar;\r
+        BootFileNamePtr += 3;\r
+      } else {\r
+        *BootFileName = *BootFileNamePtr;\r
+        BootFileName++;\r
+        BootFileNamePtr++;\r
+      }\r
+    }\r
+    *BootFileName = '\0';\r
   }\r
 \r
   }\r
 \r
-\r
   FreePool (TmpStr);\r
 \r
   return EFI_SUCCESS;\r
   FreePool (TmpStr);\r
 \r
   return EFI_SUCCESS;\r
@@ -457,13 +486,13 @@ PxeBcParseDhcp6Packet (
   // An ia_na option, embeded with valid ia_addr option and a status_code of success.\r
   //\r
   Option = Options[PXEBC_DHCP6_IDX_IA_NA];\r
   // An ia_na option, embeded with valid ia_addr option and a status_code of success.\r
   //\r
   Option = Options[PXEBC_DHCP6_IDX_IA_NA];\r
-  if (Option != NULL && NTOHS(Option->OpLen) >= 12) {\r
+  if (Option != NULL) {\r
     Option = PxeBcParseDhcp6Options (\r
                Option->Data + 12,\r
                NTOHS (Option->OpLen),\r
                PXEBC_DHCP6_OPT_STATUS_CODE\r
                );\r
     Option = PxeBcParseDhcp6Options (\r
                Option->Data + 12,\r
                NTOHS (Option->OpLen),\r
                PXEBC_DHCP6_OPT_STATUS_CODE\r
                );\r
-    if (Option != NULL && Option->Data[0] == 0) {\r
+    if ((Option != NULL && Option->Data[0] == 0) || (Option == NULL)) {\r
       IsProxyOffer = FALSE;\r
     }\r
   }\r
       IsProxyOffer = FALSE;\r
     }\r
   }\r
@@ -472,11 +501,12 @@ PxeBcParseDhcp6Packet (
   // The offer with "PXEClient" is a pxe offer.\r
   //\r
   Option        = Options[PXEBC_DHCP6_IDX_VENDOR_CLASS];\r
   // The offer with "PXEClient" is a pxe offer.\r
   //\r
   Option        = Options[PXEBC_DHCP6_IDX_VENDOR_CLASS];\r
-  EnterpriseNum = PXEBC_DHCP6_ENTERPRISE_NUM;\r
+  EnterpriseNum = HTONL(PXEBC_DHCP6_ENTERPRISE_NUM);\r
+\r
   if (Option != NULL &&\r
       NTOHS(Option->OpLen) >= 13 &&\r
       CompareMem (Option->Data, &EnterpriseNum, sizeof (UINT32)) == 0 &&\r
   if (Option != NULL &&\r
       NTOHS(Option->OpLen) >= 13 &&\r
       CompareMem (Option->Data, &EnterpriseNum, sizeof (UINT32)) == 0 &&\r
-      CompareMem (&Option->Data[4], DEFAULT_CLASS_ID_DATA, 9) == 0) {\r
+      CompareMem (&Option->Data[6], DEFAULT_CLASS_ID_DATA, 9) == 0) {\r
     IsPxeOffer = TRUE;\r
   }\r
 \r
     IsPxeOffer = TRUE;\r
   }\r
 \r
@@ -568,6 +598,223 @@ PxeBcCopyDhcp6Proxy (
   Mode->ProxyOfferReceived = TRUE;\r
 }\r
 \r
   Mode->ProxyOfferReceived = TRUE;\r
 }\r
 \r
+/**\r
+  Seek the address of the first byte of the option header.\r
+\r
+  @param[in]  Buf           The pointer to the buffer.\r
+  @param[in]  SeekLen       The length to seek.\r
+  @param[in]  OptType       The option type.\r
+\r
+  @retval     NULL          If it failed to seek the option.\r
+  @retval     others        The position to the option.\r
+\r
+**/\r
+UINT8 *\r
+PxeBcDhcp6SeekOption (\r
+  IN UINT8           *Buf,\r
+  IN UINT32          SeekLen,\r
+  IN UINT16          OptType\r
+  )\r
+{\r
+  UINT8              *Cursor;\r
+  UINT8              *Option;\r
+  UINT16             DataLen;\r
+  UINT16             OpCode;\r
+\r
+  Option = NULL;\r
+  Cursor = Buf;\r
+\r
+  while (Cursor < Buf + SeekLen) {\r
+    OpCode = ReadUnaligned16 ((UINT16 *) Cursor);\r
+    if (OpCode == HTONS (OptType)) {\r
+      Option = Cursor;\r
+      break;\r
+    }\r
+    DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2)));\r
+    Cursor += (DataLen + 4);\r
+  }\r
+\r
+  return Option;\r
+}\r
+\r
+\r
+/**\r
+  Build and send out the request packet for the bootfile, and parse the reply.\r
+\r
+  @param[in]  Private               The pointer to PxeBc private data.\r
+  @param[in]  Index                 PxeBc option boot item type.\r
+\r
+  @retval     EFI_SUCCESS           Successfully discovered the boot file.\r
+  @retval     EFI_OUT_OF_RESOURCES  Failed to allocate resources.\r
+  @retval     EFI_NOT_FOUND         Can't get the PXE reply packet.\r
+  @retval     Others                Failed to discover the boot file.\r
+\r
+**/\r
+EFI_STATUS\r
+PxeBcRequestBootService (\r
+  IN  PXEBC_PRIVATE_DATA              *Private,\r
+  IN  UINT32                          Index\r
+  )\r
+{\r
+  EFI_PXE_BASE_CODE_UDP_PORT          SrcPort;\r
+  EFI_PXE_BASE_CODE_UDP_PORT          DestPort;\r
+  EFI_PXE_BASE_CODE_MODE              *Mode;\r
+  EFI_PXE_BASE_CODE_PROTOCOL          *PxeBc;\r
+  EFI_PXE_BASE_CODE_DHCPV6_PACKET     *Discover;\r
+  UINTN                               DiscoverLen;\r
+  EFI_DHCP6_PACKET                    *Request;\r
+  UINTN                               RequestLen;\r
+  EFI_DHCP6_PACKET                    *Reply;\r
+  UINT8                               *RequestOpt;\r
+  UINT8                               *DiscoverOpt;\r
+  UINTN                               ReadSize;\r
+  UINT16                              OpFlags;\r
+  UINT16                              OpCode;\r
+  UINT16                              OpLen;\r
+  EFI_STATUS                          Status;\r
+  EFI_DHCP6_PACKET                    *ProxyOffer;\r
+  UINT8                               *Option;\r
+\r
+  PxeBc       = &Private->PxeBc;\r
+  Mode        = PxeBc->Mode;\r
+  Request     = Private->Dhcp6Request;\r
+  ProxyOffer = &Private->OfferBuffer[Index].Dhcp6.Packet.Offer;\r
+  SrcPort     = PXEBC_BS_DISCOVER_PORT;\r
+  DestPort    = PXEBC_BS_DISCOVER_PORT;\r
+  OpFlags     = 0;\r
+\r
+  if (Request == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET));\r
+  if (Discover == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Build the request packet by the cached request packet before.\r
+  //\r
+  Discover->TransactionId = ProxyOffer->Dhcp6.Header.TransactionId;\r
+  Discover->MessageType   = Request->Dhcp6.Header.MessageType;\r
+  RequestOpt              = Request->Dhcp6.Option;\r
+  DiscoverOpt             = Discover->DhcpOptions;\r
+  DiscoverLen             = sizeof (EFI_DHCP6_HEADER);\r
+  RequestLen              = DiscoverLen;\r
+\r
+  //\r
+  // Find Server ID Option from ProxyOffer.\r
+  //\r
+  Option = PxeBcDhcp6SeekOption (\r
+             ProxyOffer->Dhcp6.Option,\r
+             ProxyOffer->Length - 4,\r
+             PXEBC_DHCP6_OPT_SERVER_ID\r
+             );\r
+  if (Option == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  \r
+  //\r
+  // Add Server ID Option.\r
+  //\r
+  OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) Option)->OpLen);\r
+  CopyMem (DiscoverOpt, Option, OpLen + 4);\r
+  DiscoverOpt += (OpLen + 4);\r
+  DiscoverLen += (OpLen + 4);\r
+\r
+  while (RequestLen < Request->Length) {\r
+    OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode);\r
+    OpLen  = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpLen);\r
+    if (OpCode != EFI_DHCP6_IA_TYPE_NA &&\r
+        OpCode != EFI_DHCP6_IA_TYPE_TA &&\r
+        OpCode != PXEBC_DHCP6_OPT_SERVER_ID\r
+        ) {\r
+      //\r
+      // Copy all the options except IA option and Server ID\r
+      //\r
+      CopyMem (DiscoverOpt, RequestOpt, OpLen + 4);\r
+      DiscoverOpt += (OpLen + 4);\r
+      DiscoverLen += (OpLen + 4);\r
+    }\r
+    RequestOpt += (OpLen + 4);\r
+    RequestLen += (OpLen + 4);\r
+  }\r
+\r
+  //\r
+  // Update Elapsed option in the package \r
+  //\r
+  Option = PxeBcDhcp6SeekOption (\r
+             Discover->DhcpOptions,\r
+             (UINT32)(RequestLen - 4),\r
+             PXEBC_DHCP6_OPT_ELAPSED_TIME\r
+             );\r
+  if (Option != NULL) {\r
+    CalcElapsedTime (Private);\r
+    WriteUnaligned16 ((UINT16*)(Option + 4), HTONS((UINT16) Private->ElapsedTime));\r
+  }  \r
+\r
+  Status = PxeBc->UdpWrite (\r
+                    PxeBc,\r
+                    OpFlags,\r
+                    &Private->ServerIp,\r
+                    &DestPort,\r
+                    NULL,\r
+                    &Private->StationIp,\r
+                    &SrcPort,\r
+                    NULL,\r
+                    NULL,\r
+                    &DiscoverLen,\r
+                    (VOID *) Discover\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Cache the right PXE reply packet here, set valid flag later.\r
+  // Especially for PXE discover packet, store it into mode data here.\r
+  //\r
+  Reply = &Private->ProxyOffer.Dhcp6.Packet.Offer;\r
+  ReadSize = (UINTN) Reply->Size;\r
+\r
+  //\r
+  // Start Udp6Read instance\r
+  //\r
+  Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+    \r
+  Status = PxeBc->UdpRead (\r
+                    PxeBc,\r
+                    OpFlags,\r
+                    &Private->StationIp,\r
+                    &SrcPort,\r
+                    &Private->ServerIp,\r
+                    &DestPort,\r
+                    NULL,\r
+                    NULL,\r
+                    &ReadSize,\r
+                    (VOID *) &Reply->Dhcp6\r
+                    );\r
+  //\r
+  // Stop Udp6Read instance\r
+  //\r
+  Private->Udp6Read->Configure (Private->Udp6Read, NULL);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Update length\r
+  //\r
+  Reply->Length = (UINT32) ReadSize;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 \r
 /**\r
   Retry to request bootfile name by the BINL offer.\r
 \r
 /**\r
   Retry to request bootfile name by the BINL offer.\r
@@ -588,7 +835,6 @@ PxeBcRetryDhcp6Binl (
   EFI_PXE_BASE_CODE_MODE    *Mode;\r
   PXEBC_DHCP6_PACKET_CACHE  *Offer;\r
   PXEBC_DHCP6_PACKET_CACHE  *Cache6;\r
   EFI_PXE_BASE_CODE_MODE    *Mode;\r
   PXEBC_DHCP6_PACKET_CACHE  *Offer;\r
   PXEBC_DHCP6_PACKET_CACHE  *Cache6;\r
-  EFI_IP_ADDRESS            ServerIp;\r
   EFI_STATUS                Status;\r
 \r
   ASSERT (Index < PXEBC_OFFER_MAX_NUM);\r
   EFI_STATUS                Status;\r
 \r
   ASSERT (Index < PXEBC_OFFER_MAX_NUM);\r
@@ -604,8 +850,8 @@ PxeBcRetryDhcp6Binl (
   // Parse out the next server address from the last offer, and store it\r
   //\r
   Status = PxeBcExtractBootFileUrl (\r
   // Parse out the next server address from the last offer, and store it\r
   //\r
   Status = PxeBcExtractBootFileUrl (\r
-             NULL,\r
-             &ServerIp.v6,\r
+             &Private->BootFileName,\r
+             &Private->ServerIp.v6,\r
              (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),\r
              NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen)\r
              );\r
              (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),\r
              NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen)\r
              );\r
@@ -616,13 +862,8 @@ PxeBcRetryDhcp6Binl (
   //\r
   // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.\r
   //\r
   //\r
   // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.\r
   //\r
-  Status = PxeBcDhcp6Discover (\r
-             Private,\r
-             0,\r
-             NULL,\r
-             FALSE,\r
-             &ServerIp\r
-             );\r
+  Status = PxeBcRequestBootService (Private, Index);\r
+\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
@@ -1195,6 +1436,13 @@ PxeBcDhcp6CallBack (
   switch (Dhcp6Event) {\r
 \r
   case Dhcp6SendSolicit:\r
   switch (Dhcp6Event) {\r
 \r
   case Dhcp6SendSolicit:\r
+    //\r
+    // Record the first Solicate msg time\r
+    //\r
+    if (Private->SolicitTimes == 0) {\r
+      CalcElapsedTime (Private);\r
+      Private->SolicitTimes++;\r
+    }\r
     //\r
     // Cache the dhcp discover packet to mode data directly.\r
     //\r
     //\r
     // Cache the dhcp discover packet to mode data directly.\r
     //\r