Index: src/lcp.c
===================================================================
--- src/lcp.c	(revision 2452)
+++ src/lcp.c	(revision 2454)
@@ -26,6 +26,7 @@
 
   #define LCP_ECHO_INTERVAL	5	/* Enable keep alive by default */
   #define LCP_ECHO_TIMEOUT	40
+  #define LCP_MAX_RESETS	3
 
   #define LCP_KNOWN_CODES	(   (1 << CODE_CONFIGREQ)	\
 				  | (1 << CODE_CONFIGACK)	\
@@ -180,6 +181,7 @@ LcpInit(Link l)
   FsmInit(&lcp->fsm, &gLcpFsmType, l);
   lcp->fsm.conf.echo_int = LCP_ECHO_INTERVAL;
   lcp->fsm.conf.echo_max = LCP_ECHO_TIMEOUT;
+  lcp->resets = LCP_MAX_RESETS;
   lcp->phase = PHASE_DEAD;
   
   AuthInit(l);
@@ -690,8 +692,17 @@ LcpLayerDown(Fsm fp)
     LcpState	const lcp = &l->lcp;
 
     LcpStopActivity(l);
-    if (lcp->phase == PHASE_AUTHENTICATE || lcp->phase == PHASE_NETWORK)
+    if (lcp->phase == PHASE_AUTHENTICATE || lcp->phase == PHASE_NETWORK) {
       lcp->need_reset = 1;
+      if (lcp->resets > 0) {
+	Log(LG_LCP2, ("[%s] LCP: Reset (%u left)", l->name, (int)lcp->resets));
+	lcp->resets--;
+      } else {
+        Log(LG_LCP2, ("[%s] LCP: Too many resets", l->name));
+	FsmFailure(&lcp->fsm, FAIL_NEGOT_FAILURE);
+	lcp->resets = LCP_MAX_RESETS;
+      }
+    }
 }
 
 void LcpOpen(Link l)
Index: src/lcp.h
===================================================================
--- src/lcp.h	(revision 2452)
+++ src/lcp.h	(revision 2454)
@@ -87,6 +87,7 @@
     struct fsm	fsm;			/* Finite state machine */
     
     u_char	need_reset;		/* LCP needs complete reset before ConfReq */
+    u_char	resets;			/* LCP resets left before failure */
   };
   typedef struct lcpstate	*LcpState;
 
Index: src/link.c
===================================================================
--- src/link.c.orig	2023-05-20 18:00:54.620544000 +0700
+++ src/link.c	2023-05-20 18:01:56.814757000 +0700
@@ -52,6 +52,17 @@
     SET_NO
   };
 
+  /* Used to prevent auto-up on links closed manually */
+  enum {
+    LINK_ADMINSTATE_DOWN = 0,
+    LINK_ADMINSTATE_OPERATIONAL
+  };
+
+  static const char *linkAdminStateNames[] = {
+    "DOWN",
+    "OPERATIONAL"
+  };
+  
   #define RBUF_SIZE		100
 
 /*
@@ -185,6 +196,18 @@ LinksShutdown(void)
 }
 
 /*
+ * LinkOpenAdm()
+ */
+
+void
+LinkOpenAdm(Link l)
+{
+    l->admin_state = LINK_ADMINSTATE_OPERATIONAL;
+    RecordLinkUpDownReason(NULL, l, 1, STR_MANUALLY, NULL);
+    LinkOpen(l);
+}
+
+/*
  * LinkOpenCmd()
  */
 
@@ -193,12 +216,23 @@ LinkOpenCmd(Context ctx)
 {
     if (ctx->lnk->tmpl)
 	Error("impossible to open template");
-    RecordLinkUpDownReason(NULL, ctx->lnk, 1, STR_MANUALLY, NULL);
-    LinkOpen(ctx->lnk);
+    LinkOpenAdm(ctx->lnk);
     return (0);
 }
 
 /*
+ * LinkCloseAdm()
+ */
+
+void
+LinkCloseAdm(Link l)
+{
+    l->admin_state = LINK_ADMINSTATE_DOWN;
+    RecordLinkUpDownReason(NULL, l, 0, STR_MANUALLY, NULL);
+    LinkClose(l);
+}
+
+/*
  * LinkCloseCmd()
  */
 
