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(¬ify, 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, ¬ify);
! 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>