	     Microsoft Call Back Configuration Protocol.
			by Pedro Roque Marques

The CBCP is a method by which the Microsoft Windows NT Server may
implement additional security. It is possible to configure the server
in such a manner so as to require that the client systems which
connect with it are required that following a valid authentication to
leave a method by which the number may be returned call.

It is a requirement of servers so configured that the protocol be
exchanged.

So, this set of patches may be applied to the pppd process to enable
the cbcp client *only* portion of the specification. It is primarily
meant to permit connection with Windows NT Servers.

The ietf-working specification may be obtained from ftp.microsoft.com
in the developr/rfc directory.

The ietf task group has decided to recommend that the LCP sequence be
extended to permit the callback operation. For this reason, these
patches are not 'part' of pppd but are an adjunct to the code. I
hopefully have included enough of the context to permit the patch
program so that minor changes to the program should not effect the
patch by more than a few lines in the 'fuzz' factor.



diff -r --unified=10 ppp-2.2a5.orig/linux/ppp_defs.h ppp-2.2a5/linux/ppp_defs.h
--- ppp-2.2a5.orig/linux/ppp_defs.h	Sat May 13 12:38:19 1995
+++ ppp-2.2a5/linux/ppp_defs.h	Sat May 13 13:46:36 1995
@@ -56,20 +56,21 @@
 #define PPP_IP		0x21	/* Internet Protocol */
 #define	PPP_VJC_COMP	0x2d	/* VJ compressed TCP */
 #define	PPP_VJC_UNCOMP	0x2f	/* VJ uncompressed TCP */
 #define PPP_COMP	0xfd	/* compressed packet */
 #define PPP_IPCP	0x8021	/* IP Control Protocol */
 #define PPP_CCP		0x80fd	/* Compression Control Protocol */
 #define PPP_LCP		0xc021	/* Link Control Protocol */
 #define PPP_PAP		0xc023	/* Password Authentication Protocol */
 #define PPP_LQR		0xc025	/* Link Quality Report protocol */
 #define PPP_CHAP	0xc223	/* Cryptographic Handshake Auth. Protocol */
+#define PPP_CBCP        0xc029  /* Callback Control Protocol */
 
 /*
  * Values for FCS calculations.
  */
 #define PPP_INITFCS	0xffff	/* Initial FCS value */
 #define PPP_GOODFCS	0xf0b8	/* Good final FCS value */
 #define PPP_FCS(fcs, c)	(((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
 
 /*
  * A 32-bit unsigned integral type.
diff -r --unified=10 ppp-2.2a5.orig/net/ppp_defs.h ppp-2.2a5/net/ppp_defs.h
--- ppp-2.2a5.orig/net/ppp_defs.h	Sat May 13 12:38:19 1995
+++ ppp-2.2a5/net/ppp_defs.h	Sat May 13 13:57:14 1995
@@ -56,20 +56,21 @@
 #define PPP_IP		0x21	/* Internet Protocol */
 #define	PPP_VJC_COMP	0x2d	/* VJ compressed TCP */
 #define	PPP_VJC_UNCOMP	0x2f	/* VJ uncompressed TCP */
 #define PPP_COMP	0xfd	/* compressed packet */
 #define PPP_IPCP	0x8021	/* IP Control Protocol */
 #define PPP_CCP		0x80fd	/* Compression Control Protocol */
 #define PPP_LCP		0xc021	/* Link Control Protocol */
 #define PPP_PAP		0xc023	/* Password Authentication Protocol */
 #define PPP_LQR		0xc025	/* Link Quality Report protocol */
 #define PPP_CHAP	0xc223	/* Cryptographic Handshake Auth. Protocol */
