[joiner] check Thread state on start (#5173)

diff --git a/include/openthread/instance.h b/include/openthread/instance.h
index ee0eb45..08b464b 100644
--- a/include/openthread/instance.h
+++ b/include/openthread/instance.h
@@ -53,7 +53,7 @@
  * @note This number versions both OpenThread platform and user APIs.
  *
  */
-#define OPENTHREAD_API_VERSION (11)
+#define OPENTHREAD_API_VERSION (12)
 
 /**
  * @addtogroup api-instance
diff --git a/include/openthread/joiner.h b/include/openthread/joiner.h
index adb10b2..15e35c2 100644
--- a/include/openthread/joiner.h
+++ b/include/openthread/joiner.h
@@ -106,8 +106,10 @@
  * @param[in]  aCallback         A pointer to a function that is called when the join operation completes.
  * @param[in]  aContext          A pointer to application-specific context.
  *
- * @retval OT_ERROR_NONE              Successfully started the Commissioner role.
+ * @retval OT_ERROR_NONE              Successfully started the Joiner role.
+ * @retval OT_ERROR_BUSY              The previous attempt is still on-going.
  * @retval OT_ERROR_INVALID_ARGS      @p aPskd or @p aProvisioningUrl is invalid.
+ * @retval OT_ERROR_INVALID_STATE     The IPv6 stack is not enabled or Thread stack is fully enabled.
  *
  */
 otError otJoinerStart(otInstance *     aInstance,
diff --git a/src/core/meshcop/joiner.cpp b/src/core/meshcop/joiner.cpp
index 3676aff..e668e6d 100644
--- a/src/core/meshcop/joiner.cpp
+++ b/src/core/meshcop/joiner.cpp
@@ -143,6 +143,8 @@
     otLogInfoMeshCoP("Joiner starting");
 
     VerifyOrExit(mState == OT_JOINER_STATE_IDLE, error = OT_ERROR_BUSY);
+    VerifyOrExit(Get<ThreadNetif>().IsUp() && Get<Mle::Mle>().GetRole() == Mle::kRoleDisabled,
+                 error = OT_ERROR_INVALID_STATE);
 
     SuccessOrExit(error = joinerPskd.SetFrom(aPskd));
 
diff --git a/src/core/meshcop/joiner.hpp b/src/core/meshcop/joiner.hpp
index 0e5a4e8..08bb3e7 100644
--- a/src/core/meshcop/joiner.hpp
+++ b/src/core/meshcop/joiner.hpp
@@ -76,7 +76,9 @@
      * @param[in]  aCallback         A pointer to a function that is called when the join operation completes.
      * @param[in]  aContext          A pointer to application-specific context.
      *
-     * @retval OT_ERROR_NONE  Successfully started the Joiner service.
+     * @retval OT_ERROR_NONE          Successfully started the Joiner service.
+     * @retval OT_ERROR_BUSY          The previous attempt is still on-going.
+     * @retval OT_ERROR_INVALID_STATE The IPv6 stack is not enabled or Thread stack is fully enabled.
      *
      */
     otError Start(const char *     aPskd,