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