fsm.c 18 KB

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