+#define PPP_CBCP        0xc029  /* Callback Control Protocol */
 
 /*
  * Values for FCS calculations.
  */
 #define PPP_INITFCS	0xffff	/* Initial FCS value */
 #define PPP_GOODFCS	0xf0b8	/* Good final FCS value */
 #define PPP_FCS(fcs, c)	(((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
 
 /*
  * A 32-bit unsigned integral type.
diff -r --unified=10 ppp-2.2a5.orig/pppd/Makefile.aix4 ppp-2.2a5/pppd/Makefile.aix4
--- ppp-2.2a5.orig/pppd/Makefile.aix4	Sat May 13 12:38:20 1995
+++ ppp-2.2a5/pppd/Makefile.aix4	Sat May 13 14:09:17 1995
@@ -3,26 +3,26 @@
 # $Id: Makefile.aix4,v 1.1 1994/12/12 00:40:06 paulus Exp $
 #
 #ifndef BINDIR
 BINDIR = /usr/sbin
 #endif
 #ifndef MANDIR
 MANDIR = /usr/man
 #ENDIF
 
 PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c \
-	auth.c options.c sys-bsd.c sys-str.c sys-aix4.c ccp.c
-HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h
+	auth.c options.c sys-bsd.c sys-str.c sys-aix4.c ccp.c cbcp.c
+HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h cbc.h
 MANPAGES = pppd.8
 
 PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o \
-	auth.o options.o sys-aix4.o ccp.o
+	auth.o options.o sys-aix4.o ccp.o cbcp.o
 
 CC = xlc
 DEBUG_FLAGS = -DDEBUGALL
 # SECURE_FLAGS = -DREQ_SYSOPTIONS=1
 COMPILE_FLAGS = -DSTREAMS
 COPTS = -O
 LIBS= -bI:/lib/pse.exp
 LOCK_PREFIX=\"/var/locks/LCK..\"
 
 CFLAGS = -I.. $(COPTS) $(DEBUG_FLAGS) $(COMPILE_FLAGS) $(SECURE_FLAGS)
diff -r --unified=10 ppp-2.2a5.orig/pppd/Makefile.bsd ppp-2.2a5/pppd/Makefile.bsd
--- ppp-2.2a5.orig/pppd/Makefile.bsd	Sat May 13 12:38:20 1995
+++ ppp-2.2a5/pppd/Makefile.bsd	Sat May 13 14:09:36 1995
@@ -1,18 +1,18 @@
 #	$Id: Makefile.bsd,v 1.7 1995/04/27 00:19:50 paulus Exp $
 
 BINDIR?= /usr/sbin
 CFLAGS+= -I.. -DHAVE_PATHS_H
 
 PROG=	pppd
 SRCS=	main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
-	auth.c options.c sys-bsd.c
+	auth.c options.c sys-bsd.c cbcp.c
 MAN8=	pppd.0
 # The next line is for NetBSD-current systems.
 MAN=	pppd.cat8
 BINMODE=4555
 BINOWN=	root
 
 LDADD=	-lcrypt -lutil
 DPADD=	${LIBCRYPT} ${LIBUTIL}
 
 .include <bsd.prog.mk>
diff -r --unified=10 ppp-2.2a5.orig/pppd/Makefile.linux ppp-2.2a5/pppd/Makefile.linux
--- ppp-2.2a5.orig/pppd/Makefile.linux	Sat May 13 12:38:20 1995
+++ ppp-2.2a5/pppd/Makefile.linux	Sat May 13 13:46:36 1995
@@ -1,25 +1,25 @@
 #
 # pppd makefile for Linux
 # $Id: Makefile.linux,v 1.6 1995/04/28 04:32:20 paulus Exp $
 #
 
 BINDIR = /usr/etc
 MANDIR = /usr/man
 
 PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
-	auth.c options.c sys-linux.c
-HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h
+	auth.c options.c sys-linux.c cbcp.c
+HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.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 sys-linux.o
+	auth.o options.o sys-linux.o cbcp.o
 
 all: pppd
 
 #
 # include dependancies if present and backup if as a header file
 ifeq (.depend,$(wildcard .depend))
 include .depend
 HEADERS := $(HEADERS) .depend
 endif
 
diff -r --unified=10 ppp-2.2a5.orig/pppd/Makefile.osf ppp-2.2a5/pppd/Makefile.osf
--- ppp-2.2a5.orig/pppd/Makefile.osf	Sat May 13 12:38:20 1995
+++ ppp-2.2a5/pppd/Makefile.osf	Sat May 13 14:09:54 1995
@@ -1,26 +1,26 @@
 #
 # pppd makefile for OSF/1 on DEC Alpha
 # $Id: Makefile.osf,v 1.2 1995/04/28 04:32:39 paulus Exp $
 #
 
 BINDIR = /usr/local/etc
 MANDIR = /usr/local/man
 
 PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
 	auth.c options.c sys-bsd.c sys-str.c sys-ultrix.c sys-linux.c \
-	sys-osf.c
-HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h
+	sys-osf.c cbcp.c
+HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.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 sys-osf.o
+	auth.o options.o sys-osf.o cbcp.o
 
 CC = cc
 DEBUG_FLAGS = -DDEBUGALL
 COMPILE_FLAGS = -DSTREAMS -DGIDSET_TYPE=int
 COPTS = -O2
 LIBS = 
 
 CFLAGS = -I.. $(COPTS) $(COMPILE_FLAGS)
 
 SOURCE= RELNOTES Makefile \
diff -r --unified=10 ppp-2.2a5.orig/pppd/Makefile.sol2 ppp-2.2a5/pppd/Makefile.sol2
--- ppp-2.2a5.orig/pppd/Makefile.sol2	Sat May 13 12:38:20 1995
+++ ppp-2.2a5/pppd/Makefile.sol2	Sat May 13 14:10:09 1995
@@ -6,21 +6,21 @@
 BINDIR = /usr/local/etc
 MANDIR = /usr/local/man
 
 CC = gcc
 COPTS = -g -O2
 CFLAGS = $(COPTS) -I..
 
 INSTALL = /usr/sbin/install
 
 OBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
-	auth.o options.o sys-sol2.o
+	auth.o options.o sys-sol2.o cbcp.o
 
 pppd:	$(OBJS)
 	$(CC) -o pppd $(OBJS) -lnsl
 
 install:
 	$(INSTALL) -f $(BINDIR) -m 4755 -u root pppd
 	$(INSTALL) -f $(MANDIR)/man8 pppd.8
 
 clean:
 	rm -f $(OBJS) pppd *~ core
diff -r --unified=10 ppp-2.2a5.orig/pppd/Makefile.sun ppp-2.2a5/pppd/Makefile.sun
--- ppp-2.2a5.orig/pppd/Makefile.sun	Sat May 13 12:38:20 1995
+++ ppp-2.2a5/pppd/Makefile.sun	Sat May 13 14:10:27 1995
@@ -2,26 +2,26 @@
 # pppd makefile for Suns
 # $Id: Makefile.sun,v 1.10 1995/04/28 06:15:48 paulus Exp $
 #
 
 BINDIR = /usr/local/etc
 MANDIR = /usr/local/man
 
 INSTALL= install -o root -g daemon
 
 PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
-	auth.c options.c sys-bsd.c sys-str.c sys-ultrix.c sys-linux.c
-HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h
+	auth.c options.c sys-bsd.c sys-str.c sys-ultrix.c sys-linux.c cbcp.c
+HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.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 sys-str.o
+	auth.o options.o sys-str.o cbcp.o
 
 # CC = gcc
 DEBUG_FLAGS =
 COMPILE_FLAGS =
 COPTS = -O
 LIBS = -lkvm
 
 CFLAGS = -I.. $(COPTS) $(DEBUG_FLAGS) $(COMPILE_FLAGS)
 
 SOURCE= RELNOTES Makefile \
diff -r --unified=10 ppp-2.2a5.orig/pppd/Makefile.ultrix ppp-2.2a5/pppd/Makefile.ultrix
--- ppp-2.2a5.orig/pppd/Makefile.ultrix	Sat May 13 12:38:20 1995
+++ ppp-2.2a5/pppd/Makefile.ultrix	Sat May 13 14:10:44 1995
@@ -1,25 +1,25 @@
 #
 # pppd makefile for Ultrix
 # $Id: Makefile.ultrix,v 1.5 1995/04/28 04:33:21 paulus Exp $
 #
 
 BINDIR = /usr/local/etc
 MANDIR = /usr/local/man
 
 PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
-	auth.c options.c sys-bsd.c sys-str.c sys-ultrix.c sys-linux.c
-HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h
+	auth.c options.c sys-bsd.c sys-str.c sys-ultrix.c sys-linux.c cbcp.c
+HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.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 sys-ultrix.o
+	auth.o options.o sys-ultrix.o cbcp.o
 
 # CC = gcc
 DEBUG_FLAGS =
 COMPILE_FLAGS = -DNO_DRAND48 -DGIDSET_TYPE=int
 COPTS = -O
 LIBS =
 
 CFLAGS = -I.. $(COPTS) $(DEBUG_FLAGS) $(COMPILE_FLAGS)
 
 SOURCE= RELNOTES Makefile \
diff -r --unified=10 ppp-2.2a5.orig/pppd/auth.c ppp-2.2a5/pppd/auth.c
--- ppp-2.2a5.orig/pppd/auth.c	Sat May 13 12:38:20 1995
+++ ppp-2.2a5/pppd/auth.c	Sat May 13 13:46:36 1995
@@ -55,20 +55,21 @@
 #ifndef PW_PPP
 #define PW_PPP PW_LOGIN
 #endif
 #endif
 
 #include "pppd.h"
 #include "fsm.h"
 #include "lcp.h"
 #include "upap.h"
 #include "chap.h"
+#include "cbcp.h"
 #include "ipcp.h"
 #include "ccp.h"
 #include "pathnames.h"
 
 #ifdef sparc
 #include <alloca.h>
 #endif /*sparc*/
 
 /* Used for storing a sequence of words.  Usually malloced. */
 struct wordlist {
@@ -93,20 +94,21 @@
 /* Bits in auth_pending[] */
 #define UPAP_WITHPEER	1
 #define UPAP_PEER	2
 #define CHAP_WITHPEER	4
 #define CHAP_PEER	8
 
 /* Prototypes */
 void check_access __P((FILE *, char *));
 
 static void network_phase __P((int));
+static void callback_phase __P((int));
 static int  login __P((char *, char *, char **, int *));
 static void logout __P((void));
 static int  null_login __P((int));
 static int  get_upap_passwd __P((void));
 static int  have_upap_secret __P((void));
 static int  have_chap_secret __P((char *, char *));
 static int  scan_authfile __P((FILE *, char *, char *, char *,
 				  struct wordlist **, char *));
 static void free_wordlist __P((struct wordlist *));
 
@@ -140,20 +142,21 @@
 
 /*
  * LCP has gone down; it will either die or try to re-establish.
  */
 void
 link_down(unit)
     int unit;
 {
     ipcp_close(0);
     ccp_close(0);
+    cbcp_close(0);
     phase = PHASE_TERMINATE;
 }
 
 /*
  * The link is established.
  * Proceed to the Dead, Authenticate or Network phase as appropriate.
  */
 void
 link_established(unit)
     int unit;
@@ -189,36 +192,53 @@
     if (ho->neg_chap) {
 	ChapAuthWithPeer(unit, our_name, ho->chap_mdtype);
 	auth |= CHAP_WITHPEER;
     } else if (ho->neg_upap) {
 	upap_authwithpeer(unit, user, passwd);
 	auth |= UPAP_WITHPEER;
     }
     auth_pending[unit] = auth;
 
     if (!auth)
-	network_phase(unit);
+	callback_phase(unit);
 }
 
 /*
  * Proceed to the network phase.
  */
 static void
 network_phase(unit)
     int unit;
 {
     phase = PHASE_NETWORK;
     ipcp_open(unit);
     ccp_open(unit);
 }
 
 /*
+ * Proceed to the callback phase which may be empty.
+ */
+static void
+callback_phase(unit)
+     int unit;
+{
+    lcp_options *wo = &lcp_wantoptions[unit];
+
+    if (!wo->neg_cbcp)
+        network_phase(unit);
+    else {
+        phase = PHASE_CALLBACK;
+        cbcp_open(unit);
+    }
+}
+
+/*
  * The peer has failed to authenticate himself using `protocol'.
  */
 void
 auth_peer_fail(unit, protocol)
     int unit, protocol;
 {
     /*
      * Authentication failure: take the link down
      */
     lcp_close(unit);
@@ -242,27 +262,24 @@
 	bit = UPAP_PEER;
 	break;
     default:
 	syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x",
 	       protocol);
 	return;
     }
 
     /*
      * If there is no more authentication still to be done,
-     * proceed to the network phase.
+     * go to the next phase.
      */
