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@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