Annotation of embedaddon/libpdel/ppp/ppp_fsm.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (c) 2001-2002 Packet Design, LLC.
                      4:  * All rights reserved.
                      5:  * 
                      6:  * Subject to the following obligations and disclaimer of warranty,
                      7:  * use and redistribution of this software, in source or object code
                      8:  * forms, with or without modifications are expressly permitted by
                      9:  * Packet Design; provided, however, that:
                     10:  * 
                     11:  *    (i)  Any and all reproductions of the source or object code
                     12:  *         must include the copyright notice above and the following
                     13:  *         disclaimer of warranties; and
                     14:  *    (ii) No rights are granted, in any manner or form, to use
                     15:  *         Packet Design trademarks, including the mark "PACKET DESIGN"
                     16:  *         on advertising, endorsements, or otherwise except as such
                     17:  *         appears in the above copyright notice or in the software.
                     18:  * 
                     19:  * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
                     20:  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
                     21:  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
                     22:  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
                     23:  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
                     24:  * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
                     25:  * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
                     26:  * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
                     27:  * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
                     28:  * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
                     29:  * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
                     30:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
                     31:  * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
                     32:  * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
                     33:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     34:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
                     35:  * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
                     36:  * THE POSSIBILITY OF SUCH DAMAGE.
                     37:  *
                     38:  * Author: Archie Cobbs <archie@freebsd.org>
                     39:  */
                     40: 
                     41: #include "ppp/ppp_defs.h"
                     42: #include "ppp/ppp_log.h"
                     43: #include "ppp/ppp_util.h"
                     44: #include "ppp/ppp_fsm_option.h"
                     45: #include "ppp/ppp_fsm.h"
                     46: 
                     47: /* FSM defaults */
                     48: #define FSM_MAX_CONFIGURE      10
                     49: #define FSM_MAX_TERMINATE      3
                     50: #define FSM_MAX_FAILURE                8
                     51: #define FSM_TIMEOUT            2
                     52: 
                     53: /* Memory type */
                     54: #define FSM_MTYPE              "ppp_fsm"
                     55: 
                     56: /* Max amount of packet data to copy & send back */
                     57: #define MAX_PKTCOPY            200
                     58: 
                     59: /* FSM events */
                     60: enum fsm_event {
                     61:        UP              =0,
                     62:        DOWN            =1,
                     63:        OPEN            =2,
                     64:        CLOSE           =3,
                     65:        TO_P            =4,
                     66:        TO_M            =5,
                     67:        RCR_P           =6,
                     68:        RCR_M           =7,
                     69:        RCA             =8,
                     70:        RCN             =9,
                     71:        RTR             =10,
                     72:        RTA             =11,
                     73:        RXJ_P           =12,
                     74:        RXJ_M           =13
                     75: };
                     76: #define FSM_EVENT_MAX  14
                     77: 
                     78: /* Actions to take on events */
                     79: #define TLU            0x0010          /* this layer up */
                     80: #define TLD            0x0020          /* this layer down */
                     81: #define TLS            0x0040          /* this layer started */
                     82: #define TLF            0x0080          /* this layer finished */
                     83: #define IRC            0x0100          /* init restart counter */
                     84: #define ZRC            0x0200          /* zero restart counter */
                     85: #define SCR            0x0400          /* send config request */
                     86: #define SCA            0x0800          /* send config ack */
                     87: #define SCN            0x1000          /* send config nak/rej */
                     88: #define STR            0x2000          /* send terminate request */
                     89: #define STA            0x4000          /* send terminate ack */
                     90: 
                     91: #define STMASK         0x000f          /* next state mask */
                     92: #define NA             0xffff          /* impossible event */
                     93: 
                     94: /* Configurations we keep */
                     95: #define FSM_CONF_SELF          0       /* my requested config */
                     96: #define FSM_CONF_PEER          1       /* peer requested config */
                     97: #define FSM_CONF_NAK           2       /* nak'd peer config */
                     98: #define FSM_CONF_REJ           3       /* rejected peer config */
                     99: #define FSM_CONF_MAX           4
                    100: 
                    101: /* Information describing an instance of an FSM */
                    102: struct ppp_fsm {
                    103:        struct ppp_fsm_instance *inst;          /* fsm instance object */
                    104:        enum ppp_fsm_state      state;          /* fsm state */
                    105:        struct ppp_log          *log;           /* log object */
                    106:        struct ppp_fsm_options  *config[FSM_CONF_MAX];  /* config options */
                    107:        u_char                  ids[FSM_CODE_MAX];      /* packet ids */
                    108:        u_char                  rejcode[FSM_CODE_MAX];  /* rejected codes */
                    109:        short                   restart;        /* restart counter */
                    110:        short                   failure[2];     /* failure counter */
                    111:        time_t                  last_heard;     /* time last heard from */
                    112:        struct ppp_fsm_output   dead;           /* if dead and reason why */
                    113:        struct pevent_ctx       *ev_ctx;        /* event context */
                    114:        pthread_mutex_t         *mutex;         /* mutex */
                    115:        struct pevent           *timer;         /* restart timer */
                    116:        struct mesg_port        *outport;       /* where output goes */
                    117: };
                    118: 
                    119: #define FSM_TIMER_STATE(state)                                         \
                    120:        ((state) >= FSM_STATE_CLOSING && (state) != FSM_STATE_OPENED)
                    121: 
                    122: #define FSM_DEAD(fsm)                                                  \
                    123:        (((fsm)->state == FSM_STATE_INITIAL                             \
                    124:              || (fsm)->state == FSM_STATE_CLOSED)                      \
                    125:            && (fsm)->dead.u.down.reason != 0)
                    126: 
                    127: /* Macro for logging */
                    128: #define LOG(sev, fmt, args...) PPP_LOG(fsm->log, sev, fmt , ## args)
                    129: 
                    130: /*
                    131:  * RFC 1661 PPP state transition table
                    132:  *
                    133:  * Differences from RFC 1661:
                    134:  *     TLS added in [OPEN, CLOSED]
                    135:  *     TLF added in [DOWN, CLOSING]
                    136:  *     TLS added in [RCR+, STOPPED]
                    137:  *     TLS added in [RCR-, STOPPED]
                    138:  *     RUC and RXR events removed (handled directly)
                    139:  *
                    140:  * The extra TLS/TLF actions are to keep intention of lower layer in sync
                    141:  * with the intention of this layer (i.e., if TLS -> lower layer OPEN and
                    142:  * TLF -> lower layer CLOSE).
                    143:  */
                    144: static const u_int16_t fsm_actions[FSM_EVENT_MAX][FSM_STATE_MAX] = {
                    145: 
                    146: /*INITL        STARTNG CLOSED  STOPPED CLOSING STOPPNG REQ-SNT ACK-RCD ACK-SNT OPENED*/
                    147: 
                    148: /* Up */
                    149: { 2,   IRC|SCR|6,
                    150:                NA,     NA,     NA,     NA,     NA,     NA,     NA,     NA },
                    151: /* Down */
                    152: { NA,  NA,     0,      TLS|1,  TLF|0,  1,      1,      1,      1,      TLD|1 },
                    153: /* Open */
                    154: { TLS|1,1,     TLS|IRC|SCR|6,
                    155:                        3,      5,      5,      6,      7,      8,      9 },
                    156: /* Close */
                    157: { 0,   TLF|0,  2,      2,      4,      4,      IRC|STR|4,
                    158:                                                        IRC|STR|4,
                    159:                                                                IRC|STR|4,
                    160:                                                                 TLD|IRC|STR|4},
                    161: /* TO+ */
                    162: { NA,  NA,     NA,     NA,     STR|4,  STR|5,  SCR|6,  SCR|6,  SCR|8,  NA },
                    163: /* TO- */
                    164: { NA,  NA,     NA,     NA,     TLF|2,  TLF|3,  TLF|3,  TLF|3,  TLF|3,  NA },
                    165: /* RCR+ */
                    166: { NA,  NA,     STA|2,  TLS|IRC|SCR|SCA|8,
                    167:                                4,      5,      SCA|8,  SCA|TLU|9,
                    168:                                                                SCA|8,
                    169:                                                                 TLD|SCR|SCA|8},
                    170: /* RCR- */
                    171: { NA,  NA,     STA|2,  TLS|IRC|SCR|SCN|6,
                    172:                                4,      5,      SCN|6,  SCN|7,  SCN|6,
                    173:                                                                 TLD|SCR|SCN|6},
                    174: /* RCA */
                    175: { NA,  NA,     STA|2,  STA|3,  4,      5,      IRC|7,
                    176:                                                        SCR|6,  IRC|TLU|9,
                    177:                                                                  TLD|SCR|6 },
                    178: /* RCN */
                    179: { NA,  NA,     STA|2,  STA|3,  4,      5,      IRC|SCR|6,
                    180:                                                        SCR|6,  IRC|SCR|8,
                    181:                                                                  TLD|SCR|6 },
                    182: /* RTR */
                    183: { NA,  NA,     STA|2,  STA|3,  STA|4,  STA|5,  STA|6,  STA|6,  STA|6,
                    184:                                                                 TLD|ZRC|STA|5},
                    185: /* RTA */
                    186: { NA,  NA,     2,      3,      TLF|2,  TLF|3,  6,      6,      8,
                    187:                                                                  TLD|SCR|6 },
                    188: /* RXJ+ */
                    189: { NA,  NA,     2,      3,      4,      5,      6,      6,      8,      9 },
                    190: /* RXJ- */
                    191: { NA,  NA,     TLF|2,  TLF|3,  TLF|2,  TLF|3,  TLF|3,  TLF|3,  TLF|3,
                    192:                                                                 TLD|IRC|STR|5},
                    193: };
                    194: 
                    195: /* Minimum packet data lengths */
                    196: static const   u_char fsm_minlen[FSM_CODE_MAX] = {
                    197:        0,      /* FSM_CODE_VENDOR */
                    198:        0,      /* FSM_CODE_CONFIGREQ */
                    199:        0,      /* FSM_CODE_CONFIGACK */
                    200:        0,      /* FSM_CODE_CONFIGNAK */
                    201:        0,      /* FSM_CODE_CONFIGREJ */
                    202:        0,      /* FSM_CODE_TERMREQ */
                    203:        0,      /* FSM_CODE_TERMACK */
                    204:        1,      /* FSM_CODE_CODEREJ */
                    205:        2,      /* FSM_CODE_PROTOREJ */
                    206:        4,      /* FSM_CODE_ECHOREQ */
                    207:        4,      /* FSM_CODE_ECHOREP */
                    208:        4,      /* FSM_CODE_DISCREQ */
                    209:        4,      /* FSM_CODE_IDENT */
                    210:        8,      /* FSM_CODE_TIMEREM */
                    211:        0,      /* FSM_CODE_RESETREQ */
                    212:        0,      /* FSM_CODE_RESETACK */
                    213: };
                    214: 
                    215: /*
                    216:  * Internal functions
                    217:  */
                    218: static void    ppp_fsm_input_packet(struct ppp_fsm *fsm,
                    219:                        const u_char *data, u_int dlen);
                    220: static void    ppp_fsm_event(struct ppp_fsm *fsm, int event);
                    221: static void    ppp_fsm_send_config(struct ppp_fsm *fsm,
                    222:                        enum ppp_fsm_code code);
                    223: static void    ppp_fsm_send_packet(struct ppp_fsm *fsm, u_char code,
                    224:                        const void *data, u_int len);
                    225: static void    ppp_fsm_record(struct ppp_fsm *fsm,
                    226:                        /* enum ppp_fsm_reason reason, */ ...);
                    227: static int     ppp_fsm_output(struct ppp_fsm *fsm,
                    228:                        enum ppp_fsmoutput type, ...);
                    229: static void    ppp_fsm_output_build(struct ppp_fsm_output *output,
                    230:                        enum ppp_fsmoutput type, va_list args);
                    231: static void    ppp_fsm_output_dead(struct ppp_fsm *fsm);
                    232: static void    ppp_fsm_syserr(struct ppp_fsm *fsm, const char *func);
                    233: 
                    234: static void    ppp_fsm_log_pkt(struct ppp_fsm *fsm, int sev,
                    235:                        const char *prefix, const u_char *pkt);
                    236: 
                    237: static pevent_handler_t        ppp_fsm_timeout;
                    238: 
                    239: static const   char *st2str(u_int state);
                    240: static const   char *ev2str(u_int event);
                    241: static const   char *cd2str(u_int code);
                    242: 
                    243: /***********************************************************************
                    244:                        PUBLIC API FUNCTIONS
                    245: ***********************************************************************/
                    246: 
                    247: /*
                    248:  * Create a new FSM.
                    249:  *
                    250:  * "inst" is freed when the FSM is destroyed.
                    251:  */
                    252: struct ppp_fsm *
                    253: ppp_fsm_create(struct pevent_ctx *ev_ctx, pthread_mutex_t *mutex,
                    254:        struct ppp_fsm_instance *inst, struct ppp_log *log)
                    255: {
                    256:        struct ppp_fsm *fsm;
                    257:        int i;
                    258: 
                    259:        /* Get new FSM object */
                    260:        if ((fsm = MALLOC(FSM_MTYPE, sizeof(*fsm))) == NULL)
                    261:                return (NULL);
                    262:        memset(fsm, 0, sizeof(*fsm));
                    263:        fsm->ev_ctx = ev_ctx;
                    264:        fsm->mutex = mutex;
                    265:        fsm->inst = inst;
                    266:        fsm->state = FSM_STATE_INITIAL;
                    267: 
                    268:        /* Prefix log with FSM name */
                    269:        if ((fsm->log = ppp_log_prefix(log,
                    270:            "%s: ", inst->type->name)) == NULL) {
                    271:                FREE(FSM_MTYPE, fsm);
                    272:                return (NULL);
                    273:        }
                    274: 
                    275:        /* Get message port */
                    276:        if ((fsm->outport = mesg_port_create(inst->type->name)) == NULL) {
                    277:                FREE(FSM_MTYPE, fsm);
                    278:                return (NULL);
                    279:        }
                    280: 
                    281:        /* For 'shell' FSM's like MP LCP, no config required */
                    282:        if ((inst->type->sup_codes & (1 << FSM_CODE_CONFIGREQ)) == 0) {
                    283:                fsm->state = FSM_STATE_OPENED;
                    284:                return (fsm);
                    285:        }
                    286: 
                    287:        /* Initialize configuration options */
                    288:        for (i = 0; i < FSM_CONF_MAX; i++) {
                    289:                if ((fsm->config[i] = ppp_fsm_option_create()) == NULL) {
                    290:                        while (i-- > 0)
                    291:                                ppp_fsm_option_destroy(&fsm->config[i]);
                    292:                        mesg_port_destroy(&fsm->outport);
                    293:                        FREE(FSM_MTYPE, fsm);
                    294:                        return (NULL);
                    295:                }
                    296:        }
                    297: 
                    298:        /* Done */
                    299:        inst->fsm = fsm;
                    300:        return (fsm);
                    301: }
                    302: 
                    303: /*
                    304:  * Destroy an FSM
                    305:  */
                    306: void
                    307: ppp_fsm_destroy(struct ppp_fsm **fsmp)
                    308: {
                    309:        struct ppp_fsm *const fsm = *fsmp;
                    310:        struct ppp_fsm_output *output;
                    311:        int i;
                    312: 
                    313:        if (fsm == NULL)
                    314:                return;
                    315:        *fsmp = NULL;
                    316:        pevent_unregister(&fsm->timer);
                    317:        for (i = 0; i < FSM_CONF_MAX; i++)
                    318:                ppp_fsm_option_destroy(&fsm->config[i]);
                    319:        while ((output = mesg_port_get(fsm->outport, 0)) != NULL)
                    320:                ppp_fsm_free_output(output);
                    321:        mesg_port_destroy(&fsm->outport);
                    322:        (*fsm->inst->type->destroy)(fsm->inst);
                    323:        ppp_log_close(&fsm->log);
                    324:        FREE(FSM_MTYPE, fsm);
                    325: }
                    326: 
                    327: /*
                    328:  * Get output port.
                    329:  */
                    330: struct mesg_port *
                    331: ppp_fsm_get_outport(struct ppp_fsm *fsm)
                    332: {
                    333:        return (fsm->outport);
                    334: }
                    335: 
                    336: /*
                    337:  * Free an FSM output structure.
                    338:  */
                    339: void
                    340: ppp_fsm_free_output(struct ppp_fsm_output *output)
                    341: {
                    342:        switch (output->type) {
                    343:        case FSM_OUTPUT_DATA:
                    344:                FREE(FSM_MTYPE, output->u.data.data);
                    345:                break;
                    346:        default:
                    347:                break;
                    348:        }
                    349:        FREE(FSM_MTYPE, output);
                    350: }
                    351: 
                    352: /*
                    353:  * Input something to the FSM.
                    354:  */
                    355: void
                    356: ppp_fsm_input(struct ppp_fsm *fsm, enum ppp_fsm_input input, ...)
                    357: {
                    358:        const u_char *data;
                    359:        va_list args;
                    360:        u_int dlen;
                    361: 
                    362:        /* If we're dead, ignore it */
                    363:        if (FSM_DEAD(fsm))
                    364:                return;
                    365: 
                    366:        /* Handle input */
                    367:        va_start(args, input);
                    368:        switch (input) {
                    369:        case FSM_INPUT_OPEN:
                    370:                ppp_fsm_event(fsm, OPEN);
                    371:                break;
                    372:        case FSM_INPUT_CLOSE:
                    373:                ppp_fsm_record(fsm, FSM_REASON_CLOSE);
                    374:                ppp_fsm_event(fsm, CLOSE);
                    375:                break;
                    376:        case FSM_INPUT_UP:
                    377:                ppp_fsm_event(fsm, UP);
                    378:                break;
                    379:        case FSM_INPUT_DOWN_FATAL:
                    380:                ppp_fsm_record(fsm, FSM_REASON_DOWN_FATAL);
                    381:                ppp_fsm_event(fsm, DOWN);
                    382:                ppp_fsm_event(fsm, CLOSE);
                    383:                break;
                    384:        case FSM_INPUT_DOWN_NONFATAL:
                    385:                ppp_fsm_record(fsm, FSM_REASON_DOWN_NONFATAL);
                    386:                ppp_fsm_event(fsm, DOWN);
                    387:                break;
                    388:        case FSM_INPUT_RECD_PROTOREJ:
                    389:            {
                    390:                u_int16_t proto;
                    391: 
                    392:                proto = va_arg(args, int);
                    393:                ppp_fsm_record(fsm, FSM_REASON_PROTOREJ, proto);
                    394:                ppp_fsm_event(fsm, RXJ_M);
                    395:                break;
                    396:            }
                    397:        case FSM_INPUT_DATA:
                    398:                data = va_arg(args, const u_char *);
                    399:                dlen = va_arg(args, u_int);
                    400:                ppp_fsm_input_packet(fsm, data, dlen);
                    401:                break;
                    402:        case FSM_INPUT_XMIT_PROTOREJ:
                    403:            {
                    404:                u_int16_t proto;
                    405:                u_int16_t *prj;
                    406:                u_int prlen;
                    407: 
                    408:                proto = va_arg(args, int);
                    409:                data = va_arg(args, const u_char *);
                    410:                dlen = va_arg(args, u_int);
                    411:                prlen = 2 + MIN(dlen, MAX_PKTCOPY);
                    412:                if ((prj = MALLOC(TYPED_MEM_TEMP, prlen)) == NULL)
                    413:                        break;
                    414:                *prj = htons(proto);
                    415:                memcpy((char *)prj + 2, data, MIN(dlen, MAX_PKTCOPY));
                    416:                ppp_fsm_send_packet(fsm, FSM_CODE_PROTOREJ, prj, prlen);
                    417:                FREE(TYPED_MEM_TEMP, prj);
                    418:                break;
                    419:            }
                    420:        default:
                    421:                LOG(LOG_ERR, "invalid input %d", input);
                    422:                break;
                    423:        }
                    424:        va_end(args);
                    425: }
                    426: 
                    427: /*
                    428:  * Get FSM state.
                    429:  */
                    430: enum ppp_fsm_state
                    431: ppp_fsm_get_state(struct ppp_fsm *fsm)
                    432: {
                    433:        return (fsm->state);
                    434: }
                    435: 
                    436: /*
                    437:  * Get time we last heard from the peer.
                    438:  */
                    439: time_t
                    440: ppp_fsm_last_heard(struct ppp_fsm *fsm)
                    441: {
                    442:        return (fsm->last_heard);
                    443: }
                    444: 
                    445: /*
                    446:  * Get underlying FSM instance.
                    447:  */
                    448: struct ppp_fsm_instance *
                    449: ppp_fsm_get_instance(struct ppp_fsm *fsm)
                    450: {
                    451:        return (fsm->inst);
                    452: }
                    453: 
                    454: /*
                    455:  * Send a reset-request.
                    456:  */
                    457: void
                    458: ppp_fsm_send_reset_req(struct ppp_fsm *fsm, const void *data, size_t dlen)
                    459: {
                    460:        fsm->ids[FSM_CODE_RESETREQ]++;
                    461:        ppp_fsm_send_packet(fsm, FSM_CODE_RESETREQ, data, dlen);
                    462: }
                    463: 
                    464: /*
                    465:  * Send a reset-ack.
                    466:  */
                    467: void
                    468: ppp_fsm_send_reset_ack(struct ppp_fsm *fsm, const void *data, size_t dlen)
                    469: {
                    470:        ppp_fsm_send_packet(fsm, FSM_CODE_RESETACK, data, dlen);
                    471: }
                    472: 
                    473: /***********************************************************************
                    474:                        INTERNAL FUNCTIONS
                    475: ***********************************************************************/
                    476: 
                    477: /*
                    478:  * Handle an incoming packet
                    479:  */
                    480: static void
                    481: ppp_fsm_input_packet(struct ppp_fsm *fsm, const u_char *pkt, u_int dlen)
                    482: {
                    483:        const u_char *const payload = pkt + sizeof(struct ppp_fsm_pkt);
                    484:        const struct ppp_fsm_type *const ftyp = fsm->inst->type;
                    485:        struct ppp_fsm_options *opts = NULL;
                    486:        struct ppp_fsm_pkt hdr;
                    487:        u_int len;
                    488: 
                    489:        /* Drop packet if it's unexpected */
                    490:        if (fsm->state == FSM_STATE_INITIAL
                    491:            || fsm->state == FSM_STATE_STARTING)
                    492:                goto done;
                    493: 
                    494:        /* Check packet length */
                    495:        if (dlen < sizeof(hdr)) {
                    496:                LOG(LOG_NOTICE, "rec'd %s packet (%u bytes)", "runt", dlen);
                    497:                goto done;
                    498:        }
                    499: 
                    500:        /* Copy packet header into aligned memory */
                    501:        memcpy(&hdr, pkt, sizeof(hdr));
                    502: 
                    503:        /* Check packet length again */
                    504:        if ((len = ntohs(hdr.length)) < sizeof(hdr)) {
                    505:                LOG(LOG_NOTICE, "rec'd %s packet (%u bytes)", "runt", dlen);
                    506:                goto done;
                    507:        }
                    508:        if (len > dlen) {
                    509:                LOG(LOG_NOTICE, "rec'd %s packet (%u bytes)",
                    510:                    "truncated", dlen);
                    511:                goto done;
                    512:        }
                    513:        len -= sizeof(hdr);             /* get length of just the data part */
                    514: 
                    515:        /* Check code; send code-reject if not supported */
                    516:        if (hdr.code >= FSM_CODE_MAX
                    517:            || (ftyp->sup_codes & (1 << hdr.code)) == 0) {
                    518: code_reject:   LOG(LOG_DEBUG, "rejecting unsupported code %u", hdr.code);
                    519:                ppp_fsm_send_packet(fsm, FSM_CODE_CODEREJ,
                    520:                    pkt, MIN(dlen, MAX_PKTCOPY));
                    521:                goto done;
                    522:        }
                    523: 
                    524:        /* Check data length */
                    525:        if (len < fsm_minlen[hdr.code]) {
                    526:                LOG(LOG_DEBUG + 1, "ignoring truncated packet");
                    527:                goto done;
                    528:        }
                    529: 
                    530:        /* Reset peer's idle time */
                    531:        fsm->last_heard = time(NULL);
                    532: 
                    533:        /* Initialize failure counters if appropriate */
                    534:        if (fsm->state < FSM_STATE_REQSENT) {
                    535:                fsm->failure[PPP_SELF] = FSM_MAX_FAILURE;
                    536:                fsm->failure[PPP_PEER] = FSM_MAX_FAILURE;
                    537:        }
                    538: 
                    539:        /* Logging */
                    540:        ppp_fsm_log_pkt(fsm, (hdr.code == FSM_CODE_ECHOREQ
                    541:            || hdr.code == FSM_CODE_ECHOREP) ? LOG_DEBUG : LOG_INFO,
                    542:            "recv", pkt);
                    543: 
                    544:        /* Extract encoded config options */
                    545:        switch (hdr.code) {
                    546:        case FSM_CODE_CONFIGREQ:
                    547:        case FSM_CODE_CONFIGACK:
                    548:        case FSM_CODE_CONFIGNAK:
                    549:        case FSM_CODE_CONFIGREJ:
                    550:                ppp_fsm_record(fsm, FSM_REASON_CONF, hdr.code);
                    551:                if ((opts = ppp_fsm_option_unpack(payload, len)) == NULL) {
                    552:                        ppp_fsm_syserr(fsm, "malloc");
                    553:                        goto close;
                    554:                }
                    555:                break;
                    556:        default:
                    557:                break;
                    558:        }
                    559: 
                    560:        /* Check magic number */
                    561:        switch (hdr.code) {
                    562:        case FSM_CODE_ECHOREQ:
                    563:        case FSM_CODE_ECHOREP:
                    564:        case FSM_CODE_IDENT:
                    565:        case FSM_CODE_DISCREQ:
                    566:        case FSM_CODE_TIMEREM:
                    567:            {
                    568:                u_int32_t pkt_magic;
                    569:                u_int32_t req_magic;
                    570: 
                    571:                /* Get what peer's magic number ought to be */
                    572:                if (ftyp->get_magic == NULL)
                    573:                        break;
                    574:                req_magic = (*ftyp->get_magic)(fsm->inst, PPP_PEER);
                    575: 
                    576:                /* Get actual magic number received */
                    577:                memcpy(&pkt_magic, payload, 4);
                    578:                pkt_magic = ntohl(pkt_magic);
                    579: 
                    580:                /*
                    581:                 * Only check if both magic numbers are non-zero and
                    582:                 * the FSM has reached the opened state.
                    583:                 */
                    584:                if (req_magic == 0
                    585:                    || pkt_magic == 0
                    586:                    || fsm->state != FSM_STATE_OPENED)
                    587:                        break;
                    588: 
                    589:                /* If wrong, bail out */
                    590:                if (pkt_magic != req_magic) {
                    591:                        LOG(LOG_NOTICE,
                    592:                            "rec'd %s with invalid magic# 0x%08x != 0x%08x",
                    593:                            cd2str(hdr.code), pkt_magic, req_magic);
                    594:                        ppp_fsm_record(fsm, FSM_REASON_BADMAGIC);
                    595:                        goto close;
                    596:                }
                    597:                break;
                    598:            }
                    599:        default:
                    600:                break;
                    601:        }
                    602: 
                    603:        /* Deal with packet */
                    604:        switch (hdr.code) {
                    605:        case FSM_CODE_VENDOR:
                    606:                if (ftyp->recv_vendor == NULL)
                    607:                        goto code_reject;
                    608:                (*ftyp->recv_vendor)(fsm->inst, payload, len);
                    609:                break;
                    610: 
                    611:        case FSM_CODE_CONFIGREQ:
                    612:            {
                    613:                int ack;
                    614:                int i;
                    615: 
                    616:                /* Update reply id's */
                    617:                fsm->ids[FSM_CODE_CONFIGACK] = hdr.id;
                    618:                fsm->ids[FSM_CODE_CONFIGNAK] = hdr.id;
                    619:                fsm->ids[FSM_CODE_CONFIGREJ] = hdr.id;
                    620: 
                    621:                /* Update peer's requested options with new info */
                    622:                ppp_fsm_option_destroy(&fsm->config[FSM_CONF_PEER]);
                    623:                fsm->config[FSM_CONF_PEER] = opts;
                    624:                opts = NULL;                            /* avoid double free */
                    625: 
                    626:                /* Reset nak and rej reply options */
                    627:                ppp_fsm_option_zero(fsm->config[FSM_CONF_NAK]);
                    628:                ppp_fsm_option_zero(fsm->config[FSM_CONF_REJ]);
                    629: 
                    630:                /* Examine peer's options for basic validity */
                    631:                for (i = 0; i < fsm->config[FSM_CONF_PEER]->num; i++) {
                    632:                        const struct ppp_fsm_option *const opt
                    633:                            = &fsm->config[FSM_CONF_PEER]->opts[i];
                    634:                        const struct ppp_fsm_optdesc *const desc
                    635:                            = ppp_fsm_option_desc(ftyp->options, opt);
                    636: 
                    637:                        /* If not supported or invalid, reject it */
                    638:                        if (desc == NULL
                    639:                            || !desc->supported
                    640:                            || opt->len < desc->min
                    641:                            || opt->len > desc->max) {
                    642: 
                    643:                                /* Add to reject list */
                    644:                                if (ppp_fsm_option_add(
                    645:                                    fsm->config[FSM_CONF_REJ],
                    646:                                    opt->type, opt->len, opt->data) == -1) {
                    647:                                        ppp_fsm_syserr(fsm, "malloc");
                    648:                                        goto close;
                    649:                                }
                    650: 
                    651:                                /* Remove from request list */
                    652:                                ppp_fsm_option_del(
                    653:                                    fsm->config[FSM_CONF_PEER], i--);
                    654:                        }
                    655:                }
                    656: 
                    657:                /* Call FSM type method to deal with remaining options */
                    658:                if ((*ftyp->recv_conf_req)(fsm->inst,
                    659:                    fsm->config[FSM_CONF_PEER],
                    660:                    fsm->config[FSM_CONF_NAK],
                    661:                    fsm->config[FSM_CONF_REJ]) == -1)
                    662:                        goto config_error;
                    663: 
                    664:                /* Check if not converging */
                    665:                if (fsm->config[FSM_CONF_NAK]->num > 0
                    666:                    && --fsm->failure[PPP_PEER] <= 0) {
                    667:                        LOG(LOG_NOTICE, "negotiation failed to converge:"
                    668:                            " configuration not accepted by %s", "me");
                    669:                        ppp_fsm_record(fsm, FSM_REASON_NEGOT);
                    670:                        goto close;
                    671:                }
                    672: 
                    673:                /* Evoke RCR+ or RCR- event */
                    674:                ack = (fsm->config[FSM_CONF_NAK]->num
                    675:                    + fsm->config[FSM_CONF_REJ]->num == 0);
                    676:                if (ack)
                    677:                        fsm->failure[PPP_PEER] = FSM_MAX_FAILURE;
                    678:                ppp_fsm_event(fsm, ack ? RCR_P : RCR_M);
                    679:                break;
                    680:            }
                    681: 
                    682:        case FSM_CODE_CONFIGACK:
                    683: 
                    684:                /* Validate id and contents */
                    685:                if (hdr.id != fsm->ids[FSM_CODE_CONFIGREQ]) {
                    686:                        LOG(LOG_DEBUG + 1, "ignoring id #%u", hdr.id);
                    687:                        goto done;
                    688:                }
                    689:                if (!ppp_fsm_option_equal(opts, -1,
                    690:                    fsm->config[FSM_CONF_SELF], -1)) {
                    691:                        LOG(LOG_DEBUG + 1, "ignoring altered contents");
                    692:                        goto done;
                    693:                }
                    694: 
                    695:                /* Generate RCA event */
                    696:                fsm->ids[FSM_CODE_CONFIGREQ]++;
                    697:                fsm->failure[PPP_SELF] = FSM_MAX_FAILURE;
                    698:                ppp_fsm_event(fsm, RCA);
                    699:                break;
                    700: 
                    701:        case FSM_CODE_CONFIGNAK:
                    702:        case FSM_CODE_CONFIGREJ:
                    703:            {
                    704:                int (*func)(struct ppp_fsm_instance *inst,
                    705:                    struct ppp_fsm_options *rej);
                    706: 
                    707:                /* Validate id */
                    708:                if (hdr.id != fsm->ids[FSM_CODE_CONFIGREQ]) {
                    709:                        LOG(LOG_DEBUG + 1, "ignoring id #%u", hdr.id);
                    710:                        goto done;
                    711:                }
                    712: 
                    713:                /* Check if not converging */
                    714:                if (hdr.code == FSM_CODE_CONFIGNAK
                    715:                    && --fsm->failure[PPP_SELF] <= 0) {
                    716:                        LOG(LOG_NOTICE, "negotiation failed to converge:"
                    717:                            " configuration not accepted by %s", "peer");
                    718:                        ppp_fsm_record(fsm, FSM_REASON_NEGOT);
                    719:                        goto close;
                    720:                }
                    721: 
                    722:                /* Call implementation to deal with options */
                    723:                func = (hdr.code == FSM_CODE_CONFIGNAK) ?
                    724:                    ftyp->recv_conf_nak : ftyp->recv_conf_rej;
                    725:                if ((*func)(fsm->inst, opts) == -1) {
                    726: config_error:          if (errno == ELOOP)
                    727:                                ppp_fsm_record(fsm, FSM_REASON_LOOPBACK);
                    728:                        else if (errno == EINVAL)
                    729:                                ppp_fsm_record(fsm, FSM_REASON_NEGOT);
                    730:                        else
                    731:                                ppp_fsm_record(fsm, FSM_REASON_SYSERR, errno);
                    732:                        goto close;
                    733:                }
                    734: 
                    735:                /* Generate RCN event */
                    736:                fsm->ids[FSM_CODE_CONFIGREQ]++;
                    737:                ppp_fsm_event(fsm, RCN);
                    738:                break;
                    739:            }
                    740: 
                    741:        case FSM_CODE_TERMREQ:
                    742: 
                    743:                /* Generate RTR event */
                    744:                fsm->ids[FSM_CODE_TERMACK] = hdr.id;
                    745:                ppp_fsm_record(fsm, FSM_REASON_TERM);
                    746:                ppp_fsm_event(fsm, RTR);
                    747:                goto close;
                    748: 
                    749:        case FSM_CODE_TERMACK:
                    750: 
                    751:                /* Validate id */
                    752:                if (hdr.id != fsm->ids[FSM_CODE_TERMREQ]) {
                    753:                        LOG(LOG_DEBUG + 1, "ignoring id #%u", hdr.id);
                    754:                        goto done;
                    755:                }
                    756:                fsm->ids[FSM_CODE_TERMREQ]++;
                    757: 
                    758:                /* Generate RTA event */
                    759:                fsm->ids[FSM_CODE_TERMACK] = hdr.id;
                    760:                ppp_fsm_event(fsm, RTA);
                    761:                break;
                    762: 
                    763:        case FSM_CODE_CODEREJ:
                    764:            {
                    765:                const u_char code = payload[0];
                    766: 
                    767:                /* See if rejected code is required */
                    768:                if (code >= FSM_CODE_MAX
                    769:                    || (ftyp->req_codes & (1 << code)) == 0) {
                    770:                        fsm->rejcode[code] = 1;
                    771:                        ppp_fsm_event(fsm, RXJ_P);
                    772:                } else {
                    773:                        ppp_fsm_record(fsm, FSM_REASON_CODEREJ, code);
                    774:                        ppp_fsm_event(fsm, RXJ_M);
                    775:                        goto close;
                    776:                }
                    777:                break;
                    778:            }
                    779: 
                    780:        case FSM_CODE_PROTOREJ:
                    781:            {
                    782:                u_int16_t proto;
                    783: 
                    784:                /* Get rejected protocol */
                    785:                memcpy(&proto, payload, 2);
                    786:                proto = ntohs(proto);
                    787:                if (proto == ftyp->proto) {
                    788:                        ppp_fsm_record(fsm, FSM_REASON_PROTOREJ, proto);
                    789:                        ppp_fsm_event(fsm, RXJ_M);
                    790:                        goto close;
                    791:                }
                    792:                ppp_fsm_output(fsm, FSM_OUTPUT_PROTOREJ, proto);
                    793:                ppp_fsm_event(fsm, RXJ_P);      /* assume RXJ+ until hear o/w */
                    794:                break;
                    795:            }
                    796: 
                    797:        case FSM_CODE_ECHOREQ:
                    798:            {
                    799:                u_char buf[MAX_PKTCOPY];
                    800:                u_int32_t magic;
                    801: 
                    802:                /* Update reply id */
                    803:                fsm->ids[FSM_CODE_ECHOREP] = hdr.id;
                    804: 
                    805:                /* Only reply when in opened state (except MP LCP) */
                    806:                if (fsm->state != FSM_STATE_OPENED) {
                    807:                        LOG(LOG_DEBUG + 1, "ignoring: not in %s yet",
                    808:                            st2str(FSM_STATE_OPENED));
                    809:                        goto done;
                    810:                }
                    811: 
                    812:                /* Insert my magic number and reply */
                    813:                memcpy(buf, payload, MIN(len, sizeof(buf)));
                    814:                magic = (ftyp->get_magic != NULL) ?
                    815:                    (*ftyp->get_magic)(fsm->inst, PPP_SELF) : 0;
                    816:                magic = htonl(magic);
                    817:                memcpy(buf, &magic, 4);
                    818:                ppp_fsm_send_packet(fsm, FSM_CODE_ECHOREP,
                    819:                    buf, MIN(len, sizeof(buf)));
                    820:                break;
                    821:            }
                    822:        case FSM_CODE_RESETREQ:
                    823:                if (ftyp->recv_reset_req == NULL)
                    824:                        goto code_reject;
                    825:                fsm->ids[FSM_CODE_RESETACK] = hdr.id;
                    826:                (*ftyp->recv_reset_req)(fsm->inst, payload, len);
                    827:                break;
                    828: 
                    829:        case FSM_CODE_RESETACK:
                    830:                if (ftyp->recv_reset_ack == NULL)
                    831:                        goto code_reject;
                    832:                if (hdr.id != fsm->ids[FSM_CODE_RESETREQ])
                    833:                        break;
                    834:                (*ftyp->recv_reset_ack)(fsm->inst, payload, len);
                    835:                break;
                    836: 
                    837:        case FSM_CODE_ECHOREP:  /* ignore these */
                    838:        case FSM_CODE_IDENT:
                    839:        case FSM_CODE_DISCREQ:
                    840:        case FSM_CODE_TIMEREM:
                    841:                break;
                    842: 
                    843:        default:                /* already handled above */
                    844:                break;
                    845:        }
                    846: 
                    847:        /* Done */
                    848:        goto done;
                    849: 
                    850: close:
                    851:        /* Handle failure by closing up shop */
                    852:        ppp_fsm_event(fsm, CLOSE);
                    853: 
                    854: done:
                    855:        /* Clean up */
                    856:        ppp_fsm_option_destroy(&opts);
                    857: }
                    858: 
                    859: /*
                    860:  * Handle an event
                    861:  */
                    862: static void
                    863: ppp_fsm_event(struct ppp_fsm *fsm, int event)
                    864: {
                    865:        const int ostate = fsm->state;
                    866:        const int action = fsm_actions[event][fsm->state];
                    867: 
                    868:        /* Debugging */
                    869:        if (action == NA) {
                    870:                LOG(LOG_ERR, "%s event %s in state %s",
                    871:                    "invalid", ev2str(event), st2str(fsm->state));
                    872:                return;
                    873:        }
                    874:        LOG(LOG_DEBUG, "event %s in state %s",
                    875:            ev2str(event), st2str(fsm->state));
                    876: 
                    877:        /* Perform actions */
                    878:        if ((action & TLU) != 0)
                    879:                ppp_fsm_output(fsm, FSM_OUTPUT_UP);
                    880:        if ((action & TLD) != 0)
                    881:                ppp_fsm_output(fsm, FSM_OUTPUT_DOWN, fsm->dead.u.down.reason);
                    882:        if ((action & TLS) != 0)
                    883:                ppp_fsm_output(fsm, FSM_OUTPUT_OPEN);
                    884:        if ((action & TLF) != 0)
                    885:                ppp_fsm_output(fsm, FSM_OUTPUT_CLOSE);
                    886:        if ((action & IRC) != 0) {
                    887:                fsm->restart = (event == CLOSE || event == RXJ_M) ?
                    888:                    FSM_MAX_TERMINATE : FSM_MAX_CONFIGURE;
                    889:        }
                    890:        if ((action & SCR) != 0)
                    891:                ppp_fsm_send_config(fsm, FSM_CODE_CONFIGREQ);
                    892:        if ((action & SCA) != 0)
                    893:                ppp_fsm_send_config(fsm, FSM_CODE_CONFIGACK);
                    894:        if ((action & SCN) != 0) {
                    895:                if (fsm->config[FSM_CONF_REJ]->num != 0)
                    896:                        ppp_fsm_send_config(fsm, FSM_CODE_CONFIGREJ);
                    897:                if (fsm->config[FSM_CONF_NAK]->num != 0)
                    898:                        ppp_fsm_send_config(fsm, FSM_CODE_CONFIGNAK);
                    899:        }
                    900:        if ((action & STR) != 0)
                    901:                ppp_fsm_send_packet(fsm, FSM_CODE_TERMREQ, NULL, 0);
                    902:        if ((action & STA) != 0)
                    903:                ppp_fsm_send_packet(fsm, FSM_CODE_TERMACK, NULL, 0);
                    904: 
                    905:        /* Transition to new state */
                    906:        fsm->state = (action & STMASK);
                    907:        if (fsm->state != ostate)
                    908:                LOG(LOG_DEBUG, "%s -> %s", st2str(ostate), st2str(fsm->state));
                    909: 
                    910:        /* Initialize failure counter if appropriate */
                    911:        if (ostate < FSM_STATE_REQSENT && fsm->state >= FSM_STATE_REQSENT) {
                    912:                fsm->failure[PPP_SELF] = FSM_MAX_FAILURE;
                    913:                fsm->failure[PPP_PEER] = FSM_MAX_FAILURE;
                    914:        }
                    915: 
                    916:        /* Stop the restart timer if it's not supposed to be running */
                    917:        if (!FSM_TIMER_STATE(fsm->state)) {
                    918:                pevent_unregister(&fsm->timer);
                    919:                goto no_timer;
                    920:        }
                    921: 
                    922:        /* Check if timer is already running and doesn't need to be restarted */
                    923:        if (FSM_TIMER_STATE(ostate) && (action & (SCR|STR)) == 0)
                    924:                goto no_timer;
                    925: 
                    926:        /* (Re)start restart timer */
                    927:        pevent_unregister(&fsm->timer);
                    928:        if (pevent_register(fsm->ev_ctx, &fsm->timer, 0, fsm->mutex,
                    929:            ppp_fsm_timeout, fsm, PEVENT_TIME, FSM_TIMEOUT * 1000) == -1) {
                    930:                ppp_fsm_syserr(fsm, "pevent_register");
                    931:                return;
                    932:        }
                    933: 
                    934: no_timer:
                    935:        /* Emit 'dead' output if we're dead */
                    936:        if (FSM_DEAD(fsm))
                    937:                ppp_fsm_output_dead(fsm);
                    938: }
                    939: 
                    940: /*
                    941:  * Send a config req, ack, nak, or rej packet
                    942:  */
                    943: static void
                    944: ppp_fsm_send_config(struct ppp_fsm *fsm, enum ppp_fsm_code code)
                    945: {
                    946:        const struct ppp_fsm_type *const ftyp = fsm->inst->type;
                    947:        struct ppp_fsm_options *opts;
                    948:        u_char *buf;
                    949:        u_int len;
                    950: 
                    951:        /* Get the corresponding config option data */
                    952:        switch (code) {
                    953:        case FSM_CODE_CONFIGREQ:
                    954:            {
                    955:                u_int i;
                    956:                u_int j;
                    957: 
                    958:                /* Regenerate my requested config options */
                    959:                opts = fsm->config[FSM_CONF_SELF];
                    960:                ppp_fsm_option_zero(opts);
                    961:                if ((*ftyp->build_conf_req)(fsm->inst, opts) == -1) {
                    962:                        if (errno == EINVAL)
                    963:                                ppp_fsm_record(fsm, FSM_REASON_NEGOT);
                    964:                        else
                    965:                                ppp_fsm_syserr(fsm, "build_conf_req");
                    966:                        return;
                    967:                }
                    968: 
                    969:                /* Elide default values from within config-request */
                    970:                if (fsm->inst->type->defaults == NULL)
                    971:                        break;
                    972:                for (i = 0; i < fsm->inst->type->defaults->num; i++) {
                    973:                        for (j = 0; j < opts->num; j++) {
                    974:                                if (ppp_fsm_option_equal(
                    975:                                    fsm->inst->type->defaults, i, opts, j))
                    976:                                        ppp_fsm_option_del(opts, j--);
                    977:                        }
                    978:                }
                    979:                break;
                    980:            }
                    981:        case FSM_CODE_CONFIGACK:
                    982:                opts = fsm->config[FSM_CONF_PEER];
                    983:                break;
                    984:        case FSM_CODE_CONFIGNAK:
                    985:                opts = fsm->config[FSM_CONF_NAK];
                    986:                break;
                    987:        case FSM_CODE_CONFIGREJ:
                    988:                opts = fsm->config[FSM_CONF_REJ];
                    989:                break;
                    990:        default:
                    991:                assert (0);
                    992:                return;
                    993:        }
                    994: 
                    995:        /* Construct packet payload */
                    996:        len = ppp_fsm_option_packlen(opts);
                    997:        if ((buf = MALLOC(TYPED_MEM_TEMP, len)) == NULL) {
                    998:                LOG(LOG_ERR, "%s: %m", "malloc");
                    999:                ppp_fsm_syserr(fsm, "malloc");
                   1000:                return;
                   1001:        }
                   1002: 
                   1003:        /* Send packet */
                   1004:        ppp_fsm_option_pack(opts, buf);
                   1005:        ppp_fsm_send_packet(fsm, code, buf, len);
                   1006:        FREE(TYPED_MEM_TEMP, buf);
                   1007: }
                   1008: 
                   1009: /*
                   1010:  * Handler for an FSM timeout event.
                   1011:  */
                   1012: static void
                   1013: ppp_fsm_timeout(void *arg)
                   1014: {
                   1015:        struct ppp_fsm *const fsm = arg;
                   1016: 
                   1017:        /* Cancel event */
                   1018:        pevent_unregister(&fsm->timer);
                   1019: 
                   1020:        /* If we're dead, ignore it */
                   1021:        if (FSM_DEAD(fsm))
                   1022:                return;
                   1023: 
                   1024:        /* Send timeout event */
                   1025:        if (--fsm->restart <= 0)
                   1026:                ppp_fsm_event(fsm, TO_M);
                   1027:        else
                   1028:                ppp_fsm_event(fsm, TO_P);
                   1029: }
                   1030: 
                   1031: /*
                   1032:  * Send a packet.
                   1033:  *
                   1034:  * Handle any errors by shutting down the FSM.
                   1035:  */
                   1036: static void
                   1037: ppp_fsm_send_packet(struct ppp_fsm *fsm,
                   1038:        u_char code, const void *data, u_int len)
                   1039: {
                   1040:        struct ppp_fsm_pkt *pkt;
                   1041: 
                   1042:        /* If peer rejected code, don't bother */
                   1043:        if (fsm->rejcode[code])
                   1044:                return;
                   1045: 
                   1046:        /* Build packet */
                   1047:        if ((pkt = MALLOC(FSM_MTYPE, sizeof(*pkt) + len)) == NULL) {
                   1048:                ppp_fsm_syserr(fsm, "malloc");
                   1049:                return;
                   1050:        }
                   1051:        pkt->code = code;
                   1052:        pkt->id = fsm->ids[code];
                   1053:        pkt->length = htons(sizeof(*pkt) + len);
                   1054:        memcpy(pkt->data, data, len);
                   1055: 
                   1056:        /* Logging */
                   1057:        ppp_fsm_log_pkt(fsm, (pkt->code == FSM_CODE_ECHOREQ
                   1058:            || pkt->code == FSM_CODE_ECHOREP) ? LOG_DEBUG : LOG_INFO,
                   1059:            "xmit", (u_char *)pkt);
                   1060: 
                   1061:        /* Send packet */
                   1062:        if (ppp_fsm_output(fsm, FSM_OUTPUT_DATA, pkt, sizeof(*pkt) + len) == -1)
                   1063:                FREE(FSM_MTYPE, pkt);
                   1064: }
                   1065: 
                   1066: /*
                   1067:  * Record the reason for the FSM going down or dying.
                   1068:  *
                   1069:  * This information is saved until it can be output later.
                   1070:  */
                   1071: static void
                   1072: ppp_fsm_record(struct ppp_fsm *fsm, ...)
                   1073: {
                   1074:        struct ppp_fsm_output *const output = &fsm->dead;
                   1075:        va_list args;
                   1076: 
                   1077:        /* Prioritize reason first on severity, then first come, first serve */
                   1078:        if (fsm->dead.u.down.reason == 0)
                   1079:                goto record;
                   1080:        switch (fsm->dead.u.down.reason) {
                   1081:        case FSM_REASON_CONF:
                   1082:        case FSM_REASON_DOWN_NONFATAL:
                   1083:                break;
                   1084:        default:
                   1085:                return;
                   1086:        }
                   1087: 
                   1088: record:
                   1089:        /* Build output message */
                   1090:        va_start(args, fsm);
                   1091:        ppp_fsm_output_build(output, FSM_OUTPUT_DEAD, args);
                   1092:        va_end(args);
                   1093: }
                   1094: 
                   1095: /*
                   1096:  * Emit some sort of output from the FSM.
                   1097:  *
                   1098:  * Any errors are handled internally by shutting down the FSM.
                   1099:  */
                   1100: static int
                   1101: ppp_fsm_output(struct ppp_fsm *fsm, enum ppp_fsmoutput type, ...)
                   1102: {
                   1103:        struct ppp_fsm_output *output;
                   1104:        va_list args;
                   1105: 
                   1106:        /* Allocate new output message */
                   1107:        if ((output = MALLOC(FSM_MTYPE, sizeof(*output))) == NULL) {
                   1108:                ppp_fsm_syserr(fsm, "malloc");
                   1109:                return (-1);
                   1110:        }
                   1111:        memset(output, 0, sizeof(*output));
                   1112: 
                   1113:        /* Build output message */
                   1114:        va_start(args, type);
                   1115:        ppp_fsm_output_build(output, type, args);
                   1116:        va_end(args);
                   1117: 
                   1118:        /* Send it */
                   1119:        if (mesg_port_put(fsm->outport, output) == -1) {
                   1120:                ppp_fsm_syserr(fsm, "mesg_port_put");
                   1121:                FREE(FSM_MTYPE, output);
                   1122:                return (-1);
                   1123:        }
                   1124: 
                   1125:        /* Done */
                   1126:        return (0);
                   1127: }
                   1128: 
                   1129: /*
                   1130:  * Output FSM_OUTPUT_DEAD message because we're dead.
                   1131:  *
                   1132:  * This is called when we reach the initial state after a fatal error.
                   1133:  * We copy the reason information previously recorded via ppp_fsm_record().
                   1134:  */
                   1135: static void
                   1136: ppp_fsm_output_dead(struct ppp_fsm *fsm)
                   1137: {
                   1138:        struct ppp_fsm_output *output;
                   1139: 
                   1140:        /* Create new output message */
                   1141:        if ((output = MALLOC(FSM_MTYPE, sizeof(*output))) == NULL) {
                   1142:                ppp_fsm_syserr(fsm, "malloc");
                   1143:                return;
                   1144:        }
                   1145:        memset(output, 0, sizeof(*output));
                   1146: 
                   1147:        /* Copy previously recorded output message, changing DOWN to DEAD */
                   1148:        *output = fsm->dead;
                   1149: 
                   1150:        /* Send it */
                   1151:        if (mesg_port_put(fsm->outport, output) == -1) {
                   1152:                ppp_fsm_syserr(fsm, "mesg_port_put");
                   1153:                FREE(FSM_MTYPE, output);
                   1154:        }
                   1155: }
                   1156: 
                   1157: /*
                   1158:  * Build an FSM output structure.
                   1159:  */
                   1160: static void
                   1161: ppp_fsm_output_build(struct ppp_fsm_output *output,
                   1162:        enum ppp_fsmoutput type, va_list args)
                   1163: {
                   1164:        output->type = type;
                   1165:        switch (type) {
                   1166:        case FSM_OUTPUT_OPEN:
                   1167:        case FSM_OUTPUT_CLOSE:
                   1168:        case FSM_OUTPUT_UP:
                   1169:                break;
                   1170:        case FSM_OUTPUT_DOWN:
                   1171:        case FSM_OUTPUT_DEAD:
                   1172:                output->u.down.reason = va_arg(args, int);
                   1173:                switch (output->u.down.reason) {
                   1174:                case FSM_REASON_SYSERR:
                   1175:                        output->u.down.u.error = va_arg(args, int);
                   1176:                        break;
                   1177:                case FSM_REASON_CONF:
                   1178:                case FSM_REASON_CODEREJ:
                   1179:                        output->u.down.u.code = va_arg(args, int);
                   1180:                        break;
                   1181:                case FSM_REASON_PROTOREJ:
                   1182:                        output->u.down.u.proto = va_arg(args, int);
                   1183:                        break;
                   1184:                default:
                   1185:                        break;
                   1186:                }
                   1187:                break;
                   1188:        case FSM_OUTPUT_DATA:
                   1189:                output->u.data.data = va_arg(args, u_char *);
                   1190:                output->u.data.length = va_arg(args, u_int);
                   1191:                break;
                   1192:        case FSM_OUTPUT_PROTOREJ:
                   1193:                output->u.proto = va_arg(args, int);
                   1194:                break;
                   1195:        default:
                   1196:                assert(0);
                   1197:        }
                   1198: }
                   1199: 
                   1200: /*
                   1201:  * Handle system error
                   1202:  */
                   1203: static void
                   1204: ppp_fsm_syserr(struct ppp_fsm *fsm, const char *func)
                   1205: {
                   1206:        LOG(LOG_ERR, "%s: %m", func);
                   1207:        ppp_fsm_record(fsm, FSM_REASON_SYSERR, errno);
                   1208: }
                   1209: 
                   1210: /*
                   1211:  * Decode and log contents of an FSM packet
                   1212:  */
                   1213: static void
                   1214: ppp_fsm_log_pkt(struct ppp_fsm *fsm, int sev,
                   1215:        const char *prefix, const u_char *pkt)
                   1216: {
                   1217:        const u_char *const payload = pkt + sizeof(struct ppp_fsm_pkt);
                   1218:        struct ppp_fsm_pkt hdr;
                   1219:        char buf[512] = { '\0' };
                   1220:        u_int16_t dlen;
                   1221: 
                   1222:        memcpy(&hdr, pkt, sizeof(hdr));
                   1223:        dlen = ntohs(hdr.length) - sizeof(hdr);
                   1224:        switch (hdr.code) {
                   1225:        case FSM_CODE_CONFIGREQ:
                   1226:        case FSM_CODE_CONFIGNAK:
                   1227:        case FSM_CODE_CONFIGREJ:
                   1228:        case FSM_CODE_CONFIGACK:
                   1229:                ppp_fsm_options_decode(fsm->inst->type->options,
                   1230:                    payload, dlen, buf, sizeof(buf));
                   1231:                break;
                   1232:        case FSM_CODE_CODEREJ:
                   1233:                snprintf(buf, sizeof(buf), "code=%u", payload[0]);
                   1234:                break;
                   1235:        case FSM_CODE_PROTOREJ:
                   1236:                snprintf(buf, sizeof(buf),
                   1237:                    "proto=0x%02x%02x", payload[0], payload[1]);
                   1238:                break;
                   1239:        case FSM_CODE_IDENT:
                   1240:        case FSM_CODE_TERMREQ:
                   1241:        case FSM_CODE_TERMACK:
                   1242:                if (dlen > 0) {
                   1243:                        strlcpy(buf, "msg=\"", sizeof(buf));
                   1244:                        ppp_util_ascify(buf + strlen(buf),
                   1245:                            sizeof(buf) - strlen(buf), payload + 4, dlen - 4);
                   1246:                        strlcat(buf, "\"", sizeof(buf));
                   1247:                }
                   1248:                break;
                   1249:        case FSM_CODE_TIMEREM:
                   1250:            {
                   1251:                u_int32_t remain;
                   1252:                char tbuf[32];
                   1253: 
                   1254:                memcpy(&remain, payload + 4, 4);
                   1255:                remain = ntohl(remain);
                   1256:                if (remain == ~0)
                   1257:                        strlcpy(tbuf, "unlimited", sizeof(tbuf));
                   1258:                else {
                   1259:                        snprintf(tbuf, sizeof(tbuf),
                   1260:                            "%lu seconds", (u_long)remain);
                   1261:                }
                   1262:                strlcpy(buf, "remaining=", sizeof(buf));
                   1263:                strlcat(buf, tbuf, sizeof(buf));
                   1264:                if (dlen > 4) {
                   1265:                        strlcat(buf, " msg=\"", sizeof(buf));
                   1266:                        ppp_util_ascify(buf + strlen(buf),
                   1267:                            sizeof(buf) - strlen(buf), payload + 8, dlen - 8);
                   1268:                        strlcat(buf, "\"", sizeof(buf));
                   1269:                }
                   1270:                break;
                   1271:            }
                   1272:        default:
                   1273:                break;
                   1274:        }
                   1275: 
                   1276:        /* Finally, log it */
                   1277:        if (*buf == '\0')
                   1278:                LOG(sev, "%s %s #%u", prefix, cd2str(hdr.code), hdr.id);
                   1279:        else {
                   1280:                LOG(sev, "%s %s #%u: %s", prefix,
                   1281:                    cd2str(hdr.code), hdr.id, buf);
                   1282:        }
                   1283: }
                   1284: 
                   1285: static const char *
                   1286: st2str(u_int state)
                   1287: {
                   1288:        static const char *const snames[FSM_STATE_MAX] = {
                   1289:            "INITIAL", "STARTING", "CLOSED", "STOPPED", "CLOSING",
                   1290:            "STOPPING", "REQ-SENT", "ACK-RCVD", "ACK-SENT", "OPENED"
                   1291:        };
                   1292:        static char buf[16];
                   1293: 
                   1294:        if (state >= sizeof(snames) / sizeof(*snames)) {
                   1295:                snprintf(buf, sizeof(buf), "?[%u]", state);
                   1296:                return (buf);
                   1297:        }
                   1298:        return (snames[state]);
                   1299: }
                   1300: 
                   1301: static const char *
                   1302: ev2str(u_int event)
                   1303: {
                   1304:        static const char *const enames[FSM_EVENT_MAX] = {
                   1305:            "UP", "DOWN", "OPEN", "CLOSE", "TO+", "TO-", "RCR+",
                   1306:            "RCR-", "RCA", "RCN", "RTR", "RTA", "RXJ+", "RXJ-"
                   1307:        };
                   1308:        static char buf[16];
                   1309: 
                   1310:        if (event >= sizeof(enames) / sizeof(*enames)) {
                   1311:                snprintf(buf, sizeof(buf), "?[%u]", event);
                   1312:                return (buf);
                   1313:        }
                   1314:        return (enames[event]);
                   1315: }
                   1316: 
                   1317: static const char *
                   1318: cd2str(u_int code)
                   1319: {
                   1320:        static const char *const cnames[FSM_CODE_MAX] = {
                   1321:            "Vendor", "Conf-Req", "Conf-Ack", "Conf-Nak", "Conf-Rej",
                   1322:            "Term-Req", "Term-Ack", "Code-Rej", "Proto-Rej", "Echo-Req",
                   1323:            "Echo-Rsp", "Disc-Req", "Ident", "Time-Rem", "Reset-Req",
                   1324:            "Reset-Ack"
                   1325:        };
                   1326:        static char buf[16];
                   1327: 
                   1328:        if (code >= sizeof(cnames) / sizeof(*cnames)) {
                   1329:                snprintf(buf, sizeof(buf), "?[%u]", code);
                   1330:                return (buf);
                   1331:        }
                   1332:        return (cnames[code]);
                   1333: }
                   1334: 
                   1335: /***********************************************************************
                   1336:                    PUBLIC DEBUGGING FUNCTIONS
                   1337: ***********************************************************************/
                   1338: 
                   1339: /*
                   1340:  * Return a string describing FSM output.
                   1341:  */
                   1342: const char *
                   1343: ppp_fsm_output_str(struct ppp_fsm_output *output)
                   1344: {
                   1345:        static char buf[256];
                   1346: 
                   1347:        switch (output->type) {
                   1348:        case FSM_OUTPUT_OPEN:
                   1349:                snprintf(buf, sizeof(buf), "OPEN");
                   1350:                break;
                   1351:        case FSM_OUTPUT_CLOSE:
                   1352:                snprintf(buf, sizeof(buf), "CLOSE");
                   1353:                break;
                   1354:        case FSM_OUTPUT_UP:
                   1355:                snprintf(buf, sizeof(buf), "UP");
                   1356:                break;
                   1357:        case FSM_OUTPUT_DOWN:
                   1358:                snprintf(buf, sizeof(buf), "DOWN reason=%s",
                   1359:                    ppp_fsm_reason_str(output));
                   1360:                break;
                   1361:        case FSM_OUTPUT_DATA:
                   1362:                snprintf(buf, sizeof(buf), "DATA type=%s",
                   1363:                    cd2str(output->u.data.data[0]));
                   1364:                break;
                   1365:        case FSM_OUTPUT_PROTOREJ:
                   1366:                snprintf(buf, sizeof(buf), "PROTOREJ proto=0x%04x",
                   1367:                    output->u.proto);
                   1368:                break;
                   1369:        case FSM_OUTPUT_DEAD:
                   1370:                snprintf(buf, sizeof(buf), "DEAD reason=%s",
                   1371:                    ppp_fsm_reason_str(output));
                   1372:                break;
                   1373:        default:
                   1374:                snprintf(buf, sizeof(buf), "?[%u]?", output->type);
                   1375:                break;
                   1376:        }
                   1377:        return (buf);
                   1378: }
                   1379: 
                   1380: /*
                   1381:  * Return a string describing a FSM_OUTPUT_DOWN or FSM_OUTPUT_DEAD output.
                   1382:  */
                   1383: const char *
                   1384: ppp_fsm_reason_str(struct ppp_fsm_output *output)
                   1385: {
                   1386:        static char buf[64];
                   1387: 
                   1388:        /* Sanity check */
                   1389:        if (output->type != FSM_OUTPUT_DEAD
                   1390:            && output->type != FSM_OUTPUT_DOWN)
                   1391:                return ("?not FSM_OUTPUT_DOWN or FSM_OUTPUT_DEAD");
                   1392: 
                   1393:        /* Describe reason */
                   1394:        switch (output->u.down.reason) {
                   1395:        case FSM_REASON_CLOSE:
                   1396:                strlcpy(buf, "administratively closed", sizeof(buf));
                   1397:                break;
                   1398:        case FSM_REASON_DOWN_FATAL:
                   1399:                strlcpy(buf, "the underlying packet delivery"
                   1400:                    " layer failed (fatal)", sizeof(buf));
                   1401:                break;
                   1402:        case FSM_REASON_DOWN_NONFATAL:
                   1403:                strlcpy(buf, "the underlying packet delivery"
                   1404:                    " layer failed (non-fatal)", sizeof(buf));
                   1405:                break;
                   1406:        case FSM_REASON_CONF:
                   1407:                snprintf(buf, sizeof(buf),
                   1408:                    "rec'd %s after reaching opened state",
                   1409:                    cd2str(output->u.down.u.code));
                   1410:                break;
                   1411:        case FSM_REASON_TERM:
                   1412:                snprintf(buf, sizeof(buf),
                   1413:                    "rec'd a Terminate-Request from peer");
                   1414:                break;
                   1415:        case FSM_REASON_CODEREJ:
                   1416:                snprintf(buf, sizeof(buf),
                   1417:                    "rec'd a fatal Code-Reject (code=%s)",
                   1418:                    cd2str(output->u.down.u.code));
                   1419:                break;
                   1420:        case FSM_REASON_PROTOREJ:
                   1421:                snprintf(buf, sizeof(buf),
                   1422:                    "rec'd a fatal Protocol-Reject (proto=0x%04x)",
                   1423:                    output->u.down.u.proto);
                   1424:                break;
                   1425:        case FSM_REASON_NEGOT:
                   1426:                strlcpy(buf, "local and remote configurations"
                   1427:                    " are not compatible", sizeof(buf));
                   1428:                break;
                   1429:        case FSM_REASON_BADMAGIC:
                   1430:                strlcpy(buf, "rec'd a packet with an invalid magic number",
                   1431:                    sizeof(buf));
                   1432:                break;
                   1433:        case FSM_REASON_LOOPBACK:
                   1434:                strlcpy(buf, "a loopback condition was detected", sizeof(buf));
                   1435:                break;
                   1436:        case FSM_REASON_TIMEOUT:
                   1437:                strlcpy(buf, "timed out waiting for an echo response",
                   1438:                    sizeof(buf));
                   1439:                break;
                   1440:        case FSM_REASON_SYSERR:
                   1441:                snprintf(buf, sizeof(buf), "internal system error, error=%s",
                   1442:                    strerror(output->u.down.u.error));
                   1443:                break;
                   1444:        default:
                   1445:                snprintf(buf, sizeof(buf), "?[%u]", output->u.down.reason);
                   1446:                break;
                   1447:        }
                   1448:        return (buf);
                   1449: }
                   1450: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>