-    if ((auth_pending[unit] &= ~bit) == 0) {
-	phase = PHASE_NETWORK;
-	ipcp_open(unit);
-	ccp_open(unit);
-    }
+    if ((auth_pending[unit] &= ~bit) == 0)
+	callback_phase(unit);
 }
 
 /*
  * We have failed to authenticate ourselves to the peer using `protocol'.
  */
 void
 auth_withpeer_fail(unit, protocol)
     int unit, protocol;
 {
     /*
@@ -291,22 +308,23 @@
     default:
 	syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x",
 	       protocol);
 	bit = 0;
     }
 
     /*
      * If there is no more authentication still being done,
      * proceed to the network phase.
      */
+
     if ((auth_pending[unit] &= ~bit) == 0)
-	network_phase(unit);
+	callback_phase(unit);
 }
 
 
 /*
  * check_auth_options - called to check authentication options.
  */
 void
 check_auth_options()
 {
     lcp_options *wo = &lcp_wantoptions[0];
@@ -335,21 +353,20 @@
     if (ao->neg_chap && !have_chap_secret(our_name, remote_name))
 	ao->neg_chap = 0;
     if (wo->neg_chap && !have_chap_secret(remote_name, our_name))
 	wo->neg_chap = 0;
 
     if (auth_required && !wo->neg_chap && !wo->neg_upap) {
 	fprintf(stderr, "\
 pppd: peer authentication required but no authentication files accessible\n");
 	exit(1);
     }
-
 }
 
 
 /*
  * check_passwd - Check the user name and passwd against the PAP secrets
  * file.  If requested, also check against the system password database,
  * and login the user if OK.
  *
  * returns:
  *	UPAP_AUTHNAK: Authentication failed.
diff -r --unified=10 ppp-2.2a5.orig/pppd/cbcp.c ppp-2.2a5/pppd/cbcp.c
--- ppp-2.2a5.orig/pppd/cbcp.c	Sat May 13 14:08:45 1995
+++ ppp-2.2a5/pppd/cbcp.c	Sat May 13 14:15:12 1995
@@ -0,0 +1,370 @@
+/*
+ * cbcp - Call Back Configuration Protocol.
+ *
+ * Copyright (c) 1995 Pedro Roque Marques
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Pedro Roque Marques.  The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: cbcp.c,v 1.0 1995/04/24 05:59:12 paulus Exp $";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <syslog.h>
+
+#include "pppd.h"
+#include "cbcp.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+
+cbcp_state cbcp[NUM_PPP];	
+
+/* internal prototypes */
+
+void cbcp_recvreq(cbcp_state *us, char *pckt, int len);
+void cbcp_resp(cbcp_state *us);
+void cbcp_up(cbcp_state *us);
+void cbcp_recvack(cbcp_state *us, char *pckt, int len);
+void cbcp_send(cbcp_state *us, u_char code, u_char *buf, int len);
+
+/* init state */
+void cbcp_init(int iface)
+{
+    cbcp_state *us;
+
+    us = &cbcp[iface];
+    memset(us, 0, sizeof(cbcp_state));
+    us->us_unit = iface;
+    us->us_type |= (1 << CB_CONF_NO);
+}
+
+/* lower layer is up */
+void cbcp_lowerup(int iface)
+{
+    cbcp_state *us = &cbcp[iface];
+
+    syslog(LOG_DEBUG, "cbcp_lowerup");
+    syslog(LOG_DEBUG, "want: %d", us->us_type);
+
+    if (us->us_type == CB_CONF_USER)
+        syslog(LOG_DEBUG, "phone no: %s", us->us_number);
+}
+
+void cbcp_open(int unit)
+{
+    syslog(LOG_DEBUG, "cbcp_open");
+}
+
+void cbcp_close(int unit)
+{
+}
+
+/* process an incomming packet */
+void cbcp_input(int unit, u_char *inpacket, int pktlen)
+{
+    u_char *inp;
+    u_char code, id;
+    u_short len;
+
+    cbcp_state *us = &cbcp[unit];
+
+    inp = inpacket;
+
+    if (pktlen < CBCP_MINLEN) {
+        syslog(LOG_ERR, "CBCP packet is too small");
+	return;
+    }
+
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    GETSHORT(len, inp);
+
+#if 0
+    if (len > pktlen) {
+        syslog(LOG_ERR, "CBCP packet: invalid length");
+        return;
+    }
+#endif
+
+    len -= CBCP_MINLEN;
+ 
+    switch(code) {
+    case CBCP_REQ:
+        us->us_id = id;
+	cbcp_recvreq(us, inp, len);
+	break;
+
+    case CBCP_RESP:
+	syslog(LOG_DEBUG, "CBCP_RESP received");
+	break;
+
+    case CBCP_ACK:
+	if (id != us->us_id)
+	    syslog(LOG_DEBUG, "id doesn't match: expected %d recv %d",
+		   us->us_id, id);
+
+	cbcp_recvack(us, inp, len);
+	break;
+
+    default:
+	break;
+    }
+}
+
+/* protocol was rejected by foe */
+void cbcp_protrej(int iface)
+{
+}
+
+char *cbcp_codenames[] = {"Request", "Response", "Ack"};
+
+char *cbcp_optionnames[] = {  "NoCallback",
+			      "UserDefined",
+			      "AdminDefined",
+			      "List"};
+/* pretty print a packet */
+int cbcp_printpkt(u_char *p, int plen,
+		   void (*printer) __P((void *, char *, ...)),
+		   void *arg)
+{
+    int code, opt, id, len, olen, delay;
+    u_char *pstart, *optend;
+    u_short cishort;
+    u_long cilong;
+
+    if (plen < HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *))
+	printer(arg, " %s", cbcp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code); 
+
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+
+    switch (code) {
+    case CBCP_REQ:
+    case CBCP_RESP:
+    case CBCP_ACK:
+        while(len >= 2) {
+	    GETCHAR(opt, p);
+	    GETCHAR(olen, p);
+
+	    if (olen < 2 || olen > len) {
+	        break;
+	    }
+
+	    printer(arg, " <");
+	    len -= olen;
+
+	    if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *))
+	    	printer(arg, " %s", cbcp_optionnames[opt-1]);
+	    else
+	        printer(arg, " option=0x%x", opt); 
+
+	    if (olen > 2) {
+	        GETCHAR(delay, p);
+		printer(arg, " delay = %d", delay);
+	    }
+
+	    if (olen > 3) {
+	        int addrt;
+		char str[256];
+
+		GETCHAR(addrt, p);
+		memcpy(str, p, olen - 4);
+		str[olen - 4] = 0;
+		printer(arg, " number = %s", str);
+	    }
+	    printer(arg, ">");
+	break;
+	}
+
+      default:
+	break;
+    }
+
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", code);
+    }
+
+    return p - pstart;
+}
+
+/* received CBCP request */
+
+void cbcp_recvreq(cbcp_state *us, char *pckt, int pcktlen)
+{
+    u_char type, opt_len, delay, addr_type;
+    char address[256];
+    int len = pcktlen;
+
+    address[0] = 0;
+
+    while (len) {
+        syslog(LOG_DEBUG, "length: %d", len);
+
+	GETCHAR(type, pckt);
+	GETCHAR(opt_len, pckt);
+
+	if (opt_len > 2)
+	    GETCHAR(delay, pckt);
+
+	us->us_allowed |= (1 << type);
+
+	switch(type) {
+	case CB_CONF_NO:
+	    syslog(LOG_DEBUG, "no callback allowed");
+	    break;
+
+      case CB_CONF_USER:
+	    syslog(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])
+		    syslog(LOG_DEBUG, "address: %s", address);
+	    }
+	break;
+
+      case CB_CONF_ADMIN:
+	    syslog(LOG_DEBUG, "user admin defined allowed");
+	    break;
+
+      case CB_CONF_LIST:
+	    break;
+	}
+	len -= opt_len;
+    }
+
+  cbcp_resp(us);
+}
+
+void cbcp_resp(cbcp_state *us)
+{
+    u_char cb_type;
+    u_char buf[256];
+    u_char *bufp = buf;
+    int len = 0;
+
+    cb_type = us->us_allowed & us->us_type;
+    syslog(LOG_DEBUG, "cbcp_resp cb_type=%d", cb_type);
+
+#if 0
+    if (!cb_type)
+        lcp_down(us->us_unit);
+#endif
+
+    if (cb_type & ( 1 << CB_CONF_USER ) ) {
+	syslog(LOG_DEBUG, "cbcp_resp CONF_USER");
+	PUTCHAR(CB_CONF_USER, bufp);
+	len = 3 + 1 + strlen(us->us_number) + 1;
+	PUTCHAR(len , bufp);
+	PUTCHAR(5, bufp); /* delay */
+	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 ) ) {
+        PUTCHAR(CB_CONF_ADMIN, bufp);
+	len = 3;
+	PUTCHAR(len , bufp);
+	PUTCHAR(0, bufp);
+	cbcp_send(us, CBCP_RESP, buf, len);
+	return;
+    }
+
+    if (cb_type & ( 1 << CB_CONF_NO ) ) {
+        syslog(LOG_DEBUG, "cbcp_resp CONF_NO");
+	PUTCHAR(CB_CONF_NO, bufp);
+	len = 3;
+	PUTCHAR(len , bufp);
+	PUTCHAR(0, bufp);
+	cbcp_send(us, CBCP_RESP, buf, len);
+	ipcp_open(us->us_unit);
+	return;
+    }
+}
+
+void cbcp_send(cbcp_state *us, u_char code, u_char *buf, int len)
+{
+    u_char *outp;
+    int outlen;
+
+    outp = outpacket_buf;
+
+    outlen = 4 + len;
+    
+    MAKEHEADER(outp, PPP_CBCP);
+
+    PUTCHAR(code, outp);
+    PUTCHAR(us->us_id, outp);
+    PUTSHORT(outlen, outp);
+    
+    if (len)
+        BCOPY(buf, outp, len);
+
+    output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
+}
+
+void cbcp_recvack(cbcp_state *us, char *pckt, int len)
+{
+    u_char type, delay, addr_type;
+    int opt_len;
+    char address[256];
+
+    if (len) {
+        GETCHAR(type, pckt);
+	GETCHAR(opt_len, pckt);
+     
+	if (opt_len > 2)
+	    GETCHAR(delay, pckt);
+
+	if (opt_len > 4) {
+	    GETCHAR(addr_type, pckt);
+	    memcpy(address, pckt, opt_len - 4);
+	    address[opt_len - 4] = 0;
+	    if (address[0])
+	        syslog(LOG_DEBUG, "peer will call: %s", address);
+	}
+    }
+
+    cbcp_up(us);
+}
+
+extern int persist;
+
+/* ok peer will do callback */
+void cbcp_up(cbcp_state *us)
+{
+    persist = 0;
+    lcp_close(0);
+}
diff -r --unified=10 ppp-2.2a5.orig/pppd/cbcp.h ppp-2.2a5/pppd/cbcp.h
--- ppp-2.2a5.orig/pppd/cbcp.h	Sat May 13 14:08:40 1995
+++ ppp-2.2a5/pppd/cbcp.h	Sat May 13 13:56:20 1995
@@ -0,0 +1,33 @@
+#ifndef CBCP_H
+#define CBCP_H
+
+typedef struct cbcp_state {
+    int    us_unit;	/* Interface unit number */
+    u_char us_id;		/* Current id */
+    u_char us_allowed;
+    int    us_type;
+    char   *us_number;    /* Telefone Number */
+} cbcp_state;
+
+void cbcp_init      __P((int));
+void cbcp_open      __P((int));
+void cbcp_lowerup   __P((int));
+void cbcp_input     __P((int, u_char *, int));
+void cbcp_protrej   __P((int));
+int  cbcp_printpkt  __P((u_char *, int,
+			    void (*) __P((void *, char *, ...)),
+			    void *));
+
+extern cbcp_state cbcp[];
+
+#define CBCP_MINLEN 4
+
+#define CBCP_REQ    1
+#define CBCP_RESP   2
+#define CBCP_ACK    3
+
+#define CB_CONF_NO     1
+#define CB_CONF_USER   2
+#define CB_CONF_ADMIN  3
+#define CB_CONF_LIST   4
+#endif
diff -r --unified=10 ppp-2.2a5.orig/pppd/lcp.c ppp-2.2a5/pppd/lcp.c
--- ppp-2.2a5.orig/pppd/lcp.c	Sat May 13 12:38:20 1995
+++ ppp-2.2a5/pppd/lcp.c	Sat May 13 13:46:36 1995
@@ -112,24 +112,26 @@
     lcp_extcode,		/* Called to handle LCP-specific codes */
     "LCP"			/* String name of protocol */
 };
 
 int lcp_warnloops = DEFWARNLOOPS; /* Warn about a loopback this often */
 
 /*
  * Length of each type of configuration option (in octets)
  */
 #define CILEN_VOID	2
