1 /* 2 * cbcp - Call Back Configuration Protocol. 3 * 4 * Copyright (c) 2000 by Sun Microsystems, Inc. 5 * All rights reserved. 6 * 7 * Copyright (c) 1995 Pedro Roque Marques 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms are permitted 11 * provided that the above copyright notice and this paragraph are 12 * duplicated in all such forms and that any documentation, 13 * advertising materials, and other materials related to such 14 * distribution and use acknowledge that the software was developed 15 * by Pedro Roque Marques. The name of the author may not be used to 16 * endorse or promote products derived from this software without 17 * specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 21 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 */ 23 24 #pragma ident "%Z%%M% %I% %E% SMI" 25 #define RCSID "$Id: cbcp.c,v 1.10 1999/08/13 06:46:10 paulus Exp $" 26 27 #include <stdio.h> 28 #include <string.h> 29 #include <sys/types.h> 30 #include <sys/time.h> 31 32 #include "pppd.h" 33 #include "cbcp.h" 34 #include "fsm.h" 35 #include "lcp.h" 36 37 #if !defined(lint) && !defined(_lint) 38 static const char rcsid[] = RCSID; 39 #endif 40 41 /* 42 * Options. 43 */ 44 static int setcbcp __P((char **, option_t *)); 45 46 static option_t cbcp_option_list[] = { 47 { "callback", o_special, (void *)setcbcp, 48 "Ask for callback" }, 49 { NULL } 50 }; 51 52 /* 53 * Protocol entry points. 54 */ 55 static void cbcp_init __P((int unit)); 56 static void cbcp_lowerup __P((int unit)); 57 static void cbcp_input __P((int unit, u_char *pkt, int len)); 58 static void cbcp_protrej __P((int unit)); 59 static int cbcp_printpkt __P((u_char *pkt, int len, 60 void (*printer) __P((void *, const char *, ...)), 61 void *arg)); 62 63 struct protent cbcp_protent = { 64 PPP_CBCP, /* PPP protocol number */ 65 cbcp_init, /* Initialization procedure */ 66 cbcp_input, /* Process a received packet */ 67 cbcp_protrej, /* Process a received protocol-reject */ 68 cbcp_lowerup, /* Lower layer has come up */ 69 NULL, /* Lower layer has gone down */ 70 NULL, /* Open the protocol */ 71 NULL, /* Close the protocol */ 72 cbcp_printpkt, /* Print a packet in readable form */ 73 NULL, /* Process a received data packet */ 74 0, /* 0 iff protocol is disabled */ 75 "CBCP", /* Text name of protocol */ 76 NULL, /* Text name of corresponding data protocol */ 77 cbcp_option_list, /* List of command-line options */ 78 NULL, /* Check requested options, assign defaults */ 79 NULL, /* Configure interface for demand-dial */ 80 NULL /* Say whether to bring up link for this pkt */ 81 }; 82 83 /* Not static'd for plug-ins */ 84 cbcp_state cbcp[NUM_PPP]; 85 86 /* internal prototypes */ 87 88 static void cbcp_recvreq __P((cbcp_state *us, u_char *pckt, int len)); 89 static void cbcp_recvack __P((cbcp_state *us, u_char *pckt, int len)); 90 static void cbcp_send __P((cbcp_state *us, int code, u_char *buf, int len)); 91 92 /* option processing */ 93 /*ARGSUSED*/ 94 static int 95 setcbcp(argv, opt) 96 char **argv; 97 option_t *opt; 98 { 99 lcp_wantoptions[0].neg_cbcp = 1; 100 cbcp_protent.enabled_flag = 1; 101 cbcp[0].us_number = strdup(*argv); 102 if (cbcp[0].us_number == NULL) 103 novm("callback number"); 104 cbcp[0].us_type |= (1 << CB_CONF_USER); 105 cbcp[0].us_type |= (1 << CB_CONF_ADMIN); 106 return (1); 107 } 108 109 /* init state */ 110 static void 111 cbcp_init(unit) 112 int unit; 113 { 114 cbcp_state *us; 115 116 us = &cbcp[unit]; 117 BZERO(us, sizeof(cbcp_state)); 118 us->us_unit = unit; 119 us->us_type |= (1 << CB_CONF_NO); 120 } 121 122 /* lower layer is up */ 123 static void 124 cbcp_lowerup(unit) 125 int unit; 126 { 127 cbcp_state *us = &cbcp[unit]; 128 129 if (debug) { 130 dbglog("cbcp_lowerup: want: %d", us->us_type); 131 132 if (us->us_type == CB_CONF_USER) 133 dbglog("phone no: %s", us->us_number); 134 } 135 } 136 137 /* process an incoming packet */ 138 static void 139 cbcp_input(unit, inpacket, pktlen) 140 int unit; 141 u_char *inpacket; 142 int pktlen; 143 { 144 u_char *inp; 145 u_char code, id; 146 u_short len; 147 148 cbcp_state *us = &cbcp[unit]; 149 150 inp = inpacket; 151 152 if (pktlen < CBCP_MINLEN) { 153 error("CBCP packet is too small (%d < %d)", pktlen, CBCP_MINLEN); 154 return; 155 } 156 157 GETCHAR(code, inp); 158 GETCHAR(id, inp); 159 GETSHORT(len, inp); 160 161 if (len > pktlen) { 162 error("CBCP packet: invalid length (%d > %d)", len, pktlen); 163 return; 164 } 165 166 len -= CBCP_MINLEN; 167 168 switch (code) { 169 case CBCP_REQ: 170 us->us_id = id; 171 cbcp_recvreq(us, inp, len); 172 break; 173 174 case CBCP_RESP: 175 if (debug) 176 dbglog("CBCP Response received; no request sent"); 177 break; 178 179 case CBCP_ACK: 180 if (id != us->us_id) { 181 if (debug) 182 dbglog("CBCP Ack ID %d doesn't match expected %d", id, 183 us->us_id); 184 break; 185 } 186 187 cbcp_recvack(us, inp, len); 188 break; 189 190 default: 191 if (debug) 192 dbglog("Unknown CBCP code number %d", code); 193 break; 194 } 195 } 196 197 /* protocol was rejected by foe */ 198 /*ARGSUSED*/ 199 static void 200 cbcp_protrej(int unit) 201 { 202 start_networks(); 203 } 204 205 static char *cbcp_codenames[] = { 206 "Request", "Response", "Ack" 207 }; 208 209 static char *cbcp_optionnames[] = { 210 "NoCallback", 211 "UserDefined", 212 "AdminDefined", 213 "List" 214 }; 215 216 /* 217 * Pretty print a packet. Return value is number of bytes parsed out 218 * of the packet and printed in some way. Caller (in util.c) will 219 * print the remainder of the packet. 220 */ 221 static int 222 cbcp_printpkt(p, plen, printer, arg) 223 u_char *p; 224 int plen; 225 void (*printer) __P((void *, const char *, ...)); 226 void *arg; 227 { 228 int code, id, len, olen, alen; 229 u_char *pstart, cichar; 230 231 if (plen < HEADERLEN) { 232 printer(arg, "too short (%d<%d)", plen, HEADERLEN); 233 return (0); 234 } 235 pstart = p; 236 GETCHAR(code, p); 237 GETCHAR(id, p); 238 GETSHORT(len, p); 239 240 if (code >= 1 && code <= Dim(cbcp_codenames)) 241 printer(arg, " %s", cbcp_codenames[code-1]); 242 else 243 printer(arg, " code=0x%x", code); 244 245 printer(arg, " id=0x%x", id); 246 247 if (len < HEADERLEN) { 248 printer(arg, " header length %d<%d", len, HEADERLEN); 249 return (HEADERLEN); 250 } 251 if (len > plen) { 252 printer(arg, " truncated (%d>%d)", len, plen); 253 len = plen; 254 } 255 len -= HEADERLEN; 256 257 switch (code) { 258 case CBCP_REQ: 259 case CBCP_RESP: 260 case CBCP_ACK: 261 while (len >= 2) { 262 GETCHAR(cichar, p); 263 GETCHAR(olen, p); 264 265 if (olen < 2) 266 break; 267 268 printer(arg, " <"); 269 270 if (olen > len) { 271 printer(arg, "trunc[%d>%d] ", olen, len); 272 olen = len; 273 } 274 len -= olen; 275 olen -= 2; 276 277 if (cichar >= 1 && cichar <= Dim(cbcp_optionnames)) 278 printer(arg, " %s", cbcp_optionnames[cichar-1]); 279 else 280 printer(arg, " option=0x%x", cichar); 281 282 if (olen > 0) { 283 GETCHAR(cichar, p); 284 olen--; 285 printer(arg, " delay=%d", cichar); 286 } 287 288 while (olen > 0) { 289 GETCHAR(cichar, p); 290 olen--; 291 if (cichar != 1) 292 printer(arg, " (type %d?)", cichar); 293 alen = strllen((const char *)p, olen); 294 if (olen > 0 && alen > 0) 295 printer(arg, " '%.*s'", alen, p); 296 else 297 printer(arg, " null"); 298 p += alen + 1; 299 olen -= alen + 1; 300 } 301 printer(arg, ">"); 302 } 303 304 default: 305 break; 306 } 307 308 if (len > 0) { 309 if (len > 8) 310 printer(arg, "%8B ...", p); 311 else 312 printer(arg, "%.*B", len, p); 313 } 314 p += len; 315 316 return p - pstart; 317 } 318 319 /* 320 * received CBCP request. 321 * No reason to print packet contents in detail here, since enabling 322 * debug mode will cause the print routine above to be invoked. 323 */ 324 static void 325 cbcp_recvreq(us, pckt, pcktlen) 326 cbcp_state *us; 327 u_char *pckt; 328 int pcktlen; 329 { 330 u_char type, opt_len; 331 int len = pcktlen; 332 u_char cb_type; 333 u_char buf[256]; 334 u_char *bufp = buf; 335 336 us->us_allowed = 0; 337 while (len > 0) { 338 GETCHAR(type, pckt); 339 GETCHAR(opt_len, pckt); 340 341 if (opt_len > 2) { 342 pckt++; /* ignore the delay time */ 343 } 344 345 len -= opt_len; 346 347 /* 348 * Careful; don't use left-shift operator on numbers that are 349 * too big. 350 */ 351 if (type > CB_CONF_LIST) { 352 if (debug) 353 dbglog("CBCP: ignoring unknown type %d", type); 354 continue; 355 } 356 357 us->us_allowed |= (1 << type); 358 359 switch (type) { 360 case CB_CONF_NO: 361 if (debug) 362 dbglog("CBCP: operation without callback allowed"); 363 break; 364 365 case CB_CONF_USER: 366 if (debug) 367 dbglog("callback to user-specified number allowed"); 368 break; 369 370 case CB_CONF_ADMIN: 371 if (debug) 372 dbglog("CBCP: callback to admin-defined address allowed"); 373 break; 374 375 case CB_CONF_LIST: 376 if (debug) 377 dbglog("CBCP: callback to one out of list allowed"); 378 break; 379 } 380 } 381 382 /* Now generate the response */ 383 len = 0; 384 cb_type = us->us_allowed & us->us_type; 385 386 if (cb_type & ( 1 << CB_CONF_USER ) ) { 387 if (debug) 388 dbglog("CBCP Response: selecting user-specified number"); 389 PUTCHAR(CB_CONF_USER, bufp); 390 len = 3 + 1 + strlen(us->us_number) + 1; 391 PUTCHAR(len , bufp); 392 PUTCHAR(5, bufp); /* delay */ 393 PUTCHAR(1, bufp); 394 BCOPY(us->us_number, bufp, strlen(us->us_number) + 1); 395 cbcp_send(us, CBCP_RESP, buf, len); 396 return; 397 } 398 399 if (cb_type & ( 1 << CB_CONF_ADMIN ) ) { 400 if (debug) 401 dbglog("CBCP Response: selecting admin-specified number"); 402 PUTCHAR(CB_CONF_ADMIN, bufp); 403 len = 3; 404 PUTCHAR(len, bufp); 405 PUTCHAR(5, bufp); /* delay */ 406 cbcp_send(us, CBCP_RESP, buf, len); 407 return; 408 } 409 410 if (cb_type & ( 1 << CB_CONF_NO ) ) { 411 if (debug) 412 dbglog("CBCP Response: selecting no-callback mode"); 413 PUTCHAR(CB_CONF_NO, bufp); 414 len = 3; 415 PUTCHAR(len , bufp); 416 PUTCHAR(0, bufp); 417 cbcp_send(us, CBCP_RESP, buf, len); 418 start_networks(); 419 return; 420 } 421 422 if (debug) 423 dbglog("CBCP: no callback types in common"); 424 lcp_close(us->us_unit, "No CBCP callback options available"); 425 } 426 427 static void 428 cbcp_send(us, code, buf, len) 429 cbcp_state *us; 430 int code; 431 u_char *buf; 432 int len; 433 { 434 u_char *outp; 435 int outlen; 436 437 outp = outpacket_buf; 438 439 outlen = 4 + len; 440 441 MAKEHEADER(outp, PPP_CBCP); 442 443 PUTCHAR(code, outp); 444 PUTCHAR(us->us_id, outp); 445 PUTSHORT(outlen, outp); 446 447 if (len > 0) 448 BCOPY(buf, outp, len); 449 450 output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN); 451 } 452 453 /* 454 * Received CBCP Acknowledgment message. 455 */ 456 static void 457 cbcp_recvack(us, pckt, len) 458 cbcp_state *us; 459 u_char *pckt; 460 int len; 461 { 462 u_char type, addr_type; 463 int opt_len; 464 465 if (len > 0) { 466 GETCHAR(type, pckt); 467 GETCHAR(opt_len, pckt); 468 469 if (type == CB_CONF_NO) { 470 if (debug) 471 dbglog("CBCP: proceeding without callback"); 472 return; 473 } 474 475 /* just ignore the delay time */ 476 pckt++; 477 478 if (opt_len > 4) { 479 GETCHAR(addr_type, pckt); 480 if (addr_type != 1) 481 warn("CBCP: unknown callback address type %d", addr_type); 482 } 483 if (debug && opt_len > 5) 484 dbglog("CBCP: peer will call %.*s", pckt, opt_len - 4); 485 } 486 487 persist = 0; 488 lcp_close(us->us_unit, "Call me back, please"); 489 status = EXIT_CALLBACK; 490 } 491