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