Annotation of embedaddon/libpdel/ppp/ppp_pptp_ctrl.c, revision 1.1

1.1     ! misho       1: 
        !             2: /*
        !             3:  * Copyright (c) 1995-1999 Whistle Communications, Inc.
        !             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:  * Whistle Communications; provided, however, that:   (i) any and
        !            10:  * all reproductions of the source or object code must include the
        !            11:  * copyright notice above and the following disclaimer of warranties;
        !            12:  * and (ii) no rights are granted, in any manner or form, to use
        !            13:  * Whistle Communications, Inc. trademarks, including the mark "WHISTLE
        !            14:  * COMMUNICATIONS" on advertising, endorsements, or otherwise except
        !            15:  * as such appears in the above copyright notice or in the software.
        !            16:  * 
        !            17:  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS",
        !            18:  * AND TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS
        !            19:  * MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED,
        !            20:  * REGARDING THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND
        !            21:  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
        !            22:  * PURPOSE, OR NON-INFRINGEMENT.  WHISTLE COMMUNICATIONS DOES NOT
        !            23:  * WARRANT, GUARANTEE, OR MAKE ANY REPRESENTATIONS REGARDING THE USE
        !            24:  * OF, OR THE RESULTS OF THE USE OF THIS SOFTWARE IN TERMS OF ITS
        !            25:  * CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.  IN NO EVENT
        !            26:  * SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES RESULTING
        !            27:  * FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING WITHOUT
        !            28:  * LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
        !            29:  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE
        !            30:  * GOODS OR SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED
        !            31:  * AND UNDER ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
        !            33:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS
        !            34:  * IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            35:  *
        !            36:  * Author: <archie@freebsd.org>
        !            37:  */
        !            38: 
        !            39: #include "ppp/ppp_defs.h"
        !            40: #include "ppp/ppp_log.h"
        !            41: #include "ppp/ppp_pptp_ctrl.h"
        !            42: #include "ppp/ppp_pptp_ctrl_defs.h"
        !            43: #include <netinet/tcp.h>
        !            44: 
        !            45: /*
        !            46:  * DEFINITIONS
        !            47:  */
        !            48: 
        !            49:   #define RANDOMIZE_CID                        1
        !            50:   #define CHECK_RESERVED_FIELDS                0
        !            51:   #define LOGNAME_MAX                  32
        !            52: 
        !            53: #ifndef FALSE
        !            54:   #define FALSE                                0
        !            55:   #define TRUE                         1
        !            56: #endif
        !            57: 
        !            58:   #define PPTP_MTYPE                   "ppp_pptp_ctrl"
        !            59:   #define PPTP_CTRL_MTYPE              "ppp_pptp_ctrl.ctrl"
        !            60:   #define PPTP_CHAN_MTYPE              "ppp_pptp_ctrl.chan"
        !            61:   #define PPTP_PREP_MTYPE              "ppp_pptp_ctrl.prep"
        !            62: 
        !            63:   #define PPTP_FIRMWARE_REV            0x0101
        !            64: 
        !            65:   #define PPTP_STR_INTERNAL_CALLING    "Internally originated VPN call"
        !            66: 
        !            67:   /* Limits on how long we wait for replies to things */
        !            68:   #define PPTP_DFL_REPLY_TIME          PPTP_IDLE_TIMEOUT
        !            69:   #define PPTP_OUTCALLREQ_REPLY_TIME   60
        !            70:   #define PPTP_INCALLREP_REPLY_TIME    60
        !            71:   #define PPTP_STOPCCR_REPLY_TIME      3
        !            72: 
        !            73:   /* Logging */
        !            74:   #define PLOG(sev, fmt, args...)      \
        !            75:              ppp_log_put(pptp->log, sev, fmt , ## args)
        !            76:   #define CLOG(sev, fmt, args...)      \
        !            77:              ppp_log_put(c->log, sev, fmt , ## args)
        !            78:   #define CHLOG(sev, fmt, args...)     \
        !            79:              ppp_log_put(ch->log, sev, fmt , ## args)
        !            80: 
        !            81:   struct pptp_engine;
        !            82: 
        !            83:   /* This describes how/if a reply is required */
        !            84:   struct pptpreqrep {
        !            85:     u_char     reply;                  /* required reply (or zero) */
        !            86:     u_char     killCtrl;               /* fatal to ctrl or just to channel */
        !            87:     u_short    timeout;                /* max time to wait for reply */
        !            88:   };
        !            89:   typedef struct pptpreqrep    *PptpReqRep;
        !            90: 
        !            91:   /* This represents a pending reply we're waiting for */
        !            92:   struct pptppendrep {
        !            93:     const struct pptpmsginfo   *request;       /* original message info */
        !            94:     struct pptpctrl            *ctrl;          /* control channel */
        !            95:     struct pptpchan            *chan;          /* channel (NULL if none) */
        !            96:     struct pevent              *timer;         /* reply timeout timer */
        !            97:     struct pptppendrep         *next;          /* next in list */
        !            98:   };
        !            99:   typedef struct pptppendrep   *PptpPendRep;
        !           100: 
        !           101:   /* This describes how to match a message to the corresponding channel */
        !           102:   struct pptpchanid {
        !           103:     u_char             findIn;         /* how to find channel (incoming) */
        !           104:     u_char             findOut;        /* how to find channel (outgoing) */
        !           105:     const char         *inField;       /* field used to find channel (in) */
        !           106:     const char         *outField;      /* field used to find channel (out) */
        !           107:   };
        !           108:   typedef struct pptpchanid    *PptpChanId;
        !           109: 
        !           110:   #define PPTP_FIND_CHAN_MY_CID                1       /* match field vs. my cid */
        !           111:   #define PPTP_FIND_CHAN_PEER_CID      2       /* match field vs. peer cid */
        !           112:   #define PPTP_FIND_CHAN_PNS_CID       3       /* match field vs. PNS cid */
        !           113:   #define PPTP_FIND_CHAN_PAC_CID       4       /* match field vs. PAC cid */
        !           114: 
        !           115:   /* Message handler function type */
        !           116:   typedef void pptpmsghandler_t(void *, void *);
        !           117: 
        !           118:   /* Total info about a message type (except field layout) */
        !           119:   struct pptpmsginfo {
        !           120:     const char         *name;          /* name for this message type */
        !           121:     pptpmsghandler_t   *handler;       /* message handler function */
        !           122:     u_char             isReply;        /* this is always a reply message */
        !           123:     u_char             length;         /* length of message (sans header) */
        !           124:     u_short            states;         /* states which admit this message */
        !           125:     struct pptpchanid  match;          /* how to find corresponding channel */
        !           126:     struct pptpreqrep  reqrep;         /* what kind of reply we expect */
        !           127:   };
        !           128:   typedef const struct pptpmsginfo     *PptpMsgInfo;
        !           129: 
        !           130:   /* Receive window size XXX */
        !           131:   #define PPTP_RECV_WIN                        16
        !           132: 
        !           133:   /* Packet processing delay XXX */
        !           134:   #define PPTP_PPD                     1
        !           135: 
        !           136:   /* Channel state */
        !           137:   struct pptpchan {
        !           138:     u_char             state;          /* channel state */
        !           139:     u_char             id;             /* channel index */
        !           140:     u_char             orig:1;         /* call originated from us */
        !           141:     u_char             incoming:1;     /* call is incoming, not outgoing */
        !           142:     u_char             killing:1;      /* channel is being killed */
        !           143:     u_int16_t          cid;            /* my call id */
        !           144:     u_int16_t          serno;          /* call serial number */
        !           145:     u_int16_t          peerCid;        /* peer call id */
        !           146:     u_int16_t          peerPpd;        /* peer's packet processing delay */
        !           147:     u_int16_t          recvWin;        /* peer's recv window size */
        !           148:     u_int32_t          recvSeq;        /* last seq # we rcv'd */
        !           149:     u_int32_t          xmitSeq;        /* last seq # we sent */
        !           150:     u_int32_t          recvAck;        /* last seq # peer acknowledged */
        !           151:     u_int32_t          xmitAck;        /* last seq # we acknowledged */
        !           152:     u_int32_t          bearType;       /* call bearer type */
        !           153:     u_int32_t          frameType;      /* call framing type */
        !           154:     u_int32_t          minBps;         /* minimum acceptable speed */
        !           155:     u_int32_t          maxBps;         /* maximum acceptable speed */
        !           156:     struct pptplinkinfo        linfo;          /* info about corresponding link */
        !           157:     struct pptpctrl    *ctrl;          /* my control channel */
        !           158:     struct ppp_log     *log;           /* log */
        !           159:     char               callingNum[PPTP_PHONE_LEN + 1]; /* calling number */
        !           160:     char               calledNum[PPTP_PHONE_LEN + 1];  /* called number */
        !           161:     char               subAddress[PPTP_SUBADDR_LEN + 1];/* sub-address */
        !           162:   };
        !           163:   typedef struct pptpchan      *PptpChan;
        !           164: 
        !           165:   #define PPTP_CHAN_IS_PNS(ch)         (!(ch)->orig ^ !(ch)->incoming)
        !           166: 
        !           167:   /* Control channel state */
        !           168:   struct pptpctrl {
        !           169:     u_char             frame[PPTP_CTRL_MAX_FRAME];
        !           170:     u_char             state;          /* state */
        !           171:     u_char             id;             /* channel index */
        !           172:     u_char             orig:1;         /* we originated connection */
        !           173:     u_char             killing:1;      /* connection is being killed */
        !           174:     u_int16_t          flen;           /* length of partial frame */
        !           175:     int                        csock;          /* peer control messages */
        !           176:     struct in_addr     self_addr;      /* local IP address */
        !           177:     struct in_addr     peer_addr;      /* peer we're talking to */
        !           178:     u_int16_t          self_port;
        !           179:     u_int16_t          peer_port;
        !           180:     struct pptp_engine *pptp;          /* engine that owns me */
        !           181:     struct pevent      *connEvent;     /* connection event */
        !           182:     struct pevent      *ctrlEvent;     /* control connection input */
        !           183:     struct pevent      *killEvent;     /* kill this ctrl in separate thread */
        !           184:     struct pevent      *idleTimer;     /* idle timer */
        !           185:     struct ppp_log     *log;           /* log */
        !           186:     u_int32_t          echoId;         /* last echo id # sent */
        !           187:     PptpPendRep                reps;           /* pending replies to msgs */
        !           188:     PptpChan           *channels;      /* array of channels */
        !           189:     int                        numChannels;    /* length of channels array */
        !           190:     char               logname[LOGNAME_MAX];   /* name for logging */
        !           191:   };
        !           192:   typedef struct pptpctrl      *PptpCtrl;
        !           193: 
        !           194:   #define MAX_IOVEC    32
        !           195: 
        !           196:   /* Our physical channel ID */
        !           197:   #define PHYS_CHAN(ch)                (((ch)->ctrl->id << 16) | (ch)->id)
        !           198: 
        !           199: /*
        !           200:  * INTERNAL FUNCTIONS
        !           201:  */
        !           202: 
        !           203:   /* Methods for each control message type */
        !           204:   static void  PptpStartCtrlConnRequest(PptpCtrl c,
        !           205:                        struct pptpStartCtrlConnRequest *m);
        !           206:   static void  PptpStartCtrlConnReply(PptpCtrl c,
        !           207:                        struct pptpStartCtrlConnReply *m);
        !           208:   static void  PptpStopCtrlConnRequest(PptpCtrl c,
        !           209:                        struct pptpStopCtrlConnRequest *m);
        !           210:   static void  PptpStopCtrlConnReply(PptpCtrl c,
        !           211:                        struct pptpStopCtrlConnReply *m);
        !           212:   static void  PptpEchoRequest(PptpCtrl c, struct pptpEchoRequest *m);
        !           213:   static void  PptpEchoReply(PptpCtrl c, struct pptpEchoReply *m);
        !           214:   static void  PptpOutCallRequest(PptpCtrl c, struct pptpOutCallRequest *m);
        !           215:   static void  PptpOutCallReply(PptpChan ch, struct pptpOutCallReply *m);
        !           216:   static void  PptpInCallRequest(PptpCtrl c, struct pptpInCallRequest *m);
        !           217:   static void  PptpInCallReply(PptpChan ch, struct pptpInCallReply *m);
        !           218:   static void  PptpInCallConn(PptpChan ch, struct pptpInCallConn *m);
        !           219:   static void  PptpCallClearRequest(PptpChan ch,
        !           220:                        struct pptpCallClearRequest *m);
        !           221:   static void  PptpCallDiscNotify(PptpChan ch, struct pptpCallDiscNotify *m);
        !           222:   static void  PptpWanErrorNotify(PptpChan ch, struct pptpWanErrorNotify *m);
        !           223:   static void  PptpSetLinkInfo(PptpChan ch, struct pptpSetLinkInfo *m);
        !           224: 
        !           225:   /* Link layer callbacks */
        !           226:   static void  PptpCtrlCloseChan(PptpChan ch,
        !           227:                  int result, int error, int cause);
        !           228:   static void  PptpCtrlKillChan(PptpChan ch, const char *errmsg);
        !           229:   static void  PptpCtrlDialResult(void *cookie,
        !           230:                  int result, int error, int cause, int speed);
        !           231: 
        !           232:   /* Internal event handlers */
        !           233:   static pevent_handler_t      PptpCtrlListenEvent;
        !           234:   static pevent_handler_t      PptpCtrlConnEvent;
        !           235:   static pevent_handler_t      PptpCtrlReadCtrl;
        !           236: 
        !           237:   /* Shutdown routines */
        !           238:   static void  PptpCtrlCloseCtrl(PptpCtrl c);
        !           239:   static void  PptpCtrlKillCtrl(PptpCtrl c);
        !           240: 
        !           241:   /* Timer routines */
        !           242:   static void  PptpCtrlResetIdleTimer(PptpCtrl c);
        !           243:   static void  PptpCtrlIdleTimeout(void *arg);
        !           244:   static void  PptpCtrlReplyTimeout(void *arg);
        !           245: 
        !           246:   /* Misc routines */
        !           247:   static void  PptpCtrlInitCtrl(PptpCtrl c, int orig);
        !           248:   static void  PptpCtrlMsg(PptpCtrl c, int type, void *msg);
        !           249:   static void  PptpCtrlWriteMsg(PptpCtrl c, int type, void *msg);
        !           250:   static int   PptpCtrlGetSocket(struct in_addr ip,
        !           251:                  u_int16_t port, char *ebuf, size_t elen);
        !           252: 
        !           253:   static void  PptpCtrlSwap(int type, void *buf);
        !           254:   static void  PptpCtrlDump(int sev, PptpCtrl c, int type, void *msg);
        !           255:   static void  PptpCtrlDumpBuf(int sev, PptpCtrl c,
        !           256:                  const void *data, size_t len, const char *fmt, ...);
        !           257:   static int   PptpCtrlFindField(int type, const char *name, u_int *offset);
        !           258:   static void  PptpCtrlInitCinfo(PptpChan ch, PptpCtrlInfo ci);
        !           259: 
        !           260:   static void  PptpCtrlNewCtrlState(PptpCtrl c, int new);
        !           261:   static void  PptpCtrlNewChanState(PptpChan ch, int new);
        !           262: 
        !           263:   static int   PptpCtrlExtendArray(const char *mtype,
        !           264:                        void *arrayp, int esize, int *alenp);
        !           265: 
        !           266:   static struct pptpctrlinfo
        !           267:                        PptpCtrlOrigCall(struct pptp_engine *pptp, int incmg,
        !           268:                          struct pptplinkinfo linfo, struct in_addr ip,
        !           269:                          u_int16_t port, const char *logname,
        !           270:                          int bearType, int frameType, int minBps, int maxBps,
        !           271:                          const char *callingNum, const char *calledNum,
        !           272:                          const char *subAddress);
        !           273: 
        !           274:   static PptpCtrl      PptpCtrlGetCtrl(struct pptp_engine *pptp,
        !           275:                          int orig, struct in_addr peer_addr,
        !           276:                          u_int16_t peer_port, const char *logname,
        !           277:                          char *buf, int bsiz);
        !           278:   static PptpChan      PptpCtrlGetChan(PptpCtrl c, int chanState, int orig,
        !           279:                          int incoming, int bearType, int frameType, int minBps,
        !           280:                          int maxBps, const char *callingNum,
        !           281:                          const char *calledNum, const char *subAddress);
        !           282:   static PptpChan      PptpCtrlFindChan(PptpCtrl c, int type,
        !           283:                          void *msg, int incoming);
        !           284:   static void          PptpCtrlCheckConn(PptpCtrl c);
        !           285: 
        !           286: /*
        !           287:  * PPTP ENGINE STATE
        !           288:  */
        !           289: 
        !           290:   /* PPTP engine structure */
        !           291:   struct pptp_engine {
        !           292:          int                   listen_sock;    /* listening socket */
        !           293:          struct in_addr        listen_addr;    /* listen ip address */
        !           294:          u_int16_t             listen_port;    /* listen port */
        !           295:          u_char                nocd;           /* no collision detection */
        !           296:          struct pevent_ctx     *ev_ctx;        /* event context */
        !           297:          pthread_mutex_t       *mutex;         /* mutex */
        !           298:          struct pevent         *listen_event;  /* incoming connection event */
        !           299:          PptpCheckNewConn_t    *check_new_conn;/* callback for new connectn. */
        !           300:          PptpGetInLink_t       *get_in_link;   /* callback for incoming call */
        !           301:          PptpGetOutLink_t      *get_out_link;  /* callback for outgoing call */
        !           302:          struct ppp_log        *log;           /* log */
        !           303:          void                  *arg;           /* client arg */
        !           304:          u_int16_t             last_call_id;   /* last used call id */
        !           305:          PptpCtrl              *ctrl;          /* array of control channels */
        !           306:          int                   nctrl;          /* length of ctrl array */
        !           307:          char                  vendor[PPTP_VENDOR_LEN];    /* vendor name */
        !           308:   };
        !           309: 
        !           310: /*
        !           311:  * INTERNAL VARIABLES
        !           312:  */
        !           313: 
        !           314:   /* Control message field layout */
        !           315:   static const struct pptpfield
        !           316:     gPptpMsgLayout[PPTP_MAX_CTRL_TYPE][PPTP_CTRL_MAX_FIELDS] =
        !           317:   {
        !           318: #define _WANT_PPTP_FIELDS
        !           319: #include "ppp/ppp_pptp_ctrl_defs.h"
        !           320:   };
        !           321: 
        !           322:   /* Control channel and call state names */
        !           323:   static const char            *gPptpCtrlStates[] = {
        !           324: #define PPTP_CTRL_ST_FREE              0
        !           325:                    "FREE",
        !           326: #define PPTP_CTRL_ST_IDLE              1
        !           327:                    "IDLE",
        !           328: #define PPTP_CTRL_ST_WAIT_CTL_REPLY    2
        !           329:                    "WAIT_CTL_REPLY",
        !           330: #define PPTP_CTRL_ST_WAIT_STOP_REPLY   3
        !           331:                    "WAIT_STOP_REPLY",
        !           332: #define PPTP_CTRL_ST_ESTABLISHED       4
        !           333:                    "ESTABLISHED",
        !           334:   };
        !           335: 
        !           336:   static const char            *gPptpChanStates[] = {
        !           337: #define PPTP_CHAN_ST_FREE              0
        !           338:                    "FREE",
        !           339: #define PPTP_CHAN_ST_WAIT_IN_REPLY     1
        !           340:                    "WAIT_IN_REPLY",
        !           341: #define PPTP_CHAN_ST_WAIT_OUT_REPLY    2
        !           342:                    "WAIT_OUT_REPLY",
        !           343: #define PPTP_CHAN_ST_WAIT_CONNECT      3
        !           344:                    "WAIT_CONNECT",
        !           345: #define PPTP_CHAN_ST_WAIT_DISCONNECT   4
        !           346:                    "WAIT_DISCONNECT",
        !           347: #define PPTP_CHAN_ST_WAIT_ANSWER       5
        !           348:                    "WAIT_ANSWER",
        !           349: #define PPTP_CHAN_ST_ESTABLISHED       6
        !           350:                    "ESTABLISHED",
        !           351: #define PPTP_CHAN_ST_WAIT_CTRL         7
        !           352:                    "WAIT_CTRL",
        !           353:   };
        !           354: 
        !           355:   /* Control message descriptors */
        !           356: #define CL(s)  (1 << (PPTP_CTRL_ST_ ## s))
        !           357: #define CH(s)  ((1 << (PPTP_CHAN_ST_ ## s)) | 0x8000)
        !           358: 
        !           359:   static const struct pptpmsginfo      gPptpMsgInfo[PPTP_MAX_CTRL_TYPE] = {
        !           360:     { "PptpMsgHead", NULL,                     /* placeholder */
        !           361:       FALSE, sizeof(struct pptpMsgHead),
        !           362:     },
        !           363:     { "StartCtrlConnRequest", (pptpmsghandler_t *)PptpStartCtrlConnRequest,
        !           364:       FALSE, sizeof(struct pptpStartCtrlConnRequest),
        !           365:       CL(IDLE),
        !           366:       { 0, 0 },                                        /* no associated channel */
        !           367:       { PPTP_StartCtrlConnReply, TRUE, PPTP_DFL_REPLY_TIME },
        !           368:     },
        !           369:     { "StartCtrlConnReply", (pptpmsghandler_t *)PptpStartCtrlConnReply,
        !           370:       TRUE, sizeof(struct pptpStartCtrlConnReply),
        !           371:       CL(WAIT_CTL_REPLY),
        !           372:       { 0, 0 },                                        /* no associated channel */
        !           373:       { 0 },                                   /* no reply expected */
        !           374:     },
        !           375:     { "StopCtrlConnRequest", (pptpmsghandler_t *)PptpStopCtrlConnRequest,
        !           376:       FALSE, sizeof(struct pptpStopCtrlConnRequest),
        !           377:       CL(WAIT_CTL_REPLY)|CL(WAIT_STOP_REPLY)|CL(ESTABLISHED),
        !           378:       { 0, 0 },                                        /* no associated channel */
        !           379:       { PPTP_StopCtrlConnReply, TRUE, PPTP_STOPCCR_REPLY_TIME },
        !           380:     },
        !           381:     { "StopCtrlConnReply", (pptpmsghandler_t *)PptpStopCtrlConnReply,
        !           382:       TRUE, sizeof(struct pptpStopCtrlConnReply),
        !           383:       CL(WAIT_STOP_REPLY),
        !           384:       { 0, 0 },                                        /* no associated channel */
        !           385:       { 0 },                                   /* no reply expected */
        !           386:     },
        !           387:     { "EchoRequest", (pptpmsghandler_t *)PptpEchoRequest,
        !           388:       FALSE, sizeof(struct pptpEchoRequest),
        !           389:       CL(ESTABLISHED),
        !           390:       { 0, 0 },                                        /* no associated channel */
        !           391:       { PPTP_EchoReply, TRUE, PPTP_DFL_REPLY_TIME },
        !           392:     },
        !           393:     { "EchoReply", (pptpmsghandler_t *)PptpEchoReply,
        !           394:       TRUE, sizeof(struct pptpEchoReply),
        !           395:       CL(ESTABLISHED),
        !           396:       { 0, 0 },                                        /* no associated channel */
        !           397:       { 0 },                                   /* no reply expected */
        !           398:     },
        !           399:     { "OutCallRequest", (pptpmsghandler_t *)PptpOutCallRequest,
        !           400:       FALSE, sizeof(struct pptpOutCallRequest),
        !           401:       CL(ESTABLISHED),
        !           402:       { 0, PPTP_FIND_CHAN_MY_CID, NULL, "cid" },
        !           403:       { PPTP_OutCallReply, TRUE, PPTP_OUTCALLREQ_REPLY_TIME },
        !           404:     },
        !           405:     { "OutCallReply", (pptpmsghandler_t *)PptpOutCallReply,
        !           406:       TRUE, sizeof(struct pptpOutCallReply),
        !           407:       CH(WAIT_OUT_REPLY),
        !           408:       { PPTP_FIND_CHAN_MY_CID, PPTP_FIND_CHAN_MY_CID, "peerCid", "cid" },
        !           409:       { 0 },                                   /* no reply expected */
        !           410:     },
        !           411:     { "InCallRequest", (pptpmsghandler_t *)PptpInCallRequest,
        !           412:       FALSE, sizeof(struct pptpInCallRequest),
        !           413:       CL(ESTABLISHED),
        !           414:       { 0, PPTP_FIND_CHAN_MY_CID, NULL, "cid" },
        !           415:       { PPTP_InCallReply, FALSE, PPTP_DFL_REPLY_TIME },
        !           416:     },
        !           417:     { "InCallReply", (pptpmsghandler_t *)PptpInCallReply,
        !           418:       TRUE, sizeof(struct pptpInCallReply),
        !           419:       CH(WAIT_IN_REPLY),
        !           420:       { PPTP_FIND_CHAN_MY_CID, PPTP_FIND_CHAN_MY_CID, "peerCid", "cid" },
        !           421:       { PPTP_InCallConn, FALSE, PPTP_INCALLREP_REPLY_TIME },
        !           422:     },
        !           423:     { "InCallConn", (pptpmsghandler_t *)PptpInCallConn,
        !           424:       TRUE, sizeof(struct pptpInCallConn),
        !           425:       CH(WAIT_CONNECT),
        !           426:       { PPTP_FIND_CHAN_MY_CID, PPTP_FIND_CHAN_PEER_CID, "peerCid", "peerCid" },
        !           427:       { 0 },                                   /* no reply expected */
        !           428:     },
        !           429:     { "CallClearRequest", (pptpmsghandler_t *)PptpCallClearRequest,
        !           430:       FALSE, sizeof(struct pptpCallClearRequest),
        !           431:       CH(WAIT_IN_REPLY)|CH(WAIT_ANSWER)|CH(ESTABLISHED),
        !           432:       { PPTP_FIND_CHAN_PNS_CID, PPTP_FIND_CHAN_PNS_CID, "cid", "cid" },
        !           433:       { PPTP_CallDiscNotify, TRUE, PPTP_DFL_REPLY_TIME },
        !           434:     },
        !           435:     { "CallDiscNotify", (pptpmsghandler_t *)PptpCallDiscNotify,
        !           436:       FALSE, sizeof(struct pptpCallDiscNotify),
        !           437:       CH(WAIT_OUT_REPLY)|CH(WAIT_CONNECT)|CH(WAIT_DISCONNECT)|CH(ESTABLISHED),
        !           438:       { PPTP_FIND_CHAN_PAC_CID, PPTP_FIND_CHAN_PAC_CID, "cid", "cid" },
        !           439:       { 0 },                                   /* no reply expected */
        !           440:     },
        !           441:     { "WanErrorNotify", (pptpmsghandler_t *)PptpWanErrorNotify,
        !           442:       FALSE, sizeof(struct pptpWanErrorNotify),
        !           443:       CH(ESTABLISHED),
        !           444:       { PPTP_FIND_CHAN_PNS_CID, PPTP_FIND_CHAN_PNS_CID, "cid", "cid" },
        !           445:       { 0 },                                   /* no reply expected */
        !           446:     },
        !           447:     { "SetLinkInfo", (pptpmsghandler_t *)PptpSetLinkInfo,
        !           448:       FALSE, sizeof(struct pptpSetLinkInfo),
        !           449:       CH(ESTABLISHED),
        !           450:       { PPTP_FIND_CHAN_PAC_CID, PPTP_FIND_CHAN_PAC_CID, "cid", "cid" },
        !           451:       { 0 },                                   /* no reply expected */
        !           452:     },
        !           453:   };
        !           454: 
        !           455: #undef CL
        !           456: #undef CH
        !           457: 
        !           458:   /* Error code to string converters */
        !           459:   #define DECODE(a, n) ((u_int)(n) < (sizeof(a) / sizeof(*(a))) ? \
        !           460:                            (a)[(u_int)(n)] : "[out of range]")
        !           461: 
        !           462:   static const char    *const gPptpErrorCodes[] = {
        !           463:     "none",
        !           464:     "not connected",
        !           465:     "bad format",
        !           466:     "bad value",
        !           467:     "no resource",
        !           468:     "bad call ID",
        !           469:     "pac error",
        !           470:   };
        !           471:   #define PPTP_ERROR_CODE(n)           DECODE(gPptpErrorCodes, (n))
        !           472: 
        !           473:   static const char    *const gPptpSccrReslCodes[] = {
        !           474:     "zero?",
        !           475:     "OK",
        !           476:     "general error",
        !           477:     "channel exists",
        !           478:     "not authorized",
        !           479:     "bad protocol version",
        !           480:   };
        !           481:   #define PPTP_SCCR_RESL_CODE(n)       DECODE(gPptpSccrReslCodes, (n))
        !           482: 
        !           483:   static const char    *const gPptpSccrReasCodes[] = {
        !           484:     "zero?",
        !           485:     "none",
        !           486:     "bad protocol version",
        !           487:     "local shutdown",
        !           488:   };
        !           489:   #define PPTP_SCCR_REAS_CODE(n)       DECODE(gPptpSccrReasCodes, (n))
        !           490: 
        !           491:   static const char    *const gPptpEchoReslCodes[] = {
        !           492:     "zero?",
        !           493:     "OK",
        !           494:     "general error",
        !           495:   };
        !           496:   #define PPTP_ECHO_RESL_CODE(n)       DECODE(gPptpEchoReslCodes, (n))
        !           497: 
        !           498:   static const char    *const gPptpOcrReslCodes[] = {
        !           499:     "zero?",
        !           500:     "OK",
        !           501:     "general error",
        !           502:     "no carrier",
        !           503:     "busy",
        !           504:     "no dialtone",
        !           505:     "timed out",
        !           506:     "admin prohib",
        !           507:   };
        !           508:   #define PPTP_OCR_RESL_CODE(n)                DECODE(gPptpOcrReslCodes, (n))
        !           509: 
        !           510:   static const char    *const gPptpIcrReslCodes[] = {
        !           511:     "zero?",
        !           512:     "OK",
        !           513:     "general error",
        !           514:     "not accepted",
        !           515:   };
        !           516:   #define PPTP_ICR_RESL_CODE(n)                DECODE(gPptpIcrReslCodes, (n))
        !           517: 
        !           518:   static const char    *const gPptpCdnReslCodes[] = {
        !           519:     "zero?",
        !           520:     "lost carrier",
        !           521:     "general error",
        !           522:     "admin action",
        !           523:     "disconnect request",
        !           524:   };
        !           525:   #define PPTP_CDN_RESL_CODE(n)                DECODE(gPptpCdnReslCodes, (n))
        !           526: 
        !           527: /*************************************************************************
        !           528:                        EXPORTED FUNCTIONS
        !           529: *************************************************************************/
        !           530: 
        !           531: /*
        !           532:  * PptpCtrlInit()
        !           533:  *
        !           534:  * Initialize PPTP state and set up callbacks. This must be called
        !           535:  * first, and any calls after the first will ignore the ip parameter.
        !           536:  * Returns 0 if successful, -1 otherwise.
        !           537:  *
        !           538:  * Parameters:
        !           539:  *   arg       Client opaque argument.
        !           540:  *   getInLink Function to call when a peer has requested to establish
        !           541:  *             an incoming call. If returned cookie is NULL, call failed.
        !           542:  *             This pointer may be NULL to deny all incoming calls.
        !           543:  *   getOutLink        Function to call when a peer has requested to establish
        !           544:  *             an outgoming call. If returned cookie is NULL, call failed.
        !           545:  *             This pointer may be NULL to deny all outgoing calls.
        !           546:  *   ip                The IP address for my server to use (cannot be zero).
        !           547:  *   port      The TCP port for my server to use (zero for default).
        !           548:  *   log       The log to use. Note: the log is consumed.
        !           549:  */
        !           550: 
        !           551: struct pptp_engine *
        !           552: PptpCtrlInit(void *arg, struct pevent_ctx *ev_ctx, pthread_mutex_t *mutex,
        !           553:   PptpCheckNewConn_t *checkNewConn, PptpGetInLink_t *getInLink,
        !           554:   PptpGetOutLink_t *getOutLink, struct in_addr ip, u_int16_t port,
        !           555:   const char *vendor, struct ppp_log *log, int nocd)
        !           556: {
        !           557:   struct pptp_engine   *pptp;
        !           558:   int                  type;
        !           559: 
        !           560:   /* Sanity check structure lengths and valid state bits */
        !           561:   for (type = 0; type < PPTP_MAX_CTRL_TYPE; type++) {
        !           562:     PptpField  field = gPptpMsgLayout[type];
        !           563:     int                total;
        !           564: 
        !           565:     assert((gPptpMsgInfo[type].match.inField != NULL)
        !           566:       ^ !(gPptpMsgInfo[type].states & 0x8000));
        !           567:     for (total = 0; field->name; field++)
        !           568:       total += field->length;
        !           569:     assert(total == gPptpMsgInfo[type].length);
        !           570:   }
        !           571: 
        !           572:   /* Create new pptp object */
        !           573:   if ((pptp = MALLOC(PPTP_MTYPE, sizeof(*pptp))) == NULL)
        !           574:     return(NULL);
        !           575:   memset(pptp, 0, sizeof(*pptp));
        !           576:   pptp->ev_ctx = ev_ctx;
        !           577:   pptp->mutex = mutex;
        !           578:   pptp->log = log;
        !           579:   pptp->nocd = nocd;
        !           580:   pptp->arg = arg;
        !           581:   pptp->listen_sock = -1;
        !           582:   pptp->check_new_conn = checkNewConn;
        !           583:   pptp->get_in_link = getInLink;
        !           584:   pptp->get_out_link = getOutLink;
        !           585:   pptp->listen_addr = ip;
        !           586:   pptp->listen_port = port ? port : PPTP_PORT;
        !           587:   if (vendor != NULL)
        !           588:        strlcpy(pptp->vendor, vendor, sizeof(pptp->vendor));
        !           589: #if RANDOMIZE_CID
        !           590:   pptp->last_call_id = time(NULL) ^ (getpid() << 5);
        !           591: #endif
        !           592: 
        !           593:   /* Done */
        !           594:   return(pptp);
        !           595: }
        !           596: 
        !           597: /*
        !           598:  * PptpCtrlShutdown()
        !           599:  *
        !           600:  * Destroy a PPTP engine
        !           601:  */
        !           602: 
        !           603: void
        !           604: PptpCtrlShutdown(struct pptp_engine **enginep)
        !           605: {
        !           606:        struct pptp_engine *const pptp = *enginep;
        !           607:        int i;
        !           608: 
        !           609:        if (pptp == NULL)
        !           610:                return;
        !           611:        *enginep = NULL;
        !           612:        if (pptp->listen_sock != -1)
        !           613:            (void)close(pptp->listen_sock);
        !           614:        for (i = 0; i < pptp->nctrl; i++) {
        !           615:                if (pptp->ctrl[i] == NULL)
        !           616:                        continue;
        !           617:                PptpCtrlKillCtrl(pptp->ctrl[i]);
        !           618:        }
        !           619:        pevent_unregister(&pptp->listen_event);
        !           620:        ppp_log_close(&pptp->log);
        !           621:        FREE(PPTP_MTYPE, pptp->ctrl);
        !           622:        FREE(PPTP_MTYPE, pptp);
        !           623: }
        !           624: 
        !           625: /*
        !           626:  * PptpCtrlListen()
        !           627:  *
        !           628:  * Enable or disable incoming PPTP TCP connections.
        !           629:  * Returns 0 if successful, -1 otherwise.
        !           630:  */
        !           631: 
        !           632: int
        !           633: PptpCtrlListen(struct pptp_engine *pptp, int enable)
        !           634: {
        !           635:   char ebuf[128];
        !           636: 
        !           637:   /* Enable or disable */
        !           638:   if (enable) {
        !           639: 
        !           640:     /* Already enabled? */
        !           641:     if (pptp->listen_sock != -1)
        !           642:       return(0);
        !           643: 
        !           644:     /* We must have a callback for incoming connections */
        !           645:     if (pptp->check_new_conn == NULL) {
        !           646:       errno = ENXIO;
        !           647:       return(-1);
        !           648:     }
        !           649: 
        !           650:     /* Create listening socket */
        !           651:     if ((pptp->listen_sock = PptpCtrlGetSocket(pptp->listen_addr,
        !           652:        pptp->listen_port, ebuf, sizeof(ebuf))) == -1) {
        !           653:       PLOG(LOG_ERR, "pptp: can't get listen socket: %s", ebuf);
        !           654:       return(-1);
        !           655:     }
        !           656: 
        !           657:     /* Listen for connections */
        !           658:     if (listen(pptp->listen_sock, 10) == -1) {
        !           659:        PLOG(LOG_ERR, "pptp: %s: %s", "listen", strerror(errno));
        !           660:        goto sock_fail;
        !           661:     }
        !           662: 
        !           663:     /* Wait for incoming connections */
        !           664:     if (pevent_register(pptp->ev_ctx, &pptp->listen_event, PEVENT_RECURRING,
        !           665:        pptp->mutex, PptpCtrlListenEvent, pptp, PEVENT_READ,
        !           666:        pptp->listen_sock) == -1) {
        !           667:       PLOG(LOG_ERR, "pptp: %s: %s", "pevent_register", strerror(errno));
        !           668: sock_fail:
        !           669:       (void)close(pptp->listen_sock);
        !           670:       pptp->listen_sock = -1;
        !           671:       return(-1);
        !           672:     }
        !           673:   } else {
        !           674: 
        !           675:     /* Already disabled? */
        !           676:     if (pptp->listen_sock == -1)
        !           677:       return(0);
        !           678: 
        !           679:     /* Stop listening */
        !           680:     (void)close(pptp->listen_sock);
        !           681:     pptp->listen_sock = -1;
        !           682:     pevent_unregister(&pptp->listen_event);
        !           683:   }
        !           684: 
        !           685:   /* Done */
        !           686:   return(0);
        !           687: }
        !           688: 
        !           689: /*
        !           690:  * PptpCtrlInCall()
        !           691:  *
        !           692:  * Initiate an incoming call
        !           693:  */
        !           694: 
        !           695: struct pptpctrlinfo
        !           696: PptpCtrlInCall(struct pptp_engine *engine,
        !           697:        struct pptplinkinfo linfo, struct in_addr ip, u_int16_t port,
        !           698:        const char *logname, int bearType, int frameType, int minBps,
        !           699:        int maxBps, const char *callingNum, const char *calledNum,
        !           700:        const char *subAddress)
        !           701: {
        !           702:   return(PptpCtrlOrigCall(engine, TRUE, linfo, ip, port, logname,
        !           703:     bearType, frameType, minBps, maxBps, callingNum, calledNum, subAddress));
        !           704: }
        !           705: 
        !           706: /*
        !           707:  * PptpCtrlOutCall()
        !           708:  *
        !           709:  * Initiate an outgoing call
        !           710:  */
        !           711: 
        !           712: struct pptpctrlinfo
        !           713: PptpCtrlOutCall(struct pptp_engine *engine,
        !           714:        struct pptplinkinfo linfo,
        !           715:        struct in_addr ip, u_int16_t port, const char *logname,
        !           716:        int bearType, int frameType, int minBps, int maxBps,
        !           717:        const char *calledNum, const char *subAddress)
        !           718: {
        !           719:   return(PptpCtrlOrigCall(engine, FALSE, linfo, ip, port, logname,
        !           720:     bearType, frameType, minBps, maxBps, PPTP_STR_INTERNAL_CALLING,
        !           721:     calledNum, subAddress));
        !           722: }
        !           723: 
        !           724: /*
        !           725:  * PptpCtrlOrigCall()
        !           726:  *
        !           727:  * Request from the PPTP peer at ip:port the establishment of an
        !           728:  * incoming or outgoing call (as viewed by the peer). The "result"
        !           729:  * callback will be called when the connection has been established
        !           730:  * or failed to do so. This initiates a TCP control connection if
        !           731:  * needed; otherwise it uses the existing connection. If port is
        !           732:  * zero, then use the normal PPTP port.
        !           733:  */
        !           734: 
        !           735: static struct pptpctrlinfo
        !           736: PptpCtrlOrigCall(struct pptp_engine *pptp, int incoming,
        !           737:        struct pptplinkinfo linfo, struct in_addr ip, u_int16_t port,
        !           738:        const char *logname, int bearType, int frameType, int minBps,
        !           739:        int maxBps, const char *callingNum, const char *calledNum,
        !           740:        const char *subAddress)
        !           741: {
        !           742:   PptpCtrl             c;
        !           743:   PptpChan             ch;
        !           744:   struct pptpctrlinfo  cinfo;
        !           745:   char                 ebuf[100];
        !           746: 
        !           747:   /* Init */
        !           748:   port = port ? port : PPTP_PORT;
        !           749:   memset(&cinfo, 0, sizeof(cinfo));
        !           750: 
        !           751:   /* Sanity check */
        !           752:   if (linfo.result == NULL) {
        !           753:     PLOG(LOG_ERR, "pptp: can't originate call without 'result' callback");
        !           754:     errno = EINVAL;
        !           755:     return(cinfo);
        !           756:   }
        !           757: 
        !           758:   /* Find/create control block */
        !           759:   if ((c = PptpCtrlGetCtrl(pptp, TRUE, ip, port,
        !           760:       logname, ebuf, sizeof(ebuf))) == NULL) {
        !           761:     PLOG(LOG_INFO, "pptp: %s", ebuf);
        !           762:     return(cinfo);
        !           763:   }
        !           764: 
        !           765:   /* Get new channel */
        !           766:   if ((ch = PptpCtrlGetChan(c, PPTP_CHAN_ST_WAIT_CTRL, TRUE, incoming,
        !           767:       bearType, frameType, minBps, maxBps,
        !           768:       callingNum, calledNum, subAddress)) == NULL) {
        !           769:     PptpCtrlKillCtrl(c);
        !           770:     return(cinfo);
        !           771:   }
        !           772:   ch->linfo = linfo;
        !           773: 
        !           774:   /* Control channel may be ready already; start channel if so */
        !           775:   PptpCtrlCheckConn(c);
        !           776: 
        !           777:   /* Return OK */
        !           778:   PptpCtrlInitCinfo(ch, &cinfo);
        !           779:   return(cinfo);
        !           780: }
        !           781: 
        !           782: /*
        !           783:  * PptpCtrlGetSessionInfo()
        !           784:  *
        !           785:  * Returns information associated with a call.
        !           786:  */
        !           787: 
        !           788: int
        !           789: PptpCtrlGetSessionInfo(const struct pptpctrlinfo *cp,
        !           790:        struct in_addr *selfAddr, struct in_addr *peerAddr,
        !           791:        u_int16_t *selfCid, u_int16_t *peerCid,
        !           792:        u_int16_t *peerWin, u_int16_t *peerPpd)
        !           793: {
        !           794:   PptpChan     const ch = (PptpChan)cp->cookie;
        !           795: 
        !           796:   switch (ch->state) {
        !           797:     case PPTP_CHAN_ST_WAIT_IN_REPLY:
        !           798:     case PPTP_CHAN_ST_WAIT_OUT_REPLY:
        !           799:     case PPTP_CHAN_ST_WAIT_CONNECT:
        !           800:     case PPTP_CHAN_ST_WAIT_DISCONNECT:
        !           801:     case PPTP_CHAN_ST_WAIT_ANSWER:
        !           802:     case PPTP_CHAN_ST_ESTABLISHED:
        !           803:     case PPTP_CHAN_ST_WAIT_CTRL:
        !           804:       {
        !           805:        PptpCtrl        const c = ch->ctrl;
        !           806: 
        !           807:        if (selfAddr != NULL)
        !           808:          *selfAddr = c->self_addr;
        !           809:        if (peerAddr != NULL)
        !           810:          *peerAddr = c->peer_addr;
        !           811:        if (selfCid != NULL)
        !           812:          *selfCid = ch->cid;
        !           813:        if (peerCid != NULL)
        !           814:          *peerCid = ch->peerCid;
        !           815:        if (peerWin != NULL)
        !           816:          *peerWin = ch->recvWin;
        !           817:        if (peerPpd != NULL)
        !           818:          *peerPpd = ch->peerPpd;
        !           819:        return(0);
        !           820:      }
        !           821:     case PPTP_CHAN_ST_FREE:
        !           822:       errno = ENXIO;
        !           823:       return(-1);
        !           824:       break;
        !           825:     default:
        !           826:       assert(0);
        !           827:   }
        !           828:   return(-1);  /* NOTREACHED */
        !           829: }
        !           830: 
        !           831: /*************************************************************************
        !           832:                        CONTROL CONNECTION SETUP
        !           833: *************************************************************************/
        !           834: 
        !           835: /*
        !           836:  * PptpCtrlListenEvent()
        !           837:  *
        !           838:  * Someone has connected to our TCP socket on which we were listening.
        !           839:  */
        !           840: 
        !           841: static void
        !           842: PptpCtrlListenEvent(void *cookie)
        !           843: {
        !           844:   struct pptp_engine   *const pptp = cookie;
        !           845:   struct sockaddr_in   peer;
        !           846:   int                  psize = sizeof(peer);
        !           847:   char                 logname[LOGNAME_MAX];
        !           848:   char                 ebuf[100];
        !           849:   PptpCtrl             c;
        !           850:   int                  sock;
        !           851: 
        !           852:   /* Accept connection */
        !           853:   if ((sock = accept(pptp->listen_sock,
        !           854:       (struct sockaddr *)&peer, &psize)) == -1)
        !           855:     return;
        !           856:   (void)fcntl(sock, F_SETFD, 1);
        !           857: 
        !           858:   /* See if accepting connection is ok */
        !           859:   snprintf(logname, sizeof(logname), "%s:%u",
        !           860:     inet_ntoa(peer.sin_addr), ntohs(peer.sin_port));
        !           861:   if ((*pptp->check_new_conn)(pptp->arg, peer.sin_addr,
        !           862:       ntohs(peer.sin_port), logname, sizeof(logname)) != 0) {
        !           863:     PLOG(LOG_INFO, "pptp connection from %s rejected", logname);
        !           864:     (void)close(sock);
        !           865:     return;
        !           866:   }
        !           867: 
        !           868:   /* Initialize a new control block */
        !           869:   PLOG(LOG_INFO, "pptp connection from %s", logname);
        !           870:   if ((c = PptpCtrlGetCtrl(pptp, FALSE, peer.sin_addr,
        !           871:       ntohs(peer.sin_port), logname, ebuf, sizeof(ebuf))) == NULL) {
        !           872:     PLOG(LOG_ERR, "pptp connection failed: %s", ebuf);
        !           873:     (void)close(sock);
        !           874:     return;
        !           875:   }
        !           876:   c->csock = sock;
        !           877: 
        !           878:   /* Initialize the session */
        !           879:   PptpCtrlInitCtrl(c, FALSE);
        !           880: }
        !           881: 
        !           882: /*
        !           883:  * PptpCtrlConnEvent()
        !           884:  *
        !           885:  * We are trying to make a TCP connection to the peer. When this
        !           886:  * either succeeds or fails, we jump to here.
        !           887:  */
        !           888: 
        !           889: static void
        !           890: PptpCtrlConnEvent(void *cookie)
        !           891: {
        !           892:   PptpCtrl             const c = (PptpCtrl) cookie;
        !           893:   struct sockaddr_in   addr;
        !           894:   int                  addrLen = sizeof(addr);
        !           895: 
        !           896:   /* Unregister event */
        !           897:   assert(c->state == PPTP_CTRL_ST_IDLE);
        !           898:   pevent_unregister(&c->connEvent);
        !           899: 
        !           900:   /* Check whether the connection was successful or not */
        !           901:   if (getpeername(c->csock, (struct sockaddr *) &addr, &addrLen) < 0) {
        !           902:     CLOG(LOG_INFO, "connection to peer failed");
        !           903:     PptpCtrlKillCtrl(c);
        !           904:     return;
        !           905:   }
        !           906: 
        !           907:   /* Initialize the session */
        !           908:   CLOG(LOG_INFO, "successfully connected to peer");
        !           909:   PptpCtrlInitCtrl(c, TRUE);
        !           910: }
        !           911: 
        !           912: /*
        !           913:  * PptpCtrlInitCtrl()
        !           914:  *
        !           915:  * A TCP connection has just been established. Initialize the
        !           916:  * control block for this connection and initiate the session.
        !           917:  */
        !           918: 
        !           919: static void
        !           920: PptpCtrlInitCtrl(PptpCtrl c, int orig)
        !           921: {
        !           922:   struct pptp_engine   *const pptp = c->pptp;
        !           923:   struct sockaddr_in   self, peer;
        !           924:   static const int     one = 1;
        !           925:   int                  k, addrLen;
        !           926: 
        !           927:   /* Good time for a sanity check */
        !           928:   assert(c->state == PPTP_CTRL_ST_IDLE);
        !           929:   assert(c->connEvent == NULL);
        !           930:   assert(c->ctrlEvent == NULL);
        !           931:   assert(c->reps == NULL);
        !           932:   for (k = 0; k < c->numChannels; k++) {
        !           933:     assert(c->channels[k] == NULL
        !           934:       || c->channels[k]->state == PPTP_CHAN_ST_WAIT_CTRL);
        !           935:   }
        !           936: 
        !           937:   /* Initialize control state */
        !           938:   c->orig = orig;
        !           939:   c->echoId = 0;
        !           940:   c->flen = 0;
        !           941: 
        !           942:   /* Get local IP address */
        !           943:   addrLen = sizeof(self);
        !           944:   if (getsockname(c->csock, (struct sockaddr *) &self, &addrLen) < 0) {
        !           945:     CLOG(LOG_ERR, "%s: %s", "getsockname", strerror(errno));
        !           946: abort:
        !           947:     PptpCtrlKillCtrl(c);
        !           948:     return;
        !           949:   }
        !           950:   c->self_addr = self.sin_addr;
        !           951:   c->self_port = ntohs(self.sin_port);
        !           952: 
        !           953:   /* Get remote IP address */
        !           954:   addrLen = sizeof(peer);
        !           955:   if (getpeername(c->csock, (struct sockaddr *) &peer, &addrLen) < 0) {
        !           956:     CLOG(LOG_ERR, "%s: %s", "getpeername", strerror(errno));
        !           957:     goto abort;
        !           958:   }
        !           959:   c->peer_addr = peer.sin_addr;
        !           960:   c->peer_port = ntohs(peer.sin_port);
        !           961: 
        !           962:   /* Turn of Nagle algorithm on the TCP socket, since we are going to
        !           963:      be writing complete control frames one at a time */
        !           964:   if (setsockopt(c->csock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0)
        !           965:     CLOG(LOG_ERR, "%s: %s", "setsockopt", strerror(errno));
        !           966: 
        !           967:   /* Register for events on control and data sockets */
        !           968:   if (pevent_register(pptp->ev_ctx, &c->ctrlEvent, PEVENT_RECURRING,
        !           969:       pptp->mutex, PptpCtrlReadCtrl, c, PEVENT_READ, c->csock) == -1) {
        !           970:     CLOG(LOG_ERR, "%s: %s", "pevent_register", strerror(errno));
        !           971:     goto abort;
        !           972:   }
        !           973: 
        !           974:   /* Start echo keep-alive timer */
        !           975:   PptpCtrlResetIdleTimer(c);
        !           976: 
        !           977:   /* If we originated the call, we start the conversation */
        !           978:   if (c->orig) {
        !           979:     struct pptpStartCtrlConnRequest    msg;
        !           980: 
        !           981:     memset(&msg, 0, sizeof(msg));
        !           982:     msg.vers = PPTP_PROTO_VERS;
        !           983:     msg.frameCap = PPTP_FRAMECAP_SYNC;
        !           984:     msg.bearCap = PPTP_BEARCAP_ANY;
        !           985:     msg.firmware = PPTP_FIRMWARE_REV;
        !           986:     gethostname(msg.host, sizeof(msg.host));
        !           987:     strncpy(msg.vendor, pptp->vendor, sizeof(msg.vendor));
        !           988:     PptpCtrlNewCtrlState(c, PPTP_CTRL_ST_WAIT_CTL_REPLY);
        !           989:     PptpCtrlWriteMsg(c, PPTP_StartCtrlConnRequest, &msg);
        !           990:   }
        !           991: }
        !           992: 
        !           993: /*************************************************************************
        !           994:                CONTROL CONNECTION MESSAGE HANDLING
        !           995: *************************************************************************/
        !           996: 
        !           997: /*
        !           998:  * PptpCtrlReadCtrl()
        !           999:  */
        !          1000: 
        !          1001: static void
        !          1002: PptpCtrlReadCtrl(void *cookie)
        !          1003: {
        !          1004:   PptpCtrl     const c = (PptpCtrl) cookie;
        !          1005:   PptpMsgHead  const hdr = (PptpMsgHead) c->frame;
        !          1006:   int          nread;
        !          1007: 
        !          1008:   /* Figure how much to read and read it */
        !          1009:   nread = (c->flen < sizeof(*hdr) ? sizeof(*hdr) : hdr->length) - c->flen;
        !          1010:   if ((nread = read(c->csock, c->frame + c->flen, nread)) <= 0) {
        !          1011:     if (nread < 0)
        !          1012:       CLOG(LOG_ERR, "%s: %s", "read", strerror(errno));
        !          1013:     else
        !          1014:       CLOG(LOG_INFO, "control connection closed by peer");
        !          1015:     goto abort;
        !          1016:   }
        !          1017:   PptpCtrlDumpBuf(LOG_DEBUG + 1, c,
        !          1018:     c->frame + c->flen, nread, "read ctrl data");
        !          1019:   c->flen += nread;
        !          1020: 
        !          1021:   /* Do whatever with what we got */
        !          1022:   if (c->flen < sizeof(*hdr))                  /* incomplete header */
        !          1023:     return;
        !          1024:   if (c->flen == sizeof(*hdr)) {               /* complete header */
        !          1025:     PptpCtrlSwap(0, hdr);              /* byte swap header */
        !          1026:     CLOG(LOG_DEBUG + 1, "rec'd hdr");
        !          1027:     PptpCtrlDump(LOG_DEBUG + 1, c, 0, hdr);
        !          1028:     if (hdr->msgType != PPTP_CTRL_MSG_TYPE) {
        !          1029:       CLOG(LOG_NOTICE, "rec'd invalid msg type %d", hdr->msgType);
        !          1030:       goto abort;
        !          1031:     }
        !          1032:     if (hdr->magic != PPTP_MAGIC) {
        !          1033:       CLOG(LOG_NOTICE, "rec'd invalid magic 0x%08x", hdr->type);
        !          1034:       goto abort;
        !          1035:     }
        !          1036:     if (!PPTP_VALID_CTRL_TYPE(hdr->type)) {
        !          1037:       CLOG(LOG_NOTICE, "rec'd invalid ctrl type %d", hdr->type);
        !          1038:       goto abort;
        !          1039:     }
        !          1040: #if CHECK_RESERVED_FIELDS
        !          1041:     if (hdr->resv0 != 0) {
        !          1042:       CLOG(LOG_NOTICE, "rec'd non-zero reserved field in header");
        !          1043:       goto abort;
        !          1044:     }
        !          1045: #endif
        !          1046:     if (hdr->length != sizeof(*hdr) + gPptpMsgInfo[hdr->type].length) {
        !          1047:       CLOG(LOG_NOTICE, "rec'd invalid length %u for type %s",
        !          1048:        hdr->length, gPptpMsgInfo[hdr->type].name);
        !          1049: abort:
        !          1050:       PptpCtrlKillCtrl(c);
        !          1051:       return;
        !          1052:     }
        !          1053:     return;
        !          1054:   }
        !          1055:   if (c->flen == hdr->length) {                        /* complete message */
        !          1056:     void       *const msg = ((u_char *) hdr) + sizeof(*hdr);
        !          1057: 
        !          1058:     PptpCtrlSwap(hdr->type, msg);              /* byte swap message */
        !          1059:     CLOG(LOG_DEBUG, "recv %s", gPptpMsgInfo[hdr->type].name);
        !          1060:     PptpCtrlDump(LOG_DEBUG, c, hdr->type, msg);
        !          1061:     c->flen = 0;
        !          1062:     PptpCtrlResetIdleTimer(c);
        !          1063:     PptpCtrlMsg(c, hdr->type, msg);
        !          1064:   }
        !          1065: }
        !          1066: 
        !          1067: /*
        !          1068:  * PptpCtrlMsg()
        !          1069:  *
        !          1070:  * We read a complete control message. Sanity check it and handle it.
        !          1071:  */
        !          1072: 
        !          1073: static void
        !          1074: PptpCtrlMsg(PptpCtrl c, int type, void *msg)
        !          1075: {
        !          1076:   PptpMsgInfo          const mi = &gPptpMsgInfo[type];
        !          1077:   PptpChan             ch = NULL;
        !          1078:   PptpPendRep          *pp;
        !          1079: 
        !          1080: #if CHECK_RESERVED_FIELDS
        !          1081:   {
        !          1082:     PptpField          field = gPptpMsgLayout[type];
        !          1083:     u_int              off;
        !          1084:     static u_char      zeros[4];
        !          1085: 
        !          1086:     /* Make sure all reserved fields are zero */
        !          1087:     for (off = 0; field->name; off += field->length, field++) {
        !          1088:       if (!strncmp(field->name, PPTP_RESV_PREF, strlen(PPTP_RESV_PREF))
        !          1089:          && memcmp((u_char *) msg + off, zeros, field->length)) {
        !          1090:        CLOG(LOG_INFO, "rec'd non-zero reserved field %s in %s",
        !          1091:          field->name, mi->name);
        !          1092:        PptpCtrlKillCtrl(c);
        !          1093:        return;
        !          1094:       }
        !          1095:     }
        !          1096:   }
        !          1097: #endif
        !          1098: 
        !          1099:   /* Find channel this message corresponds to (if any) */
        !          1100:   if (mi->match.inField && !(ch = PptpCtrlFindChan(c, type, msg, TRUE)))
        !          1101:     return;
        !          1102: 
        !          1103:   /* See if this message qualifies as the reply to a previously sent message */
        !          1104:   for (pp = &c->reps; *pp; pp = &(*pp)->next) {
        !          1105:     if ((*pp)->request->reqrep.reply == type && (*pp)->chan == ch)
        !          1106:       break;
        !          1107:   }
        !          1108: 
        !          1109:   /* If not, and this message is *always* a reply, ignore it */
        !          1110:   if (*pp == NULL && mi->isReply) {
        !          1111:     CLOG(LOG_NOTICE, "rec'd spurious %s", mi->name);
        !          1112:     return;
        !          1113:   }
        !          1114: 
        !          1115:   /* If so, cancel the matching pending reply */
        !          1116:   if (*pp) {
        !          1117:     PptpPendRep        const prep = *pp;
        !          1118: 
        !          1119:     pevent_unregister(&prep->timer);
        !          1120:     *pp = prep->next;
        !          1121:     FREE(PPTP_PREP_MTYPE, prep);
        !          1122:   }
        !          1123: 
        !          1124:   /* Check for invalid message and call or control state combinations */
        !          1125:   if (!ch && ((1 << c->state) & mi->states) == 0) {
        !          1126:     CLOG(LOG_NOTICE, "rec'd %s in %s state %s (not valid)",
        !          1127:       gPptpMsgInfo[type].name, "control channel", gPptpCtrlStates[c->state]);
        !          1128:     PptpCtrlKillCtrl(c);
        !          1129:     return;
        !          1130:   }
        !          1131:   if (ch && ((1 << ch->state) & mi->states) == 0) {
        !          1132:     CHLOG(LOG_NOTICE, "rec'd %s in %s state %s (not valid)",
        !          1133:       gPptpMsgInfo[type].name, "channel", gPptpChanStates[ch->state]);
        !          1134:     PptpCtrlKillCtrl(c);
        !          1135:     return;
        !          1136:   }
        !          1137: 
        !          1138:   /* Things look OK; process message */
        !          1139:   (*mi->handler)(ch ? (void *) ch : (void *) c, msg);
        !          1140: }
        !          1141: 
        !          1142: /*
        !          1143:  * PptpCtrlWriteMsg()
        !          1144:  *
        !          1145:  * Write out a control message. If we should expect a reply,
        !          1146:  * register a matching pending reply for it.
        !          1147:  */
        !          1148: 
        !          1149: static void
        !          1150: PptpCtrlWriteMsg(PptpCtrl c, int type, void *msg)
        !          1151: {
        !          1152:   struct pptp_engine   *const pptp = c->pptp;
        !          1153:   PptpMsgInfo          const mi = &gPptpMsgInfo[type];
        !          1154:   u_char               buf[PPTP_CTRL_MAX_FRAME];
        !          1155:   PptpMsgHead          const hdr = (PptpMsgHead) buf;
        !          1156:   u_char               *const payload = (u_char *) (hdr + 1);
        !          1157:   const int            totlen = sizeof(*hdr) + gPptpMsgInfo[type].length;
        !          1158:   int                  nwrote;
        !          1159: 
        !          1160:   /* Build message */
        !          1161:   assert(PPTP_VALID_CTRL_TYPE(type));
        !          1162:   memset(hdr, 0, sizeof(*hdr));
        !          1163:   hdr->length = totlen;
        !          1164:   hdr->msgType = PPTP_CTRL_MSG_TYPE;
        !          1165:   hdr->magic = PPTP_MAGIC;
        !          1166:   hdr->type = type;
        !          1167:   memcpy(payload, msg, gPptpMsgInfo[type].length);
        !          1168:   CLOG(LOG_DEBUG, "send %s msg", gPptpMsgInfo[hdr->type].name);
        !          1169:   PptpCtrlDump(LOG_DEBUG, c, 0, hdr);
        !          1170:   PptpCtrlDump(LOG_DEBUG, c, type, msg);
        !          1171: 
        !          1172:   /* Byte swap it */
        !          1173:   PptpCtrlSwap(0, hdr);
        !          1174:   PptpCtrlSwap(type, payload);
        !          1175: 
        !          1176:   /* Send it; if TCP buffer is full, we abort the connection */
        !          1177:   if ((nwrote = write(c->csock, buf, totlen)) != totlen) {
        !          1178:     if (nwrote < 0)
        !          1179:       CLOG(LOG_ERR, "%s: %s", "write", strerror(errno));
        !          1180:     else
        !          1181:       CLOG(LOG_ERR, "only wrote %d/%d", nwrote, totlen);
        !          1182:     goto kill;
        !          1183:   }
        !          1184:   PptpCtrlDumpBuf(LOG_DEBUG + 1, c, buf, totlen, "wrote ctrl data");
        !          1185: 
        !          1186:   /* If we expect a reply to this message, start expecting it now */
        !          1187:   if (PPTP_VALID_CTRL_TYPE(mi->reqrep.reply)) {
        !          1188:     PptpPendRep        prep;
        !          1189: 
        !          1190:     if ((prep = MALLOC(PPTP_PREP_MTYPE, sizeof(*prep))) == NULL) {
        !          1191:       CLOG(LOG_ERR, "%s: %s", "malloc", strerror(errno));
        !          1192:       goto kill;
        !          1193:     }
        !          1194:     memset(prep, 0, sizeof(*prep));
        !          1195:     prep->ctrl = c;
        !          1196:     prep->chan = PptpCtrlFindChan(c, type, msg, FALSE);
        !          1197:     prep->request = mi;
        !          1198:     if (pevent_register(pptp->ev_ctx, &prep->timer, 0,
        !          1199:        pptp->mutex, PptpCtrlReplyTimeout, prep, PEVENT_TIME,
        !          1200:        mi->reqrep.timeout * 1000) == -1) {
        !          1201:       CLOG(LOG_ERR, "%s: %s", "pevent_register", strerror(errno));
        !          1202:       FREE(PPTP_PREP_MTYPE, prep);
        !          1203:       goto kill;
        !          1204:     }
        !          1205:     prep->next = c->reps;
        !          1206:     c->reps = prep;
        !          1207:   }
        !          1208: 
        !          1209:   /* Done */
        !          1210:   return;
        !          1211: 
        !          1212: kill:
        !          1213:   /* There was an error, kill connection (later) */
        !          1214:   pevent_unregister(&c->killEvent);
        !          1215:   if (pevent_register(pptp->ev_ctx, &c->killEvent, 0, pptp->mutex,
        !          1216:       (pevent_handler_t *)PptpCtrlKillCtrl, c, PEVENT_TIME, 0) == -1)
        !          1217:     CLOG(LOG_ERR, "pevent_register: %m");
        !          1218: }
        !          1219: 
        !          1220: /*************************************************************************
        !          1221:                CONTROL AND CHANNEL ALLOCATION FUNCTIONS
        !          1222: *************************************************************************/
        !          1223: 
        !          1224: /*
        !          1225:  * PptpCtrlGetCtrl()
        !          1226:  *
        !          1227:  * Get existing or create new control bock for given peer and return it.
        !          1228:  * Returns NULL if there was some problem, and puts an error message
        !          1229:  * into the buffer.
        !          1230:  *
        !          1231:  * If "orig" is TRUE, and we currently have no TCP connection to the peer,
        !          1232:  * then initiate one. Otherwise, make sure we don't already have one,
        !          1233:  * because that would mean we'd have two connections to the same peer.
        !          1234:  */
        !          1235: 
        !          1236: static PptpCtrl
        !          1237: PptpCtrlGetCtrl(struct pptp_engine *pptp, int orig, struct in_addr peer_addr,
        !          1238:        u_int16_t peer_port, const char *logname, char *buf, int bsiz)
        !          1239: {
        !          1240:   PptpCtrl                     c;
        !          1241:   struct sockaddr_in           peer;
        !          1242:   static const struct in_addr  any = { 0 };
        !          1243:   int                          flags;
        !          1244:   int                          k;
        !          1245: 
        !          1246:   /* See if we're already have a control block matching this address and port */
        !          1247:   for (k = 0; k < pptp->nctrl; k++) {
        !          1248:     PptpCtrl   const c = pptp->ctrl[k];
        !          1249: 
        !          1250:     if (c != NULL
        !          1251:        && c->peer_addr.s_addr == peer_addr.s_addr
        !          1252:        && c->peer_port == peer_port) {
        !          1253:       if (orig)
        !          1254:        return(c);
        !          1255:       snprintf(buf, bsiz, "connection to %s already exists", logname);
        !          1256:       return(NULL);
        !          1257:     }
        !          1258:   }
        !          1259: 
        !          1260:   /* Find/create a free one */
        !          1261:   for (k = 0; k < pptp->nctrl && pptp->ctrl[k] != NULL; k++);
        !          1262:   if (k == pptp->nctrl) {
        !          1263:     if (PptpCtrlExtendArray(PPTP_MTYPE, &pptp->ctrl,
        !          1264:        sizeof(*pptp->ctrl), &pptp->nctrl) == -1) {
        !          1265:       snprintf(buf, bsiz, "%s: %s", "malloc", strerror(errno));
        !          1266:       return(NULL);
        !          1267:     }
        !          1268:   }
        !          1269:   if ((c = MALLOC(PPTP_CTRL_MTYPE, sizeof(*c))) == NULL) {
        !          1270:     snprintf(buf, bsiz, "%s: %s", "malloc", strerror(errno));
        !          1271:     return(NULL);
        !          1272:   }
        !          1273:   memset(c, 0, sizeof(*c));
        !          1274:   pptp->ctrl[k] = c;
        !          1275: 
        !          1276:   /* Initialize it */
        !          1277:   c->id = k;
        !          1278:   c->pptp = pptp;
        !          1279:   c->orig = orig;
        !          1280:   c->csock = -1;
        !          1281:   c->peer_addr = peer_addr;
        !          1282:   c->peer_port = peer_port;
        !          1283:   strlcpy(c->logname, logname, sizeof(c->logname));
        !          1284:   if ((c->log = ppp_log_prefix(pptp->log, "%s: ", c->logname)) == NULL) {
        !          1285:     snprintf(buf, bsiz, "%s: %s", "ppp_log_prefix", strerror(errno));
        !          1286:     pptp->ctrl[k] = NULL;
        !          1287:     FREE(PPTP_CTRL_MTYPE, c);
        !          1288:     return(NULL);
        !          1289:   }
        !          1290: 
        !          1291:   /* Go to the idle state */
        !          1292:   PptpCtrlNewCtrlState(c, PPTP_CTRL_ST_IDLE);
        !          1293: 
        !          1294:   /* If not doing the connecting, return here */
        !          1295:   if (!c->orig)
        !          1296:     return(c);
        !          1297: 
        !          1298:   /* Get socket */
        !          1299:   if ((c->csock = PptpCtrlGetSocket(any, 0, buf, bsiz)) < 0) {
        !          1300:     PptpCtrlNewCtrlState(c, PPTP_CTRL_ST_FREE);
        !          1301:     return(NULL);
        !          1302:   }
        !          1303: 
        !          1304:   /* Put socket in non-blocking mode */
        !          1305:   if (fcntl(c->csock, F_GETFL, &flags) == -1
        !          1306:       || fcntl(c->csock, F_SETFL, flags | O_NONBLOCK) == -1) {
        !          1307:     snprintf(buf, bsiz, "pptp: connect to %s failed: %s: %s",
        !          1308:       logname, "fcntl", strerror(errno));
        !          1309:     PptpCtrlNewCtrlState(c, PPTP_CTRL_ST_FREE);
        !          1310:     return(NULL);
        !          1311:   }
        !          1312: 
        !          1313:   /* Initiate connection to peer */
        !          1314:   memset(&peer, 0, sizeof(peer));
        !          1315:   peer.sin_family = AF_INET;
        !          1316:   peer.sin_addr = c->peer_addr;
        !          1317:   peer.sin_port = htons(c->peer_port);
        !          1318:   if (connect(c->csock, (struct sockaddr *) &peer, sizeof(peer)) < 0
        !          1319:       && errno != EINPROGRESS) {
        !          1320:     (void) close(c->csock);
        !          1321:     c->csock = -1;
        !          1322:     snprintf(buf, bsiz, "pptp: connect to %s failed: %s",
        !          1323:       logname, strerror(errno));
        !          1324:     PptpCtrlNewCtrlState(c, PPTP_CTRL_ST_FREE);
        !          1325:     return(NULL);
        !          1326:   }
        !          1327: 
        !          1328:   /* Put socket back in blocking mode */
        !          1329:   if (fcntl(c->csock, F_SETFL, flags) == -1) {
        !          1330:     (void) close(c->csock);
        !          1331:     c->csock = -1;
        !          1332:     snprintf(buf, bsiz, "pptp: connect to %s failed: %s: %s",
        !          1333:       logname, "fcntl", strerror(errno));
        !          1334:     PptpCtrlNewCtrlState(c, PPTP_CTRL_ST_FREE);
        !          1335:     return(NULL);
        !          1336:   }
        !          1337: 
        !          1338:   /* Wait for it to go through */
        !          1339:   if (pevent_register(pptp->ev_ctx, &c->connEvent, PEVENT_RECURRING,
        !          1340:       pptp->mutex, PptpCtrlConnEvent, c, PEVENT_READ, c->csock) == -1) {
        !          1341:     CLOG(LOG_ERR, "%s: %s", "pevent_register", strerror(errno));
        !          1342:     PptpCtrlNewCtrlState(c, PPTP_CTRL_ST_FREE);
        !          1343:     return(NULL);
        !          1344:   }
        !          1345: 
        !          1346:   /* Done */
        !          1347:   CLOG(LOG_INFO, "intiating connection to peer");
        !          1348:   return(c);
        !          1349: }
        !          1350: 
        !          1351: /*
        !          1352:  * PptpCtrlGetChan()
        !          1353:  *
        !          1354:  * Find a free data channel and attach it to the control channel.
        !          1355:  */
        !          1356: 
        !          1357: static PptpChan
        !          1358: PptpCtrlGetChan(PptpCtrl c, int chanState, int orig, int incoming,
        !          1359:        int bearType, int frameType, int minBps, int maxBps,
        !          1360:        const char *callingNum, const char *calledNum, const char *subAddress)
        !          1361: {
        !          1362:   struct pptp_engine   *const pptp = c->pptp;
        !          1363:   PptpChan             ch;
        !          1364:   int                  k;
        !          1365: 
        !          1366:   /* Get a free data channel */
        !          1367:   for (k = 0; k < c->numChannels && c->channels[k] != NULL; k++);
        !          1368:   if (k == c->numChannels) {
        !          1369:     if (PptpCtrlExtendArray(PPTP_CTRL_MTYPE, &c->channels,
        !          1370:        sizeof(*c->channels), &c->numChannels) == -1) {
        !          1371:       CLOG(LOG_ERR, "%s: %s", "malloc", strerror(errno));
        !          1372:       return(NULL);
        !          1373:     }
        !          1374:   }
        !          1375:   if ((ch = MALLOC(PPTP_CHAN_MTYPE, sizeof(*ch))) == NULL) {
        !          1376:     CLOG(LOG_ERR, "%s: %s", "malloc", strerror(errno));
        !          1377:     return(NULL);
        !          1378:   }
        !          1379:   memset(ch, 0, sizeof(*ch));
        !          1380:   c->channels[k] = ch;
        !          1381:   ch->id = k;
        !          1382:   ch->cid = ++pptp->last_call_id;
        !          1383:   ch->ctrl = c;
        !          1384:   ch->orig = orig;
        !          1385:   ch->incoming = incoming;
        !          1386:   ch->minBps = minBps;
        !          1387:   ch->maxBps = maxBps;
        !          1388:   ch->bearType = bearType;
        !          1389:   ch->frameType = frameType;
        !          1390:   snprintf(ch->calledNum, sizeof(ch->calledNum), "%s", calledNum);
        !          1391:   snprintf(ch->callingNum, sizeof(ch->callingNum), "%s", callingNum);
        !          1392:   snprintf(ch->subAddress, sizeof(ch->subAddress), "%s", subAddress);
        !          1393: 
        !          1394:   /* Get log for this channel */
        !          1395:   if ((ch->log = ppp_log_prefix(pptp->log,
        !          1396:       "%s[%d]: ", c->logname, ch->id)) == NULL) {
        !          1397:     CLOG(LOG_ERR, "%s: %s", "ppp_log_prefix", strerror(errno));
        !          1398:     pptp->last_call_id--;
        !          1399:     c->channels[k] = NULL;
        !          1400:     FREE(PPTP_CHAN_MTYPE, ch);
        !          1401:     return(NULL);
        !          1402:   }
        !          1403: 
        !          1404:   /* Go to starting state */
        !          1405:   PptpCtrlNewChanState(ch, chanState);
        !          1406:   return(ch);
        !          1407: }
        !          1408: 
        !          1409: /*
        !          1410:  * PptpCtrlDialResult()
        !          1411:  *
        !          1412:  * Link layer calls this to let us know whether an outgoing call
        !          1413:  * has been successfully completed or has failed.
        !          1414:  */
        !          1415: 
        !          1416: static void
        !          1417: PptpCtrlDialResult(void *cookie, int result, int error, int cause, int speed)
        !          1418: {
        !          1419:   PptpChan                     const ch = (PptpChan) cookie;
        !          1420:   PptpCtrl                     const c = ch->ctrl;
        !          1421:   struct pptpOutCallReply      rep;
        !          1422: 
        !          1423:   memset(&rep, 0, sizeof(rep));
        !          1424:   rep.cid = ch->cid;
        !          1425:   rep.peerCid = ch->peerCid;
        !          1426:   rep.result = result;
        !          1427:   if (rep.result == PPTP_OCR_RESL_ERR)
        !          1428:     rep.err = error;
        !          1429:   rep.cause = cause;
        !          1430:   rep.speed = speed;
        !          1431:   rep.ppd = PPTP_PPD;          /* XXX should get this value from link layer */
        !          1432:   rep.recvWin = PPTP_RECV_WIN; /* XXX */
        !          1433:   rep.channel = PHYS_CHAN(ch);
        !          1434:   PptpCtrlWriteMsg(c, PPTP_OutCallReply, &rep);
        !          1435:   if (rep.result == PPTP_OCR_RESL_OK)
        !          1436:     PptpCtrlNewChanState(ch, PPTP_CHAN_ST_ESTABLISHED);
        !          1437:   else
        !          1438:     PptpCtrlKillChan(ch, "local outgoing call failed");
        !          1439: }
        !          1440: 
        !          1441: /*************************************************************************
        !          1442:                    SHUTDOWN FUNCTIONS
        !          1443: *************************************************************************/
        !          1444: 
        !          1445: /*
        !          1446:  * PptpCtrlCloseCtrl()
        !          1447:  */
        !          1448: 
        !          1449: static void
        !          1450: PptpCtrlCloseCtrl(PptpCtrl c)
        !          1451: {
        !          1452:   CLOG(LOG_INFO, "closing PPTP control connection");
        !          1453:   switch (c->state) {
        !          1454:     case PPTP_CTRL_ST_IDLE:
        !          1455:     case PPTP_CTRL_ST_WAIT_STOP_REPLY:
        !          1456:     case PPTP_CTRL_ST_WAIT_CTL_REPLY:
        !          1457:       PptpCtrlKillCtrl(c);
        !          1458:       return;
        !          1459:     case PPTP_CTRL_ST_ESTABLISHED:
        !          1460:       {
        !          1461:        struct pptpStopCtrlConnRequest  req;
        !          1462: 
        !          1463:        memset(&req, 0, sizeof(req));
        !          1464:        req.reason = PPTP_SCCR_REAS_LOCAL;
        !          1465:        PptpCtrlNewCtrlState(c, PPTP_CTRL_ST_WAIT_STOP_REPLY);
        !          1466:        PptpCtrlWriteMsg(c, PPTP_StopCtrlConnRequest, &req);
        !          1467:        return;
        !          1468:       }
        !          1469:       break;
        !          1470:     default:
        !          1471:       assert(0);
        !          1472:   }
        !          1473: }
        !          1474: 
        !          1475: /*
        !          1476:  * PptpCtrlKillCtrl()
        !          1477:  */
        !          1478: 
        !          1479: static void
        !          1480: PptpCtrlKillCtrl(PptpCtrl c)
        !          1481: {
        !          1482:   PptpPendRep          prep, next;
        !          1483:   int                  k;
        !          1484: 
        !          1485:   /* Cancel kill event */
        !          1486:   pevent_unregister(&c->killEvent);
        !          1487: 
        !          1488:   /* Don't recurse */
        !          1489:   assert(c);
        !          1490:   if (c->killing || c->state == PPTP_CTRL_ST_FREE)
        !          1491:     return;
        !          1492:   c->killing = 1;
        !          1493: 
        !          1494:   /* Do ungraceful shutdown */
        !          1495:   CLOG(LOG_DEBUG, "killing control connection");
        !          1496:   for (k = 0; k < c->numChannels; k++) {
        !          1497:     PptpChan   const ch = c->channels[k];
        !          1498: 
        !          1499:     if (ch != NULL)
        !          1500:       PptpCtrlKillChan(ch, "control channel shutdown");
        !          1501:   }
        !          1502:   if (c->csock >= 0) {
        !          1503:     close(c->csock);
        !          1504:     c->csock = -1;
        !          1505:   }
        !          1506:   pevent_unregister(&c->connEvent);
        !          1507:   pevent_unregister(&c->ctrlEvent);
        !          1508:   pevent_unregister(&c->idleTimer);
        !          1509:   for (prep = c->reps; prep; prep = next) {
        !          1510:     next = prep->next;
        !          1511:     pevent_unregister(&prep->timer);
        !          1512:     FREE(PPTP_PREP_MTYPE, prep);
        !          1513:   }
        !          1514:   c->reps = NULL;
        !          1515:   PptpCtrlNewCtrlState(c, PPTP_CTRL_ST_FREE);
        !          1516: }
        !          1517: 
        !          1518: /*
        !          1519:  * PptpCtrlCloseChan()
        !          1520:  *
        !          1521:  * Gracefully clear a call.
        !          1522:  */
        !          1523: 
        !          1524: static void
        !          1525: PptpCtrlCloseChan(PptpChan ch, int result, int error, int cause)
        !          1526: {
        !          1527:   PptpCtrl     const c = ch->ctrl;
        !          1528: 
        !          1529:   /* Don't recurse */
        !          1530:   if (ch->killing)
        !          1531:     return;
        !          1532: 
        !          1533:   /* Check call state */
        !          1534:   switch (ch->state) {
        !          1535:     case PPTP_CHAN_ST_ESTABLISHED:
        !          1536:       if (PPTP_CHAN_IS_PNS(ch))
        !          1537:        goto pnsClear;
        !          1538:       else
        !          1539:        goto pacClear;
        !          1540:       break;
        !          1541:     case PPTP_CHAN_ST_WAIT_ANSWER:
        !          1542:       {
        !          1543:        struct pptpOutCallReply reply;
        !          1544: 
        !          1545:        memset(&reply, 0, sizeof(reply));
        !          1546:        reply.peerCid = ch->peerCid;
        !          1547:        reply.result = PPTP_OCR_RESL_ADMIN;
        !          1548:        PptpCtrlWriteMsg(c, PPTP_OutCallReply, &reply);
        !          1549:        PptpCtrlKillChan(ch, "link layer shutdown");    /* XXX errmsg */
        !          1550:        return;
        !          1551:       }
        !          1552:       break;
        !          1553:     case PPTP_CHAN_ST_WAIT_IN_REPLY:           /* we are the PAC */
        !          1554: pacClear:
        !          1555:       {
        !          1556:        struct pptpCallDiscNotify       disc;
        !          1557: 
        !          1558:        CHLOG(LOG_INFO, "clearing call");
        !          1559:        memset(&disc, 0, sizeof(disc));
        !          1560:        disc.cid = ch->cid;
        !          1561:        disc.result = result;
        !          1562:        if (disc.result == PPTP_CDN_RESL_ERR)
        !          1563:          disc.err = error;
        !          1564:        disc.cause = cause;
        !          1565:        /* XXX stats? */
        !          1566:        PptpCtrlWriteMsg(c, PPTP_CallDiscNotify, &disc);
        !          1567:        PptpCtrlKillChan(ch, "link layer shutdown");    /* XXX errmsg */
        !          1568:       }
        !          1569:       break;
        !          1570:     case PPTP_CHAN_ST_WAIT_OUT_REPLY:          /* we are the PNS */
        !          1571:     case PPTP_CHAN_ST_WAIT_CONNECT:            /* we are the PNS */
        !          1572: pnsClear:
        !          1573:       {
        !          1574:        struct pptpCallClearRequest     req;
        !          1575: 
        !          1576:        CHLOG(LOG_INFO, "clearing call");
        !          1577:        memset(&req, 0, sizeof(req));
        !          1578:        req.cid = ch->cid;
        !          1579:        PptpCtrlNewChanState(ch, PPTP_CHAN_ST_WAIT_DISCONNECT);
        !          1580:        PptpCtrlWriteMsg(c, PPTP_CallClearRequest, &req);
        !          1581:       }
        !          1582:       break;
        !          1583:     case PPTP_CHAN_ST_WAIT_DISCONNECT:         /* call was already cleared */
        !          1584:       return;
        !          1585:     case PPTP_CHAN_ST_WAIT_CTRL:
        !          1586:       PptpCtrlKillChan(ch, "link layer shutdown");
        !          1587:       return;
        !          1588:     default:
        !          1589:       assert(0);
        !          1590:   }
        !          1591: }
        !          1592: 
        !          1593: /*
        !          1594:  * PptpCtrlKillChan()
        !          1595:  */
        !          1596: 
        !          1597: static void
        !          1598: PptpCtrlKillChan(PptpChan ch, const char *errmsg)
        !          1599: {
        !          1600:   PptpCtrl             const c = ch->ctrl;
        !          1601:   PptpPendRep          *pp;
        !          1602:   int                  k;
        !          1603: 
        !          1604:   /* Don't recurse */
        !          1605:   assert(ch);
        !          1606:   if (ch->killing)             /* should never happen anyway */
        !          1607:     return;
        !          1608:   ch->killing = 1;
        !          1609: 
        !          1610:   /* If link layer needs notification, tell it */
        !          1611:   CHLOG(LOG_DEBUG, "killing channel");
        !          1612:   switch (ch->state) {
        !          1613:     case PPTP_CHAN_ST_WAIT_IN_REPLY:
        !          1614:     case PPTP_CHAN_ST_WAIT_OUT_REPLY:
        !          1615:     case PPTP_CHAN_ST_WAIT_CONNECT:
        !          1616:     case PPTP_CHAN_ST_ESTABLISHED:
        !          1617:     case PPTP_CHAN_ST_WAIT_CTRL:
        !          1618:       (*ch->linfo.result)(ch->linfo.cookie, errmsg);
        !          1619:       break;
        !          1620:     case PPTP_CHAN_ST_WAIT_DISCONNECT:
        !          1621:       break;
        !          1622:     case PPTP_CHAN_ST_WAIT_ANSWER:
        !          1623:       (*ch->linfo.cancel)(ch->linfo.cookie);
        !          1624:       break;
        !          1625:     default:
        !          1626:       assert(0);
        !          1627:   }
        !          1628: 
        !          1629:   /* Nuke any pending replies pertaining to this channel */
        !          1630:   for (pp = &c->reps; *pp; ) {
        !          1631:     PptpPendRep        const prep = *pp;
        !          1632: 
        !          1633:     if (prep->chan == ch) {
        !          1634:       pevent_unregister(&prep->timer);
        !          1635:       *pp = prep->next;
        !          1636:       FREE(PPTP_PREP_MTYPE, prep);
        !          1637:     } else
        !          1638:       pp = &prep->next;
        !          1639:   }
        !          1640: 
        !          1641:   /* Free channel */
        !          1642:   PptpCtrlNewChanState(ch, PPTP_CHAN_ST_FREE);
        !          1643: 
        !          1644:   /* When the last channel is closed, close the control channel too,
        !          1645:      unless we're already in the process of killing it. */
        !          1646:   for (k = 0; k < c->numChannels; k++) {
        !          1647:     PptpChan   const ch2 = c->channels[k];
        !          1648: 
        !          1649:     if (ch2 != NULL && ch2->ctrl == c)
        !          1650:       break;
        !          1651:   }
        !          1652:   if (k == c->numChannels
        !          1653:       && c->state == PPTP_CTRL_ST_ESTABLISHED
        !          1654:       && !c->killing)
        !          1655:     PptpCtrlCloseCtrl(c);
        !          1656: }
        !          1657: 
        !          1658: /*************************************************************************
        !          1659:                    TIMER RELATED FUNCTIONS
        !          1660: *************************************************************************/
        !          1661: 
        !          1662: /*
        !          1663:  * PptpCtrlReplyTimeout()
        !          1664:  */
        !          1665: 
        !          1666: static void
        !          1667: PptpCtrlReplyTimeout(void *arg)
        !          1668: {
        !          1669:   PptpPendRep          const prep = (PptpPendRep) arg;
        !          1670:   PptpPendRep          *pp;
        !          1671:   PptpChan             const ch = prep->chan;
        !          1672:   PptpCtrl             const c = prep->ctrl;
        !          1673: 
        !          1674:   /* Cancel timer event */
        !          1675:   pevent_unregister(&prep->timer);
        !          1676: 
        !          1677:   /* Log it */
        !          1678:   if (ch) {
        !          1679:     CHLOG(LOG_NOTICE, "no reply to %s after %d sec",
        !          1680:       prep->request->name, prep->request->reqrep.timeout);
        !          1681:   } else if (prep->request - gPptpMsgInfo != PPTP_StopCtrlConnRequest) {
        !          1682:     CLOG(LOG_NOTICE, "no reply to %s after %d sec",
        !          1683:       prep->request->name, prep->request->reqrep.timeout);
        !          1684:   }
        !          1685: 
        !          1686:   /* Unlink pending reply */
        !          1687:   for (pp = &c->reps; *pp != prep; pp = &(*pp)->next);
        !          1688:   assert(*pp);
        !          1689:   *pp = prep->next;
        !          1690: 
        !          1691:   /* Either close this channel or kill entire control connection */
        !          1692:   if (prep->request->reqrep.killCtrl)
        !          1693:     PptpCtrlKillCtrl(c);
        !          1694:   else
        !          1695:     PptpCtrlCloseChan(ch, PPTP_CDN_RESL_ERR, PPTP_ERROR_PAC_ERROR, 0);
        !          1696: 
        !          1697:   /* Done */
        !          1698:   FREE(PPTP_PREP_MTYPE, prep);
        !          1699: }
        !          1700: 
        !          1701: /*
        !          1702:  * PptpCtrlIdleTimeout()
        !          1703:  *
        !          1704:  * We've heard PPTP_IDLE_TIMEOUT seconds of silence from the peer.
        !          1705:  * Send an echo request to make sure it's alive.
        !          1706:  */
        !          1707: 
        !          1708: static void
        !          1709: PptpCtrlIdleTimeout(void *arg)
        !          1710: {
        !          1711:   PptpCtrl                     const c = (PptpCtrl) arg;
        !          1712:   struct pptpEchoRequest       msg;
        !          1713:   int                          k;
        !          1714: 
        !          1715:   /* Cancel timer event */
        !          1716:   pevent_unregister(&c->idleTimer);
        !          1717: 
        !          1718:   /* If no channels are left on this control connection, shut it down */
        !          1719:   for (k = 0; k < c->numChannels && c->channels[k] == NULL; k++);
        !          1720:   if (k == c->numChannels) {
        !          1721:     PptpCtrlCloseCtrl(c);
        !          1722:     return;
        !          1723:   }
        !          1724: 
        !          1725:   /* Send echo request */
        !          1726:   memset(&msg, 0, sizeof(msg));
        !          1727:   msg.id = ++c->echoId;
        !          1728:   PptpCtrlWriteMsg(c, PPTP_EchoRequest, &msg);
        !          1729: }
        !          1730: 
        !          1731: /*
        !          1732:  * PptpCtrlResetIdleTimer()
        !          1733:  *
        !          1734:  * Reset the idle timer back up to PPTP_IDLE_TIMEOUT seconds.
        !          1735:  */
        !          1736: 
        !          1737: static void
        !          1738: PptpCtrlResetIdleTimer(PptpCtrl c)
        !          1739: {
        !          1740:   struct pptp_engine   *const pptp = c->pptp;
        !          1741: 
        !          1742:   pevent_unregister(&c->idleTimer);
        !          1743:   if (pevent_register(pptp->ev_ctx, &c->idleTimer, 0, pptp->mutex,
        !          1744:       PptpCtrlIdleTimeout, c, PEVENT_TIME, PPTP_IDLE_TIMEOUT * 1000) == -1)
        !          1745:     CLOG(LOG_ERR, "%s: %s", "pevent_register", strerror(errno));
        !          1746: }
        !          1747: 
        !          1748: 
        !          1749: /*************************************************************************
        !          1750:                    CHANNEL MAINTENANCE FUNCTIONS
        !          1751: *************************************************************************/
        !          1752: 
        !          1753: /*
        !          1754:  * PptpCtrlCheckConn()
        !          1755:  *
        !          1756:  * Check whether we have any pending connection requests, and whether
        !          1757:  * we can send them yet, or what.
        !          1758:  */
        !          1759: 
        !          1760: static void
        !          1761: PptpCtrlCheckConn(PptpCtrl c)
        !          1762: {
        !          1763:   int  k;
        !          1764: 
        !          1765:   switch (c->state) {
        !          1766:     case PPTP_CTRL_ST_IDLE:
        !          1767:     case PPTP_CTRL_ST_WAIT_CTL_REPLY:
        !          1768:     case PPTP_CTRL_ST_WAIT_STOP_REPLY:
        !          1769:       break;
        !          1770:     case PPTP_CTRL_ST_ESTABLISHED:
        !          1771:       for (k = 0; k < c->numChannels; k++) {
        !          1772:        PptpChan        const ch = c->channels[k];
        !          1773: 
        !          1774:        if (ch == NULL || ch->state != PPTP_CHAN_ST_WAIT_CTRL)
        !          1775:          continue;
        !          1776:        if (ch->incoming) {
        !          1777:          struct pptpInCallRequest      req;
        !          1778: 
        !          1779:          memset(&req, 0, sizeof(req));
        !          1780:          req.cid = ch->cid;
        !          1781:          req.serno = req.cid;
        !          1782:          req.bearType = PPTP_BEARCAP_DIGITAL;
        !          1783:          req.channel = PHYS_CHAN(ch);
        !          1784:          PptpCtrlNewChanState(ch, PPTP_CHAN_ST_WAIT_IN_REPLY);
        !          1785:          PptpCtrlWriteMsg(c, PPTP_InCallRequest, &req);
        !          1786:        } else {
        !          1787:          struct pptpOutCallRequest     req;
        !          1788: 
        !          1789:          memset(&req, 0, sizeof(req));
        !          1790:          req.cid = ch->cid;
        !          1791:          req.serno = req.cid;
        !          1792:          req.minBps = ch->minBps;
        !          1793:          req.maxBps = ch->maxBps;
        !          1794:          req.bearType = ch->bearType;
        !          1795:          req.frameType = ch->frameType;
        !          1796:          req.recvWin = PPTP_RECV_WIN;          /* XXX */
        !          1797:          req.ppd = PPTP_PPD;                   /* XXX */
        !          1798:          req.numLen = strlen(ch->calledNum);
        !          1799:          strncpy(req.phone, ch->calledNum, sizeof(req.phone));
        !          1800:          strncpy(req.subaddr, ch->subAddress, sizeof(req.subaddr));
        !          1801:          PptpCtrlNewChanState(ch, PPTP_CHAN_ST_WAIT_OUT_REPLY);
        !          1802:          PptpCtrlWriteMsg(c, PPTP_OutCallRequest, &req);
        !          1803:        }
        !          1804:        return;
        !          1805:       }
        !          1806:       break;
        !          1807:     default:
        !          1808:       assert(0);
        !          1809:   }
        !          1810: }
        !          1811: 
        !          1812: /*
        !          1813:  * PptpCtrlFindChan()
        !          1814:  *
        !          1815:  * Find the channel identified by this message. Returns NULL if
        !          1816:  * the message is not channel specific, or the channel was not found.
        !          1817:  */
        !          1818: 
        !          1819: static PptpChan
        !          1820: PptpCtrlFindChan(PptpCtrl c, int type, void *msg, int incoming)
        !          1821: {
        !          1822:   PptpMsgInfo  const mi = &gPptpMsgInfo[type];
        !          1823:   const char   *fname = incoming ? mi->match.inField : mi->match.outField;
        !          1824:   const int    how = incoming ? mi->match.findIn : mi->match.findOut;
        !          1825:   u_int16_t    cid;
        !          1826:   int          k, off;
        !          1827: 
        !          1828:   /* Get the identifying CID field */
        !          1829:   if (!fname)
        !          1830:     return(NULL);
        !          1831:   (void) PptpCtrlFindField(type, fname, &off);         /* we know len == 2 */
        !          1832:   cid = *((u_int16_t *) ((u_char *) msg + off));
        !          1833: 
        !          1834:   /* Match the CID against our list of active channels */
        !          1835:   for (k = 0; k < c->numChannels; k++) {
        !          1836:     PptpChan   const ch = c->channels[k];
        !          1837:     u_int16_t  tryCid = 0;
        !          1838: 
        !          1839:     if (ch == NULL)
        !          1840:       continue;
        !          1841:     switch (how) {
        !          1842:       case PPTP_FIND_CHAN_MY_CID:
        !          1843:        tryCid = ch->cid;
        !          1844:        break;
        !          1845:       case PPTP_FIND_CHAN_PEER_CID:
        !          1846:        tryCid = ch->peerCid;
        !          1847:        break;
        !          1848:       case PPTP_FIND_CHAN_PNS_CID:
        !          1849:        tryCid = PPTP_CHAN_IS_PNS(ch) ? ch->cid : ch->peerCid;
        !          1850:        break;
        !          1851:       case PPTP_FIND_CHAN_PAC_CID:
        !          1852:        tryCid = !PPTP_CHAN_IS_PNS(ch) ? ch->cid : ch->peerCid;
        !          1853:        break;
        !          1854:       default:
        !          1855:        assert(0);
        !          1856:     }
        !          1857:     if (cid == tryCid)
        !          1858:       return(ch);
        !          1859:   }
        !          1860: 
        !          1861:   /* Not found */
        !          1862:   CLOG(LOG_INFO, "CID 0x%04x in %s not found", cid, mi->name);
        !          1863:   return(NULL);
        !          1864: }
        !          1865: 
        !          1866: /*************************************************************************
        !          1867:                          MISC FUNCTIONS
        !          1868: *************************************************************************/
        !          1869: 
        !          1870: /*
        !          1871:  * PptpCtrlNewCtrlState()
        !          1872:  */
        !          1873: 
        !          1874: static void
        !          1875: PptpCtrlNewCtrlState(PptpCtrl c, int new)
        !          1876: {
        !          1877:   struct pptp_engine   *const pptp = c->pptp;
        !          1878: 
        !          1879:   assert(c->state != new);
        !          1880:   CLOG(LOG_DEBUG, "ctrl state %s --> %s",
        !          1881:     gPptpCtrlStates[c->state], gPptpCtrlStates[new]);
        !          1882:   if (new == PPTP_CTRL_ST_FREE) {
        !          1883:     pptp->ctrl[c->id] = NULL;
        !          1884:     ppp_log_close(&c->log);
        !          1885:     FREE(PPTP_CTRL_MTYPE, c->channels);
        !          1886:     memset(c, 0, sizeof(*c));
        !          1887:     FREE(PPTP_CTRL_MTYPE, c);
        !          1888:     return;
        !          1889:   }
        !          1890:   c->state = new;
        !          1891: }
        !          1892: 
        !          1893: /*
        !          1894:  * PptpCtrlNewChanState()
        !          1895:  */
        !          1896: 
        !          1897: static void
        !          1898: PptpCtrlNewChanState(PptpChan ch, int new)
        !          1899: {
        !          1900:   PptpCtrl     const c = ch->ctrl;
        !          1901: 
        !          1902:   assert(ch->state != new);
        !          1903:   CHLOG(LOG_DEBUG, "chan state %s --> %s",
        !          1904:     gPptpChanStates[ch->state], gPptpChanStates[new]);
        !          1905:   switch (new) {
        !          1906:     case PPTP_CHAN_ST_FREE:
        !          1907:       c->channels[ch->id] = NULL;
        !          1908:       ppp_log_close(&ch->log);
        !          1909:       memset(ch, 0, sizeof(*ch));
        !          1910:       FREE(PPTP_CHAN_MTYPE, ch);
        !          1911:       return;
        !          1912:     case PPTP_CHAN_ST_WAIT_IN_REPLY:
        !          1913:     case PPTP_CHAN_ST_WAIT_OUT_REPLY:
        !          1914:     case PPTP_CHAN_ST_WAIT_CONNECT:
        !          1915:     case PPTP_CHAN_ST_WAIT_DISCONNECT:
        !          1916:     case PPTP_CHAN_ST_WAIT_ANSWER:
        !          1917:     case PPTP_CHAN_ST_ESTABLISHED:
        !          1918:     case PPTP_CHAN_ST_WAIT_CTRL:
        !          1919:       break;
        !          1920:   }
        !          1921:   ch->state = new;
        !          1922: }
        !          1923: 
        !          1924: /*
        !          1925:  * PptpCtrlSwap()
        !          1926:  *
        !          1927:  * Byteswap message between host order <--> network order. Note:
        !          1928:  * this relies on the fact that ntohs == htons and ntohl == htonl.
        !          1929:  */
        !          1930: 
        !          1931: static void
        !          1932: PptpCtrlSwap(int type, void *buf)
        !          1933: {
        !          1934:   PptpField    field = gPptpMsgLayout[type];
        !          1935:   int          off;
        !          1936: 
        !          1937:   for (off = 0; field->name; off += field->length, field++) {
        !          1938:     switch (field->length) {
        !          1939:       case 4:
        !          1940:        {
        !          1941:          u_int32_t     *const valp = (u_int32_t *) ((u_char *) buf + off);
        !          1942: 
        !          1943:          *valp = ntohl(*valp);
        !          1944:        }
        !          1945:        break;
        !          1946:       case 2:
        !          1947:        {
        !          1948:          u_int16_t     *const valp = (u_int16_t *) ((u_char *) buf + off);
        !          1949: 
        !          1950:          *valp = ntohs(*valp);
        !          1951:        }
        !          1952:        break;
        !          1953:     }
        !          1954:   }
        !          1955: }
        !          1956: 
        !          1957: /*
        !          1958:  * PptpCtrlDump()
        !          1959:  *
        !          1960:  * Debugging display of a control message.
        !          1961:  */
        !          1962: 
        !          1963: #define DUMP_DING      65
        !          1964: #define DUMP_MAX_DEC   100
        !          1965: #define DUMP_MAX_BUF   200
        !          1966: 
        !          1967: static void
        !          1968: PptpCtrlDump(int sev, PptpCtrl c, int type, void *msg)
        !          1969: {
        !          1970:   struct pptp_engine   *const pptp = c->pptp;
        !          1971:   PptpField            field = gPptpMsgLayout[type];
        !          1972:   char                 line[DUMP_MAX_BUF];
        !          1973:   int                  off;
        !          1974: 
        !          1975:   for (*line = off = 0; field->name; off += field->length, field++) {
        !          1976:     u_char     *data = (u_char *) msg + off;
        !          1977:     char       buf[DUMP_MAX_BUF];
        !          1978:     const char *fmt;
        !          1979: 
        !          1980:     if (!strncmp(field->name, PPTP_RESV_PREF, strlen(PPTP_RESV_PREF)))
        !          1981:       continue;
        !          1982:     snprintf(buf, sizeof(buf), " %s=", field->name);
        !          1983:     switch (field->length) {
        !          1984:       case 4:
        !          1985:        fmt = (*((u_int16_t *) data) <= DUMP_MAX_DEC) ? "%d" : "0x%x";
        !          1986:        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
        !          1987:          fmt, *((u_int32_t *) data));
        !          1988:        break;
        !          1989:       case 2:
        !          1990:        fmt = (*((u_int16_t *) data) <= DUMP_MAX_DEC) ? "%d" : "0x%x";
        !          1991:        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
        !          1992:          fmt, *((u_int16_t *) data));
        !          1993:        break;
        !          1994:       case 1:
        !          1995:        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
        !          1996:          "%d", *((u_int8_t *) data));
        !          1997:        break;
        !          1998:       default:
        !          1999:        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
        !          2000:          "\"%s\"", (char *) data);
        !          2001:        break;
        !          2002:     }
        !          2003:     if (*line && strlen(line) + strlen(buf) > DUMP_DING) {
        !          2004:       PLOG(sev, " %s", line);
        !          2005:       *line = 0;
        !          2006:     }
        !          2007:     snprintf(line + strlen(line), sizeof(line) - strlen(line), "%s", buf);
        !          2008:   }
        !          2009:   if (*line)
        !          2010:     PLOG(sev, " %s", line);
        !          2011: }
        !          2012: 
        !          2013: /*
        !          2014:  * PptpCtrlDumpBuf()
        !          2015:  *
        !          2016:  * Debugging display of a some bytes with a prefix line.
        !          2017:  */
        !          2018: 
        !          2019: static void
        !          2020: PptpCtrlDumpBuf(int sev, PptpCtrl c,
        !          2021:   const void *data, size_t len, const char *fmt, ...)
        !          2022: {
        !          2023:   struct pptp_engine   *const pptp = c->pptp;
        !          2024:   va_list args;
        !          2025: 
        !          2026:   va_start(args, fmt);
        !          2027:   ppp_log_vput(pptp->log, sev, fmt, args);
        !          2028:   va_end(args);
        !          2029:   ppp_log_dump(pptp->log, sev, data, len);
        !          2030: }
        !          2031: 
        !          2032: /*
        !          2033:  * PptpCtrlFindField()
        !          2034:  *
        !          2035:  * Locate a field in a structure, returning length and offset (*offset).
        !          2036:  * Die if field was not found.
        !          2037:  */
        !          2038: 
        !          2039: static int
        !          2040: PptpCtrlFindField(int type, const char *name, u_int *offp)
        !          2041: {
        !          2042:   PptpField    field = gPptpMsgLayout[type];
        !          2043:   u_int                off;
        !          2044: 
        !          2045:   for (off = 0; field->name; off += field->length, field++) {
        !          2046:     if (!strcmp(field->name, name)) {
        !          2047:       *offp = off;
        !          2048:       return(field->length);
        !          2049:     }
        !          2050:   }
        !          2051:   assert(0);
        !          2052:   return(0);
        !          2053: }
        !          2054: 
        !          2055: /*
        !          2056:  * PptpCtrlInitCinfo()
        !          2057:  */
        !          2058: 
        !          2059: static void
        !          2060: PptpCtrlInitCinfo(PptpChan ch, PptpCtrlInfo ci)
        !          2061: {
        !          2062:   PptpCtrl     const c = ch->ctrl;
        !          2063: 
        !          2064:   memset(ci, 0, sizeof(*ci));
        !          2065:   ci->cookie = ch;
        !          2066:   ci->peer_addr = c->peer_addr;
        !          2067:   ci->peer_port = c->peer_port;
        !          2068:   ci->close = (void (*)(void *, int, int, int))PptpCtrlCloseChan;
        !          2069:   ci->answer = PptpCtrlDialResult;
        !          2070: }
        !          2071: 
        !          2072: /*
        !          2073:  * PptpCtrlExtendArray()
        !          2074:  *
        !          2075:  * Extend an array
        !          2076:  */
        !          2077: 
        !          2078: static int
        !          2079: PptpCtrlExtendArray(const char *mtype, void *array, int esize, int *alenp)
        !          2080: {
        !          2081:   void **const arrayp = (void **)array;
        !          2082:   void *newa;
        !          2083: 
        !          2084:   if ((newa = REALLOC(mtype, *arrayp, (*alenp + 1) * esize)) == NULL)
        !          2085:     return(-1);
        !          2086:   *arrayp = newa;
        !          2087:   memset((u_char *)*arrayp + (*alenp * esize), 0, esize);
        !          2088:   (*alenp)++;
        !          2089:   return(0);
        !          2090: }
        !          2091: 
        !          2092: /*
        !          2093:  * PptpCtrlGetSocket()
        !          2094:  *
        !          2095:  * Get and (if port != 0) bind a TCP socket.
        !          2096:  */
        !          2097: 
        !          2098: static int
        !          2099: PptpCtrlGetSocket(struct in_addr ip, u_int16_t port, char *ebuf, size_t elen)
        !          2100: {
        !          2101:   static const int     one = 1;
        !          2102:   struct sockaddr_in   addr;
        !          2103:   int                  sock;
        !          2104:   int                  addr_size = sizeof(addr);
        !          2105: 
        !          2106:   /* Get socket */
        !          2107:   if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
        !          2108:     snprintf(ebuf, elen, "socket: %s", strerror(errno));
        !          2109:     return(-1);
        !          2110:   }
        !          2111:   (void)fcntl(sock, F_SETFD, 1);
        !          2112: 
        !          2113:   /* Set reusable address and port */
        !          2114:   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
        !          2115:     snprintf(ebuf, elen, "setsockopt: %s", strerror(errno));
        !          2116:     (void)close(sock);
        !          2117:     return(-1);
        !          2118:   }
        !          2119:   if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) {
        !          2120:     snprintf(ebuf, elen, "setsockopt: %s", strerror(errno));
        !          2121:     (void)close(sock);
        !          2122:     return(-1);
        !          2123:   }
        !          2124: 
        !          2125:   /* Bind socket */
        !          2126:   if (port != 0) {
        !          2127:     memset(&addr, 0, sizeof(addr));
        !          2128:     addr.sin_family = AF_INET;
        !          2129:     addr.sin_addr = ip;
        !          2130:     addr.sin_port = htons(port);
        !          2131:     if (bind(sock, (struct sockaddr *) &addr, addr_size) == -1) {
        !          2132:       snprintf(ebuf, elen, "bind: %s", strerror(errno));
        !          2133:       (void)close(sock);
        !          2134:       return(-1);
        !          2135:     }
        !          2136:   }
        !          2137: 
        !          2138:   /* Done */
        !          2139:   return(sock);
        !          2140: }
        !          2141: 
        !          2142: /*************************************************************************
        !          2143:                      CONTROL MESSAGE FUNCTIONS
        !          2144: *************************************************************************/
        !          2145: 
        !          2146: /*
        !          2147:  * PptpStartCtrlConnRequest()
        !          2148:  */
        !          2149: 
        !          2150: static void
        !          2151: PptpStartCtrlConnRequest(PptpCtrl c, struct pptpStartCtrlConnRequest *req)
        !          2152: {
        !          2153:   struct pptp_engine           *const pptp = c->pptp;
        !          2154:   struct pptpStartCtrlConnReply        reply;
        !          2155:   int                          k;
        !          2156: 
        !          2157:   /* Check for a collision */
        !          2158:   if (!pptp->nocd) {
        !          2159:     for (k = 0; k < pptp->nctrl; k++) {
        !          2160:       PptpCtrl const c2 = pptp->ctrl[k];
        !          2161:       int              iwin;
        !          2162: 
        !          2163:       if (c2 == NULL
        !          2164:          || c2 == c
        !          2165:          || c2->peer_addr.s_addr != c->peer_addr.s_addr)
        !          2166:        continue;
        !          2167:       iwin = (u_int32_t) ntohl(c->self_addr.s_addr)
        !          2168:              > (u_int32_t) ntohl(c->peer_addr.s_addr);
        !          2169:       CLOG(LOG_INFO, "collision with peer! %s", iwin ? "i win" : "peer wins");
        !          2170:       if (iwin)
        !          2171:        goto abort;             /* Kill this peer-initiated connection */
        !          2172:       else
        !          2173:        PptpCtrlKillCtrl(c2);   /* Kill the connection that I initiated */
        !          2174:     }
        !          2175:   }
        !          2176: 
        !          2177:   /* Initialize reply */
        !          2178:   memset(&reply, 0, sizeof(reply));
        !          2179:   reply.vers = PPTP_PROTO_VERS;
        !          2180:   reply.frameCap = PPTP_FRAMECAP_SYNC;
        !          2181:   reply.bearCap = PPTP_BEARCAP_ANY;
        !          2182:   reply.firmware = PPTP_FIRMWARE_REV;
        !          2183:   reply.result = PPTP_SCCR_RESL_OK;
        !          2184:   gethostname(reply.host, sizeof(reply.host));
        !          2185:   strncpy(reply.vendor, pptp->vendor, sizeof(reply.vendor));
        !          2186: 
        !          2187:   /* Check protocol version */
        !          2188:   if (req->vers != PPTP_PROTO_VERS) {
        !          2189:     CLOG(LOG_ERR, "incompatible PPTP protocol version 0x%04x", req->vers);
        !          2190:     reply.result = PPTP_SCCR_RESL_VERS;
        !          2191:     PptpCtrlWriteMsg(c, PPTP_StartCtrlConnReply, &reply);
        !          2192: abort:
        !          2193:     PptpCtrlKillCtrl(c);
        !          2194:     return;
        !          2195:   }
        !          2196: 
        !          2197:   /* OK */
        !          2198:   PptpCtrlNewCtrlState(c, PPTP_CTRL_ST_ESTABLISHED);
        !          2199:   PptpCtrlWriteMsg(c, PPTP_StartCtrlConnReply, &reply);
        !          2200: }
        !          2201: 
        !          2202: /*
        !          2203:  * PptpStartCtrlConnReply()
        !          2204:  */
        !          2205: 
        !          2206: static void
        !          2207: PptpStartCtrlConnReply(PptpCtrl c, struct pptpStartCtrlConnReply *rep)
        !          2208: {
        !          2209: 
        !          2210:   /* Is peer happy? */
        !          2211:   if (rep->result != PPTP_SCCR_RESL_OK) {
        !          2212:     CLOG(LOG_NOTICE, "my %s failed, result=%s err=%s",
        !          2213:       gPptpMsgInfo[PPTP_StartCtrlConnRequest].name,
        !          2214:       PPTP_SCCR_RESL_CODE(rep->result), PPTP_ERROR_CODE(rep->err));
        !          2215:     PptpCtrlKillCtrl(c);
        !          2216:     return;
        !          2217:   }
        !          2218: 
        !          2219:   /* Check peer's protocol version */
        !          2220:   if (rep->vers != PPTP_PROTO_VERS) {
        !          2221:     struct pptpStopCtrlConnRequest     req;
        !          2222: 
        !          2223:     CLOG(LOG_ERR, "incompatible PPTP protocol version 0x%04x", rep->vers);
        !          2224:     memset(&req, 0, sizeof(req));
        !          2225:     req.reason = PPTP_SCCR_REAS_PROTO;
        !          2226:     PptpCtrlNewCtrlState(c, PPTP_CTRL_ST_WAIT_STOP_REPLY);
        !          2227:     PptpCtrlWriteMsg(c, PPTP_StopCtrlConnRequest, &req);
        !          2228:     return;
        !          2229:   }
        !          2230: 
        !          2231:   /* OK */
        !          2232:   PptpCtrlNewCtrlState(c, PPTP_CTRL_ST_ESTABLISHED);
        !          2233:   PptpCtrlCheckConn(c);
        !          2234: }
        !          2235: 
        !          2236: /*
        !          2237:  * PptpStopCtrlConnRequest()
        !          2238:  */
        !          2239: 
        !          2240: static void
        !          2241: PptpStopCtrlConnRequest(PptpCtrl c, struct pptpStopCtrlConnRequest *req)
        !          2242: {
        !          2243:   struct pptpStopCtrlConnReply rep;
        !          2244: 
        !          2245:   CLOG(LOG_INFO, "rec'd %s: reason=%s",
        !          2246:     gPptpMsgInfo[PPTP_StopCtrlConnRequest].name,
        !          2247:     PPTP_SCCR_REAS_CODE(req->reason));
        !          2248:   memset(&rep, 0, sizeof(rep));
        !          2249:   rep.result = PPTP_SCCR_RESL_OK;
        !          2250:   PptpCtrlNewCtrlState(c, PPTP_CTRL_ST_IDLE);
        !          2251:   PptpCtrlWriteMsg(c, PPTP_StopCtrlConnReply, &rep);
        !          2252:   PptpCtrlKillCtrl(c);
        !          2253: }
        !          2254: 
        !          2255: /*
        !          2256:  * PptpStopCtrlConnReply()
        !          2257:  */
        !          2258: 
        !          2259: static void
        !          2260: PptpStopCtrlConnReply(PptpCtrl c, struct pptpStopCtrlConnReply *rep)
        !          2261: {
        !          2262:   PptpCtrlKillCtrl(c);
        !          2263: }
        !          2264: 
        !          2265: /*
        !          2266:  * PptpEchoRequest()
        !          2267:  */
        !          2268: 
        !          2269: static void
        !          2270: PptpEchoRequest(PptpCtrl c, struct pptpEchoRequest *req)
        !          2271: {
        !          2272:   struct pptpEchoReply reply;
        !          2273: 
        !          2274:   memset(&reply, 0, sizeof(reply));
        !          2275:   reply.id = req->id;
        !          2276:   reply.result = PPTP_ECHO_RESL_OK;
        !          2277:   PptpCtrlWriteMsg(c, PPTP_EchoReply, &reply);
        !          2278: }
        !          2279: 
        !          2280: /*
        !          2281:  * PptpEchoReply()
        !          2282:  */
        !          2283: 
        !          2284: static void
        !          2285: PptpEchoReply(PptpCtrl c, struct pptpEchoReply *rep)
        !          2286: {
        !          2287:   if (rep->result != PPTP_ECHO_RESL_OK) {
        !          2288:     CLOG(LOG_NOTICE, "echo reply failed: res=%s err=%s",
        !          2289:       PPTP_ECHO_RESL_CODE(rep->result), PPTP_ERROR_CODE(rep->err));
        !          2290:     PptpCtrlKillCtrl(c);
        !          2291:   } else if (rep->id != c->echoId) {
        !          2292:     CLOG(LOG_NOTICE, "bogus echo reply: %u != %u", rep->id, c->echoId);
        !          2293:     PptpCtrlKillCtrl(c);
        !          2294:   }
        !          2295: }
        !          2296: 
        !          2297: /*
        !          2298:  * PptpOutCallRequest()
        !          2299:  */
        !          2300: 
        !          2301: static void
        !          2302: PptpOutCallRequest(PptpCtrl c, struct pptpOutCallRequest *req)
        !          2303: {
        !          2304:   struct pptp_engine           *const pptp = c->pptp;
        !          2305:   struct pptpOutCallReply      reply;
        !          2306:   struct pptpctrlinfo          cinfo;
        !          2307:   struct pptplinkinfo          linfo;
        !          2308:   PptpChan                     ch = NULL;
        !          2309:   char                         calledNum[PPTP_PHONE_LEN + 1];
        !          2310:   char                         subAddress[PPTP_SUBADDR_LEN + 1];
        !          2311: 
        !          2312:   /* Does link allow this? */
        !          2313:   if (pptp->get_out_link == NULL)
        !          2314:     goto denied;
        !          2315: 
        !          2316:   /* Copy out fields */
        !          2317:   strncpy(calledNum, req->phone, sizeof(calledNum) - 1);
        !          2318:   calledNum[sizeof(calledNum) - 1] = 0;
        !          2319:   strncpy(subAddress, req->subaddr, sizeof(subAddress) - 1);
        !          2320:   subAddress[sizeof(subAddress) - 1] = 0;
        !          2321: 
        !          2322:   /* Get a data channel */
        !          2323:   if ((ch = PptpCtrlGetChan(c, PPTP_CHAN_ST_WAIT_ANSWER, FALSE, FALSE,
        !          2324:       req->bearType, req->frameType, req->minBps, req->maxBps,
        !          2325:       PPTP_STR_INTERNAL_CALLING, calledNum, subAddress)) == NULL) {
        !          2326:     CLOG(LOG_ERR, "can't get channel for %s call", "outgoing");
        !          2327:     goto chFail;
        !          2328:   }
        !          2329: 
        !          2330:   /* Fill in details */
        !          2331:   ch->serno = req->serno;
        !          2332:   ch->peerCid = req->cid;
        !          2333:   ch->peerPpd = req->ppd;
        !          2334:   ch->recvWin = req->recvWin;
        !          2335: 
        !          2336:   /* Ask link layer about making the outgoing call */
        !          2337:   PptpCtrlInitCinfo(ch, &cinfo);
        !          2338:   linfo = (*pptp->get_out_link)(pptp->arg,
        !          2339:     cinfo, c->peer_addr, c->peer_port, req->bearType,
        !          2340:     req->frameType, req->minBps, req->maxBps, calledNum, subAddress);
        !          2341:   if (linfo.cookie == NULL || linfo.cancel == NULL || linfo.result == NULL)
        !          2342:     goto denied;
        !          2343: 
        !          2344:   /* Link layer says it's OK; wait for link layer to report back later */
        !          2345:   ch->linfo = linfo;
        !          2346:   return;
        !          2347: 
        !          2348:   /* Failed */
        !          2349: denied:
        !          2350:   CLOG(LOG_NOTICE, "peer's %s call request was denied", "outgoing");
        !          2351:   if (ch)
        !          2352:     PptpCtrlNewChanState(ch, PPTP_CHAN_ST_FREE);
        !          2353: chFail:
        !          2354:   memset(&reply, 0, sizeof(reply));
        !          2355:   reply.peerCid = req->cid;
        !          2356:   reply.result = PPTP_OCR_RESL_ADMIN;
        !          2357:   PptpCtrlWriteMsg(c, PPTP_OutCallReply, &reply);
        !          2358: }
        !          2359: 
        !          2360: /*
        !          2361:  * PptpOutCallReply()
        !          2362:  */
        !          2363: 
        !          2364: static void
        !          2365: PptpOutCallReply(PptpChan ch, struct pptpOutCallReply *reply)
        !          2366: {
        !          2367:   /* Did call go through? */
        !          2368:   if (reply->result != PPTP_OCR_RESL_OK) {
        !          2369:     char       errmsg[100];
        !          2370: 
        !          2371:     snprintf(errmsg, sizeof(errmsg),
        !          2372:       "outgoing call failed: res=%s err=%s",
        !          2373:       PPTP_OCR_RESL_CODE(reply->result), PPTP_ERROR_CODE(reply->err));
        !          2374:     CHLOG(LOG_NOTICE, "%s", errmsg);
        !          2375:     (*ch->linfo.result)(ch->linfo.cookie, errmsg);
        !          2376:     PptpCtrlKillChan(ch, "remote outgoing call failed");
        !          2377:     return;
        !          2378:   }
        !          2379: 
        !          2380:   /* Call succeeded */
        !          2381:   ch->peerPpd = reply->ppd;
        !          2382:   ch->recvWin = reply->recvWin;
        !          2383:   ch->peerCid = reply->cid;
        !          2384:   CHLOG(LOG_INFO, "outgoing call connected at %d bps", reply->speed);
        !          2385:   PptpCtrlNewChanState(ch, PPTP_CHAN_ST_ESTABLISHED);
        !          2386:   (*ch->linfo.result)(ch->linfo.cookie, NULL);
        !          2387: }
        !          2388: 
        !          2389: /*
        !          2390:  * PptpInCallRequest()
        !          2391:  */
        !          2392: 
        !          2393: static void
        !          2394: PptpInCallRequest(PptpCtrl c, struct pptpInCallRequest *req)
        !          2395: {
        !          2396:   struct pptp_engine           *const pptp = c->pptp;
        !          2397:   struct pptpInCallReply       reply;
        !          2398:   struct pptpctrlinfo          cinfo;
        !          2399:   struct pptplinkinfo          linfo;
        !          2400:   PptpChan                     ch;
        !          2401:   char                         callingNum[PPTP_PHONE_LEN + 1];
        !          2402:   char                         calledNum[PPTP_PHONE_LEN + 1];
        !          2403:   char                         subAddress[PPTP_SUBADDR_LEN + 1];
        !          2404: 
        !          2405:   /* Copy out fields */
        !          2406:   if (req->dialedLen > PPTP_PHONE_LEN)
        !          2407:     req->dialedLen = PPTP_PHONE_LEN;
        !          2408:   if (req->dialingLen > PPTP_PHONE_LEN)
        !          2409:     req->dialingLen = PPTP_PHONE_LEN;
        !          2410:   strncpy(callingNum, req->dialing, sizeof(callingNum) - 1);
        !          2411:   callingNum[req->dialingLen] = 0;
        !          2412:   strncpy(calledNum, req->dialed, sizeof(calledNum) - 1);
        !          2413:   calledNum[req->dialedLen] = 0;
        !          2414:   strncpy(subAddress, req->subaddr, sizeof(subAddress) - 1);
        !          2415:   subAddress[sizeof(subAddress) - 1] = 0;
        !          2416: 
        !          2417:   CLOG(LOG_INFO, "peer incoming call to \"%s\" from \"%s\"",
        !          2418:     calledNum, callingNum);
        !          2419: 
        !          2420:   /* Initialize reply */
        !          2421:   memset(&reply, 0, sizeof(reply));
        !          2422:   reply.peerCid = req->cid;
        !          2423:   reply.recvWin = PPTP_RECV_WIN;       /* XXX */
        !          2424:   reply.ppd = PPTP_PPD;                        /* XXX */
        !          2425: 
        !          2426:   /* Get a data channel */
        !          2427:   if ((ch = PptpCtrlGetChan(c, PPTP_CHAN_ST_WAIT_CONNECT, FALSE, TRUE,
        !          2428:       req->bearType, 0, 0, INT_MAX,
        !          2429:       callingNum, calledNum, subAddress)) == NULL) {
        !          2430:     CLOG(LOG_ERR, "can't get channel for %s call", "incoming");
        !          2431:     reply.result = PPTP_ICR_RESL_ERR;
        !          2432:     reply.err = PPTP_ERROR_NO_RESOURCE;
        !          2433:     goto done;
        !          2434:   }
        !          2435:   reply.cid = ch->cid;
        !          2436: 
        !          2437:   /* Fill in details */
        !          2438:   ch->serno = req->serno;
        !          2439:   ch->peerCid = req->cid;
        !          2440:   ch->bearType = req->bearType;
        !          2441: 
        !          2442:   /* Ask link layer about accepting the incoming call */
        !          2443:   PptpCtrlInitCinfo(ch, &cinfo);
        !          2444:   linfo.cookie = NULL;
        !          2445:   if (pptp->get_in_link != NULL)
        !          2446:     linfo = (*pptp->get_in_link)(pptp->arg, cinfo, c->peer_addr, c->peer_port,
        !          2447:       req->bearType, callingNum, calledNum, subAddress);
        !          2448:   if (linfo.cookie == NULL) {
        !          2449:     CLOG(LOG_NOTICE, "peer's %s call request was denied", "incoming");
        !          2450:     reply.result = PPTP_ICR_RESL_NAK;
        !          2451:     goto done;
        !          2452:   }
        !          2453: 
        !          2454:   /* Link layer says it's OK */
        !          2455:   CHLOG(LOG_INFO, "accepting incoming call to \"%s\" from \"%s\"",
        !          2456:     calledNum, callingNum);
        !          2457:   reply.result = PPTP_ICR_RESL_OK;
        !          2458:   ch->linfo = linfo;
        !          2459:   strncpy(ch->callingNum, req->dialing, sizeof(ch->callingNum));
        !          2460:   strncpy(ch->calledNum, req->dialed, sizeof(ch->calledNum));
        !          2461:   strncpy(ch->subAddress, req->subaddr, sizeof(ch->subAddress));
        !          2462: 
        !          2463:   /* Return result */
        !          2464: done:
        !          2465:   PptpCtrlWriteMsg(c, PPTP_InCallReply, &reply);
        !          2466:   if (reply.result != PPTP_ICR_RESL_OK)
        !          2467:     PptpCtrlKillChan(ch, "peer incoming call failed");
        !          2468: }
        !          2469: 
        !          2470: /*
        !          2471:  * PptpInCallReply()
        !          2472:  */
        !          2473: 
        !          2474: static void
        !          2475: PptpInCallReply(PptpChan ch, struct pptpInCallReply *reply)
        !          2476: {
        !          2477:   PptpCtrl             const c = ch->ctrl;
        !          2478:   struct pptpInCallConn        con;
        !          2479: 
        !          2480:   /* Did call go through? */
        !          2481:   if (reply->result != PPTP_ICR_RESL_OK) {
        !          2482:     char       errmsg[100];
        !          2483: 
        !          2484:     snprintf(errmsg, sizeof(errmsg),
        !          2485:       "peer denied incoming call: res=%s err=%s",
        !          2486:       PPTP_ICR_RESL_CODE(reply->result), PPTP_ERROR_CODE(reply->err));
        !          2487:     CHLOG(LOG_NOTICE, "%s", errmsg);
        !          2488:     (*ch->linfo.result)(ch->linfo.cookie, errmsg);
        !          2489:     PptpCtrlKillChan(ch, "peer denied incoming call");
        !          2490:     return;
        !          2491:   }
        !          2492: 
        !          2493:   /* Call succeeded */
        !          2494:   CHLOG(LOG_INFO, "incoming call accepted by peer");
        !          2495:   ch->peerCid = reply->cid;
        !          2496:   ch->peerPpd = reply->ppd;
        !          2497:   ch->recvWin = reply->recvWin;
        !          2498:   PptpCtrlNewChanState(ch, PPTP_CHAN_ST_ESTABLISHED);
        !          2499:   (*ch->linfo.result)(ch->linfo.cookie, NULL);
        !          2500: 
        !          2501:   /* Send back connected message */
        !          2502:   memset(&con, 0, sizeof(con));
        !          2503:   con.peerCid = reply->cid;
        !          2504:   con.speed = 64000;                   /* XXX */
        !          2505:   con.recvWin = PPTP_RECV_WIN;         /* XXX */
        !          2506:   con.ppd = PPTP_PPD;                  /* XXX */
        !          2507:   con.frameType = PPTP_FRAMECAP_SYNC;
        !          2508:   PptpCtrlWriteMsg(c, PPTP_InCallConn, &con);
        !          2509: }
        !          2510: 
        !          2511: /*
        !          2512:  * PptpInCallConn()
        !          2513:  */
        !          2514: 
        !          2515: static void
        !          2516: PptpInCallConn(PptpChan ch, struct pptpInCallConn *con)
        !          2517: {
        !          2518:   CHLOG(LOG_INFO, "peer incoming call connected at %d bps", con->speed);
        !          2519:   ch->peerPpd = con->ppd;
        !          2520:   ch->recvWin = con->recvWin;
        !          2521:   ch->frameType = con->frameType;
        !          2522:   (*ch->linfo.result)(ch->linfo.cookie, NULL);
        !          2523:   PptpCtrlNewChanState(ch, PPTP_CHAN_ST_ESTABLISHED);
        !          2524: }
        !          2525: 
        !          2526: /*
        !          2527:  * PptpCallClearRequest()
        !          2528:  */
        !          2529: 
        !          2530: static void
        !          2531: PptpCallClearRequest(PptpChan ch, struct pptpCallClearRequest *req)
        !          2532: {
        !          2533:   struct pptpCallDiscNotify    notify;
        !          2534:   PptpCtrl                     const c = ch->ctrl;
        !          2535: 
        !          2536:   if (PPTP_CHAN_IS_PNS(ch)) {
        !          2537:     CHLOG(LOG_NOTICE, "rec'd %s, but we are PNS for this call",
        !          2538:       gPptpMsgInfo[PPTP_CallClearRequest].name);
        !          2539:     PptpCtrlKillCtrl(c);
        !          2540:     return;
        !          2541:   }
        !          2542:   CHLOG(LOG_INFO, "call cleared by peer");
        !          2543:   memset(&notify, 0, sizeof(notify));
        !          2544:   notify.cid = ch->cid;                        /* we are the PAC, use our CID */
        !          2545:   notify.result = PPTP_CDN_RESL_REQ;
        !          2546:   /* XXX stats? */
        !          2547:   PptpCtrlWriteMsg(c, PPTP_CallDiscNotify, &notify);
        !          2548:   PptpCtrlKillChan(ch, "cleared by peer");
        !          2549: }
        !          2550: 
        !          2551: /*
        !          2552:  * PptpCallDiscNotify()
        !          2553:  */
        !          2554: 
        !          2555: static void
        !          2556: PptpCallDiscNotify(PptpChan ch, struct pptpCallDiscNotify *notify)
        !          2557: {
        !          2558:   CHLOG(LOG_INFO, "peer call disconnected res=%s err=%s",
        !          2559:     PPTP_CDN_RESL_CODE(notify->result), PPTP_ERROR_CODE(notify->err));
        !          2560:   PptpCtrlKillChan(ch, "disconnected by peer");
        !          2561: }
        !          2562: 
        !          2563: /*
        !          2564:  * PptpWanErrorNotify()
        !          2565:  */
        !          2566: 
        !          2567: static void
        !          2568: PptpWanErrorNotify(PptpChan ch, struct pptpWanErrorNotify *notif)
        !          2569: {
        !          2570:   CHLOG(LOG_DEBUG, "ignoring %s", gPptpMsgInfo[PPTP_WanErrorNotify].name);
        !          2571: }
        !          2572: 
        !          2573: /*
        !          2574:  * PptpSetLinkInfo()
        !          2575:  */
        !          2576: 
        !          2577: static void
        !          2578: PptpSetLinkInfo(PptpChan ch, struct pptpSetLinkInfo *info)
        !          2579: {
        !          2580:   if (ch->linfo.setLinkInfo)
        !          2581:     (*ch->linfo.setLinkInfo)(ch->linfo.cookie, info->sendAccm, info->recvAccm);
        !          2582:   else {
        !          2583:     CHLOG(LOG_DEBUG, "ignoring %s", gPptpMsgInfo[PPTP_SetLinkInfo].name);
        !          2584:   }
        !          2585: }
        !          2586: 

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