diff -Naur ppp-2.3.10/etc.ppp/callback-client ppp-2.3.10.CBCP/etc.ppp/callback-client
--- ppp-2.3.10/etc.ppp/callback-client	Thu Jan  1 01:00:00 1970
+++ ppp-2.3.10.CBCP/etc.ppp/callback-client	Wed Oct 27 08:51:18 1999
@@ -0,0 +1,9 @@
+#!/bin/sh
+# Script callback-client
+# Script parameters: delay time in seconds
+
+DELAY="$1"
+
+/usr/sbin/chat -v -t 2 "" \d+++\d\c OK ATH0 OK
+sleep $DELAY
+/usr/sbin/chat -v "" ATZ OK "" RING ATA CONNECT
diff -Naur ppp-2.3.10/etc.ppp/callback-server ppp-2.3.10.CBCP/etc.ppp/callback-server
--- ppp-2.3.10/etc.ppp/callback-server	Thu Jan  1 01:00:00 1970
+++ ppp-2.3.10.CBCP/etc.ppp/callback-server	Wed Jul 15 14:13:25 1998
@@ -0,0 +1,10 @@
+#!/bin/sh
+# Script callback-server
+# Script parameters: delay time in seconds, callback number
+
+DELAY="$1"
+NUMBER="$2"
+
+/usr/sbin/chat -v -t 2 "" \d+++\d\c OK ATH0 OK  
+sleep $DELAY
+/usr/sbin/chat -v "" ATZ OK ATD$NUMBER CONNECT
diff -Naur ppp-2.3.10/etc.ppp/callback-users ppp-2.3.10.CBCP/etc.ppp/callback-users
--- ppp-2.3.10/etc.ppp/callback-users	Thu Jan  1 01:00:00 1970
+++ ppp-2.3.10.CBCP/etc.ppp/callback-users	Thu Jul 16 23:53:44 1998
@@ -0,0 +1,10 @@
+# User list for callback
+# Username option
+# option - no callback
+# option * or empty user definied
+# option other admin definied: this number
+# in username * and ? wildcars valid, callback uses the best fit
+# Examples:
+# zotyo	67435	# user zotyo admin definied, number 67453
+# gates	-	# gates not called back
+*
\ No newline at end of file
diff -Naur ppp-2.3.10/pppd/Makefile.linux ppp-2.3.10.CBCP/pppd/Makefile.linux
--- ppp-2.3.10/pppd/Makefile.linux	Sat Sep 11 14:08:56 1999
+++ ppp-2.3.10.CBCP/pppd/Makefile.linux	Mon Oct 25 13:48:25 1999
@@ -14,7 +14,7 @@
 	   ipxcp.h cbcp.h
 MANPAGES = pppd.8
 PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
-	   auth.o options.o demand.o utils.o sys-linux.o ipxcp.o
+	   auth.o options.o demand.o utils.o sys-linux.o ipxcp.o cbcp.o
 
 all: pppd
 
@@ -50,7 +50,7 @@
 
 INCLUDE_DIRS= -I../include
 
-COMPILE_FLAGS= -D_linux_=1 -DHAVE_PATHS_H -DIPX_CHANGE
+COMPILE_FLAGS= -D_linux_=1 -DHAVE_PATHS_H -DIPX_CHANGE -DCBCP_SUPPORT
 
 CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS)
 
diff -Naur ppp-2.3.10/pppd/auth.c ppp-2.3.10.CBCP/pppd/auth.c
--- ppp-2.3.10/pppd/auth.c	Sat Sep 11 14:08:56 1999
+++ ppp-2.3.10.CBCP/pppd/auth.c	Mon Oct 25 12:51:38 1999
@@ -162,7 +162,6 @@
 
 /* Prototypes for procedures local to this file. */
 
-static void network_phase __P((int));
 static void check_idle __P((void *));
 static void connect_time_expired __P((void *));
 static int  plogin __P((char *, char *, char **));
@@ -453,8 +452,7 @@
 /*
  * Proceed to the network phase.
  */
