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