Home | History | Annotate | Line # | Download | only in pppd
      1 /*	$NetBSD: cbcp.c,v 1.6 2025/01/08 19:59:38 christos Exp $	*/
      2 
      3 /*
      4  * cbcp - Call Back Configuration Protocol.
      5  *
      6  * Copyright (c) 1995 Pedro Roque Marques.  All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  *
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in
     17  *    the documentation and/or other materials provided with the
     18  *    distribution.
     19  *
     20  * 3. The names of the authors of this software must not be used to
     21  *    endorse or promote products derived from this software without
     22  *    prior written permission.
     23  *
     24  * 4. Redistributions of any form whatsoever must retain the following
     25  *    acknowledgment:
     26  *    "This product includes software developed by Pedro Roque Marques
     27  *     <pedro_m (at) yahoo.com>"
     28  *
     29  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
     30  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     31  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
     32  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     33  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     34  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     35  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     36  */
     37 #ifdef HAVE_CONFIG_H
     38 #include "config.h"
     39 #endif
     40 
     41 #include <sys/cdefs.h>
     42 __RCSID("$NetBSD: cbcp.c,v 1.6 2025/01/08 19:59:38 christos Exp $");
     43 
     44 #include <stdio.h>
     45 #include <string.h>
     46 #include <sys/types.h>
     47 #include <sys/time.h>
     48 
     49 #include "pppd-private.h"
     50 #include "cbcp.h"
     51 #include "fsm.h"
     52 #include "lcp.h"
     53 #include "options.h"
     54 
     55 
     56 /*
     57  * Options.
     58  */
     59 static int setcbcp (char **);
     60 
     61 static struct option cbcp_option_list[] = {
     62     { "callback", o_special, (void *)setcbcp,
     63       "Ask for callback", OPT_PRIO | OPT_A2STRVAL, &cbcp[0].us_number },
     64     { NULL }
     65 };
     66 
     67 /*
     68  * Protocol entry points.
     69  */
     70 static void cbcp_init      (int unit);
     71 static void cbcp_open      (int unit);
     72 static void cbcp_lowerup   (int unit);
     73 static void cbcp_input     (int unit, u_char *pkt, int len);
     74 static void cbcp_protrej   (int unit);
     75 static int  cbcp_printpkt  (u_char *pkt, int len,
     76 			    void (*printer)(void *, char *, ...),
     77 			    void *arg);
     78 
     79 struct protent cbcp_protent = {
     80     PPP_CBCP,
     81     cbcp_init,
     82     cbcp_input,
     83     cbcp_protrej,
     84     cbcp_lowerup,
     85     NULL,
     86     cbcp_open,
     87     NULL,
     88     cbcp_printpkt,
     89     NULL,
     90     0,
     91     "CBCP",
     92     NULL,
     93     cbcp_option_list,
     94     NULL,
     95     NULL,
     96     NULL
     97 };
     98 
     99 cbcp_state cbcp[NUM_PPP];
    100 
    101 /* internal prototypes */
    102 
    103 static void cbcp_recvreq (cbcp_state *us, u_char *pckt, int len);
    104 static void cbcp_resp (cbcp_state *us);
    105 static void cbcp_up (cbcp_state *us);
    106 static void cbcp_recvack (cbcp_state *us, u_char *pckt, int len);
    107 static void cbcp_send (cbcp_state *us, int code, u_char *buf, int len);
    108 
    109 /* option processing */
    110 static int
    111 setcbcp(char **argv)
    112 {
    113     lcp_wantoptions[0].neg_cbcp = 1;
    114     cbcp_protent.enabled_flag = 1;
    115     cbcp[0].us_number = strdup(*argv);
    116     if (cbcp[0].us_number == 0)
    117 	novm("callback number");
    118     cbcp[0].us_type |= (1 << CB_CONF_USER);
    119     cbcp[0].us_type |= (1 << CB_CONF_ADMIN);
    120     return (1);
    121 }
    122 
    123 /* init state */
    124 static void
    125 cbcp_init(int iface)
    126 {
    127     cbcp_state *us;
    128 
    129     us = &cbcp[iface];
    130     memset(us, 0, sizeof(cbcp_state));
    131     us->us_unit = iface;
    132     us->us_type |= (1 << CB_CONF_NO);
    133 }
    134 
    135 /* lower layer is up */
    136 static void
    137 cbcp_lowerup(int iface)
    138 {
    139     cbcp_state *us = &cbcp[iface];
    140 
    141     dbglog("cbcp_lowerup");
    142     dbglog("want: %d", us->us_type);
    143 
    144     if (us->us_type == CB_CONF_USER)
    145         dbglog("phone no: %s", us->us_number);
    146 }
    147 
    148 static void
    149 cbcp_open(int unit)
    150 {
    151     dbglog("cbcp_open");
    152 }
    153 
    154 /* process an incomming packet */
    155 static void
    156 cbcp_input(int unit, u_char *inpacket, int pktlen)
    157 {
    158     u_char *inp;
    159     u_char code, id;
    160     u_short len;
    161 
    162     cbcp_state *us = &cbcp[unit];
    163 
    164     inp = inpacket;
    165 
    166     if (pktlen < CBCP_MINLEN) {
    167 	if (debug)
    168 	    dbglog("CBCP: Packet too short (%d)", pktlen);
    169 	return;
    170     }
    171 
    172     GETCHAR(code, inp);
    173     GETCHAR(id, inp);
    174     GETSHORT(len, inp);
    175 
    176     if (len > pktlen || len < CBCP_MINLEN) {
    177 	if (debug)
    178 	    dbglog("CBCP: Invalid packet length (%d/%d)", len, pktlen);
    179         return;
    180     }
    181 
    182     len -= CBCP_MINLEN;
    183 
    184     switch(code) {
    185     case CBCP_REQ:
    186         us->us_id = id;
    187 	cbcp_recvreq(us, inp, len);
    188 	break;
    189 
    190     case CBCP_RESP:
    191 	if (debug)
    192 	    dbglog("CBCP_RESP received");
    193 	break;
    194 
    195     case CBCP_ACK:
    196 	if (debug && id != us->us_id)
    197 	    dbglog("id doesn't match: expected %d recv %d",
    198 		   us->us_id, id);
    199 
    200 	cbcp_recvack(us, inp, len);
    201 	break;
    202 
    203     default:
    204 	break;
    205     }
    206 }
    207 
    208 /* protocol was rejected by foe */
    209 void cbcp_protrej(int iface)
    210 {
    211 }
    212 
    213 char *cbcp_codenames[] = {
    214     "Request", "Response", "Ack"
    215 };
    216 
    217 char *cbcp_optionnames[] = {
    218     "NoCallback",
    219     "UserDefined",
    220     "AdminDefined",
    221     "List"
    222 };
    223 
    224 /* pretty print a packet */
    225 static int
    226 cbcp_printpkt(u_char *p, int plen,
    227 	      void (*printer) (void *, char *, ...), void *arg)
    228 {
    229     int code, opt, id, len, olen, delay;
    230     u_char *pstart;
    231 
    232     if (plen < HEADERLEN)
    233 	return 0;
    234     pstart = p;
    235     GETCHAR(code, p);
    236     GETCHAR(id, p);
    237     GETSHORT(len, p);
    238     if (len < HEADERLEN || len > plen)
    239 	return 0;
    240 
    241     if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *))
    242 	printer(arg, " %s", cbcp_codenames[code-1]);
    243     else
    244 	printer(arg, " code=0x%x", code);
    245 
    246     printer(arg, " id=0x%x", id);
    247     len -= HEADERLEN;
    248 
    249     switch (code) {
    250     case CBCP_REQ:
    251     case CBCP_RESP:
    252     case CBCP_ACK:
    253         while(len >= 2) {
    254 	    GETCHAR(opt, p);
    255 	    GETCHAR(olen, p);
    256 
    257 	    if (olen < 2 || olen > len) {
    258 	        break;
    259 	    }
    260 
    261 	    printer(arg, " <");
    262 	    len -= olen;
    263 
    264 	    if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *))
    265 	    	printer(arg, " %s", cbcp_optionnames[opt-1]);
    266 	    else
    267 	        printer(arg, " option=0x%x", opt);
    268 
    269 	    if (olen > 2) {
    270 	        GETCHAR(delay, p);
    271 		printer(arg, " delay = %d", delay);
    272 	    }
    273 
    274 	    if (olen > 3) {
    275 	        int addrt;
    276 		char str[256];
    277 
    278 		GETCHAR(addrt, p);
    279 		__USE(addrt);
    280 		memcpy(str, p, olen - 4);
    281 		str[olen - 4] = 0;
    282 		printer(arg, " number = %s", str);
    283 	    }
    284 	    printer(arg, ">");
    285 	}
    286 	break;
    287 
    288     default:
    289 	break;
    290     }
    291 
    292     for (; len > 0; --len) {
    293 	GETCHAR(code, p);
    294 	printer(arg, " %.2x", code);
    295     }
    296 
    297     return p - pstart;
    298 }
    299 
    300 /* received CBCP request */
    301 static void
    302 cbcp_recvreq(cbcp_state *us, u_char *pckt, int pcktlen)
    303 {
    304     u_char type, opt_len, delay, addr_type;
    305     char address[256];
    306     int len = pcktlen;
    307 
    308     address[0] = 0;
    309 
    310     while (len >= 2) {
    311         dbglog("length: %d", len);
    312 
    313 	GETCHAR(type, pckt);
    314 	GETCHAR(opt_len, pckt);
    315 	if (opt_len < 2 || opt_len > len) {
    316 	    if (debug)
    317 		dbglog("CBCP: Malformed option length (%d/%d)", opt_len, len);
    318 	    break;
    319 	}
    320 
    321 	if (opt_len > 2) {
    322 	    GETCHAR(delay, pckt);
    323 	    __USE(delay);
    324 	}
    325 
    326 	us->us_allowed |= (1 << type);
    327 
    328 	switch(type) {
    329 	case CB_CONF_NO:
    330 	    dbglog("no callback allowed");
    331 	    break;
    332 
    333 	case CB_CONF_USER:
    334 	    dbglog("user callback allowed");
    335 	    if (opt_len > 4) {
    336 	        GETCHAR(addr_type, pckt);
    337 		__USE(addr_type);
    338 		memcpy(address, pckt, opt_len - 4);
    339 		address[opt_len - 4] = 0;
    340 		if (address[0])
    341 		    dbglog("address: %s", address);
    342 	    }
    343 	    break;
    344 
    345 	case CB_CONF_ADMIN:
    346 	    dbglog("user admin defined allowed");
    347 	    break;
    348 
    349 	case CB_CONF_LIST:
    350 	    break;
    351 	}
    352 	len -= opt_len;
    353     }
    354     if (len != 0) {
    355 	if (debug)
    356 	    dbglog("cbcp_recvreq: malformed packet (%d bytes left)", len);
    357 	return;
    358     }
    359 
    360     cbcp_resp(us);
    361 }
    362 
    363 static void
    364 cbcp_resp(cbcp_state *us)
    365 {
    366     u_char cb_type;
    367     u_char buf[256];
    368     u_char *bufp = buf;
    369     int len = 0;
    370     int slen;
    371 
    372     cb_type = us->us_allowed & us->us_type;
    373     dbglog("cbcp_resp cb_type=%d", cb_type);
    374 
    375 #if 0
    376     if (!cb_type)
    377         lcp_down(us->us_unit);
    378 #endif
    379 
    380     if (cb_type & ( 1 << CB_CONF_USER ) ) {
    381 	dbglog("cbcp_resp CONF_USER");
    382 	slen = strlen(us->us_number);
    383 	if (slen > 250) {
    384 	    warn("callback number truncated to 250 characters");
    385 	    slen = 250;
    386 	}
    387 	PUTCHAR(CB_CONF_USER, bufp);
    388 	len = 3 + 1 + slen + 1;
    389 	PUTCHAR(len , bufp);
    390 	PUTCHAR(5, bufp); /* delay */
    391 	PUTCHAR(1, bufp);
    392 	BCOPY(us->us_number, bufp, slen + 1);
    393 	cbcp_send(us, CBCP_RESP, buf, len);
    394 	return;
    395     }
    396 
    397     if (cb_type & ( 1 << CB_CONF_ADMIN ) ) {
    398 	dbglog("cbcp_resp CONF_ADMIN");
    399         PUTCHAR(CB_CONF_ADMIN, bufp);
    400 	len = 3;
    401 	PUTCHAR(len, bufp);
    402 	PUTCHAR(5, bufp); /* delay */
    403 	cbcp_send(us, CBCP_RESP, buf, len);
    404 	return;
    405     }
    406 
    407     if (cb_type & ( 1 << CB_CONF_NO ) ) {
    408         dbglog("cbcp_resp CONF_NO");
    409 	PUTCHAR(CB_CONF_NO, bufp);
    410 	len = 2;
    411 	PUTCHAR(len , bufp);
    412 	cbcp_send(us, CBCP_RESP, buf, len);
    413 	start_networks(us->us_unit);
    414 	return;
    415     }
    416 }
    417 
    418 static void
    419 cbcp_send(cbcp_state *us, int code, u_char *buf, int len)
    420 {
    421     u_char *outp;
    422     int outlen;
    423 
    424     outp = outpacket_buf;
    425 
    426     outlen = 4 + len;
    427 
    428     MAKEHEADER(outp, PPP_CBCP);
    429 
    430     PUTCHAR(code, outp);
    431     PUTCHAR(us->us_id, outp);
    432     PUTSHORT(outlen, outp);
    433 
    434     if (len)
    435         BCOPY(buf, outp, len);
    436 
    437     output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
    438 }
    439 
    440 static void
    441 cbcp_recvack(cbcp_state *us, u_char *pckt, int len)
    442 {
    443     u_char type, delay, addr_type;
    444     int opt_len;
    445     char address[256];
    446 
    447     if (len >= 2) {
    448         GETCHAR(type, pckt);
    449 	GETCHAR(opt_len, pckt);
    450 	if (opt_len >= 2 && opt_len <= len) {
    451 
    452 	    if (opt_len > 2) {
    453 		GETCHAR(delay, pckt);
    454 		__USE(delay);
    455 	    }
    456 
    457 	    if (opt_len > 4) {
    458 		GETCHAR(addr_type, pckt);
    459 		__USE(addr_type);
    460 		memcpy(address, pckt, opt_len - 4);
    461 		address[opt_len - 4] = 0;
    462 		if (address[0])
    463 		    dbglog("peer will call: %s", address);
    464 	    }
    465 	    if (type == CB_CONF_NO)
    466 		return;
    467 
    468 	    cbcp_up(us);
    469 
    470 	} else if (debug)
    471 	    dbglog("cbcp_recvack: malformed packet");
    472     }
    473 }
    474 
    475 /* ok peer will do callback */
    476 static void
    477 cbcp_up(cbcp_state *us)
    478 {
    479     persist = 0;
    480     ppp_set_status(EXIT_CALLBACK);
    481     lcp_close(0, "Call me back, please");
    482 }
    483