]> 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
-  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
@@ -97,7 +97,7 @@ PxeBcBuildDhcp6Options (
   // 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
@@ -110,7 +110,6 @@ PxeBcBuildDhcp6Options (
     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
@@ -233,12 +232,14 @@ PxeBcExtractBootFileUrl (
   )\r
 {\r
   UINT16                     PrefixLen;\r
-  UINT8                      *BootFileNamePtr;\r
-  UINT8                      *BootFileName;\r
+  CHAR8                      *BootFileNamePtr;\r
+  CHAR8                      *BootFileName;\r
   UINT16                     BootFileNameLen;\r
   CHAR8                      *TmpStr;\r
+  CHAR8                      TmpChar;\r
   CHAR8                      *ServerAddressOption;\r
   CHAR8                      *ServerAddress;\r
+  CHAR8                      *ModeStr;\r
   EFI_STATUS                 Status;\r
 \r
   //\r
@@ -256,9 +257,8 @@ PxeBcExtractBootFileUrl (
   //\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
@@ -314,7 +314,7 @@ PxeBcExtractBootFileUrl (
   //\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
@@ -323,18 +323,47 @@ PxeBcExtractBootFileUrl (
   ++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
+    *FileName = (UINT8*) BootFileName;\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
   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
-  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
-    if (Option != NULL && Option->Data[0] == 0) {\r
+    if ((Option != NULL && Option->Data[0] == 0) || (Option == NULL)) {\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
-  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
-      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
@@ -568,6 +598,223 @@ PxeBcCopyDhcp6Proxy (
   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
@@ -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_IP_ADDRESS            ServerIp;\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
-             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
@@ -616,13 +862,8 @@ PxeBcRetryDhcp6Binl (
   //\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
@@ -1195,6 +1436,13 @@ PxeBcDhcp6CallBack (
   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