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