17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * fsm.c - {Link, IP} Control Protocol Finite State Machine.
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
57c478bd9Sstevel@tonic-gate * Use is subject to license terms.
67c478bd9Sstevel@tonic-gate *
77c478bd9Sstevel@tonic-gate * Copyright (c) 1989 Carnegie Mellon University.
87c478bd9Sstevel@tonic-gate * All rights reserved.
97c478bd9Sstevel@tonic-gate *
107c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted
117c478bd9Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are
127c478bd9Sstevel@tonic-gate * duplicated in all such forms and that any documentation,
137c478bd9Sstevel@tonic-gate * advertising materials, and other materials related to such
147c478bd9Sstevel@tonic-gate * distribution and use acknowledge that the software was developed
157c478bd9Sstevel@tonic-gate * by Carnegie Mellon University. The name of the
167c478bd9Sstevel@tonic-gate * University may not be used to endorse or promote products derived
177c478bd9Sstevel@tonic-gate * from this software without specific prior written permission.
187c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
197c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
207c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate
237c478bd9Sstevel@tonic-gate /*
247c478bd9Sstevel@tonic-gate * TODO:
257c478bd9Sstevel@tonic-gate * Randomize fsm id on link/init.
267c478bd9Sstevel@tonic-gate * Deal with variable outgoing MTU.
277c478bd9Sstevel@tonic-gate */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #ifndef NO_DRAND48
337c478bd9Sstevel@tonic-gate #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #endif /* NO_DRAND48 */
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gate #include "pppd.h"
377c478bd9Sstevel@tonic-gate #include "fsm.h"
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate static void fsm_timeout __P((void *));
407c478bd9Sstevel@tonic-gate static void fsm_rconfreq __P((fsm *, int, u_char *, int));
417c478bd9Sstevel@tonic-gate static void fsm_rconfack __P((fsm *, int, u_char *, int));
427c478bd9Sstevel@tonic-gate static void fsm_rconfnakrej __P((fsm *, int, int, u_char *, int));
437c478bd9Sstevel@tonic-gate static void fsm_rtermreq __P((fsm *, int, u_char *, int));
447c478bd9Sstevel@tonic-gate static void fsm_rtermack __P((fsm *));
457c478bd9Sstevel@tonic-gate static void fsm_rcoderej __P((fsm *, u_char *, int));
467c478bd9Sstevel@tonic-gate static void fsm_sconfreq __P((fsm *, int));
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate #define PROTO_NAME(f) ((f)->callbacks->proto_name)
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate static int peer_mru[NUM_PPP];
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate const char *
fsm_state(int statenum)537c478bd9Sstevel@tonic-gate fsm_state(int statenum)
547c478bd9Sstevel@tonic-gate {
557c478bd9Sstevel@tonic-gate static const char *fsm_states[] = { FSM__STATES };
567c478bd9Sstevel@tonic-gate static char buf[32];
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate if (statenum < 0 || statenum >= Dim(fsm_states)) {
597c478bd9Sstevel@tonic-gate (void) slprintf(buf, sizeof (buf), "unknown#%d", statenum);
607c478bd9Sstevel@tonic-gate return buf;
617c478bd9Sstevel@tonic-gate }
627c478bd9Sstevel@tonic-gate return fsm_states[statenum];
637c478bd9Sstevel@tonic-gate }
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate /*
667c478bd9Sstevel@tonic-gate * fsm_init - Initialize fsm.
677c478bd9Sstevel@tonic-gate *
687c478bd9Sstevel@tonic-gate * Initialize fsm state.
697c478bd9Sstevel@tonic-gate */
707c478bd9Sstevel@tonic-gate void
fsm_init(f)717c478bd9Sstevel@tonic-gate fsm_init(f)
727c478bd9Sstevel@tonic-gate fsm *f;
737c478bd9Sstevel@tonic-gate {
747c478bd9Sstevel@tonic-gate f->state = INITIAL;
757c478bd9Sstevel@tonic-gate f->flags = 0;
767c478bd9Sstevel@tonic-gate f->id = (uchar_t)(drand48() * 0xFF); /* Start with random id */
777c478bd9Sstevel@tonic-gate f->timeouttime = DEFTIMEOUT;
787c478bd9Sstevel@tonic-gate f->maxconfreqtransmits = DEFMAXCONFREQS;
797c478bd9Sstevel@tonic-gate f->maxtermtransmits = DEFMAXTERMREQS;
807c478bd9Sstevel@tonic-gate f->maxnakloops = DEFMAXNAKLOOPS;
817c478bd9Sstevel@tonic-gate f->term_reason_len = 0;
827c478bd9Sstevel@tonic-gate }
837c478bd9Sstevel@tonic-gate
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate * fsm_lowerup - The lower layer is up.
877c478bd9Sstevel@tonic-gate */
887c478bd9Sstevel@tonic-gate void
fsm_lowerup(f)897c478bd9Sstevel@tonic-gate fsm_lowerup(f)
907c478bd9Sstevel@tonic-gate fsm *f;
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate switch( f->state ){
937c478bd9Sstevel@tonic-gate case INITIAL:
947c478bd9Sstevel@tonic-gate f->state = CLOSED;
957c478bd9Sstevel@tonic-gate break;
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate case STARTING:
987c478bd9Sstevel@tonic-gate if( f->flags & OPT_SILENT )
997c478bd9Sstevel@tonic-gate f->state = STOPPED;
1007c478bd9Sstevel@tonic-gate else {
1017c478bd9Sstevel@tonic-gate /* Send an initial configure-request */
1027c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0);
1037c478bd9Sstevel@tonic-gate f->state = REQSENT;
1047c478bd9Sstevel@tonic-gate }
1057c478bd9Sstevel@tonic-gate break;
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate default:
1087c478bd9Sstevel@tonic-gate error("%s: Up event in state %s", PROTO_NAME(f), fsm_state(f->state));
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate }
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate /*
1147c478bd9Sstevel@tonic-gate * fsm_lowerdown - The lower layer is down.
1157c478bd9Sstevel@tonic-gate *
1167c478bd9Sstevel@tonic-gate * Cancel all timeouts and inform upper layers.
1177c478bd9Sstevel@tonic-gate */
1187c478bd9Sstevel@tonic-gate void
fsm_lowerdown(f)1197c478bd9Sstevel@tonic-gate fsm_lowerdown(f)
1207c478bd9Sstevel@tonic-gate fsm *f;
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate switch( f->state ){
1237c478bd9Sstevel@tonic-gate case CLOSED:
1247c478bd9Sstevel@tonic-gate f->state = INITIAL;
1257c478bd9Sstevel@tonic-gate break;
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate case STOPPED:
1287c478bd9Sstevel@tonic-gate f->state = STARTING;
1297c478bd9Sstevel@tonic-gate if (f->callbacks->starting != NULL)
1307c478bd9Sstevel@tonic-gate (*f->callbacks->starting)(f);
1317c478bd9Sstevel@tonic-gate break;
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate case CLOSING:
1347c478bd9Sstevel@tonic-gate f->state = INITIAL;
1357c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
1367c478bd9Sstevel@tonic-gate break;
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate case STOPPING:
1397c478bd9Sstevel@tonic-gate case REQSENT:
1407c478bd9Sstevel@tonic-gate case ACKRCVD:
1417c478bd9Sstevel@tonic-gate case ACKSENT:
1427c478bd9Sstevel@tonic-gate f->state = STARTING;
1437c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
1447c478bd9Sstevel@tonic-gate break;
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate case OPENED:
1477c478bd9Sstevel@tonic-gate f->state = STARTING;
1487c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL)
1497c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f);
1507c478bd9Sstevel@tonic-gate break;
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate default:
1537c478bd9Sstevel@tonic-gate dbglog("%s: Down event in state %s", PROTO_NAME(f),
1547c478bd9Sstevel@tonic-gate fsm_state(f->state));
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate * fsm_open - Link is allowed to come up.
1617c478bd9Sstevel@tonic-gate */
1627c478bd9Sstevel@tonic-gate void
fsm_open(f)1637c478bd9Sstevel@tonic-gate fsm_open(f)
1647c478bd9Sstevel@tonic-gate fsm *f;
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate switch( f->state ){
1677c478bd9Sstevel@tonic-gate case INITIAL:
1687c478bd9Sstevel@tonic-gate f->state = STARTING;
1697c478bd9Sstevel@tonic-gate if (f->callbacks->starting != NULL)
1707c478bd9Sstevel@tonic-gate (*f->callbacks->starting)(f);
1717c478bd9Sstevel@tonic-gate break;
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate case CLOSED:
1747c478bd9Sstevel@tonic-gate if( f->flags & OPT_SILENT )
1757c478bd9Sstevel@tonic-gate f->state = STOPPED;
1767c478bd9Sstevel@tonic-gate else {
1777c478bd9Sstevel@tonic-gate /* Send an initial configure-request */
1787c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0);
1797c478bd9Sstevel@tonic-gate f->state = REQSENT;
1807c478bd9Sstevel@tonic-gate }
1817c478bd9Sstevel@tonic-gate break;
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate case CLOSING:
1847c478bd9Sstevel@tonic-gate f->state = STOPPING;
1857c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/
1867c478bd9Sstevel@tonic-gate case STOPPING:
1877c478bd9Sstevel@tonic-gate case STOPPED:
1887c478bd9Sstevel@tonic-gate case OPENED:
1897c478bd9Sstevel@tonic-gate if( f->flags & OPT_RESTART ){
1907c478bd9Sstevel@tonic-gate fsm_lowerdown(f);
1917c478bd9Sstevel@tonic-gate fsm_lowerup(f);
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate break;
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate case STARTING:
1967c478bd9Sstevel@tonic-gate case REQSENT:
1977c478bd9Sstevel@tonic-gate case ACKRCVD:
1987c478bd9Sstevel@tonic-gate case ACKSENT:
1997c478bd9Sstevel@tonic-gate /* explicitly do nothing here. */
2007c478bd9Sstevel@tonic-gate break;
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate /*
2067c478bd9Sstevel@tonic-gate * fsm_close - Start closing connection.
2077c478bd9Sstevel@tonic-gate *
2087c478bd9Sstevel@tonic-gate * Cancel timeouts and either initiate close or possibly go directly to
2097c478bd9Sstevel@tonic-gate * the CLOSED state.
2107c478bd9Sstevel@tonic-gate */
2117c478bd9Sstevel@tonic-gate void
fsm_close(f,reason)2127c478bd9Sstevel@tonic-gate fsm_close(f, reason)
2137c478bd9Sstevel@tonic-gate fsm *f;
2147c478bd9Sstevel@tonic-gate char *reason;
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate int prevstate = f->state;
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate f->term_reason = reason;
2197c478bd9Sstevel@tonic-gate f->term_reason_len = (reason == NULL? 0: strlen(reason));
2207c478bd9Sstevel@tonic-gate switch( f->state ){
2217c478bd9Sstevel@tonic-gate case STARTING:
2227c478bd9Sstevel@tonic-gate f->state = INITIAL;
2237c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL)
2247c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f);
2257c478bd9Sstevel@tonic-gate break;
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate case STOPPED:
2287c478bd9Sstevel@tonic-gate f->state = CLOSED;
2297c478bd9Sstevel@tonic-gate break;
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate case STOPPING:
2327c478bd9Sstevel@tonic-gate f->state = CLOSING;
2337c478bd9Sstevel@tonic-gate break;
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate case REQSENT:
2367c478bd9Sstevel@tonic-gate case ACKRCVD:
2377c478bd9Sstevel@tonic-gate case ACKSENT:
2387c478bd9Sstevel@tonic-gate case OPENED:
2397c478bd9Sstevel@tonic-gate f->state = CLOSING;
2407c478bd9Sstevel@tonic-gate if (prevstate != OPENED )
2417c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
2427c478bd9Sstevel@tonic-gate else if (f->callbacks->down != NULL)
2437c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f); /* Inform upper layers we're down */
2447c478bd9Sstevel@tonic-gate /*
2457c478bd9Sstevel@tonic-gate * Note that this-layer-down means "stop transmitting."
2467c478bd9Sstevel@tonic-gate * This-layer-finished means "stop everything."
2477c478bd9Sstevel@tonic-gate */
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate /* Init restart counter, send Terminate-Request */
2507c478bd9Sstevel@tonic-gate f->retransmits = f->maxtermtransmits;
2517c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id,
2527c478bd9Sstevel@tonic-gate (u_char *) f->term_reason, f->term_reason_len);
2537c478bd9Sstevel@tonic-gate TIMEOUT(fsm_timeout, f, f->timeouttime);
2547c478bd9Sstevel@tonic-gate --f->retransmits;
2557c478bd9Sstevel@tonic-gate break;
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate case INITIAL:
2587c478bd9Sstevel@tonic-gate case CLOSED:
2597c478bd9Sstevel@tonic-gate case CLOSING:
2607c478bd9Sstevel@tonic-gate /* explicitly do nothing here. */
2617c478bd9Sstevel@tonic-gate break;
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate /*
2677c478bd9Sstevel@tonic-gate * fsm_timeout - Timeout expired.
2687c478bd9Sstevel@tonic-gate */
2697c478bd9Sstevel@tonic-gate static void
fsm_timeout(arg)2707c478bd9Sstevel@tonic-gate fsm_timeout(arg)
2717c478bd9Sstevel@tonic-gate void *arg;
2727c478bd9Sstevel@tonic-gate {
2737c478bd9Sstevel@tonic-gate fsm *f = (fsm *) arg;
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate switch (f->state) {
2767c478bd9Sstevel@tonic-gate case CLOSING:
2777c478bd9Sstevel@tonic-gate case STOPPING:
2787c478bd9Sstevel@tonic-gate if( f->retransmits <= 0 ){
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate * We've waited for an ack long enough. Peer probably heard us.
2817c478bd9Sstevel@tonic-gate */
2827c478bd9Sstevel@tonic-gate f->state = (f->state == CLOSING)? CLOSED: STOPPED;
2837c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL)
2847c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f);
2857c478bd9Sstevel@tonic-gate } else {
2867c478bd9Sstevel@tonic-gate /* Send Terminate-Request */
2877c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id,
2887c478bd9Sstevel@tonic-gate (u_char *) f->term_reason, f->term_reason_len);
2897c478bd9Sstevel@tonic-gate TIMEOUT(fsm_timeout, f, f->timeouttime);
2907c478bd9Sstevel@tonic-gate --f->retransmits;
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate break;
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate case REQSENT:
2957c478bd9Sstevel@tonic-gate case ACKRCVD:
2967c478bd9Sstevel@tonic-gate case ACKSENT:
2977c478bd9Sstevel@tonic-gate if (f->retransmits <= 0) {
2987c478bd9Sstevel@tonic-gate warn("%s: timeout sending Config-Requests\n", PROTO_NAME(f));
2997c478bd9Sstevel@tonic-gate f->state = STOPPED;
3007c478bd9Sstevel@tonic-gate if (!(f->flags & OPT_PASSIVE) && f->callbacks->finished != NULL)
3017c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f);
3027c478bd9Sstevel@tonic-gate
3037c478bd9Sstevel@tonic-gate } else {
3047c478bd9Sstevel@tonic-gate /* Retransmit the configure-request */
3057c478bd9Sstevel@tonic-gate if (f->callbacks->retransmit != NULL)
3067c478bd9Sstevel@tonic-gate (*f->callbacks->retransmit)(f);
3077c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 1); /* Re-send Configure-Request */
3087c478bd9Sstevel@tonic-gate if( f->state == ACKRCVD )
3097c478bd9Sstevel@tonic-gate f->state = REQSENT;
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate break;
3127c478bd9Sstevel@tonic-gate
3137c478bd9Sstevel@tonic-gate default:
3147c478bd9Sstevel@tonic-gate fatal("%s: Timeout event in state %s!", PROTO_NAME(f),
3157c478bd9Sstevel@tonic-gate fsm_state(f->state));
3167c478bd9Sstevel@tonic-gate }
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate
3207c478bd9Sstevel@tonic-gate /*
3217c478bd9Sstevel@tonic-gate * fsm_input - Input packet.
3227c478bd9Sstevel@tonic-gate */
3237c478bd9Sstevel@tonic-gate void
fsm_input(f,inpacket,l)3247c478bd9Sstevel@tonic-gate fsm_input(f, inpacket, l)
3257c478bd9Sstevel@tonic-gate fsm *f;
3267c478bd9Sstevel@tonic-gate u_char *inpacket;
3277c478bd9Sstevel@tonic-gate int l;
3287c478bd9Sstevel@tonic-gate {
3297c478bd9Sstevel@tonic-gate u_char *inp;
3307c478bd9Sstevel@tonic-gate u_char code, id;
3317c478bd9Sstevel@tonic-gate int len;
3327c478bd9Sstevel@tonic-gate
3337c478bd9Sstevel@tonic-gate /*
3347c478bd9Sstevel@tonic-gate * Parse header (code, id and length).
3357c478bd9Sstevel@tonic-gate * If packet too short, drop it.
3367c478bd9Sstevel@tonic-gate */
3377c478bd9Sstevel@tonic-gate inp = inpacket;
3387c478bd9Sstevel@tonic-gate if (l < HEADERLEN) {
3397c478bd9Sstevel@tonic-gate error("%s packet: discard; too small (%d < %d)", PROTO_NAME(f), l,
3407c478bd9Sstevel@tonic-gate HEADERLEN);
3417c478bd9Sstevel@tonic-gate return;
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate GETCHAR(code, inp);
3447c478bd9Sstevel@tonic-gate GETCHAR(id, inp);
3457c478bd9Sstevel@tonic-gate GETSHORT(len, inp);
3467c478bd9Sstevel@tonic-gate if (len < HEADERLEN) {
3477c478bd9Sstevel@tonic-gate error("%s packet: discard; invalid length (%d < %d)", PROTO_NAME(f),
3487c478bd9Sstevel@tonic-gate len, HEADERLEN);
3497c478bd9Sstevel@tonic-gate return;
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate if (len > l) {
3527c478bd9Sstevel@tonic-gate error("%s packet: discard; truncated (%d > %d)", PROTO_NAME(f), len,
3537c478bd9Sstevel@tonic-gate l);
3547c478bd9Sstevel@tonic-gate return;
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate len -= HEADERLEN; /* subtract header length */
3577c478bd9Sstevel@tonic-gate
3587c478bd9Sstevel@tonic-gate if (f->state == INITIAL || f->state == STARTING) {
3597c478bd9Sstevel@tonic-gate dbglog("%s: discarded packet in state %s", PROTO_NAME(f),
3607c478bd9Sstevel@tonic-gate fsm_state(f->state));
3617c478bd9Sstevel@tonic-gate return;
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate /*
3657c478bd9Sstevel@tonic-gate * Action depends on code.
3667c478bd9Sstevel@tonic-gate */
3677c478bd9Sstevel@tonic-gate switch (code) {
3687c478bd9Sstevel@tonic-gate case CODE_CONFREQ:
3697c478bd9Sstevel@tonic-gate fsm_rconfreq(f, id, inp, len);
3707c478bd9Sstevel@tonic-gate break;
371*55fea89dSDan Cross
3727c478bd9Sstevel@tonic-gate case CODE_CONFACK:
3737c478bd9Sstevel@tonic-gate fsm_rconfack(f, id, inp, len);
3747c478bd9Sstevel@tonic-gate break;
375*55fea89dSDan Cross
3767c478bd9Sstevel@tonic-gate case CODE_CONFNAK:
3777c478bd9Sstevel@tonic-gate case CODE_CONFREJ:
3787c478bd9Sstevel@tonic-gate fsm_rconfnakrej(f, code, id, inp, len);
3797c478bd9Sstevel@tonic-gate break;
380*55fea89dSDan Cross
3817c478bd9Sstevel@tonic-gate case CODE_TERMREQ:
3827c478bd9Sstevel@tonic-gate fsm_rtermreq(f, id, inp, len);
3837c478bd9Sstevel@tonic-gate break;
384*55fea89dSDan Cross
3857c478bd9Sstevel@tonic-gate case CODE_TERMACK:
3867c478bd9Sstevel@tonic-gate fsm_rtermack(f);
3877c478bd9Sstevel@tonic-gate break;
388*55fea89dSDan Cross
3897c478bd9Sstevel@tonic-gate case CODE_CODEREJ:
3907c478bd9Sstevel@tonic-gate fsm_rcoderej(f, inp, len);
3917c478bd9Sstevel@tonic-gate break;
392*55fea89dSDan Cross
3937c478bd9Sstevel@tonic-gate default:
3947c478bd9Sstevel@tonic-gate if (f->callbacks->extcode == NULL ||
3957c478bd9Sstevel@tonic-gate !(*f->callbacks->extcode)(f, code, id, inp, len))
3967c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_CODEREJ, ++f->id, inpacket, len + HEADERLEN);
3977c478bd9Sstevel@tonic-gate break;
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate
4027c478bd9Sstevel@tonic-gate /*
4037c478bd9Sstevel@tonic-gate * fsm_rconfreq - Receive Configure-Request.
4047c478bd9Sstevel@tonic-gate */
4057c478bd9Sstevel@tonic-gate static void
fsm_rconfreq(f,id,inp,len)4067c478bd9Sstevel@tonic-gate fsm_rconfreq(f, id, inp, len)
4077c478bd9Sstevel@tonic-gate fsm *f;
4087c478bd9Sstevel@tonic-gate u_char id;
4097c478bd9Sstevel@tonic-gate u_char *inp;
4107c478bd9Sstevel@tonic-gate int len;
4117c478bd9Sstevel@tonic-gate {
4127c478bd9Sstevel@tonic-gate int code, reject_if_disagree;
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate switch( f->state ){
4157c478bd9Sstevel@tonic-gate case CLOSED:
4167c478bd9Sstevel@tonic-gate /* Go away, we're closed */
4177c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMACK, id, NULL, 0);
4187c478bd9Sstevel@tonic-gate return;
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate case CLOSING:
4217c478bd9Sstevel@tonic-gate case STOPPING:
4227c478bd9Sstevel@tonic-gate dbglog("%s: discarded Configure-Request in state %s", PROTO_NAME(f),
4237c478bd9Sstevel@tonic-gate fsm_state(f->state));
4247c478bd9Sstevel@tonic-gate return;
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate case OPENED:
4277c478bd9Sstevel@tonic-gate /* Go down and restart negotiation */
4287c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL)
4297c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f); /* Inform upper layers */
4307c478bd9Sstevel@tonic-gate break;
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate #ifdef DEBUG
4347c478bd9Sstevel@tonic-gate if (inp >= outpacket_buf && inp < outpacket_buf+PPP_MRU+PPP_HDRLEN)
4357c478bd9Sstevel@tonic-gate fatal("bad pointer");
4367c478bd9Sstevel@tonic-gate #endif
4377c478bd9Sstevel@tonic-gate
4387c478bd9Sstevel@tonic-gate /*
4397c478bd9Sstevel@tonic-gate * Pass the requested configuration options
4407c478bd9Sstevel@tonic-gate * to protocol-specific code for checking.
4417c478bd9Sstevel@tonic-gate */
4427c478bd9Sstevel@tonic-gate if (f->callbacks->reqci != NULL) { /* Check CI */
4437c478bd9Sstevel@tonic-gate reject_if_disagree = (f->nakloops >= f->maxnakloops);
4447c478bd9Sstevel@tonic-gate code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
4457c478bd9Sstevel@tonic-gate } else if (len > 0)
4467c478bd9Sstevel@tonic-gate code = CODE_CONFREJ; /* Reject all CI */
4477c478bd9Sstevel@tonic-gate else
4487c478bd9Sstevel@tonic-gate code = CODE_CONFACK;
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate /* Allow NCP to do fancy footwork, such as reinitializing. */
4517c478bd9Sstevel@tonic-gate if (code <= 0)
4527c478bd9Sstevel@tonic-gate return;
4537c478bd9Sstevel@tonic-gate
4547c478bd9Sstevel@tonic-gate if (f->state == OPENED || f->state == STOPPED)
4557c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0); /* Send initial Configure-Request */
4567c478bd9Sstevel@tonic-gate
4577c478bd9Sstevel@tonic-gate /* send the Ack, Nak or Rej to the peer */
4587c478bd9Sstevel@tonic-gate fsm_sdata(f, code, id, inp, len);
4597c478bd9Sstevel@tonic-gate
4607c478bd9Sstevel@tonic-gate if (code == CODE_CONFACK) {
4617c478bd9Sstevel@tonic-gate /* RFC 1661 event RCR+ */
4627c478bd9Sstevel@tonic-gate if (f->state == ACKRCVD) {
4637c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
4647c478bd9Sstevel@tonic-gate f->state = OPENED;
4657c478bd9Sstevel@tonic-gate if (f->callbacks->up != NULL)
4667c478bd9Sstevel@tonic-gate (*f->callbacks->up)(f); /* Inform upper layers */
4677c478bd9Sstevel@tonic-gate } else
4687c478bd9Sstevel@tonic-gate f->state = ACKSENT;
4697c478bd9Sstevel@tonic-gate f->nakloops = 0;
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate } else {
4727c478bd9Sstevel@tonic-gate /* RFC 1661 event RCR- */
4737c478bd9Sstevel@tonic-gate /* (we sent CODE_CONFNAK or CODE_CONFREJ) */
4747c478bd9Sstevel@tonic-gate if (f->state != ACKRCVD)
4757c478bd9Sstevel@tonic-gate f->state = REQSENT;
4767c478bd9Sstevel@tonic-gate if( code == CODE_CONFNAK )
4777c478bd9Sstevel@tonic-gate ++f->nakloops;
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate /*
4837c478bd9Sstevel@tonic-gate * fsm_rconfack - Receive Configure-Ack.
4847c478bd9Sstevel@tonic-gate */
4857c478bd9Sstevel@tonic-gate static void
fsm_rconfack(f,id,inp,len)4867c478bd9Sstevel@tonic-gate fsm_rconfack(f, id, inp, len)
4877c478bd9Sstevel@tonic-gate fsm *f;
4887c478bd9Sstevel@tonic-gate int id;
4897c478bd9Sstevel@tonic-gate u_char *inp;
4907c478bd9Sstevel@tonic-gate int len;
4917c478bd9Sstevel@tonic-gate {
4927c478bd9Sstevel@tonic-gate if (id != f->reqid || f->seen_ack) /* Expected id? */
4937c478bd9Sstevel@tonic-gate return; /* Nope, toss... */
4947c478bd9Sstevel@tonic-gate if( !(f->callbacks->ackci != NULL ? (*f->callbacks->ackci)(f, inp, len):
4957c478bd9Sstevel@tonic-gate (len == 0)) ){
4967c478bd9Sstevel@tonic-gate /* Ack is bad - ignore it */
4977c478bd9Sstevel@tonic-gate error("Received bad configure-ack: %P", inp, len);
4987c478bd9Sstevel@tonic-gate return;
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate f->seen_ack = 1;
5017c478bd9Sstevel@tonic-gate
5027c478bd9Sstevel@tonic-gate switch (f->state) {
5037c478bd9Sstevel@tonic-gate case CLOSED:
5047c478bd9Sstevel@tonic-gate case STOPPED:
5057c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMACK, id, NULL, 0);
5067c478bd9Sstevel@tonic-gate break;
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate case REQSENT:
5097c478bd9Sstevel@tonic-gate f->state = ACKRCVD;
5107c478bd9Sstevel@tonic-gate f->retransmits = f->maxconfreqtransmits;
5117c478bd9Sstevel@tonic-gate break;
5127c478bd9Sstevel@tonic-gate
5137c478bd9Sstevel@tonic-gate case ACKRCVD:
5147c478bd9Sstevel@tonic-gate /* Huh? an extra valid Ack? oh well... */
5157c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
5167c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0);
5177c478bd9Sstevel@tonic-gate f->state = REQSENT;
5187c478bd9Sstevel@tonic-gate break;
5197c478bd9Sstevel@tonic-gate
5207c478bd9Sstevel@tonic-gate case ACKSENT:
5217c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
5227c478bd9Sstevel@tonic-gate f->state = OPENED;
5237c478bd9Sstevel@tonic-gate f->retransmits = f->maxconfreqtransmits;
5247c478bd9Sstevel@tonic-gate if (f->callbacks->up != NULL)
5257c478bd9Sstevel@tonic-gate (*f->callbacks->up)(f); /* Inform upper layers */
5267c478bd9Sstevel@tonic-gate break;
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate case OPENED:
5297c478bd9Sstevel@tonic-gate /* Go down and restart negotiation */
5307c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0); /* Send initial Configure-Request */
5317c478bd9Sstevel@tonic-gate f->state = REQSENT;
5327c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL)
5337c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f); /* Inform upper layers */
5347c478bd9Sstevel@tonic-gate break;
5357c478bd9Sstevel@tonic-gate }
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate
5387c478bd9Sstevel@tonic-gate
5397c478bd9Sstevel@tonic-gate /*
5407c478bd9Sstevel@tonic-gate * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
5417c478bd9Sstevel@tonic-gate */
5427c478bd9Sstevel@tonic-gate static void
fsm_rconfnakrej(f,code,id,inp,len)5437c478bd9Sstevel@tonic-gate fsm_rconfnakrej(f, code, id, inp, len)
5447c478bd9Sstevel@tonic-gate fsm *f;
5457c478bd9Sstevel@tonic-gate int code, id;
5467c478bd9Sstevel@tonic-gate u_char *inp;
5477c478bd9Sstevel@tonic-gate int len;
5487c478bd9Sstevel@tonic-gate {
5497c478bd9Sstevel@tonic-gate int (*proc) __P((fsm *, u_char *, int));
5507c478bd9Sstevel@tonic-gate int ret;
5517c478bd9Sstevel@tonic-gate
5527c478bd9Sstevel@tonic-gate if (id != f->reqid || f->seen_ack) /* Expected id? */
5537c478bd9Sstevel@tonic-gate return; /* Nope, toss... */
5547c478bd9Sstevel@tonic-gate proc = (code == CODE_CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
5557c478bd9Sstevel@tonic-gate if (proc == NULL || !(ret = proc(f, inp, len))) {
5567c478bd9Sstevel@tonic-gate /* Nak/reject is bad - ignore it */
5577c478bd9Sstevel@tonic-gate error("Received bad configure-nak/rej: %P", inp, len);
5587c478bd9Sstevel@tonic-gate return;
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate f->seen_ack = 1;
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate switch (f->state) {
5637c478bd9Sstevel@tonic-gate case CLOSED:
5647c478bd9Sstevel@tonic-gate case STOPPED:
5657c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMACK, id, NULL, 0);
5667c478bd9Sstevel@tonic-gate break;
5677c478bd9Sstevel@tonic-gate
5687c478bd9Sstevel@tonic-gate case REQSENT:
5697c478bd9Sstevel@tonic-gate case ACKSENT:
5707c478bd9Sstevel@tonic-gate /* They didn't agree to what we wanted - try another request */
5717c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
5727c478bd9Sstevel@tonic-gate if (ret < 0)
5737c478bd9Sstevel@tonic-gate f->state = STOPPED; /* kludge for stopping CCP */
5747c478bd9Sstevel@tonic-gate else
5757c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0); /* Send Configure-Request */
5767c478bd9Sstevel@tonic-gate break;
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate case ACKRCVD:
5797c478bd9Sstevel@tonic-gate /* Got a Nak/reject when we had already had an Ack?? oh well... */
5807c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
5817c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0);
5827c478bd9Sstevel@tonic-gate f->state = REQSENT;
5837c478bd9Sstevel@tonic-gate break;
5847c478bd9Sstevel@tonic-gate
5857c478bd9Sstevel@tonic-gate case OPENED:
5867c478bd9Sstevel@tonic-gate /* Go down and restart negotiation */
5877c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0); /* Send initial Configure-Request */
5887c478bd9Sstevel@tonic-gate f->state = REQSENT;
5897c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL)
5907c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f); /* Inform upper layers */
5917c478bd9Sstevel@tonic-gate break;
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate /*
5977c478bd9Sstevel@tonic-gate * fsm_rtermreq - Receive Terminate-Req.
5987c478bd9Sstevel@tonic-gate */
5997c478bd9Sstevel@tonic-gate static void
fsm_rtermreq(f,id,p,len)6007c478bd9Sstevel@tonic-gate fsm_rtermreq(f, id, p, len)
6017c478bd9Sstevel@tonic-gate fsm *f;
6027c478bd9Sstevel@tonic-gate int id;
6037c478bd9Sstevel@tonic-gate u_char *p;
6047c478bd9Sstevel@tonic-gate int len;
6057c478bd9Sstevel@tonic-gate {
6067c478bd9Sstevel@tonic-gate switch (f->state) {
6077c478bd9Sstevel@tonic-gate case ACKRCVD:
6087c478bd9Sstevel@tonic-gate case ACKSENT:
6097c478bd9Sstevel@tonic-gate f->state = REQSENT; /* Start over but keep trying */
6107c478bd9Sstevel@tonic-gate break;
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate case OPENED:
6137c478bd9Sstevel@tonic-gate if (len > 0) {
6147c478bd9Sstevel@tonic-gate info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p);
6157c478bd9Sstevel@tonic-gate } else {
6167c478bd9Sstevel@tonic-gate info("%s terminated by peer", PROTO_NAME(f));
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate f->state = STOPPING;
6197c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL)
6207c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f); /* Inform upper layers */
6217c478bd9Sstevel@tonic-gate f->retransmits = 0;
6227c478bd9Sstevel@tonic-gate TIMEOUT(fsm_timeout, f, f->timeouttime);
6237c478bd9Sstevel@tonic-gate break;
6247c478bd9Sstevel@tonic-gate }
6257c478bd9Sstevel@tonic-gate
6267c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMACK, id, NULL, 0);
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate /*
6317c478bd9Sstevel@tonic-gate * fsm_rtermack - Receive Terminate-Ack.
6327c478bd9Sstevel@tonic-gate */
6337c478bd9Sstevel@tonic-gate static void
fsm_rtermack(f)6347c478bd9Sstevel@tonic-gate fsm_rtermack(f)
6357c478bd9Sstevel@tonic-gate fsm *f;
6367c478bd9Sstevel@tonic-gate {
6377c478bd9Sstevel@tonic-gate switch (f->state) {
6387c478bd9Sstevel@tonic-gate case CLOSING:
6397c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f);
6407c478bd9Sstevel@tonic-gate f->state = CLOSED;
6417c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL)
6427c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f);
6437c478bd9Sstevel@tonic-gate break;
6447c478bd9Sstevel@tonic-gate case STOPPING:
6457c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f);
6467c478bd9Sstevel@tonic-gate f->state = STOPPED;
6477c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL)
6487c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f);
6497c478bd9Sstevel@tonic-gate break;
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate case ACKRCVD:
6527c478bd9Sstevel@tonic-gate f->state = REQSENT;
6537c478bd9Sstevel@tonic-gate break;
6547c478bd9Sstevel@tonic-gate
6557c478bd9Sstevel@tonic-gate case OPENED:
6567c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0);
6577c478bd9Sstevel@tonic-gate f->state = REQSENT;
6587c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL)
6597c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f); /* Inform upper layers */
6607c478bd9Sstevel@tonic-gate break;
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate /*
6667c478bd9Sstevel@tonic-gate * fsm_rcoderej - Receive a Code-Reject.
6677c478bd9Sstevel@tonic-gate */
6687c478bd9Sstevel@tonic-gate static void
fsm_rcoderej(f,inp,len)6697c478bd9Sstevel@tonic-gate fsm_rcoderej(f, inp, len)
6707c478bd9Sstevel@tonic-gate fsm *f;
6717c478bd9Sstevel@tonic-gate u_char *inp;
6727c478bd9Sstevel@tonic-gate int len;
6737c478bd9Sstevel@tonic-gate {
6747c478bd9Sstevel@tonic-gate u_char code, id;
6757c478bd9Sstevel@tonic-gate int seriouserr;
6767c478bd9Sstevel@tonic-gate
6777c478bd9Sstevel@tonic-gate if (len < HEADERLEN) {
6787c478bd9Sstevel@tonic-gate error("%s: Code-Reject too short (%d < %d)", PROTO_NAME(f), len,
6797c478bd9Sstevel@tonic-gate HEADERLEN);
6807c478bd9Sstevel@tonic-gate return;
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate GETCHAR(code, inp);
6837c478bd9Sstevel@tonic-gate GETCHAR(id, inp);
6847c478bd9Sstevel@tonic-gate len -= 2;
6857c478bd9Sstevel@tonic-gate warn("%s: Rcvd Code-Reject for %s id %d", PROTO_NAME(f),
6867c478bd9Sstevel@tonic-gate code_name(code,0), id);
6877c478bd9Sstevel@tonic-gate
6887c478bd9Sstevel@tonic-gate setbit(f->codemask, code);
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate /* Let the protocol know what happened. */
6917c478bd9Sstevel@tonic-gate if (f->callbacks->codereject != NULL) {
6927c478bd9Sstevel@tonic-gate seriouserr = (*f->callbacks->codereject)(f,code,id,inp,len);
6937c478bd9Sstevel@tonic-gate } else {
6947c478bd9Sstevel@tonic-gate /*
6957c478bd9Sstevel@tonic-gate * By default, it's RXJ- for well-known codes and RXJ+ for
6967c478bd9Sstevel@tonic-gate * unknown ones.
6977c478bd9Sstevel@tonic-gate */
6987c478bd9Sstevel@tonic-gate seriouserr = (code >= CODE_CONFREQ && code <= CODE_CODEREJ);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate if (seriouserr) {
7027c478bd9Sstevel@tonic-gate /* RXJ- -- shut down the protocol. */
7037c478bd9Sstevel@tonic-gate switch (f->state) {
7047c478bd9Sstevel@tonic-gate case CLOSING:
7057c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
7067c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/
7077c478bd9Sstevel@tonic-gate case CLOSED:
7087c478bd9Sstevel@tonic-gate f->state = CLOSED;
7097c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL)
7107c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f);
7117c478bd9Sstevel@tonic-gate break;
7127c478bd9Sstevel@tonic-gate
7137c478bd9Sstevel@tonic-gate case STOPPING:
7147c478bd9Sstevel@tonic-gate case REQSENT:
7157c478bd9Sstevel@tonic-gate case ACKRCVD:
7167c478bd9Sstevel@tonic-gate case ACKSENT:
7177c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
7187c478bd9Sstevel@tonic-gate f->state = STOPPED;
7197c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/
7207c478bd9Sstevel@tonic-gate case STOPPED:
7217c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL)
7227c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f);
7237c478bd9Sstevel@tonic-gate break;
7247c478bd9Sstevel@tonic-gate
7257c478bd9Sstevel@tonic-gate case OPENED:
7267c478bd9Sstevel@tonic-gate f->state = STOPPING;
7277c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL)
7287c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f);
7297c478bd9Sstevel@tonic-gate
7307c478bd9Sstevel@tonic-gate if (f->term_reason == NULL) {
7317c478bd9Sstevel@tonic-gate f->term_reason = "unacceptable Code-Reject received";
7327c478bd9Sstevel@tonic-gate f->term_reason_len = strlen(f->term_reason);
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate
7357c478bd9Sstevel@tonic-gate /* Init restart counter, send Terminate-Request */
7367c478bd9Sstevel@tonic-gate f->retransmits = f->maxtermtransmits;
7377c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id,
7387c478bd9Sstevel@tonic-gate (u_char *) f->term_reason, f->term_reason_len);
7397c478bd9Sstevel@tonic-gate TIMEOUT(fsm_timeout, f, f->timeouttime);
7407c478bd9Sstevel@tonic-gate --f->retransmits;
7417c478bd9Sstevel@tonic-gate break;
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate default:
7447c478bd9Sstevel@tonic-gate fatal("state error");
7457c478bd9Sstevel@tonic-gate }
7467c478bd9Sstevel@tonic-gate } else {
7477c478bd9Sstevel@tonic-gate /* RXJ+ -- just back up from Ack-Rcvd to Req-Sent. */
7487c478bd9Sstevel@tonic-gate if (f->state == ACKRCVD)
7497c478bd9Sstevel@tonic-gate f->state = REQSENT;
7507c478bd9Sstevel@tonic-gate }
7517c478bd9Sstevel@tonic-gate }
7527c478bd9Sstevel@tonic-gate
7537c478bd9Sstevel@tonic-gate
7547c478bd9Sstevel@tonic-gate /*
7557c478bd9Sstevel@tonic-gate * fsm_protreject - Peer doesn't speak this protocol.
7567c478bd9Sstevel@tonic-gate *
7577c478bd9Sstevel@tonic-gate * Treat this as a catastrophic error (RXJ-).
7587c478bd9Sstevel@tonic-gate */
7597c478bd9Sstevel@tonic-gate void
fsm_protreject(f)7607c478bd9Sstevel@tonic-gate fsm_protreject(f)
7617c478bd9Sstevel@tonic-gate fsm *f;
7627c478bd9Sstevel@tonic-gate {
7637c478bd9Sstevel@tonic-gate switch( f->state ){
7647c478bd9Sstevel@tonic-gate case CLOSING:
7657c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
7667c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/
7677c478bd9Sstevel@tonic-gate case CLOSED:
7687c478bd9Sstevel@tonic-gate f->state = CLOSED;
7697c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL)
7707c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f);
7717c478bd9Sstevel@tonic-gate break;
7727c478bd9Sstevel@tonic-gate
7737c478bd9Sstevel@tonic-gate case STOPPING:
7747c478bd9Sstevel@tonic-gate case REQSENT:
7757c478bd9Sstevel@tonic-gate case ACKRCVD:
7767c478bd9Sstevel@tonic-gate case ACKSENT:
7777c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
7787c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/
7797c478bd9Sstevel@tonic-gate case STOPPED:
7807c478bd9Sstevel@tonic-gate f->state = STOPPED;
7817c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL)
7827c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f);
7837c478bd9Sstevel@tonic-gate break;
7847c478bd9Sstevel@tonic-gate
7857c478bd9Sstevel@tonic-gate case OPENED:
7867c478bd9Sstevel@tonic-gate f->state = STOPPING;
7877c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL)
7887c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f);
7897c478bd9Sstevel@tonic-gate
7907c478bd9Sstevel@tonic-gate /* Init restart counter, send Terminate-Request */
7917c478bd9Sstevel@tonic-gate f->retransmits = f->maxtermtransmits;
7927c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id,
7937c478bd9Sstevel@tonic-gate (u_char *) f->term_reason, f->term_reason_len);
7947c478bd9Sstevel@tonic-gate TIMEOUT(fsm_timeout, f, f->timeouttime);
7957c478bd9Sstevel@tonic-gate --f->retransmits;
7967c478bd9Sstevel@tonic-gate break;
7977c478bd9Sstevel@tonic-gate
7987c478bd9Sstevel@tonic-gate default:
7997c478bd9Sstevel@tonic-gate dbglog("%s: Protocol-Reject in state %s", PROTO_NAME(f),
8007c478bd9Sstevel@tonic-gate fsm_state(f->state));
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate }
8037c478bd9Sstevel@tonic-gate
8047c478bd9Sstevel@tonic-gate
8057c478bd9Sstevel@tonic-gate /*
8067c478bd9Sstevel@tonic-gate * fsm_sconfreq - Send a Configure-Request.
8077c478bd9Sstevel@tonic-gate */
8087c478bd9Sstevel@tonic-gate static void
fsm_sconfreq(f,retransmit)8097c478bd9Sstevel@tonic-gate fsm_sconfreq(f, retransmit)
8107c478bd9Sstevel@tonic-gate fsm *f;
8117c478bd9Sstevel@tonic-gate int retransmit;
8127c478bd9Sstevel@tonic-gate {
8137c478bd9Sstevel@tonic-gate u_char *outp;
8147c478bd9Sstevel@tonic-gate int cilen;
8157c478bd9Sstevel@tonic-gate
8167c478bd9Sstevel@tonic-gate if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
8177c478bd9Sstevel@tonic-gate /* Not currently negotiating - reset options */
8187c478bd9Sstevel@tonic-gate if (f->callbacks->resetci != NULL)
8197c478bd9Sstevel@tonic-gate (*f->callbacks->resetci)(f);
8207c478bd9Sstevel@tonic-gate f->nakloops = 0;
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate
8237c478bd9Sstevel@tonic-gate if( !retransmit ){
8247c478bd9Sstevel@tonic-gate /* New request - reset retransmission counter, use new ID */
8257c478bd9Sstevel@tonic-gate f->retransmits = f->maxconfreqtransmits;
8267c478bd9Sstevel@tonic-gate f->reqid = ++f->id;
8277c478bd9Sstevel@tonic-gate }
8287c478bd9Sstevel@tonic-gate
8297c478bd9Sstevel@tonic-gate f->seen_ack = 0;
8307c478bd9Sstevel@tonic-gate
8317c478bd9Sstevel@tonic-gate /*
8327c478bd9Sstevel@tonic-gate * Make up the request packet
8337c478bd9Sstevel@tonic-gate */
8347c478bd9Sstevel@tonic-gate outp = outpacket_buf + PPP_HDRLEN + HEADERLEN;
8357c478bd9Sstevel@tonic-gate if (f->callbacks->cilen != NULL) {
8367c478bd9Sstevel@tonic-gate cilen = (*f->callbacks->cilen)(f);
8377c478bd9Sstevel@tonic-gate if (cilen > peer_mru[f->unit] - HEADERLEN)
8387c478bd9Sstevel@tonic-gate cilen = peer_mru[f->unit] - HEADERLEN;
8397c478bd9Sstevel@tonic-gate } else {
8407c478bd9Sstevel@tonic-gate cilen = peer_mru[f->unit] - HEADERLEN;
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate
8437c478bd9Sstevel@tonic-gate if (f->callbacks->addci != NULL)
8447c478bd9Sstevel@tonic-gate (*f->callbacks->addci)(f, outp, &cilen);
8457c478bd9Sstevel@tonic-gate else
8467c478bd9Sstevel@tonic-gate cilen = 0;
8477c478bd9Sstevel@tonic-gate
8487c478bd9Sstevel@tonic-gate /* send the request to our peer */
8497c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_CONFREQ, f->reqid, outp, cilen);
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate /* start the retransmit timer */
8527c478bd9Sstevel@tonic-gate --f->retransmits;
8537c478bd9Sstevel@tonic-gate TIMEOUT(fsm_timeout, f, f->timeouttime);
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate /*
8587c478bd9Sstevel@tonic-gate * fsm_sdata - Send some data.
8597c478bd9Sstevel@tonic-gate *
8607c478bd9Sstevel@tonic-gate * Used for all packets sent to our peer by this module.
8617c478bd9Sstevel@tonic-gate */
8627c478bd9Sstevel@tonic-gate void
fsm_sdata(f,code,id,data,datalen)8637c478bd9Sstevel@tonic-gate fsm_sdata(f, code, id, data, datalen)
8647c478bd9Sstevel@tonic-gate fsm *f;
8657c478bd9Sstevel@tonic-gate u_char code, id;
8667c478bd9Sstevel@tonic-gate u_char *data;
8677c478bd9Sstevel@tonic-gate int datalen;
8687c478bd9Sstevel@tonic-gate {
8697c478bd9Sstevel@tonic-gate u_char *outp;
8707c478bd9Sstevel@tonic-gate int outlen;
8717c478bd9Sstevel@tonic-gate
8727c478bd9Sstevel@tonic-gate if (isset(f->codemask,code)) {
8737c478bd9Sstevel@tonic-gate dbglog("%s: Peer has rejected %s; not sending another",
8747c478bd9Sstevel@tonic-gate PROTO_NAME(f), code_name(code,0));
8757c478bd9Sstevel@tonic-gate return;
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate
8787c478bd9Sstevel@tonic-gate /* Adjust length to be smaller than MTU */
8797c478bd9Sstevel@tonic-gate outp = outpacket_buf;
8807c478bd9Sstevel@tonic-gate if (datalen > peer_mru[f->unit] - HEADERLEN)
8817c478bd9Sstevel@tonic-gate datalen = peer_mru[f->unit] - HEADERLEN;
8827c478bd9Sstevel@tonic-gate if (datalen && data != outp + PPP_HDRLEN + HEADERLEN)
8837c478bd9Sstevel@tonic-gate BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
8847c478bd9Sstevel@tonic-gate outlen = datalen + HEADERLEN;
8857c478bd9Sstevel@tonic-gate MAKEHEADER(outp, f->protocol);
8867c478bd9Sstevel@tonic-gate PUTCHAR(code, outp);
8877c478bd9Sstevel@tonic-gate PUTCHAR(id, outp);
8887c478bd9Sstevel@tonic-gate PUTSHORT(outlen, outp);
8897c478bd9Sstevel@tonic-gate output(f->unit, outpacket_buf, outlen + PPP_HDRLEN);
8907c478bd9Sstevel@tonic-gate }
8917c478bd9Sstevel@tonic-gate
8927c478bd9Sstevel@tonic-gate /*
8937c478bd9Sstevel@tonic-gate * fsm_setpeermru - Set our idea of the peer's mru
8947c478bd9Sstevel@tonic-gate *
8957c478bd9Sstevel@tonic-gate * Used by routines in lcp.c which negotiate this value.
8967c478bd9Sstevel@tonic-gate */
8977c478bd9Sstevel@tonic-gate void
fsm_setpeermru(unit,mru)8987c478bd9Sstevel@tonic-gate fsm_setpeermru(unit, mru)
8997c478bd9Sstevel@tonic-gate int unit;
9007c478bd9Sstevel@tonic-gate int mru;
9017c478bd9Sstevel@tonic-gate {
9027c478bd9Sstevel@tonic-gate if (unit >= NUM_PPP) {
9037c478bd9Sstevel@tonic-gate dbglog("fsm_setpeermru: unit out of bounds");
9047c478bd9Sstevel@tonic-gate } else {
9057c478bd9Sstevel@tonic-gate peer_mru[unit] = mru;
9067c478bd9Sstevel@tonic-gate }
9077c478bd9Sstevel@tonic-gate }
908