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