+#define CILEN_CHAR      3
 #define CILEN_SHORT	4	/* CILEN_VOID + sizeof(short) */
 #define CILEN_CHAP	5	/* CILEN_VOID + sizeof(short) + 1 */
 #define CILEN_LONG	6	/* CILEN_VOID + sizeof(long) */
 #define CILEN_LQR	8	/* CILEN_VOID + sizeof(short) + sizeof(long) */
+#define CILEN_CBCP      3
 
 #define CODENAME(x)	((x) == CONFACK ? "ACK" : \
 			 (x) == CONFNAK ? "NAK" : "REJ")
 
 
 /*
  * lcp_init - Initialize LCP.
  */
 void
 lcp_init(unit)
@@ -153,32 +155,34 @@
     wo->mru = DEFMRU;
     wo->neg_asyncmap = 0;
     wo->asyncmap = 0;
     wo->neg_chap = 0;			/* Set to 1 on server */
     wo->neg_upap = 0;			/* Set to 1 on server */
     wo->chap_mdtype = CHAP_DIGEST_MD5;
     wo->neg_magicnumber = 1;
     wo->neg_pcompression = 1;
     wo->neg_accompression = 1;
     wo->neg_lqr = 0;			/* no LQR implementation yet */
+    wo->neg_cbcp = 0;
 
     ao->neg_mru = 1;
     ao->mru = MAXMRU;
     ao->neg_asyncmap = 1;
     ao->asyncmap = 0;
     ao->neg_chap = 1;
     ao->chap_mdtype = CHAP_DIGEST_MD5;
     ao->neg_upap = 1;
     ao->neg_magicnumber = 1;
     ao->neg_pcompression = 1;
     ao->neg_accompression = 1;
     ao->neg_lqr = 0;			/* no LQR implementation yet */
