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.6 1998/10/25 23:35:15 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 = (char *)&data.delay - (char *)&data; 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 /* 358 * If the callee offers no callback, we send our desired response 359 * anyway. This is what Win95 does - although I can't find this 360 * behaviour documented in the spec.... 361 */ 362 return 1; 363 364 case CBCP_CLIENTNUM: 365 if (cbcp->fsm.type == CBCP_CLIENTNUM) { 366 char *ptr; 367 368 if (data->length > data->addr_start - (char *)data) { 369 /* 370 * The peer has given us an address type spec - make sure we 371 * understand ! 372 */ 373 addr = (struct cbcp_addr *)data->addr_start; 374 if (addr->type != CBCP_ADDR_PSTN) { 375 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 376 (int)addr->type); 377 return 0; 378 } 379 } 380 /* we accept the REQ even if the peer didn't specify an addr->type */ 381 ptr = strchr(cbcp->fsm.phone, ','); 382 if (ptr) 383 *ptr = '\0'; /* Just use the first number in our list */ 384 return 1; 385 } 386 log_Printf(LogPHASE, "CBCP: no number to pass to the peer !\n"); 387 return 0; 388 389 case CBCP_SERVERNUM: 390 if (cbcp->fsm.type == CBCP_SERVERNUM) { 391 *cbcp->fsm.phone = '\0'; 392 return 1; 393 } 394 if (data->length > data->addr_start - (char *)data) { 395 /* 396 * This violates the spec, but if the peer has told us the 397 * number it wants to call back, take advantage of this fact 398 * and allow things to proceed if we've specified the same 399 * number 400 */ 401 addr = (struct cbcp_addr *)data->addr_start; 402 if (addr->type != CBCP_ADDR_PSTN) { 403 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 404 (int)addr->type); 405 return 0; 406 } else if (cbcp->fsm.type == CBCP_CLIENTNUM) { 407 /* 408 * If the peer's insisting on deciding the number, make sure 409 * it's one of the ones in our list. If it is, let the peer 410 * think it's in control :-) 411 */ 412 char list[sizeof cbcp->fsm.phone], *next; 413 414 strncpy(list, cbcp->fsm.phone, sizeof list - 1); 415 list[sizeof list - 1] = '\0'; 416 for (next = strtok(list, ","); next; next = strtok(NULL, ",")) 417 if (!strcmp(next, addr->addr)) { 418 cbcp->fsm.type = CBCP_SERVERNUM; 419 strcpy(cbcp->fsm.phone, next); 420 return 1; 421 } 422 } 423 } 424 log_Printf(LogPHASE, "CBCP: Peer won't allow local decision !\n"); 425 return 0; 426 427 case CBCP_LISTNUM: 428 if (cbcp->fsm.type == CBCP_CLIENTNUM || cbcp->fsm.type == CBCP_LISTNUM) { 429 /* 430 * Search through ``data''s addresses and see if cbcp->fsm.phone 431 * contains any of them 432 */ 433 char list[sizeof cbcp->fsm.phone], *next, *end; 434 435 addr = (struct cbcp_addr *)data->addr_start; 436 end = (char *)data + data->length; 437 438 while (addr->addr < end) { 439 if (addr->type == CBCP_ADDR_PSTN) { 440 strncpy(list, cbcp->fsm.phone, sizeof list - 1); 441 list[sizeof list - 1] = '\0'; 442 for (next = strtok(list, ","); next; next = strtok(NULL, ",")) 443 if (!strcmp(next, addr->addr)) { 444 cbcp->fsm.type = CBCP_LISTNUM; 445 strcpy(cbcp->fsm.phone, next); 446 return 1; 447 } 448 } else 449 log_Printf(LogCBCP, "Warning: Unrecognised address type %d !\n", 450 (int)addr->type); 451 addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1); 452 } 453 } 454 log_Printf(LogPHASE, "CBCP: no good number to pass to the peer !\n"); 455 return 0; 456 } 457 458 log_Printf(LogCBCP, "Unrecognised REQ type %d !\n", (int)data->type); 459 return 0; 460 } 461 462 static void 463 cbcp_SendResponse(struct cbcp *cbcp) 464 { 465 struct cbcp_data data; 466 struct cbcp_addr *addr; 467 468 /* Only callers send RESPONSEs */ 469 470 log_Printf(LogCBCP, "%s: SendResponse(%d) state = %s\n", cbcp->p->dl->name, 471 cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); 472 473 data.type = cbcp->fsm.type; 474 data.delay = cbcp->fsm.delay; 475 addr = (struct cbcp_addr *)data.addr_start; 476 if (data.type == CBCP_NONUM) 477 data.length = (char *)&data.delay - (char *)&data; 478 else if (*cbcp->fsm.phone) { 479 addr->type = CBCP_ADDR_PSTN; 480 strcpy(addr->addr, cbcp->fsm.phone); 481 data.length = (addr->addr + strlen(addr->addr) + 1) - (char *)&data; 482 } else 483 data.length = data.addr_start - (char *)&data; 484 485 cbcp_data_Show(&data); 486 cbcp_Output(cbcp, CBCP_RESPONSE, &data); 487 cbcp->fsm.restart--; 488 cbcp_StartTimer(cbcp, cbcp->fsm.delay); 489 cbcp_NewPhase(cbcp, CBCP_RESPSENT); /* Wait for an ACK */ 490 } 491 492 /* What to do after checking an incoming response */ 493 #define CBCP_ACTION_DOWN (0) 494 #define CBCP_ACTION_REQ (1) 495 #define CBCP_ACTION_ACK (2) 496 497 static int 498 cbcp_CheckResponse(struct cbcp *cbcp, struct cbcp_data *data) 499 { 500 /* 501 * We've received a RESPONSE (data). Check if it agrees with 502 * our REQ (cbcp->fsm) 503 */ 504 struct cbcp_addr *addr; 505 506 addr = (struct cbcp_addr *)data->addr_start; 507 508 if (data->type == cbcp->fsm.type) { 509 switch (cbcp->fsm.type) { 510 case CBCP_NONUM: 511 return CBCP_ACTION_ACK; 512 513 case CBCP_CLIENTNUM: 514 if ((char *)data + data->length <= addr->addr) 515 log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n"); 516 else if (addr->type != CBCP_ADDR_PSTN) 517 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 518 addr->type); 519 else { 520 strcpy(cbcp->fsm.phone, addr->addr); 521 cbcp->fsm.delay = data->delay; 522 return CBCP_ACTION_ACK; 523 } 524 return CBCP_ACTION_DOWN; 525 526 case CBCP_SERVERNUM: 527 cbcp->fsm.delay = data->delay; 528 return CBCP_ACTION_ACK; 529 530 case CBCP_LISTNUM: 531 if ((char *)data + data->length <= addr->addr) 532 log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n"); 533 else if (addr->type != CBCP_ADDR_PSTN) 534 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 535 addr->type); 536 else { 537 char list[sizeof cbcp->fsm.phone], *next; 538 539 strncpy(list, cbcp->fsm.phone, sizeof list - 1); 540 list[sizeof list - 1] = '\0'; 541 for (next = strtok(list, ","); next; next = strtok(NULL, ",")) 542 if (!strcmp(addr->addr, next)) { 543 strcpy(cbcp->fsm.phone, next); 544 cbcp->fsm.delay = data->delay; 545 return CBCP_ACTION_ACK; 546 } 547 log_Printf(LogPHASE, "CBCP: peer didn't respond with a " 548 "valid number !\n"); 549 } 550 return CBCP_ACTION_DOWN; 551 } 552 log_Printf(LogPHASE, "Internal CBCP error - agreed on %d ??!?\n", 553 (int)cbcp->fsm.type); 554 return CBCP_ACTION_DOWN; 555 } else if (data->type == CBCP_NONUM && cbcp->fsm.type == CBCP_CLIENTNUM) { 556 /* 557 * Client doesn't want CBCP after all.... 558 * We only allow this when ``set cbcp *'' has been specified. 559 */ 560 cbcp->fsm.type = CBCP_NONUM; 561 return CBCP_ACTION_ACK; 562 } 563 log_Printf(LogCBCP, "Invalid peer RESPONSE\n"); 564 return CBCP_ACTION_REQ; 565 } 566 567 static void 568 cbcp_SendAck(struct cbcp *cbcp) 569 { 570 struct cbcp_data data; 571 char *end; 572 573 /* Only callees send ACKs */ 574 575 log_Printf(LogCBCP, "%s: SendAck(%d) state = %s\n", cbcp->p->dl->name, 576 cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); 577 578 data.type = cbcp->fsm.type; 579 data.delay = cbcp->fsm.delay; 580 end = data.type == CBCP_NONUM ? (char *)&data.delay : data.addr_start; 581 data.length = end - (char *)&data; 582 583 cbcp_data_Show(&data); 584 cbcp_Output(cbcp, CBCP_ACK, &data); 585 cbcp->fsm.restart--; 586 cbcp_StartTimer(cbcp, cbcp->fsm.delay); 587 cbcp_NewPhase(cbcp, CBCP_ACKSENT); /* Wait for an ACK */ 588 } 589 590 void 591 cbcp_Input(struct physical *p, struct mbuf *bp) 592 { 593 struct cbcp_header *head; 594 struct cbcp_data *data; 595 struct cbcp *cbcp = &p->dl->cbcp; 596 int len; 597 598 len = mbuf_Length(bp); 599 if (len < sizeof(struct cbcp_header)) { 600 mbuf_Free(bp); 601 return; 602 } 603 head = (struct cbcp_header *)MBUF_CTOP(bp); 604 if (ntohs(head->length) != len) { 605 log_Printf(LogWARN, "Corrupt CBCP packet (code %d, length %d not %d)" 606 " - ignored\n", head->code, ntohs(head->length), len); 607 mbuf_Free(bp); 608 return; 609 } 610 611 /* XXX check the id */ 612 613 bp->offset += sizeof(struct cbcp_header); 614 bp->cnt -= sizeof(struct cbcp_header); 615 data = (struct cbcp_data *)MBUF_CTOP(bp); 616 617 switch (head->code) { 618 case CBCP_REQ: 619 log_Printf(LogCBCP, "%s: RecvReq(%d) state = %s\n", 620 p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); 621 cbcp_data_Show(data); 622 if (cbcp->fsm.state == CBCP_STOPPED || cbcp->fsm.state == CBCP_RESPSENT) { 623 timer_Stop(&cbcp->fsm.timer); 624 if (cbcp_AdjustResponse(cbcp, data)) { 625 cbcp->fsm.restart = DEF_REQs; 626 cbcp->fsm.id = head->id; 627 cbcp_SendResponse(cbcp); 628 } else 629 datalink_CBCPFailed(cbcp->p->dl); 630 } else 631 log_Printf(LogCBCP, "%s: unexpected REQ dropped\n", p->dl->name); 632 break; 633 634 case CBCP_RESPONSE: 635 log_Printf(LogCBCP, "%s: RecvResponse(%d) state = %s\n", 636 p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); 637 cbcp_data_Show(data); 638 if (cbcp->fsm.id != head->id) { 639 log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n", 640 cbcp->fsm.id, head->id); 641 cbcp->fsm.id = head->id; 642 } 643 if (cbcp->fsm.state == CBCP_REQSENT || cbcp->fsm.state == CBCP_ACKSENT) { 644 timer_Stop(&cbcp->fsm.timer); 645 switch (cbcp_CheckResponse(cbcp, data)) { 646 case CBCP_ACTION_REQ: 647 cbcp_SendReq(cbcp); 648 break; 649 650 case CBCP_ACTION_ACK: 651 cbcp->fsm.restart = DEF_REQs; 652 cbcp_SendAck(cbcp); 653 if (cbcp->fsm.type == CBCP_NONUM) { 654 /* 655 * Don't change state in case the peer doesn't get our ACK, 656 * just bring the layer up. 657 */ 658 timer_Stop(&cbcp->fsm.timer); 659 datalink_NCPUp(cbcp->p->dl); 660 } 661 break; 662 663 default: 664 datalink_CBCPFailed(cbcp->p->dl); 665 break; 666 } 667 } else 668 log_Printf(LogCBCP, "%s: unexpected RESPONSE dropped\n", p->dl->name); 669 break; 670 671 case CBCP_ACK: 672 log_Printf(LogCBCP, "%s: RecvAck(%d) state = %s\n", 673 p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); 674 cbcp_data_Show(data); 675 if (cbcp->fsm.id != head->id) { 676 log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n", 677 cbcp->fsm.id, head->id); 678 cbcp->fsm.id = head->id; 679 } 680 if (cbcp->fsm.state == CBCP_RESPSENT) { 681 timer_Stop(&cbcp->fsm.timer); 682 datalink_CBCPComplete(cbcp->p->dl); 683 log_Printf(LogPHASE, "%s: CBCP: Peer will dial back\n", p->dl->name); 684 } else 685 log_Printf(LogCBCP, "%s: unexpected ACK dropped\n", p->dl->name); 686 break; 687 688 default: 689 log_Printf(LogWARN, "Unrecognised CBCP packet (code %d, length %d)\n", 690 head->code, len); 691 break; 692 } 693 694 mbuf_Free(bp); 695 } 696 697 void 698 cbcp_Down(struct cbcp *cbcp) 699 { 700 timer_Stop(&cbcp->fsm.timer); 701 cbcp_NewPhase(cbcp, CBCP_CLOSED); 702 cbcp->required = 0; 703 } 704 705 void 706 cbcp_ReceiveTerminateReq(struct physical *p) 707 { 708 if (p->dl->cbcp.fsm.state == CBCP_ACKSENT) { 709 /* Don't change our state in case the peer doesn't get the ACK */ 710 p->dl->cbcp.required = 1; 711 log_Printf(LogPHASE, "%s: CBCP: Will dial back on %s\n", p->dl->name, 712 p->dl->cbcp.fsm.phone); 713 } else 714 cbcp_NewPhase(&p->dl->cbcp, CBCP_CLOSED); 715 } 716