-static void
-network_phase(unit)
+void network_phase(unit)
     int unit;
 {
     lcp_options *go = &lcp_gotoptions[unit];
@@ -474,7 +472,8 @@
     /*
      * If we negotiated callback, do it now.
      */
-    if (go->neg_cbcp) {
+    if (((go->neg_cbcp)||(lcp_hisoptions[ unit ].neg_cbcp))
+        &&(phase!=PHASE_CALLBACK)) {
 	new_phase(PHASE_CALLBACK);
 	(*cbcp_protent.open)(unit);
 	return;
diff -Naur ppp-2.3.10/pppd/cbcp.c ppp-2.3.10.CBCP/pppd/cbcp.c
--- ppp-2.3.10/pppd/cbcp.c	Fri Aug 13 08:46:10 1999
+++ ppp-2.3.10.CBCP/pppd/cbcp.c	Mon Oct 25 13:57:00 1999
@@ -18,30 +18,23 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#define RCSID	"$Id: cbcp.c,v 1.10 1999/08/13 06:46:10 paulus Exp $"
+#ifndef lint
+static const char rcsid[] = "$Id: cbcp.c,v 1.2 1997/04/30 05:50:26 paulus Exp $";
+#endif
 
 #include <stdio.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/time.h>
+#include <syslog.h>
+#include <sys/stat.h>
 
 #include "pppd.h"
 #include "cbcp.h"
 #include "fsm.h"
 #include "lcp.h"
-
-static const char rcsid[] = RCSID;
-
-/*
- * Options.
- */
-static int setcbcp __P((char **));
-
-static option_t cbcp_option_list[] = {
-    { "callback", o_special, setcbcp,
-      "Ask for callback" },
-    { NULL }
-};
+#include "ipcp.h"
+#include "pathnames.h"
 
 /*
  * Protocol entry points.
@@ -69,8 +62,6 @@
     0,
     "CBCP",
     NULL,
-    cbcp_option_list,
-    NULL,
     NULL,
     NULL
 };
@@ -79,26 +70,22 @@
 
 /* internal prototypes */
 
+static void cbcp_sendreq __P((void *arg));
 static void cbcp_recvreq __P((cbcp_state *us, char *pckt, int len));
-static void cbcp_resp __P((cbcp_state *us));
-static void cbcp_up __P((cbcp_state *us));
+static void cbcp_sendresp __P((cbcp_state *us));
+static void cbcp_recvresp __P((cbcp_state *us, char *pckt, int len));
+static void cbcp_sendack __P((void *));
 static void cbcp_recvack __P((cbcp_state *us, char *pckt, int len));
+
 static void cbcp_send __P((cbcp_state *us, u_char code, u_char *buf, int len));
+static void cbcp_make_options __P((int unit));
+static int  cbcp_check_user __P((char *user, char *mask));
+static void cbcp_start_callback __P((cbcp_state *us));
+static void cbcp_up __P((cbcp_state *us));
+
+
+cbcp_state *stop_iface = NULL;
 
-/* option processing */
-static int
-setcbcp(argv)
-    char **argv;
-{
-    lcp_wantoptions[0].neg_cbcp = 1;
-    cbcp_protent.enabled_flag = 1;
-    cbcp[0].us_number = strdup(*argv);
-    if (cbcp[0].us_number == 0)
-	novm("callback number");
-    cbcp[0].us_type |= (1 << CB_CONF_USER);
-    cbcp[0].us_type |= (1 << CB_CONF_ADMIN);
-    return (1);
-}
 
 /* init state */
 static void
@@ -110,7 +97,6 @@
     us = &cbcp[iface];
     memset(us, 0, sizeof(cbcp_state));
     us->us_unit = iface;
-    us->us_type |= (1 << CB_CONF_NO);
 }
 
 /* lower layer is up */
@@ -120,18 +106,19 @@
 {
     cbcp_state *us = &cbcp[iface];
 
-    dbglog("cbcp_lowerup");
-    dbglog("want: %d", us->us_type);
-
-    if (us->us_type == CB_CONF_USER)
-        dbglog("phone no: %s", us->us_number);
+    CBCPDEBUG((LOG_DEBUG, "cbcp_lowerup"));
+    CBCPDEBUG((LOG_DEBUG, "want: %d", us->us_type));
 }
 
+/* CBCP indulhat: kliens oldal eseten nincs feladat,
+		szerver oldalon atkuldeni a valszthato opciokat */
 static void
 cbcp_open(unit)
     int unit;
 {
-    dbglog("cbcp_open");
+    CBCPDEBUG((LOG_DEBUG, "cbcp_open"));
+    if (lcp_hisoptions[unit].neg_cbcp)
+	cbcp_make_options(unit);
 }
 
 /* process an incomming packet */
@@ -146,11 +133,13 @@
     u_short len;
 
     cbcp_state *us = &cbcp[unit];
+    lcp_options *go  = &lcp_gotoptions[unit];
+    lcp_options *his = &lcp_hisoptions[unit];
 
     inp = inpacket;
 
     if (pktlen < CBCP_MINLEN) {
-        error("CBCP packet is too small");
+        syslog(LOG_ERR, "CBCP packet is too small");
 	return;
     }
 
@@ -160,7 +149,7 @@
 
 #if 0
     if (len > pktlen) {
-        error("CBCP packet: invalid length");
+        syslog(LOG_ERR, "CBCP packet: invalid length");
         return;
     }
 #endif
@@ -169,17 +158,36 @@
  
     switch(code) {
     case CBCP_REQ:
+	if ( !go->neg_cbcp )
+	{
+    	    syslog(LOG_ERR, "CBCP received CBCP_REQ, but CBCP running in server mode!");
+	    return;
+	}
         us->us_id = id;
 	cbcp_recvreq(us, inp, len);
 	break;
 
     case CBCP_RESP:
-	dbglog("CBCP_RESP received");
+	if ( !his->neg_cbcp )
+	{
+    	    syslog(LOG_ERR, "CBCP received CBCP_RESP, but CBCP running in client mode!");
+	    return;
+	}
+	if (id != us->us_id)
+	    syslog(LOG_DEBUG, "id doesn't match: expected %d recv %d",
+		   us->us_id, id);
+
+	cbcp_recvresp(us, inp, len);
 	break;
 
     case CBCP_ACK:
+	if ( !go->neg_cbcp )
+	{
+    	    syslog(LOG_ERR, "CBCP received CBCP_ACK, but CBCP running in server mode!");
+	    return;
+	}
 	if (id != us->us_id)
-	    dbglog("id doesn't match: expected %d recv %d",
+	    syslog(LOG_DEBUG, "id doesn't match: expected %d recv %d",
 		   us->us_id, id);
 
 	cbcp_recvack(us, inp, len);
@@ -259,13 +267,14 @@
 		printer(arg, " delay = %d", delay);
 	    }
 
-	    if (olen > 3) {
+	    if (olen > 4) {
 	        int addrt;
 		char str[256];
 
 		GETCHAR(addrt, p);
 		memcpy(str, p, olen - 4);
 		str[olen - 4] = 0;
+		p += olen - 4;
 		printer(arg, " number = %s", str);
 	    }
 	    printer(arg, ">");
@@ -291,41 +300,40 @@
     char *pckt;
     int pcktlen;
 {
-    u_char type, opt_len, delay, addr_type;
+    u_char type, opt_len, addr_type;
     char address[256];
     int len = pcktlen;
 
     address[0] = 0;
 
     while (len) {
-        dbglog("length: %d", len);
-
 	GETCHAR(type, pckt);
 	GETCHAR(opt_len, pckt);
 
+	us->us_delay =0;
 	if (opt_len > 2)
-	    GETCHAR(delay, pckt);
+	    GETCHAR(us->us_delay, pckt);
 
 	us->us_allowed |= (1 << type);
 
 	switch(type) {
 	case CB_CONF_NO:
-	    dbglog("no callback allowed");
+	    CBCPDEBUG((LOG_DEBUG, "no callback allowed"));
 	    break;
 
 	case CB_CONF_USER:
-	    dbglog("user callback allowed");
+	    CBCPDEBUG((LOG_DEBUG, "user callback allowed"));
 	    if (opt_len > 4) {
 	        GETCHAR(addr_type, pckt);
 		memcpy(address, pckt, opt_len - 4);
 		address[opt_len - 4] = 0;
 		if (address[0])
-		    dbglog("address: %s", address);
+		    CBCPDEBUG((LOG_DEBUG, "address: %s", address));
 	    }
 	    break;
 
 	case CB_CONF_ADMIN:
-	    dbglog("user admin defined allowed");
+	    CBCPDEBUG((LOG_DEBUG, "user admin defined allowed"));
 	    break;
 
 	case CB_CONF_LIST:
@@ -334,60 +342,64 @@
 	len -= opt_len;
     }
 
-    cbcp_resp(us);
+    cbcp_sendresp(us);
 }
 
 static void
-cbcp_resp(us)
+cbcp_sendresp(us)
     cbcp_state *us;
 {
-    u_char cb_type;
+    u_char cb_allowed;
     u_char buf[256];
     u_char *bufp = buf;
     int len = 0;
 
-    cb_type = us->us_allowed & us->us_type;
-    dbglog("cbcp_resp cb_type=%d", cb_type);
+    cb_allowed = us->us_allowed;
+    CBCPDEBUG((LOG_DEBUG, "cbcp_sendresp: available options: %d", cb_allowed));
 
 #if 0
-    if (!cb_type)
+    if (!cb_allowed)
         lcp_down(us->us_unit);
 #endif
 
-    if (cb_type & ( 1 << CB_CONF_USER ) ) {
-	dbglog("cbcp_resp CONF_USER");
+    if (cb_allowed & ( 1 << CB_CONF_USER ) ) { /* The best metod :-) */
+	us->us_type= ( 1 << CB_CONF_USER );
+	CBCPDEBUG((LOG_DEBUG, "cbcp_sendresp CONF_USER"));
 	PUTCHAR(CB_CONF_USER, bufp);
 	len = 3 + 1 + strlen(us->us_number) + 1;
 	PUTCHAR(len , bufp);
-	PUTCHAR(5, bufp); /* delay */
+	PUTCHAR(us->us_delay, bufp);
 	PUTCHAR(1, bufp);
 	BCOPY(us->us_number, bufp, strlen(us->us_number) + 1);
 	cbcp_send(us, CBCP_RESP, buf, len);
 	return;
     }
 
-    if (cb_type & ( 1 << CB_CONF_ADMIN ) ) {
-	dbglog("cbcp_resp CONF_ADMIN");
+    if (cb_allowed & ( 1 << CB_CONF_ADMIN ) ) {
+	us->us_type= ( 1 << CB_CONF_ADMIN );
+	CBCPDEBUG((LOG_DEBUG, "cbcp_sendresp CONF_ADMIN"));
         PUTCHAR(CB_CONF_ADMIN, bufp);
 	len = 3;
-	PUTCHAR(len, bufp);
-	PUTCHAR(5, bufp); /* delay */
+	PUTCHAR(len , bufp);
+	PUTCHAR(us->us_delay, bufp);
 	cbcp_send(us, CBCP_RESP, buf, len);
 	return;
     }
 
-    if (cb_type & ( 1 << CB_CONF_NO ) ) {
-        dbglog("cbcp_resp CONF_NO");
+    if (cb_allowed & ( 1 << CB_CONF_NO ) ) {
+	us->us_type= ( 1 << CB_CONF_NO );
+        CBCPDEBUG((LOG_DEBUG, "cbcp_sendresp CONF_NO"));
 	PUTCHAR(CB_CONF_NO, bufp);
 	len = 3;
 	PUTCHAR(len , bufp);
 	PUTCHAR(0, bufp);
 	cbcp_send(us, CBCP_RESP, buf, len);
-	start_networks();
 	return;
     }
+    syslog(LOG_WARNING, "cbcp_sendresp: no usable options available!");
 }
 
+/* Send the packet */
 static void
 cbcp_send(us, code, buf, len)
     cbcp_state *us;
@@ -414,43 +426,427 @@
     output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
 }
 
+/* Received Ack */
 static void
 cbcp_recvack(us, pckt, len)
     cbcp_state *us;
     char *pckt;
     int len;
 {
-    u_char type, delay, addr_type;
+    u_char type, addr_type;
     int opt_len;
     char address[256];
 
+    stop_iface = us;
+
     if (len) {
         GETCHAR(type, pckt);
 	GETCHAR(opt_len, pckt);
      
 	if (opt_len > 2)
-	    GETCHAR(delay, pckt);
+	    GETCHAR(us->us_delay, pckt);
 
 	if (opt_len > 4) {
 	    GETCHAR(addr_type, pckt);
 	    memcpy(address, pckt, opt_len - 4);
 	    address[opt_len - 4] = 0;
 	    if (address[0])
-	        dbglog("peer will call: %s", address);
+	        CBCPDEBUG((LOG_DEBUG, "peer will call: %s", address));
 	}
-	if (type == CB_CONF_NO)
-	    return;
+	if (type != CB_CONF_NO)
+	{
+    	    callback_in_progress = us->us_unit + 1;
+	    callback_in_progress |=  CBCP_CLIENT;
+	    cbcp_up(us);
+	}
+	else
+	    network_phase(us->us_unit);    
     }
+    else
+        syslog(LOG_DEBUG, "cbcp: received bad ack - packet too small");
+    
 
-    cbcp_up(us);
 }
 
-/* ok peer will do callback */
+/* Make options
+   if auth req, options from callback-users file, else use CBCP_CONF_USER */
+static void
+cbcp_make_options (unit)
+    int	unit;
+{
+    cbcp_state *us = &cbcp[unit];
+    FILE *userfile;
+    struct stat sbuf;
+    int best_fit, got_fit, newline;
+    char  uname[ 256 ], option[ 256 ];    
+
+    us->us_id = 1;
+    us->us_count = 0;
+    us->us_delay = 5; /* Default delay 5 seconds */
+    if ( *peer_authname ) { /* Username available */
+	userfile = fopen( _PATH_CBCP_USERS, "r" );
+	if ( userfile == NULL ){
+	    syslog( LOG_ERR, "Can't open callback user file: %s %m",
+	            _PATH_CBCP_USERS );
+	    syslog( LOG_WARNING, "Allow user definied callback." );
+	    us->us_allowed = ( 1 << CB_CONF_USER );
+	}else
+	{
+    	    if ( fstat(fileno(userfile), &sbuf) < 0) {
+		syslog(LOG_WARNING, "Cannot stat userfile file %s: %m",
+	            _PATH_CBCP_USERS );
+	    } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
+		syslog(LOG_WARNING, "Warning - user file %s has world and/or group access",
+	            _PATH_CBCP_USERS );
+	    }
+
+	    us->us_allowed = ( 1 << CB_CONF_NO ); /* Assume, no callback allowed */
+
+	    if (getword(userfile, uname, &newline, _PATH_CBCP_USERS)){	/* file not empty */
+	        newline = 1;
+		best_fit = 0;
+		*option = 0;
+		for (;;) {
+	    	    /*
+		     * Skip until we find a word at the start of a line.
+		     */
+		    while (!newline && getword(userfile, uname, 
+						&newline, _PATH_CBCP_USERS))
+			;
+		    if (!newline)
+			break;		/* got to end of file */
+
+		    /*
+	             * Got a user - check if it's a match or a wildcard.
+	             */
+		    got_fit = cbcp_check_user( peer_authname, uname );
+		    if ( got_fit <= best_fit ){
+			newline = 0;
+			continue;
+		    }
+		    
+		    /* Read the options */
+		    best_fit = got_fit;
+		    if (getword(userfile, option, &newline, _PATH_CBCP_USERS))
+			break;
+			
+		    if ( newline )
+			*option = 0;
+
+		    if ( best_fit == 100 )
+			break;
+		}
+	    }
+
+	    switch ( *option ){
+	    case '-' : us->us_allowed = ( 1 << CB_CONF_NO ); break;
+	    case '*' :
+	    case  0  : us->us_allowed = ( 1 << CB_CONF_USER ); break;
+	    default  : us->us_allowed = ( 1 << CB_CONF_ADMIN );
+		       us->us_number = strdup( option ); break;
+	    }
+	    fclose( userfile );
+	}    
+    }
+    else
+	us->us_allowed = ( 1 << CB_CONF_USER );
+        
+    cbcp_sendreq( us );
+}    
+
+
+/* make cbcp request packet & send it */
+static void
+cbcp_sendreq (arg)
+    void *arg;
+{
+    cbcp_state *us=(cbcp_state *)arg;
+    u_char cb_allow = us->us_allowed;
+    u_char buf[256];
+    u_char *bufp = buf;
+    int len = 0;
+    
+    us->us_count++;
+    if (us->us_count<=CBCP_MAXRETRY)
+	TIMEOUT( cbcp_sendreq, arg, CBCP_DEFTIMEOUT );
+    else
+    {
+	lcp_close(0, "Sorry, CBCP not responding.");
+	return;
+    }
+    CBCPDEBUG((LOG_DEBUG, "cbcp_sendreq cb_allowed=%d", cb_allow));
+
+
+    if (cb_allow & ( 1 << CB_CONF_USER ) ) {
+	CBCPDEBUG((LOG_DEBUG, "cbcp_sendreq CONF_USER"));
+	PUTCHAR(CB_CONF_USER, bufp);
+	len+=3;
+	PUTCHAR(3 , bufp);
+	PUTCHAR(us->us_delay, bufp);
+    }
+
+    if (cb_allow & ( 1 << CB_CONF_ADMIN ) ) {
+	CBCPDEBUG((LOG_DEBUG, "cbcp_sendreq CONF_ADMIN"));
+        PUTCHAR(CB_CONF_ADMIN, bufp);
+	len += 3;
+	PUTCHAR(3 , bufp);
+	PUTCHAR(us->us_delay, bufp);
+    }
+
+    if (cb_allow & ( 1 << CB_CONF_NO ) ) {
+        CBCPDEBUG((LOG_DEBUG, "cbcp_sendreq CONF_NO"));
+	PUTCHAR(CB_CONF_NO, bufp);
+	len += 3;
+	PUTCHAR(3 , bufp);
+	PUTCHAR(us->us_delay, bufp);
+    }
+
+    if (len)
+	cbcp_send(us, CBCP_REQ, buf, len);
+    else
+    {
+        syslog(LOG_WARNING, "cbcp: no available options to client!");    
+    }	
+}  
+
+/* Received CBCP response, make ACK */
+static void
+cbcp_recvresp (us, pckt, len)
+    cbcp_state *us;
+    char *pckt;
+    int len;
+{
+    u_char type, addr_type;
+    int opt_len;
+    char address[256];
+
+    if (len) {
+        GETCHAR(type, pckt);
+	GETCHAR(opt_len, pckt);
+     
+	if (!(( 1 << type )& us->us_allowed )) {
+            CBCPDEBUG((LOG_DEBUG, "CBCP received options not allowed on server!"));
+	    return;	    
+	}
+
+	if ((type!= CB_CONF_NO ) &&
+	    (type!= CB_CONF_USER ) &&
+	    (type!= CB_CONF_ADMIN )) {
+            syslog(LOG_DEBUG, "CBCP received BAD Response: too more or unknown options %d",type);
+	    return;	    
+	}
+	
+	UNTIMEOUT( cbcp_sendreq, us );
+        us->us_count = 0;
+
+
+	if (opt_len > 2)
+	    GETCHAR(us->us_delay, pckt)
+	if ( us->us_delay < 5 ) 
+	    us->us_delay = 5;
+
+	if (opt_len > 4) {
+	    GETCHAR(addr_type, pckt); /*  Address Type mezo elvesztve  !!! */
+	    memcpy(address, pckt, opt_len - 4);
+	    address[opt_len - 4] = 0;
+	    if (address[0])
+	        syslog(LOG_DEBUG, "peer will callback the client on: %s", address);
+	    us->us_number=strdup( address );
+	}
+
+	us->us_type = ( 1 << type );    
+	cbcp_sendack( us );
+    }
+    else
+    {
+        syslog(LOG_DEBUG, "CBCP received BAD Response: size to small");
+    }
+}
+
+/* Send the CBCP_ACK packet */
+static void
+cbcp_sendack (arg)
+    void *arg;
+{
+    cbcp_state *us= (cbcp_state *)arg;
+    u_char cb_type;
+    u_char buf[256];
+    u_char *bufp = buf;
+    int len = 0;
+    
+    stop_iface = (cbcp_state *)arg;
+    cb_type = us->us_type;
+    
+    CBCPDEBUG((LOG_DEBUG, "cbcp_sendack cb_type=%d", cb_type));
+
+    us->us_count++;
+    if (us->us_count<=CBCP_MAXRETRY)
+	TIMEOUT( cbcp_sendack, arg, CBCP_DEFTIMEOUT );
+    else
+    {
+	lcp_close(0, "Sorry, CBCP not responding.");
+	return;
+    }
+
+#if 0
+    if (!cb_type)
+        lcp_down(us->us_unit);
+#endif
+
+    if (cb_type == (1 << CB_CONF_USER )) {
+	CBCPDEBUG((LOG_DEBUG, "cbcp_sendack CONF_USER"));
+	PUTCHAR(CB_CONF_USER, bufp);
+	len = 3 + 1 + strlen(us->us_number) + 1;
+	PUTCHAR(len , bufp);
+	PUTCHAR(us->us_delay, bufp); /* delay */
+	PUTCHAR(1, bufp); /* Elvesztett byte... */
+	BCOPY(us->us_number, bufp, strlen(us->us_number) + 1);
+	cbcp_send(us, CBCP_ACK, buf, len);
+/*	lcp_close( 2, "Illegal, but required to server..." ); */
+        callback_in_progress = us->us_unit + 1;
+	return;
+    }
+
+    if (cb_type == (1 << CB_CONF_ADMIN )) {
+	CBCPDEBUG((LOG_DEBUG, "cbcp_sendack CONF_ADMIN"));
+        PUTCHAR(CB_CONF_ADMIN, bufp);
+	len = 3 + 1;
+	PUTCHAR(len , bufp);
+	PUTCHAR(us->us_delay, bufp); /* delay */
+	PUTCHAR(0, bufp);
+	cbcp_send(us, CBCP_ACK, buf, len);
+/*	lcp_close( 2, "Illegal, but required to server..." ); */
+        callback_in_progress = us->us_unit + 1;
+	return;
+    }
+
+    if (cb_type == (1 << CB_CONF_NO )) {
+        CBCPDEBUG((LOG_DEBUG, "cbcp_sendack CONF_NO"));
+	PUTCHAR(CB_CONF_NO, bufp);
+	len = 3;
+	PUTCHAR(len , bufp);
+	PUTCHAR(0, bufp);
+	cbcp_send(us, CBCP_ACK, buf, len);
+	if (us->us_count<=1)
+	    network_phase(us->us_unit);
+	return;
+    }
+
+    syslog(LOG_DEBUG, "CBCP - Bad options in Ack routine.");
+
+}
+
+/* CBCP coming succesful up */
+void cbcp_stop()
+{
+    if ( stop_iface && lcp_allowoptions[stop_iface->us_unit].neg_cbcp )
+    {
+	UNTIMEOUT( cbcp_sendack, stop_iface );
+	cbcp_start_callback( stop_iface );
+    }
+}
+
+/* The server side coming up & client 'ack-ed' */
+void cbcp_start_callback (us)
+    cbcp_state *us;
+{
+    lcp_allowoptions[us->us_unit].neg_cbcp=0;
+
+    CBCPDEBUG((LOG_DEBUG, "cbcp_start_callback running"));
+}
+
+/* The client side coming up: server allowed the callback */
 static void
 cbcp_up(us)
     cbcp_state *us;
 {
-    persist = 0;
-    lcp_close(0, "Call me back, please");
-    status = EXIT_CALLBACK;
+    lcp_wantoptions[us->us_unit].neg_cbcp=0;
+    CBCPDEBUG((LOG_DEBUG, "cbcp_up called"));
+    lcp_close(us->us_unit, "Call me back, please");
 }
+
+/* The main module gets the script with parameters to run */
+char *cbcp_get_script()
+{
+    cbcp_state *us = &cbcp[(callback_in_progress & CBCP_NCLIENT)-1];
+    char script[ 256 ];
+    
+    if ( callback_in_progress & CBCP_CLIENT )
+	sprintf( script, "%s %d", _PATH_CBCP_CLIENT, us->us_delay );
+    else
+	sprintf( script, "%s %d %s", _PATH_CBCP_SERVER, 
+	us->us_delay, us->us_number );
+
+    return strdup( script );        
+}
+
+/* give me the hit rate. wild cars '*?' valids */
+int cbcp_check_user ( user, mask )
+    char *user;
+    char *mask;
+{
+    char *curr_user = user;
+    char *curr_mask = mask;
+    char *find, backp = 0;
+    int  count, len = 0;
+    
+    if ( !strcmp( user, mask ))
+	return 100;
+	
+    if ( !strcmp( mask, "*" ))
+	return 1;
+	
+    if ( !*user )
+	return 0;
+
+    count = 0;
+
+    while(( find = strpbrk( curr_mask, "*?" )) != 0 ) {
+	if ( find != curr_mask ){
+	    len = find - curr_mask;
+	    if ( strncmp( curr_user, curr_mask, len ))
+		break;	    
+	}
+
+	curr_mask += len + 1;
+	curr_user += len;
+	count += len;
+	if ( *curr_user == 0 )
+	    break;
+	
+	if ( *find == '?' ) {
+	    curr_user++;
+	    if ( *curr_user == 0 )
+		break;
+	} else {
+	    if ( *curr_mask == 0 )
+		break;
+		
+	    if ( ( find = strpbrk( curr_mask, "*?" )) != 0 ){
+		backp = *find;
+		*find = 0;
+	    }
+	    curr_user = strstr( curr_user, curr_mask );
+	    if ( find )
+		*find = backp;
+	    if ( !curr_user )
+		break;
+	    
+	    find = strpbrk( curr_mask, "*?" );
+	    if ( find )
+		len = find - curr_mask;
+	    else
+		len = strlen( curr_mask );
+		
+	    curr_mask += len;
+	    curr_user += len;
+	    count += len;
+	}	
+    }
+    
+    if ( *curr_user && *curr_mask && !strcmp( curr_user, curr_mask ))
+	count += strlen( curr_user );
+
+    return ( count * 100 / strlen( user ) );
+}
+
diff -Naur ppp-2.3.10/pppd/cbcp.h ppp-2.3.10.CBCP/pppd/cbcp.h
--- ppp-2.3.10/pppd/cbcp.h	Sat Nov  7 07:55:38 1998
+++ ppp-2.3.10.CBCP/pppd/cbcp.h	Wed Jun  2 10:01:25 1999
@@ -6,6 +6,8 @@
     u_char us_id;		/* Current id */
     u_char us_allowed;
     int    us_type;
+    u_char us_delay;
+    u_char us_count;
     char   *us_number;    /* Telefone Number */
 } cbcp_state;
 
@@ -19,8 +21,19 @@
 #define CBCP_RESP   2
 #define CBCP_ACK    3
 
+#define CBCP_DEFTIMEOUT	5
+#define CBCP_MAXRETRY	50
+#define CBCP_CLIENT	0x8000
+#define CBCP_NCLIENT	0x7fff
+
+#define CBCPDEBUG(x)	if (debug) syslog x
+
 #define CB_CONF_NO     1
 #define CB_CONF_USER   2
 #define CB_CONF_ADMIN  3
 #define CB_CONF_LIST   4
+
+char *cbcp_get_script __P(());
+void  cbcp_stop __P(());
+
 #endif
diff -Naur ppp-2.3.10/pppd/ipcp.c ppp-2.3.10.CBCP/pppd/ipcp.c
--- ppp-2.3.10/pppd/ipcp.c	Tue Aug 24 07:31:09 1999
+++ ppp-2.3.10.CBCP/pppd/ipcp.c	Mon Oct 25 12:58:17 1999
@@ -37,6 +37,10 @@
 #include "ipcp.h"
 #include "pathnames.h"
 
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
+
 static const char rcsid[] = RCSID;
 
 /* global vars */
@@ -1015,6 +1019,9 @@
     u_char maxslotindex, cflag;
     int d;
 
+#ifdef CBCP_SUPPORT
+    cbcp_stop();
+#endif
     /*
      * Reset all his options.
      */
diff -Naur ppp-2.3.10/pppd/ipv6cp.c ppp-2.3.10.CBCP/pppd/ipv6cp.c
--- ppp-2.3.10/pppd/ipv6cp.c	Sat Sep 11 14:04:22 1999
+++ ppp-2.3.10.CBCP/pppd/ipv6cp.c	Mon Oct 25 13:00:10 1999
@@ -127,6 +127,10 @@
 #include "magic.h"
 #include "pathnames.h"
 
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
+
 static const char rcsid[] = RCSID;
 
 /* global vars */
@@ -823,6 +827,10 @@
     u_char *p;			/* Pointer to next char to parse */
     u_char *ucp = inp;		/* Pointer to current output char */
     int l = *len;		/* Length left */
+
+#ifdef CBCP_SUPPORT
+    cbcp_stop();
+#endif
 
     /*
      * Reset all his options.
diff -Naur ppp-2.3.10/pppd/ipxcp.c ppp-2.3.10.CBCP/pppd/ipxcp.c
--- ppp-2.3.10/pppd/ipxcp.c	Tue Aug 24 07:31:09 1999
+++ ppp-2.3.10.CBCP/pppd/ipxcp.c	Mon Oct 25 13:08:47 1999
@@ -39,6 +39,10 @@
 #include "pathnames.h"
 #include "magic.h"
 
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
+
 static const char rcsid[] = RCSID;
 
 /* global vars */
@@ -927,6 +931,10 @@
     u_char *p;			/* Pointer to next char to parse */
     u_char *ucp = inp;		/* Pointer to current output char */
     int l = *len;		/* Length left */
+
+#ifdef CBCP_SUPPORT
+    cbcp_stop();
+#endif
 
     /*
      * Reset all his options.
diff -Naur ppp-2.3.10/pppd/lcp.c ppp-2.3.10.CBCP/pppd/lcp.c
--- ppp-2.3.10/pppd/lcp.c	Sat Sep 11 14:08:56 1999
+++ ppp-2.3.10.CBCP/pppd/lcp.c	Mon Oct 25 13:24:00 1999
@@ -295,11 +295,7 @@
     ao->neg_pcompression = 1;
     ao->neg_accompression = 1;
     ao->neg_lqr = 0;			/* no LQR implementation yet */
-#ifdef CBCP_SUPPORT
-    ao->neg_cbcp = 1;
-#else
     ao->neg_cbcp = 0;
-#endif
 
     memset(xmit_accm[unit], 0, sizeof(xmit_accm[0]));
     xmit_accm[unit][3] = 0x60000000;
@@ -1466,6 +1462,16 @@
 		break;
 	    }
 	    ho->neg_accompression = 1;
+	    break;
+
+	case CI_CALLBACK:
+	    LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd CALLBACK"));
+	    if (!ao->neg_cbcp ||
+	        cilen != CILEN_CHAR ) {
+		orc = CONFREJ;
+		break;
+	    }
+	    ho->neg_cbcp = 1;
 	    break;
 
 	default:
diff -Naur ppp-2.3.10/pppd/main.c ppp-2.3.10.CBCP/pppd/main.c
--- ppp-2.3.10/pppd/main.c	Sat Sep 11 14:08:57 1999
+++ ppp-2.3.10.CBCP/pppd/main.c	Mon Oct 25 16:02:00 1999
@@ -111,6 +111,10 @@
 char **script_env;		/* Env. variable values for scripts */
 int s_env_nalloc;		/* # words avail at script_env */
 
+#ifdef CBCP_SUPPORT
+int callback_in_progress;	/* Callback running */
+#endif
+
 u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */
 u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */
 
@@ -227,6 +231,10 @@
     struct stat statbuf;
     char numbuf[16];
 
+#ifdef CBCP_SUPPORT
+    char *s;
+#endif
+
     new_phase(PHASE_INITIALIZE);
 
     /*
@@ -788,6 +796,10 @@
 	}
 
 	lcp_open(0);		/* Start protocol */
+#ifdef CBCP_SUPPORT
+	for(callback_in_progress=1;callback_in_progress;){
+	    callback_in_progress=0;
+#endif
 	open_ccp_flag = 0;
 	add_fd(fd_ppp);
 	status = EXIT_NEGOTIATION_FAILED;
@@ -820,6 +832,128 @@
 	    if (got_sigchld)
 		reap_kids(0);	/* Don't leave dead kids lying around */
 	}
+#ifdef CBCP_SUPPORT
+	    if (callback_in_progress){
+		cbcp_stop();
+		remove_fd(fd_ppp);
+		clean_check();
+		disestablish_ppp(ttyfd);
+		fd_ppp = -1;
+
+		if (!hungup){
+		    lcp_lowerdown(0);
+		} else {
+		    if (pty_master >= 0)
+			close(pty_master);
+		    if (pty_slave >= 0)
+			close(pty_slave);
+		    if (real_ttyfd >= 0)
+			close_tty();
+		    
+		    hungup = 0;
+		    if (devnam[0] != 0) {
+			for (;;) {
+			    /* If the user specified the device name, become the
+		               user before opening it. */
+			    int err;
+			    if (!devnam_info.priv && !privopen)
+				seteuid(uid);
+			    ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
+			    err = errno;
+			    if (!devnam_info.priv && !privopen)
+				seteuid(0);
+			    if (ttyfd >= 0)
+				break;
+			    errno = err;
+			    if (err != EINTR) {
+				error("Failed to open %s: %m", devnam);
+				status = EXIT_OPEN_FAILED;
+			    }
+			    if (!persist || err != EINTR)
+				goto fail;
+			}
+			if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1
+			    || fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
+			    warn("Couldn't reset non-blocking mode on device: %m");
+
+			/*
+	                 * Do the equivalent of `mesg n' to stop broadcast messages.
+	                 */
+			if (fstat(ttyfd, &statbuf) < 0
+			    || fchmod(ttyfd, statbuf.st_mode & ~(S_IWGRP | S_IWOTH)) < 0) {
+			    warn("Couldn't restrict write permissions to %s: %m", devnam);
+			} else
+			    tty_mode = statbuf.st_mode;
+
+			real_ttyfd = ttyfd;
+		    }
+		}
+		
+		cbcp_protent.enabled_flag = 0; /* Already not need */
+		s = cbcp_get_script();
+		syslog(LOG_INFO, "Callback with <%s>",s );
+		
+		set_up_tty( ttyfd, 1 );
+		if (real_ttyfd != -1) {
+		    if (!default_device && modem) {
+			setdtr(real_ttyfd, 0);	/* in case modem is off hook */
+			sleep(1);
+			setdtr(real_ttyfd, 1);
+		    }
+		}
+
+		if (device_script(s, ttyfd, ttyfd, 0) < 0) {
+		    error("Callback script failed");
+		    status = EXIT_INIT_FAILED;
+		    setdtr(ttyfd, 0 );
+		    goto fail;
+		}
+		    
+		info("Serial connection established." );
+		
+		if (real_ttyfd != -1)
+    		    set_up_tty( real_ttyfd, 0 );
+		    
+		
+
+		slprintf(numbuf, sizeof(numbuf), "%d", baud_rate);
+		script_setenv("SPEED", numbuf);
+
+		/* set up the serial device as a ppp interface */
+		fd_ppp = establish_ppp(ttyfd);
+		if (fd_ppp < 0) {
+		    status = EXIT_FATAL_ERROR;
+		    goto disconnect;
+		}
+
+    		/*
+		 * Start opening the connection and wait for
+		 * incoming events (reply, timeout, etc.).
+	 	 */
+	 	notice("Connect: %s <--> %s", ifname, ppp_devnam);
+	 	gettimeofday(&start_time, NULL);
+		link_stats_valid = 0;
+		script_unsetenv("CONNECT_TIME");
+		script_unsetenv("BYTES_SENT");
+		script_unsetenv("BYTES_RCVD");
+		lcp_lowerup(0);
+
+		/*
+		 * If we are initiating this connection, wait for a short
+		 * time for something from the peer.  This can avoid bouncing
+		 * our packets off his tty before he has it set up.
+		 */
+		if (connector != NULL || ptycommand != NULL) {
+		    struct timeval t;
+		    t.tv_sec = 1;
+		    t.tv_usec = 0;
+		    wait_input(&t);
+		}
+
+		lcp_open(0);		/* Start protocol */
+	    }
+	}	
+#endif
 
 	/*
 	 * Print connect time and statistics.
diff -Naur ppp-2.3.10/pppd/options.c ppp-2.3.10.CBCP/pppd/options.c
--- ppp-2.3.10/pppd/options.c	Sat Sep 11 14:08:58 1999
+++ ppp-2.3.10.CBCP/pppd/options.c	Mon Oct 25 15:03:40 1999
@@ -58,6 +58,10 @@
 char *strdup __P((char *));
 #endif
 
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
+
 static const char rcsid[] = RCSID;
 
 /*
@@ -153,6 +157,10 @@
 static int n_arguments __P((option_t *));
 static int number_option __P((char *, u_int32_t *, int));
 
+#ifdef CBCP_SUPPORT
+static int setcbcp __P((char **));
+#endif
+
 /*
  * Structure to store extra lists of options.
  */
@@ -281,6 +289,11 @@
       "set filter for active pkts" },
 #endif
 
+#ifdef CBCP_SUPPORT
+    { "callback", o_special, setcbcp,
+      "Callback request to server - OR - calling back the client" },
+#endif
+
     { NULL }
 };
 
@@ -1568,3 +1581,23 @@
     return 1;
 }
 #endif /* PLUGIN */