+    ao->neg_cbcp = 1;
 
     memset(xmit_accm[unit], 0, sizeof(xmit_accm[0]));
     xmit_accm[unit][3] = 0x60000000;
 }
 
 
 /*
  * lcp_open - LCP is allowed to come up.
  */
 void
@@ -478,29 +482,31 @@
 lcp_cilen(f)
     fsm *f;
 {
     lcp_options *go = &lcp_gotoptions[f->unit];
 
 #define LENCIVOID(neg)	(neg ? CILEN_VOID : 0)
 #define LENCICHAP(neg)	(neg ? CILEN_CHAP : 0)
 #define LENCISHORT(neg)	(neg ? CILEN_SHORT : 0)
 #define LENCILONG(neg)	(neg ? CILEN_LONG : 0)
 #define LENCILQR(neg)	(neg ? CILEN_LQR: 0)
+#define LENCICBCP(neg)	(neg ? CILEN_CBCP: 0)
     /*
      * NB: we only ask for one of CHAP and UPAP, even if we will
      * accept either.
      */
     return (LENCISHORT(go->neg_mru) +
 	    LENCILONG(go->neg_asyncmap) +
 	    LENCICHAP(go->neg_chap) +
 	    LENCISHORT(!go->neg_chap && go->neg_upap) +
 	    LENCILQR(go->neg_lqr) +
+	    LENCICBCP(go->neg_cbcp) +
 	    LENCILONG(go->neg_magicnumber) +
 	    LENCIVOID(go->neg_pcompression) +
 	    LENCIVOID(go->neg_accompression));
 }
 
 
 /*
  * lcp_addci - Add our desired CIs to a packet.
  */
 static void