@@ -207,6 +241,7 @@ LinkCloseCmd(Context ctx)
 {
     if (ctx->lnk->tmpl)
 	Error("impossible to close template");
+    ctx->lnk->admin_state = LINK_ADMINSTATE_DOWN;
     RecordLinkUpDownReason(NULL, ctx->lnk, 0, STR_MANUALLY, NULL);
     LinkClose(ctx->lnk);
     return (0);
@@ -258,7 +293,7 @@ LinkDown(Link l)
 {
     Log(LG_LINK, ("[%s] Link: DOWN event", l->name));
 
-    if (OPEN_STATE(l->lcp.fsm.state)) {
+    if (OPEN_STATE(l->lcp.fsm.state) || l->admin_state != LINK_ADMINSTATE_DOWN) {
 	if (((l->conf.max_redial != 0) && (l->num_redial >= l->conf.max_redial)) ||
 	    gShutdownInProgress) {
 	    if (l->conf.max_redial >= 0) {
@@ -307,6 +342,8 @@ LinkReopenTimeout(void *arg)
     Log(LG_LINK, ("[%s] Link: reconnection attempt %hu",
 	l->name, l->num_redial));
     RecordLinkUpDownReason(NULL, l, 1, STR_REDIAL, NULL);
+    if (!OPEN_STATE(l->lcp.fsm.state))
+	LinkOpen(l);
     PhysOpen(l);
 }
 
@@ -411,6 +448,7 @@ LinkCreate(Context ctx, int ac, const char *const av[]
 	strlcpy(l->name, av[0 + stay], sizeof(l->name));
 	l->type = pt;
 	l->tmpl = tmpl;
+	l->admin_state = LINK_ADMINSTATE_OPERATIONAL;
 	l->stay = stay;
 	l->parent = -1;
 	SLIST_INIT(&l->actions);
@@ -552,6 +590,7 @@ LinkInst(Link lt, const char *name, int tmpl, int stay
 	    SLIST_INSERT_AFTER(ap, a, next);
 	ap = a;
     }
+    l->admin_state = LINK_ADMINSTATE_OPERATIONAL;
     l->tmpl = tmpl;
     l->stay = stay;
     /* Count link as one more child of parent. */
@@ -1322,6 +1361,7 @@ LinkStat(Context ctx, int ac, const char *const av[], 
 	Printf("\tChildren       : %d\r\n", l->children);
     else {
 	Printf("\tState          : %s\r\n", gPhysStateNames[l->state]);
+	Printf("\tAdmin. state   : %s\r\n", linkAdminStateNames[l->admin_state]);
 	Printf("\tSession Id     : %s\r\n", l->session_id);
 	Printf("\tPeer ident     : %s\r\n", l->lcp.peer_ident);
 	if (l->state == PHYS_STATE_UP)
Index: src/link.h
===================================================================
--- src/link.h.orig	2023-05-20 18:00:54.621341000 +0700
+++ src/link.h	2023-05-20 18:01:56.808633000 +0700
@@ -115,7 +115,8 @@
     int			id;			/* Index of this link in gLinks */
     u_char		tmpl;			/* This is template, not an instance */
     u_char		stay;			/* Must not disappear */
-    u_char		state;			/* Device current state */
+    u_char		state;			/* Physical device current state */
+    u_char		admin_state;		/* Link administrative state */
     u_char		joined_bund;		/* Link successfully joined bundle */
     u_char		originate;		/* Who originated the connection */
     u_char		die;			/* LCP agreed to die */
@@ -179,6 +180,8 @@
   extern void	LinkDown(Link l);
   extern void	LinkOpen(Link l);
   extern void	LinkClose(Link l);
+  extern void	LinkOpenAdm(Link l);
+  extern void	LinkCloseAdm(Link l);
   extern int	LinkOpenCmd(Context ctx);
   extern int	LinkCloseCmd(Context ctx);
 
--- src/main.c.orig	2023-05-20 17:59:19.804688000 +0700
+++ src/main.c	2023-05-20 18:01:56.815786000 +0700
@@ -556,13 +556,11 @@ OpenCloseSignal(int sig)
 	if (sig == SIGUSR1) {
 	    Log(LG_ALWAYS, ("[%s] rec'd signal %s, opening",
     		l->name, sys_signame[sig]));
-	    RecordLinkUpDownReason(NULL, l, 1, STR_MANUALLY, NULL);
-	    LinkOpen(l);
+	    LinkOpenAdm(l);
 	} else {
 	    Log(LG_ALWAYS, ("[%s] rec'd signal %s, closing",
     		l->name, sys_signame[sig]));
-	    RecordLinkUpDownReason(NULL, l, 0, STR_MANUALLY, NULL);
-	    LinkClose(l);
+	    LinkCloseAdm(l);
 	}
     } else
 	Log(LG_ALWAYS, ("rec'd signal %s, ignored", sys_signame[sig]));
Index: src/phys.c
===================================================================
--- src/phys.c	(revision 2452)
+++ src/phys.c	(revision 2461)
@@ -590,8 +590,8 @@ PhysMsg(int type, void *arg)
 	UNREF(l);
 	return;
     }
-    Log(LG_PHYS2, ("[%s] device: %s event",
-	l->name, MsgName(type)));
+    Log(LG_PHYS2, ("[%s] device: %s event in state %s",
+	l->name, MsgName(type), gPhysStateNames[l->state]));
     switch (type) {
     case MSG_OPEN:
     	l->downReasonValid=0;
@@ -599,7 +599,12 @@ PhysMsg(int type, void *arg)
 	    PhysUp(l);
 	    break;
 	}
-        (*l->type->open)(l);
+	/* Redial may result in MSG_OPEN for just opened device */
+	if (l->state != PHYS_STATE_UP)
+	    (*l->type->open)(l);
+	else
+	    Log(LG_PHYS2, ("[%s] device: OPEN event ignored",
+		l->name));
         break;
     case MSG_CLOSE:
         (*l->type->close)(l);
