17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * cbcp - Call Back Configuration Protocol.
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * Copyright (c) 2000 by Sun Microsystems, Inc.
57c478bd9Sstevel@tonic-gate  * All rights reserved.
67c478bd9Sstevel@tonic-gate  *
77c478bd9Sstevel@tonic-gate  * Copyright (c) 1995 Pedro Roque Marques
87c478bd9Sstevel@tonic-gate  * All rights reserved.
97c478bd9Sstevel@tonic-gate  *
107c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
117c478bd9Sstevel@tonic-gate  * provided that the above copyright notice and this paragraph are
127c478bd9Sstevel@tonic-gate  * duplicated in all such forms and that any documentation,
137c478bd9Sstevel@tonic-gate  * advertising materials, and other materials related to such
147c478bd9Sstevel@tonic-gate  * distribution and use acknowledge that the software was developed
157c478bd9Sstevel@tonic-gate  * by Pedro Roque Marques.  The name of the author may not be used to
167c478bd9Sstevel@tonic-gate  * endorse or promote products derived from this software without
177c478bd9Sstevel@tonic-gate  * specific prior written permission.
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
207c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
217c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
227c478bd9Sstevel@tonic-gate  */
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate #include <stdio.h>
257c478bd9Sstevel@tonic-gate #include <string.h>
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/time.h>
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include "pppd.h"
307c478bd9Sstevel@tonic-gate #include "cbcp.h"
317c478bd9Sstevel@tonic-gate #include "fsm.h"
327c478bd9Sstevel@tonic-gate #include "lcp.h"
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate  * Options.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate static int setcbcp __P((char **, option_t *));
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate static option_t cbcp_option_list[] = {
407c478bd9Sstevel@tonic-gate     { "callback", o_special, (void *)setcbcp,
417c478bd9Sstevel@tonic-gate       "Ask for callback" },
427c478bd9Sstevel@tonic-gate     { NULL }
437c478bd9Sstevel@tonic-gate };
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * Protocol entry points.
477c478bd9Sstevel@tonic-gate  */
487c478bd9Sstevel@tonic-gate static void cbcp_init      __P((int unit));
497c478bd9Sstevel@tonic-gate static void cbcp_lowerup   __P((int unit));
507c478bd9Sstevel@tonic-gate static void cbcp_input     __P((int unit, u_char *pkt, int len));
517c478bd9Sstevel@tonic-gate static void cbcp_protrej   __P((int unit));
527c478bd9Sstevel@tonic-gate static int  cbcp_printpkt  __P((u_char *pkt, int len,
537c478bd9Sstevel@tonic-gate     void (*printer) __P((void *, const char *, ...)),
547c478bd9Sstevel@tonic-gate     void *arg));
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate struct protent cbcp_protent = {
577c478bd9Sstevel@tonic-gate     PPP_CBCP,			/* PPP protocol number */
587c478bd9Sstevel@tonic-gate     cbcp_init,			/* Initialization procedure */
597c478bd9Sstevel@tonic-gate     cbcp_input,			/* Process a received packet */
607c478bd9Sstevel@tonic-gate     cbcp_protrej,		/* Process a received protocol-reject */
617c478bd9Sstevel@tonic-gate     cbcp_lowerup,		/* Lower layer has come up */
627c478bd9Sstevel@tonic-gate     NULL,			/* Lower layer has gone down */
637c478bd9Sstevel@tonic-gate     NULL,			/* Open the protocol */
647c478bd9Sstevel@tonic-gate     NULL,			/* Close the protocol */
657c478bd9Sstevel@tonic-gate     cbcp_printpkt,		/* Print a packet in readable form */
667c478bd9Sstevel@tonic-gate     NULL,			/* Process a received data packet */
677c478bd9Sstevel@tonic-gate     0,				/* 0 iff protocol is disabled */
687c478bd9Sstevel@tonic-gate     "CBCP",			/* Text name of protocol */
697c478bd9Sstevel@tonic-gate     NULL,			/* Text name of corresponding data protocol */
707c478bd9Sstevel@tonic-gate     cbcp_option_list,		/* List of command-line options */
717c478bd9Sstevel@tonic-gate     NULL,			/* Check requested options, assign defaults */
727c478bd9Sstevel@tonic-gate     NULL,			/* Configure interface for demand-dial */
737c478bd9Sstevel@tonic-gate     NULL			/* Say whether to bring up link for this pkt */
747c478bd9Sstevel@tonic-gate };
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /* Not static'd for plug-ins */
77*55fea89dSDan Cross cbcp_state cbcp[NUM_PPP];
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate /* internal prototypes */
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate static void cbcp_recvreq __P((cbcp_state *us, u_char *pckt, int len));
827c478bd9Sstevel@tonic-gate static void cbcp_recvack __P((cbcp_state *us, u_char *pckt, int len));
837c478bd9Sstevel@tonic-gate static void cbcp_send __P((cbcp_state *us, int code, u_char *buf, int len));
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate /* option processing */
867c478bd9Sstevel@tonic-gate /*ARGSUSED*/
877c478bd9Sstevel@tonic-gate static int
setcbcp(argv,opt)887c478bd9Sstevel@tonic-gate setcbcp(argv, opt)
897c478bd9Sstevel@tonic-gate     char **argv;
907c478bd9Sstevel@tonic-gate     option_t *opt;
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate     lcp_wantoptions[0].neg_cbcp = 1;
937c478bd9Sstevel@tonic-gate     cbcp_protent.enabled_flag = 1;
947c478bd9Sstevel@tonic-gate     cbcp[0].us_number = strdup(*argv);
957c478bd9Sstevel@tonic-gate     if (cbcp[0].us_number == NULL)
967c478bd9Sstevel@tonic-gate 	novm("callback number");
977c478bd9Sstevel@tonic-gate     cbcp[0].us_type |= (1 << CB_CONF_USER);
987c478bd9Sstevel@tonic-gate     cbcp[0].us_type |= (1 << CB_CONF_ADMIN);
997c478bd9Sstevel@tonic-gate     return (1);
1007c478bd9Sstevel@tonic-gate }
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /* init state */
1037c478bd9Sstevel@tonic-gate static void
cbcp_init(unit)1047c478bd9Sstevel@tonic-gate cbcp_init(unit)
1057c478bd9Sstevel@tonic-gate     int unit;
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate     cbcp_state *us;
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate     us = &cbcp[unit];
1107c478bd9Sstevel@tonic-gate     BZERO(us, sizeof(cbcp_state));
1117c478bd9Sstevel@tonic-gate     us->us_unit = unit;
1127c478bd9Sstevel@tonic-gate     us->us_type |= (1 << CB_CONF_NO);
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /* lower layer is up */
1167c478bd9Sstevel@tonic-gate static void
cbcp_lowerup(unit)1177c478bd9Sstevel@tonic-gate cbcp_lowerup(unit)
1187c478bd9Sstevel@tonic-gate     int unit;
1197c478bd9Sstevel@tonic-gate {
1207c478bd9Sstevel@tonic-gate     cbcp_state *us = &cbcp[unit];
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate     if (debug) {
1237c478bd9Sstevel@tonic-gate 	dbglog("cbcp_lowerup: want: %d", us->us_type);
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	if (us->us_type == CB_CONF_USER)
1267c478bd9Sstevel@tonic-gate 	    dbglog("phone no: %s", us->us_number);
1277c478bd9Sstevel@tonic-gate     }
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate /* process an incoming packet */
1317c478bd9Sstevel@tonic-gate static void
cbcp_input(unit,inpacket,pktlen)1327c478bd9Sstevel@tonic-gate cbcp_input(unit, inpacket, pktlen)
1337c478bd9Sstevel@tonic-gate     int unit;
1347c478bd9Sstevel@tonic-gate     u_char *inpacket;
1357c478bd9Sstevel@tonic-gate     int pktlen;
1367c478bd9Sstevel@tonic-gate {
1377c478bd9Sstevel@tonic-gate     u_char *inp;
1387c478bd9Sstevel@tonic-gate     u_char code, id;
1397c478bd9Sstevel@tonic-gate     u_short len;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate     cbcp_state *us = &cbcp[unit];
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate     inp = inpacket;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate     if (pktlen < CBCP_MINLEN) {
1467c478bd9Sstevel@tonic-gate         error("CBCP packet is too small (%d < %d)", pktlen, CBCP_MINLEN);
1477c478bd9Sstevel@tonic-gate 	return;
1487c478bd9Sstevel@tonic-gate     }
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate     GETCHAR(code, inp);
1517c478bd9Sstevel@tonic-gate     GETCHAR(id, inp);
1527c478bd9Sstevel@tonic-gate     GETSHORT(len, inp);
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate     if (len > pktlen) {
1557c478bd9Sstevel@tonic-gate         error("CBCP packet: invalid length (%d > %d)", len, pktlen);
1567c478bd9Sstevel@tonic-gate         return;
1577c478bd9Sstevel@tonic-gate     }
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate     len -= CBCP_MINLEN;
160*55fea89dSDan Cross 
1617c478bd9Sstevel@tonic-gate     switch (code) {
1627c478bd9Sstevel@tonic-gate     case CBCP_REQ:
1637c478bd9Sstevel@tonic-gate         us->us_id = id;
1647c478bd9Sstevel@tonic-gate 	cbcp_recvreq(us, inp, len);
1657c478bd9Sstevel@tonic-gate 	break;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate     case CBCP_RESP:
1687c478bd9Sstevel@tonic-gate 	if (debug)
1697c478bd9Sstevel@tonic-gate 	    dbglog("CBCP Response received; no request sent");
1707c478bd9Sstevel@tonic-gate 	break;
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate     case CBCP_ACK:
1737c478bd9Sstevel@tonic-gate 	if (id != us->us_id) {
1747c478bd9Sstevel@tonic-gate 	    if (debug)
1757c478bd9Sstevel@tonic-gate 		dbglog("CBCP Ack ID %d doesn't match expected %d", id,
1767c478bd9Sstevel@tonic-gate 		    us->us_id);
1777c478bd9Sstevel@tonic-gate 	    break;
1787c478bd9Sstevel@tonic-gate 	}
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	cbcp_recvack(us, inp, len);
1817c478bd9Sstevel@tonic-gate 	break;
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate     default:
1847c478bd9Sstevel@tonic-gate 	if (debug)
1857c478bd9Sstevel@tonic-gate 	    dbglog("Unknown CBCP code number %d", code);
1867c478bd9Sstevel@tonic-gate 	break;
1877c478bd9Sstevel@tonic-gate     }
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate /* protocol was rejected by foe */
1917c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1927c478bd9Sstevel@tonic-gate static void
cbcp_protrej(int unit)1937c478bd9Sstevel@tonic-gate cbcp_protrej(int unit)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate     start_networks();
1967c478bd9Sstevel@tonic-gate }
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate static char *cbcp_codenames[] = {
1997c478bd9Sstevel@tonic-gate     "Request", "Response", "Ack"
2007c478bd9Sstevel@tonic-gate };
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate static char *cbcp_optionnames[] = {
2037c478bd9Sstevel@tonic-gate     "NoCallback",
2047c478bd9Sstevel@tonic-gate     "UserDefined",
2057c478bd9Sstevel@tonic-gate     "AdminDefined",
2067c478bd9Sstevel@tonic-gate     "List"
2077c478bd9Sstevel@tonic-gate };
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate /*
2107c478bd9Sstevel@tonic-gate  * Pretty print a packet.  Return value is number of bytes parsed out
2117c478bd9Sstevel@tonic-gate  * of the packet and printed in some way.  Caller (in util.c) will
2127c478bd9Sstevel@tonic-gate  * print the remainder of the packet.
2137c478bd9Sstevel@tonic-gate  */
2147c478bd9Sstevel@tonic-gate static int
cbcp_printpkt(p,plen,printer,arg)2157c478bd9Sstevel@tonic-gate cbcp_printpkt(p, plen, printer, arg)
2167c478bd9Sstevel@tonic-gate     u_char *p;
2177c478bd9Sstevel@tonic-gate     int plen;
2187c478bd9Sstevel@tonic-gate     void (*printer) __P((void *, const char *, ...));
2197c478bd9Sstevel@tonic-gate     void *arg;
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate     int code, id, len, olen, alen;
2227c478bd9Sstevel@tonic-gate     u_char *pstart, cichar;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate     if (plen < HEADERLEN) {
2257c478bd9Sstevel@tonic-gate 	printer(arg, "too short (%d<%d)", plen, HEADERLEN);
2267c478bd9Sstevel@tonic-gate 	return (0);
2277c478bd9Sstevel@tonic-gate     }
2287c478bd9Sstevel@tonic-gate     pstart = p;
2297c478bd9Sstevel@tonic-gate     GETCHAR(code, p);
2307c478bd9Sstevel@tonic-gate     GETCHAR(id, p);
2317c478bd9Sstevel@tonic-gate     GETSHORT(len, p);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate     if (code >= 1 && code <= Dim(cbcp_codenames))
2347c478bd9Sstevel@tonic-gate 	printer(arg, " %s", cbcp_codenames[code-1]);
2357c478bd9Sstevel@tonic-gate     else
236*55fea89dSDan Cross 	printer(arg, " code=0x%x", code);
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate     printer(arg, " id=0x%x", id);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate     if (len < HEADERLEN) {
2417c478bd9Sstevel@tonic-gate 	printer(arg, " header length %d<%d", len, HEADERLEN);
2427c478bd9Sstevel@tonic-gate 	return (HEADERLEN);
2437c478bd9Sstevel@tonic-gate     }
2447c478bd9Sstevel@tonic-gate     if (len > plen) {
2457c478bd9Sstevel@tonic-gate 	printer(arg, " truncated (%d>%d)", len, plen);
2467c478bd9Sstevel@tonic-gate 	len = plen;
2477c478bd9Sstevel@tonic-gate     }
2487c478bd9Sstevel@tonic-gate     len -= HEADERLEN;
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate     switch (code) {
2517c478bd9Sstevel@tonic-gate     case CBCP_REQ:
2527c478bd9Sstevel@tonic-gate     case CBCP_RESP:
2537c478bd9Sstevel@tonic-gate     case CBCP_ACK:
2547c478bd9Sstevel@tonic-gate         while (len >= 2) {
2557c478bd9Sstevel@tonic-gate 	    GETCHAR(cichar, p);
2567c478bd9Sstevel@tonic-gate 	    GETCHAR(olen, p);
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	    if (olen < 2)
2597c478bd9Sstevel@tonic-gate 		break;
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	    printer(arg, " <");
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	    if (olen > len) {
2647c478bd9Sstevel@tonic-gate 		printer(arg, "trunc[%d>%d] ", olen, len);
2657c478bd9Sstevel@tonic-gate 	        olen = len;
2667c478bd9Sstevel@tonic-gate 	    }
2677c478bd9Sstevel@tonic-gate 	    len -= olen;
2687c478bd9Sstevel@tonic-gate 	    olen -= 2;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	    if (cichar >= 1 && cichar <= Dim(cbcp_optionnames))
2717c478bd9Sstevel@tonic-gate 	    	printer(arg, " %s", cbcp_optionnames[cichar-1]);
2727c478bd9Sstevel@tonic-gate 	    else
273*55fea89dSDan Cross 	        printer(arg, " option=0x%x", cichar);
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	    if (olen > 0) {
2767c478bd9Sstevel@tonic-gate 	        GETCHAR(cichar, p);
2777c478bd9Sstevel@tonic-gate 		olen--;
2787c478bd9Sstevel@tonic-gate 		printer(arg, " delay=%d", cichar);
2797c478bd9Sstevel@tonic-gate 	    }
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	    while (olen > 0) {
2827c478bd9Sstevel@tonic-gate 		GETCHAR(cichar, p);
2837c478bd9Sstevel@tonic-gate 		olen--;
2847c478bd9Sstevel@tonic-gate 		if (cichar != 1)
2857c478bd9Sstevel@tonic-gate 		    printer(arg, " (type %d?)", cichar);
2867c478bd9Sstevel@tonic-gate 		alen = strllen((const char *)p, olen);
2877c478bd9Sstevel@tonic-gate 		if (olen > 0 && alen > 0)
2887c478bd9Sstevel@tonic-gate 		    printer(arg, " '%.*s'", alen, p);
2897c478bd9Sstevel@tonic-gate 		else
2907c478bd9Sstevel@tonic-gate 		    printer(arg, " null");
2917c478bd9Sstevel@tonic-gate 		p += alen + 1;
2927c478bd9Sstevel@tonic-gate 		olen -= alen + 1;
2937c478bd9Sstevel@tonic-gate 	    }
2947c478bd9Sstevel@tonic-gate 	    printer(arg, ">");
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate     default:
2987c478bd9Sstevel@tonic-gate 	break;
2997c478bd9Sstevel@tonic-gate     }
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate     if (len > 0) {
3027c478bd9Sstevel@tonic-gate 	if (len > 8)
3037c478bd9Sstevel@tonic-gate 	    printer(arg, "%8B ...", p);
3047c478bd9Sstevel@tonic-gate 	else
3057c478bd9Sstevel@tonic-gate 	    printer(arg, "%.*B", len, p);
3067c478bd9Sstevel@tonic-gate     }
3077c478bd9Sstevel@tonic-gate     p += len;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate     return p - pstart;
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate /*
3137c478bd9Sstevel@tonic-gate  * received CBCP request.
3147c478bd9Sstevel@tonic-gate  * No reason to print packet contents in detail here, since enabling
3157c478bd9Sstevel@tonic-gate  * debug mode will cause the print routine above to be invoked.
3167c478bd9Sstevel@tonic-gate  */
3177c478bd9Sstevel@tonic-gate static void
cbcp_recvreq(us,pckt,pcktlen)3187c478bd9Sstevel@tonic-gate cbcp_recvreq(us, pckt, pcktlen)
3197c478bd9Sstevel@tonic-gate     cbcp_state *us;
3207c478bd9Sstevel@tonic-gate     u_char *pckt;
3217c478bd9Sstevel@tonic-gate     int pcktlen;
3227c478bd9Sstevel@tonic-gate {
3237c478bd9Sstevel@tonic-gate     u_char type, opt_len;
3247c478bd9Sstevel@tonic-gate     int len = pcktlen;
3257c478bd9Sstevel@tonic-gate     u_char cb_type;
3267c478bd9Sstevel@tonic-gate     u_char buf[256];
3277c478bd9Sstevel@tonic-gate     u_char *bufp = buf;
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate     us->us_allowed = 0;
3307c478bd9Sstevel@tonic-gate     while (len > 0) {
3317c478bd9Sstevel@tonic-gate 	GETCHAR(type, pckt);
3327c478bd9Sstevel@tonic-gate 	GETCHAR(opt_len, pckt);
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	if (opt_len > 2) {
3357c478bd9Sstevel@tonic-gate 	    pckt++;	/* ignore the delay time */
3367c478bd9Sstevel@tonic-gate 	}
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	len -= opt_len;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	/*
3417c478bd9Sstevel@tonic-gate 	 * Careful; don't use left-shift operator on numbers that are
3427c478bd9Sstevel@tonic-gate 	 * too big.
3437c478bd9Sstevel@tonic-gate 	 */
3447c478bd9Sstevel@tonic-gate 	if (type > CB_CONF_LIST) {
3457c478bd9Sstevel@tonic-gate 	    if (debug)
3467c478bd9Sstevel@tonic-gate 		dbglog("CBCP: ignoring unknown type %d", type);
3477c478bd9Sstevel@tonic-gate 	    continue;
3487c478bd9Sstevel@tonic-gate 	}
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	us->us_allowed |= (1 << type);
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	switch (type) {
3537c478bd9Sstevel@tonic-gate 	case CB_CONF_NO:
3547c478bd9Sstevel@tonic-gate 	    if (debug)
3557c478bd9Sstevel@tonic-gate 		dbglog("CBCP: operation without callback allowed");
3567c478bd9Sstevel@tonic-gate 	    break;
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	case CB_CONF_USER:
3597c478bd9Sstevel@tonic-gate 	    if (debug)
3607c478bd9Sstevel@tonic-gate 		dbglog("callback to user-specified number allowed");
3617c478bd9Sstevel@tonic-gate 	    break;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	case CB_CONF_ADMIN:
3647c478bd9Sstevel@tonic-gate 	    if (debug)
3657c478bd9Sstevel@tonic-gate 		dbglog("CBCP: callback to admin-defined address allowed");
3667c478bd9Sstevel@tonic-gate 	    break;
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	case CB_CONF_LIST:
3697c478bd9Sstevel@tonic-gate 	    if (debug)
3707c478bd9Sstevel@tonic-gate 		dbglog("CBCP: callback to one out of list allowed");
3717c478bd9Sstevel@tonic-gate 	    break;
3727c478bd9Sstevel@tonic-gate 	}
3737c478bd9Sstevel@tonic-gate     }
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate     /* Now generate the response */
3767c478bd9Sstevel@tonic-gate     len = 0;
3777c478bd9Sstevel@tonic-gate     cb_type = us->us_allowed & us->us_type;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate     if (cb_type & ( 1 << CB_CONF_USER ) ) {
3807c478bd9Sstevel@tonic-gate 	if (debug)
3817c478bd9Sstevel@tonic-gate 	    dbglog("CBCP Response: selecting user-specified number");
3827c478bd9Sstevel@tonic-gate 	PUTCHAR(CB_CONF_USER, bufp);
3837c478bd9Sstevel@tonic-gate 	len = 3 + 1 + strlen(us->us_number) + 1;
3847c478bd9Sstevel@tonic-gate 	PUTCHAR(len , bufp);
3857c478bd9Sstevel@tonic-gate 	PUTCHAR(5, bufp); /* delay */
3867c478bd9Sstevel@tonic-gate 	PUTCHAR(1, bufp);
3877c478bd9Sstevel@tonic-gate 	BCOPY(us->us_number, bufp, strlen(us->us_number) + 1);
3887c478bd9Sstevel@tonic-gate 	cbcp_send(us, CBCP_RESP, buf, len);
3897c478bd9Sstevel@tonic-gate 	return;
3907c478bd9Sstevel@tonic-gate     }
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate     if (cb_type & ( 1 << CB_CONF_ADMIN ) ) {
3937c478bd9Sstevel@tonic-gate 	if (debug)
3947c478bd9Sstevel@tonic-gate 	    dbglog("CBCP Response: selecting admin-specified number");
3957c478bd9Sstevel@tonic-gate         PUTCHAR(CB_CONF_ADMIN, bufp);
3967c478bd9Sstevel@tonic-gate 	len = 3;
3977c478bd9Sstevel@tonic-gate 	PUTCHAR(len, bufp);
3987c478bd9Sstevel@tonic-gate 	PUTCHAR(5, bufp); /* delay */
3997c478bd9Sstevel@tonic-gate 	cbcp_send(us, CBCP_RESP, buf, len);
4007c478bd9Sstevel@tonic-gate 	return;
4017c478bd9Sstevel@tonic-gate     }
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate     if (cb_type & ( 1 << CB_CONF_NO ) ) {
4047c478bd9Sstevel@tonic-gate 	if (debug)
4057c478bd9Sstevel@tonic-gate 	    dbglog("CBCP Response: selecting no-callback mode");
4067c478bd9Sstevel@tonic-gate 	PUTCHAR(CB_CONF_NO, bufp);
4077c478bd9Sstevel@tonic-gate 	len = 3;
4087c478bd9Sstevel@tonic-gate 	PUTCHAR(len , bufp);
4097c478bd9Sstevel@tonic-gate 	PUTCHAR(0, bufp);
4107c478bd9Sstevel@tonic-gate 	cbcp_send(us, CBCP_RESP, buf, len);
4117c478bd9Sstevel@tonic-gate 	start_networks();
4127c478bd9Sstevel@tonic-gate 	return;
4137c478bd9Sstevel@tonic-gate     }
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate     if (debug)
4167c478bd9Sstevel@tonic-gate 	dbglog("CBCP:  no callback types in common");
4177c478bd9Sstevel@tonic-gate     lcp_close(us->us_unit, "No CBCP callback options available");
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate static void
cbcp_send(us,code,buf,len)4217c478bd9Sstevel@tonic-gate cbcp_send(us, code, buf, len)
4227c478bd9Sstevel@tonic-gate     cbcp_state *us;
4237c478bd9Sstevel@tonic-gate     int code;
4247c478bd9Sstevel@tonic-gate     u_char *buf;
4257c478bd9Sstevel@tonic-gate     int len;
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate     u_char *outp;
4287c478bd9Sstevel@tonic-gate     int outlen;
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate     outp = outpacket_buf;
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate     outlen = 4 + len;
433*55fea89dSDan Cross 
4347c478bd9Sstevel@tonic-gate     MAKEHEADER(outp, PPP_CBCP);
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate     PUTCHAR(code, outp);
4377c478bd9Sstevel@tonic-gate     PUTCHAR(us->us_id, outp);
4387c478bd9Sstevel@tonic-gate     PUTSHORT(outlen, outp);
439*55fea89dSDan Cross 
4407c478bd9Sstevel@tonic-gate     if (len > 0)
4417c478bd9Sstevel@tonic-gate         BCOPY(buf, outp, len);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate     output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate /*
4477c478bd9Sstevel@tonic-gate  * Received CBCP Acknowledgment message.
4487c478bd9Sstevel@tonic-gate  */
4497c478bd9Sstevel@tonic-gate static void
cbcp_recvack(us,pckt,len)4507c478bd9Sstevel@tonic-gate cbcp_recvack(us, pckt, len)
4517c478bd9Sstevel@tonic-gate     cbcp_state *us;
4527c478bd9Sstevel@tonic-gate     u_char *pckt;
4537c478bd9Sstevel@tonic-gate     int len;
4547c478bd9Sstevel@tonic-gate {
4557c478bd9Sstevel@tonic-gate     u_char type, addr_type;
4567c478bd9Sstevel@tonic-gate     int opt_len;
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate     if (len > 0) {
4597c478bd9Sstevel@tonic-gate         GETCHAR(type, pckt);
4607c478bd9Sstevel@tonic-gate 	GETCHAR(opt_len, pckt);
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	if (type == CB_CONF_NO) {
4637c478bd9Sstevel@tonic-gate 	    if (debug)
4647c478bd9Sstevel@tonic-gate 		dbglog("CBCP: proceeding without callback");
4657c478bd9Sstevel@tonic-gate 	    return;
4667c478bd9Sstevel@tonic-gate 	}
467*55fea89dSDan Cross 
4687c478bd9Sstevel@tonic-gate 	/* just ignore the delay time */
4697c478bd9Sstevel@tonic-gate 	pckt++;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	if (opt_len > 4) {
4727c478bd9Sstevel@tonic-gate 	    GETCHAR(addr_type, pckt);
4737c478bd9Sstevel@tonic-gate 	    if (addr_type != 1)
4747c478bd9Sstevel@tonic-gate 		warn("CBCP: unknown callback address type %d", addr_type);
4757c478bd9Sstevel@tonic-gate 	}
4767c478bd9Sstevel@tonic-gate 	if (debug && opt_len > 5)
4777c478bd9Sstevel@tonic-gate 	    dbglog("CBCP: peer will call %.*s", pckt, opt_len - 4);
4787c478bd9Sstevel@tonic-gate     }
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate     persist = 0;
4817c478bd9Sstevel@tonic-gate     lcp_close(us->us_unit, "Call me back, please");
4827c478bd9Sstevel@tonic-gate     status = EXIT_CALLBACK;
4837c478bd9Sstevel@tonic-gate }
484