@@ -537,25 +543,33 @@
 	PUTLONG(val, ucp); \
     }
 #define ADDCILQR(opt, neg, val) \
     if (neg) { \
 	PUTCHAR(opt, ucp); \
 	PUTCHAR(CILEN_LQR, ucp); \
 	PUTSHORT(PPP_LQR, ucp); \
 	PUTLONG(val, ucp); \
     }
 
+#define ADDCICHAR(opt, neg, val) \
+    if (neg) { \
+	PUTCHAR(opt, ucp); \
+	PUTCHAR(CILEN_CHAR, ucp); \
+	PUTCHAR(val, ucp); \
+    }
+
     ADDCISHORT(CI_MRU, go->neg_mru, go->mru);
     ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap);
     ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
     ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
     ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+    ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
     ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
     ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
     ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
 
     if (ucp - start_ucp != *lenp) {
 	/* this should never happen, because peer_mtu should be 1500 */
 	syslog(LOG_ERR, "Bug in lcp_addci: wrong length");
     }
 }
 
@@ -600,20 +614,33 @@
 	    goto bad; \
 	GETCHAR(citype, p); \
 	GETCHAR(cilen, p); \
 	if (cilen != CILEN_SHORT || \
 	    citype != opt) \
 	    goto bad; \
 	GETSHORT(cishort, p); \
 	if (cishort != val) \
 	    goto bad; \
     }
+#define ACKCICHAR(opt, neg, val) \
+    if (neg) { \
+	if ((len -= CILEN_CHAR) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_CHAR || \
+	    citype != opt) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (cichar != val) \
+	    goto bad; \
+    }
 #define ACKCICHAP(opt, neg, val, digest) \
     if (neg) { \
 	if ((len -= CILEN_CHAP) < 0) \
 	    goto bad; \
 	GETCHAR(citype, p); \
 	GETCHAR(cilen, p); \
 	if (cilen != CILEN_CHAP || \
 	    citype != opt) \
 	    goto bad; \
 	GETSHORT(cishort, p); \
@@ -651,20 +678,21 @@
 	GETLONG(cilong, p); \
 	if (cilong != val) \
 	  goto bad; \
     }
 
     ACKCISHORT(CI_MRU, go->neg_mru, go->mru);
     ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap);
     ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
     ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
     ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+    ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
     ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
     ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
     ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
 
     /*
      * If there are any remaining CIs, then this packet is bad.
      */
     if (len != 0)
 	goto bad;
     return (1);
@@ -722,20 +750,31 @@
 	len >= CILEN_CHAP && \
 	p[1] == CILEN_CHAP && \
 	p[0] == opt) { \
 	len -= CILEN_CHAP; \
 	INCPTR(2, p); \
 	GETSHORT(cishort, p); \
 	GETCHAR(cichar, p); \
 	no.neg = 1; \
 	code \
     }
+#define NAKCICHAR(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_CHAR && \
+	p[1] == CILEN_CHAR && \
+	p[0] == opt) { \
+	len -= CILEN_CHAR; \
+	INCPTR(2, p); \
+	GETCHAR(cichar, p); \
+	no.neg = 1; \
+	code \
+    }
 #define NAKCISHORT(opt, neg, code) \
     if (go->neg && \
 	len >= CILEN_SHORT && \
 	p[1] == CILEN_SHORT && \
 	p[0] == opt) { \
 	len -= CILEN_SHORT; \
 	INCPTR(2, p); \
 	GETSHORT(cishort, p); \
 	no.neg = 1; \
 	code \
@@ -851,20 +890,27 @@
      * If they Nak the reporting period, take their value XXX ?
      */
     NAKCILQR(CI_QUALITY, neg_lqr,
 	     if (cishort != PPP_LQR)
 		 try.neg_lqr = 0;
 	     else
 		 try.lqr_period = cilong;
 	     );
 
     /*
+     * Only implementing CBCP... not the rest of the callback options
+     */
+    NAKCICHAR(CI_CALLBACK, neg_cbcp,
+	      try.neg_cbcp = 0;
+	      );
+
+    /*
      * Check for a looped-back line.
      */
     NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
 	      try.magicnumber = magic();
 	      ++try.numloops;
 	      looped_back = 1;
 	      );
 
     NAKCIVOID(CI_PCOMPRESSION, neg_pcompression,
 	      try.neg_pcompression = 0;
@@ -1045,28 +1091,43 @@
 	len -= CILEN_LQR; \
 	INCPTR(2, p); \
 	GETSHORT(cishort, p); \
 	GETLONG(cilong, p); \
 	/* Check rejected value. */ \
 	if (cishort != PPP_LQR || cilong != val) \
 	    goto bad; \
 	try.neg = 0; \
 	LCPDEBUG((LOG_INFO,"lcp_rejci rejected LQR opt %d", opt)); \
     }
+#define REJCICBCP(opt, neg, val) \
+    if (go->neg && \
+	len >= CILEN_CBCP && \
+	p[1] == CILEN_CBCP && \
+	p[0] == opt) { \
+	len -= CILEN_CBCP; \
+	INCPTR(2, p); \
+	GETCHAR(cichar, p); \
+	/* Check rejected value. */ \
+	if (cichar != val) \
+	    goto bad; \
+	try.neg = 0; \
+	LCPDEBUG((LOG_INFO,"lcp_rejci rejected Callback opt %d", opt)); \
+    }
 
     REJCISHORT(CI_MRU, neg_mru, go->mru);
     REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
     REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype);
     if (!go->neg_chap) {
 	REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
     }
     REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
+    REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);
     REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
     REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
     REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
 
     /*
      * If there are any remaining CIs, then this packet is bad.
      */
     if (len != 0)
 	goto bad;
     /*
@@ -1447,20 +1508,21 @@
      */
     ppp_recv_config(f->unit, (go->neg_mru? MAX(wo->mru, go->mru): PPP_MRU),
 		    (go->neg_asyncmap? go->asyncmap: 0x00000000),
 		    go->neg_pcompression, go->neg_accompression);
 
     if (ho->neg_mru)
 	peer_mru[f->unit] = ho->mru;
 
     ChapLowerUp(f->unit);	/* Enable CHAP */
     upap_lowerup(f->unit);	/* Enable UPAP */
