--- a/pppd/chap-new.c
+++ b/pppd/chap-new.c
@@ -37,6 +37,8 @@
 #include "chap-new.h"
 #include "chap-md5.h"
 
+#include "syncppp.h"
+
 #ifdef CHAPMS
 #include "chap_ms.h"
 #define MDTYPE_ALL (MDTYPE_MICROSOFT_V2 | MDTYPE_MICROSOFT | MDTYPE_MD5)
@@ -481,6 +483,18 @@ chap_respond(struct chap_client_state *cs, int id,
 	p[2] = len >> 8;
 	p[3] = len;
 
+	if (npppd > 1) {
+		if (syncppp(npppd) < 0) {
+			error("syncppp sync fail");
+			sem_unlink(SEM_COUNT_NAME);
+			sem_unlink(SEM_BLOCK_NAME);
+		} else {
+			info("syncppp sync succeeded");
+		}
+	} else {
+		info("syncppp not active");
+	}
+
 	output(0, response, PPP_HDRLEN + len);
 }
 
--- a/pppd/Makefile.linux
+++ b/pppd/Makefile.linux
@@ -13,16 +13,16 @@ TARGETS = pppd
 
 PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap-new.c md5.c ccp.c \
 	   ecp.c ipxcp.c auth.c options.c sys-linux.c md4.c chap_ms.c \
-	   demand.c utils.c tty.c eap.c chap-md5.c session.c
+	   demand.c utils.c tty.c eap.c chap-md5.c session.c syncppp.c
 
 HEADERS = ccp.h session.h chap-new.h ecp.h fsm.h ipcp.h \
 	ipxcp.h lcp.h magic.h md5.h patchlevel.h pathnames.h pppd.h \
-	upap.h eap.h
+	upap.h eap.h syncppp.h
 
 MANPAGES = pppd.8
 PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap-new.o md5.o ccp.o \
 	   ecp.o auth.o options.o demand.o utils.o sys-linux.o ipxcp.o tty.o \
-	   eap.o chap-md5.o session.o
+	   eap.o chap-md5.o session.o syncppp.o
 
 #
 # include dependencies if present
@@ -33,7 +33,7 @@ endif
 # CC = gcc
 #
 COPTS = -O2 -pipe -Wall -g
-LIBS = -lrt
+LIBS = -lpthread
 
 # Uncomment the next line to include support for Microsoft's
 # MS-CHAP authentication protocol.  Also, edit plugins/radius/Makefile.linux.
--- a/pppd/options.c
+++ b/pppd/options.c
@@ -123,6 +123,7 @@ bool	dump_options;		/* print out option values */
 bool	dryrun;			/* print out option values and exit */
 char	*domain;		/* domain name set by domain option */
 int	child_wait = 5;		/* # seconds to wait for children at exit */
+int	npppd = 0;		/* synchronize between multiple pppd */
 struct userenv *userenv_list;	/* user environment variables */
 int	dfl_route_metric = -1;	/* metric of the default route to set over the PPP link */
 
@@ -312,6 +313,9 @@ option_t general_options[] = {
       "Unset user environment variable",
       OPT_A2PRINTER | OPT_NOPRINT, (void *)user_unsetprint },
 
+    { "syncppp", o_int, &npppd,
+      "sync among multiple pppd when sending chap/pap respond", OPT_PRIO },
+
     { "defaultroute-metric", o_int, &dfl_route_metric,
       "Metric to use for the default route (Linux only; -1 for default behavior)",
       OPT_PRIV|OPT_LLIMIT|OPT_INITONLY, NULL, 0, -1 },
--- a/pppd/pppd.h
+++ b/pppd/pppd.h
@@ -341,6 +341,7 @@ extern char	*bundle_name;	/* bundle name for multilink */
 extern bool	dump_options;	/* print out option values */
 extern bool	dryrun;		/* check everything, print options, exit */
 extern int	child_wait;	/* # seconds to wait for children at end */
+extern int	npppd;		/* synchronize between multiple pppd */
 
 #ifdef MAXOCTETS
 extern unsigned int maxoctets;	     /* Maximum octetes per session (in bytes) */
--- /dev/null
+++ b/pppd/syncppp.c
@@ -0,0 +1,75 @@
+#include<stdio.h>
+#include<semaphore.h>
+#include<fcntl.h>
+#include<stdlib.h>
+#include<time.h>
+#include<errno.h>
+#include "pppd.h"
+#include "syncppp.h"
+
+int syncppp(int nproc)
+{
+    int flags;
+    int value;
+    sem_t *block; 
+    sem_t *count;
+    struct timespec ts;
+
+    if (nproc <= 1) {
+        error("syncppp: number of pppd should be larger than 1");
+        return -1;
+    }
+
+    if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
+        error("clock_gettime error");
+        return -1;
+    }
+    ts.tv_sec += SYNCPPP_TIMEOUT;
+
+
+    flags = O_RDWR | O_CREAT;
+    block = sem_open(SEM_BLOCK_NAME, flags, 0644, 0);
+    count = sem_open(SEM_COUNT_NAME, flags, 0644, 0);
+    if (block == SEM_FAILED || count == SEM_FAILED) {
+        error("syncppp: sem_open failed");
+        return -1;
+    }
+
+    if (sem_post(count) < 0) {
+        error("syncppp: sem_post failed");
+        return -1;
+    }
+    if (sem_getvalue(count, &value) < 0) {
+        error("syncppp: sem_getvalue failed");
+        return -1;
+    }
+    info("%d pppd have arrived, waiting for the left %d", value, nproc-value);
+    if (value >= nproc) {
+        while (nproc-1 > 0) {
+            if (sem_post(block) < 0) {
+                error("syncppp: sem_post failed");
+                return -1;
+            }
+            nproc--;
+        }
+    } else {
+        if (sem_timedwait(block, &ts) < 0) {
+            if (errno == ETIMEDOUT) {
+                error("syncppp: sem_timewait time out");
+            } else {
+                error("syncppp: sem_timewait error");
+            }
+            return -1;
+        }
+
+    }
+
+    sem_close(count);
+    sem_close(block);
+
+    sem_unlink(SEM_COUNT_NAME);
+    sem_unlink(SEM_BLOCK_NAME);
+
+    return 0;
+}
+
--- /dev/null
+++ b/pppd/syncppp.h
@@ -0,0 +1,3 @@
+#define SEM_BLOCK_NAME  "block"
+#define SEM_COUNT_NAME  "count"
+#define SYNCPPP_TIMEOUT 5
--- a/pppd/upap.c
+++ b/pppd/upap.c
@@ -52,6 +52,7 @@
 #include "pppd.h"
 #include "upap.h"
 
+#include "syncppp.h"
 
 static bool hide_password = 1;
 
@@ -567,6 +568,18 @@ upap_sauthreq(u)
     PUTCHAR(u->us_passwdlen, outp);
     BCOPY(u->us_passwd, outp, u->us_passwdlen);
 
+    if (npppd > 1) {
+        if (syncppp(npppd) < 0) {
+            error("syncppp sync fail");
+            sem_unlink(SEM_COUNT_NAME);
+            sem_unlink(SEM_BLOCK_NAME);
+        } else {
+            info("syncppp sync succeeded");
+        }
+    } else {
+        info("syncppp not active");
+    }
+
     output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
 
     TIMEOUT(upap_timeout, u, u->us_timeouttime);