+
+#ifdef CBCP_SUPPORT
+static int
+setcbcp(argv)
+    char **argv;
+{
+    cbcp[0].us_number = strdup(*argv);
+    if (cbcp_protent.enabled_flag)
+	novm("Only one callback parameter supported!");
+    if (cbcp[0].us_number == 0)	
+	novm("callback number");
+    if (!strcmp(cbcp[0].us_number,"server")){
+	lcp_allowoptions[0].neg_cbcp = 1;
+    } else {
+	lcp_wantoptions[0].neg_cbcp = 1;
+    }
+    cbcp_protent.enabled_flag = 1;
+    return 1;
+}
+#endif
diff -Naur ppp-2.3.10/pppd/patchlevel.h ppp-2.3.10.CBCP/pppd/patchlevel.h
--- ppp-2.3.10/pppd/patchlevel.h	Fri Sep 17 07:21:01 1999
+++ ppp-2.3.10.CBCP/pppd/patchlevel.h	Mon Oct 25 13:39:49 1999
@@ -2,5 +2,5 @@
 #define	PATCHLEVEL	10
 
 #define VERSION		"2.3"
-#define IMPLEMENTATION	""
-#define DATE		"17 September 1999"
+#define IMPLEMENTATION	" with Callback extension"
+#define DATE		"25 October 1999"
diff -Naur ppp-2.3.10/pppd/pathnames.h ppp-2.3.10.CBCP/pppd/pathnames.h
--- ppp-2.3.10/pppd/pathnames.h	Fri Aug 13 03:58:05 1999
+++ ppp-2.3.10.CBCP/pppd/pathnames.h	Mon Oct 25 13:52:20 1999
@@ -34,3 +34,10 @@
 #define _PATH_IPXUP	"/etc/ppp/ipx-up"
 #define _PATH_IPXDOWN	"/etc/ppp/ipx-down"
 #endif /* IPX_CHANGE */