+    cbcp_lowerup(f->unit);      /* Enable CBCP */
     ipcp_lowerup(f->unit);	/* Enable IPCP */
     ccp_lowerup(f->unit);	/* Enable CCP */
     lcp_echo_lowerup(f->unit);  /* Enable echo messages */
 
     link_established(f->unit);
 }
 
 
 /*
  * lcp_down - LCP has gone DOWN.
@@ -1593,20 +1655,34 @@
 		}
 		break;
 	    case CI_QUALITY:
 		if (olen >= CILEN_SHORT) {
 		    p += 2;
 		    printer(arg, "quality ");
 		    GETSHORT(cishort, p);
 		    switch (cishort) {
 		    case PPP_LQR:
 			printer(arg, "lqr");
+			break;
+		    default:
+			printer(arg, "0x%x", cishort);
+		    }
+		}
+		break;
+	    case CI_CALLBACK:
+		if (olen >= CILEN_CHAR) {
+		    p += 2;
+		    printer(arg, "callback ");
+		    GETSHORT(cishort, p);
+		    switch (cishort) {
+		    case CBCP_OPT:
+			printer(arg, "CBCP");
 			break;
 		    default:
 			printer(arg, "0x%x", cishort);
 		    }
 		}
 		break;
 	    case CI_MAGICNUMBER:
 		if (olen == CILEN_LONG) {
 		    p += 2;
 		    GETLONG(cilong, p);
diff -r --unified=10 ppp-2.2a5.orig/pppd/lcp.h ppp-2.2a5/pppd/lcp.h
--- ppp-2.2a5.orig/pppd/lcp.h	Sat May 13 12:38:20 1995
+++ ppp-2.2a5/pppd/lcp.h	Sat May 13 13:46:36 1995
@@ -22,44 +22,47 @@
 /*
  * Options.
  */
 #define CI_MRU		1	/* Maximum Receive Unit */
 #define CI_ASYNCMAP	2	/* Async Control Character Map */
 #define CI_AUTHTYPE	3	/* Authentication Type */
 #define CI_QUALITY	4	/* Quality Protocol */
 #define CI_MAGICNUMBER	5	/* Magic Number */
 #define CI_PCOMPRESSION	7	/* Protocol Field Compression */
 #define CI_ACCOMPRESSION 8	/* Address/Control Field Compression */
+#define CI_CALLBACK      13     /* callback */
 
 /*
  * LCP-specific packet types.
  */
 #define PROTREJ		8	/* Protocol Reject */
 #define ECHOREQ		9	/* Echo Request */
 #define ECHOREP		10	/* Echo Reply */
 #define DISCREQ		11	/* Discard Request */
+#define CBCP_OPT        6       /* Use callback control protocol */
 
 /*
  * The state of options is described by an lcp_options structure.
  */
 typedef struct lcp_options {
     int passive : 1;		/* Don't die if we don't get a response */
     int silent : 1;		/* Wait for the other end to start first */
     int restart : 1;		/* Restart vs. exit after close */
     int neg_mru : 1;		/* Negotiate the MRU? */
     int neg_asyncmap : 1;	/* Negotiate the async map? */
     int neg_upap : 1;		/* Ask for UPAP authentication? */
     int neg_chap : 1;		/* Ask for CHAP authentication? */
     int neg_magicnumber : 1;	/* Ask for magic number? */
     int neg_pcompression : 1;	/* HDLC Protocol Field Compression? */
     int neg_accompression : 1;	/* HDLC Address/Control Field Compression? */
     int neg_lqr : 1;		/* Negotiate use of Link Quality Reports */
+    int neg_cbcp : 1;           /* Negotiate use of CBCP */
     u_short mru;		/* Value of MRU */
     u_char chap_mdtype;		/* which MD type (hashing algorithm) */
     u_int32_t asyncmap;		/* Value of async map */
     u_int32_t magicnumber;
     int numloops;		/* Number of loops during magic number neg. */
     u_int32_t lqr_period;	/* Reporting period for link quality */
 } lcp_options;
 
 extern fsm lcp_fsm[];
 extern lcp_options lcp_wantoptions[];
diff -r --unified=10 ppp-2.2a5.orig/pppd/main.c ppp-2.2a5/pppd/main.c
--- ppp-2.2a5.orig/pppd/main.c	Sat May 13 12:38:20 1995
+++ ppp-2.2a5/pppd/main.c	Sat May 13 13:46:36 1995
@@ -40,20 +40,21 @@
 #include <sys/socket.h>
 #include <net/if.h>
 
 #include "pppd.h"
 #include "magic.h"
 #include "fsm.h"
 #include "lcp.h"
 #include "ipcp.h"
 #include "upap.h"
 #include "chap.h"
+#include "cbcp.h"
 #include "ccp.h"
 #include "pathnames.h"
 #include "patchlevel.h"
 
 /*
  * If REQ_SYSOPTIONS is defined to 1, pppd will not run unless
  * /etc/ppp/options exists.
  */
 #ifndef	REQ_SYSOPTIONS
 #define REQ_SYSOPTIONS	1
@@ -129,20 +130,22 @@
     int  (*printpkt)();
     void (*datainput)();
     char *name;
 } prottbl[] = {
     { PPP_LCP, lcp_init, lcp_input, lcp_protrej,
 	  lcp_printpkt, NULL, "LCP" },
     { PPP_IPCP, ipcp_init, ipcp_input, ipcp_protrej,
 	  ipcp_printpkt, NULL, "IPCP" },
     { PPP_PAP, upap_init, upap_input, upap_protrej,
 	  upap_printpkt, NULL, "PAP" },
+    { PPP_CBCP, cbcp_init, cbcp_input, cbcp_protrej,
+	  cbcp_printpkt, NULL, "CBCP" },
     { PPP_CHAP, ChapInit, ChapInput, ChapProtocolReject,
 	  ChapPrintPkt, NULL, "CHAP" },
     { PPP_CCP, ccp_init, ccp_input, ccp_protrej,
 	  ccp_printpkt, ccp_datainput, "CCP" },
 };
 
 #define N_PROTO		(sizeof(prottbl) / sizeof(prottbl[0]))
 
 main(argc, argv)
     int argc;
diff -r --unified=10 ppp-2.2a5.orig/pppd/options.c ppp-2.2a5/pppd/options.c
--- ppp-2.2a5.orig/pppd/options.c	Sat May 13 12:38:21 1995
+++ ppp-2.2a5/pppd/options.c	Sat May 13 13:59:24 1995
@@ -36,20 +36,21 @@
 #include <netinet/in.h>
 
 #include "pppd.h"
 #include "pathnames.h"
 #include "patchlevel.h"
 #include "fsm.h"
 #include "lcp.h"
 #include "ipcp.h"
 #include "upap.h"
 #include "chap.h"
