libfdt: Add APIs for iterating and deleting subnodes

In detail, added following APIs for implementing FDT filtering:
  - FdtNodeMut::first_subnode()
  - FdtNodeMut::next_subnode()
  - FdtNodeMut::delete_and_next_subnode()

Bug: 277993056
Test: atest liblibfdt.integration_test
Change-Id: I18f93910ed5d28c4dbb2d38119b6839046775608
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index df57bd3..7eb08b2 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -777,6 +777,40 @@
         fdt_err(ret)
     }
 
+    /// Returns the first subnode of this
+    pub fn first_subnode(&'a mut self) -> Result<Option<Self>> {
+        // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
+        let ret = unsafe { libfdt_bindgen::fdt_first_subnode(self.fdt.as_ptr(), self.offset) };
+
+        Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
+    }
+
+    /// Returns the next subnode that shares the same parent with this
+    pub fn next_subnode(self) -> Result<Option<Self>> {
+        // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
+        let ret = unsafe { libfdt_bindgen::fdt_next_subnode(self.fdt.as_ptr(), self.offset) };
+
+        Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
+    }
+
+    /// Deletes the current node and returns the next subnode
+    pub fn delete_and_next_subnode(mut self) -> Result<Option<Self>> {
+        // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
+        let ret = unsafe { libfdt_bindgen::fdt_next_subnode(self.fdt.as_ptr(), self.offset) };
+
+        let next_offset = fdt_err_or_option(ret)?;
+
+        if Some(self.offset) == next_offset {
+            return Err(FdtError::Internal);
+        }
+
+        // SAFETY: nop_self() only touches bytes of the self and its properties and subnodes, and
+        // doesn't alter any other blob in the tree. self.fdt and next_offset would remain valid.
+        unsafe { self.nop_self()? };
+
+        Ok(next_offset.map(|offset| Self { fdt: self.fdt, offset }))
+    }
+
     fn parent(&'a self) -> Result<FdtNode<'a>> {
         // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
         let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };