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