+#include "cbcp.h"
 #include "ccp.h"
 
 #include <net/ppp-comp.h>
 
 #define FALSE	0
 #define TRUE	1
 
 #if defined(ultrix) || defined(NeXT)
 char *strdup __P((char *));
 #endif
@@ -112,20 +113,21 @@
 static int reqchap __P((void));
 static int setspeed __P((char *));
 static int noaccomp __P((void));
 static int noasyncmap __P((void));
 static int noipaddr __P((void));
 static int nomagicnumber __P((void));
 static int setasyncmap __P((char **));
 static int setescape __P((char **));
 static int setmru __P((char **));
 static int setmtu __P((char **));
+static int setcbcp __P((char **));
 static int nomru __P((void));
 static int nopcomp __P((void));
 static int setconnector __P((char **));
 static int setdisconnector __P((char **));
 static int setdomain __P((char **));
 static int setnetmask __P((char **));
 static int setcrtscts __P((void));
 static int setnocrtscts __P((void));
 static int setxonxoff __P((void));
 static int setnodetach __P((void));
@@ -202,20 +204,21 @@
     {"connect", 1, setconnector}, /* A program to set up a connection */
     {"disconnect", 1, setdisconnector},	/* program to disconnect serial dev. */
     {"crtscts", 0, setcrtscts},	/* set h/w flow control */
     {"-crtscts", 0, setnocrtscts}, /* clear h/w flow control */
     {"xonxoff", 0, setxonxoff},	/* set s/w flow control */
     {"debug", 0, setdebug},	/* Increase debugging level */
     {"kdebug", 1, setkdebug},	/* Enable kernel-level debugging */
     {"domain", 1, setdomain},	/* Add given domain name to hostname*/
     {"mru", 1, setmru},		/* Set MRU value for negotiation */
     {"mtu", 1, setmtu},		/* Set our MTU */
+    {"cb", 1, setcbcp},		/* Set CBCP */
     {"netmask", 1, setnetmask},	/* set netmask */
     {"passive", 0, setpassive},	/* Set passive mode */
     {"silent", 0, setsilent},	/* Set silent mode */
     {"modem", 0, setmodem},	/* Use modem control lines */
     {"local", 0, setlocal},	/* Don't use modem control lines */
     {"lock", 0, setlock},	/* Lock serial device (with lock file) */
     {"name", 1, setname},	/* Set local name for authentication */
     {"user", 1, setuser},	/* Set username for PAP auth with peer */
     {"usehostname", 0, setusehostname},	/* Must use hostname for auth. */
     {"remotename", 1, setremote}, /* Set remote name for authentication */
@@ -775,20 +778,31 @@
 	return 0;
     if (mtu < MINMRU || mtu > MAXMRU) {
 	fprintf(stderr, "mtu option value of %ld is too %s\n", mtu,
 		(mtu < MINMRU? "small": "large"));
 	return 0;
     }
     lcp_allowoptions[0].mru = mtu;
     return (1);
 }
 
+static int
+setcbcp(argv)
+    char **argv;
+{
+    lcp_wantoptions[0].neg_cbcp = 1;
+   
+    cbcp[0].us_number = (char *) malloc(strlen(*argv) + 1);
+    strcpy(cbcp[0].us_number, *argv);
+    cbcp[0].us_type |= (1 << CB_CONF_USER);
+    return (1);
+}
 
 /*
  * nopcomp - Disable Protocol field compression negotiation.
  */
 static int
 nopcomp()
 {
     lcp_wantoptions[0].neg_pcompression = 0;
     lcp_allowoptions[0].neg_pcompression = 0;
     return (1);
diff -r --unified=10 ppp-2.2a5.orig/pppd/pppd.8 ppp-2.2a5/pppd/pppd.8
--- ppp-2.2a5.orig/pppd/pppd.8	Sat May 13 12:38:21 1995
+++ ppp-2.2a5/pppd/pppd.8	Sat May 13 13:52:26 1995
@@ -221,20 +221,31 @@
 .B -pap
 Don't agree to authenticate using PAP.
 .TP
 .B +chap
 Require the peer to authenticate itself using CHAP [Cryptographic
 Handshake Authentication Protocol] authentication.
 .TP
 .B -chap
 Don't agree to authenticate using CHAP.
 .TP
+.B cb \fItelephone_number
+Configure the current execution of pppd to negotiate the \fIclient\fR
+portion of '\fIC\fRall \fIB\fRack \fIC\fRonfiguration
+\fIP\fRrotocol'. The use of this protocol will permit the client to
+authenticate itself with the server and then supply a telephone number
+for the reverse connection. Once the telephone number is accepted, the
+connection will be terminated. You should then wait for the server to
+recall your location and re-authenticate yourself. This second step
+will require a second execution of \fIpppd\fR. This second execution should
+not include the \fIcb\fR option.
+.TP
 .B -vj
 Disable negotiation of Van Jacobson style IP header compression (use
 default, i.e. no compression).
 .TP
 .B bsdcomp \fInr,nt
 Request that the peer compress packets that it sends, using the
 BSD-Compress scheme, with a maximum code size of \fInr\fR bits, and
 agree to compress packets sent to the peer with a maximum code size of
 \fInt\fR bits.  If \fInt\fR is not specified, it defaults to the value
 given for \fInr\fR.  Values in the range 9 to 15 may be used for
diff -r --unified=10 ppp-2.2a5.orig/pppd/pppd.h ppp-2.2a5/pppd/pppd.h
--- ppp-2.2a5.orig/pppd/pppd.h	Sat May 13 12:38:21 1995
+++ ppp-2.2a5/pppd/pppd.h	Sat May 13 13:46:36 1995
@@ -85,22 +85,23 @@
 extern int	disable_defaultip; /* Don't use hostname for default IP adrs */
 extern char	*ipparam;	/* Extra parameter for ip up/down scripts */
 extern int	cryptpap;	/* Others' PAP passwords are encrypted */
 
 /*
  * Values for phase.
  */
 #define PHASE_DEAD		0
 #define PHASE_ESTABLISH		1
 #define PHASE_AUTHENTICATE	2
-#define PHASE_NETWORK		3
-#define PHASE_TERMINATE		4
+#define PHASE_CALLBACK          3
+#define PHASE_NETWORK		4
+#define PHASE_TERMINATE		5
 
 /*
  * Prototypes.
  */
 void quit __P((void));	/* Cleanup and exit */
 void timeout __P((void (*)(), caddr_t, int));
 				/* Look-alike of kernel's timeout() */
 void untimeout __P((void (*)(), caddr_t));
 				/* Look-alike of kernel's untimeout() */
 void output __P((int, u_char *, int));
