#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <net/if_dl.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <event.h>
#ifdef USE_LIBSOCKUTIL
#include <seil/sockfromto.h>
#endif
#include "bytebuf.h"
#include "slist.h"
#include "hash.h"
#include "debugutil.h"
#include "time_utils.h"
#include "pptp.h"
#include "pptp_local.h"
#include "pptp_subr.h"
#include "npppd.h"
#ifdef PPTP_CALL_DEBUG
#define PPTP_CALL_DBG(x) pptp_call_log x
#define PPTP_CALL_ASSERT(x) ASSERT(x)
#else
#define PPTP_CALL_DBG(x)
#define PPTP_CALL_ASSERT(x)
#endif
static void pptp_call_log (pptp_call *, int, const char *, ...) __printflike(3,4);
static void pptp_call_notify_down (pptp_call *);
static int pptp_call_recv_SLI (pptp_call *, u_char *, int);
static int pptp_call_recv_CCR (pptp_call *, u_char *, int);
static int pptp_call_recv_OCRQ (pptp_call *, u_char *, int);
static void pptp_call_send_CDN (pptp_call *, int, int, int, const char *);
static int pptp_call_send_OCRP (pptp_call *, int, int, int);
static int pptp_call_gre_output (pptp_call *, int, int, u_char *, int);
static int pptp_call_bind_ppp (pptp_call *);
static void pptp_call_log (pptp_call *, int, const char *, ...);
static void pptp_call_OCRQ_string (struct pptp_ocrq *, char *, int);
static void pptp_call_OCRP_string (struct pptp_ocrp *, char *, int);
static void pptp_call_ppp_input (pptp_call *, unsigned char *, int, int);
static char * pptp_call_state_string(int);
static int pptp_call_ppp_output (npppd_ppp *, unsigned char *, int, int);
static void pptp_call_closed_by_ppp (npppd_ppp *);
#define SEQ_LT(a,b) ((int)((a) - (b)) < 0)
#define SEQ_LE(a,b) ((int)((a) - (b)) <= 0)
#define SEQ_GT(a,b) ((int)((a) - (b)) > 0)
#define SEQ_GE(a,b) ((int)((a) - (b)) >= 0)
#define SEQ_SUB(a,b) ((int32_t)((a) - (b)))
#define RUPDIV(n,d) (((n) + ((d) - ((n) % (d)))) / (d))
pptp_call *
pptp_call_create(void)
{
pptp_call *_this;
if ((_this = malloc(sizeof(pptp_call))) == NULL)
return NULL;
return _this;
}
int
pptp_call_init(pptp_call *_this, pptp_ctrl *ctrl)
{
memset(_this, 0, sizeof(pptp_call));
_this->ctrl = ctrl;
_this->maxwinsz = PPTP_CALL_DEFAULT_MAXWINSZ;
_this->winsz = RUPDIV(_this->maxwinsz, 2);
_this->last_io = get_monosec();
_this->snd_nxt = 1;
return 0;
}
int
pptp_call_start(pptp_call *_this)
{
if (pptp_call_bind_ppp(_this) != 0)
return 1;
return 0;
}
int
pptp_call_stop(pptp_call *_this)
{
if (_this->state != PPTP_CALL_STATE_CLEANUP_WAIT)
pptp_call_disconnect(_this, 0, 0, NULL);
pptp_call_log(_this, LOG_NOTICE, "logtype=Terminated");
pptpd_release_call(_this->ctrl->pptpd, _this);
return 0;
}
void
pptp_call_destroy(pptp_call *_this)
{
PPTP_CALL_ASSERT(_this != NULL);
free(_this);
}
void
pptp_call_disconnect(pptp_call *_this, int result, int error, const char *
statistics)
{
if (_this->state == PPTP_CALL_STATE_CLEANUP_WAIT) {
pptp_call_notify_down(_this);
return;
}
if (result > 0)
pptp_call_send_CDN(_this, result, error, 0, statistics);
_this->state = PPTP_CALL_STATE_CLEANUP_WAIT;
pptp_call_notify_down(_this);
}
void
pptp_call_input(pptp_call *_this, int mes_type, u_char *pkt, int lpkt)
{
PPTP_CALL_ASSERT(_this != NULL);
PPTP_CALL_ASSERT(pkt != NULL);
PPTP_CALL_ASSERT(lpkt >= 4);
_this->last_io = get_monosec();
switch (mes_type) {
case PPTP_CTRL_MES_CODE_OCRQ:
if (_this->state != PPTP_CALL_STATE_IDLE) {
pptp_call_send_OCRP(_this,
PPTP_OCRP_RESULT_GENERIC_ERROR,
PPTP_ERROR_BAD_CALL, 0);
goto bad_state;
}
if (pptp_call_recv_OCRQ(_this, pkt, lpkt) != 0) {
pptp_call_send_OCRP(_this,
PPTP_OCRP_RESULT_GENERIC_ERROR,
PPTP_ERROR_BAD_CALL, 0);
return;
}
if (pptpd_assign_call(_this->ctrl->pptpd, _this) != 0) {
pptp_call_send_OCRP(_this, PPTP_OCRP_RESULT_BUSY,
PPTP_ERROR_NONE, 0);
return;
}
if (pptp_call_send_OCRP(_this, PPTP_OCRP_RESULT_CONNECTED,
PPTP_ERROR_NONE, 0) != 0) {
pptp_call_disconnect(_this,
PPTP_CDN_RESULT_GENRIC_ERROR,
PPTP_ERROR_PAC_ERROR, NULL);
return;
}
if (pptp_call_start(_this) != 0) {
pptp_call_disconnect(_this,
PPTP_CDN_RESULT_GENRIC_ERROR,
PPTP_ERROR_PAC_ERROR, NULL);
return;
}
_this->state = PPTP_CALL_STATE_ESTABLISHED;
break;
case PPTP_CTRL_MES_CODE_SLI:
if (pptp_call_recv_SLI(_this, pkt, lpkt) != 0) {
return;
}
return;
case PPTP_CTRL_MES_CODE_CCR:
pptp_call_recv_CCR(_this, pkt, lpkt);
if (_this->state == PPTP_CALL_STATE_ESTABLISHED) {
pptp_call_disconnect(_this, PPTP_CDN_RESULT_REQUEST,
PPTP_ERROR_NONE, NULL);
} else {
pptp_call_disconnect(_this, 0, 0, NULL);
if (_this->state != PPTP_CALL_STATE_CLEANUP_WAIT)
goto bad_state;
}
return;
default:
pptp_call_log(_this, LOG_WARNING,
"Unhandled control message type=%s(%d)",
pptp_ctrl_mes_type_string(mes_type), mes_type);
}
return;
bad_state:
pptp_call_log(_this, LOG_WARNING,
"Received control message %s(%d) in bad state=%s",
pptp_ctrl_mes_type_string(mes_type), mes_type,
pptp_call_state_string(_this->state));
}
static int
pptp_call_recv_SLI(pptp_call *_this, u_char *pkt, int lpkt)
{
struct pptp_sli *sli;
if (lpkt < sizeof(struct pptp_sli)) {
pptp_call_log(_this, LOG_ERR, "Received bad SLI: packet too "
"short: %d < %d", lpkt, (int)sizeof(struct pptp_sli));
return 1;
}
sli = (struct pptp_sli *)pkt;
sli->send_accm = ntohl(sli->send_accm);
sli->recv_accm = ntohl(sli->recv_accm);
if (sli->send_accm != 0xffffffffL ||
sli->recv_accm != 0xffffffffL) {
pptp_call_log(_this, LOG_WARNING,
"RecvSLI Received bad ACCM %08x:%08x: asynchronous framing "
"is not supported.\n", sli->send_accm, sli->recv_accm);
return 1;
}
pptp_call_log(_this, LOG_INFO, "RecvSLI accm=%08x:%08x",
sli->send_accm, sli->recv_accm);
return 0;
}
#if 0
static int
pptp_call_send_SLI(pptp_call *_this)
{
int lpkt;
struct pptp_sli *sli;
sli = bytebuffer_pointer(_this->ctrl->send_buf);
lpkt = bytebuffer_remaining(_this->ctrl->send_buf);
if (lpkt < sizeof(struct pptp_sli)) {
pptp_call_log(_this, LOG_ERR,
"SendOCRP failed: No buffer space available");
return -1;
}
memset(sli, 0, sizeof(struct pptp_sli));
pptp_init_header(&sli->header, sizeof(struct pptp_sli),
PPTP_CTRL_MES_CODE_SLI);
sli->peers_call_id = _this->id;
sli->send_accm = 0xffffffff;
sli->recv_accm = 0xffffffff;
_this->last_io = get_monosec();
pptp_call_log(_this, LOG_INFO, "SendSLI accm=%08x:%08x",
sli->send_accm, sli->recv_accm);
sli->peers_call_id = htons(sli->peers_call_id);
sli->send_accm = htonl(sli->send_accm);
sli->recv_accm = htonl(sli->recv_accm);
pptp_ctrl_output(_this->ctrl, NULL, sizeof(struct pptp_sli));
return 0;
}
#endif
static int
pptp_call_recv_CCR(pptp_call *_this, u_char *pkt, int lpkt)
{
struct pptp_ccr *ccr;
PPTP_CALL_ASSERT(lpkt >= sizeof(struct pptp_ccr));
if (lpkt < sizeof(struct pptp_ccr)) {
return 1;
}
ccr = (struct pptp_ccr *)pkt;
ccr->call_id = ntohs(ccr->call_id);
pptp_call_log(_this, LOG_INFO, "RecvCCR call_id=%u", ccr->call_id);
return 0;
}
static void
pptp_call_send_CDN(pptp_call *_this, int result, int error, int cause,
const char *statistics)
{
int lpkt;
struct pptp_cdn *cdn;
cdn = bytebuffer_pointer(_this->ctrl->send_buf);
lpkt = bytebuffer_remaining(_this->ctrl->send_buf);
if (lpkt < sizeof(struct pptp_cdn)) {
pptp_call_log(_this, LOG_ERR,
"SendCCR failed: No buffer space available");
return;
}
memset(cdn, 0, sizeof(struct pptp_cdn));
pptp_init_header(&cdn->header, sizeof(struct pptp_cdn),
PPTP_CTRL_MES_CODE_CDN);
cdn->call_id = _this->id;
cdn->result_code = result;
cdn->error_code = error;
cdn->cause_code = cause;
if (statistics != NULL)
strlcpy(cdn->statistics, statistics, sizeof(cdn->statistics));
pptp_call_log(_this, LOG_INFO, "SendCDN "
"call_id=%u result=%s(%d) error=%s(%d) cause=%d statistics=%s",
cdn->call_id,
pptp_CDN_result_string(cdn->result_code), cdn->result_code,
pptp_general_error_string(cdn->error_code), cdn->error_code,
cdn->cause_code,
(statistics == NULL)? "(none)" : (char *)cdn->statistics);
cdn->call_id = htons(cdn->call_id);
cdn->cause_code = htons(cdn->cause_code);
_this->last_io = get_monosec();
pptp_ctrl_output(_this->ctrl, NULL, sizeof(struct pptp_cdn));
}
static int
pptp_call_send_OCRP(pptp_call *_this, int result, int error, int cause)
{
int lpkt;
struct pptp_ocrp *ocrp;
char logbuf[512];
ocrp = bytebuffer_pointer(_this->ctrl->send_buf);
lpkt = bytebuffer_remaining(_this->ctrl->send_buf);
if (lpkt < sizeof(struct pptp_ocrp)) {
pptp_call_log(_this, LOG_ERR,
"SendOCRP failed: No buffer space available");
return -1;
}
memset(ocrp, 0, sizeof(struct pptp_ocrp));
pptp_init_header(&ocrp->header, sizeof(struct pptp_ocrp),
PPTP_CTRL_MES_CODE_OCRP);
ocrp->call_id = _this->id;
ocrp->peers_call_id = _this->peers_call_id;
ocrp->result_code = result;
ocrp->error_code = error;
ocrp->cause_code = cause;
ocrp->connect_speed = PPTP_CALL_CONNECT_SPEED;
ocrp->recv_winsz = _this->maxwinsz;
ocrp->packet_proccessing_delay = PPTP_CALL_INITIAL_PPD;
ocrp->physical_channel_id = _this->id;
pptp_call_OCRP_string(ocrp, logbuf, sizeof(logbuf));
pptp_call_log(_this, LOG_INFO, "SendOCRP %s", logbuf);
ocrp->call_id = htons(ocrp->call_id);
ocrp->peers_call_id = htons(ocrp->peers_call_id);
ocrp->cause_code = htons(ocrp->cause_code);
ocrp->connect_speed = htons(ocrp->connect_speed);
ocrp->recv_winsz = htons(ocrp->recv_winsz);
ocrp->packet_proccessing_delay = htons(ocrp->packet_proccessing_delay);
ocrp->physical_channel_id = htonl(ocrp->physical_channel_id);
_this->last_io = get_monosec();
pptp_ctrl_output(_this->ctrl, NULL, sizeof(struct pptp_ocrp));
return 0;
}
static int
pptp_call_recv_OCRQ(pptp_call *_this, u_char *pkt, int lpkt)
{
char logbuf[512];
struct pptp_ocrq *ocrq;
if (lpkt < sizeof(struct pptp_ocrq)) {
pptp_call_log(_this, LOG_ERR, "Received bad OCRQ: packet too "
"short: %d < %d", lpkt, (int)sizeof(struct pptp_ocrq));
return 1;
}
ocrq = (struct pptp_ocrq *)pkt;
ocrq->call_id = ntohs(ocrq->call_id);
ocrq->call_serial_number = ntohs(ocrq->call_serial_number);
ocrq->recv_winsz = ntohs(ocrq->recv_winsz);
ocrq->packet_proccessing_delay =
ntohs(ocrq->packet_proccessing_delay);
ocrq->phone_number_length = ntohs(ocrq->phone_number_length);
ocrq->reservied1 = ntohs(ocrq->reservied1);
ocrq->maximum_bps = ntohl(ocrq->maximum_bps);
ocrq->minimum_bps = ntohl(ocrq->minimum_bps);
ocrq->bearer_type = ntohl(ocrq->bearer_type);
ocrq->framing_type = ntohl(ocrq->framing_type);
_this->peers_call_id = ocrq->call_id;
_this->peers_maxwinsz = ocrq->recv_winsz;
pptp_call_OCRQ_string(ocrq, logbuf, sizeof(logbuf));
pptp_call_log(_this, LOG_INFO, "RecvOCRQ %s", logbuf);
return 0;
}
void
pptp_call_gre_input(pptp_call *_this, uint32_t seq, uint32_t ack,
int input_flags, u_char *pkt, int pktlen)
{
int log_prio;
const char *reason;
int delayed = 0;
PPTP_CALL_ASSERT(_this != NULL);
log_prio = LOG_INFO;
#ifdef PPTP_CALL_DEBUG
if (debuglevel >= 2) {
pptp_call_log(_this, LOG_DEBUG,
"Received data packet seq=%u(%u-%u) ack=%u(%u-%u)",
seq, _this->rcv_nxt,
_this->rcv_nxt + _this->peers_maxwinsz - 1,
ack, _this->snd_una, _this->snd_nxt);
}
#endif
if (_this->state != PPTP_CALL_STATE_ESTABLISHED) {
pptp_call_log(_this, LOG_INFO,
"Received data packet in illegal state=%s",
pptp_call_state_string(_this->state));
return;
}
PPTP_CALL_ASSERT(_this->state == PPTP_CALL_STATE_ESTABLISHED);
if (input_flags & PPTP_GRE_PKT_ACK_PRESENT) {
if (ack + 1 == _this->snd_una) {
} else if (SEQ_LT(ack, _this->snd_una)) {
delayed = 1;
} else if (SEQ_GT(ack, _this->snd_nxt)) {
reason = "ack for unknown sequence.";
goto bad_pkt;
} else {
ack++;
_this->snd_una = ack;
}
}
if ((input_flags & PPTP_GRE_PKT_SEQ_PRESENT) == 0)
return;
if (SEQ_LT(seq, _this->rcv_nxt)) {
if (SEQ_LT(seq, _this->rcv_nxt - PPTP_CALL_DELAY_LIMIT)) {
reason = "out of sequence";
goto bad_pkt;
}
delayed = 1;
} else if (SEQ_GE(seq, _this->rcv_nxt + _this->maxwinsz)){
pptp_call_log(_this, LOG_INFO,
"Received packet caused window overflow. seq=%u(%u-%u), "
"may lost %d packets.", seq, _this->rcv_nxt,
_this->rcv_nxt + _this->maxwinsz - 1,
SEQ_SUB(seq, _this->rcv_nxt));
}
if (!delayed) {
seq++;
_this->rcv_nxt = seq;
if (SEQ_SUB(seq, _this->rcv_acked) > RUPDIV(_this->winsz, 2)) {
PPTP_CALL_DBG((_this, LOG_DEBUG,
"rcv window size=%u %u %u\n",
SEQ_SUB(seq, _this->rcv_acked), seq,
_this->rcv_acked));
pptp_call_gre_output(_this, 0, 1, NULL, 0);
}
}
pptp_call_ppp_input(_this, pkt, pktlen, delayed);
return;
bad_pkt:
pptp_call_log(_this, log_prio,
"Received bad data packet: %s: seq=%u(%u-%u) ack=%u(%u-%u)",
reason, seq, _this->rcv_nxt, _this->rcv_nxt + _this->maxwinsz - 1,
ack, _this->snd_una, _this->snd_nxt);
}
static int
pptp_call_gre_output(pptp_call *_this, int fseq, int fack, u_char *pkt,
int lpkt)
{
int sz;
struct pptp_gre_header *grehdr;
u_char buf[65535], *opkt;
struct sockaddr_storage peer, sock;
#ifndef USE_LIBSOCKUTIL
socklen_t peerlen;
#endif
memset(buf, 0, sizeof(buf));
opkt = buf;
grehdr = (struct pptp_gre_header *)opkt;
opkt += sizeof(struct pptp_gre_header);
grehdr->K = 1;
grehdr->ver = PPTP_GRE_VERSION;
grehdr->protocol_type = htons(PPTP_GRE_PROTOCOL_TYPE);
grehdr->payload_length = htons(lpkt);
grehdr->call_id = htons(_this->peers_call_id);
#ifdef PPTP_CALL_DEBUG
if (debuglevel >= 2 && (fseq || fack)) {
pptp_call_log(_this, LOG_DEBUG,
"Sending data packet seq=%u ack=%u",
_this->snd_nxt, _this->rcv_nxt - 1);
}
#endif
PPTP_CALL_ASSERT(ALIGNED_POINTER(opkt, uint32_t));
if (fseq) {
grehdr->S = 1;
*(uint32_t *)opkt = htonl(_this->snd_nxt++);
opkt += 4;
}
if (fack) {
grehdr->A = 1;
_this->rcv_acked = _this->rcv_nxt;
*(uint32_t *)opkt = htonl(_this->rcv_nxt - 1);
opkt += 4;
}
if (lpkt > 0) {
memcpy(opkt, pkt, lpkt);
opkt += lpkt;
}
memcpy(&peer, &_this->ctrl->peer, sizeof(peer));
memcpy(&sock, &_this->ctrl->our, sizeof(sock));
switch (peer.ss_family) {
case AF_INET:
((struct sockaddr_in *)&peer)->sin_port = 0;
((struct sockaddr_in *)&sock)->sin_port = 0;
#ifndef USE_LIBSOCKUTIL
peerlen = sizeof(struct sockaddr_in);
#endif
break;
default:
return 1;
}
if (PPTP_CTRL_CONF(_this->ctrl)->data_out_pktdump != 0) {
pptp_call_log(_this, LOG_DEBUG, "PPTP Data output packet dump");
show_hd(debug_get_debugfp(), buf, opkt - buf);
}
#ifdef USE_LIBSOCKUTIL
sz = sendfromto(pptp_ctrl_sock_gre(_this->ctrl), buf, opkt - buf,
0, (struct sockaddr *)&sock, (struct sockaddr *)&peer);
#else
sz = sendto(pptp_ctrl_sock_gre(_this->ctrl), buf, opkt - buf, 0,
(struct sockaddr *)&peer, peerlen);
#endif
if (sz <= 0)
pptp_call_log(_this, LOG_WARNING, "sendto(%d) failed: %m",
pptp_ctrl_sock_gre(_this->ctrl));
return (sz > 0)? 0 : 1;
}
static void
pptp_call_notify_down(pptp_call *_this)
{
if (_this->ppp != NULL)
ppp_phy_downed(_this->ppp);
}
static void
pptp_call_ppp_input(pptp_call *_this, u_char *pkt, int pktlen, int delayed)
{
int rval;
npppd_ppp *ppp;
ppp = _this->ppp;
if (ppp == NULL) {
pptp_call_log(_this, LOG_WARNING,
"Received ppp frame but ppp is not assigned yet");
return;
}
rval = ppp->recv_packet(ppp, pkt, pktlen, delayed ? PPP_IO_FLAGS_DELAYED : 0);
if (_this->ppp == NULL)
return;
if (rval != 0) {
ppp->ierrors++;
} else {
ppp->ipackets++;
ppp->ibytes += pktlen;
}
}
static int
pptp_call_ppp_output(npppd_ppp *ppp, unsigned char *bytes, int nbytes,
int flags)
{
pptp_call *_this;
_this = ppp->phy_context;
PPTP_CALL_ASSERT(_this != NULL);
if (_this == NULL)
return 0;
if (pptp_call_gre_output(_this, 1, 1, bytes, nbytes) != 0) {
ppp->oerrors++;
return 1;
}
ppp->opackets++;
ppp->obytes += nbytes;
return 0;
}
static void
pptp_call_closed_by_ppp(npppd_ppp *ppp)
{
pptp_call *_this;
PPTP_CALL_ASSERT(ppp != NULL);
PPTP_CALL_ASSERT(ppp->phy_context != NULL);
_this = ppp->phy_context;
_this->ppp = NULL;
if (_this->state != PPTP_CALL_STATE_CLEANUP_WAIT) {
pptp_call_disconnect(_this, PPTP_CDN_RESULT_LOST_CARRIER, 0,
NULL);
}
pptp_call_log(_this, LOG_NOTICE, "logtype=PPPUnbind");
}
static int
pptp_call_bind_ppp(pptp_call *_this)
{
npppd_ppp *ppp;
ppp = NULL;
if ((ppp = ppp_create()) == NULL)
goto fail;
PPTP_CALL_ASSERT(_this->ppp == NULL);
if (_this->ppp != NULL)
return -1;
_this->ppp = ppp;
ppp->phy_context = _this;
ppp->tunnel_type = NPPPD_TUNNEL_PPTP;
ppp->tunnel_session_id = _this->id;
ppp->send_packet = pptp_call_ppp_output;
ppp->phy_close = pptp_call_closed_by_ppp;
strlcpy(ppp->phy_label, PPTP_CTRL_LISTENER_TUN_NAME(_this->ctrl),
sizeof(ppp->phy_label));
PPTP_CALL_ASSERT(sizeof(ppp->phy_info) >= _this->ctrl->peer.ss_len);
memcpy(&ppp->phy_info, &_this->ctrl->peer,
MINIMUM(sizeof(ppp->phy_info), _this->ctrl->peer.ss_len));
if (ppp_init(npppd_get_npppd(), ppp) != 0)
goto fail;
pptp_call_log(_this, LOG_NOTICE, "logtype=PPPBind ppp=%d", ppp->id);
ppp_start(ppp);
return 0;
fail:
pptp_call_log(_this, LOG_ERR, "failed binding ppp");
if (ppp != NULL)
ppp_destroy(ppp);
_this->ppp = NULL;
return 1;
}
static void
pptp_call_log(pptp_call *_this, int prio, const char *fmt, ...)
{
char logbuf[BUFSIZ];
va_list ap;
va_start(ap, fmt);
#ifdef PPTPD_MULTIPLE
snprintf(logbuf, sizeof(logbuf), "pptpd id=%u ctrl=%u call=%u %s",
_this->ctrl->pptpd->id, _this->ctrl->id, _this->id, fmt);
#else
snprintf(logbuf, sizeof(logbuf), "pptpd ctrl=%u call=%u %s",
_this->ctrl->id, _this->id, fmt);
#endif
vlog_printf(prio, logbuf, ap);
va_end(ap);
}
static void
pptp_call_OCRQ_string(struct pptp_ocrq *ocrq, char *buf, int lbuf)
{
snprintf(buf, lbuf,
"call_id=%u call_serial_number=%u max_bps=%u min_bps=%u bearer=%s "
"framing=%s recv_winsz=%u packet_proccessing_delay=%u "
"phone_number=%.*s subaddress=%.*s",
ocrq->call_id, ocrq->call_serial_number, ocrq->maximum_bps,
ocrq->minimum_bps, pptp_bearer_string(ocrq->bearer_type),
pptp_framing_string(ocrq->framing_type), ocrq->recv_winsz,
ocrq->packet_proccessing_delay,
(u_int)sizeof(ocrq->phone_number), ocrq->phone_number,
(u_int)sizeof(ocrq->subaddress), ocrq->subaddress);
}
void
pptp_call_OCRP_string(struct pptp_ocrp *ocrp, char *buf, int lbuf)
{
snprintf(buf, lbuf,
"call_id=%u peers_call_id=%u result=%u error=%u cause=%u "
"conn_speed=%u recv_winsz=%u packet_proccessing_delay=%u "
"physical_channel_id=%u",
ocrp->call_id, ocrp->peers_call_id, ocrp->result_code,
ocrp->error_code, ocrp->cause_code, ocrp->connect_speed,
ocrp->recv_winsz, ocrp->packet_proccessing_delay,
ocrp->physical_channel_id);
}
static char *
pptp_call_state_string(int state)
{
switch (state) {
case PPTP_CALL_STATE_IDLE:
return "idle";
case PPTP_CALL_STATE_WAIT_CONN:
return "wait-conn";
case PPTP_CALL_STATE_ESTABLISHED:
return "established";
case PPTP_CALL_STATE_CLEANUP_WAIT:
return "cleanup-wait";
}
return "unknown";
}