1/* 2 * cbcp - Call Back Configuration Protocol. 3 * 4 * Copyright (c) 1995 Pedro Roque Marques 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms are permitted 8 * provided that the above copyright notice and this paragraph are 9 * duplicated in all such forms and that any documentation, 10 * advertising materials, and other materials related to such 11 * distribution and use acknowledge that the software was developed 12 * by Pedro Roque Marques. The name of the author may not be used to 13 * endorse or promote products derived from this software without 14 * specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 */ 20 21#define RCSID "$Id: cbcp.c 241182 2011-02-17 21:50:03Z $" 22 23#include <stdio.h> 24#include <string.h> 25#include <sys/types.h> 26#include <sys/time.h> 27 28#include "pppd.h" 29#include "cbcp.h" 30#include "fsm.h" 31#include "lcp.h" 32 33static const char rcsid[] = RCSID; 34 35/* 36 * Options. 37 */ 38static int setcbcp __P((char **)); 39 40static option_t cbcp_option_list[] = { 41 { "callback", o_special, setcbcp, 42 "Ask for callback", OPT_PRIO | OPT_A2STRVAL, &cbcp[0].us_number }, 43 { NULL } 44}; 45 46/* 47 * Protocol entry points. 48 */ 49static void cbcp_init __P((int unit)); 50static void cbcp_open __P((int unit)); 51static void cbcp_lowerup __P((int unit)); 52static void cbcp_input __P((int unit, u_char *pkt, int len)); 53static void cbcp_protrej __P((int unit)); 54static int cbcp_printpkt __P((u_char *pkt, int len, 55 void (*printer) __P((void *, char *, ...)), 56 void *arg)); 57 58struct protent cbcp_protent = { 59 PPP_CBCP, 60 cbcp_init, 61 cbcp_input, 62 cbcp_protrej, 63 cbcp_lowerup, 64 NULL, 65 cbcp_open, 66 NULL, 67 cbcp_printpkt, 68 NULL, 69 0, 70 "CBCP", 71 NULL, 72 cbcp_option_list, 73 NULL, 74 NULL, 75 NULL 76}; 77 78cbcp_state cbcp[NUM_PPP]; 79 80/* internal prototypes */ 81 82static void cbcp_recvreq __P((cbcp_state *us, char *pckt, int len)); 83static void cbcp_resp __P((cbcp_state *us)); 84static void cbcp_up __P((cbcp_state *us)); 85static void cbcp_recvack __P((cbcp_state *us, char *pckt, int len)); 86static void cbcp_send __P((cbcp_state *us, u_char code, u_char *buf, int len)); 87 88/* option processing */ 89static int 90setcbcp(argv) 91 char **argv; 92{ 93 lcp_wantoptions[0].neg_cbcp = 1; 94 cbcp_protent.enabled_flag = 1; 95 cbcp[0].us_number = strdup(*argv); 96 if (cbcp[0].us_number == 0) 97 novm("callback number"); 98 cbcp[0].us_type |= (1 << CB_CONF_USER); 99 cbcp[0].us_type |= (1 << CB_CONF_ADMIN); 100 return (1); 101} 102 103/* init state */ 104static void 105cbcp_init(iface) 106 int iface; 107{ 108 cbcp_state *us; 109 110 us = &cbcp[iface]; 111 memset(us, 0, sizeof(cbcp_state)); 112 us->us_unit = iface; 113 us->us_type |= (1 << CB_CONF_NO); 114} 115 116/* lower layer is up */ 117static void 118cbcp_lowerup(iface) 119 int iface; 120{ 121 cbcp_state *us = &cbcp[iface]; 122 123 dbglog("cbcp_lowerup"); 124 dbglog("want: %d", us->us_type); 125 126 if (us->us_type == CB_CONF_USER) 127 dbglog("phone no: %s", us->us_number); 128} 129 130static void 131cbcp_open(unit) 132 int unit; 133{ 134 dbglog("cbcp_open"); 135} 136 137/* process an incomming packet */ 138static void 139cbcp_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"); 154 return; 155 } 156 157 GETCHAR(code, inp); 158 GETCHAR(id, inp); 159 GETSHORT(len, inp); 160 161 162 len -= CBCP_MINLEN; 163 164 switch(code) { 165 case CBCP_REQ: 166 us->us_id = id; 167 cbcp_recvreq(us, inp, len); 168 break; 169 170 case CBCP_RESP: 171 dbglog("CBCP_RESP received"); 172 break; 173 174 case CBCP_ACK: 175 if (id != us->us_id) 176 dbglog("id doesn't match: expected %d recv %d", 177 us->us_id, id); 178 179 cbcp_recvack(us, inp, len); 180 break; 181 182 default: 183 break; 184 } 185} 186 187/* protocol was rejected by foe */ 188void cbcp_protrej(int iface) 189{ 190} 191 192char *cbcp_codenames[] = { 193 "Request", "Response", "Ack" 194}; 195 196char *cbcp_optionnames[] = { 197 "NoCallback", 198 "UserDefined", 199 "AdminDefined", 200 "List" 201}; 202 203/* pretty print a packet */ 204static int 205cbcp_printpkt(p, plen, printer, arg) 206 u_char *p; 207 int plen; 208 void (*printer) __P((void *, char *, ...)); 209 void *arg; 210{ 211 int code, opt, id, len, olen, delay; 212 u_char *pstart; 213 214 if (plen < HEADERLEN) 215 return 0; 216 pstart = p; 217 GETCHAR(code, p); 218 GETCHAR(id, p); 219 GETSHORT(len, p); 220 if (len < HEADERLEN || len > plen) 221 return 0; 222 223 if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *)) 224 printer(arg, " %s", cbcp_codenames[code-1]); 225 else 226 printer(arg, " code=0x%x", code); 227 228 printer(arg, " id=0x%x", id); 229 len -= HEADERLEN; 230 231 switch (code) { 232 case CBCP_REQ: 233 case CBCP_RESP: 234 case CBCP_ACK: 235 while(len >= 2) { 236 GETCHAR(opt, p); 237 GETCHAR(olen, p); 238 239 if (olen < 2 || olen > len) { 240 break; 241 } 242 243 printer(arg, " <"); 244 len -= olen; 245 246 if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *)) 247 printer(arg, " %s", cbcp_optionnames[opt-1]); 248 else 249 printer(arg, " option=0x%x", opt); 250 251 if (olen > 2) { 252 GETCHAR(delay, p); 253 printer(arg, " delay = %d", delay); 254 } 255 256 if (olen > 3) { 257 int addrt; 258 char str[256]; 259 260 GETCHAR(addrt, p); 261 memcpy(str, p, olen - 4); 262 str[olen - 4] = 0; 263 printer(arg, " number = %s", str); 264 } 265 printer(arg, ">"); 266 break; 267 } 268 269 default: 270 break; 271 } 272 273 for (; len > 0; --len) { 274 GETCHAR(code, p); 275 printer(arg, " %.2x", code); 276 } 277 278 return p - pstart; 279} 280 281/* received CBCP request */ 282static void 283cbcp_recvreq(us, pckt, pcktlen) 284 cbcp_state *us; 285 char *pckt; 286 int pcktlen; 287{ 288 u_char type, opt_len, delay, addr_type; 289 char address[256]; 290 int len = pcktlen; 291 292 address[0] = 0; 293 294 while (len) { 295 dbglog("length: %d", len); 296 297 GETCHAR(type, pckt); 298 GETCHAR(opt_len, pckt); 299 300 if (opt_len > 2) 301 GETCHAR(delay, pckt); 302 303 us->us_allowed |= (1 << type); 304 305 switch(type) { 306 case CB_CONF_NO: 307 dbglog("no callback allowed"); 308 break; 309 310 case CB_CONF_USER: 311 dbglog("user callback allowed"); 312 if (opt_len > 4) { 313 GETCHAR(addr_type, pckt); 314 memcpy(address, pckt, opt_len - 4); 315 address[opt_len - 4] = 0; 316 if (address[0]) 317 dbglog("address: %s", address); 318 } 319 break; 320 321 case CB_CONF_ADMIN: 322 dbglog("user admin defined allowed"); 323 break; 324 325 case CB_CONF_LIST: 326 break; 327 } 328 len -= opt_len; 329 } 330 331 cbcp_resp(us); 332} 333 334static void 335cbcp_resp(us) 336 cbcp_state *us; 337{ 338 u_char cb_type; 339 u_char buf[256]; 340 u_char *bufp = buf; 341 int len = 0; 342 343 cb_type = us->us_allowed & us->us_type; 344 dbglog("cbcp_resp cb_type=%d", cb_type); 345 346 347 if (cb_type & ( 1 << CB_CONF_USER ) ) { 348 dbglog("cbcp_resp CONF_USER"); 349 PUTCHAR(CB_CONF_USER, bufp); 350 len = 3 + 1 + strlen(us->us_number) + 1; 351 PUTCHAR(len , bufp); 352 PUTCHAR(5, bufp); /* delay */ 353 PUTCHAR(1, bufp); 354 BCOPY(us->us_number, bufp, strlen(us->us_number) + 1); 355 cbcp_send(us, CBCP_RESP, buf, len); 356 return; 357 } 358 359 if (cb_type & ( 1 << CB_CONF_ADMIN ) ) { 360 dbglog("cbcp_resp CONF_ADMIN"); 361 PUTCHAR(CB_CONF_ADMIN, bufp); 362 len = 3; 363 PUTCHAR(len, bufp); 364 PUTCHAR(5, bufp); /* delay */ 365 cbcp_send(us, CBCP_RESP, buf, len); 366 return; 367 } 368 369 if (cb_type & ( 1 << CB_CONF_NO ) ) { 370 dbglog("cbcp_resp CONF_NO"); 371 PUTCHAR(CB_CONF_NO, bufp); 372 len = 3; 373 PUTCHAR(len , bufp); 374 PUTCHAR(0, bufp); 375 cbcp_send(us, CBCP_RESP, buf, len); 376 start_networks(); 377 return; 378 } 379} 380 381static void 382cbcp_send(us, code, buf, len) 383 cbcp_state *us; 384 u_char code; 385 u_char *buf; 386 int len; 387{ 388 u_char *outp; 389 int outlen; 390 391 outp = outpacket_buf; 392 393 outlen = 4 + len; 394 395 MAKEHEADER(outp, PPP_CBCP); 396 397 PUTCHAR(code, outp); 398 PUTCHAR(us->us_id, outp); 399 PUTSHORT(outlen, outp); 400 401 if (len) 402 BCOPY(buf, outp, len); 403 404 output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN); 405} 406 407static void 408cbcp_recvack(us, pckt, len) 409 cbcp_state *us; 410 char *pckt; 411 int len; 412{ 413 u_char type, delay, addr_type; 414 int opt_len; 415 char address[256]; 416 417 if (len) { 418 GETCHAR(type, pckt); 419 GETCHAR(opt_len, pckt); 420 421 if (opt_len > 2) 422 GETCHAR(delay, pckt); 423 424 if (opt_len > 4) { 425 GETCHAR(addr_type, pckt); 426 memcpy(address, pckt, opt_len - 4); 427 address[opt_len - 4] = 0; 428 if (address[0]) 429 dbglog("peer will call: %s", address); 430 } 431 if (type == CB_CONF_NO) 432 return; 433 } 434 435 cbcp_up(us); 436} 437 438/* ok peer will do callback */ 439static void 440cbcp_up(us) 441 cbcp_state *us; 442{ 443 persist = 0; 444 lcp_close(0, "Call me back, please"); 445 status = EXIT_CALLBACK; 446} 447