+
+#ifdef CBCP_SUPPORT
+#define _PATH_CBCP_SERVER	"/etc/ppp/callback-server"
+#define _PATH_CBCP_CLIENT	"/etc/ppp/callback-client"
+#define _PATH_CBCP_USERS	"/etc/ppp/callback-users"
+#define _PATH_CBCP_	"/etc/ppp/callback"
+#endif /* CBCP_SUPPORT */
diff -Naur ppp-2.3.10/pppd/pppd.h ppp-2.3.10.CBCP/pppd/pppd.h
--- ppp-2.3.10/pppd/pppd.h	Sat Sep 11 14:08:59 1999
+++ ppp-2.3.10.CBCP/pppd/pppd.h	Mon Oct 25 13:47:09 1999
@@ -214,6 +214,10 @@
 extern struct	bpf_program active_filter; /* Filter for link-active pkts */
 #endif
 
+#ifdef CBCP_SUPPORT
+extern int	callback_in_progress;	/*Callback running*/
+#endif
+
 #ifdef MSLANMAN
 extern bool	ms_lanman;	/* Use LanMan password instead of NT */
 				/* Has meaning only with MS-CHAP challenges */
@@ -319,6 +323,7 @@
 void fatal __P((char *, ...));	/* log an error message and die(1) */
 
 /* Procedures exported from auth.c */
+void network_phase __P((int));	  /* the dataexchanger CP-s goung up */
 void link_required __P((int));	  /* we are starting to use the link */
 void link_terminated __P((int));  /* we are finished with the link */
 void link_down __P((int));	  /* the LCP layer has left the Opened state */
