1 /* 2 * fsm.c - {Link, IP} Control Protocol Finite State Machine. 3 * 4 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 5 * Use is subject to license terms. 6 * 7 * Copyright (c) 1989 Carnegie Mellon University. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms are permitted 11 * provided that the above copyright notice and this paragraph are 12 * duplicated in all such forms and that any documentation, 13 * advertising materials, and other materials related to such 14 * distribution and use acknowledge that the software was developed 15 * by Carnegie Mellon University. The name of the 16 * University may not be used to endorse or promote products derived 17 * from this software without specific prior written permission. 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 #pragma ident "%Z%%M% %I% %E% SMI" 24 #define RCSID "$Id: fsm.c,v 1.17 1999/08/13 06:46:12 paulus Exp $" 25 26 /* 27 * TODO: 28 * Randomize fsm id on link/init. 29 * Deal with variable outgoing MTU. 30 */ 31 32 #include <stdio.h> 33 #include <string.h> 34 #include <sys/types.h> 35 #ifndef NO_DRAND48 36 #include <stdlib.h> 37 #endif /* NO_DRAND48 */ 38 39 #include "pppd.h" 40 #include "fsm.h" 41 42 #if !defined(lint) && !defined(_lint) 43 static const char rcsid[] = RCSID; 44 #endif 45 46 static void fsm_timeout __P((void *)); 47 static void fsm_rconfreq __P((fsm *, int, u_char *, int)); 48 static void fsm_rconfack __P((fsm *, int, u_char *, int)); 49 static void fsm_rconfnakrej __P((fsm *, int, int, u_char *, int)); 50 static void fsm_rtermreq __P((fsm *, int, u_char *, int)); 51 static void fsm_rtermack __P((fsm *)); 52 static void fsm_rcoderej __P((fsm *, u_char *, int)); 53 static void fsm_sconfreq __P((fsm *, int)); 54 55 #define PROTO_NAME(f) ((f)->callbacks->proto_name) 56 57 static int peer_mru[NUM_PPP]; 58 59 const char * 60 fsm_state(int statenum) 61 { 62 static const char *fsm_states[] = { FSM__STATES }; 63 static char buf[32]; 64 65 if (statenum < 0 || statenum >= Dim(fsm_states)) { 66 (void) slprintf(buf, sizeof (buf), "unknown#%d", statenum); 67 return buf; 68 } 69 return fsm_states[statenum]; 70 } 71 72 /* 73 * fsm_init - Initialize fsm. 74 * 75 * Initialize fsm state. 76 */ 77 void 78 fsm_init(f) 79 fsm *f; 80 { 81 f->state = INITIAL; 82 f->flags = 0; 83 f->id = (uchar_t)(drand48() * 0xFF); /* Start with random id */ 84 f->timeouttime = DEFTIMEOUT; 85 f->maxconfreqtransmits = DEFMAXCONFREQS; 86 f->maxtermtransmits = DEFMAXTERMREQS; 87 f->maxnakloops = DEFMAXNAKLOOPS; 88 f->term_reason_len = 0; 89 } 90 91 92 /* 93 * fsm_lowerup - The lower layer is up. 94 */ 95 void 96 fsm_lowerup(f) 97 fsm *f; 98 { 99 switch( f->state ){ 100 case INITIAL: 101 f->state = CLOSED; 102 break; 103 104 case STARTING: 105 if( f->flags & OPT_SILENT ) 106 f->state = STOPPED; 107 else { 108 /* Send an initial configure-request */ 109 fsm_sconfreq(f, 0); 110 f->state = REQSENT; 111 } 112 break; 113 114 default: 115 error("%s: Up event in state %s", PROTO_NAME(f), fsm_state(f->state)); 116 } 117 } 118 119 120 /* 121 * fsm_lowerdown - The lower layer is down. 122 * 123 * Cancel all timeouts and inform upper layers. 124 */ 125 void 126 fsm_lowerdown(f) 127 fsm *f; 128 { 129 switch( f->state ){ 130 case CLOSED: 131 f->state = INITIAL; 132 break; 133 134 case STOPPED: 135 f->state = STARTING; 136 if (f->callbacks->starting != NULL) 137 (*f->callbacks->starting)(f); 138 break; 139 140 case CLOSING: 141 f->state = INITIAL; 142 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 143 break; 144 145 case STOPPING: 146 case REQSENT: 147 case ACKRCVD: 148 case ACKSENT: 149 f->state = STARTING; 150 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 151 break; 152 153 case OPENED: 154 f->state = STARTING; 155 if (f->callbacks->down != NULL) 156 (*f->callbacks->down)(f); 157 break; 158 159 default: 160 dbglog("%s: Down event in state %s", PROTO_NAME(f), 161 fsm_state(f->state)); 162 } 163 } 164 165 166 /* 167 * fsm_open - Link is allowed to come up. 168 */ 169 void 170 fsm_open(f) 171 fsm *f; 172 { 173 switch( f->state ){ 174 case INITIAL: 175 f->state = STARTING; 176 if (f->callbacks->starting != NULL) 177 (*f->callbacks->starting)(f); 178 break; 179 180 case CLOSED: 181 if( f->flags & OPT_SILENT ) 182 f->state = STOPPED; 183 else { 184 /* Send an initial configure-request */ 185 fsm_sconfreq(f, 0); 186 f->state = REQSENT; 187 } 188 break; 189 190 case CLOSING: 191 f->state = STOPPING; 192 /*FALLTHROUGH*/ 193 case STOPPING: 194 case STOPPED: 195 case OPENED: 196 if( f->flags & OPT_RESTART ){ 197 fsm_lowerdown(f); 198 fsm_lowerup(f); 199 } 200 break; 201 202 case STARTING: 203 case REQSENT: 204 case ACKRCVD: 205 case ACKSENT: 206 /* explicitly do nothing here. */ 207 break; 208 } 209 } 210 211 212 /* 213 * fsm_close - Start closing connection. 214 * 215 * Cancel timeouts and either initiate close or possibly go directly to 216 * the CLOSED state. 217 */ 218 void 219 fsm_close(f, reason) 220 fsm *f; 221 char *reason; 222 { 223 int prevstate = f->state; 224 225 f->term_reason = reason; 226 f->term_reason_len = (reason == NULL? 0: strlen(reason)); 227 switch( f->state ){ 228 case STARTING: 229 f->state = INITIAL; 230 if (f->callbacks->finished != NULL) 231 (*f->callbacks->finished)(f); 232 break; 233 234 case STOPPED: 235 f->state = CLOSED; 236 break; 237 238 case STOPPING: 239 f->state = CLOSING; 240 break; 241 242 case REQSENT: 243 case ACKRCVD: 244 case ACKSENT: 245 case OPENED: 246 f->state = CLOSING; 247 if (prevstate != OPENED ) 248 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 249 else if (f->callbacks->down != NULL) 250 (*f->callbacks->down)(f); /* Inform upper layers we're down */ 251 /* 252 * Note that this-layer-down means "stop transmitting." 253 * This-layer-finished means "stop everything." 254 */ 255 256 /* Init restart counter, send Terminate-Request */ 257 f->retransmits = f->maxtermtransmits; 258 fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id, 259 (u_char *) f->term_reason, f->term_reason_len); 260 TIMEOUT(fsm_timeout, f, f->timeouttime); 261 --f->retransmits; 262 break; 263 264 case INITIAL: 265 case CLOSED: 266 case CLOSING: 267 /* explicitly do nothing here. */ 268 break; 269 } 270 } 271 272 273 /* 274 * fsm_timeout - Timeout expired. 275 */ 276 static void 277 fsm_timeout(arg) 278 void *arg; 279 { 280 fsm *f = (fsm *) arg; 281 282 switch (f->state) { 283 case CLOSING: 284 case STOPPING: 285 if( f->retransmits <= 0 ){ 286 /* 287 * We've waited for an ack long enough. Peer probably heard us. 288 */ 289 f->state = (f->state == CLOSING)? CLOSED: STOPPED; 290 if (f->callbacks->finished != NULL) 291 (*f->callbacks->finished)(f); 292 } else { 293 /* Send Terminate-Request */ 294 fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id, 295 (u_char *) f->term_reason, f->term_reason_len); 296 TIMEOUT(fsm_timeout, f, f->timeouttime); 297 --f->retransmits; 298 } 299 break; 300 301 case REQSENT: 302 case ACKRCVD: 303 case ACKSENT: 304 if (f->retransmits <= 0) { 305 warn("%s: timeout sending Config-Requests\n", PROTO_NAME(f)); 306 f->state = STOPPED; 307 if (!(f->flags & OPT_PASSIVE) && f->callbacks->finished != NULL) 308 (*f->callbacks->finished)(f); 309 310 } else { 311 /* Retransmit the configure-request */ 312 if (f->callbacks->retransmit != NULL) 313 (*f->callbacks->retransmit)(f); 314 fsm_sconfreq(f, 1); /* Re-send Configure-Request */ 315 if( f->state == ACKRCVD ) 316 f->state = REQSENT; 317 } 318 break; 319 320 default: 321 fatal("%s: Timeout event in state %s!", PROTO_NAME(f), 322 fsm_state(f->state)); 323 } 324 } 325 326 327 /* 328 * fsm_input - Input packet. 329 */ 330 void 331 fsm_input(f, inpacket, l) 332 fsm *f; 333 u_char *inpacket; 334 int l; 335 { 336 u_char *inp; 337 u_char code, id; 338 int len; 339 340 /* 341 * Parse header (code, id and length). 342 * If packet too short, drop it. 343 */ 344 inp = inpacket; 345 if (l < HEADERLEN) { 346 error("%s packet: discard; too small (%d < %d)", PROTO_NAME(f), l, 347 HEADERLEN); 348 return; 349 } 350 GETCHAR(code, inp); 351 GETCHAR(id, inp); 352 GETSHORT(len, inp); 353 if (len < HEADERLEN) { 354 error("%s packet: discard; invalid length (%d < %d)", PROTO_NAME(f), 355 len, HEADERLEN); 356 return; 357 } 358 if (len > l) { 359 error("%s packet: discard; truncated (%d > %d)", PROTO_NAME(f), len, 360 l); 361 return; 362 } 363 len -= HEADERLEN; /* subtract header length */ 364 365 if (f->state == INITIAL || f->state == STARTING) { 366 dbglog("%s: discarded packet in state %s", PROTO_NAME(f), 367 fsm_state(f->state)); 368 return; 369 } 370 371 /* 372 * Action depends on code. 373 */ 374 switch (code) { 375 case CODE_CONFREQ: 376 fsm_rconfreq(f, id, inp, len); 377 break; 378 379 case CODE_CONFACK: 380 fsm_rconfack(f, id, inp, len); 381 break; 382 383 case CODE_CONFNAK: 384 case CODE_CONFREJ: 385 fsm_rconfnakrej(f, code, id, inp, len); 386 break; 387 388 case CODE_TERMREQ: 389 fsm_rtermreq(f, id, inp, len); 390 break; 391 392 case CODE_TERMACK: 393 fsm_rtermack(f); 394 break; 395 396 case CODE_CODEREJ: 397 fsm_rcoderej(f, inp, len); 398 break; 399 400 default: 401 if (f->callbacks->extcode == NULL || 402 !(*f->callbacks->extcode)(f, code, id, inp, len)) 403 fsm_sdata(f, CODE_CODEREJ, ++f->id, inpacket, len + HEADERLEN); 404 break; 405 } 406 } 407 408 409 /* 410 * fsm_rconfreq - Receive Configure-Request. 411 */ 412 static void 413 fsm_rconfreq(f, id, inp, len) 414 fsm *f; 415 u_char id; 416 u_char *inp; 417 int len; 418 { 419 int code, reject_if_disagree; 420 421 switch( f->state ){ 422 case CLOSED: 423 /* Go away, we're closed */ 424 fsm_sdata(f, CODE_TERMACK, id, NULL, 0); 425 return; 426 427 case CLOSING: 428 case STOPPING: 429 dbglog("%s: discarded Configure-Request in state %s", PROTO_NAME(f), 430 fsm_state(f->state)); 431 return; 432 433 case OPENED: 434 /* Go down and restart negotiation */ 435 if (f->callbacks->down != NULL) 436 (*f->callbacks->down)(f); /* Inform upper layers */ 437 break; 438 } 439 440 #ifdef DEBUG 441 if (inp >= outpacket_buf && inp < outpacket_buf+PPP_MRU+PPP_HDRLEN) 442 fatal("bad pointer"); 443 #endif 444 445 /* 446 * Pass the requested configuration options 447 * to protocol-specific code for checking. 448 */ 449 if (f->callbacks->reqci != NULL) { /* Check CI */ 450 reject_if_disagree = (f->nakloops >= f->maxnakloops); 451 code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree); 452 } else if (len > 0) 453 code = CODE_CONFREJ; /* Reject all CI */ 454 else 455 code = CODE_CONFACK; 456 457 /* Allow NCP to do fancy footwork, such as reinitializing. */ 458 if (code <= 0) 459 return; 460 461 if (f->state == OPENED || f->state == STOPPED) 462 fsm_sconfreq(f, 0); /* Send initial Configure-Request */ 463 464 /* send the Ack, Nak or Rej to the peer */ 465 fsm_sdata(f, code, id, inp, len); 466 467 if (code == CODE_CONFACK) { 468 /* RFC 1661 event RCR+ */ 469 if (f->state == ACKRCVD) { 470 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 471 f->state = OPENED; 472 if (f->callbacks->up != NULL) 473 (*f->callbacks->up)(f); /* Inform upper layers */ 474 } else 475 f->state = ACKSENT; 476 f->nakloops = 0; 477 478 } else { 479 /* RFC 1661 event RCR- */ 480 /* (we sent CODE_CONFNAK or CODE_CONFREJ) */ 481 if (f->state != ACKRCVD) 482 f->state = REQSENT; 483 if( code == CODE_CONFNAK ) 484 ++f->nakloops; 485 } 486 } 487 488 489 /* 490 * fsm_rconfack - Receive Configure-Ack. 491 */ 492 static void 493 fsm_rconfack(f, id, inp, len) 494 fsm *f; 495 int id; 496 u_char *inp; 497 int len; 498 { 499 if (id != f->reqid || f->seen_ack) /* Expected id? */ 500 return; /* Nope, toss... */ 501 if( !(f->callbacks->ackci != NULL ? (*f->callbacks->ackci)(f, inp, len): 502 (len == 0)) ){ 503 /* Ack is bad - ignore it */ 504 error("Received bad configure-ack: %P", inp, len); 505 return; 506 } 507 f->seen_ack = 1; 508 509 switch (f->state) { 510 case CLOSED: 511 case STOPPED: 512 fsm_sdata(f, CODE_TERMACK, id, NULL, 0); 513 break; 514 515 case REQSENT: 516 f->state = ACKRCVD; 517 f->retransmits = f->maxconfreqtransmits; 518 break; 519 520 case ACKRCVD: 521 /* Huh? an extra valid Ack? oh well... */ 522 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 523 fsm_sconfreq(f, 0); 524 f->state = REQSENT; 525 break; 526 527 case ACKSENT: 528 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 529 f->state = OPENED; 530 f->retransmits = f->maxconfreqtransmits; 531 if (f->callbacks->up != NULL) 532 (*f->callbacks->up)(f); /* Inform upper layers */ 533 break; 534 535 case OPENED: 536 /* Go down and restart negotiation */ 537 fsm_sconfreq(f, 0); /* Send initial Configure-Request */ 538 f->state = REQSENT; 539 if (f->callbacks->down != NULL) 540 (*f->callbacks->down)(f); /* Inform upper layers */ 541 break; 542 } 543 } 544 545 546 /* 547 * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. 548 */ 549 static void 550 fsm_rconfnakrej(f, code, id, inp, len) 551 fsm *f; 552 int code, id; 553 u_char *inp; 554 int len; 555 { 556 int (*proc) __P((fsm *, u_char *, int)); 557 int ret; 558 559 if (id != f->reqid || f->seen_ack) /* Expected id? */ 560 return; /* Nope, toss... */ 561 proc = (code == CODE_CONFNAK)? f->callbacks->nakci: f->callbacks->rejci; 562 if (proc == NULL || !(ret = proc(f, inp, len))) { 563 /* Nak/reject is bad - ignore it */ 564 error("Received bad configure-nak/rej: %P", inp, len); 565 return; 566 } 567 f->seen_ack = 1; 568 569 switch (f->state) { 570 case CLOSED: 571 case STOPPED: 572 fsm_sdata(f, CODE_TERMACK, id, NULL, 0); 573 break; 574 575 case REQSENT: 576 case ACKSENT: 577 /* They didn't agree to what we wanted - try another request */ 578 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 579 if (ret < 0) 580 f->state = STOPPED; /* kludge for stopping CCP */ 581 else 582 fsm_sconfreq(f, 0); /* Send Configure-Request */ 583 break; 584 585 case ACKRCVD: 586 /* Got a Nak/reject when we had already had an Ack?? oh well... */ 587 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 588 fsm_sconfreq(f, 0); 589 f->state = REQSENT; 590 break; 591 592 case OPENED: 593 /* Go down and restart negotiation */ 594 fsm_sconfreq(f, 0); /* Send initial Configure-Request */ 595 f->state = REQSENT; 596 if (f->callbacks->down != NULL) 597 (*f->callbacks->down)(f); /* Inform upper layers */ 598 break; 599 } 600 } 601 602 603 /* 604 * fsm_rtermreq - Receive Terminate-Req. 605 */ 606 static void 607 fsm_rtermreq(f, id, p, len) 608 fsm *f; 609 int id; 610 u_char *p; 611 int len; 612 { 613 switch (f->state) { 614 case ACKRCVD: 615 case ACKSENT: 616 f->state = REQSENT; /* Start over but keep trying */ 617 break; 618 619 case OPENED: 620 if (len > 0) { 621 info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p); 622 } else { 623 info("%s terminated by peer", PROTO_NAME(f)); 624 } 625 f->state = STOPPING; 626 if (f->callbacks->down != NULL) 627 (*f->callbacks->down)(f); /* Inform upper layers */ 628 f->retransmits = 0; 629 TIMEOUT(fsm_timeout, f, f->timeouttime); 630 break; 631 } 632 633 fsm_sdata(f, CODE_TERMACK, id, NULL, 0); 634 } 635 636 637 /* 638 * fsm_rtermack - Receive Terminate-Ack. 639 */ 640 static void 641 fsm_rtermack(f) 642 fsm *f; 643 { 644 switch (f->state) { 645 case CLOSING: 646 UNTIMEOUT(fsm_timeout, f); 647 f->state = CLOSED; 648 if (f->callbacks->finished != NULL) 649 (*f->callbacks->finished)(f); 650 break; 651 case STOPPING: 652 UNTIMEOUT(fsm_timeout, f); 653 f->state = STOPPED; 654 if (f->callbacks->finished != NULL) 655 (*f->callbacks->finished)(f); 656 break; 657 658 case ACKRCVD: 659 f->state = REQSENT; 660 break; 661 662 case OPENED: 663 fsm_sconfreq(f, 0); 664 f->state = REQSENT; 665 if (f->callbacks->down != NULL) 666 (*f->callbacks->down)(f); /* Inform upper layers */ 667 break; 668 } 669 } 670 671 672 /* 673 * fsm_rcoderej - Receive a Code-Reject. 674 */ 675 static void 676 fsm_rcoderej(f, inp, len) 677 fsm *f; 678 u_char *inp; 679 int len; 680 { 681 u_char code, id; 682 int seriouserr; 683 684 if (len < HEADERLEN) { 685 error("%s: Code-Reject too short (%d < %d)", PROTO_NAME(f), len, 686 HEADERLEN); 687 return; 688 } 689 GETCHAR(code, inp); 690 GETCHAR(id, inp); 691 len -= 2; 692 warn("%s: Rcvd Code-Reject for %s id %d", PROTO_NAME(f), 693 code_name(code,0), id); 694 695 setbit(f->codemask, code); 696 697 /* Let the protocol know what happened. */ 698 if (f->callbacks->codereject != NULL) { 699 seriouserr = (*f->callbacks->codereject)(f,code,id,inp,len); 700 } else { 701 /* 702 * By default, it's RXJ- for well-known codes and RXJ+ for 703 * unknown ones. 704 */ 705 seriouserr = (code >= CODE_CONFREQ && code <= CODE_CODEREJ); 706 } 707 708 if (seriouserr) { 709 /* RXJ- -- shut down the protocol. */ 710 switch (f->state) { 711 case CLOSING: 712 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 713 /*FALLTHROUGH*/ 714 case CLOSED: 715 f->state = CLOSED; 716 if (f->callbacks->finished != NULL) 717 (*f->callbacks->finished)(f); 718 break; 719 720 case STOPPING: 721 case REQSENT: 722 case ACKRCVD: 723 case ACKSENT: 724 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 725 f->state = STOPPED; 726 /*FALLTHROUGH*/ 727 case STOPPED: 728 if (f->callbacks->finished != NULL) 729 (*f->callbacks->finished)(f); 730 break; 731 732 case OPENED: 733 f->state = STOPPING; 734 if (f->callbacks->down != NULL) 735 (*f->callbacks->down)(f); 736 737 if (f->term_reason == NULL) { 738 f->term_reason = "unacceptable Code-Reject received"; 739 f->term_reason_len = strlen(f->term_reason); 740 } 741 742 /* Init restart counter, send Terminate-Request */ 743 f->retransmits = f->maxtermtransmits; 744 fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id, 745 (u_char *) f->term_reason, f->term_reason_len); 746 TIMEOUT(fsm_timeout, f, f->timeouttime); 747 --f->retransmits; 748 break; 749 750 default: 751 fatal("state error"); 752 } 753 } else { 754 /* RXJ+ -- just back up from Ack-Rcvd to Req-Sent. */ 755 if (f->state == ACKRCVD) 756 f->state = REQSENT; 757 } 758 } 759 760 761 /* 762 * fsm_protreject - Peer doesn't speak this protocol. 763 * 764 * Treat this as a catastrophic error (RXJ-). 765 */ 766 void 767 fsm_protreject(f) 768 fsm *f; 769 { 770 switch( f->state ){ 771 case CLOSING: 772 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 773 /*FALLTHROUGH*/ 774 case CLOSED: 775 f->state = CLOSED; 776 if (f->callbacks->finished != NULL) 777 (*f->callbacks->finished)(f); 778 break; 779 780 case STOPPING: 781 case REQSENT: 782 case ACKRCVD: 783 case ACKSENT: 784 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 785 /*FALLTHROUGH*/ 786 case STOPPED: 787 f->state = STOPPED; 788 if (f->callbacks->finished != NULL) 789 (*f->callbacks->finished)(f); 790 break; 791 792 case OPENED: 793 f->state = STOPPING; 794 if (f->callbacks->down != NULL) 795 (*f->callbacks->down)(f); 796 797 /* Init restart counter, send Terminate-Request */ 798 f->retransmits = f->maxtermtransmits; 799 fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id, 800 (u_char *) f->term_reason, f->term_reason_len); 801 TIMEOUT(fsm_timeout, f, f->timeouttime); 802 --f->retransmits; 803 break; 804 805 default: 806 dbglog("%s: Protocol-Reject in state %s", PROTO_NAME(f), 807 fsm_state(f->state)); 808 } 809 } 810 811 812 /* 813 * fsm_sconfreq - Send a Configure-Request. 814 */ 815 static void 816 fsm_sconfreq(f, retransmit) 817 fsm *f; 818 int retransmit; 819 { 820 u_char *outp; 821 int cilen; 822 823 if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){ 824 /* Not currently negotiating - reset options */ 825 if (f->callbacks->resetci != NULL) 826 (*f->callbacks->resetci)(f); 827 f->nakloops = 0; 828 } 829 830 if( !retransmit ){ 831 /* New request - reset retransmission counter, use new ID */ 832 f->retransmits = f->maxconfreqtransmits; 833 f->reqid = ++f->id; 834 } 835 836 f->seen_ack = 0; 837 838 /* 839 * Make up the request packet 840 */ 841 outp = outpacket_buf + PPP_HDRLEN + HEADERLEN; 842 if (f->callbacks->cilen != NULL) { 843 cilen = (*f->callbacks->cilen)(f); 844 if (cilen > peer_mru[f->unit] - HEADERLEN) 845 cilen = peer_mru[f->unit] - HEADERLEN; 846 } else { 847 cilen = peer_mru[f->unit] - HEADERLEN; 848 } 849 850 if (f->callbacks->addci != NULL) 851 (*f->callbacks->addci)(f, outp, &cilen); 852 else 853 cilen = 0; 854 855 /* send the request to our peer */ 856 fsm_sdata(f, CODE_CONFREQ, f->reqid, outp, cilen); 857 858 /* start the retransmit timer */ 859 --f->retransmits; 860 TIMEOUT(fsm_timeout, f, f->timeouttime); 861 } 862 863 864 /* 865 * fsm_sdata - Send some data. 866 * 867 * Used for all packets sent to our peer by this module. 868 */ 869 void 870 fsm_sdata(f, code, id, data, datalen) 871 fsm *f; 872 u_char code, id; 873 u_char *data; 874 int datalen; 875 { 876 u_char *outp; 877 int outlen; 878 879 if (isset(f->codemask,code)) { 880 dbglog("%s: Peer has rejected %s; not sending another", 881 PROTO_NAME(f), code_name(code,0)); 882 return; 883 } 884 885 /* Adjust length to be smaller than MTU */ 886 outp = outpacket_buf; 887 if (datalen > peer_mru[f->unit] - HEADERLEN) 888 datalen = peer_mru[f->unit] - HEADERLEN; 889 if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) 890 BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen); 891 outlen = datalen + HEADERLEN; 892 MAKEHEADER(outp, f->protocol); 893 PUTCHAR(code, outp); 894 PUTCHAR(id, outp); 895 PUTSHORT(outlen, outp); 896 output(f->unit, outpacket_buf, outlen + PPP_HDRLEN); 897 } 898 899 /* 900 * fsm_setpeermru - Set our idea of the peer's mru 901 * 902 * Used by routines in lcp.c which negotiate this value. 903 */ 904 void 905 fsm_setpeermru(unit, mru) 906 int unit; 907 int mru; 908 { 909 if (unit >= NUM_PPP) { 910 dbglog("fsm_setpeermru: unit out of bounds"); 911 } else { 912 peer_mru[unit] = mru; 913 } 914 } 915