
/*
 * pptp_ctrl.h
 *
 * Written by Archie Cobbs <archie@freebsd.org>
 * Copyright (c) 1998-1999 Whistle Communications, Inc. All rights reserved.
 * See ``COPYRIGHT.whistle''
 */

#if !defined(_PPTP_CTRL_H_) || defined(_WANT_PPTP_FIELDS)
#ifndef _WANT_PPTP_FIELDS
#define	_PPTP_CTRL_H_

/*
 * DEFINITIONS
 */

  /* Definitions per the spec */
  #define PPTP_PORT		1723
  #define PPTP_MTU		1532
  #define PPTP_PROTO_VERS	0x0100
  #define PPTP_MAGIC		0x1a2b3c4d
  #define PPTP_IDLE_TIMEOUT	60

  #define PPTP_HOSTNAME_LEN	64
  #define PPTP_VENDOR_LEN	64
  #define PPTP_PHONE_LEN	64
  #define PPTP_SUBADDR_LEN	64
  #define PPTP_STATS_LEN	128

  /* Control messages */
  #define PPTP_CTRL_MSG_TYPE	1

  enum {
    PPTP_StartCtrlConnRequest = 1,
    PPTP_StartCtrlConnReply = 2,
    PPTP_StopCtrlConnRequest = 3,
    PPTP_StopCtrlConnReply = 4,
    PPTP_EchoRequest = 5,
    PPTP_EchoReply = 6,
    PPTP_OutCallRequest = 7,
    PPTP_OutCallReply = 8,
    PPTP_InCallRequest = 9,
    PPTP_InCallReply = 10,
    PPTP_InCallConn = 11,
    PPTP_CallClearRequest = 12,
    PPTP_CallDiscNotify = 13,
    PPTP_WanErrorNotify = 14,
    PPTP_SetLinkInfo = 15,
  };

  #define PPTP_MIN_CTRL_TYPE		1
  #define PPTP_MAX_CTRL_TYPE		16

  #define PPTP_VALID_CTRL_TYPE(x)	\
	((x) >= PPTP_MIN_CTRL_TYPE && (x) < PPTP_MAX_CTRL_TYPE)

  /* Framing capabilities */
  #define PPTP_FRAMECAP_ASYNC		0x01
  #define PPTP_FRAMECAP_SYNC		0x02
  #define PPTP_FRAMECAP_ANY		0x03

  /* Bearer capabilities */
  #define PPTP_BEARCAP_ANALOG		0x01
  #define PPTP_BEARCAP_DIGITAL		0x02
  #define PPTP_BEARCAP_ANY		0x03

  /* General error codes */
  #define PPTP_ERROR_NONE		0
  #define PPTP_ERROR_NOT_CONNECTED	1
  #define PPTP_ERROR_BAD_FORMAT		2
  #define PPTP_ERROR_BAD_VALUE		3
  #define PPTP_ERROR_NO_RESOURCE	4
  #define PPTP_ERROR_BAD_CALL_ID	5
  #define PPTP_ERROR_PAC_ERROR		6

  /* All reserved fields have this prefix */
  #define PPTP_RESV_PREF		"resv"

  /* Message structures */
  struct pptpMsgHead {
    u_int16_t	length;		/* total length */
    u_int16_t	msgType;	/* PPTP message type */
    u_int32_t	magic;		/* magic cookie */
    u_int16_t	type;		/* control message type */
    u_int16_t	resv0;		/* reserved */
  };
  typedef struct pptpMsgHead	*PptpMsgHead;

