1 /* $OpenBSD: fsm.c,v 1.7 2002/07/01 19:31:37 deraadt Exp $ */ 2 3 /* 4 * fsm.c - {Link, IP} Control Protocol Finite State Machine. 5 * 6 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. The name "Carnegie Mellon University" must not be used to 21 * endorse or promote products derived from this software without 22 * prior written permission. For permission or any legal 23 * details, please contact 24 * Office of Technology Transfer 25 * Carnegie Mellon University 26 * 5000 Forbes Avenue 27 * Pittsburgh, PA 15213-3890 28 * (412) 268-4387, fax: (412) 268-7395 29 * tech-transfer@andrew.cmu.edu 30 * 31 * 4. Redistributions of any form whatsoever must retain the following 32 * acknowledgment: 33 * "This product includes software developed by Computing Services 34 * at Carnegie Mellon University (http://www.cmu.edu/computing/)." 35 * 36 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO 37 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 38 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 39 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 40 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 41 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 42 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 43 */ 44 45 #ifndef lint 46 #if 0 47 static char rcsid[] = "Id: fsm.c,v 1.13 1997/04/30 05:52:17 paulus Exp"; 48 #else 49 static char rcsid[] = "$OpenBSD: fsm.c,v 1.7 2002/07/01 19:31:37 deraadt Exp $"; 50 #endif 51 #endif 52 53 /* 54 * TODO: 55 * Randomize fsm id on link/init. 56 * Deal with variable outgoing MTU. 57 */ 58 59 #include <stdio.h> 60 #include <string.h> 61 #include <sys/types.h> 62 #include <syslog.h> 63 64 #include "pppd.h" 65 #include "fsm.h" 66 67 static void fsm_timeout(void *); 68 static void fsm_rconfreq(fsm *, int, u_char *, int); 69 static void fsm_rconfack(fsm *, int, u_char *, int); 70 static void fsm_rconfnakrej(fsm *, int, int, u_char *, int); 71 static void fsm_rtermreq(fsm *, int, u_char *, int); 72 static void fsm_rtermack(fsm *); 73 static void fsm_rcoderej(fsm *, u_char *, int); 74 static void fsm_sconfreq(fsm *, int); 75 76 #define PROTO_NAME(f) ((f)->callbacks->proto_name) 77 78 int peer_mru[NUM_PPP]; 79 80 81 /* 82 * fsm_init - Initialize fsm. 83 * 84 * Initialize fsm state. 85 */ 86 void 87 fsm_init(f) 88 fsm *f; 89 { 90 f->state = INITIAL; 91 f->flags = 0; 92 f->id = 0; /* XXX Start with random id? */ 93 f->timeouttime = DEFTIMEOUT; 94 f->maxconfreqtransmits = DEFMAXCONFREQS; 95 f->maxtermtransmits = DEFMAXTERMREQS; 96 f->maxnakloops = DEFMAXNAKLOOPS; 97 f->term_reason_len = 0; 98 } 99 100 101 /* 102 * fsm_lowerup - The lower layer is up. 103 */ 104 void 105 fsm_lowerup(f) 106 fsm *f; 107 { 108 switch( f->state ){ 109 case INITIAL: 110 f->state = CLOSED; 111 break; 112 113 case STARTING: 114 if( f->flags & OPT_SILENT ) 115 f->state = STOPPED; 116 else { 117 /* Send an initial configure-request */ 118 fsm_sconfreq(f, 0); 119 f->state = REQSENT; 120 } 121 break; 122 123 default: 124 FSMDEBUG((LOG_INFO, "%s: Up event in state %d!", 125 PROTO_NAME(f), f->state)); 126 } 127 } 128 129 130 /* 131 * fsm_lowerdown - The lower layer is down. 132 * 133 * Cancel all timeouts and inform upper layers. 134 */ 135 void 136 fsm_lowerdown(f) 137 fsm *f; 138 { 139 switch( f->state ){ 140 case CLOSED: 141 f->state = INITIAL; 142 break; 143 144 case STOPPED: 145 f->state = STARTING; 146 if( f->callbacks->starting ) 147 (*f->callbacks->starting)(f); 148 break; 149 150 case CLOSING: 151 f->state = INITIAL; 152 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 153 break; 154 155 case STOPPING: 156 case REQSENT: 157 case ACKRCVD: 158 case ACKSENT: 159 f->state = STARTING; 160 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 161 break; 162 163 case OPENED: 164 if( f->callbacks->down ) 165 (*f->callbacks->down)(f); 166 f->state = STARTING; 167 break; 168 169 default: 170 FSMDEBUG((LOG_INFO, "%s: Down event in state %d!", 171 PROTO_NAME(f), f->state)); 172 } 173 } 174 175 176 /* 177 * fsm_open - Link is allowed to come up. 178 */ 179 void 180 fsm_open(f) 181 fsm *f; 182 { 183 switch( f->state ){ 184 case INITIAL: 185 f->state = STARTING; 186 if( f->callbacks->starting ) 187 (*f->callbacks->starting)(f); 188 break; 189 190 case CLOSED: 191 if( f->flags & OPT_SILENT ) 192 f->state = STOPPED; 193 else { 194 /* Send an initial configure-request */ 195 fsm_sconfreq(f, 0); 196 f->state = REQSENT; 197 } 198 break; 199 200 case CLOSING: 201 f->state = STOPPING; 202 /* fall through */ 203 case STOPPED: 204 case OPENED: 205 if( f->flags & OPT_RESTART ){ 206 fsm_lowerdown(f); 207 fsm_lowerup(f); 208 } 209 break; 210 } 211 } 212 213 214 /* 215 * fsm_close - Start closing connection. 216 * 217 * Cancel timeouts and either initiate close or possibly go directly to 218 * the CLOSED state. 219 */ 220 void 221 fsm_close(f, reason) 222 fsm *f; 223 char *reason; 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 break; 231 case STOPPED: 232 f->state = CLOSED; 233 break; 234 case STOPPING: 235 f->state = CLOSING; 236 break; 237 238 case REQSENT: 239 case ACKRCVD: 240 case ACKSENT: 241 case OPENED: 242 if( f->state != OPENED ) 243 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 244 else if( f->callbacks->down ) 245 (*f->callbacks->down)(f); /* Inform upper layers we're down */ 246 247 /* Init restart counter, send Terminate-Request */ 248 f->retransmits = f->maxtermtransmits; 249 fsm_sdata(f, TERMREQ, f->reqid = ++f->id, 250 (u_char *) f->term_reason, f->term_reason_len); 251 TIMEOUT(fsm_timeout, f, f->timeouttime); 252 --f->retransmits; 253 254 f->state = CLOSING; 255 break; 256 } 257 } 258 259 260 /* 261 * fsm_timeout - Timeout expired. 262 */ 263 static void 264 fsm_timeout(arg) 265 void *arg; 266 { 267 fsm *f = (fsm *) arg; 268 269 switch (f->state) { 270 case CLOSING: 271 case STOPPING: 272 if( f->retransmits <= 0 ){ 273 /* 274 * We've waited for an ack long enough. Peer probably heard us. 275 */ 276 f->state = (f->state == CLOSING)? CLOSED: STOPPED; 277 if( f->callbacks->finished ) 278 (*f->callbacks->finished)(f); 279 } else { 280 /* Send Terminate-Request */ 281 fsm_sdata(f, TERMREQ, f->reqid = ++f->id, 282 (u_char *) f->term_reason, f->term_reason_len); 283 TIMEOUT(fsm_timeout, f, f->timeouttime); 284 --f->retransmits; 285 } 286 break; 287 288 case REQSENT: 289 case ACKRCVD: 290 case ACKSENT: 291 if (f->retransmits <= 0) { 292 syslog(LOG_WARNING, "%s: timeout sending Config-Requests", 293 PROTO_NAME(f)); 294 f->state = STOPPED; 295 if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) 296 (*f->callbacks->finished)(f); 297 298 } else { 299 /* Retransmit the configure-request */ 300 if (f->callbacks->retransmit) 301 (*f->callbacks->retransmit)(f); 302 fsm_sconfreq(f, 1); /* Re-send Configure-Request */ 303 if( f->state == ACKRCVD ) 304 f->state = REQSENT; 305 } 306 break; 307 308 default: 309 FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d!", 310 PROTO_NAME(f), f->state)); 311 } 312 } 313 314 315 /* 316 * fsm_input - Input packet. 317 */ 318 void 319 fsm_input(f, inpacket, l) 320 fsm *f; 321 u_char *inpacket; 322 int l; 323 { 324 u_char *inp; 325 u_char code, id; 326 int len; 327 328 /* 329 * Parse header (code, id and length). 330 * If packet too short, drop it. 331 */ 332 inp = inpacket; 333 if (l < HEADERLEN) { 334 FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.", 335 f->protocol)); 336 return; 337 } 338 GETCHAR(code, inp); 339 GETCHAR(id, inp); 340 GETSHORT(len, inp); 341 if (len < HEADERLEN) { 342 FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.", 343 f->protocol)); 344 return; 345 } 346 if (len > l) { 347 FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.", 348 f->protocol)); 349 return; 350 } 351 len -= HEADERLEN; /* subtract header length */ 352 353 if( f->state == INITIAL || f->state == STARTING ){ 354 FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.", 355 f->protocol, f->state)); 356 return; 357 } 358 359 /* 360 * Action depends on code. 361 */ 362 switch (code) { 363 case CONFREQ: 364 fsm_rconfreq(f, id, inp, len); 365 break; 366 367 case CONFACK: 368 fsm_rconfack(f, id, inp, len); 369 break; 370 371 case CONFNAK: 372 case CONFREJ: 373 fsm_rconfnakrej(f, code, id, inp, len); 374 break; 375 376 case TERMREQ: 377 fsm_rtermreq(f, id, inp, len); 378 break; 379 380 case TERMACK: 381 fsm_rtermack(f); 382 break; 383 384 case CODEREJ: 385 fsm_rcoderej(f, inp, len); 386 break; 387 388 default: 389 if( !f->callbacks->extcode 390 || !(*f->callbacks->extcode)(f, code, id, inp, len) ) 391 fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); 392 break; 393 } 394 } 395 396 397 /* 398 * fsm_rconfreq - Receive Configure-Request. 399 */ 400 static void 401 fsm_rconfreq(f, id, inp, len) 402 fsm *f; 403 u_char id; 404 u_char *inp; 405 int len; 406 { 407 int code, reject_if_disagree; 408 409 FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d.", PROTO_NAME(f), id)); 410 switch( f->state ){ 411 case CLOSED: 412 /* Go away, we're closed */ 413 fsm_sdata(f, TERMACK, id, NULL, 0); 414 return; 415 case CLOSING: 416 case STOPPING: 417 return; 418 419 case OPENED: 420 /* Go down and restart negotiation */ 421 if( f->callbacks->down ) 422 (*f->callbacks->down)(f); /* Inform upper layers */ 423 fsm_sconfreq(f, 0); /* Send initial Configure-Request */ 424 break; 425 426 case STOPPED: 427 /* Negotiation started by our peer */ 428 fsm_sconfreq(f, 0); /* Send initial Configure-Request */ 429 f->state = REQSENT; 430 break; 431 } 432 433 /* 434 * Pass the requested configuration options 435 * to protocol-specific code for checking. 436 */ 437 if (f->callbacks->reqci){ /* Check CI */ 438 reject_if_disagree = (f->nakloops >= f->maxnakloops); 439 code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree); 440 } else if (len) 441 code = CONFREJ; /* Reject all CI */ 442 else 443 code = CONFACK; 444 445 /* send the Ack, Nak or Rej to the peer */ 446 fsm_sdata(f, code, id, inp, len); 447 448 if (code == CONFACK) { 449 if (f->state == ACKRCVD) { 450 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 451 f->state = OPENED; 452 if (f->callbacks->up) 453 (*f->callbacks->up)(f); /* Inform upper layers */ 454 } else 455 f->state = ACKSENT; 456 f->nakloops = 0; 457 458 } else { 459 /* we sent CONFACK or CONFREJ */ 460 if (f->state != ACKRCVD) 461 f->state = REQSENT; 462 if( code == CONFNAK ) 463 ++f->nakloops; 464 } 465 } 466 467 468 /* 469 * fsm_rconfack - Receive Configure-Ack. 470 */ 471 static void 472 fsm_rconfack(f, id, inp, len) 473 fsm *f; 474 int id; 475 u_char *inp; 476 int len; 477 { 478 FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d.", 479 PROTO_NAME(f), id)); 480 481 if (id != f->reqid || f->seen_ack) /* Expected id? */ 482 return; /* Nope, toss... */ 483 if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): 484 (len == 0)) ){ 485 /* Ack is bad - ignore it */ 486 log_packet(inp, len, "Received bad configure-ack: ", LOG_ERR); 487 FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)", 488 PROTO_NAME(f), len)); 489 return; 490 } 491 f->seen_ack = 1; 492 493 switch (f->state) { 494 case CLOSED: 495 case STOPPED: 496 fsm_sdata(f, TERMACK, id, NULL, 0); 497 break; 498 499 case REQSENT: 500 f->state = ACKRCVD; 501 f->retransmits = f->maxconfreqtransmits; 502 break; 503 504 case ACKRCVD: 505 /* Huh? an extra valid Ack? oh well... */ 506 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 507 fsm_sconfreq(f, 0); 508 f->state = REQSENT; 509 break; 510 511 case ACKSENT: 512 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 513 f->state = OPENED; 514 f->retransmits = f->maxconfreqtransmits; 515 if (f->callbacks->up) 516 (*f->callbacks->up)(f); /* Inform upper layers */ 517 break; 518 519 case OPENED: 520 /* Go down and restart negotiation */ 521 if (f->callbacks->down) 522 (*f->callbacks->down)(f); /* Inform upper layers */ 523 fsm_sconfreq(f, 0); /* Send initial Configure-Request */ 524 f->state = REQSENT; 525 break; 526 } 527 } 528 529 530 /* 531 * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. 532 */ 533 static void 534 fsm_rconfnakrej(f, code, id, inp, len) 535 fsm *f; 536 int code, id; 537 u_char *inp; 538 int len; 539 { 540 int (*proc)(fsm *, u_char *, int); 541 int ret; 542 543 FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d.", 544 PROTO_NAME(f), id)); 545 546 if (id != f->reqid || f->seen_ack) /* Expected id? */ 547 return; /* Nope, toss... */ 548 proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci; 549 if (!proc || !(ret = proc(f, inp, len))) { 550 /* Nak/reject is bad - ignore it */ 551 log_packet(inp, len, "Received bad configure-nak/rej: ", LOG_ERR); 552 FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)", 553 PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len)); 554 return; 555 } 556 f->seen_ack = 1; 557 558 switch (f->state) { 559 case CLOSED: 560 case STOPPED: 561 fsm_sdata(f, TERMACK, id, NULL, 0); 562 break; 563 564 case REQSENT: 565 case ACKSENT: 566 /* They didn't agree to what we wanted - try another request */ 567 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 568 if (ret < 0) 569 f->state = STOPPED; /* kludge for stopping CCP */ 570 else 571 fsm_sconfreq(f, 0); /* Send Configure-Request */ 572 break; 573 574 case ACKRCVD: 575 /* Got a Nak/reject when we had already had an Ack?? oh well... */ 576 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 577 fsm_sconfreq(f, 0); 578 f->state = REQSENT; 579 break; 580 581 case OPENED: 582 /* Go down and restart negotiation */ 583 if (f->callbacks->down) 584 (*f->callbacks->down)(f); /* Inform upper layers */ 585 fsm_sconfreq(f, 0); /* Send initial Configure-Request */ 586 f->state = REQSENT; 587 break; 588 } 589 } 590 591 592 /* 593 * fsm_rtermreq - Receive Terminate-Req. 594 */ 595 static void 596 fsm_rtermreq(f, id, p, len) 597 fsm *f; 598 int id; 599 u_char *p; 600 int len; 601 { 602 char str[80]; 603 604 FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d.", 605 PROTO_NAME(f), id)); 606 607 switch (f->state) { 608 case ACKRCVD: 609 case ACKSENT: 610 f->state = REQSENT; /* Start over but keep trying */ 611 break; 612 613 case OPENED: 614 if (len > 0) { 615 fmtmsg(str, sizeof(str), "%0.*v", len, p); 616 syslog(LOG_INFO, "%s terminated by peer (%s)", PROTO_NAME(f), str); 617 } else 618 syslog(LOG_INFO, "%s terminated by peer", PROTO_NAME(f)); 619 if (f->callbacks->down) 620 (*f->callbacks->down)(f); /* Inform upper layers */ 621 f->retransmits = 0; 622 f->state = STOPPING; 623 TIMEOUT(fsm_timeout, f, f->timeouttime); 624 break; 625 } 626 627 fsm_sdata(f, TERMACK, id, NULL, 0); 628 } 629 630 631 /* 632 * fsm_rtermack - Receive Terminate-Ack. 633 */ 634 static void 635 fsm_rtermack(f) 636 fsm *f; 637 { 638 FSMDEBUG((LOG_INFO, "fsm_rtermack(%s).", PROTO_NAME(f))); 639 640 switch (f->state) { 641 case CLOSING: 642 UNTIMEOUT(fsm_timeout, f); 643 f->state = CLOSED; 644 if( f->callbacks->finished ) 645 (*f->callbacks->finished)(f); 646 break; 647 case STOPPING: 648 UNTIMEOUT(fsm_timeout, f); 649 f->state = STOPPED; 650 if( f->callbacks->finished ) 651 (*f->callbacks->finished)(f); 652 break; 653 654 case ACKRCVD: 655 f->state = REQSENT; 656 break; 657 658 case OPENED: 659 if (f->callbacks->down) 660 (*f->callbacks->down)(f); /* Inform upper layers */ 661 fsm_sconfreq(f, 0); 662 break; 663 } 664 } 665 666 667 /* 668 * fsm_rcoderej - Receive an Code-Reject. 669 */ 670 static void 671 fsm_rcoderej(f, inp, len) 672 fsm *f; 673 u_char *inp; 674 int len; 675 { 676 u_char code, id; 677 678 FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s).", PROTO_NAME(f))); 679 680 if (len < HEADERLEN) { 681 FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!")); 682 return; 683 } 684 GETCHAR(code, inp); 685 GETCHAR(id, inp); 686 syslog(LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d", 687 PROTO_NAME(f), code, id); 688 689 if( f->state == ACKRCVD ) 690 f->state = REQSENT; 691 } 692 693 694 /* 695 * fsm_protreject - Peer doesn't speak this protocol. 696 * 697 * Treat this as a catastrophic error (RXJ-). 698 */ 699 void 700 fsm_protreject(f) 701 fsm *f; 702 { 703 switch( f->state ){ 704 case CLOSING: 705 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 706 /* fall through */ 707 case CLOSED: 708 f->state = CLOSED; 709 if( f->callbacks->finished ) 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 /* fall through */ 719 case STOPPED: 720 f->state = STOPPED; 721 if( f->callbacks->finished ) 722 (*f->callbacks->finished)(f); 723 break; 724 725 case OPENED: 726 if( f->callbacks->down ) 727 (*f->callbacks->down)(f); 728 729 /* Init restart counter, send Terminate-Request */ 730 f->retransmits = f->maxtermtransmits; 731 fsm_sdata(f, TERMREQ, f->reqid = ++f->id, 732 (u_char *) f->term_reason, f->term_reason_len); 733 TIMEOUT(fsm_timeout, f, f->timeouttime); 734 --f->retransmits; 735 736 f->state = STOPPING; 737 break; 738 739 default: 740 FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!", 741 PROTO_NAME(f), f->state)); 742 } 743 } 744 745 746 /* 747 * fsm_sconfreq - Send a Configure-Request. 748 */ 749 static void 750 fsm_sconfreq(f, retransmit) 751 fsm *f; 752 int retransmit; 753 { 754 u_char *outp; 755 int cilen; 756 757 if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){ 758 /* Not currently negotiating - reset options */ 759 if( f->callbacks->resetci ) 760 (*f->callbacks->resetci)(f); 761 f->nakloops = 0; 762 } 763 764 if( !retransmit ){ 765 /* New request - reset retransmission counter, use new ID */ 766 f->retransmits = f->maxconfreqtransmits; 767 f->reqid = ++f->id; 768 } 769 770 f->seen_ack = 0; 771 772 /* 773 * Make up the request packet 774 */ 775 outp = outpacket_buf + PPP_HDRLEN + HEADERLEN; 776 if( f->callbacks->cilen && f->callbacks->addci ){ 777 cilen = (*f->callbacks->cilen)(f); 778 if( cilen > peer_mru[f->unit] - HEADERLEN ) 779 cilen = peer_mru[f->unit] - HEADERLEN; 780 if (f->callbacks->addci) 781 (*f->callbacks->addci)(f, outp, &cilen); 782 } else 783 cilen = 0; 784 785 /* send the request to our peer */ 786 fsm_sdata(f, CONFREQ, f->reqid, outp, cilen); 787 788 /* start the retransmit timer */ 789 --f->retransmits; 790 TIMEOUT(fsm_timeout, f, f->timeouttime); 791 792 FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d", 793 PROTO_NAME(f), f->reqid)); 794 } 795 796 797 /* 798 * fsm_sdata - Send some data. 799 * 800 * Used for all packets sent to our peer by this module. 801 */ 802 void 803 fsm_sdata(f, code, id, data, datalen) 804 fsm *f; 805 u_char code, id; 806 u_char *data; 807 int datalen; 808 { 809 u_char *outp; 810 int outlen; 811 812 /* Adjust length to be smaller than MTU */ 813 outp = outpacket_buf; 814 if (datalen > peer_mru[f->unit] - HEADERLEN) 815 datalen = peer_mru[f->unit] - HEADERLEN; 816 if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) 817 BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen); 818 outlen = datalen + HEADERLEN; 819 MAKEHEADER(outp, f->protocol); 820 PUTCHAR(code, outp); 821 PUTCHAR(id, outp); 822 PUTSHORT(outlen, outp); 823 output(f->unit, outpacket_buf, outlen + PPP_HDRLEN); 824 825 FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d, id %d.", 826 PROTO_NAME(f), code, id)); 827 } 828