fsm.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  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 "lwip/opt.h"
  57. #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
  58. #include "ppp_impl.h"
  59. #include "pppdebug.h"
  60. #include "fsm.h"
  61. #include <string.h>
  62. #if PPP_DEBUG
  63. static const char *ppperr_strerr[] = {
  64. "LS_INITIAL", /* LS_INITIAL 0 */
  65. "LS_STARTING", /* LS_STARTING 1 */
  66. "LS_CLOSED", /* LS_CLOSED 2 */
  67. "LS_STOPPED", /* LS_STOPPED 3 */
  68. "LS_CLOSING", /* LS_CLOSING 4 */
  69. "LS_STOPPING", /* LS_STOPPING 5 */
  70. "LS_REQSENT", /* LS_REQSENT 6 */
  71. "LS_ACKRCVD", /* LS_ACKRCVD 7 */
  72. "LS_ACKSENT", /* LS_ACKSENT 8 */
  73. "LS_OPENED" /* LS_OPENED 9 */
  74. };
  75. #endif /* PPP_DEBUG */
  76. static void fsm_timeout (void *);
  77. static void fsm_rconfreq (fsm *, u_char, u_char *, int);
  78. static void fsm_rconfack (fsm *, int, u_char *, int);
  79. static void fsm_rconfnakrej (fsm *, int, int, u_char *, int);
  80. static void fsm_rtermreq (fsm *, int, u_char *, int);
  81. static void fsm_rtermack (fsm *);
  82. static void fsm_rcoderej (fsm *, u_char *, int);
  83. static void fsm_sconfreq (fsm *, int);
  84. #define PROTO_NAME(f) ((f)->callbacks->proto_name)
  85. int peer_mru[NUM_PPP];
  86. /*
  87. * fsm_init - Initialize fsm.
  88. *
  89. * Initialize fsm state.
  90. */
  91. void
  92. fsm_init(fsm *f)
  93. {
  94. f->state = LS_INITIAL;
  95. f->flags = 0;
  96. f->id = 0; /* XXX Start with random id? */
  97. f->timeouttime = FSM_DEFTIMEOUT;
  98. f->maxconfreqtransmits = FSM_DEFMAXCONFREQS;
  99. f->maxtermtransmits = FSM_DEFMAXTERMREQS;
  100. f->maxnakloops = FSM_DEFMAXNAKLOOPS;
  101. f->term_reason_len = 0;
  102. }
  103. /*
  104. * fsm_lowerup - The lower layer is up.
  105. */
  106. void
  107. fsm_lowerup(fsm *f)
  108. {
  109. int oldState = f->state;
  110. LWIP_UNUSED_ARG(oldState);
  111. switch( f->state ) {
  112. case LS_INITIAL:
  113. f->state = LS_CLOSED;
  114. break;
  115. case LS_STARTING:
  116. if( f->flags & OPT_SILENT ) {
  117. f->state = LS_STOPPED;
  118. } else {
  119. /* Send an initial configure-request */
  120. fsm_sconfreq(f, 0);
  121. f->state = LS_REQSENT;
  122. }
  123. break;
  124. default:
  125. FSMDEBUG(LOG_INFO, ("%s: Up event in state %d (%s)!\n",
  126. PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
  127. }
  128. FSMDEBUG(LOG_INFO, ("%s: lowerup state %d (%s) -> %d (%s)\n",
  129. PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
  130. }
  131. /*
  132. * fsm_lowerdown - The lower layer is down.
  133. *
  134. * Cancel all timeouts and inform upper layers.
  135. */
  136. void
  137. fsm_lowerdown(fsm *f)
  138. {
  139. int oldState = f->state;
  140. LWIP_UNUSED_ARG(oldState);
  141. switch( f->state ) {
  142. case LS_CLOSED:
  143. f->state = LS_INITIAL;
  144. break;
  145. case LS_STOPPED:
  146. f->state = LS_STARTING;
  147. if( f->callbacks->starting ) {
  148. (*f->callbacks->starting)(f);
  149. }
  150. break;
  151. case LS_CLOSING:
  152. f->state = LS_INITIAL;
  153. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  154. break;
  155. case LS_STOPPING:
  156. case LS_REQSENT:
  157. case LS_ACKRCVD:
  158. case LS_ACKSENT:
  159. f->state = LS_STARTING;
  160. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  161. break;
  162. case LS_OPENED:
  163. if( f->callbacks->down ) {
  164. (*f->callbacks->down)(f);
  165. }
  166. f->state = LS_STARTING;
  167. break;
  168. default:
  169. FSMDEBUG(LOG_INFO, ("%s: Down event in state %d (%s)!\n",
  170. PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
  171. }
  172. FSMDEBUG(LOG_INFO, ("%s: lowerdown state %d (%s) -> %d (%s)\n",
  173. PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
  174. }
  175. /*
  176. * fsm_open - Link is allowed to come up.
  177. */
  178. void
  179. fsm_open(fsm *f)
  180. {
  181. int oldState = f->state;
  182. LWIP_UNUSED_ARG(oldState);
  183. switch( f->state ) {
  184. case LS_INITIAL:
  185. f->state = LS_STARTING;
  186. if( f->callbacks->starting ) {
  187. (*f->callbacks->starting)(f);
  188. }
  189. break;
  190. case LS_CLOSED:
  191. if( f->flags & OPT_SILENT ) {
  192. f->state = LS_STOPPED;
  193. } else {
  194. /* Send an initial configure-request */
  195. fsm_sconfreq(f, 0);
  196. f->state = LS_REQSENT;
  197. }
  198. break;
  199. case LS_CLOSING:
  200. f->state = LS_STOPPING;
  201. /* fall through */
  202. case LS_STOPPED:
  203. case LS_OPENED:
  204. if( f->flags & OPT_RESTART ) {
  205. fsm_lowerdown(f);
  206. fsm_lowerup(f);
  207. }
  208. break;
  209. }
  210. FSMDEBUG(LOG_INFO, ("%s: open state %d (%s) -> %d (%s)\n",
  211. PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
  212. }
  213. #if 0 /* backport pppd 2.4.4b1; */
  214. /*
  215. * terminate_layer - Start process of shutting down the FSM
  216. *
  217. * Cancel any timeout running, notify upper layers we're done, and
  218. * send a terminate-request message as configured.
  219. */
  220. static void
  221. terminate_layer(fsm *f, int nextstate)
  222. {
  223. /* @todo */
  224. }
  225. #endif
  226. /*
  227. * fsm_close - Start closing connection.
  228. *
  229. * Cancel timeouts and either initiate close or possibly go directly to
  230. * the LS_CLOSED state.
  231. */
  232. void
  233. fsm_close(fsm *f, char *reason)
  234. {
  235. int oldState = f->state;
  236. LWIP_UNUSED_ARG(oldState);
  237. f->term_reason = reason;
  238. f->term_reason_len = (reason == NULL ? 0 : (int)strlen(reason));
  239. switch( f->state ) {
  240. case LS_STARTING:
  241. f->state = LS_INITIAL;
  242. break;
  243. case LS_STOPPED:
  244. f->state = LS_CLOSED;
  245. break;
  246. case LS_STOPPING:
  247. f->state = LS_CLOSING;
  248. break;
  249. case LS_REQSENT:
  250. case LS_ACKRCVD:
  251. case LS_ACKSENT:
  252. case LS_OPENED:
  253. if( f->state != LS_OPENED ) {
  254. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  255. } else if( f->callbacks->down ) {
  256. (*f->callbacks->down)(f); /* Inform upper layers we're down */
  257. }
  258. /* Init restart counter, send Terminate-Request */
  259. f->retransmits = f->maxtermtransmits;
  260. fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
  261. (u_char *) f->term_reason, f->term_reason_len);
  262. TIMEOUT(fsm_timeout, f, f->timeouttime);
  263. --f->retransmits;
  264. f->state = LS_CLOSING;
  265. break;
  266. }
  267. FSMDEBUG(LOG_INFO, ("%s: close reason=%s state %d (%s) -> %d (%s)\n",
  268. PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
  269. }
  270. /*
  271. * fsm_timeout - Timeout expired.
  272. */
  273. static void
  274. fsm_timeout(void *arg)
  275. {
  276. fsm *f = (fsm *) arg;
  277. switch (f->state) {
  278. case LS_CLOSING:
  279. case LS_STOPPING:
  280. if( f->retransmits <= 0 ) {
  281. FSMDEBUG(LOG_WARNING, ("%s: timeout sending Terminate-Request state=%d (%s)\n",
  282. PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
  283. /*
  284. * We've waited for an ack long enough. Peer probably heard us.
  285. */
  286. f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED;
  287. if( f->callbacks->finished ) {
  288. (*f->callbacks->finished)(f);
  289. }
  290. } else {
  291. FSMDEBUG(LOG_WARNING, ("%s: timeout resending Terminate-Requests state=%d (%s)\n",
  292. PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
  293. /* Send Terminate-Request */
  294. fsm_sdata(f, 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. case LS_REQSENT:
  301. case LS_ACKRCVD:
  302. case LS_ACKSENT:
  303. if (f->retransmits <= 0) {
  304. FSMDEBUG(LOG_WARNING, ("%s: timeout sending Config-Requests state=%d (%s)\n",
  305. PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
  306. f->state = LS_STOPPED;
  307. if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) {
  308. (*f->callbacks->finished)(f);
  309. }
  310. } else {
  311. FSMDEBUG(LOG_WARNING, ("%s: timeout resending Config-Request state=%d (%s)\n",
  312. PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
  313. /* Retransmit the configure-request */
  314. if (f->callbacks->retransmit) {
  315. (*f->callbacks->retransmit)(f);
  316. }
  317. fsm_sconfreq(f, 1); /* Re-send Configure-Request */
  318. if( f->state == LS_ACKRCVD ) {
  319. f->state = LS_REQSENT;
  320. }
  321. }
  322. break;
  323. default:
  324. FSMDEBUG(LOG_INFO, ("%s: UNHANDLED timeout event in state %d (%s)!\n",
  325. PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
  326. }
  327. }
  328. /*
  329. * fsm_input - Input packet.
  330. */
  331. void
  332. fsm_input(fsm *f, u_char *inpacket, int l)
  333. {
  334. u_char *inp = inpacket;
  335. u_char code, id;
  336. int len;
  337. /*
  338. * Parse header (code, id and length).
  339. * If packet too short, drop it.
  340. */
  341. if (l < HEADERLEN) {
  342. FSMDEBUG(LOG_WARNING, ("fsm_input(%x): Rcvd short header.\n",
  343. f->protocol));
  344. return;
  345. }
  346. GETCHAR(code, inp);
  347. GETCHAR(id, inp);
  348. GETSHORT(len, inp);
  349. if (len < HEADERLEN) {
  350. FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd illegal length.\n",
  351. f->protocol));
  352. return;
  353. }
  354. if (len > l) {
  355. FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd short packet.\n",
  356. f->protocol));
  357. return;
  358. }
  359. len -= HEADERLEN; /* subtract header length */
  360. if( f->state == LS_INITIAL || f->state == LS_STARTING ) {
  361. FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd packet in state %d (%s).\n",
  362. f->protocol, f->state, ppperr_strerr[f->state]));
  363. return;
  364. }
  365. FSMDEBUG(LOG_INFO, ("fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));
  366. /*
  367. * Action depends on code.
  368. */
  369. switch (code) {
  370. case CONFREQ:
  371. fsm_rconfreq(f, id, inp, len);
  372. break;
  373. case CONFACK:
  374. fsm_rconfack(f, id, inp, len);
  375. break;
  376. case CONFNAK:
  377. case CONFREJ:
  378. fsm_rconfnakrej(f, code, id, inp, len);
  379. break;
  380. case TERMREQ:
  381. fsm_rtermreq(f, id, inp, len);
  382. break;
  383. case TERMACK:
  384. fsm_rtermack(f);
  385. break;
  386. case CODEREJ:
  387. fsm_rcoderej(f, inp, len);
  388. break;
  389. default:
  390. FSMDEBUG(LOG_INFO, ("fsm_input(%s): default: \n", PROTO_NAME(f)));
  391. if( !f->callbacks->extcode ||
  392. !(*f->callbacks->extcode)(f, code, id, inp, len) ) {
  393. fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
  394. }
  395. break;
  396. }
  397. }
  398. /*
  399. * fsm_rconfreq - Receive Configure-Request.
  400. */
  401. static void
  402. fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)
  403. {
  404. int code, reject_if_disagree;
  405. FSMDEBUG(LOG_INFO, ("fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n",
  406. PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
  407. switch( f->state ) {
  408. case LS_CLOSED:
  409. /* Go away, we're closed */
  410. fsm_sdata(f, TERMACK, id, NULL, 0);
  411. return;
  412. case LS_CLOSING:
  413. case LS_STOPPING:
  414. return;
  415. case LS_OPENED:
  416. /* Go down and restart negotiation */
  417. if( f->callbacks->down ) {
  418. (*f->callbacks->down)(f); /* Inform upper layers */
  419. }
  420. fsm_sconfreq(f, 0); /* Send initial Configure-Request */
  421. break;
  422. case LS_STOPPED:
  423. /* Negotiation started by our peer */
  424. fsm_sconfreq(f, 0); /* Send initial Configure-Request */
  425. f->state = LS_REQSENT;
  426. break;
  427. }
  428. /*
  429. * Pass the requested configuration options
  430. * to protocol-specific code for checking.
  431. */
  432. if (f->callbacks->reqci) { /* Check CI */
  433. reject_if_disagree = (f->nakloops >= f->maxnakloops);
  434. code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
  435. } else if (len) {
  436. code = CONFREJ; /* Reject all CI */
  437. } else {
  438. code = CONFACK;
  439. }
  440. /* send the Ack, Nak or Rej to the peer */
  441. fsm_sdata(f, (u_char)code, id, inp, len);
  442. if (code == CONFACK) {
  443. if (f->state == LS_ACKRCVD) {
  444. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  445. f->state = LS_OPENED;
  446. if (f->callbacks->up) {
  447. (*f->callbacks->up)(f); /* Inform upper layers */
  448. }
  449. } else {
  450. f->state = LS_ACKSENT;
  451. }
  452. f->nakloops = 0;
  453. } else {
  454. /* we sent CONFACK or CONFREJ */
  455. if (f->state != LS_ACKRCVD) {
  456. f->state = LS_REQSENT;
  457. }
  458. if( code == CONFNAK ) {
  459. ++f->nakloops;
  460. }
  461. }
  462. }
  463. /*
  464. * fsm_rconfack - Receive Configure-Ack.
  465. */
  466. static void
  467. fsm_rconfack(fsm *f, int id, u_char *inp, int len)
  468. {
  469. FSMDEBUG(LOG_INFO, ("fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n",
  470. PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
  471. if (id != f->reqid || f->seen_ack) { /* Expected id? */
  472. return; /* Nope, toss... */
  473. }
  474. if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ) {
  475. /* Ack is bad - ignore it */
  476. FSMDEBUG(LOG_INFO, ("%s: received bad Ack (length %d)\n",
  477. PROTO_NAME(f), len));
  478. return;
  479. }
  480. f->seen_ack = 1;
  481. switch (f->state) {
  482. case LS_CLOSED:
  483. case LS_STOPPED:
  484. fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
  485. break;
  486. case LS_REQSENT:
  487. f->state = LS_ACKRCVD;
  488. f->retransmits = f->maxconfreqtransmits;
  489. break;
  490. case LS_ACKRCVD:
  491. /* Huh? an extra valid Ack? oh well... */
  492. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  493. fsm_sconfreq(f, 0);
  494. f->state = LS_REQSENT;
  495. break;
  496. case LS_ACKSENT:
  497. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  498. f->state = LS_OPENED;
  499. f->retransmits = f->maxconfreqtransmits;
  500. if (f->callbacks->up) {
  501. (*f->callbacks->up)(f); /* Inform upper layers */
  502. }
  503. break;
  504. case LS_OPENED:
  505. /* Go down and restart negotiation */
  506. if (f->callbacks->down) {
  507. (*f->callbacks->down)(f); /* Inform upper layers */
  508. }
  509. fsm_sconfreq(f, 0); /* Send initial Configure-Request */
  510. f->state = LS_REQSENT;
  511. break;
  512. }
  513. }
  514. /*
  515. * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
  516. */
  517. static void
  518. fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)
  519. {
  520. int (*proc) (fsm *, u_char *, int);
  521. int ret;
  522. FSMDEBUG(LOG_INFO, ("fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n",
  523. PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
  524. if (id != f->reqid || f->seen_ack) { /* Expected id? */
  525. return; /* Nope, toss... */
  526. }
  527. proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
  528. if (!proc || !((ret = proc(f, inp, len)))) {
  529. /* Nak/reject is bad - ignore it */
  530. FSMDEBUG(LOG_INFO, ("%s: received bad %s (length %d)\n",
  531. PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
  532. return;
  533. }
  534. f->seen_ack = 1;
  535. switch (f->state) {
  536. case LS_CLOSED:
  537. case LS_STOPPED:
  538. fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
  539. break;
  540. case LS_REQSENT:
  541. case LS_ACKSENT:
  542. /* They didn't agree to what we wanted - try another request */
  543. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  544. if (ret < 0) {
  545. f->state = LS_STOPPED; /* kludge for stopping CCP */
  546. } else {
  547. fsm_sconfreq(f, 0); /* Send Configure-Request */
  548. }
  549. break;
  550. case LS_ACKRCVD:
  551. /* Got a Nak/reject when we had already had an Ack?? oh well... */
  552. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  553. fsm_sconfreq(f, 0);
  554. f->state = LS_REQSENT;
  555. break;
  556. case LS_OPENED:
  557. /* Go down and restart negotiation */
  558. if (f->callbacks->down) {
  559. (*f->callbacks->down)(f); /* Inform upper layers */
  560. }
  561. fsm_sconfreq(f, 0); /* Send initial Configure-Request */
  562. f->state = LS_REQSENT;
  563. break;
  564. }
  565. }
  566. /*
  567. * fsm_rtermreq - Receive Terminate-Req.
  568. */
  569. static void
  570. fsm_rtermreq(fsm *f, int id, u_char *p, int len)
  571. {
  572. LWIP_UNUSED_ARG(p);
  573. FSMDEBUG(LOG_INFO, ("fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n",
  574. PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
  575. switch (f->state) {
  576. case LS_ACKRCVD:
  577. case LS_ACKSENT:
  578. f->state = LS_REQSENT; /* Start over but keep trying */
  579. break;
  580. case LS_OPENED:
  581. if (len > 0) {
  582. FSMDEBUG(LOG_INFO, ("%s terminated by peer (%p)\n", PROTO_NAME(f), p));
  583. } else {
  584. FSMDEBUG(LOG_INFO, ("%s terminated by peer\n", PROTO_NAME(f)));
  585. }
  586. if (f->callbacks->down) {
  587. (*f->callbacks->down)(f); /* Inform upper layers */
  588. }
  589. f->retransmits = 0;
  590. f->state = LS_STOPPING;
  591. TIMEOUT(fsm_timeout, f, f->timeouttime);
  592. break;
  593. }
  594. fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
  595. }
  596. /*
  597. * fsm_rtermack - Receive Terminate-Ack.
  598. */
  599. static void
  600. fsm_rtermack(fsm *f)
  601. {
  602. FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): state=%d (%s)\n",
  603. PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
  604. switch (f->state) {
  605. case LS_CLOSING:
  606. UNTIMEOUT(fsm_timeout, f);
  607. f->state = LS_CLOSED;
  608. if( f->callbacks->finished ) {
  609. (*f->callbacks->finished)(f);
  610. }
  611. break;
  612. case LS_STOPPING:
  613. UNTIMEOUT(fsm_timeout, f);
  614. f->state = LS_STOPPED;
  615. if( f->callbacks->finished ) {
  616. (*f->callbacks->finished)(f);
  617. }
  618. break;
  619. case LS_ACKRCVD:
  620. f->state = LS_REQSENT;
  621. break;
  622. case LS_OPENED:
  623. if (f->callbacks->down) {
  624. (*f->callbacks->down)(f); /* Inform upper layers */
  625. }
  626. fsm_sconfreq(f, 0);
  627. break;
  628. default:
  629. FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): UNHANDLED state=%d (%s)!!!\n",
  630. PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
  631. }
  632. }
  633. /*
  634. * fsm_rcoderej - Receive an Code-Reject.
  635. */
  636. static void
  637. fsm_rcoderej(fsm *f, u_char *inp, int len)
  638. {
  639. u_char code, id;
  640. FSMDEBUG(LOG_INFO, ("fsm_rcoderej(%s): state=%d (%s)\n",
  641. PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
  642. if (len < HEADERLEN) {
  643. FSMDEBUG(LOG_INFO, ("fsm_rcoderej: Rcvd short Code-Reject packet!\n"));
  644. return;
  645. }
  646. GETCHAR(code, inp);
  647. GETCHAR(id, inp);
  648. FSMDEBUG(LOG_WARNING, ("%s: Rcvd Code-Reject for code %d, id %d\n",
  649. PROTO_NAME(f), code, id));
  650. if( f->state == LS_ACKRCVD ) {
  651. f->state = LS_REQSENT;
  652. }
  653. }
  654. /*
  655. * fsm_protreject - Peer doesn't speak this protocol.
  656. *
  657. * Treat this as a catastrophic error (RXJ-).
  658. */
  659. void
  660. fsm_protreject(fsm *f)
  661. {
  662. switch( f->state ) {
  663. case LS_CLOSING:
  664. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  665. /* fall through */
  666. case LS_CLOSED:
  667. f->state = LS_CLOSED;
  668. if( f->callbacks->finished ) {
  669. (*f->callbacks->finished)(f);
  670. }
  671. break;
  672. case LS_STOPPING:
  673. case LS_REQSENT:
  674. case LS_ACKRCVD:
  675. case LS_ACKSENT:
  676. UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  677. /* fall through */
  678. case LS_STOPPED:
  679. f->state = LS_STOPPED;
  680. if( f->callbacks->finished ) {
  681. (*f->callbacks->finished)(f);
  682. }
  683. break;
  684. case LS_OPENED:
  685. if( f->callbacks->down ) {
  686. (*f->callbacks->down)(f);
  687. }
  688. /* Init restart counter, send Terminate-Request */
  689. f->retransmits = f->maxtermtransmits;
  690. fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
  691. (u_char *) f->term_reason, f->term_reason_len);
  692. TIMEOUT(fsm_timeout, f, f->timeouttime);
  693. --f->retransmits;
  694. f->state = LS_STOPPING;
  695. break;
  696. default:
  697. FSMDEBUG(LOG_INFO, ("%s: Protocol-reject event in state %d (%s)!\n",
  698. PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
  699. }
  700. }
  701. /*
  702. * fsm_sconfreq - Send a Configure-Request.
  703. */
  704. static void
  705. fsm_sconfreq(fsm *f, int retransmit)
  706. {
  707. u_char *outp;
  708. int cilen;
  709. if( f->state != LS_REQSENT && f->state != LS_ACKRCVD && f->state != LS_ACKSENT ) {
  710. /* Not currently negotiating - reset options */
  711. if( f->callbacks->resetci ) {
  712. (*f->callbacks->resetci)(f);
  713. }
  714. f->nakloops = 0;
  715. }
  716. if( !retransmit ) {
  717. /* New request - reset retransmission counter, use new ID */
  718. f->retransmits = f->maxconfreqtransmits;
  719. f->reqid = ++f->id;
  720. }
  721. f->seen_ack = 0;
  722. /*
  723. * Make up the request packet
  724. */
  725. outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN;
  726. if( f->callbacks->cilen && f->callbacks->addci ) {
  727. cilen = (*f->callbacks->cilen)(f);
  728. if( cilen > peer_mru[f->unit] - (int)HEADERLEN ) {
  729. cilen = peer_mru[f->unit] - HEADERLEN;
  730. }
  731. if (f->callbacks->addci) {
  732. (*f->callbacks->addci)(f, outp, &cilen);
  733. }
  734. } else {
  735. cilen = 0;
  736. }
  737. /* send the request to our peer */
  738. fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
  739. /* start the retransmit timer */
  740. --f->retransmits;
  741. TIMEOUT(fsm_timeout, f, f->timeouttime);
  742. FSMDEBUG(LOG_INFO, ("%s: sending Configure-Request, id %d\n",
  743. PROTO_NAME(f), f->reqid));
  744. }
  745. /*
  746. * fsm_sdata - Send some data.
  747. *
  748. * Used for all packets sent to our peer by this module.
  749. */
  750. void
  751. fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen)
  752. {
  753. u_char *outp;
  754. int outlen;
  755. /* Adjust length to be smaller than MTU */
  756. outp = outpacket_buf[f->unit];
  757. if (datalen > peer_mru[f->unit] - (int)HEADERLEN) {
  758. datalen = peer_mru[f->unit] - HEADERLEN;
  759. }
  760. if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) {
  761. BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
  762. }
  763. outlen = datalen + HEADERLEN;
  764. MAKEHEADER(outp, f->protocol);
  765. PUTCHAR(code, outp);
  766. PUTCHAR(id, outp);
  767. PUTSHORT(outlen, outp);
  768. pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);
  769. FSMDEBUG(LOG_INFO, ("fsm_sdata(%s): Sent code %d,%d,%d.\n",
  770. PROTO_NAME(f), code, id, outlen));
  771. }
  772. #endif /* PPP_SUPPORT */