xref: /freebsd/lib/libefivar/uefi-dputil.c (revision ce1342883e03e6a021f03a49d13539a145d320e2)
1 /*-
2  * Copyright (c) 2017 Netflix, Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 /*
27  * Routines to format EFI_DEVICE_PATHs from the UEFI standard. Much of
28  * this file is taken from EDK2 and rototilled.
29  */
30 
31 #include <efivar.h>
32 #include <limits.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <sys/endian.h>
36 #include "uefi-dplib.h"
37 
38 /* XXX maybe I should include the entire DevicePathUtiltiies.c and ifdef out what we don't use */
39 
40 /*
41  * Taken from MdePkg/Library/UefiDevicePathLib/DevicePathUtilities.c
42  * hash a11928f3310518ab1c6fd34e8d0fdbb72de9602c 2017-Mar-01
43  */
44 
45 /** @file
46   Device Path services. The thing to remember is device paths are built out of
47   nodes. The device path is terminated by an end node that is length
48   sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL)
49   all over this file.
50 
51   The only place where multi-instance device paths are supported is in
52   environment varibles. Multi-instance device paths should never be placed
53   on a Handle.
54 
55   Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
56   This program and the accompanying materials
57   are licensed and made available under the terms and conditions of the BSD License
58   which accompanies this distribution.  The full text of the license may be found at
59   http://opensource.org/licenses/bsd-license.php.
60 
61   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
62   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
63 
64 **/
65 
66 //
67 // Template for an end-of-device path node.
68 //
69 static CONST EFI_DEVICE_PATH_PROTOCOL  mUefiDevicePathLibEndDevicePath = {
70   END_DEVICE_PATH_TYPE,
71   END_ENTIRE_DEVICE_PATH_SUBTYPE,
72   {
73     END_DEVICE_PATH_LENGTH,
74     0
75   }
76 };
77 
78 
79 /**
80   Returns the size of a device path in bytes.
81 
82   This function returns the size, in bytes, of the device path data structure
83   specified by DevicePath including the end of device path node.
84   If DevicePath is NULL or invalid, then 0 is returned.
85 
86   @param  DevicePath  A pointer to a device path data structure.
87 
88   @retval 0           If DevicePath is NULL or invalid.
89   @retval Others      The size of a device path in bytes.
90 
91 **/
92 UINTN
93 EFIAPI
GetDevicePathSize(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)94 GetDevicePathSize (
95   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
96   )
97 {
98   CONST EFI_DEVICE_PATH_PROTOCOL  *Start;
99 
100   if (DevicePath == NULL) {
101     return 0;
102   }
103 
104   if (!IsDevicePathValid (DevicePath, 0)) {
105     return 0;
106   }
107 
108   //
109   // Search for the end of the device path structure
110   //
111   Start = DevicePath;
112   while (!IsDevicePathEnd (DevicePath)) {
113     DevicePath = NextDevicePathNode (DevicePath);
114   }
115 
116   //
117   // Compute the size and add back in the size of the end device path structure
118   //
119   return ((UINTN) DevicePath - (UINTN) Start) + DevicePathNodeLength (DevicePath);
120 }
121 
122 /**
123   Determine whether a given device path is valid.
124   If DevicePath is NULL, then ASSERT().
125 
126   @param  DevicePath  A pointer to a device path data structure.
127   @param  MaxSize     The maximum size of the device path data structure.
128 
129   @retval TRUE        DevicePath is valid.
130   @retval FALSE       The length of any node in the DevicePath is less
131                       than sizeof (EFI_DEVICE_PATH_PROTOCOL).
132   @retval FALSE       If MaxSize is not zero, the size of the DevicePath
133                       exceeds MaxSize.
134   @retval FALSE       If PcdMaximumDevicePathNodeCount is not zero, the node
135                       count of the DevicePath exceeds PcdMaximumDevicePathNodeCount.
136 **/
137 BOOLEAN
138 EFIAPI
IsDevicePathValid(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN UINTN MaxSize)139 IsDevicePathValid (
140   IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
141   IN       UINTN                    MaxSize
142   )
143 {
144   UINTN Count;
145   UINTN Size;
146   UINTN NodeLength;
147 
148   ASSERT (DevicePath != NULL);
149 
150   if (MaxSize == 0) {
151     MaxSize = MAX_UINTN;
152   }
153 
154   //
155   // Validate the input size big enough to touch the first node.
156   //
157   if (MaxSize < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
158     return FALSE;
159   }
160 
161   for (Count = 0, Size = 0; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) {
162     NodeLength = DevicePathNodeLength (DevicePath);
163     if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
164       return FALSE;
165     }
166 
167     if (NodeLength > MAX_UINTN - Size) {
168       return FALSE;
169     }
170     Size += NodeLength;
171 
172     //
173     // Validate next node before touch it.
174     //
175     if (Size > MaxSize - END_DEVICE_PATH_LENGTH ) {
176       return FALSE;
177     }
178 
179     if (PcdGet32 (PcdMaximumDevicePathNodeCount) > 0) {
180       Count++;
181       if (Count >= PcdGet32 (PcdMaximumDevicePathNodeCount)) {
182         return FALSE;
183       }
184     }
185   }
186 
187   //
188   // Only return TRUE when the End Device Path node is valid.
189   //
190   return (BOOLEAN) (DevicePathNodeLength (DevicePath) == END_DEVICE_PATH_LENGTH);
191 }
192 
193 /**
194   Returns the Type field of a device path node.
195 
196   Returns the Type field of the device path node specified by Node.
197 
198   If Node is NULL, then ASSERT().
199 
200   @param  Node      A pointer to a device path node data structure.
201 
202   @return The Type field of the device path node specified by Node.
203 
204 **/
205 UINT8
206 EFIAPI
DevicePathType(IN CONST VOID * Node)207 DevicePathType (
208   IN CONST VOID  *Node
209   )
210 {
211   ASSERT (Node != NULL);
212   return ((const EFI_DEVICE_PATH_PROTOCOL *)(Node))->Type;
213 }
214 
215 
216 /**
217   Returns the SubType field of a device path node.
218 
219   Returns the SubType field of the device path node specified by Node.
220 
221   If Node is NULL, then ASSERT().
222 
223   @param  Node      A pointer to a device path node data structure.
224 
225   @return The SubType field of the device path node specified by Node.
226 
227 **/
228 UINT8
229 EFIAPI
DevicePathSubType(IN CONST VOID * Node)230 DevicePathSubType (
231   IN CONST VOID  *Node
232   )
233 {
234   ASSERT (Node != NULL);
235   return ((const EFI_DEVICE_PATH_PROTOCOL *)(Node))->SubType;
236 }
237 
238 /**
239   Returns the 16-bit Length field of a device path node.
240 
241   Returns the 16-bit Length field of the device path node specified by Node.
242   Node is not required to be aligned on a 16-bit boundary, so it is recommended
243   that a function such as ReadUnaligned16() be used to extract the contents of
244   the Length field.
245 
246   If Node is NULL, then ASSERT().
247 
248   @param  Node      A pointer to a device path node data structure.
249 
250   @return The 16-bit Length field of the device path node specified by Node.
251 
252 **/
253 UINTN
254 EFIAPI
DevicePathNodeLength(IN CONST VOID * Node)255 DevicePathNodeLength (
256   IN CONST VOID  *Node
257   )
258 {
259   ASSERT (Node != NULL);
260   return ((const EFI_DEVICE_PATH_PROTOCOL *)Node)->Length[0] |
261       (((const EFI_DEVICE_PATH_PROTOCOL *)Node)->Length[1] << 8);
262 }
263 
264 /**
265   Returns a pointer to the next node in a device path.
266 
267   Returns a pointer to the device path node that follows the device path node
268   specified by Node.
269 
270   If Node is NULL, then ASSERT().
271 
272   @param  Node      A pointer to a device path node data structure.
273 
274   @return a pointer to the device path node that follows the device path node
275   specified by Node.
276 
277 **/
278 EFI_DEVICE_PATH_PROTOCOL *
279 EFIAPI
NextDevicePathNode(IN CONST VOID * Node)280 NextDevicePathNode (
281   IN CONST VOID  *Node
282   )
283 {
284   ASSERT (Node != NULL);
285   return ((EFI_DEVICE_PATH_PROTOCOL *)(__DECONST(UINT8 *, Node) + DevicePathNodeLength(Node)));
286 }
287 
288 /**
289   Determines if a device path node is an end node of a device path.
290   This includes nodes that are the end of a device path instance and nodes that
291   are the end of an entire device path.
292 
293   Determines if the device path node specified by Node is an end node of a device path.
294   This includes nodes that are the end of a device path instance and nodes that are the
295   end of an entire device path.  If Node represents an end node of a device path,
296   then TRUE is returned.  Otherwise, FALSE is returned.
297 
298   If Node is NULL, then ASSERT().
299 
300   @param  Node      A pointer to a device path node data structure.
301 
302   @retval TRUE      The device path node specified by Node is an end node of a
303                     device path.
304   @retval FALSE     The device path node specified by Node is not an end node of
305                     a device path.
306 
307 **/
308 BOOLEAN
309 EFIAPI
IsDevicePathEndType(IN CONST VOID * Node)310 IsDevicePathEndType (
311   IN CONST VOID  *Node
312   )
313 {
314   ASSERT (Node != NULL);
315   return (BOOLEAN) (DevicePathType (Node) == END_DEVICE_PATH_TYPE);
316 }
317 
318 /**
319   Determines if a device path node is an end node of an entire device path.
320 
321   Determines if a device path node specified by Node is an end node of an entire
322   device path. If Node represents the end of an entire device path, then TRUE is
323   returned.  Otherwise, FALSE is returned.
324 
325   If Node is NULL, then ASSERT().
326 
327   @param  Node      A pointer to a device path node data structure.
328 
329   @retval TRUE      The device path node specified by Node is the end of an entire
330                     device path.
331   @retval FALSE     The device path node specified by Node is not the end of an
332                     entire device path.
333 
334 **/
335 BOOLEAN
336 EFIAPI
IsDevicePathEnd(IN CONST VOID * Node)337 IsDevicePathEnd (
338   IN CONST VOID  *Node
339   )
340 {
341   ASSERT (Node != NULL);
342   return (BOOLEAN) (IsDevicePathEndType (Node) && DevicePathSubType(Node) == END_ENTIRE_DEVICE_PATH_SUBTYPE);
343 }
344 
345 /**
346   Fills in all the fields of a device path node that is the end of an entire device path.
347 
348   Fills in all the fields of a device path node specified by Node so Node represents
349   the end of an entire device path.  The Type field of Node is set to
350   END_DEVICE_PATH_TYPE, the SubType field of Node is set to
351   END_ENTIRE_DEVICE_PATH_SUBTYPE, and the Length field of Node is set to
352   END_DEVICE_PATH_LENGTH.  Node is not required to be aligned on a 16-bit boundary,
353   so it is recommended that a function such as WriteUnaligned16() be used to set
354   the contents of the Length field.
355 
356   If Node is NULL, then ASSERT().
357 
358   @param  Node      A pointer to a device path node data structure.
359 
360 **/
361 VOID
362 EFIAPI
SetDevicePathEndNode(OUT VOID * Node)363 SetDevicePathEndNode (
364   OUT VOID  *Node
365   )
366 {
367   ASSERT (Node != NULL);
368   memcpy (Node, &mUefiDevicePathLibEndDevicePath, sizeof (mUefiDevicePathLibEndDevicePath));
369 }
370 
371 /**
372   Sets the length, in bytes, of a device path node.
373 
374   Sets the length of the device path node specified by Node to the value specified
375   by NodeLength.  NodeLength is returned.  Node is not required to be aligned on
376   a 16-bit boundary, so it is recommended that a function such as WriteUnaligned16()
377   be used to set the contents of the Length field.
378 
379   If Node is NULL, then ASSERT().
380   If NodeLength >= SIZE_64KB, then ASSERT().
381   If NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL), then ASSERT().
382 
383   @param  Node      A pointer to a device path node data structure.
384   @param  Length    The length, in bytes, of the device path node.
385 
386   @return Length
387 
388 **/
389 UINT16
390 EFIAPI
SetDevicePathNodeLength(IN OUT VOID * Node,IN UINTN Length)391 SetDevicePathNodeLength (
392   IN OUT VOID  *Node,
393   IN UINTN     Length
394   )
395 {
396   ASSERT (Node != NULL);
397   ASSERT ((Length >= sizeof (EFI_DEVICE_PATH_PROTOCOL)) && (Length < SIZE_64KB));
398 //  return WriteUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0], (UINT16)(Length));
399   le16enc(&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0], (UINT16)(Length));
400   return Length;
401 }
402 
403 /**
404   Creates a device node.
405 
406   This function creates a new device node in a newly allocated buffer of size
407   NodeLength and initializes the device path node header with NodeType and NodeSubType.
408   The new device path node is returned.
409   If NodeLength is smaller than a device path header, then NULL is returned.
410   If there is not enough memory to allocate space for the new device path, then
411   NULL is returned.
412   The memory is allocated from EFI boot services memory. It is the responsibility
413   of the caller to free the memory allocated.
414 
415   @param  NodeType                   The device node type for the new device node.
416   @param  NodeSubType                The device node sub-type for the new device node.
417   @param  NodeLength                 The length of the new device node.
418 
419   @return The new device path.
420 
421 **/
422 EFI_DEVICE_PATH_PROTOCOL *
423 EFIAPI
CreateDeviceNode(IN UINT8 NodeType,IN UINT8 NodeSubType,IN UINT16 NodeLength)424 CreateDeviceNode (
425   IN UINT8                           NodeType,
426   IN UINT8                           NodeSubType,
427   IN UINT16                          NodeLength
428   )
429 {
430   EFI_DEVICE_PATH_PROTOCOL      *DevicePath;
431 
432   if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
433     //
434     // NodeLength is less than the size of the header.
435     //
436     return NULL;
437   }
438 
439   DevicePath = AllocateZeroPool (NodeLength);
440   if (DevicePath != NULL) {
441      DevicePath->Type    = NodeType;
442      DevicePath->SubType = NodeSubType;
443      SetDevicePathNodeLength (DevicePath, NodeLength);
444   }
445 
446   return DevicePath;
447 }
448 
449 /**
450   Creates a new copy of an existing device path.
451 
452   This function allocates space for a new copy of the device path specified by DevicePath.
453   If DevicePath is NULL, then NULL is returned.  If the memory is successfully
454   allocated, then the contents of DevicePath are copied to the newly allocated
455   buffer, and a pointer to that buffer is returned.  Otherwise, NULL is returned.
456   The memory for the new device path is allocated from EFI boot services memory.
457   It is the responsibility of the caller to free the memory allocated.
458 
459   @param  DevicePath    A pointer to a device path data structure.
460 
461   @retval NULL          DevicePath is NULL or invalid.
462   @retval Others        A pointer to the duplicated device path.
463 
464 **/
465 EFI_DEVICE_PATH_PROTOCOL *
466 EFIAPI
DuplicateDevicePath(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)467 DuplicateDevicePath (
468   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
469   )
470 {
471   UINTN                     Size;
472 
473   //
474   // Compute the size
475   //
476   Size = GetDevicePathSize (DevicePath);
477   if (Size == 0) {
478     return NULL;
479   }
480 
481   //
482   // Allocate space for duplicate device path
483   //
484 
485   return AllocateCopyPool (Size, DevicePath);
486 }
487 
488 /**
489   Creates a new device path by appending a second device path to a first device path.
490 
491   This function creates a new device path by appending a copy of SecondDevicePath
492   to a copy of FirstDevicePath in a newly allocated buffer.  Only the end-of-device-path
493   device node from SecondDevicePath is retained. The newly created device path is
494   returned. If FirstDevicePath is NULL, then it is ignored, and a duplicate of
495   SecondDevicePath is returned.  If SecondDevicePath is NULL, then it is ignored,
496   and a duplicate of FirstDevicePath is returned. If both FirstDevicePath and
497   SecondDevicePath are NULL, then a copy of an end-of-device-path is returned.
498 
499   If there is not enough memory for the newly allocated buffer, then NULL is returned.
500   The memory for the new device path is allocated from EFI boot services memory.
501   It is the responsibility of the caller to free the memory allocated.
502 
503   @param  FirstDevicePath            A pointer to a device path data structure.
504   @param  SecondDevicePath           A pointer to a device path data structure.
505 
506   @retval NULL      If there is not enough memory for the newly allocated buffer.
507   @retval NULL      If FirstDevicePath or SecondDevicePath is invalid.
508   @retval Others    A pointer to the new device path if success.
509                     Or a copy an end-of-device-path if both FirstDevicePath and SecondDevicePath are NULL.
510 
511 **/
512 EFI_DEVICE_PATH_PROTOCOL *
513 EFIAPI
AppendDevicePath(IN CONST EFI_DEVICE_PATH_PROTOCOL * FirstDevicePath,OPTIONAL IN CONST EFI_DEVICE_PATH_PROTOCOL * SecondDevicePath OPTIONAL)514 AppendDevicePath (
515   IN CONST EFI_DEVICE_PATH_PROTOCOL  *FirstDevicePath,  OPTIONAL
516   IN CONST EFI_DEVICE_PATH_PROTOCOL  *SecondDevicePath  OPTIONAL
517   )
518 {
519   UINTN                     Size;
520   UINTN                     Size1;
521   UINTN                     Size2;
522   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
523   EFI_DEVICE_PATH_PROTOCOL  *DevicePath2;
524 
525   //
526   // If there's only 1 path, just duplicate it.
527   //
528   if (FirstDevicePath == NULL) {
529     return DuplicateDevicePath ((SecondDevicePath != NULL) ? SecondDevicePath : &mUefiDevicePathLibEndDevicePath);
530   }
531 
532   if (SecondDevicePath == NULL) {
533     return DuplicateDevicePath (FirstDevicePath);
534   }
535 
536   if (!IsDevicePathValid (FirstDevicePath, 0) || !IsDevicePathValid (SecondDevicePath, 0)) {
537     return NULL;
538   }
539 
540   //
541   // Allocate space for the combined device path. It only has one end node of
542   // length EFI_DEVICE_PATH_PROTOCOL.
543   //
544   Size1         = GetDevicePathSize (FirstDevicePath);
545   Size2         = GetDevicePathSize (SecondDevicePath);
546   Size          = Size1 + Size2 - END_DEVICE_PATH_LENGTH;
547 
548   NewDevicePath = AllocatePool (Size);
549 
550   if (NewDevicePath != NULL) {
551     NewDevicePath = CopyMem (NewDevicePath, FirstDevicePath, Size1);
552     //
553     // Over write FirstDevicePath EndNode and do the copy
554     //
555     DevicePath2 = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath +
556                   (Size1 - END_DEVICE_PATH_LENGTH));
557     CopyMem (DevicePath2, SecondDevicePath, Size2);
558   }
559 
560   return NewDevicePath;
561 }
562 
563 /**
564   Creates a new path by appending the device node to the device path.
565 
566   This function creates a new device path by appending a copy of the device node
567   specified by DevicePathNode to a copy of the device path specified by DevicePath
568   in an allocated buffer. The end-of-device-path device node is moved after the
569   end of the appended device node.
570   If DevicePathNode is NULL then a copy of DevicePath is returned.
571   If DevicePath is NULL then a copy of DevicePathNode, followed by an end-of-device
572   path device node is returned.
573   If both DevicePathNode and DevicePath are NULL then a copy of an end-of-device-path
574   device node is returned.
575   If there is not enough memory to allocate space for the new device path, then
576   NULL is returned.
577   The memory is allocated from EFI boot services memory. It is the responsibility
578   of the caller to free the memory allocated.
579 
580   @param  DevicePath                 A pointer to a device path data structure.
581   @param  DevicePathNode             A pointer to a single device path node.
582 
583   @retval NULL      If there is not enough memory for the new device path.
584   @retval Others    A pointer to the new device path if success.
585                     A copy of DevicePathNode followed by an end-of-device-path node
586                     if both FirstDevicePath and SecondDevicePath are NULL.
587                     A copy of an end-of-device-path node if both FirstDevicePath
588                     and SecondDevicePath are NULL.
589 
590 **/
591 EFI_DEVICE_PATH_PROTOCOL *
592 EFIAPI
AppendDevicePathNode(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath,OPTIONAL IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePathNode OPTIONAL)593 AppendDevicePathNode (
594   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath,     OPTIONAL
595   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePathNode  OPTIONAL
596   )
597 {
598   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
599   EFI_DEVICE_PATH_PROTOCOL  *NextNode;
600   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
601   UINTN                     NodeLength;
602 
603   if (DevicePathNode == NULL) {
604     return DuplicateDevicePath ((DevicePath != NULL) ? DevicePath : &mUefiDevicePathLibEndDevicePath);
605   }
606   //
607   // Build a Node that has a terminator on it
608   //
609   NodeLength = DevicePathNodeLength (DevicePathNode);
610 
611   TempDevicePath = AllocatePool (NodeLength + END_DEVICE_PATH_LENGTH);
612   if (TempDevicePath == NULL) {
613     return NULL;
614   }
615   TempDevicePath = CopyMem (TempDevicePath, DevicePathNode, NodeLength);
616   //
617   // Add and end device path node to convert Node to device path
618   //
619   NextNode = NextDevicePathNode (TempDevicePath);
620   SetDevicePathEndNode (NextNode);
621   //
622   // Append device paths
623   //
624   NewDevicePath = AppendDevicePath (DevicePath, TempDevicePath);
625 
626   FreePool (TempDevicePath);
627 
628   return NewDevicePath;
629 }
630