Annotation of embedaddon/mpd/src/pptp_ctrl.c, revision 1.1

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

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