cbcp.c revision 1.2
1/* $NetBSD: cbcp.c,v 1.2 2013/11/28 22:33:42 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#if 0 40#define RCSID "Id: cbcp.c,v 1.17 2006/05/22 00:04:07 paulus Exp " 41static const char rcsid[] = RCSID; 42#else 43__RCSID("$NetBSD: cbcp.c,v 1.2 2013/11/28 22:33:42 christos Exp $"); 44#endif 45 46#include <stdio.h> 47#include <string.h> 48#include <sys/types.h> 49#include <sys/time.h> 50 51#include "pppd.h" 52#include "cbcp.h" 53#include "fsm.h" 54#include "lcp.h" 55 56/* 57 * Options. 58 */ 59static int setcbcp __P((char **)); 60 61static option_t 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 */ 70static void cbcp_init __P((int unit)); 71static void cbcp_open __P((int unit)); 72static void cbcp_lowerup __P((int unit)); 73static void cbcp_input __P((int unit, u_char *pkt, int len)); 74static void cbcp_protrej __P((int unit)); 75static int cbcp_printpkt __P((u_char *pkt, int len, 76 void (*printer) __P((void *, char *, ...)), 77 void *arg)); 78 79struct 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 99cbcp_state cbcp[NUM_PPP]; 100 101/* internal prototypes */ 102 103static void cbcp_recvreq __P((cbcp_state *us, u_char *pckt, int len)); 104static void cbcp_resp __P((cbcp_state *us)); 105static void cbcp_up __P((cbcp_state *us)); 106static void cbcp_recvack __P((cbcp_state *us, u_char *pckt, int len)); 107static void cbcp_send __P((cbcp_state *us, int code, u_char *buf, int len)); 108 109/* option processing */ 110static int 111setcbcp(argv) 112 char **argv; 113{ 114 lcp_wantoptions[0].neg_cbcp = 1; 115 cbcp_protent.enabled_flag = 1; 116 cbcp[0].us_number = strdup(*argv); 117 if (cbcp[0].us_number == 0) 118 novm("callback number"); 119 cbcp[0].us_type |= (1 << CB_CONF_USER); 120 cbcp[0].us_type |= (1 << CB_CONF_ADMIN); 121 return (1); 122} 123 124/* init state */ 125static void 126cbcp_init(iface) 127 int iface; 128{ 129 cbcp_state *us; 130 131 us = &cbcp[iface]; 132 memset(us, 0, sizeof(cbcp_state)); 133 us->us_unit = iface; 134 us->us_type |= (1 << CB_CONF_NO); 135} 136 137/* lower layer is up */ 138static void 139cbcp_lowerup(iface) 140 int iface; 141{ 142 cbcp_state *us = &cbcp[iface]; 143 144 dbglog("cbcp_lowerup"); 145 dbglog("want: %d", us->us_type); 146 147 if (us->us_type == CB_CONF_USER) 148 dbglog("phone no: %s", us->us_number); 149} 150 151static void 152cbcp_open(unit) 153 int unit; 154{ 155 dbglog("cbcp_open"); 156} 157 158/* process an incomming packet */ 159static void 160cbcp_input(unit, inpacket, pktlen) 161 int unit; 162 u_char *inpacket; 163 int pktlen; 164{ 165 u_char *inp; 166 u_char code, id; 167 u_short len; 168 169 cbcp_state *us = &cbcp[unit]; 170 171 inp = inpacket; 172 173 if (pktlen < CBCP_MINLEN) { 174 if (debug) 175 dbglog("CBCP: Packet too short (%d)", pktlen); 176 return; 177 } 178 179 GETCHAR(code, inp); 180 GETCHAR(id, inp); 181 GETSHORT(len, inp); 182 183 if (len > pktlen || len < CBCP_MINLEN) { 184 if (debug) 185 dbglog("CBCP: Invalid packet length (%d/%d)", len, pktlen); 186 return; 187 } 188 189 len -= CBCP_MINLEN; 190 191 switch(code) { 192 case CBCP_REQ: 193 us->us_id = id; 194 cbcp_recvreq(us, inp, len); 195 break; 196 197 case CBCP_RESP: 198 if (debug) 199 dbglog("CBCP_RESP received"); 200 break; 201 202 case CBCP_ACK: 203 if (debug && id != us->us_id) 204 dbglog("id doesn't match: expected %d recv %d", 205 us->us_id, id); 206 207 cbcp_recvack(us, inp, len); 208 break; 209 210 default: 211 break; 212 } 213} 214 215/* protocol was rejected by foe */ 216void cbcp_protrej(int iface) 217{ 218} 219 220char *cbcp_codenames[] = { 221 "Request", "Response", "Ack" 222}; 223 224char *cbcp_optionnames[] = { 225 "NoCallback", 226 "UserDefined", 227 "AdminDefined", 228 "List" 229}; 230 231/* pretty print a packet */ 232static int 233cbcp_printpkt(p, plen, printer, arg) 234 u_char *p; 235 int plen; 236 void (*printer) __P((void *, char *, ...)); 237 void *arg; 238{ 239 int code, opt, id, len, olen, delay; 240 u_char *pstart; 241 242 if (plen < HEADERLEN) 243 return 0; 244 pstart = p; 245 GETCHAR(code, p); 246 GETCHAR(id, p); 247 GETSHORT(len, p); 248 if (len < HEADERLEN || len > plen) 249 return 0; 250 251 if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *)) 252 printer(arg, " %s", cbcp_codenames[code-1]); 253 else 254 printer(arg, " code=0x%x", code); 255 256 printer(arg, " id=0x%x", id); 257 len -= HEADERLEN; 258 259 switch (code) { 260 case CBCP_REQ: 261 case CBCP_RESP: 262 case CBCP_ACK: 263 while(len >= 2) { 264 GETCHAR(opt, p); 265 GETCHAR(olen, p); 266 267 if (olen < 2 || olen > len) { 268 break; 269 } 270 271 printer(arg, " <"); 272 len -= olen; 273 274 if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *)) 275 printer(arg, " %s", cbcp_optionnames[opt-1]); 276 else 277 printer(arg, " option=0x%x", opt); 278 279 if (olen > 2) { 280 GETCHAR(delay, p); 281 printer(arg, " delay = %d", delay); 282 } 283 284 if (olen > 3) { 285 int addrt; 286 char str[256]; 287 288 GETCHAR(addrt, p); 289 __USE(addrt); 290 memcpy(str, p, olen - 4); 291 str[olen - 4] = 0; 292 printer(arg, " number = %s", str); 293 } 294 printer(arg, ">"); 295 } 296 break; 297 298 default: 299 break; 300 } 301 302 for (; len > 0; --len) { 303 GETCHAR(code, p); 304 printer(arg, " %.2x", code); 305 } 306 307 return p - pstart; 308} 309 310/* received CBCP request */ 311static void 312cbcp_recvreq(us, pckt, pcktlen) 313 cbcp_state *us; 314 u_char *pckt; 315 int pcktlen; 316{ 317 u_char type, opt_len, delay, addr_type; 318 char address[256]; 319 int len = pcktlen; 320 321 address[0] = 0; 322 323 while (len >= 2) { 324 dbglog("length: %d", len); 325 326 GETCHAR(type, pckt); 327 GETCHAR(opt_len, pckt); 328 if (opt_len < 2 || opt_len > len) { 329 if (debug) 330 dbglog("CBCP: Malformed option length (%d/%d)", opt_len, len); 331 break; 332 } 333 334 if (opt_len > 2) { 335 GETCHAR(delay, pckt); 336 __USE(delay); 337 } 338 339 us->us_allowed |= (1 << type); 340 341 switch(type) { 342 case CB_CONF_NO: 343 dbglog("no callback allowed"); 344 break; 345 346 case CB_CONF_USER: 347 dbglog("user callback allowed"); 348 if (opt_len > 4) { 349 GETCHAR(addr_type, pckt); 350 __USE(addr_type); 351 memcpy(address, pckt, opt_len - 4); 352 address[opt_len - 4] = 0; 353 if (address[0]) 354 dbglog("address: %s", address); 355 } 356 break; 357 358 case CB_CONF_ADMIN: 359 dbglog("user admin defined allowed"); 360 break; 361 362 case CB_CONF_LIST: 363 break; 364 } 365 len -= opt_len; 366 } 367 if (len != 0) { 368 if (debug) 369 dbglog("cbcp_recvreq: malformed packet (%d bytes left)", len); 370 return; 371 } 372 373 cbcp_resp(us); 374} 375 376static void 377cbcp_resp(us) 378 cbcp_state *us; 379{ 380 u_char cb_type; 381 u_char buf[256]; 382 u_char *bufp = buf; 383 int len = 0; 384 int slen; 385 386 cb_type = us->us_allowed & us->us_type; 387 dbglog("cbcp_resp cb_type=%d", cb_type); 388 389#if 0 390 if (!cb_type) 391 lcp_down(us->us_unit); 392#endif 393 394 if (cb_type & ( 1 << CB_CONF_USER ) ) { 395 dbglog("cbcp_resp CONF_USER"); 396 slen = strlen(us->us_number); 397 if (slen > 250) { 398 warn("callback number truncated to 250 characters"); 399 slen = 250; 400 } 401 PUTCHAR(CB_CONF_USER, bufp); 402 len = 3 + 1 + slen + 1; 403 PUTCHAR(len , bufp); 404 PUTCHAR(5, bufp); /* delay */ 405 PUTCHAR(1, bufp); 406 BCOPY(us->us_number, bufp, slen + 1); 407 cbcp_send(us, CBCP_RESP, buf, len); 408 return; 409 } 410 411 if (cb_type & ( 1 << CB_CONF_ADMIN ) ) { 412 dbglog("cbcp_resp CONF_ADMIN"); 413 PUTCHAR(CB_CONF_ADMIN, bufp); 414 len = 3; 415 PUTCHAR(len, bufp); 416 PUTCHAR(5, bufp); /* delay */ 417 cbcp_send(us, CBCP_RESP, buf, len); 418 return; 419 } 420 421 if (cb_type & ( 1 << CB_CONF_NO ) ) { 422 dbglog("cbcp_resp CONF_NO"); 423 PUTCHAR(CB_CONF_NO, bufp); 424 len = 2; 425 PUTCHAR(len , bufp); 426 cbcp_send(us, CBCP_RESP, buf, len); 427 start_networks(us->us_unit); 428 return; 429 } 430} 431 432static void 433cbcp_send(us, code, buf, len) 434 cbcp_state *us; 435 int code; 436 u_char *buf; 437 int len; 438{ 439 u_char *outp; 440 int outlen; 441 442 outp = outpacket_buf; 443 444 outlen = 4 + len; 445 446 MAKEHEADER(outp, PPP_CBCP); 447 448 PUTCHAR(code, outp); 449 PUTCHAR(us->us_id, outp); 450 PUTSHORT(outlen, outp); 451 452 if (len) 453 BCOPY(buf, outp, len); 454 455 output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN); 456} 457 458static void 459cbcp_recvack(us, pckt, len) 460 cbcp_state *us; 461 u_char *pckt; 462 int len; 463{ 464 u_char type, delay, addr_type; 465 int opt_len; 466 char address[256]; 467 468 if (len >= 2) { 469 GETCHAR(type, pckt); 470 GETCHAR(opt_len, pckt); 471 if (opt_len >= 2 && opt_len <= len) { 472 473 if (opt_len > 2) { 474 GETCHAR(delay, pckt); 475 __USE(delay); 476 } 477 478 if (opt_len > 4) { 479 GETCHAR(addr_type, pckt); 480 __USE(addr_type); 481 memcpy(address, pckt, opt_len - 4); 482 address[opt_len - 4] = 0; 483 if (address[0]) 484 dbglog("peer will call: %s", address); 485 } 486 if (type == CB_CONF_NO) 487 return; 488 489 cbcp_up(us); 490 491 } else if (debug) 492 dbglog("cbcp_recvack: malformed packet"); 493 } 494} 495 496/* ok peer will do callback */ 497static void 498cbcp_up(us) 499 cbcp_state *us; 500{ 501 persist = 0; 502 status = EXIT_CALLBACK; 503 lcp_close(0, "Call me back, please"); 504} 505