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