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