1195972f6Sopenharmony_ci/* 2195972f6Sopenharmony_ci * fsm.c - {Link, IP} Control Protocol Finite State Machine. 3195972f6Sopenharmony_ci * 4195972f6Sopenharmony_ci * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. 5195972f6Sopenharmony_ci * 6195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 7195972f6Sopenharmony_ci * modification, are permitted provided that the following conditions 8195972f6Sopenharmony_ci * are met: 9195972f6Sopenharmony_ci * 10195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 11195972f6Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 12195972f6Sopenharmony_ci * 13195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 14195972f6Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 15195972f6Sopenharmony_ci * the documentation and/or other materials provided with the 16195972f6Sopenharmony_ci * distribution. 17195972f6Sopenharmony_ci * 18195972f6Sopenharmony_ci * 3. The name "Carnegie Mellon University" must not be used to 19195972f6Sopenharmony_ci * endorse or promote products derived from this software without 20195972f6Sopenharmony_ci * prior written permission. For permission or any legal 21195972f6Sopenharmony_ci * details, please contact 22195972f6Sopenharmony_ci * Office of Technology Transfer 23195972f6Sopenharmony_ci * Carnegie Mellon University 24195972f6Sopenharmony_ci * 5000 Forbes Avenue 25195972f6Sopenharmony_ci * Pittsburgh, PA 15213-3890 26195972f6Sopenharmony_ci * (412) 268-4387, fax: (412) 268-7395 27195972f6Sopenharmony_ci * tech-transfer@andrew.cmu.edu 28195972f6Sopenharmony_ci * 29195972f6Sopenharmony_ci * 4. Redistributions of any form whatsoever must retain the following 30195972f6Sopenharmony_ci * acknowledgment: 31195972f6Sopenharmony_ci * "This product includes software developed by Computing Services 32195972f6Sopenharmony_ci * at Carnegie Mellon University (http://www.cmu.edu/computing/)." 33195972f6Sopenharmony_ci * 34195972f6Sopenharmony_ci * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO 35195972f6Sopenharmony_ci * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 36195972f6Sopenharmony_ci * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 37195972f6Sopenharmony_ci * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 38195972f6Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 39195972f6Sopenharmony_ci * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 40195972f6Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 41195972f6Sopenharmony_ci */ 42195972f6Sopenharmony_ci 43195972f6Sopenharmony_ci#include "netif/ppp/ppp_opts.h" 44195972f6Sopenharmony_ci#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ 45195972f6Sopenharmony_ci 46195972f6Sopenharmony_ci/* 47195972f6Sopenharmony_ci * @todo: 48195972f6Sopenharmony_ci * Randomize fsm id on link/init. 49195972f6Sopenharmony_ci * Deal with variable outgoing MTU. 50195972f6Sopenharmony_ci */ 51195972f6Sopenharmony_ci 52195972f6Sopenharmony_ci#if 0 /* UNUSED */ 53195972f6Sopenharmony_ci#include <stdio.h> 54195972f6Sopenharmony_ci#include <string.h> 55195972f6Sopenharmony_ci#include <sys/types.h> 56195972f6Sopenharmony_ci#endif /* UNUSED */ 57195972f6Sopenharmony_ci 58195972f6Sopenharmony_ci#include "netif/ppp/ppp_impl.h" 59195972f6Sopenharmony_ci 60195972f6Sopenharmony_ci#include "netif/ppp/fsm.h" 61195972f6Sopenharmony_ci 62195972f6Sopenharmony_cistatic void fsm_timeout (void *); 63195972f6Sopenharmony_cistatic void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len); 64195972f6Sopenharmony_cistatic void fsm_rconfack(fsm *f, int id, u_char *inp, int len); 65195972f6Sopenharmony_cistatic void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len); 66195972f6Sopenharmony_cistatic void fsm_rtermreq(fsm *f, int id, u_char *p, int len); 67195972f6Sopenharmony_cistatic void fsm_rtermack(fsm *f); 68195972f6Sopenharmony_cistatic void fsm_rcoderej(fsm *f, u_char *inp, int len); 69195972f6Sopenharmony_cistatic void fsm_sconfreq(fsm *f, int retransmit); 70195972f6Sopenharmony_ci 71195972f6Sopenharmony_ci#define PROTO_NAME(f) ((f)->callbacks->proto_name) 72195972f6Sopenharmony_ci 73195972f6Sopenharmony_ci/* 74195972f6Sopenharmony_ci * fsm_init - Initialize fsm. 75195972f6Sopenharmony_ci * 76195972f6Sopenharmony_ci * Initialize fsm state. 77195972f6Sopenharmony_ci */ 78195972f6Sopenharmony_civoid fsm_init(fsm *f) { 79195972f6Sopenharmony_ci ppp_pcb *pcb = f->pcb; 80195972f6Sopenharmony_ci f->state = PPP_FSM_INITIAL; 81195972f6Sopenharmony_ci f->flags = 0; 82195972f6Sopenharmony_ci f->id = 0; /* XXX Start with random id? */ 83195972f6Sopenharmony_ci f->maxnakloops = pcb->settings.fsm_max_nak_loops; 84195972f6Sopenharmony_ci f->term_reason_len = 0; 85195972f6Sopenharmony_ci} 86195972f6Sopenharmony_ci 87195972f6Sopenharmony_ci 88195972f6Sopenharmony_ci/* 89195972f6Sopenharmony_ci * fsm_lowerup - The lower layer is up. 90195972f6Sopenharmony_ci */ 91195972f6Sopenharmony_civoid fsm_lowerup(fsm *f) { 92195972f6Sopenharmony_ci switch( f->state ){ 93195972f6Sopenharmony_ci case PPP_FSM_INITIAL: 94195972f6Sopenharmony_ci f->state = PPP_FSM_CLOSED; 95195972f6Sopenharmony_ci break; 96195972f6Sopenharmony_ci 97195972f6Sopenharmony_ci case PPP_FSM_STARTING: 98195972f6Sopenharmony_ci if( f->flags & OPT_SILENT ) 99195972f6Sopenharmony_ci f->state = PPP_FSM_STOPPED; 100195972f6Sopenharmony_ci else { 101195972f6Sopenharmony_ci /* Send an initial configure-request */ 102195972f6Sopenharmony_ci fsm_sconfreq(f, 0); 103195972f6Sopenharmony_ci f->state = PPP_FSM_REQSENT; 104195972f6Sopenharmony_ci } 105195972f6Sopenharmony_ci break; 106195972f6Sopenharmony_ci 107195972f6Sopenharmony_ci default: 108195972f6Sopenharmony_ci FSMDEBUG(("%s: Up event in state %d!", PROTO_NAME(f), f->state)); 109195972f6Sopenharmony_ci /* no break */ 110195972f6Sopenharmony_ci } 111195972f6Sopenharmony_ci} 112195972f6Sopenharmony_ci 113195972f6Sopenharmony_ci 114195972f6Sopenharmony_ci/* 115195972f6Sopenharmony_ci * fsm_lowerdown - The lower layer is down. 116195972f6Sopenharmony_ci * 117195972f6Sopenharmony_ci * Cancel all timeouts and inform upper layers. 118195972f6Sopenharmony_ci */ 119195972f6Sopenharmony_civoid fsm_lowerdown(fsm *f) { 120195972f6Sopenharmony_ci switch( f->state ){ 121195972f6Sopenharmony_ci case PPP_FSM_CLOSED: 122195972f6Sopenharmony_ci f->state = PPP_FSM_INITIAL; 123195972f6Sopenharmony_ci break; 124195972f6Sopenharmony_ci 125195972f6Sopenharmony_ci case PPP_FSM_STOPPED: 126195972f6Sopenharmony_ci f->state = PPP_FSM_STARTING; 127195972f6Sopenharmony_ci if( f->callbacks->starting ) 128195972f6Sopenharmony_ci (*f->callbacks->starting)(f); 129195972f6Sopenharmony_ci break; 130195972f6Sopenharmony_ci 131195972f6Sopenharmony_ci case PPP_FSM_CLOSING: 132195972f6Sopenharmony_ci f->state = PPP_FSM_INITIAL; 133195972f6Sopenharmony_ci UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 134195972f6Sopenharmony_ci break; 135195972f6Sopenharmony_ci 136195972f6Sopenharmony_ci case PPP_FSM_STOPPING: 137195972f6Sopenharmony_ci case PPP_FSM_REQSENT: 138195972f6Sopenharmony_ci case PPP_FSM_ACKRCVD: 139195972f6Sopenharmony_ci case PPP_FSM_ACKSENT: 140195972f6Sopenharmony_ci f->state = PPP_FSM_STARTING; 141195972f6Sopenharmony_ci UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 142195972f6Sopenharmony_ci break; 143195972f6Sopenharmony_ci 144195972f6Sopenharmony_ci case PPP_FSM_OPENED: 145195972f6Sopenharmony_ci if( f->callbacks->down ) 146195972f6Sopenharmony_ci (*f->callbacks->down)(f); 147195972f6Sopenharmony_ci f->state = PPP_FSM_STARTING; 148195972f6Sopenharmony_ci break; 149195972f6Sopenharmony_ci 150195972f6Sopenharmony_ci default: 151195972f6Sopenharmony_ci FSMDEBUG(("%s: Down event in state %d!", PROTO_NAME(f), f->state)); 152195972f6Sopenharmony_ci /* no break */ 153195972f6Sopenharmony_ci } 154195972f6Sopenharmony_ci} 155195972f6Sopenharmony_ci 156195972f6Sopenharmony_ci 157195972f6Sopenharmony_ci/* 158195972f6Sopenharmony_ci * fsm_open - Link is allowed to come up. 159195972f6Sopenharmony_ci */ 160195972f6Sopenharmony_civoid fsm_open(fsm *f) { 161195972f6Sopenharmony_ci switch( f->state ){ 162195972f6Sopenharmony_ci case PPP_FSM_INITIAL: 163195972f6Sopenharmony_ci f->state = PPP_FSM_STARTING; 164195972f6Sopenharmony_ci if( f->callbacks->starting ) 165195972f6Sopenharmony_ci (*f->callbacks->starting)(f); 166195972f6Sopenharmony_ci break; 167195972f6Sopenharmony_ci 168195972f6Sopenharmony_ci case PPP_FSM_CLOSED: 169195972f6Sopenharmony_ci if( f->flags & OPT_SILENT ) 170195972f6Sopenharmony_ci f->state = PPP_FSM_STOPPED; 171195972f6Sopenharmony_ci else { 172195972f6Sopenharmony_ci /* Send an initial configure-request */ 173195972f6Sopenharmony_ci fsm_sconfreq(f, 0); 174195972f6Sopenharmony_ci f->state = PPP_FSM_REQSENT; 175195972f6Sopenharmony_ci } 176195972f6Sopenharmony_ci break; 177195972f6Sopenharmony_ci 178195972f6Sopenharmony_ci case PPP_FSM_CLOSING: 179195972f6Sopenharmony_ci f->state = PPP_FSM_STOPPING; 180195972f6Sopenharmony_ci /* fall through */ 181195972f6Sopenharmony_ci /* no break */ 182195972f6Sopenharmony_ci case PPP_FSM_STOPPED: 183195972f6Sopenharmony_ci case PPP_FSM_OPENED: 184195972f6Sopenharmony_ci if( f->flags & OPT_RESTART ){ 185195972f6Sopenharmony_ci fsm_lowerdown(f); 186195972f6Sopenharmony_ci fsm_lowerup(f); 187195972f6Sopenharmony_ci } 188195972f6Sopenharmony_ci break; 189195972f6Sopenharmony_ci default: 190195972f6Sopenharmony_ci break; 191195972f6Sopenharmony_ci } 192195972f6Sopenharmony_ci} 193195972f6Sopenharmony_ci 194195972f6Sopenharmony_ci/* 195195972f6Sopenharmony_ci * terminate_layer - Start process of shutting down the FSM 196195972f6Sopenharmony_ci * 197195972f6Sopenharmony_ci * Cancel any timeout running, notify upper layers we're done, and 198195972f6Sopenharmony_ci * send a terminate-request message as configured. 199195972f6Sopenharmony_ci */ 200195972f6Sopenharmony_cistatic void terminate_layer(fsm *f, int nextstate) { 201195972f6Sopenharmony_ci ppp_pcb *pcb = f->pcb; 202195972f6Sopenharmony_ci 203195972f6Sopenharmony_ci if( f->state != PPP_FSM_OPENED ) 204195972f6Sopenharmony_ci UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 205195972f6Sopenharmony_ci else if( f->callbacks->down ) 206195972f6Sopenharmony_ci (*f->callbacks->down)(f); /* Inform upper layers we're down */ 207195972f6Sopenharmony_ci 208195972f6Sopenharmony_ci /* Init restart counter and send Terminate-Request */ 209195972f6Sopenharmony_ci f->retransmits = pcb->settings.fsm_max_term_transmits; 210195972f6Sopenharmony_ci fsm_sdata(f, TERMREQ, f->reqid = ++f->id, 211195972f6Sopenharmony_ci (const u_char *) f->term_reason, f->term_reason_len); 212195972f6Sopenharmony_ci 213195972f6Sopenharmony_ci if (f->retransmits == 0) { 214195972f6Sopenharmony_ci /* 215195972f6Sopenharmony_ci * User asked for no terminate requests at all; just close it. 216195972f6Sopenharmony_ci * We've already fired off one Terminate-Request just to be nice 217195972f6Sopenharmony_ci * to the peer, but we're not going to wait for a reply. 218195972f6Sopenharmony_ci */ 219195972f6Sopenharmony_ci f->state = nextstate == PPP_FSM_CLOSING ? PPP_FSM_CLOSED : PPP_FSM_STOPPED; 220195972f6Sopenharmony_ci if( f->callbacks->finished ) 221195972f6Sopenharmony_ci (*f->callbacks->finished)(f); 222195972f6Sopenharmony_ci return; 223195972f6Sopenharmony_ci } 224195972f6Sopenharmony_ci 225195972f6Sopenharmony_ci TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); 226195972f6Sopenharmony_ci --f->retransmits; 227195972f6Sopenharmony_ci 228195972f6Sopenharmony_ci f->state = nextstate; 229195972f6Sopenharmony_ci} 230195972f6Sopenharmony_ci 231195972f6Sopenharmony_ci/* 232195972f6Sopenharmony_ci * fsm_close - Start closing connection. 233195972f6Sopenharmony_ci * 234195972f6Sopenharmony_ci * Cancel timeouts and either initiate close or possibly go directly to 235195972f6Sopenharmony_ci * the PPP_FSM_CLOSED state. 236195972f6Sopenharmony_ci */ 237195972f6Sopenharmony_civoid fsm_close(fsm *f, const char *reason) { 238195972f6Sopenharmony_ci f->term_reason = reason; 239195972f6Sopenharmony_ci f->term_reason_len = (reason == NULL? 0: (u8_t)LWIP_MIN(strlen(reason), 0xFF) ); 240195972f6Sopenharmony_ci switch( f->state ){ 241195972f6Sopenharmony_ci case PPP_FSM_STARTING: 242195972f6Sopenharmony_ci f->state = PPP_FSM_INITIAL; 243195972f6Sopenharmony_ci break; 244195972f6Sopenharmony_ci case PPP_FSM_STOPPED: 245195972f6Sopenharmony_ci f->state = PPP_FSM_CLOSED; 246195972f6Sopenharmony_ci break; 247195972f6Sopenharmony_ci case PPP_FSM_STOPPING: 248195972f6Sopenharmony_ci f->state = PPP_FSM_CLOSING; 249195972f6Sopenharmony_ci break; 250195972f6Sopenharmony_ci 251195972f6Sopenharmony_ci case PPP_FSM_REQSENT: 252195972f6Sopenharmony_ci case PPP_FSM_ACKRCVD: 253195972f6Sopenharmony_ci case PPP_FSM_ACKSENT: 254195972f6Sopenharmony_ci case PPP_FSM_OPENED: 255195972f6Sopenharmony_ci terminate_layer(f, PPP_FSM_CLOSING); 256195972f6Sopenharmony_ci break; 257195972f6Sopenharmony_ci default: 258195972f6Sopenharmony_ci break; 259195972f6Sopenharmony_ci } 260195972f6Sopenharmony_ci} 261195972f6Sopenharmony_ci 262195972f6Sopenharmony_ci 263195972f6Sopenharmony_ci/* 264195972f6Sopenharmony_ci * fsm_timeout - Timeout expired. 265195972f6Sopenharmony_ci */ 266195972f6Sopenharmony_cistatic void fsm_timeout(void *arg) { 267195972f6Sopenharmony_ci fsm *f = (fsm *) arg; 268195972f6Sopenharmony_ci ppp_pcb *pcb = f->pcb; 269195972f6Sopenharmony_ci 270195972f6Sopenharmony_ci switch (f->state) { 271195972f6Sopenharmony_ci case PPP_FSM_CLOSING: 272195972f6Sopenharmony_ci case PPP_FSM_STOPPING: 273195972f6Sopenharmony_ci if( f->retransmits <= 0 ){ 274195972f6Sopenharmony_ci /* 275195972f6Sopenharmony_ci * We've waited for an ack long enough. Peer probably heard us. 276195972f6Sopenharmony_ci */ 277195972f6Sopenharmony_ci f->state = (f->state == PPP_FSM_CLOSING)? PPP_FSM_CLOSED: PPP_FSM_STOPPED; 278195972f6Sopenharmony_ci if( f->callbacks->finished ) 279195972f6Sopenharmony_ci (*f->callbacks->finished)(f); 280195972f6Sopenharmony_ci } else { 281195972f6Sopenharmony_ci /* Send Terminate-Request */ 282195972f6Sopenharmony_ci fsm_sdata(f, TERMREQ, f->reqid = ++f->id, 283195972f6Sopenharmony_ci (const u_char *) f->term_reason, f->term_reason_len); 284195972f6Sopenharmony_ci TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); 285195972f6Sopenharmony_ci --f->retransmits; 286195972f6Sopenharmony_ci } 287195972f6Sopenharmony_ci break; 288195972f6Sopenharmony_ci 289195972f6Sopenharmony_ci case PPP_FSM_REQSENT: 290195972f6Sopenharmony_ci case PPP_FSM_ACKRCVD: 291195972f6Sopenharmony_ci case PPP_FSM_ACKSENT: 292195972f6Sopenharmony_ci if (f->retransmits <= 0) { 293195972f6Sopenharmony_ci ppp_warn("%s: timeout sending Config-Requests", PROTO_NAME(f)); 294195972f6Sopenharmony_ci f->state = PPP_FSM_STOPPED; 295195972f6Sopenharmony_ci if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) 296195972f6Sopenharmony_ci (*f->callbacks->finished)(f); 297195972f6Sopenharmony_ci 298195972f6Sopenharmony_ci } else { 299195972f6Sopenharmony_ci /* Retransmit the configure-request */ 300195972f6Sopenharmony_ci if (f->callbacks->retransmit) 301195972f6Sopenharmony_ci (*f->callbacks->retransmit)(f); 302195972f6Sopenharmony_ci fsm_sconfreq(f, 1); /* Re-send Configure-Request */ 303195972f6Sopenharmony_ci if( f->state == PPP_FSM_ACKRCVD ) 304195972f6Sopenharmony_ci f->state = PPP_FSM_REQSENT; 305195972f6Sopenharmony_ci } 306195972f6Sopenharmony_ci break; 307195972f6Sopenharmony_ci 308195972f6Sopenharmony_ci default: 309195972f6Sopenharmony_ci FSMDEBUG(("%s: Timeout event in state %d!", PROTO_NAME(f), f->state)); 310195972f6Sopenharmony_ci /* no break */ 311195972f6Sopenharmony_ci } 312195972f6Sopenharmony_ci} 313195972f6Sopenharmony_ci 314195972f6Sopenharmony_ci 315195972f6Sopenharmony_ci/* 316195972f6Sopenharmony_ci * fsm_input - Input packet. 317195972f6Sopenharmony_ci */ 318195972f6Sopenharmony_civoid fsm_input(fsm *f, u_char *inpacket, int l) { 319195972f6Sopenharmony_ci u_char *inp; 320195972f6Sopenharmony_ci u_char code, id; 321195972f6Sopenharmony_ci int len; 322195972f6Sopenharmony_ci 323195972f6Sopenharmony_ci /* 324195972f6Sopenharmony_ci * Parse header (code, id and length). 325195972f6Sopenharmony_ci * If packet too short, drop it. 326195972f6Sopenharmony_ci */ 327195972f6Sopenharmony_ci inp = inpacket; 328195972f6Sopenharmony_ci if (l < HEADERLEN) { 329195972f6Sopenharmony_ci FSMDEBUG(("fsm_input(%x): Rcvd short header.", f->protocol)); 330195972f6Sopenharmony_ci return; 331195972f6Sopenharmony_ci } 332195972f6Sopenharmony_ci GETCHAR(code, inp); 333195972f6Sopenharmony_ci GETCHAR(id, inp); 334195972f6Sopenharmony_ci GETSHORT(len, inp); 335195972f6Sopenharmony_ci if (len < HEADERLEN) { 336195972f6Sopenharmony_ci FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol)); 337195972f6Sopenharmony_ci return; 338195972f6Sopenharmony_ci } 339195972f6Sopenharmony_ci if (len > l) { 340195972f6Sopenharmony_ci FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol)); 341195972f6Sopenharmony_ci return; 342195972f6Sopenharmony_ci } 343195972f6Sopenharmony_ci len -= HEADERLEN; /* subtract header length */ 344195972f6Sopenharmony_ci 345195972f6Sopenharmony_ci if( f->state == PPP_FSM_INITIAL || f->state == PPP_FSM_STARTING ){ 346195972f6Sopenharmony_ci FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.", 347195972f6Sopenharmony_ci f->protocol, f->state)); 348195972f6Sopenharmony_ci return; 349195972f6Sopenharmony_ci } 350195972f6Sopenharmony_ci 351195972f6Sopenharmony_ci /* 352195972f6Sopenharmony_ci * Action depends on code. 353195972f6Sopenharmony_ci */ 354195972f6Sopenharmony_ci switch (code) { 355195972f6Sopenharmony_ci case CONFREQ: 356195972f6Sopenharmony_ci fsm_rconfreq(f, id, inp, len); 357195972f6Sopenharmony_ci break; 358195972f6Sopenharmony_ci 359195972f6Sopenharmony_ci case CONFACK: 360195972f6Sopenharmony_ci fsm_rconfack(f, id, inp, len); 361195972f6Sopenharmony_ci break; 362195972f6Sopenharmony_ci 363195972f6Sopenharmony_ci case CONFNAK: 364195972f6Sopenharmony_ci case CONFREJ: 365195972f6Sopenharmony_ci fsm_rconfnakrej(f, code, id, inp, len); 366195972f6Sopenharmony_ci break; 367195972f6Sopenharmony_ci 368195972f6Sopenharmony_ci case TERMREQ: 369195972f6Sopenharmony_ci fsm_rtermreq(f, id, inp, len); 370195972f6Sopenharmony_ci break; 371195972f6Sopenharmony_ci 372195972f6Sopenharmony_ci case TERMACK: 373195972f6Sopenharmony_ci fsm_rtermack(f); 374195972f6Sopenharmony_ci break; 375195972f6Sopenharmony_ci 376195972f6Sopenharmony_ci case CODEREJ: 377195972f6Sopenharmony_ci fsm_rcoderej(f, inp, len); 378195972f6Sopenharmony_ci break; 379195972f6Sopenharmony_ci 380195972f6Sopenharmony_ci default: 381195972f6Sopenharmony_ci if( !f->callbacks->extcode 382195972f6Sopenharmony_ci || !(*f->callbacks->extcode)(f, code, id, inp, len) ) 383195972f6Sopenharmony_ci fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); 384195972f6Sopenharmony_ci break; 385195972f6Sopenharmony_ci } 386195972f6Sopenharmony_ci} 387195972f6Sopenharmony_ci 388195972f6Sopenharmony_ci 389195972f6Sopenharmony_ci/* 390195972f6Sopenharmony_ci * fsm_rconfreq - Receive Configure-Request. 391195972f6Sopenharmony_ci */ 392195972f6Sopenharmony_cistatic void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len) { 393195972f6Sopenharmony_ci int code, reject_if_disagree; 394195972f6Sopenharmony_ci 395195972f6Sopenharmony_ci switch( f->state ){ 396195972f6Sopenharmony_ci case PPP_FSM_CLOSED: 397195972f6Sopenharmony_ci /* Go away, we're closed */ 398195972f6Sopenharmony_ci fsm_sdata(f, TERMACK, id, NULL, 0); 399195972f6Sopenharmony_ci return; 400195972f6Sopenharmony_ci case PPP_FSM_CLOSING: 401195972f6Sopenharmony_ci case PPP_FSM_STOPPING: 402195972f6Sopenharmony_ci return; 403195972f6Sopenharmony_ci 404195972f6Sopenharmony_ci case PPP_FSM_OPENED: 405195972f6Sopenharmony_ci /* Go down and restart negotiation */ 406195972f6Sopenharmony_ci if( f->callbacks->down ) 407195972f6Sopenharmony_ci (*f->callbacks->down)(f); /* Inform upper layers */ 408195972f6Sopenharmony_ci fsm_sconfreq(f, 0); /* Send initial Configure-Request */ 409195972f6Sopenharmony_ci f->state = PPP_FSM_REQSENT; 410195972f6Sopenharmony_ci break; 411195972f6Sopenharmony_ci 412195972f6Sopenharmony_ci case PPP_FSM_STOPPED: 413195972f6Sopenharmony_ci /* Negotiation started by our peer */ 414195972f6Sopenharmony_ci fsm_sconfreq(f, 0); /* Send initial Configure-Request */ 415195972f6Sopenharmony_ci f->state = PPP_FSM_REQSENT; 416195972f6Sopenharmony_ci break; 417195972f6Sopenharmony_ci default: 418195972f6Sopenharmony_ci break; 419195972f6Sopenharmony_ci } 420195972f6Sopenharmony_ci 421195972f6Sopenharmony_ci /* 422195972f6Sopenharmony_ci * Pass the requested configuration options 423195972f6Sopenharmony_ci * to protocol-specific code for checking. 424195972f6Sopenharmony_ci */ 425195972f6Sopenharmony_ci if (f->callbacks->reqci){ /* Check CI */ 426195972f6Sopenharmony_ci reject_if_disagree = (f->nakloops >= f->maxnakloops); 427195972f6Sopenharmony_ci code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree); 428195972f6Sopenharmony_ci } else if (len) 429195972f6Sopenharmony_ci code = CONFREJ; /* Reject all CI */ 430195972f6Sopenharmony_ci else 431195972f6Sopenharmony_ci code = CONFACK; 432195972f6Sopenharmony_ci 433195972f6Sopenharmony_ci /* send the Ack, Nak or Rej to the peer */ 434195972f6Sopenharmony_ci fsm_sdata(f, code, id, inp, len); 435195972f6Sopenharmony_ci 436195972f6Sopenharmony_ci if (code == CONFACK) { 437195972f6Sopenharmony_ci if (f->state == PPP_FSM_ACKRCVD) { 438195972f6Sopenharmony_ci UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 439195972f6Sopenharmony_ci f->state = PPP_FSM_OPENED; 440195972f6Sopenharmony_ci if (f->callbacks->up) 441195972f6Sopenharmony_ci (*f->callbacks->up)(f); /* Inform upper layers */ 442195972f6Sopenharmony_ci } else 443195972f6Sopenharmony_ci f->state = PPP_FSM_ACKSENT; 444195972f6Sopenharmony_ci f->nakloops = 0; 445195972f6Sopenharmony_ci 446195972f6Sopenharmony_ci } else { 447195972f6Sopenharmony_ci /* we sent CONFACK or CONFREJ */ 448195972f6Sopenharmony_ci if (f->state != PPP_FSM_ACKRCVD) 449195972f6Sopenharmony_ci f->state = PPP_FSM_REQSENT; 450195972f6Sopenharmony_ci if( code == CONFNAK ) 451195972f6Sopenharmony_ci ++f->nakloops; 452195972f6Sopenharmony_ci } 453195972f6Sopenharmony_ci} 454195972f6Sopenharmony_ci 455195972f6Sopenharmony_ci 456195972f6Sopenharmony_ci/* 457195972f6Sopenharmony_ci * fsm_rconfack - Receive Configure-Ack. 458195972f6Sopenharmony_ci */ 459195972f6Sopenharmony_cistatic void fsm_rconfack(fsm *f, int id, u_char *inp, int len) { 460195972f6Sopenharmony_ci ppp_pcb *pcb = f->pcb; 461195972f6Sopenharmony_ci 462195972f6Sopenharmony_ci if (id != f->reqid || f->seen_ack) /* Expected id? */ 463195972f6Sopenharmony_ci return; /* Nope, toss... */ 464195972f6Sopenharmony_ci if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): 465195972f6Sopenharmony_ci (len == 0)) ){ 466195972f6Sopenharmony_ci /* Ack is bad - ignore it */ 467195972f6Sopenharmony_ci ppp_error("Received bad configure-ack: %P", inp, len); 468195972f6Sopenharmony_ci return; 469195972f6Sopenharmony_ci } 470195972f6Sopenharmony_ci f->seen_ack = 1; 471195972f6Sopenharmony_ci f->rnakloops = 0; 472195972f6Sopenharmony_ci 473195972f6Sopenharmony_ci switch (f->state) { 474195972f6Sopenharmony_ci case PPP_FSM_CLOSED: 475195972f6Sopenharmony_ci case PPP_FSM_STOPPED: 476195972f6Sopenharmony_ci fsm_sdata(f, TERMACK, id, NULL, 0); 477195972f6Sopenharmony_ci break; 478195972f6Sopenharmony_ci 479195972f6Sopenharmony_ci case PPP_FSM_REQSENT: 480195972f6Sopenharmony_ci f->state = PPP_FSM_ACKRCVD; 481195972f6Sopenharmony_ci f->retransmits = pcb->settings.fsm_max_conf_req_transmits; 482195972f6Sopenharmony_ci break; 483195972f6Sopenharmony_ci 484195972f6Sopenharmony_ci case PPP_FSM_ACKRCVD: 485195972f6Sopenharmony_ci /* Huh? an extra valid Ack? oh well... */ 486195972f6Sopenharmony_ci UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 487195972f6Sopenharmony_ci fsm_sconfreq(f, 0); 488195972f6Sopenharmony_ci f->state = PPP_FSM_REQSENT; 489195972f6Sopenharmony_ci break; 490195972f6Sopenharmony_ci 491195972f6Sopenharmony_ci case PPP_FSM_ACKSENT: 492195972f6Sopenharmony_ci UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 493195972f6Sopenharmony_ci f->state = PPP_FSM_OPENED; 494195972f6Sopenharmony_ci f->retransmits = pcb->settings.fsm_max_conf_req_transmits; 495195972f6Sopenharmony_ci if (f->callbacks->up) 496195972f6Sopenharmony_ci (*f->callbacks->up)(f); /* Inform upper layers */ 497195972f6Sopenharmony_ci break; 498195972f6Sopenharmony_ci 499195972f6Sopenharmony_ci case PPP_FSM_OPENED: 500195972f6Sopenharmony_ci /* Go down and restart negotiation */ 501195972f6Sopenharmony_ci if (f->callbacks->down) 502195972f6Sopenharmony_ci (*f->callbacks->down)(f); /* Inform upper layers */ 503195972f6Sopenharmony_ci fsm_sconfreq(f, 0); /* Send initial Configure-Request */ 504195972f6Sopenharmony_ci f->state = PPP_FSM_REQSENT; 505195972f6Sopenharmony_ci break; 506195972f6Sopenharmony_ci default: 507195972f6Sopenharmony_ci break; 508195972f6Sopenharmony_ci } 509195972f6Sopenharmony_ci} 510195972f6Sopenharmony_ci 511195972f6Sopenharmony_ci 512195972f6Sopenharmony_ci/* 513195972f6Sopenharmony_ci * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. 514195972f6Sopenharmony_ci */ 515195972f6Sopenharmony_cistatic void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len) { 516195972f6Sopenharmony_ci int ret; 517195972f6Sopenharmony_ci int treat_as_reject; 518195972f6Sopenharmony_ci 519195972f6Sopenharmony_ci if (id != f->reqid || f->seen_ack) /* Expected id? */ 520195972f6Sopenharmony_ci return; /* Nope, toss... */ 521195972f6Sopenharmony_ci 522195972f6Sopenharmony_ci if (code == CONFNAK) { 523195972f6Sopenharmony_ci ++f->rnakloops; 524195972f6Sopenharmony_ci treat_as_reject = (f->rnakloops >= f->maxnakloops); 525195972f6Sopenharmony_ci if (f->callbacks->nakci == NULL 526195972f6Sopenharmony_ci || !(ret = f->callbacks->nakci(f, inp, len, treat_as_reject))) { 527195972f6Sopenharmony_ci ppp_error("Received bad configure-nak: %P", inp, len); 528195972f6Sopenharmony_ci return; 529195972f6Sopenharmony_ci } 530195972f6Sopenharmony_ci } else { 531195972f6Sopenharmony_ci f->rnakloops = 0; 532195972f6Sopenharmony_ci if (f->callbacks->rejci == NULL 533195972f6Sopenharmony_ci || !(ret = f->callbacks->rejci(f, inp, len))) { 534195972f6Sopenharmony_ci ppp_error("Received bad configure-rej: %P", inp, len); 535195972f6Sopenharmony_ci return; 536195972f6Sopenharmony_ci } 537195972f6Sopenharmony_ci } 538195972f6Sopenharmony_ci 539195972f6Sopenharmony_ci f->seen_ack = 1; 540195972f6Sopenharmony_ci 541195972f6Sopenharmony_ci switch (f->state) { 542195972f6Sopenharmony_ci case PPP_FSM_CLOSED: 543195972f6Sopenharmony_ci case PPP_FSM_STOPPED: 544195972f6Sopenharmony_ci fsm_sdata(f, TERMACK, id, NULL, 0); 545195972f6Sopenharmony_ci break; 546195972f6Sopenharmony_ci 547195972f6Sopenharmony_ci case PPP_FSM_REQSENT: 548195972f6Sopenharmony_ci case PPP_FSM_ACKSENT: 549195972f6Sopenharmony_ci /* They didn't agree to what we wanted - try another request */ 550195972f6Sopenharmony_ci UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 551195972f6Sopenharmony_ci if (ret < 0) 552195972f6Sopenharmony_ci f->state = PPP_FSM_STOPPED; /* kludge for stopping CCP */ 553195972f6Sopenharmony_ci else 554195972f6Sopenharmony_ci fsm_sconfreq(f, 0); /* Send Configure-Request */ 555195972f6Sopenharmony_ci break; 556195972f6Sopenharmony_ci 557195972f6Sopenharmony_ci case PPP_FSM_ACKRCVD: 558195972f6Sopenharmony_ci /* Got a Nak/reject when we had already had an Ack?? oh well... */ 559195972f6Sopenharmony_ci UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 560195972f6Sopenharmony_ci fsm_sconfreq(f, 0); 561195972f6Sopenharmony_ci f->state = PPP_FSM_REQSENT; 562195972f6Sopenharmony_ci break; 563195972f6Sopenharmony_ci 564195972f6Sopenharmony_ci case PPP_FSM_OPENED: 565195972f6Sopenharmony_ci /* Go down and restart negotiation */ 566195972f6Sopenharmony_ci if (f->callbacks->down) 567195972f6Sopenharmony_ci (*f->callbacks->down)(f); /* Inform upper layers */ 568195972f6Sopenharmony_ci fsm_sconfreq(f, 0); /* Send initial Configure-Request */ 569195972f6Sopenharmony_ci f->state = PPP_FSM_REQSENT; 570195972f6Sopenharmony_ci break; 571195972f6Sopenharmony_ci default: 572195972f6Sopenharmony_ci break; 573195972f6Sopenharmony_ci } 574195972f6Sopenharmony_ci} 575195972f6Sopenharmony_ci 576195972f6Sopenharmony_ci 577195972f6Sopenharmony_ci/* 578195972f6Sopenharmony_ci * fsm_rtermreq - Receive Terminate-Req. 579195972f6Sopenharmony_ci */ 580195972f6Sopenharmony_cistatic void fsm_rtermreq(fsm *f, int id, u_char *p, int len) { 581195972f6Sopenharmony_ci ppp_pcb *pcb = f->pcb; 582195972f6Sopenharmony_ci 583195972f6Sopenharmony_ci switch (f->state) { 584195972f6Sopenharmony_ci case PPP_FSM_ACKRCVD: 585195972f6Sopenharmony_ci case PPP_FSM_ACKSENT: 586195972f6Sopenharmony_ci f->state = PPP_FSM_REQSENT; /* Start over but keep trying */ 587195972f6Sopenharmony_ci break; 588195972f6Sopenharmony_ci 589195972f6Sopenharmony_ci case PPP_FSM_OPENED: 590195972f6Sopenharmony_ci if (len > 0) { 591195972f6Sopenharmony_ci ppp_info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p); 592195972f6Sopenharmony_ci } else 593195972f6Sopenharmony_ci ppp_info("%s terminated by peer", PROTO_NAME(f)); 594195972f6Sopenharmony_ci f->retransmits = 0; 595195972f6Sopenharmony_ci f->state = PPP_FSM_STOPPING; 596195972f6Sopenharmony_ci if (f->callbacks->down) 597195972f6Sopenharmony_ci (*f->callbacks->down)(f); /* Inform upper layers */ 598195972f6Sopenharmony_ci TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); 599195972f6Sopenharmony_ci break; 600195972f6Sopenharmony_ci default: 601195972f6Sopenharmony_ci break; 602195972f6Sopenharmony_ci } 603195972f6Sopenharmony_ci 604195972f6Sopenharmony_ci fsm_sdata(f, TERMACK, id, NULL, 0); 605195972f6Sopenharmony_ci} 606195972f6Sopenharmony_ci 607195972f6Sopenharmony_ci 608195972f6Sopenharmony_ci/* 609195972f6Sopenharmony_ci * fsm_rtermack - Receive Terminate-Ack. 610195972f6Sopenharmony_ci */ 611195972f6Sopenharmony_cistatic void fsm_rtermack(fsm *f) { 612195972f6Sopenharmony_ci switch (f->state) { 613195972f6Sopenharmony_ci case PPP_FSM_CLOSING: 614195972f6Sopenharmony_ci UNTIMEOUT(fsm_timeout, f); 615195972f6Sopenharmony_ci f->state = PPP_FSM_CLOSED; 616195972f6Sopenharmony_ci if( f->callbacks->finished ) 617195972f6Sopenharmony_ci (*f->callbacks->finished)(f); 618195972f6Sopenharmony_ci break; 619195972f6Sopenharmony_ci case PPP_FSM_STOPPING: 620195972f6Sopenharmony_ci UNTIMEOUT(fsm_timeout, f); 621195972f6Sopenharmony_ci f->state = PPP_FSM_STOPPED; 622195972f6Sopenharmony_ci if( f->callbacks->finished ) 623195972f6Sopenharmony_ci (*f->callbacks->finished)(f); 624195972f6Sopenharmony_ci break; 625195972f6Sopenharmony_ci 626195972f6Sopenharmony_ci case PPP_FSM_ACKRCVD: 627195972f6Sopenharmony_ci f->state = PPP_FSM_REQSENT; 628195972f6Sopenharmony_ci break; 629195972f6Sopenharmony_ci 630195972f6Sopenharmony_ci case PPP_FSM_OPENED: 631195972f6Sopenharmony_ci if (f->callbacks->down) 632195972f6Sopenharmony_ci (*f->callbacks->down)(f); /* Inform upper layers */ 633195972f6Sopenharmony_ci fsm_sconfreq(f, 0); 634195972f6Sopenharmony_ci f->state = PPP_FSM_REQSENT; 635195972f6Sopenharmony_ci break; 636195972f6Sopenharmony_ci default: 637195972f6Sopenharmony_ci break; 638195972f6Sopenharmony_ci } 639195972f6Sopenharmony_ci} 640195972f6Sopenharmony_ci 641195972f6Sopenharmony_ci 642195972f6Sopenharmony_ci/* 643195972f6Sopenharmony_ci * fsm_rcoderej - Receive an Code-Reject. 644195972f6Sopenharmony_ci */ 645195972f6Sopenharmony_cistatic void fsm_rcoderej(fsm *f, u_char *inp, int len) { 646195972f6Sopenharmony_ci u_char code, id; 647195972f6Sopenharmony_ci 648195972f6Sopenharmony_ci if (len < HEADERLEN) { 649195972f6Sopenharmony_ci FSMDEBUG(("fsm_rcoderej: Rcvd short Code-Reject packet!")); 650195972f6Sopenharmony_ci return; 651195972f6Sopenharmony_ci } 652195972f6Sopenharmony_ci GETCHAR(code, inp); 653195972f6Sopenharmony_ci GETCHAR(id, inp); 654195972f6Sopenharmony_ci ppp_warn("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id); 655195972f6Sopenharmony_ci 656195972f6Sopenharmony_ci if( f->state == PPP_FSM_ACKRCVD ) 657195972f6Sopenharmony_ci f->state = PPP_FSM_REQSENT; 658195972f6Sopenharmony_ci} 659195972f6Sopenharmony_ci 660195972f6Sopenharmony_ci 661195972f6Sopenharmony_ci/* 662195972f6Sopenharmony_ci * fsm_protreject - Peer doesn't speak this protocol. 663195972f6Sopenharmony_ci * 664195972f6Sopenharmony_ci * Treat this as a catastrophic error (RXJ-). 665195972f6Sopenharmony_ci */ 666195972f6Sopenharmony_civoid fsm_protreject(fsm *f) { 667195972f6Sopenharmony_ci switch( f->state ){ 668195972f6Sopenharmony_ci case PPP_FSM_CLOSING: 669195972f6Sopenharmony_ci UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 670195972f6Sopenharmony_ci /* fall through */ 671195972f6Sopenharmony_ci /* no break */ 672195972f6Sopenharmony_ci case PPP_FSM_CLOSED: 673195972f6Sopenharmony_ci f->state = PPP_FSM_CLOSED; 674195972f6Sopenharmony_ci if( f->callbacks->finished ) 675195972f6Sopenharmony_ci (*f->callbacks->finished)(f); 676195972f6Sopenharmony_ci break; 677195972f6Sopenharmony_ci 678195972f6Sopenharmony_ci case PPP_FSM_STOPPING: 679195972f6Sopenharmony_ci case PPP_FSM_REQSENT: 680195972f6Sopenharmony_ci case PPP_FSM_ACKRCVD: 681195972f6Sopenharmony_ci case PPP_FSM_ACKSENT: 682195972f6Sopenharmony_ci UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 683195972f6Sopenharmony_ci /* fall through */ 684195972f6Sopenharmony_ci /* no break */ 685195972f6Sopenharmony_ci case PPP_FSM_STOPPED: 686195972f6Sopenharmony_ci f->state = PPP_FSM_STOPPED; 687195972f6Sopenharmony_ci if( f->callbacks->finished ) 688195972f6Sopenharmony_ci (*f->callbacks->finished)(f); 689195972f6Sopenharmony_ci break; 690195972f6Sopenharmony_ci 691195972f6Sopenharmony_ci case PPP_FSM_OPENED: 692195972f6Sopenharmony_ci terminate_layer(f, PPP_FSM_STOPPING); 693195972f6Sopenharmony_ci break; 694195972f6Sopenharmony_ci 695195972f6Sopenharmony_ci default: 696195972f6Sopenharmony_ci FSMDEBUG(("%s: Protocol-reject event in state %d!", 697195972f6Sopenharmony_ci PROTO_NAME(f), f->state)); 698195972f6Sopenharmony_ci /* no break */ 699195972f6Sopenharmony_ci } 700195972f6Sopenharmony_ci} 701195972f6Sopenharmony_ci 702195972f6Sopenharmony_ci 703195972f6Sopenharmony_ci/* 704195972f6Sopenharmony_ci * fsm_sconfreq - Send a Configure-Request. 705195972f6Sopenharmony_ci */ 706195972f6Sopenharmony_cistatic void fsm_sconfreq(fsm *f, int retransmit) { 707195972f6Sopenharmony_ci ppp_pcb *pcb = f->pcb; 708195972f6Sopenharmony_ci struct pbuf *p; 709195972f6Sopenharmony_ci u_char *outp; 710195972f6Sopenharmony_ci int cilen; 711195972f6Sopenharmony_ci 712195972f6Sopenharmony_ci if( f->state != PPP_FSM_REQSENT && f->state != PPP_FSM_ACKRCVD && f->state != PPP_FSM_ACKSENT ){ 713195972f6Sopenharmony_ci /* Not currently negotiating - reset options */ 714195972f6Sopenharmony_ci if( f->callbacks->resetci ) 715195972f6Sopenharmony_ci (*f->callbacks->resetci)(f); 716195972f6Sopenharmony_ci f->nakloops = 0; 717195972f6Sopenharmony_ci f->rnakloops = 0; 718195972f6Sopenharmony_ci } 719195972f6Sopenharmony_ci 720195972f6Sopenharmony_ci if( !retransmit ){ 721195972f6Sopenharmony_ci /* New request - reset retransmission counter, use new ID */ 722195972f6Sopenharmony_ci f->retransmits = pcb->settings.fsm_max_conf_req_transmits; 723195972f6Sopenharmony_ci f->reqid = ++f->id; 724195972f6Sopenharmony_ci } 725195972f6Sopenharmony_ci 726195972f6Sopenharmony_ci f->seen_ack = 0; 727195972f6Sopenharmony_ci 728195972f6Sopenharmony_ci /* 729195972f6Sopenharmony_ci * Make up the request packet 730195972f6Sopenharmony_ci */ 731195972f6Sopenharmony_ci if( f->callbacks->cilen && f->callbacks->addci ){ 732195972f6Sopenharmony_ci cilen = (*f->callbacks->cilen)(f); 733195972f6Sopenharmony_ci if( cilen > pcb->peer_mru - HEADERLEN ) 734195972f6Sopenharmony_ci cilen = pcb->peer_mru - HEADERLEN; 735195972f6Sopenharmony_ci } else 736195972f6Sopenharmony_ci cilen = 0; 737195972f6Sopenharmony_ci 738195972f6Sopenharmony_ci p = pbuf_alloc(PBUF_RAW, (u16_t)(cilen + HEADERLEN + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE); 739195972f6Sopenharmony_ci if(NULL == p) 740195972f6Sopenharmony_ci return; 741195972f6Sopenharmony_ci if(p->tot_len != p->len) { 742195972f6Sopenharmony_ci pbuf_free(p); 743195972f6Sopenharmony_ci return; 744195972f6Sopenharmony_ci } 745195972f6Sopenharmony_ci 746195972f6Sopenharmony_ci /* send the request to our peer */ 747195972f6Sopenharmony_ci outp = (u_char*)p->payload; 748195972f6Sopenharmony_ci MAKEHEADER(outp, f->protocol); 749195972f6Sopenharmony_ci PUTCHAR(CONFREQ, outp); 750195972f6Sopenharmony_ci PUTCHAR(f->reqid, outp); 751195972f6Sopenharmony_ci PUTSHORT(cilen + HEADERLEN, outp); 752195972f6Sopenharmony_ci if (cilen != 0) { 753195972f6Sopenharmony_ci (*f->callbacks->addci)(f, outp, &cilen); 754195972f6Sopenharmony_ci LWIP_ASSERT("cilen == p->len - HEADERLEN - PPP_HDRLEN", cilen == p->len - HEADERLEN - PPP_HDRLEN); 755195972f6Sopenharmony_ci } 756195972f6Sopenharmony_ci 757195972f6Sopenharmony_ci ppp_write(pcb, p); 758195972f6Sopenharmony_ci 759195972f6Sopenharmony_ci /* start the retransmit timer */ 760195972f6Sopenharmony_ci --f->retransmits; 761195972f6Sopenharmony_ci TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); 762195972f6Sopenharmony_ci} 763195972f6Sopenharmony_ci 764195972f6Sopenharmony_ci 765195972f6Sopenharmony_ci/* 766195972f6Sopenharmony_ci * fsm_sdata - Send some data. 767195972f6Sopenharmony_ci * 768195972f6Sopenharmony_ci * Used for all packets sent to our peer by this module. 769195972f6Sopenharmony_ci */ 770195972f6Sopenharmony_civoid fsm_sdata(fsm *f, u_char code, u_char id, const u_char *data, int datalen) { 771195972f6Sopenharmony_ci ppp_pcb *pcb = f->pcb; 772195972f6Sopenharmony_ci struct pbuf *p; 773195972f6Sopenharmony_ci u_char *outp; 774195972f6Sopenharmony_ci int outlen; 775195972f6Sopenharmony_ci 776195972f6Sopenharmony_ci /* Adjust length to be smaller than MTU */ 777195972f6Sopenharmony_ci if (datalen > pcb->peer_mru - HEADERLEN) 778195972f6Sopenharmony_ci datalen = pcb->peer_mru - HEADERLEN; 779195972f6Sopenharmony_ci outlen = datalen + HEADERLEN; 780195972f6Sopenharmony_ci 781195972f6Sopenharmony_ci p = pbuf_alloc(PBUF_RAW, (u16_t)(outlen + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE); 782195972f6Sopenharmony_ci if(NULL == p) 783195972f6Sopenharmony_ci return; 784195972f6Sopenharmony_ci if(p->tot_len != p->len) { 785195972f6Sopenharmony_ci pbuf_free(p); 786195972f6Sopenharmony_ci return; 787195972f6Sopenharmony_ci } 788195972f6Sopenharmony_ci 789195972f6Sopenharmony_ci outp = (u_char*)p->payload; 790195972f6Sopenharmony_ci if (datalen) /* && data != outp + PPP_HDRLEN + HEADERLEN) -- was only for fsm_sconfreq() */ 791195972f6Sopenharmony_ci MEMCPY(outp + PPP_HDRLEN + HEADERLEN, data, datalen); 792195972f6Sopenharmony_ci MAKEHEADER(outp, f->protocol); 793195972f6Sopenharmony_ci PUTCHAR(code, outp); 794195972f6Sopenharmony_ci PUTCHAR(id, outp); 795195972f6Sopenharmony_ci PUTSHORT(outlen, outp); 796195972f6Sopenharmony_ci ppp_write(pcb, p); 797195972f6Sopenharmony_ci} 798195972f6Sopenharmony_ci 799195972f6Sopenharmony_ci#endif /* PPP_SUPPORT */ 800