1 /* $OpenBSD: cbcp.c,v 1.8 2010/05/01 08:14:26 mk 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 name(s) 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 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO 25 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 26 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 27 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 28 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 29 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 30 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 31 */ 32 33 #include <stdio.h> 34 #include <string.h> 35 #include <sys/types.h> 36 #include <sys/time.h> 37 #include <syslog.h> 38 39 #include "pppd.h" 40 #include "cbcp.h" 41 #include "fsm.h" 42 #include "lcp.h" 43 #include "ipcp.h" 44 45 /* 46 * Protocol entry points. 47 */ 48 static void cbcp_init(int unit); 49 static void cbcp_open(int unit); 50 static void cbcp_lowerup(int unit); 51 static void cbcp_input(int unit, u_char *pkt, int len); 52 static void cbcp_protrej(int unit); 53 static int cbcp_printpkt(u_char *pkt, int len, 54 void (*printer)(void *, char *, ...), void *arg); 55 56 struct protent cbcp_protent = { 57 PPP_CBCP, 58 cbcp_init, 59 cbcp_input, 60 cbcp_protrej, 61 cbcp_lowerup, 62 NULL, 63 cbcp_open, 64 NULL, 65 cbcp_printpkt, 66 NULL, 67 0, 68 "CBCP", 69 NULL, 70 NULL, 71 NULL 72 }; 73 74 cbcp_state cbcp[NUM_PPP]; 75 76 /* internal prototypes */ 77 78 static void cbcp_recvreq(cbcp_state *us, char *pckt, int len); 79 static void cbcp_resp(cbcp_state *us); 80 static void cbcp_up(cbcp_state *us); 81 static void cbcp_recvack(cbcp_state *us, char *pckt, int len); 82 static void cbcp_send(cbcp_state *us, u_char code, u_char *buf, int len); 83 84 /* init state */ 85 static void 86 cbcp_init(iface) 87 int iface; 88 { 89 cbcp_state *us; 90 91 us = &cbcp[iface]; 92 memset(us, 0, sizeof(cbcp_state)); 93 us->us_unit = iface; 94 us->us_type |= (1 << CB_CONF_NO); 95 } 96 97 /* lower layer is up */ 98 static void 99 cbcp_lowerup(iface) 100 int iface; 101 { 102 cbcp_state *us = &cbcp[iface]; 103 104 syslog(LOG_DEBUG, "cbcp_lowerup"); 105 syslog(LOG_DEBUG, "want: %d", us->us_type); 106 107 if (us->us_type == CB_CONF_USER) 108 syslog(LOG_DEBUG, "phone no: %s", us->us_number); 109 } 110 111 static void 112 cbcp_open(unit) 113 int unit; 114 { 115 syslog(LOG_DEBUG, "cbcp_open"); 116 } 117 118 /* process an incoming packet */ 119 static void 120 cbcp_input(unit, inpacket, pktlen) 121 int unit; 122 u_char *inpacket; 123 int pktlen; 124 { 125 u_char *inp; 126 u_char code, id; 127 u_short len; 128 129 cbcp_state *us = &cbcp[unit]; 130 131 inp = inpacket; 132 133 if (pktlen < CBCP_MINLEN) { 134 syslog(LOG_ERR, "CBCP packet is too small"); 135 return; 136 } 137 138 GETCHAR(code, inp); 139 GETCHAR(id, inp); 140 GETSHORT(len, inp); 141 142 if (len < CBCP_MINLEN || len > pktlen) { 143 syslog(LOG_ERR, "CBCP packet: invalid length"); 144 return; 145 } 146 len -= CBCP_MINLEN; 147 148 switch(code) { 149 case CBCP_REQ: 150 us->us_id = id; 151 cbcp_recvreq(us, inp, len); 152 break; 153 154 case CBCP_RESP: 155 syslog(LOG_DEBUG, "CBCP_RESP received"); 156 break; 157 158 case CBCP_ACK: 159 if (id != us->us_id) 160 syslog(LOG_DEBUG, "id doesn't match: expected %d recv %d", 161 us->us_id, id); 162 163 cbcp_recvack(us, inp, len); 164 break; 165 166 default: 167 break; 168 } 169 } 170 171 /* protocol was rejected by foe */ 172 void cbcp_protrej(int iface) 173 { 174 } 175 176 char *cbcp_codenames[] = { 177 "Request", "Response", "Ack" 178 }; 179 180 char *cbcp_optionnames[] = { 181 "NoCallback", 182 "UserDefined", 183 "AdminDefined", 184 "List" 185 }; 186 187 /* pretty print a packet */ 188 static int 189 cbcp_printpkt(p, plen, printer, arg) 190 u_char *p; 191 int plen; 192 void (*printer)(void *, char *, ...); 193 void *arg; 194 { 195 int code, opt, id, len, olen, delay; 196 u_char *pstart; 197 198 if (plen < HEADERLEN) 199 return 0; 200 pstart = p; 201 GETCHAR(code, p); 202 GETCHAR(id, p); 203 GETSHORT(len, p); 204 if (len < HEADERLEN || len > plen) 205 return 0; 206 207 if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *)) 208 printer(arg, " %s", cbcp_codenames[code-1]); 209 else 210 printer(arg, " code=0x%x", code); 211 212 printer(arg, " id=0x%x", id); 213 len -= HEADERLEN; 214 215 switch (code) { 216 case CBCP_REQ: 217 case CBCP_RESP: 218 case CBCP_ACK: 219 while(len >= 2) { 220 GETCHAR(opt, p); 221 GETCHAR(olen, p); 222 223 if (olen < 2 || olen > len) { 224 break; 225 } 226 227 printer(arg, " <"); 228 len -= olen; 229 230 if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *)) 231 printer(arg, " %s", cbcp_optionnames[opt-1]); 232 else 233 printer(arg, " option=0x%x", opt); 234 235 if (olen > 2) { 236 GETCHAR(delay, p); 237 printer(arg, " delay = %d", delay); 238 } 239 240 if (olen > 3) { 241 int addrt; 242 char str[256]; 243 244 GETCHAR(addrt, p); 245 memcpy(str, p, olen - 4); 246 str[olen - 4] = 0; 247 printer(arg, " number = %s", str); 248 } 249 printer(arg, ">"); 250 break; 251 } 252 253 default: 254 break; 255 } 256 257 for (; len > 0; --len) { 258 GETCHAR(code, p); 259 printer(arg, " %.2x", code); 260 } 261 262 return p - pstart; 263 } 264 265 /* received CBCP request */ 266 static void 267 cbcp_recvreq(us, pckt, pcktlen) 268 cbcp_state *us; 269 char *pckt; 270 int pcktlen; 271 { 272 u_char type, opt_len, delay, addr_type; 273 char address[256]; 274 int len = pcktlen; 275 276 address[0] = 0; 277 278 while (len > 1) { 279 syslog(LOG_DEBUG, "length: %d", len); 280 281 GETCHAR(type, pckt); 282 GETCHAR(opt_len, pckt); 283 284 if (len < opt_len) 285 break; 286 len -= opt_len; 287 288 if (opt_len > 2) 289 GETCHAR(delay, pckt); 290 291 us->us_allowed |= (1 << type); 292 293 switch(type) { 294 case CB_CONF_NO: 295 syslog(LOG_DEBUG, "no callback allowed"); 296 break; 297 298 case CB_CONF_USER: 299 syslog(LOG_DEBUG, "user callback allowed"); 300 if (opt_len > 4) { 301 GETCHAR(addr_type, pckt); 302 memcpy(address, pckt, opt_len - 4); 303 address[opt_len - 4] = 0; 304 if (address[0]) 305 syslog(LOG_DEBUG, "address: %s", address); 306 } 307 break; 308 309 case CB_CONF_ADMIN: 310 syslog(LOG_DEBUG, "user admin defined allowed"); 311 break; 312 313 case CB_CONF_LIST: 314 break; 315 } 316 } 317 318 cbcp_resp(us); 319 } 320 321 static void 322 cbcp_resp(us) 323 cbcp_state *us; 324 { 325 u_char cb_type; 326 u_char buf[256]; 327 u_char *bufp = buf; 328 int len = 0; 329 330 cb_type = us->us_allowed & us->us_type; 331 syslog(LOG_DEBUG, "cbcp_resp cb_type=%d", cb_type); 332 333 #if 0 334 if (!cb_type) 335 lcp_down(us->us_unit); 336 #endif 337 338 if (cb_type & ( 1 << CB_CONF_USER ) ) { 339 syslog(LOG_DEBUG, "cbcp_resp CONF_USER"); 340 PUTCHAR(CB_CONF_USER, bufp); 341 len = 3 + 1 + strlen(us->us_number) + 1; 342 PUTCHAR(len , bufp); 343 PUTCHAR(5, bufp); /* delay */ 344 PUTCHAR(1, bufp); 345 BCOPY(us->us_number, bufp, strlen(us->us_number) + 1); 346 cbcp_send(us, CBCP_RESP, buf, len); 347 return; 348 } 349 350 if (cb_type & ( 1 << CB_CONF_ADMIN ) ) { 351 syslog(LOG_DEBUG, "cbcp_resp CONF_ADMIN"); 352 PUTCHAR(CB_CONF_ADMIN, bufp); 353 len = 3 + 1; 354 PUTCHAR(len , bufp); 355 PUTCHAR(5, bufp); /* delay */ 356 PUTCHAR(0, bufp); 357 cbcp_send(us, CBCP_RESP, buf, len); 358 return; 359 } 360 361 if (cb_type & ( 1 << CB_CONF_NO ) ) { 362 syslog(LOG_DEBUG, "cbcp_resp CONF_NO"); 363 PUTCHAR(CB_CONF_NO, bufp); 364 len = 3; 365 PUTCHAR(len , bufp); 366 PUTCHAR(0, bufp); 367 cbcp_send(us, CBCP_RESP, buf, len); 368 (*ipcp_protent.open)(us->us_unit); 369 return; 370 } 371 } 372 373 static void 374 cbcp_send(us, code, buf, len) 375 cbcp_state *us; 376 u_char code; 377 u_char *buf; 378 int len; 379 { 380 u_char *outp; 381 int outlen; 382 383 outp = outpacket_buf; 384 385 outlen = 4 + len; 386 387 MAKEHEADER(outp, PPP_CBCP); 388 389 PUTCHAR(code, outp); 390 PUTCHAR(us->us_id, outp); 391 PUTSHORT(outlen, outp); 392 393 if (len) 394 BCOPY(buf, outp, len); 395 396 output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN); 397 } 398 399 static void 400 cbcp_recvack(us, pckt, len) 401 cbcp_state *us; 402 char *pckt; 403 int len; 404 { 405 u_char type, delay, addr_type; 406 int opt_len; 407 char address[256]; 408 409 if (len > 1) { 410 GETCHAR(type, pckt); 411 GETCHAR(opt_len, pckt); 412 413 if (opt_len > len) 414 return; 415 416 if (opt_len > 2) 417 GETCHAR(delay, pckt); 418 419 if (opt_len > 4) { 420 GETCHAR(addr_type, pckt); 421 memcpy(address, pckt, opt_len - 4); 422 address[opt_len - 4] = 0; 423 if (address[0]) 424 syslog(LOG_DEBUG, "peer will call: %s", address); 425 } 426 } 427 428 cbcp_up(us); 429 } 430 431 extern int persist; 432 433 /* ok peer will do callback */ 434 static void 435 cbcp_up(us) 436 cbcp_state *us; 437 { 438 persist = 0; 439 lcp_close(0, "Call me back, please"); 440 } 441