#else
  { { "len", 2 }, { "msgType", 2 }, { "magic", 4 }, { "type", 2 },
    { PPTP_RESV_PREF "0", 2 }, { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  struct pptpStartCtrlConnRequest {
    u_int16_t		vers;		/* protocol version */
    u_int16_t		resv0;		/* reserved */
    u_int32_t		frameCap;	/* framing capabilities */
    u_int32_t		bearCap;	/* bearer capabilities */
    u_int16_t		maxChan;	/* maximum # channels */
    u_int16_t		firmware;	/* firmware revision */
    char		host[PPTP_HOSTNAME_LEN];	/* host name */
    char		vendor[PPTP_VENDOR_LEN];	/* vendor name */
  };

#else
  { { "vers", 2 }, { PPTP_RESV_PREF "0", 2 }, { "frameCap", 4 },
    { "bearCap", 4 }, { "maxChan", 2 }, { "firm", 2 },
    { "host", PPTP_HOSTNAME_LEN }, { "vend", PPTP_VENDOR_LEN }, { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  struct pptpStartCtrlConnReply {
    u_int16_t		vers;		/* protocol version */
    u_int8_t		result;		/* result code */
    u_int8_t		err;		/* error code */
    u_int32_t		frameCap;	/* framing capabilities */
    u_int32_t		bearCap;	/* bearer capabilities */
    u_int16_t		maxChan;	/* maximum # channels */
    u_int16_t		firmware;	/* firmware revision */
    char		host[PPTP_HOSTNAME_LEN];	/* host name */
    char		vendor[PPTP_VENDOR_LEN];	/* vendor name */
  };

#else
  { { "vers", 2 }, { "result", 1 }, { "err", 1 }, { "frameCap", 4 },
    { "bearCap", 4 }, { "maxChan", 2 }, { "firm", 2 },
    { "host", PPTP_HOSTNAME_LEN }, { "vend", PPTP_VENDOR_LEN }, { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  #define PPTP_SCCR_RESL_OK	1	/* channel successfully established */
  #define PPTP_SCCR_RESL_ERR	2	/* general error; see error code */
  #define PPTP_SCCR_RESL_EXISTS	3	/* command channel already exists */
  #define PPTP_SCCR_RESL_AUTH	4	/* not authorized */
  #define PPTP_SCCR_RESL_VERS	5	/* incompatible protocol version */

  struct pptpStopCtrlConnRequest {
    u_int8_t		reason;		/* reason */
    u_int8_t		resv0;		/* reserved */
    u_int16_t		resv1;		/* reserved */
  };

#else
  { { "reason", 1 }, { PPTP_RESV_PREF "0", 1 }, { PPTP_RESV_PREF "1", 2 },
    { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  #define PPTP_SCCR_REAS_NONE	1	/* general */
  #define PPTP_SCCR_REAS_PROTO	2	/* can't support protocol version */
  #define PPTP_SCCR_REAS_LOCAL	3	/* local shutdown */

  struct pptpStopCtrlConnReply {
    u_int8_t		result;		/* result code */
    u_int8_t		err;		/* error code */
    u_int16_t		resv0;		/* reserved */
  };

#else
  { { "result", 1 }, { "err", 1 }, { PPTP_RESV_PREF "0", 2 }, { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  struct pptpEchoRequest {
    u_int32_t		id;		/* identifier */
  };

#else
  { { "id", 4 }, { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  struct pptpEchoReply {
    u_int32_t		id;		/* identifier */
    u_int8_t		result;		/* result code */
    u_int8_t		err;		/* error code */
    u_int16_t		resv0;		/* reserved */
  };

#else
  { { "id", 4 }, { "result", 1 }, { "err", 1 },
    { "ignore", 2 }, { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  #define PPTP_ECHO_RESL_OK	1	/* echo reply is valid */
  #define PPTP_ECHO_RESL_ERR	2	/* general error; see error code */

  struct pptpOutCallRequest {
    u_int16_t		cid;		/* call id */
    u_int16_t		serno;		/* call serial # */
    u_int32_t		minBps;		/* minimum BPS */
    u_int32_t		maxBps;		/* maximum BPS */
    u_int32_t		frameType;	/* framing type */
    u_int32_t		bearType;	/* bearer type */
    u_int16_t		recvWin;	/* pkt receive window size */
    u_int16_t		ppd;		/* pkt processing delay */
    u_int16_t		numLen;		/* phone number length */
    u_int16_t		resv0;		/* reserved */
    char		phone[PPTP_PHONE_LEN];		/* phone number */
    char		subaddr[PPTP_SUBADDR_LEN];	/* sub-address */
  };

#else
  { { "cid", 2 }, { "serno", 2 }, { "minBPS", 4 }, { "maxBPS", 4 },
    { "frameType", 4 }, { "bearType", 4 }, { "recvWin", 2 }, { "ppd", 2 },
    { "numLen", 2 }, { PPTP_RESV_PREF "0", 2 },
    { "phone", PPTP_PHONE_LEN }, { "subaddr", PPTP_SUBADDR_LEN },
    { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  struct pptpOutCallReply {
    u_int16_t		cid;		/* call id */
    u_int16_t		peerCid;	/* peer call id */
    u_int8_t		result;		/* result code */
    u_int8_t		err;		/* error code */
    u_int16_t		cause;		/* cause code */
    u_int32_t		speed;		/* cause code */
    u_int16_t		recvWin;	/* pkt receive window size code */
    u_int16_t		ppd;		/* pkt processing delay */
    u_int32_t		channel;	/* physical channel id */
  };

#else
  { { "cid", 2 }, { "peerCid", 2 }, { "result", 1 }, { "err", 1 },
    { "cause", 2 }, { "speed", 4 }, { "recvWin", 2 }, { "ppd", 2 },
    { "channel", 4 }, { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  #define PPTP_OCR_RESL_OK	1	/* call established OK */
  #define PPTP_OCR_RESL_ERR	2	/* general error; see error code */
  #define PPTP_OCR_RESL_NOCARR	3	/* no carrier */
  #define PPTP_OCR_RESL_BUSY	4	/* busy */
  #define PPTP_OCR_RESL_NODIAL	5	/* no dialtone */
  #define PPTP_OCR_RESL_TIMED	6	/* timed out */
  #define PPTP_OCR_RESL_ADMIN	7	/* administratvely prohibited */

  struct pptpInCallRequest {
    u_int16_t		cid;		/* call id */
    u_int16_t		serno;		/* call serial # */
    u_int32_t		bearType;	/* bearer type */
    u_int32_t		channel;	/* physical channel id */
    u_int16_t		dialedLen;	/* dialed number len */
    u_int16_t		dialingLen;	/* dialing number len */
    char		dialed[PPTP_PHONE_LEN];		/* dialed number */
    char		dialing[PPTP_PHONE_LEN];	/* dialing number */
    char		subaddr[PPTP_SUBADDR_LEN];	/* sub-address */
  };

#else
  { { "cid", 2 }, { "serno", 2 }, { "bearType", 4 }, { "channel", 4 },
    { "dialedLen", 2 }, { "dialingLen", 2 }, { "dialed", PPTP_PHONE_LEN },
    { "dialing", PPTP_PHONE_LEN }, { "subaddr", PPTP_SUBADDR_LEN },
    { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  struct pptpInCallReply {
    u_int16_t		cid;		/* call id */
    u_int16_t		peerCid;	/* peer call id */
    u_int8_t		result;		/* result code */
    u_int8_t		err;		/* error code */
    u_int16_t		recvWin;	/* pkt receive window size code */
    u_int16_t		ppd;		/* pkt processing delay */
    u_int16_t		resv0;		/* reserved */
  };

#else
  { { "cid", 2 }, { "peerCid", 2 }, { "result", 1 }, { "err", 1 },
    { "recvWin", 2 }, { "ppd", 2 }, { PPTP_RESV_PREF "0", 2 },
    { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  #define PPTP_ICR_RESL_OK	1	/* call established OK */
  #define PPTP_ICR_RESL_ERR	2	/* general error; see error code */
  #define PPTP_ICR_RESL_NAK	3	/* do not accept */

  struct pptpInCallConn {
    u_int16_t		peerCid;	/* peer call id */
    u_int16_t		resv0;		/* reserved */
    u_int32_t		speed;		/* connect speed */
    u_int16_t		recvWin;	/* pkt receive window size code */
    u_int16_t		ppd;		/* pkt processing delay */
    u_int32_t		frameType;	/* framing type */
  };

#else
  { { "peerCid", 2 }, { PPTP_RESV_PREF "0", 2 }, { "speed", 4 },
    { "recvWin", 2 }, { "ppd", 2 }, { "frameType", 4 }, { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  struct pptpCallClearRequest {
    u_int16_t		cid;		/* PNS assigned call id */
    u_int16_t		resv0;		/* reserved */
  };

#else
  { { "cid", 2 }, { PPTP_RESV_PREF "0", 2 }, { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  struct pptpCallDiscNotify {
    u_int16_t		cid;		/* PAC assigned call id */
    u_int8_t		result;		/* result code */
    u_int8_t		err;		/* error code */
    u_int16_t		cause;		/* cause code */
    u_int16_t		resv0;		/* reserved */
    char		stats[PPTP_STATS_LEN];	/* call stats */
  };

#else
  { { "cid", 2 }, { "result", 1 }, { "err", 1 }, { "cause", 2 },
    { PPTP_RESV_PREF "0", 2 }, { "stats", PPTP_STATS_LEN },
    { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  #define PPTP_CDN_RESL_CARR	1	/* lost carrier */
  #define PPTP_CDN_RESL_ERR	2	/* general error; see error code */
  #define PPTP_CDN_RESL_ADMIN	3	/* administrative reason */
  #define PPTP_CDN_RESL_REQ	4	/* received disconnect request */

  struct pptpWanErrorNotify {
    u_int16_t		cid;		/* PNS assigned call id */
    u_int16_t		resv0;		/* reserved */
    u_int32_t		crc;		/* crc errors */
    u_int32_t		frame;		/* framing errors */
    u_int32_t		hdw;		/* hardware errors */
    u_int32_t		ovfl;		/* buffer overrun errors */
    u_int32_t		timeout;	/* timeout errors */
    u_int32_t		align;		/* alignment errors */
  };

#else
  { { "cid", 2 }, { PPTP_RESV_PREF "0", 2 }, { "crc", 4 },
    { "frame", 4 }, { "hdw", 4 }, { "ovfl", 4 }, { "timeout", 4 },
    { "align", 4 }, { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  struct pptpSetLinkInfo {
    u_int16_t		cid;		/* call id */
    u_int16_t		resv0;		/* reserved */
    u_int32_t		sendAccm;	/* send ACCM */
    u_int32_t		recvAccm;	/* receive ACCM */
  };

#else
  { { "cid", 2 }, { PPTP_RESV_PREF "0", 2 }, { "sendAccm", 4 },
    { "recvAccm", 4 }, { NULL, 0 } },
#endif
#ifndef _WANT_PPTP_FIELDS

  #define PPTP_CTRL_MAX_FRAME	\
	(sizeof(struct pptpMsgHead) + sizeof(struct pptpInCallRequest))
  #define PPTP_CTRL_MAX_FIELDS	14

  /* Describes one field of a PPTP control message structure */
  struct pptpfield {
    const char	*name;
    u_short	length;
  };
  typedef struct pptpfield	*PptpField;

  /* Link <-> control liason structures and callback function types */
  struct pptplinkinfo {		/* PPTP's info for accessing link code */
    void	*cookie;	/* NULL indicates response is invalid */
    void	(*result)(void *cookie, const char *errmsg);
    void	(*setLinkInfo)(void *cookie, u_int32_t sa, u_int32_t ra);
    void	(*cancel)(void *cookie);	/* cancel outgoing call */
  };
  typedef struct pptplinkinfo	*PptpLinkInfo;

  struct pptpctrlinfo {		/* Link's info for accessing PPTP code */
    void		*cookie;	/* NULL indicates response is invalid */
    struct in_addr	peer_addr;	/* Peer IP address and port */
    u_short		peer_port;
    void		(*close)(void *cookie, int result, int err, int cause);
    void		(*answer)(void *cookie, int rs, int er, int cs, int sp);
  };
  typedef struct pptpctrlinfo	*PptpCtrlInfo;

  typedef struct pptplinkinfo	(*PptpGetInLink_t)(struct pptpctrlinfo cinfo,
				  struct in_addr peer, int port, int bearType,
				  const char *callingNum,
				  const char *calledNum,
				  const char *subAddress);

  typedef struct pptplinkinfo	(*PptpGetOutLink_t)(struct pptpctrlinfo cinfo,
				  struct in_addr peer, int port, int bearType,
				  int frameType, int minBps, int maxBps,
				  const char *calledNum,
				  const char *subAddress);

/*
 * FUNCTIONS
 */

  extern int			PptpCtrlInit(PptpGetInLink_t getInLink,
				  PptpGetOutLink_t getOutLink,
				  struct in_addr myip);

  extern int			PptpCtrlListen(int enable, int port,
				  int allow_multiple);

  extern struct pptpctrlinfo	PptpCtrlInCall(struct pptplinkinfo linfo,
				  struct in_addr locip, struct in_addr ip,
				  int port, int bearType, int frameType,
				  int minBps, int maxBps,
				  const char *callingNum,
				  const char *calledNum,
				  const char *subAddress);

  extern struct pptpctrlinfo	PptpCtrlOutCall(struct pptplinkinfo linfo,
				  struct in_addr locip, struct in_addr ip,
				  int port, int bearType, int frameType,
				  int minBps, int maxBps,
				  const char *calledNum,
				  const char *subAddress);

  extern int			PptpCtrlGetSessionInfo(struct pptpctrlinfo *cp,
				  struct in_addr *selfAddr,
				  struct in_addr *peerAddr,
				  u_int16_t *selfCid, u_int16_t *peerCid,
				  u_int16_t *peerWin, u_int16_t *peerPpd);

#endif	/* #ifndef _WANT_PPTP_FIELDS */
#endif	/* #if !defined(_PPTP_CTRL_H_) || defined(_WANT_PPTP_FIELDS) */

