diff --git a/package/pppd/0006-utils-add-mkdir_recursive.patch b/package/pppd/0006-utils-add-mkdir_recursive.patch
new file mode 100644
index 000000000000..fa52ee075830
--- /dev/null
+++ b/package/pppd/0006-utils-add-mkdir_recursive.patch
@@ -0,0 +1,294 @@
+From 2c1e12a7ebacc9b18b7c34f55bf01b75b292c2d9 Mon Sep 17 00:00:00 2001
+From: Dominique Martinet <dominique.martinet@atmark-techno.com>
+Date: Wed, 30 Aug 2023 11:46:01 +0900
+Subject: [PATCH] utils: add mkdir_recursive
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This will be used in the next commit.
+
+A test file for utils has also been added to check mkdir works as
+intended.
+
+Signed-off-by: Dominique Martinet <dominique.martinet@atmark-techno.com>
+Upstream: https://github.com/ppp-project/ppp/commit/b0e7307b3569a5dad0f2606d2736cc8317851598
+Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
+---
+ pppd/Makefile.am    |   6 ++
+ pppd/pppd-private.h |   1 +
+ pppd/utils.c        |  82 ++++++++++++++++++++++++++
+ pppd/utils_utest.c  | 139 ++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 228 insertions(+)
+ create mode 100644 pppd/utils_utest.c
+
+diff --git a/pppd/Makefile.am b/pppd/Makefile.am
+index 7cb30053322e..c5fe10776ede 100644
+--- a/pppd/Makefile.am
++++ b/pppd/Makefile.am
+@@ -20,6 +20,12 @@ utest_pppcrypt_LDFLAGS =
+ 
+ check_PROGRAMS += utest_crypto
+ 
++utest_utils_SOURCES = utils.c utils_utest.c
++utest_utils_CPPFLAGS = -DUNIT_TEST
++utest_utils_LDFLAGS =
++
++check_PROGRAMS += utest_utils
++
+ if WITH_SRP
+ sbin_PROGRAMS += srp-entry
+ dist_man8_MANS += srp-entry.8
+diff --git a/pppd/pppd-private.h b/pppd/pppd-private.h
+index 2883e4622acb..46ce0c8bdceb 100644
+--- a/pppd/pppd-private.h
++++ b/pppd/pppd-private.h
+@@ -437,6 +437,7 @@ int  sifproxyarp(int, u_int32_t);
+ int  cifproxyarp(int, u_int32_t);
+ 				/* Delete proxy ARP entry for peer */
+ u_int32_t GetMask(u_int32_t); /* Get appropriate netmask for address */
++int  mkdir_recursive(const char *); /* Recursively create directory */
+ int  lock(char *);	/* Create lock file for device */
+ int  relock(int);		/* Rewrite lock file with new pid */
+ void unlock(void);	/* Delete previously-created lock file */
+diff --git a/pppd/utils.c b/pppd/utils.c
+index c1bdbbbfe4e5..c47192e67fef 100644
+--- a/pppd/utils.c
++++ b/pppd/utils.c
+@@ -781,6 +781,88 @@ complete_read(int fd, void *buf, size_t count)
+ }
+ #endif
+ 
++/*
++ * mkdir_check - helper for mkdir_recursive, creates a directory
++ * but do not error on EEXIST if and only if entry is a directory
++ * The caller must check for errno == ENOENT if appropriate.
++ */
++static int
++mkdir_check(const char *path)
++{
++    struct stat statbuf;
++
++    if (mkdir(path, 0755) >= 0)
++	return 0;
++
++    if (errno == EEXIST) {
++	if (stat(path, &statbuf) < 0)
++	    /* got raced? */
++	    return -1;
++
++	if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
++	    return 0;
++
++	/* already exists but not a dir, treat as failure */
++	errno = EEXIST;
++	return -1;
++    }
++
++    return -1;
++}
++
++/*
++ * mkdir_parent - helper for mkdir_recursive, modifies the string in place
++ * Assumes mkdir(path) already failed, so it first creates the parent then
++ * full path again.
++ */
++static int
++mkdir_parent(char *path)
++{
++    char *slash;
++    int rc;
++
++    slash = strrchr(path, '/');
++    if (!slash)
++	return -1;
++
++    *slash = 0;
++    if (mkdir_check(path) < 0) {
++	if (errno != ENOENT) {
++	    *slash = '/';
++	    return -1;
++	}
++	if (mkdir_parent(path) < 0) {
++	    *slash = '/';
++	    return -1;
++	}
++    }
++    *slash = '/';
++
++    return mkdir_check(path);
++}
++
++/*
++ * mkdir_recursive - recursively create directory if it didn't exist
++ */
++int
++mkdir_recursive(const char *path)
++{
++    char *copy;
++    int rc;
++
++    // optimistically try on full path first to avoid allocation
++    if (mkdir_check(path) == 0)
++	return 0;
++
++    copy = strdup(path);
++    if (!copy)
++	return -1;
++
++    rc = mkdir_parent(copy);
++    free(copy);
++    return rc;
++}
++
+ /* Procedures for locking the serial device using a lock file. */
+ static char lock_file[MAXPATHLEN];
+ 
+diff --git a/pppd/utils_utest.c b/pppd/utils_utest.c
+new file mode 100644
+index 000000000000..cdca97e6d025
+--- /dev/null
++++ b/pppd/utils_utest.c
+@@ -0,0 +1,139 @@
++#include <fcntl.h>
++#include <string.h>
++#include <sys/stat.h>
++#include <unistd.h>
++
++#include "pppd-private.h"
++
++/* globals used in test.c... */
++int debug = 1;
++int error_count;
++int unsuccess;
++
++/* check if path exists and returns its type */
++static int
++file_type(char *path)
++{
++    struct stat statbuf;
++
++    if (stat(path, &statbuf) < 0)
++	return -1;
++
++    return statbuf.st_mode & S_IFMT;
++}
++
++int
++test_simple() {
++    if (mkdir_recursive("dir"))
++	return -1;
++
++    if (file_type("dir") != S_IFDIR)
++	return -1;
++
++    rmdir("dir");
++    return 0;
++}
++
++int
++test_recurse() {
++    if (mkdir_recursive("dir/subdir/subsubdir"))
++	return -1;
++
++    if (file_type("dir/subdir/subsubdir") != S_IFDIR)
++	return -1;
++
++    rmdir("dir/subdir/subsubdir");
++
++    /* try again with partial existence */
++    if (mkdir_recursive("dir/subdir/subsubdir"))
++	return -1;
++
++    if (file_type("dir/subdir/subsubdir") != S_IFDIR)
++	return -1;
++
++    rmdir("dir/subdir/subsubdir");
++    rmdir("dir/subdir");
++    rmdir("dir");
++    return 0;
++}
++
++int
++test_recurse_multislash() {
++    if (mkdir_recursive("dir/subdir///subsubdir"))
++	return -1;
++
++    if (file_type("dir/subdir/subsubdir") != S_IFDIR)
++	return -1;
++
++    rmdir("dir/subdir/subsubdir");
++    rmdir("dir/subdir");
++
++    /* try again with partial existence */
++    if (mkdir_recursive("dir/subdir/subsubdir///"))
++	return -1;
++
++    if (file_type("dir/subdir/subsubdir") != S_IFDIR)
++	return -1;
++
++    rmdir("dir/subdir/subsubdir");
++    rmdir("dir/subdir");
++    rmdir("dir");
++    return 0;
++}
++
++int
++test_parent_notdir() {
++    int fd = open("file", O_CREAT, 0600);
++    if (fd < 0)
++	return -1;
++    close(fd);
++
++    if (mkdir_recursive("file") == 0)
++	return -1;
++    if (mkdir_recursive("file/dir") == 0)
++	return -1;
++
++    unlink("file");
++    return 0;
++}
++
++int
++main()
++{
++    char *base_dir = strdup("/tmp/ppp_utils_utest.XXXXXX");
++    int failure = 0;
++
++    if (mkdtemp(base_dir) == NULL) {
++	printf("Could not create test directory, aborting\n");
++	return 1;
++    }
++
++    if (chdir(base_dir) < 0) {
++	printf("Could not enter newly created test dir, aborting\n");
++	return 1;
++    }
++
++    if (test_simple()) {
++	printf("Could not create simple directory\n");
++	failure++;
++    }
++
++    if (test_recurse()) {
++	printf("Could not create recursive directory\n");
++	failure++;
++    }
++
++    if (test_recurse_multislash()) {
++	printf("Could not create recursive directory with multiple slashes\n");
++	failure++;
++    }
++
++    if (test_parent_notdir()) {
++	printf("Creating over a file appeared to work?\n");
++	failure++;
++    }
++
++    rmdir(base_dir);
++    free(base_dir);
++    return failure;
++}
+-- 
+2.44.0
+
