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>