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