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