fsm.c
上传用户:yyhongfa
上传日期:2013-01-18
资源大小:267k
文件大小:20k
开发平台:

C/C++

  1. /*****************************************************************************
  2. * fsm.c - Network Control Protocol Finite State Machine program file.
  3. *
  4. * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
  5. * portions Copyright (c) 1997 by Global Election Systems Inc.
  6. *
  7. * The authors hereby grant permission to use, copy, modify, distribute,
  8. * and license this software and its documentation for any purpose, provided
  9. * that existing copyright notices are retained in all copies and that this
  10. * notice and the following disclaimer are included verbatim in any 
  11. * distributions. No written agreement, license, or royalty fee is required
  12. * for any of the authorized uses.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
  15. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  16. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
  17. * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  18. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  21. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. *
  25. ******************************************************************************
  26. * REVISION HISTORY
  27. *
  28. * 03-01-01 Marc Boucher <marc@mbsi.ca>
  29. *   Ported to lwIP.
  30. * 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
  31. * Original based on BSD fsm.c.
  32. *****************************************************************************/
  33. /*
  34.  * fsm.c - {Link, IP} Control Protocol Finite State Machine.
  35.  *
  36.  * Copyright (c) 1989 Carnegie Mellon University.
  37.  * All rights reserved.
  38.  *
  39.  * Redistribution and use in source and binary forms are permitted
  40.  * provided that the above copyright notice and this paragraph are
  41.  * duplicated in all such forms and that any documentation,
  42.  * advertising materials, and other materials related to such
  43.  * distribution and use acknowledge that the software was developed
  44.  * by Carnegie Mellon University.  The name of the
  45.  * University may not be used to endorse or promote products derived
  46.  * from this software without specific prior written permission.
  47.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  48.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  49.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  50.  */
  51. /*
  52.  * TODO:
  53.  * Randomize fsm id on link/init.
  54.  * Deal with variable outgoing MTU.
  55.  */
  56. #include "ppp.h"
  57. #if PPP_SUPPORT > 0
  58. #include "fsm.h"
  59. #include "pppdebug.h"
  60. #include "timer.h"
  61. #include "uart.h"
  62. /*************************/
  63. /*** LOCAL DEFINITIONS ***/
  64. /*************************/
  65. /************************/
  66. /*** LOCAL DATA TYPES ***/
  67. /************************/
  68. /***********************************/
  69. /*** LOCAL FUNCTION DECLARATIONS ***/
  70. /***********************************/
  71. static void fsm_timeout (void *);
  72. static void fsm_rconfreq (fsm *, u_char, u_char *, int);
  73. static void fsm_rconfack (fsm *, int, u_char *, int);
  74. static void fsm_rconfnakrej (fsm *, int, int, u_char *, int);
  75. static void fsm_rtermreq (fsm *, int, u_char *, int);
  76. static void fsm_rtermack (fsm *);
  77. static void fsm_rcoderej (fsm *, u_char *, int);
  78. static void fsm_sconfreq (fsm *, int);
  79. #define PROTO_NAME(f) ((f)->callbacks->proto_name)
  80. /******************************/
  81. /*** PUBLIC DATA STRUCTURES ***/
  82. /******************************/
  83. /*****************************/
  84. /*** LOCAL DATA STRUCTURES ***/
  85. /*****************************/
  86. int peer_mru[NUM_PPP];
  87. /***********************************/
  88. /*** PUBLIC FUNCTION DEFINITIONS ***/
  89. /***********************************/
  90. /*
  91.  * fsm_init - Initialize fsm.
  92.  *
  93.  * Initialize fsm state.
  94.  */
  95. void fsm_init(fsm *f)
  96. {
  97. f->state = INITIAL;
  98. f->flags = 0;
  99. f->id = 0; /* XXX Start with random id? */
  100. f->timeouttime = FSM_DEFTIMEOUT;
  101. f->maxconfreqtransmits = FSM_DEFMAXCONFREQS;
  102. f->maxtermtransmits = FSM_DEFMAXTERMREQS;
  103. f->maxnakloops = FSM_DEFMAXNAKLOOPS;
  104. f->term_reason_len = 0;
  105. }
  106. /*
  107.  * fsm_lowerup - The lower layer is up.
  108.  */
  109. void fsm_lowerup(fsm *f)
  110. {
  111. int oldState = f->state;
  112. switch( f->state ){
  113. case INITIAL:
  114. f->state = CLOSED;
  115. break;
  116. case STARTING:
  117. if( f->flags & OPT_SILENT )
  118. f->state = STOPPED;
  119. else {
  120. /* Send an initial configure-request */
  121. fsm_sconfreq(f, 0);
  122. f->state = REQSENT;
  123. }
  124. break;
  125. default:
  126. FSMDEBUG((LOG_INFO, "%s: Up event in state %d!n",
  127. PROTO_NAME(f), f->state));
  128. }
  129. FSMDEBUG((LOG_INFO, "%s: lowerup state %d -> %dn",
  130. PROTO_NAME(f), oldState, f->state));
  131. }
  132. /*
  133.  * fsm_lowerdown - The lower layer is down.
  134.  *
  135.  * Cancel all timeouts and inform upper layers.
  136.  */
  137. void fsm_lowerdown(fsm *f)
  138. {
  139. int oldState = f->state;
  140. switch( f->state ){
  141. case CLOSED:
  142. f->state = INITIAL;
  143. break;
  144. case STOPPED:
  145. f->state = STARTING;
  146. if( f->callbacks->starting )
  147. (*f->callbacks->starting)(f);
  148. break;
  149. case CLOSING:
  150. f->state = INITIAL;
  151. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  152. break;
  153. case STOPPING:
  154. case REQSENT:
  155. case ACKRCVD:
  156. case ACKSENT:
  157. f->state = STARTING;
  158. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  159. break;
  160. case OPENED:
  161. if( f->callbacks->down )
  162. (*f->callbacks->down)(f);
  163. f->state = STARTING;
  164. break;
  165. default:
  166. FSMDEBUG((LOG_INFO, "%s: Down event in state %d!n",
  167. PROTO_NAME(f), f->state));
  168. }
  169. FSMDEBUG((LOG_INFO, "%s: lowerdown state %d -> %dn",
  170. PROTO_NAME(f), oldState, f->state));
  171. }
  172. /*
  173.  * fsm_open - Link is allowed to come up.
  174.  */
  175. void fsm_open(fsm *f)
  176. {
  177. int oldState = f->state;
  178. switch( f->state ){
  179. case INITIAL:
  180. f->state = STARTING;
  181. if( f->callbacks->starting )
  182. (*f->callbacks->starting)(f);
  183. break;
  184. case CLOSED:
  185. if( f->flags & OPT_SILENT )
  186. f->state = STOPPED;
  187. else {
  188. /* Send an initial configure-request */
  189. fsm_sconfreq(f, 0);
  190. f->state = REQSENT;
  191. }
  192. break;
  193. case CLOSING:
  194. f->state = STOPPING;
  195. /* fall through */
  196. case STOPPED:
  197. case OPENED:
  198. if( f->flags & OPT_RESTART ){
  199. fsm_lowerdown(f);
  200. fsm_lowerup(f);
  201. }
  202. break;
  203. }
  204. FSMDEBUG((LOG_INFO, "%s: open state %d -> %dn",
  205. PROTO_NAME(f), oldState, f->state));
  206. }
  207. /*
  208.  * fsm_close - Start closing connection.
  209.  *
  210.  * Cancel timeouts and either initiate close or possibly go directly to
  211.  * the CLOSED state.
  212.  */
  213. void fsm_close(fsm *f, char *reason)
  214. {
  215. int oldState = f->state;
  216. f->term_reason = reason;
  217. f->term_reason_len = (reason == NULL? 0: strlen(reason));
  218. switch( f->state ){
  219. case STARTING:
  220. f->state = INITIAL;
  221. break;
  222. case STOPPED:
  223. f->state = CLOSED;
  224. break;
  225. case STOPPING:
  226. f->state = CLOSING;
  227. break;
  228. case REQSENT:
  229. case ACKRCVD:
  230. case ACKSENT:
  231. case OPENED:
  232. if( f->state != OPENED )
  233. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  234. else if( f->callbacks->down )
  235. (*f->callbacks->down)(f); /* Inform upper layers we're down */
  236. /* Init restart counter, send Terminate-Request */
  237. f->retransmits = f->maxtermtransmits;
  238. fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
  239. (u_char *) f->term_reason, f->term_reason_len);
  240. TIMEOUT(fsm_timeout, f, f->timeouttime);
  241. --f->retransmits;
  242. f->state = CLOSING;
  243. break;
  244. }
  245. FSMDEBUG((LOG_INFO, "%s: close reason=%s state %d -> %dn",
  246. PROTO_NAME(f), reason, oldState, f->state));
  247. }
  248. /*
  249.  * fsm_sdata - Send some data.
  250.  *
  251.  * Used for all packets sent to our peer by this module.
  252.  */
  253. void fsm_sdata(
  254. fsm *f,
  255. u_char code, 
  256. u_char id,
  257. u_char *data,
  258. int datalen
  259. )
  260. {
  261. u_char *outp;
  262. int outlen;
  263. /* Adjust length to be smaller than MTU */
  264. outp = outpacket_buf[f->unit];
  265. if (datalen > peer_mru[f->unit] - (int)HEADERLEN)
  266. datalen = peer_mru[f->unit] - HEADERLEN;
  267. if (datalen && data != outp + PPP_HDRLEN + HEADERLEN)
  268. BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
  269. outlen = datalen + HEADERLEN;
  270. MAKEHEADER(outp, f->protocol);
  271. PUTCHAR(code, outp);
  272. PUTCHAR(id, outp);
  273. PUTSHORT(outlen, outp);
  274. pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);
  275. FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d,%d,%d.n",
  276. PROTO_NAME(f), code, id, outlen));
  277. }
  278. /*
  279.  * fsm_input - Input packet.
  280.  */
  281. void fsm_input(fsm *f, u_char *inpacket, int l)
  282. {
  283. u_char *inp = inpacket;
  284. u_char code, id;
  285. int len;
  286. /*
  287. * Parse header (code, id and length).
  288. * If packet too short, drop it.
  289. */
  290. if (l < HEADERLEN) {
  291. FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.n",
  292. f->protocol));
  293. return;
  294. }
  295. GETCHAR(code, inp);
  296. GETCHAR(id, inp);
  297. GETSHORT(len, inp);
  298. if (len < HEADERLEN) {
  299. FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.n",
  300. f->protocol));
  301. return;
  302. }
  303. if (len > l) {
  304. FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.n",
  305. f->protocol));
  306. return;
  307. }
  308. len -= HEADERLEN; /* subtract header length */
  309. if( f->state == INITIAL || f->state == STARTING ){
  310. FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.n",
  311. f->protocol, f->state));
  312. return;
  313. }
  314. FSMDEBUG((LOG_INFO, "fsm_input(%s):%d,%d,%dn", PROTO_NAME(f), code, id, l));
  315. /*
  316.  * Action depends on code.
  317.  */
  318. switch (code) {
  319. case CONFREQ:
  320. fsm_rconfreq(f, id, inp, len);
  321. break;
  322. case CONFACK:
  323. fsm_rconfack(f, id, inp, len);
  324. break;
  325. case CONFNAK:
  326. case CONFREJ:
  327. fsm_rconfnakrej(f, code, id, inp, len);
  328. break;
  329. case TERMREQ:
  330. fsm_rtermreq(f, id, inp, len);
  331. break;
  332. case TERMACK:
  333. fsm_rtermack(f);
  334. break;
  335. case CODEREJ:
  336. fsm_rcoderej(f, inp, len);
  337. break;
  338. default:
  339. if( !f->callbacks->extcode
  340. || !(*f->callbacks->extcode)(f, code, id, inp, len) )
  341. fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
  342. break;
  343. }
  344. }
  345. /*
  346.  * fsm_protreject - Peer doesn't speak this protocol.
  347.  *
  348.  * Treat this as a catastrophic error (RXJ-).
  349.  */
  350. void fsm_protreject(fsm *f)
  351. {
  352. switch( f->state ){
  353. case CLOSING:
  354. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  355. /* fall through */
  356. case CLOSED:
  357. f->state = CLOSED;
  358. if( f->callbacks->finished )
  359. (*f->callbacks->finished)(f);
  360. break;
  361. case STOPPING:
  362. case REQSENT:
  363. case ACKRCVD:
  364. case ACKSENT:
  365. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  366. /* fall through */
  367. case STOPPED:
  368. f->state = STOPPED;
  369. if( f->callbacks->finished )
  370. (*f->callbacks->finished)(f);
  371. break;
  372. case OPENED:
  373. if( f->callbacks->down )
  374. (*f->callbacks->down)(f);
  375. /* Init restart counter, send Terminate-Request */
  376. f->retransmits = f->maxtermtransmits;
  377. fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
  378. (u_char *) f->term_reason, f->term_reason_len);
  379. TIMEOUT(fsm_timeout, f, f->timeouttime);
  380. --f->retransmits;
  381. f->state = STOPPING;
  382. break;
  383. default:
  384. FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!n",
  385. PROTO_NAME(f), f->state));
  386. }
  387. }
  388. /**********************************/
  389. /*** LOCAL FUNCTION DEFINITIONS ***/
  390. /**********************************/
  391. /*
  392.  * fsm_timeout - Timeout expired.
  393.  */
  394. static void fsm_timeout(void *arg)
  395. {
  396.     fsm *f = (fsm *) arg;
  397.    DEBUG_FUNCTION(" fsm_timeout()")
  398.     switch (f->state) {
  399.     case CLOSING:
  400.     case STOPPING:
  401. if( f->retransmits <= 0 ){
  402.     FSMDEBUG((LOG_WARNING, "%s: timeout sending Terminate-Request state=%dn",
  403.    PROTO_NAME(f), f->state));
  404.     /*
  405.      * We've waited for an ack long enough.  Peer probably heard us.
  406.      */
  407.     f->state = (f->state == CLOSING)? CLOSED: STOPPED;
  408.     if( f->callbacks->finished )
  409. (*f->callbacks->finished)(f);
  410.  /*
  411.          *added by zhouzhigang 2006.01.22 to delete lcp timer
  412.   */
  413.         UNTIMEOUT(fsm_timeout, f);
  414. } else {
  415.     FSMDEBUG((LOG_WARNING, "%s: timeout resending Terminate-Requests state=%dn",
  416.    PROTO_NAME(f), f->state));
  417.     /* Send Terminate-Request */
  418.     fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
  419.       (u_char *) f->term_reason, f->term_reason_len);
  420.     TIMEOUT(fsm_timeout, f, f->timeouttime);
  421.     --f->retransmits;
  422. }
  423. break;
  424.     case REQSENT:
  425.     case ACKRCVD:
  426.     case ACKSENT:
  427. if (f->retransmits <= 0) {
  428.     FSMDEBUG((LOG_WARNING, "%s: timeout sending Config-Requests state=%dn",
  429.    PROTO_NAME(f), f->state));
  430.     f->state = STOPPED;
  431.     if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
  432. (*f->callbacks->finished)(f);
  433.  /*
  434.    *added by zhouzhigang 2006.01.22 to delete lcp timer
  435.          */
  436. UNTIMEOUT(fsm_timeout, f);
  437. } else {
  438.     FSMDEBUG((LOG_WARNING, "%s: timeout resending Config-Request state=%dn",
  439.    PROTO_NAME(f), f->state));
  440.     /* Retransmit the configure-request */
  441.     if (f->callbacks->retransmit)
  442. (*f->callbacks->retransmit)(f);
  443.     fsm_sconfreq(f, 1); /* Re-send Configure-Request */
  444.     if( f->state == ACKRCVD )
  445. f->state = REQSENT;
  446. }
  447. break;
  448.     default:
  449. FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d!n",
  450.   PROTO_NAME(f), f->state));
  451.  /*
  452.           *added by zhouzhigang 2006.01.22 to delete lcp timer
  453.  */
  454.         UNTIMEOUT(fsm_timeout, f);
  455.     }
  456. }
  457. /*
  458.  * fsm_rconfreq - Receive Configure-Request.
  459.  */
  460. static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)
  461. {
  462. int code, reject_if_disagree;
  463. FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d state=%dn", 
  464. PROTO_NAME(f), id, f->state));
  465. switch( f->state ){
  466. case CLOSED:
  467. /* Go away, we're closed */
  468. fsm_sdata(f, TERMACK, id, NULL, 0);
  469. return;
  470. case CLOSING:
  471. case STOPPING:
  472. return;
  473. case OPENED:
  474. /* Go down and restart negotiation */
  475. if( f->callbacks->down )
  476. (*f->callbacks->down)(f); /* Inform upper layers */
  477. fsm_sconfreq(f, 0); /* Send initial Configure-Request */
  478. break;
  479. case STOPPED:
  480. /* Negotiation started by our peer */
  481. fsm_sconfreq(f, 0); /* Send initial Configure-Request */
  482. f->state = REQSENT;
  483. break;
  484. }
  485. /*
  486. * Pass the requested configuration options
  487. * to protocol-specific code for checking.
  488. */
  489. if (f->callbacks->reqci){ /* Check CI */
  490. reject_if_disagree = (f->nakloops >= f->maxnakloops);
  491. code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
  492. else if (len)
  493. code = CONFREJ; /* Reject all CI */
  494. else
  495. code = CONFACK;
  496. /* send the Ack, Nak or Rej to the peer */
  497. fsm_sdata(f, (u_char)code, id, inp, len);
  498. if (code == CONFACK) {
  499. if (f->state == ACKRCVD) {
  500. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  501. f->state = OPENED;
  502. if (f->callbacks->up)
  503. (*f->callbacks->up)(f); /* Inform upper layers */
  504. else
  505. f->state = ACKSENT;
  506. f->nakloops = 0;
  507. else {
  508. /* we sent CONFACK or CONFREJ */
  509. if (f->state != ACKRCVD)
  510. f->state = REQSENT;
  511. if( code == CONFNAK )
  512. ++f->nakloops;
  513. }
  514. }
  515. /*
  516.  * fsm_rconfack - Receive Configure-Ack.
  517.  */
  518. static void fsm_rconfack(fsm *f, int id, u_char *inp, int len)
  519. {
  520. FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d state=%dn",
  521. PROTO_NAME(f), id, f->state));
  522. if (id != f->reqid || f->seen_ack) /* Expected id? */
  523. return; /* Nope, toss... */
  524. if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len):
  525. (len == 0)) ){
  526. /* Ack is bad - ignore it */
  527. FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)n",
  528. PROTO_NAME(f), len));
  529. return;
  530. }
  531. f->seen_ack = 1;
  532. switch (f->state) {
  533. case CLOSED:
  534. case STOPPED:
  535. fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
  536. break;
  537. case REQSENT:
  538. f->state = ACKRCVD;
  539. f->retransmits = f->maxconfreqtransmits;
  540. break;
  541. case ACKRCVD:
  542. /* Huh? an extra valid Ack? oh well... */
  543. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  544. fsm_sconfreq(f, 0);
  545. f->state = REQSENT;
  546. break;
  547. case ACKSENT:
  548. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  549. f->state = OPENED;
  550. f->retransmits = f->maxconfreqtransmits;
  551. if (f->callbacks->up)
  552. (*f->callbacks->up)(f); /* Inform upper layers */
  553. break;
  554. case OPENED:
  555. /* Go down and restart negotiation */
  556. if (f->callbacks->down)
  557. (*f->callbacks->down)(f); /* Inform upper layers */
  558. fsm_sconfreq(f, 0); /* Send initial Configure-Request */
  559. f->state = REQSENT;
  560. break;
  561. }
  562. }
  563. /*
  564.  * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
  565.  */
  566. static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)
  567. {
  568. int (*proc) (fsm *, u_char *, int);
  569. int ret;
  570. FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d state=%dn",
  571. PROTO_NAME(f), id, f->state));
  572. if (id != f->reqid || f->seen_ack) /* Expected id? */
  573. return; /* Nope, toss... */
  574. proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
  575. if (!proc || !(ret = proc(f, inp, len))) {
  576. /* Nak/reject is bad - ignore it */
  577. FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)n",
  578. PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
  579. return;
  580. }
  581. f->seen_ack = 1;
  582. switch (f->state) {
  583. case CLOSED:
  584. case STOPPED:
  585. fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
  586. break;
  587. case REQSENT:
  588. case ACKSENT:
  589. /* They didn't agree to what we wanted - try another request */
  590. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  591. if (ret < 0)
  592. f->state = STOPPED; /* kludge for stopping CCP */
  593. else
  594. fsm_sconfreq(f, 0); /* Send Configure-Request */
  595. break;
  596. case ACKRCVD:
  597. /* Got a Nak/reject when we had already had an Ack?? oh well... */
  598. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  599. fsm_sconfreq(f, 0);
  600. f->state = REQSENT;
  601. break;
  602. case OPENED:
  603. /* Go down and restart negotiation */
  604. if (f->callbacks->down)
  605. (*f->callbacks->down)(f); /* Inform upper layers */
  606. fsm_sconfreq(f, 0); /* Send initial Configure-Request */
  607. f->state = REQSENT;
  608. break;
  609. }
  610. }
  611. /*
  612.  * fsm_rtermreq - Receive Terminate-Req.
  613.  */
  614. static void fsm_rtermreq(fsm *f, int id, u_char *p, int len)
  615. {
  616. FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d state=%dn",
  617. PROTO_NAME(f), id, f->state));
  618. switch (f->state) {
  619. case ACKRCVD:
  620. case ACKSENT:
  621. f->state = REQSENT; /* Start over but keep trying */
  622. break;
  623. case OPENED:
  624. if (len > 0) {
  625. FSMDEBUG((LOG_INFO, "%s terminated by peer (%x)n", PROTO_NAME(f), p));
  626. } else {
  627. FSMDEBUG((LOG_INFO, "%s terminated by peern", PROTO_NAME(f)));
  628. }
  629. if (f->callbacks->down)
  630. (*f->callbacks->down)(f); /* Inform upper layers */
  631. f->retransmits = 0;
  632. f->state = STOPPING;
  633. TIMEOUT(fsm_timeout, f, f->timeouttime);
  634. break;
  635. }
  636. fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
  637. }
  638. /*
  639.  * fsm_rtermack - Receive Terminate-Ack.
  640.  */
  641. static void fsm_rtermack(fsm *f)
  642. {
  643. FSMDEBUG((LOG_INFO, "fsm_rtermack(%s): state=%dn", 
  644. PROTO_NAME(f), f->state));
  645. switch (f->state) {
  646. case CLOSING:
  647. UNTIMEOUT(fsm_timeout, f);
  648. f->state = CLOSED;
  649. if( f->callbacks->finished )
  650. (*f->callbacks->finished)(f);
  651. break;
  652. case STOPPING:
  653. UNTIMEOUT(fsm_timeout, f);
  654. f->state = STOPPED;
  655. if( f->callbacks->finished )
  656. (*f->callbacks->finished)(f);
  657. break;
  658. case ACKRCVD:
  659. f->state = REQSENT;
  660. break;
  661. case OPENED:
  662. if (f->callbacks->down)
  663. (*f->callbacks->down)(f); /* Inform upper layers */
  664. fsm_sconfreq(f, 0);
  665. break;
  666. }
  667. }
  668. /*
  669.  * fsm_rcoderej - Receive an Code-Reject.
  670.  */
  671. static void fsm_rcoderej(fsm *f, u_char *inp, int len)
  672. {
  673. u_char code, id;
  674. FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s): state=%dn", 
  675. PROTO_NAME(f), f->state));
  676. if (len < HEADERLEN) {
  677. FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!n"));
  678. return;
  679. }
  680. GETCHAR(code, inp);
  681. GETCHAR(id, inp);
  682. FSMDEBUG((LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %dn",
  683. PROTO_NAME(f), code, id));
  684. if( f->state == ACKRCVD )
  685. f->state = REQSENT;
  686. }
  687. /*
  688.  * fsm_sconfreq - Send a Configure-Request.
  689.  */
  690. static void fsm_sconfreq(fsm *f, int retransmit)
  691. {
  692. u_char *outp;
  693. int cilen;
  694. if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
  695. /* Not currently negotiating - reset options */
  696. if( f->callbacks->resetci )
  697. (*f->callbacks->resetci)(f);/* void lcp_resetci(fsm *f)  */
  698. f->nakloops = 0;
  699. }
  700. if( !retransmit ){
  701. /* New request - reset retransmission counter, use new ID */
  702. f->retransmits = f->maxconfreqtransmits;
  703. f->reqid = ++f->id;
  704. }
  705. f->seen_ack = 0;
  706. /*
  707.  * Make up the request packet
  708.  */
  709. outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN;
  710. if( f->callbacks->cilen && f->callbacks->addci ){
  711. cilen = (*f->callbacks->cilen)(f);                              /*lcp_cilen()*/
  712. if( cilen > peer_mru[f->unit] - (int)HEADERLEN )
  713. cilen = peer_mru[f->unit] - HEADERLEN;
  714. if (f->callbacks->addci)
  715. (*f->callbacks->addci)(f, outp, &cilen);
  716. } else
  717. cilen = 0;
  718. /* send the request to our peer */
  719. fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
  720. /* start the retransmit timer */
  721. --f->retransmits;
  722. TIMEOUT(fsm_timeout, f, f->timeouttime);
  723. FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %dn",
  724. PROTO_NAME(f), f->reqid));
  725. }
  726. #endif /* PPP_SUPPORT */