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