1 /*- 2 * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $Id: cbcp.c,v 1.1 1998/08/07 18:44:16 brian Exp $ 27 */ 28 29 #include <sys/types.h> 30 31 #include <sys/un.h> 32 33 #include <string.h> 34 #include <termios.h> 35 36 #include "defs.h" 37 #include "log.h" 38 #include "timer.h" 39 #include "descriptor.h" 40 #include "lqr.h" 41 #include "mbuf.h" 42 #include "fsm.h" 43 #include "lcp.h" 44 #include "throughput.h" 45 #include "hdlc.h" 46 #include "ccp.h" 47 #include "link.h" 48 #include "async.h" 49 #include "physical.h" 50 #include "lcpproto.h" 51 #include "cbcp.h" 52 #include "mp.h" 53 #include "chat.h" 54 #include "auth.h" 55 #include "chap.h" 56 #include "datalink.h" 57 58 void 59 cbcp_Init(struct cbcp *cbcp, struct physical *p) 60 { 61 cbcp->required = 0; 62 cbcp->fsm.state = CBCP_CLOSED; 63 cbcp->fsm.id = 0; 64 cbcp->fsm.delay = 0; 65 *cbcp->fsm.phone = '\0'; 66 memset(&cbcp->fsm.timer, '\0', sizeof cbcp->fsm.timer); 67 cbcp->p = p; 68 } 69 70 static void cbcp_SendReq(struct cbcp *); 71 static void cbcp_SendResponse(struct cbcp *); 72 static void cbcp_SendAck(struct cbcp *); 73 74 static void 75 cbcp_Timeout(void *v) 76 { 77 struct cbcp *cbcp = (struct cbcp *)v; 78 79 timer_Stop(&cbcp->fsm.timer); 80 if (cbcp->fsm.restart) { 81 switch (cbcp->fsm.state) { 82 case CBCP_CLOSED: 83 case CBCP_STOPPED: 84 log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n", 85 cbcp->p->dl->name); 86 break; 87 88 case CBCP_REQSENT: 89 cbcp_SendReq(cbcp); 90 break; 91 case CBCP_RESPSENT: 92 cbcp_SendResponse(cbcp); 93 break; 94 case CBCP_ACKSENT: 95 cbcp_SendAck(cbcp); 96 break; 97 } 98 } else { 99 const char *missed; 100 101 switch (cbcp->fsm.state) { 102 case CBCP_STOPPED: 103 missed = "REQ"; 104 break; 105 case CBCP_REQSENT: 106 missed = "RESPONSE"; 107 break; 108 case CBCP_RESPSENT: 109 missed = "ACK"; 110 break; 111 case CBCP_ACKSENT: 112 missed = "Terminate REQ"; 113 break; 114 default: 115 log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n", 116 cbcp->p->dl->name); 117 missed = NULL; 118 break; 119 } 120 if (missed) 121 log_Printf(LogCBCP, "%s: Timeout waiting for peer %s\n", 122 cbcp->p->dl->name, missed); 123 datalink_CBCPFailed(cbcp->p->dl); 124 } 125 } 126 127 static void 128 cbcp_StartTimer(struct cbcp *cbcp, int timeout) 129 { 130 timer_Stop(&cbcp->fsm.timer); 131 cbcp->fsm.timer.func = cbcp_Timeout; 132 cbcp->fsm.timer.name = "cbcp"; 133 cbcp->fsm.timer.load = timeout * SECTICKS; 134 cbcp->fsm.timer.arg = cbcp; 135 timer_Start(&cbcp->fsm.timer); 136 } 137 138 #define CBCP_CLOSED (0) /* Not in use */ 139 #define CBCP_STOPPED (1) /* Waiting for a REQ */ 140 #define CBCP_REQSENT (2) /* Waiting for a RESP */ 141 #define CBCP_RESPSENT (3) /* Waiting for an ACK */ 142 #define CBCP_ACKSENT (4) /* Waiting for an LCP Term REQ */ 143 144 static const char *cbcpname[] = { 145 "closed", "stopped", "req-sent", "resp-sent", "ack-sent" 146 }; 147 148 static const char * 149 cbcpstate(int s) 150 { 151 if (s < sizeof cbcpname / sizeof cbcpname[0]) 152 return cbcpname[s]; 153 return "???"; 154 } 155 156 static void 157 cbcp_NewPhase(struct cbcp *cbcp, int new) 158 { 159 if (cbcp->fsm.state != new) { 160 log_Printf(LogCBCP, "%s: State change %s --> %s\n", cbcp->p->dl->name, 161 cbcpstate(cbcp->fsm.state), cbcpstate(new)); 162 cbcp->fsm.state = new; 163 } 164 } 165 166 struct cbcp_header { 167 u_char code; 168 u_char id; 169 u_int16_t length; /* Network byte order */ 170 }; 171 172 173 /* cbcp_header::code values */ 174 #define CBCP_REQ (1) 175 #define CBCP_RESPONSE (2) 176 #define CBCP_ACK (3) 177 178 struct cbcp_data { 179 u_char type; 180 u_char length; 181 u_char delay; 182 char addr_start[253]; /* max cbcp_data length 255 + 1 for NULL */ 183 }; 184 185 /* cbcp_data::type values */ 186 #define CBCP_NONUM (1) 187 #define CBCP_CLIENTNUM (2) 188 #define CBCP_SERVERNUM (3) 189 #define CBCP_LISTNUM (4) 190 191 static void 192 cbcp_Output(struct cbcp *cbcp, u_char code, struct cbcp_data *data) 193 { 194 struct cbcp_header *head; 195 struct mbuf *bp; 196 197 bp = mbuf_Alloc(sizeof *head + data->length, MB_CBCP); 198 head = (struct cbcp_header *)MBUF_CTOP(bp); 199 head->code = code; 200 head->id = cbcp->fsm.id; 201 head->length = htons(sizeof *head + data->length); 202 memcpy(MBUF_CTOP(bp) + sizeof *head, data, data->length); 203 log_DumpBp(LogDEBUG, "cbcp_Output", bp); 204 hdlc_Output(&cbcp->p->link, PRI_LINK, PROTO_CBCP, bp); 205 } 206 207 static const char * 208 cbcp_data_Type(int type) 209 { 210 static const char *types[] = { 211 "No callback", "User-spec", "Server-spec", "list" 212 }; 213 214 if (type < 1 || type > sizeof types / sizeof types[0]) 215 return "???"; 216 return types[type-1]; 217 } 218 219 struct cbcp_addr { 220 u_char type; 221 char addr[1]; /* Really ASCIIZ */ 222 }; 223 224 /* cbcp_data::type values */ 225 #define CBCP_ADDR_PSTN (1) 226 227 static void 228 cbcp_data_Show(struct cbcp_data *data) 229 { 230 struct cbcp_addr *addr; 231 char *end; 232 233 addr = (struct cbcp_addr *)data->addr_start; 234 end = (char *)data + data->length; 235 *end = '\0'; 236 237 log_Printf(LogCBCP, " TYPE %s\n", cbcp_data_Type(data->type)); 238 if ((char *)&data->delay < end) { 239 log_Printf(LogCBCP, " DELAY %d\n", data->delay); 240 while (addr->addr < end) { 241 if (addr->type == CBCP_ADDR_PSTN) 242 log_Printf(LogCBCP, " ADDR %s\n", addr->addr); 243 else 244 log_Printf(LogCBCP, " ADDR type %d ??\n", (int)addr->type); 245 addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1); 246 } 247 } 248 } 249 250 static void 251 cbcp_SendReq(struct cbcp *cbcp) 252 { 253 struct cbcp_data data; 254 struct cbcp_addr *addr; 255 char list[sizeof cbcp->fsm.phone], *next; 256 int len, max; 257 258 /* Only callees send REQs */ 259 260 log_Printf(LogCBCP, "%s: SendReq(%d) state = %s\n", cbcp->p->dl->name, 261 cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); 262 data.type = cbcp->fsm.type; 263 data.delay = 0; 264 strncpy(list, cbcp->fsm.phone, sizeof list - 1); 265 list[sizeof list - 1] = '\0'; 266 267 switch (data.type) { 268 case CBCP_CLIENTNUM: 269 addr = (struct cbcp_addr *)data.addr_start; 270 addr->type = CBCP_ADDR_PSTN; 271 *addr->addr = '\0'; 272 data.length = addr->addr - (char *)&data; 273 break; 274 275 case CBCP_LISTNUM: 276 addr = (struct cbcp_addr *)data.addr_start; 277 for (next = strtok(list, ","); next; next = strtok(NULL, ",")) { 278 len = strlen(next); 279 max = data.addr_start + sizeof data.addr_start - addr->addr - 1; 280 if (len <= max) { 281 addr->type = CBCP_ADDR_PSTN; 282 strcpy(addr->addr, next); 283 addr = (struct cbcp_addr *)((char *)addr + len + 2); 284 } else 285 log_Printf(LogWARN, "CBCP ADDR \"%s\" skipped - packet too large\n", 286 next); 287 } 288 data.length = (char *)addr - (char *)&data; 289 break; 290 291 case CBCP_SERVERNUM: 292 data.length = data.addr_start - (char *)&data; 293 break; 294 295 default: 296 data.length = 2; 297 break; 298 } 299 300 cbcp_data_Show(&data); 301 cbcp_Output(cbcp, CBCP_REQ, &data); 302 cbcp->fsm.restart--; 303 cbcp_StartTimer(cbcp, cbcp->fsm.delay); 304 cbcp_NewPhase(cbcp, CBCP_REQSENT); /* Wait for a RESPONSE */ 305 } 306 307 void 308 cbcp_Up(struct cbcp *cbcp) 309 { 310 struct lcp *lcp = &cbcp->p->link.lcp; 311 312 cbcp->fsm.delay = cbcp->p->dl->cfg.cbcp.delay; 313 if (*cbcp->p->dl->peer.authname == '\0' || 314 !auth_SetPhoneList(cbcp->p->dl->peer.authname, cbcp->fsm.phone, 315 sizeof cbcp->fsm.phone)) { 316 strncpy(cbcp->fsm.phone, cbcp->p->dl->cfg.cbcp.phone, 317 sizeof cbcp->fsm.phone - 1); 318 cbcp->fsm.phone[sizeof cbcp->fsm.phone - 1] = '\0'; 319 } 320 321 if (lcp->want_callback.opmask) { 322 if (*cbcp->fsm.phone == '\0') 323 cbcp->fsm.type = CBCP_NONUM; 324 else if (!strcmp(cbcp->fsm.phone, "*")) { 325 cbcp->fsm.type = CBCP_SERVERNUM; 326 *cbcp->fsm.phone = '\0'; 327 } else 328 cbcp->fsm.type = CBCP_CLIENTNUM; 329 cbcp_NewPhase(cbcp, CBCP_STOPPED); /* Wait for a REQ */ 330 cbcp_StartTimer(cbcp, cbcp->fsm.delay * DEF_REQs); 331 } else { 332 if (*cbcp->fsm.phone == '\0') 333 cbcp->fsm.type = CBCP_NONUM; 334 else if (!strcmp(cbcp->fsm.phone, "*")) { 335 cbcp->fsm.type = CBCP_CLIENTNUM; 336 *cbcp->fsm.phone = '\0'; 337 } else if (strchr(cbcp->fsm.phone, ',')) 338 cbcp->fsm.type = CBCP_LISTNUM; 339 else 340 cbcp->fsm.type = CBCP_SERVERNUM; 341 cbcp->fsm.restart = DEF_REQs; 342 cbcp_SendReq(cbcp); 343 } 344 } 345 346 static int 347 cbcp_AdjustResponse(struct cbcp *cbcp, struct cbcp_data *data) 348 { 349 /* 350 * We've received a REQ (data). Adjust our reponse (cbcp->fsm.*) 351 * so that we (hopefully) agree with the peer 352 */ 353 struct cbcp_addr *addr; 354 355 switch (data->type) { 356 case CBCP_NONUM: 357 if (cbcp->fsm.type == CBCP_NONUM) 358 return 1; 359 log_Printf(LogPHASE, "CBCP: server wants no callback !\n"); 360 return 0; 361 362 case CBCP_CLIENTNUM: 363 if (cbcp->fsm.type == CBCP_CLIENTNUM) { 364 char *ptr; 365 366 if (data->length > data->addr_start - (char *)data) { 367 /* 368 * The peer has given us an address type spec - make sure we 369 * understand ! 370 */ 371 addr = (struct cbcp_addr *)data->addr_start; 372 if (addr->type != CBCP_ADDR_PSTN) { 373 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 374 (int)addr->type); 375 return 0; 376 } 377 } 378 /* we accept the REQ even if the peer didn't specify an addr->type */ 379 ptr = strchr(cbcp->fsm.phone, ','); 380 if (ptr) 381 *ptr = '\0'; /* Just use the first number in our list */ 382 return 1; 383 } 384 log_Printf(LogPHASE, "CBCP: no number to pass to the peer !\n"); 385 return 0; 386 387 case CBCP_SERVERNUM: 388 if (cbcp->fsm.type == CBCP_SERVERNUM) { 389 *cbcp->fsm.phone = '\0'; 390 return 1; 391 } 392 if (data->length > data->addr_start - (char *)data) { 393 /* 394 * This violates the spec, but if the peer has told us the 395 * number it wants to call back, take advantage of this fact 396 * and allow things to proceed if we've specified the same 397 * number 398 */ 399 addr = (struct cbcp_addr *)data->addr_start; 400 if (addr->type != CBCP_ADDR_PSTN) { 401 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 402 (int)addr->type); 403 return 0; 404 } else if (cbcp->fsm.type == CBCP_CLIENTNUM) { 405 /* 406 * If the peer's insisting on deciding the number, make sure 407 * it's one of the ones in our list. If it is, let the peer 408 * think it's in control :-) 409 */ 410 char list[sizeof cbcp->fsm.phone], *next; 411 412 strncpy(list, cbcp->fsm.phone, sizeof list - 1); 413 list[sizeof list - 1] = '\0'; 414 for (next = strtok(list, ","); next; next = strtok(NULL, ",")) 415 if (!strcmp(next, addr->addr)) { 416 cbcp->fsm.type = CBCP_SERVERNUM; 417 strcpy(cbcp->fsm.phone, next); 418 return 1; 419 } 420 } 421 } 422 log_Printf(LogPHASE, "CBCP: Peer won't allow local decision !\n"); 423 return 0; 424 425 case CBCP_LISTNUM: 426 if (cbcp->fsm.type == CBCP_CLIENTNUM || cbcp->fsm.type == CBCP_LISTNUM) { 427 /* 428 * Search through ``data''s addresses and see if cbcp->fsm.phone 429 * contains any of them 430 */ 431 char list[sizeof cbcp->fsm.phone], *next, *end; 432 433 addr = (struct cbcp_addr *)data->addr_start; 434 end = (char *)data + data->length; 435 436 while (addr->addr < end) { 437 if (addr->type == CBCP_ADDR_PSTN) { 438 strncpy(list, cbcp->fsm.phone, sizeof list - 1); 439 list[sizeof list - 1] = '\0'; 440 for (next = strtok(list, ","); next; next = strtok(NULL, ",")) 441 if (!strcmp(next, addr->addr)) { 442 cbcp->fsm.type = CBCP_LISTNUM; 443 strcpy(cbcp->fsm.phone, next); 444 return 1; 445 } 446 } else 447 log_Printf(LogCBCP, "Warning: Unrecognised address type %d !\n", 448 (int)addr->type); 449 addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1); 450 } 451 } 452 log_Printf(LogPHASE, "CBCP: no good number to pass to the peer !\n"); 453 return 0; 454 } 455 456 log_Printf(LogCBCP, "Unrecognised REQ type %d !\n", (int)data->type); 457 return 0; 458 } 459 460 static void 461 cbcp_SendResponse(struct cbcp *cbcp) 462 { 463 struct cbcp_data data; 464 struct cbcp_addr *addr; 465 466 /* Only callers send RESPONSEs */ 467 468 log_Printf(LogCBCP, "%s: SendResponse(%d) state = %s\n", cbcp->p->dl->name, 469 cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); 470 471 data.type = cbcp->fsm.type; 472 data.delay = cbcp->fsm.delay; 473 addr = (struct cbcp_addr *)data.addr_start; 474 if (*cbcp->fsm.phone) { 475 addr->type = CBCP_ADDR_PSTN; 476 strcpy(addr->addr, cbcp->fsm.phone); 477 data.length = (addr->addr + strlen(addr->addr) + 1) - (char *)&data; 478 } else 479 data.length = data.addr_start - (char *)&data; 480 481 cbcp_data_Show(&data); 482 cbcp_Output(cbcp, CBCP_RESPONSE, &data); 483 cbcp->fsm.restart--; 484 cbcp_StartTimer(cbcp, cbcp->fsm.delay); 485 cbcp_NewPhase(cbcp, CBCP_RESPSENT); /* Wait for an ACK */ 486 } 487 488 /* What to do after checking an incoming response */ 489 #define CBCP_ACTION_DOWN (0) 490 #define CBCP_ACTION_REQ (1) 491 #define CBCP_ACTION_ACK (2) 492 493 static int 494 cbcp_CheckResponse(struct cbcp *cbcp, struct cbcp_data *data) 495 { 496 /* 497 * We've received a RESPONSE (data). Check if it agrees with 498 * our REQ (cbcp->fsm) 499 */ 500 struct cbcp_addr *addr; 501 502 addr = (struct cbcp_addr *)data->addr_start; 503 504 if (data->type == cbcp->fsm.type) { 505 switch (cbcp->fsm.type) { 506 case CBCP_NONUM: 507 return CBCP_ACTION_ACK; 508 509 case CBCP_CLIENTNUM: 510 if ((char *)data + data->length <= addr->addr) 511 log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n"); 512 else if (addr->type != CBCP_ADDR_PSTN) 513 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 514 addr->type); 515 else { 516 strcpy(cbcp->fsm.phone, addr->addr); 517 cbcp->fsm.delay = data->delay; 518 return CBCP_ACTION_ACK; 519 } 520 return CBCP_ACTION_DOWN; 521 522 case CBCP_SERVERNUM: 523 cbcp->fsm.delay = data->delay; 524 return CBCP_ACTION_ACK; 525 526 case CBCP_LISTNUM: 527 if ((char *)data + data->length <= addr->addr) 528 log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n"); 529 else if (addr->type != CBCP_ADDR_PSTN) 530 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 531 addr->type); 532 else { 533 char list[sizeof cbcp->fsm.phone], *next; 534 535 strncpy(list, cbcp->fsm.phone, sizeof list - 1); 536 list[sizeof list - 1] = '\0'; 537 for (next = strtok(list, ","); next; next = strtok(NULL, ",")) 538 if (!strcmp(addr->addr, next)) { 539 strcpy(cbcp->fsm.phone, next); 540 cbcp->fsm.delay = data->delay; 541 return CBCP_ACTION_ACK; 542 } 543 log_Printf(LogPHASE, "CBCP: peer didn't respond with a " 544 "valid number !\n"); 545 } 546 return CBCP_ACTION_DOWN; 547 } 548 log_Printf(LogPHASE, "Internal CBCP error - agreed on %d ??!?\n", 549 (int)cbcp->fsm.type); 550 return CBCP_ACTION_DOWN; 551 } 552 log_Printf(LogCBCP, "Invalid peer RESPONSE\n"); 553 return CBCP_ACTION_REQ; 554 } 555 556 static void 557 cbcp_SendAck(struct cbcp *cbcp) 558 { 559 struct cbcp_data data; 560 561 /* Only callees send ACKs */ 562 563 log_Printf(LogCBCP, "%s: SendAck(%d) state = %s\n", cbcp->p->dl->name, 564 cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); 565 566 data.type = cbcp->fsm.type; 567 data.delay = cbcp->fsm.delay; 568 data.length = data.addr_start - (char *)&data; 569 570 cbcp_data_Show(&data); 571 cbcp_Output(cbcp, CBCP_ACK, &data); 572 cbcp->fsm.restart--; 573 cbcp_StartTimer(cbcp, cbcp->fsm.delay); 574 cbcp_NewPhase(cbcp, CBCP_ACKSENT); /* Wait for an ACK */ 575 } 576 577 void 578 cbcp_Input(struct physical *p, struct mbuf *bp) 579 { 580 struct cbcp_header *head; 581 struct cbcp_data *data; 582 struct cbcp *cbcp = &p->dl->cbcp; 583 int len; 584 585 len = mbuf_Length(bp); 586 if (len < sizeof(struct cbcp_header)) { 587 mbuf_Free(bp); 588 return; 589 } 590 head = (struct cbcp_header *)MBUF_CTOP(bp); 591 if (ntohs(head->length) != len) { 592 log_Printf(LogWARN, "Corrupt CBCP packet (code %d, length %d not %d)" 593 " - ignored\n", head->code, ntohs(head->length), len); 594 mbuf_Free(bp); 595 return; 596 } 597 598 /* XXX check the id */ 599 600 bp->offset += sizeof(struct cbcp_header); 601 bp->cnt -= sizeof(struct cbcp_header); 602 data = (struct cbcp_data *)MBUF_CTOP(bp); 603 604 switch (head->code) { 605 case CBCP_REQ: 606 log_Printf(LogCBCP, "%s: RecvReq(%d) state = %s\n", 607 p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); 608 cbcp_data_Show(data); 609 if (cbcp->fsm.state == CBCP_STOPPED || cbcp->fsm.state == CBCP_RESPSENT) { 610 timer_Stop(&cbcp->fsm.timer); 611 if (cbcp_AdjustResponse(cbcp, data)) { 612 cbcp->fsm.restart = DEF_REQs; 613 cbcp_SendResponse(cbcp); 614 } else 615 datalink_CBCPFailed(cbcp->p->dl); 616 } else 617 log_Printf(LogCBCP, "%s: unexpected REQ dropped\n", p->dl->name); 618 break; 619 620 case CBCP_RESPONSE: 621 log_Printf(LogCBCP, "%s: RecvResponse(%d) state = %s\n", 622 p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); 623 cbcp_data_Show(data); 624 if (cbcp->fsm.state == CBCP_REQSENT || cbcp->fsm.state == CBCP_ACKSENT) { 625 timer_Stop(&cbcp->fsm.timer); 626 switch (cbcp_CheckResponse(cbcp, data)) { 627 case CBCP_ACTION_REQ: 628 cbcp_SendReq(cbcp); 629 break; 630 631 case CBCP_ACTION_ACK: 632 cbcp->fsm.restart = DEF_REQs; 633 cbcp_SendAck(cbcp); 634 if (cbcp->fsm.type == CBCP_NONUM) { 635 /* 636 * Don't change state in case the peer doesn't get our ACK, 637 * just bring the layer up. 638 */ 639 timer_Stop(&cbcp->fsm.timer); 640 datalink_NCPUp(cbcp->p->dl); 641 } 642 break; 643 644 default: 645 datalink_CBCPFailed(cbcp->p->dl); 646 break; 647 } 648 } else 649 log_Printf(LogCBCP, "%s: unexpected RESPONSE dropped\n", p->dl->name); 650 break; 651 652 case CBCP_ACK: 653 log_Printf(LogCBCP, "%s: RecvAck(%d) state = %s\n", 654 p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); 655 cbcp_data_Show(data); 656 if (cbcp->fsm.state == CBCP_RESPSENT) { 657 timer_Stop(&cbcp->fsm.timer); 658 datalink_CBCPComplete(cbcp->p->dl); 659 log_Printf(LogPHASE, "%s: CBCP: Peer will dial back\n", p->dl->name); 660 } else 661 log_Printf(LogCBCP, "%s: unexpected ACK dropped\n", p->dl->name); 662 break; 663 664 default: 665 log_Printf(LogWARN, "Unrecognised CBCP packet (code %d, length %d)\n", 666 head->code, len); 667 break; 668 } 669 670 mbuf_Free(bp); 671 } 672 673 void 674 cbcp_Down(struct cbcp *cbcp) 675 { 676 timer_Stop(&cbcp->fsm.timer); 677 cbcp_NewPhase(cbcp, CBCP_CLOSED); 678 cbcp->required = 0; 679 } 680 681 void 682 cbcp_ReceiveTerminateReq(struct physical *p) 683 { 684 if (p->dl->cbcp.fsm.state == CBCP_ACKSENT) { 685 /* Don't change our state in case the peer doesn't get the ACK */ 686 p->dl->cbcp.required = 1; 687 log_Printf(LogPHASE, "%s: CBCP: Will dial back on %s\n", p->dl->name, 688 p->dl->cbcp.fsm.phone); 689 } else 690 cbcp_NewPhase(&p->dl->cbcp, CBCP_CLOSED); 691 } 692