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