[mle] fix some corner cases when trying to attach to a better partition (#2461)

diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp
index 4455484..e14099c 100644
--- a/src/core/thread/mle.cpp
+++ b/src/core/thread/mle.cpp
@@ -1647,11 +1647,23 @@
     Message *message = NULL;
     Ip6::Address destination;
 
-    if (mRole == OT_DEVICE_ROLE_CHILD &&
-        mParent.GetExtAddress() == mParentCandidate.GetExtAddress())
+    if (mParent.GetExtAddress() == mParentCandidate.GetExtAddress())
     {
-        otLogInfoMle(GetInstance(), "Already attached to candidate parent");
-        ExitNow(error = OT_ERROR_ALREADY);
+        if (mRole == OT_DEVICE_ROLE_CHILD)
+        {
+            otLogInfoMle(GetInstance(), "Already attached to candidate parent");
+            ExitNow(error = OT_ERROR_ALREADY);
+        }
+        else
+        {
+            // Invalidate stale parent state.
+            //
+            // Parent state is not normally invalidated after becoming a Router/Leader (see #1875).  When trying to
+            // attach to a better partition, invalidating old parent state (especially when in kStateRestored) ensures
+            // that GetNeighbor() returns mParentCandidate when processing the Child ID Response.
+            mParent.SetState(Neighbor::kStateInvalid);
+            otPlatSettingsDelete(&GetInstance(), Settings::kKeyParentInfo, -1);
+        }
     }
 
     VerifyOrExit((message = NewMleMessage()) != NULL, error = OT_ERROR_NO_BUFS);
diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp
index 7094909..582289b 100644
--- a/src/core/thread/mle_router.cpp
+++ b/src/core/thread/mle_router.cpp
@@ -551,7 +551,14 @@
 {
     otError error = OT_ERROR_NONE;
     Ip6::Address destination;
-    Message *message;
+    Message *message = NULL;
+
+    // Suppress MLE Advertisements when trying to attach to a better partition.
+    //
+    // Without this suppression, a device may send an MLE Advertisement before receiving the MLE Child ID Response.
+    // The candidate parent then removes the attaching device because the Source Address TLV includes an RLOC16 that
+    // indicates a Router role (i.e. a Child ID equal to zero).
+    VerifyOrExit(mParentRequestState == kParentIdle);
 
     VerifyOrExit((message = NewMleMessage()) != NULL, error = OT_ERROR_NO_BUFS);
     SuccessOrExit(error = AppendHeader(*message, Header::kCommandAdvertisement));