xref: /openbsd/usr.sbin/npppd/pptp/pptp_ctrl.c (revision f5c2ff87)
1*f5c2ff87Syasuoka /*	$OpenBSD: pptp_ctrl.c,v 1.13 2021/03/29 03:54:40 yasuoka Exp $	*/
2e109dc18Syasuoka 
30fbf3537Syasuoka /*-
40fbf3537Syasuoka  * Copyright (c) 2009 Internet Initiative Japan Inc.
50fbf3537Syasuoka  * All rights reserved.
60fbf3537Syasuoka  *
70fbf3537Syasuoka  * Redistribution and use in source and binary forms, with or without
80fbf3537Syasuoka  * modification, are permitted provided that the following conditions
90fbf3537Syasuoka  * are met:
100fbf3537Syasuoka  * 1. Redistributions of source code must retain the above copyright
110fbf3537Syasuoka  *    notice, this list of conditions and the following disclaimer.
120fbf3537Syasuoka  * 2. Redistributions in binary form must reproduce the above copyright
130fbf3537Syasuoka  *    notice, this list of conditions and the following disclaimer in the
140fbf3537Syasuoka  *    documentation and/or other materials provided with the distribution.
150fbf3537Syasuoka  *
160fbf3537Syasuoka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
170fbf3537Syasuoka  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
180fbf3537Syasuoka  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
190fbf3537Syasuoka  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
200fbf3537Syasuoka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
210fbf3537Syasuoka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
220fbf3537Syasuoka  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
230fbf3537Syasuoka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
240fbf3537Syasuoka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
250fbf3537Syasuoka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
260fbf3537Syasuoka  * SUCH DAMAGE.
270fbf3537Syasuoka  */
280fbf3537Syasuoka /**@file
29f0a4e295Syasuoka  * PPTP(RFC 2637) control connection implementation.
30f0a4e295Syasuoka  * currently it only support PAC part
310fbf3537Syasuoka  */
32*f5c2ff87Syasuoka /* $Id: pptp_ctrl.c,v 1.13 2021/03/29 03:54:40 yasuoka Exp $ */
330fbf3537Syasuoka #include <sys/types.h>
340fbf3537Syasuoka #include <sys/socket.h>
350fbf3537Syasuoka #include <netinet/in.h>
360fbf3537Syasuoka #include <stdio.h>
370fbf3537Syasuoka #include <stdarg.h>
380fbf3537Syasuoka #include <stdlib.h>
390fbf3537Syasuoka #include <netdb.h>
400fbf3537Syasuoka #include <unistd.h>
410fbf3537Syasuoka #include <syslog.h>
420fbf3537Syasuoka #include <time.h>
430fbf3537Syasuoka #include <fcntl.h>
440fbf3537Syasuoka #include <errno.h>
450fbf3537Syasuoka #include <string.h>
460fbf3537Syasuoka #include <event.h>
470fbf3537Syasuoka 
480fbf3537Syasuoka #include "bytebuf.h"
490fbf3537Syasuoka #include "debugutil.h"
500fbf3537Syasuoka #include "hash.h"
510fbf3537Syasuoka #include "slist.h"
520fbf3537Syasuoka #include "time_utils.h"
530fbf3537Syasuoka 
540fbf3537Syasuoka #include "version.h"
550fbf3537Syasuoka 
560fbf3537Syasuoka #include "pptp.h"
570fbf3537Syasuoka #include "pptp_local.h"
580fbf3537Syasuoka #include "pptp_subr.h"
590fbf3537Syasuoka 
60dbad4650Sderaadt #define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
61dbad4650Sderaadt #define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
62dbad4650Sderaadt 
63f0a4e295Syasuoka /* periods of pptp_ctrl_timeout */
640fbf3537Syasuoka #define PPTP_CTRL_TIMEOUT_IVAL_SEC	2
650fbf3537Syasuoka 
660fbf3537Syasuoka #ifdef	PPTP_CTRL_DEBUG
670fbf3537Syasuoka #define	PPTP_CTRL_ASSERT(x)	ASSERT(x)
680fbf3537Syasuoka #define	PPTP_CTRL_DBG(x)	pptp_ctrl_log x
690fbf3537Syasuoka #else
700fbf3537Syasuoka #define	PPTP_CTRL_ASSERT(x)
710fbf3537Syasuoka #define	PPTP_CTRL_DBG(x)
720fbf3537Syasuoka #endif
730fbf3537Syasuoka 
740fbf3537Syasuoka static unsigned pptp_ctrl_seqno = 0;
750fbf3537Syasuoka 
760fbf3537Syasuoka static void  pptp_ctrl_log (pptp_ctrl *, int, const char *, ...) __printflike(3,4);
770fbf3537Syasuoka static void        pptp_ctrl_timeout (int, short, void *);
780fbf3537Syasuoka static void        pptp_ctrl_reset_timeout (pptp_ctrl *);
790fbf3537Syasuoka static void        pptp_ctrl_io_event (int, short, void *);
800fbf3537Syasuoka static void        pptp_ctrl_set_io_event (pptp_ctrl *);
810fbf3537Syasuoka static int         pptp_ctrl_output_flush (pptp_ctrl *);
820fbf3537Syasuoka static void        pptp_ctrl_SCCRx_string (struct pptp_scc *, u_char *, int);
830fbf3537Syasuoka static int         pptp_ctrl_recv_SCCRQ (pptp_ctrl *, u_char *, int);
840fbf3537Syasuoka static int         pptp_ctrl_recv_StopCCRP (pptp_ctrl *, u_char *, int);
850fbf3537Syasuoka static int         pptp_ctrl_send_StopCCRQ (pptp_ctrl *, int);
860fbf3537Syasuoka static int         pptp_ctrl_recv_StopCCRQ (pptp_ctrl *, u_char *, int);
870fbf3537Syasuoka static int         pptp_ctrl_send_StopCCRP (pptp_ctrl *, int, int);
880fbf3537Syasuoka static int         pptp_ctrl_send_SCCRP (pptp_ctrl *, int, int);
890fbf3537Syasuoka static void        pptp_ctrl_send_CDN (pptp_ctrl *, int, int, int, const char *);
900fbf3537Syasuoka static void        pptp_ctrl_process_echo_req (pptp_ctrl *, u_char *, int);
910fbf3537Syasuoka static int         pptp_ctrl_recv_echo_rep (pptp_ctrl *, u_char *, int);
920fbf3537Syasuoka static void        pptp_ctrl_send_echo_req (pptp_ctrl *);
930fbf3537Syasuoka static int         pptp_ctrl_input (pptp_ctrl *, u_char *, int);
940fbf3537Syasuoka static int         pptp_ctrl_call_input (pptp_ctrl *, int, u_char *, int);
950fbf3537Syasuoka static const char  *pptp_ctrl_state_string (int);
960fbf3537Syasuoka static void        pptp_ctrl_fini(pptp_ctrl *);
970fbf3537Syasuoka 
98f0a4e295Syasuoka /*
99f0a4e295Syasuoka  * pptp_ctrl instance operation functions
100f0a4e295Syasuoka  */
1010fbf3537Syasuoka pptp_ctrl *
pptp_ctrl_create(void)1020fbf3537Syasuoka pptp_ctrl_create(void)
1030fbf3537Syasuoka {
1040fbf3537Syasuoka 	pptp_ctrl *_this;
1050fbf3537Syasuoka 
1060fbf3537Syasuoka 	if ((_this = malloc(sizeof(pptp_ctrl))) == NULL)
1070fbf3537Syasuoka 		return NULL;
1080fbf3537Syasuoka 
1090fbf3537Syasuoka 	return _this;
1100fbf3537Syasuoka }
1110fbf3537Syasuoka 
1120fbf3537Syasuoka int
pptp_ctrl_init(pptp_ctrl * _this)1130fbf3537Syasuoka pptp_ctrl_init(pptp_ctrl *_this)
1140fbf3537Syasuoka {
1150fbf3537Syasuoka 	time_t curr_time;
1160fbf3537Syasuoka 
1170fbf3537Syasuoka 	PPTP_CTRL_ASSERT(_this != NULL);
1180fbf3537Syasuoka 	curr_time = get_monosec();
1190fbf3537Syasuoka 	memset(_this, 0, sizeof(pptp_ctrl));
1200fbf3537Syasuoka 	_this->id = pptp_ctrl_seqno++;
1210fbf3537Syasuoka 	_this->sock = -1;
1220fbf3537Syasuoka 
1230fbf3537Syasuoka 	if ((_this->recv_buf = bytebuffer_create(PPTP_BUFSIZ)) == NULL) {
1240fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR, "bytebuffer_create() failed at "
1250fbf3537Syasuoka 		    "%s(): %m", __func__);
126f0a4e295Syasuoka 		goto fail;
1270fbf3537Syasuoka 	}
1280fbf3537Syasuoka 	if ((_this->send_buf = bytebuffer_create(PPTP_BUFSIZ)) == NULL) {
1290fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR, "bytebuffer_create() failed at "
1300fbf3537Syasuoka 		    "%s(): %m", __func__);
131f0a4e295Syasuoka 		goto fail;
1320fbf3537Syasuoka 	}
1330fbf3537Syasuoka 	_this->last_rcv_ctrl = curr_time;
1340fbf3537Syasuoka 	_this->last_snd_ctrl = curr_time;
135c2307f15Syasuoka 	_this->echo_seq = arc4random();
1360fbf3537Syasuoka 	_this->echo_interval = PPTP_CTRL_DEFAULT_ECHO_INTERVAL;
1370fbf3537Syasuoka 	_this->echo_timeout = PPTP_CTRL_DEFAULT_ECHO_TIMEOUT;
1380fbf3537Syasuoka 	slist_init(&_this->call_list);
1390fbf3537Syasuoka 	evtimer_set(&_this->ev_timer, pptp_ctrl_timeout, _this);
1400fbf3537Syasuoka 
1410fbf3537Syasuoka 	return 0;
142f0a4e295Syasuoka fail:
1430fbf3537Syasuoka 	return 1;
1440fbf3537Syasuoka }
1450fbf3537Syasuoka 
1460fbf3537Syasuoka int
pptp_ctrl_start(pptp_ctrl * _this)1470fbf3537Syasuoka pptp_ctrl_start(pptp_ctrl *_this)
1480fbf3537Syasuoka {
1490fbf3537Syasuoka 	int ival;
1500fbf3537Syasuoka 	char hbuf0[NI_MAXHOST], sbuf0[NI_MAXSERV];
1510fbf3537Syasuoka 	char hbuf1[NI_MAXHOST], sbuf1[NI_MAXSERV];
1520fbf3537Syasuoka 	struct sockaddr_storage sock;
1530fbf3537Syasuoka 	socklen_t socklen;
1540fbf3537Syasuoka 
1550fbf3537Syasuoka 	PPTP_CTRL_ASSERT(_this != NULL);
1560fbf3537Syasuoka 	PPTP_CTRL_ASSERT(_this->sock >= 0);
1570fbf3537Syasuoka 
158f0a4e295Syasuoka 	/* convert address to strings for logging */
1590fbf3537Syasuoka 	strlcpy(hbuf0, "<unknown>", sizeof(hbuf0));
1600fbf3537Syasuoka 	strlcpy(sbuf0, "<unknown>", sizeof(sbuf0));
1610fbf3537Syasuoka 	strlcpy(hbuf1, "<unknown>", sizeof(hbuf1));
1620fbf3537Syasuoka 	strlcpy(sbuf1, "<unknown>", sizeof(sbuf1));
1630fbf3537Syasuoka 	if (getnameinfo((struct sockaddr *)&_this->peer, _this->peer.ss_len,
1640fbf3537Syasuoka 	    hbuf0, sizeof(hbuf0), sbuf0, sizeof(sbuf0),
1650fbf3537Syasuoka 	    NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
1660fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR,
1670fbf3537Syasuoka 		    "getnameinfo() failed at %s(): %m", __func__);
1680fbf3537Syasuoka 	}
1690fbf3537Syasuoka 	socklen = sizeof(sock);
1700fbf3537Syasuoka 	if (getsockname(_this->sock, (struct sockaddr *)&sock, &socklen) != 0) {
1710fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR,
1720fbf3537Syasuoka 		    "getsockname() failed at %s(): %m", __func__);
173f0a4e295Syasuoka 		goto fail;
1740fbf3537Syasuoka 	}
1750fbf3537Syasuoka 	if (getnameinfo((struct sockaddr *)&sock, sock.ss_len, hbuf1,
1760fbf3537Syasuoka 	    sizeof(hbuf1), sbuf1, sizeof(sbuf1),
1770fbf3537Syasuoka 	    NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
1780fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR,
1790fbf3537Syasuoka 		    "getnameinfo() failed at %s(): %m", __func__);
1800fbf3537Syasuoka 	}
1810fbf3537Syasuoka 	pptp_ctrl_log(_this, LOG_INFO, "Starting peer=%s:%s/tcp "
1820fbf3537Syasuoka 	    "sock=%s:%s/tcp", hbuf0, sbuf0, hbuf1, sbuf1);
1830fbf3537Syasuoka 
184c8939cf4Skrw 	if ((ival = fcntl(_this->sock, F_GETFL)) < 0) {
1850fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR,
1860fbf3537Syasuoka 		    "fcntl(F_GET_FL) failed at %s(): %m", __func__);
187f0a4e295Syasuoka 		goto fail;
1880fbf3537Syasuoka 	} else if (fcntl(_this->sock, F_SETFL, ival | O_NONBLOCK) < 0) {
1890fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR,
1900fbf3537Syasuoka 		    "fcntl(F_SET_FL) failed at %s(): %m", __func__);
191f0a4e295Syasuoka 		goto fail;
1920fbf3537Syasuoka 	}
1930fbf3537Syasuoka 	pptp_ctrl_set_io_event(_this);
1940fbf3537Syasuoka 	pptp_ctrl_reset_timeout(_this);
1950fbf3537Syasuoka 
1960fbf3537Syasuoka 	return 0;
197f0a4e295Syasuoka fail:
1980fbf3537Syasuoka 	return 1;
1990fbf3537Syasuoka }
2000fbf3537Syasuoka 
201f0a4e295Syasuoka /* Timer */
2020fbf3537Syasuoka static void
pptp_ctrl_timeout(int fd,short event,void * ctx)2030fbf3537Syasuoka pptp_ctrl_timeout(int fd, short event, void *ctx)
2040fbf3537Syasuoka {
2050fbf3537Syasuoka 	int i;
2060fbf3537Syasuoka 	pptp_call *call;
2070fbf3537Syasuoka 	pptp_ctrl *_this;
2080fbf3537Syasuoka 	time_t last, curr_time;
2090fbf3537Syasuoka 
2100fbf3537Syasuoka 	_this = ctx;
2110fbf3537Syasuoka 	curr_time = get_monosec();
2120fbf3537Syasuoka 
2130fbf3537Syasuoka 	PPTP_CTRL_DBG((_this, DEBUG_LEVEL_3, "enter %s()", __func__));
214f0a4e295Syasuoka 	/* clean up call */
2150fbf3537Syasuoka 	i = 0;
2160fbf3537Syasuoka 	while (i < slist_length(&_this->call_list)) {
2170fbf3537Syasuoka 		call = slist_get(&_this->call_list, i);
2180fbf3537Syasuoka 		if (call->state == PPTP_CALL_STATE_CLEANUP_WAIT &&
2190fbf3537Syasuoka 		    curr_time - call->last_io > PPTP_CALL_CLEANUP_WAIT_TIME) {
2200fbf3537Syasuoka 			pptp_call_stop(call);
2210fbf3537Syasuoka 			pptp_call_destroy(call);
2220fbf3537Syasuoka 			slist_remove(&_this->call_list, i);
2230fbf3537Syasuoka 		} else
2240fbf3537Syasuoka 			i++;
2250fbf3537Syasuoka 	}
2260fbf3537Syasuoka 
227f0a4e295Syasuoka 	/* State machine: Timeout */
2280fbf3537Syasuoka 	switch (_this->state) {
2290fbf3537Syasuoka 	default:
2300fbf3537Syasuoka 	case PPTP_CTRL_STATE_WAIT_CTRL_REPLY:
2310fbf3537Syasuoka 	case PPTP_CTRL_STATE_IDLE:
2320fbf3537Syasuoka 		if (curr_time - _this->last_rcv_ctrl > PPTPD_IDLE_TIMEOUT) {
2330fbf3537Syasuoka 			pptp_ctrl_log(_this, LOG_ERR,
2340fbf3537Syasuoka 			    "Timeout in state %s",
2350fbf3537Syasuoka 			    pptp_ctrl_state_string(_this->state));
2360fbf3537Syasuoka 			pptp_ctrl_fini(_this);
2370fbf3537Syasuoka 			return;
2380fbf3537Syasuoka 		}
2390fbf3537Syasuoka 		break;
2400fbf3537Syasuoka 	case PPTP_CTRL_STATE_ESTABLISHED:
241dbad4650Sderaadt 		last = MAXIMUM(_this->last_rcv_ctrl, _this->last_snd_ctrl);
2420fbf3537Syasuoka 
2430fbf3537Syasuoka 		if (curr_time - _this->last_rcv_ctrl
2440fbf3537Syasuoka 			    >= _this->echo_interval + _this->echo_timeout) {
2450fbf3537Syasuoka 			pptp_ctrl_log(_this, LOG_INFO,
2460fbf3537Syasuoka 			    "Timeout waiting for echo reply");
2470fbf3537Syasuoka 			pptp_ctrl_fini(_this);
2480fbf3537Syasuoka 			return;
2490fbf3537Syasuoka 		}
2500fbf3537Syasuoka 		if (curr_time - last >= _this->echo_interval) {
2510fbf3537Syasuoka 			PPTP_CTRL_DBG((_this, LOG_DEBUG, "Echo"));
2520fbf3537Syasuoka 			_this->echo_seq++;
2530fbf3537Syasuoka 			pptp_ctrl_send_echo_req(_this);
2540fbf3537Syasuoka 		}
2550fbf3537Syasuoka 		break;
2560fbf3537Syasuoka 	case PPTP_CTRL_STATE_WAIT_STOP_REPLY:
2570fbf3537Syasuoka 		if (curr_time - _this->last_snd_ctrl >
2580fbf3537Syasuoka 		    PPTP_CTRL_StopCCRP_WAIT_TIME) {
2590fbf3537Syasuoka 			pptp_ctrl_log(_this, LOG_WARNING,
2600fbf3537Syasuoka 			    "Timeout waiting for StopCCRP");
2610fbf3537Syasuoka 			pptp_ctrl_fini(_this);
2620fbf3537Syasuoka 			return;
2630fbf3537Syasuoka 		}
2640fbf3537Syasuoka 		break;
2650fbf3537Syasuoka 	case PPTP_CTRL_STATE_DISPOSING:
2660fbf3537Syasuoka 		pptp_ctrl_fini(_this);
2670fbf3537Syasuoka 		return;
2680fbf3537Syasuoka 	}
2690fbf3537Syasuoka 	pptp_ctrl_reset_timeout(_this);
2700fbf3537Syasuoka }
2710fbf3537Syasuoka 
2720fbf3537Syasuoka static void
pptp_ctrl_reset_timeout(pptp_ctrl * _this)2730fbf3537Syasuoka pptp_ctrl_reset_timeout(pptp_ctrl *_this)
2740fbf3537Syasuoka {
2750fbf3537Syasuoka 	struct timeval tv;
2760fbf3537Syasuoka 
2770fbf3537Syasuoka 	switch (_this->state) {
2780fbf3537Syasuoka 	case PPTP_CTRL_STATE_DISPOSING:
279adafb749Sokan 		/* call back immediately */
280adafb749Sokan 		timerclear(&tv);
2810fbf3537Syasuoka 		break;
2820fbf3537Syasuoka 	default:
2830fbf3537Syasuoka 		tv.tv_sec = PPTP_CTRL_TIMEOUT_IVAL_SEC;
2840fbf3537Syasuoka 		tv.tv_usec = 0;
2850fbf3537Syasuoka 		break;
2860fbf3537Syasuoka 	}
2870fbf3537Syasuoka 	evtimer_add(&_this->ev_timer, &tv);
2880fbf3537Syasuoka }
2890fbf3537Syasuoka 
2900fbf3537Syasuoka /**
291f0a4e295Syasuoka  * Terminate PPTP control connection
292f0a4e295Syasuoka  * @result	The value for Stop-Control-Connection-Request(StopCCRQ) result.
293f0a4e295Syasuoka 		This function will not sent StopCCRQ when the value == 0 and
294f0a4e295Syasuoka 		the specification does not require to sent it.
2950fbf3537Syasuoka  * @see		::#PPTP_StopCCRQ_REASON_STOP_PROTOCOL
2960fbf3537Syasuoka  * @see		::#PPTP_StopCCRQ_REASON_STOP_LOCAL_SHUTDOWN
2970fbf3537Syasuoka  */
2980fbf3537Syasuoka void
pptp_ctrl_stop(pptp_ctrl * _this,int result)2990fbf3537Syasuoka pptp_ctrl_stop(pptp_ctrl *_this, int result)
3000fbf3537Syasuoka {
3010fbf3537Syasuoka 	int i;
3020fbf3537Syasuoka 	pptp_call *call;
3030fbf3537Syasuoka 
3040fbf3537Syasuoka 	switch (_this->state) {
3050fbf3537Syasuoka 	case PPTP_CTRL_STATE_WAIT_STOP_REPLY:
306*f5c2ff87Syasuoka 		/* waiting response. */
307f0a4e295Syasuoka 		/* this state will timeout by pptp_ctrl_timeout */
3080fbf3537Syasuoka 		break;
3090fbf3537Syasuoka 	case PPTP_CTRL_STATE_ESTABLISHED:
3100fbf3537Syasuoka 		if (result != 0) {
3110fbf3537Syasuoka 			for (i = 0; i < slist_length(&_this->call_list); i++) {
3120fbf3537Syasuoka 				call = slist_get(&_this->call_list, i);
3130fbf3537Syasuoka 				pptp_call_disconnect(call,
3140fbf3537Syasuoka 				    PPTP_CDN_RESULT_ADMIN_SHUTDOWN, 0, NULL);
3150fbf3537Syasuoka 			}
3160fbf3537Syasuoka 			pptp_ctrl_send_StopCCRQ(_this, result);
3170fbf3537Syasuoka 			_this->state = PPTP_CTRL_STATE_WAIT_STOP_REPLY;
3180fbf3537Syasuoka 			break;
3190fbf3537Syasuoka 		}
320f0a4e295Syasuoka 		/* FALLTHROUGH */
3210fbf3537Syasuoka 	default:
3220fbf3537Syasuoka 		pptp_ctrl_fini(_this);
3230fbf3537Syasuoka 	}
3240fbf3537Syasuoka 	return;
3250fbf3537Syasuoka }
3260fbf3537Syasuoka 
3270fbf3537Syasuoka 
328f0a4e295Syasuoka /* finish PPTP control */
3290fbf3537Syasuoka static void
pptp_ctrl_fini(pptp_ctrl * _this)3300fbf3537Syasuoka pptp_ctrl_fini(pptp_ctrl *_this)
3310fbf3537Syasuoka {
3320fbf3537Syasuoka 	pptp_call *call;
3330fbf3537Syasuoka 
3340fbf3537Syasuoka 	PPTP_CTRL_ASSERT(_this != NULL);
3350fbf3537Syasuoka 
3360fbf3537Syasuoka 	if (_this->sock >= 0) {
3370fbf3537Syasuoka 		event_del(&_this->ev_sock);
3380fbf3537Syasuoka 		close(_this->sock);
3390fbf3537Syasuoka 		_this->sock = -1;
3400fbf3537Syasuoka 	}
3410fbf3537Syasuoka 	for (slist_itr_first(&_this->call_list);
3420fbf3537Syasuoka 	    slist_itr_has_next(&_this->call_list);) {
3430fbf3537Syasuoka 		call = slist_itr_next(&_this->call_list);
3440fbf3537Syasuoka 		pptp_call_stop(call);
3450fbf3537Syasuoka 		pptp_call_destroy(call);
3460fbf3537Syasuoka 		slist_itr_remove(&_this->call_list);
3470fbf3537Syasuoka 	}
3480fbf3537Syasuoka 
3490fbf3537Syasuoka 	if (_this->on_io_event != 0) {
3500fbf3537Syasuoka 		/*
351f0a4e295Syasuoka 		 * as the complete terminate process needs complicated
352f0a4e295Syasuoka 		 * exception handling, do partially at here.
353f0a4e295Syasuoka 		 * rest of part will be handled by timer-event-handler.
3540fbf3537Syasuoka 		 */
3550fbf3537Syasuoka 		PPTP_CTRL_DBG((_this, LOG_DEBUG, "Disposing"));
3560fbf3537Syasuoka 		_this->state = PPTP_CTRL_STATE_DISPOSING;
3570fbf3537Syasuoka 		pptp_ctrl_reset_timeout(_this);
3580fbf3537Syasuoka 		return;
3590fbf3537Syasuoka 	}
3600fbf3537Syasuoka 
3610fbf3537Syasuoka 	evtimer_del(&_this->ev_timer);
3620fbf3537Syasuoka 	slist_fini(&_this->call_list);
3630fbf3537Syasuoka 
3640fbf3537Syasuoka 	pptp_ctrl_log (_this, LOG_NOTICE, "logtype=Finished");
3650fbf3537Syasuoka 
366f0a4e295Syasuoka 	/* disable _this */
3670fbf3537Syasuoka 	pptpd_ctrl_finished_notify(_this->pptpd, _this);
3680fbf3537Syasuoka }
3690fbf3537Syasuoka 
370f0a4e295Syasuoka /* free PPTP control context */
3710fbf3537Syasuoka void
pptp_ctrl_destroy(pptp_ctrl * _this)3720fbf3537Syasuoka pptp_ctrl_destroy(pptp_ctrl *_this)
3730fbf3537Syasuoka {
3740fbf3537Syasuoka 	if (_this->send_buf != NULL) {
3750fbf3537Syasuoka 		bytebuffer_destroy(_this->send_buf);
3760fbf3537Syasuoka 		_this->send_buf = NULL;
3770fbf3537Syasuoka 	}
3780fbf3537Syasuoka 	if (_this->recv_buf != NULL) {
3790fbf3537Syasuoka 		bytebuffer_destroy(_this->recv_buf);
3800fbf3537Syasuoka 		_this->recv_buf = NULL;
3810fbf3537Syasuoka 	}
3820fbf3537Syasuoka 	free(_this);
3830fbf3537Syasuoka }
3840fbf3537Syasuoka 
385f0a4e295Syasuoka /*
386f0a4e295Syasuoka  * network I/O
387f0a4e295Syasuoka  */
388f0a4e295Syasuoka /* I/O event dispather */
3890fbf3537Syasuoka static void
pptp_ctrl_io_event(int fd,short evmask,void * ctx)3900fbf3537Syasuoka pptp_ctrl_io_event(int fd, short evmask, void *ctx)
3910fbf3537Syasuoka {
3920fbf3537Syasuoka 	int sz, lpkt, hdrlen;
3930fbf3537Syasuoka 	u_char *pkt;
3940fbf3537Syasuoka 	pptp_ctrl *_this;
3950fbf3537Syasuoka 
3960fbf3537Syasuoka 	_this = ctx;
3970fbf3537Syasuoka 	PPTP_CTRL_ASSERT(_this != NULL);
3980fbf3537Syasuoka 
3990fbf3537Syasuoka 	_this->on_io_event = 1;
4000fbf3537Syasuoka 	if ((evmask & EV_WRITE) != 0) {
4010fbf3537Syasuoka 		if (pptp_ctrl_output_flush(_this) != 0 ||
4020fbf3537Syasuoka 		    _this->state == PPTP_CTRL_STATE_DISPOSING)
403f0a4e295Syasuoka 			goto fail;
4040fbf3537Syasuoka 		_this->send_ready = 1;
4050fbf3537Syasuoka 	}
4060fbf3537Syasuoka 	if ((evmask & EV_READ) != 0) {
4070fbf3537Syasuoka 		sz = read(_this->sock, bytebuffer_pointer(_this->recv_buf),
4080fbf3537Syasuoka 		    bytebuffer_remaining(_this->recv_buf));
4090fbf3537Syasuoka 		if (sz <= 0) {
4109a200ddfSyasuoka 			if (sz == 0 || errno == ECONNRESET) {
4110fbf3537Syasuoka 				pptp_ctrl_log(_this, LOG_INFO,
4120fbf3537Syasuoka 				    "Connection closed by foreign host");
4130fbf3537Syasuoka 				pptp_ctrl_fini(_this);
414f0a4e295Syasuoka 				goto fail;
4150fbf3537Syasuoka 			} else if (errno != EAGAIN && errno != EINTR) {
4160fbf3537Syasuoka 				pptp_ctrl_log(_this, LOG_INFO,
4170fbf3537Syasuoka 				    "read() failed at %s(): %m", __func__);
4180fbf3537Syasuoka 				pptp_ctrl_fini(_this);
419f0a4e295Syasuoka 				goto fail;
4200fbf3537Syasuoka 			}
4210fbf3537Syasuoka 		}
4220fbf3537Syasuoka 		bytebuffer_put(_this->recv_buf, BYTEBUFFER_PUT_DIRECT, sz);
4230fbf3537Syasuoka 		bytebuffer_flip(_this->recv_buf);
4240fbf3537Syasuoka 
4250fbf3537Syasuoka 		for (;;) {
4260fbf3537Syasuoka 			pkt = bytebuffer_pointer(_this->recv_buf);
4270fbf3537Syasuoka 			lpkt = bytebuffer_remaining(_this->recv_buf);
4280fbf3537Syasuoka 			if (pkt == NULL ||
4290fbf3537Syasuoka 			    lpkt < sizeof(struct pptp_ctrl_header))
4300fbf3537Syasuoka 				break;	/* read again */
4310fbf3537Syasuoka 
4320fbf3537Syasuoka 			hdrlen = pkt[0] << 8 | pkt[1];
4330fbf3537Syasuoka 			if (lpkt < hdrlen)
4340fbf3537Syasuoka 				break;	/* read again */
4350fbf3537Syasuoka 
4360fbf3537Syasuoka 			bytebuffer_get(_this->recv_buf, NULL, hdrlen);
4370fbf3537Syasuoka 			if (pptp_ctrl_input(_this, pkt, hdrlen) != 0 ||
4380fbf3537Syasuoka 			    _this->state == PPTP_CTRL_STATE_DISPOSING) {
4390fbf3537Syasuoka 				bytebuffer_compact(_this->recv_buf);
440f0a4e295Syasuoka 				goto fail;
4410fbf3537Syasuoka 			}
4420fbf3537Syasuoka 		}
4430fbf3537Syasuoka 		bytebuffer_compact(_this->recv_buf);
4440fbf3537Syasuoka 	}
4450fbf3537Syasuoka 	if (pptp_ctrl_output_flush(_this) != 0)
446f0a4e295Syasuoka 		goto fail;
4470fbf3537Syasuoka 	pptp_ctrl_set_io_event(_this);
448f0a4e295Syasuoka fail:
4490fbf3537Syasuoka 	_this->on_io_event = 0;
4500fbf3537Syasuoka }
4510fbf3537Syasuoka 
4520fbf3537Syasuoka 
453f0a4e295Syasuoka /* set i/o event mask */
4540fbf3537Syasuoka static void
pptp_ctrl_set_io_event(pptp_ctrl * _this)4550fbf3537Syasuoka pptp_ctrl_set_io_event(pptp_ctrl *_this)
4560fbf3537Syasuoka {
4570fbf3537Syasuoka 	int evmask;
4580fbf3537Syasuoka 
4590fbf3537Syasuoka 	PPTP_CTRL_ASSERT(_this != NULL);
4600fbf3537Syasuoka 	PPTP_CTRL_ASSERT(_this->sock >= 0);
4610fbf3537Syasuoka 
4620fbf3537Syasuoka 	evmask = 0;
4630fbf3537Syasuoka 	if (bytebuffer_remaining(_this->recv_buf) > 128)
4640fbf3537Syasuoka 		evmask |= EV_READ;
4650fbf3537Syasuoka 	if (_this->send_ready == 0)
4660fbf3537Syasuoka 		evmask |= EV_WRITE;
4670fbf3537Syasuoka 
4680fbf3537Syasuoka 	event_del(&_this->ev_sock);
4690fbf3537Syasuoka 	if (evmask != 0) {
4700fbf3537Syasuoka 		event_set(&_this->ev_sock, _this->sock, evmask,
4710fbf3537Syasuoka 		    pptp_ctrl_io_event, _this);
4720fbf3537Syasuoka 		event_add(&_this->ev_sock, NULL);
4730fbf3537Syasuoka 	}
4740fbf3537Syasuoka }
4750fbf3537Syasuoka 
4760fbf3537Syasuoka /**
477f0a4e295Syasuoka  * Output PPTP control packet
478f0a4e295Syasuoka  * @param pkt	pointer to packet buffer.
479f0a4e295Syasuoka  *		when it was appended by _this-.send_buf using bytebuffer,
480f0a4e295Syasuoka  *		specify NULL.
481f0a4e295Syasuoka  * @param lpkt	packet length
4820fbf3537Syasuoka  */
4830fbf3537Syasuoka void
pptp_ctrl_output(pptp_ctrl * _this,u_char * pkt,int lpkt)4840fbf3537Syasuoka pptp_ctrl_output(pptp_ctrl *_this, u_char *pkt, int lpkt)
4850fbf3537Syasuoka {
4860fbf3537Syasuoka 	PPTP_CTRL_ASSERT(_this != NULL);
4870fbf3537Syasuoka 	PPTP_CTRL_ASSERT(lpkt > 0);
4880fbf3537Syasuoka 
489f0a4e295Syasuoka 	/* just put the packet into the buffer now.  send it later */
4900fbf3537Syasuoka 	bytebuffer_put(_this->send_buf, pkt, lpkt);
4910fbf3537Syasuoka 
4920fbf3537Syasuoka 	if (_this->on_io_event != 0) {
493f0a4e295Syasuoka 		/*
494f0a4e295Syasuoka 		 * pptp_ctrl_output_flush() will be called by the end of
495f0a4e295Syasuoka 		 * the I/O event handler.
496f0a4e295Syasuoka 		 */
4970fbf3537Syasuoka 	} else {
4980fbf3537Syasuoka 		/*
499f0a4e295Syasuoka 		 * When this function is called by other than I/O event handler,
500f0a4e295Syasuoka 		 * we need to call pptp_ctrl_output_flush().  However if we do
501f0a4e295Syasuoka 		 * it here, then we need to consider the situation
502f0a4e295Syasuoka 		 * 'flush => write failure => finalize'.  The situation requires
503f0a4e295Syasuoka 		 * the caller function to handle the exception and causes
504f0a4e295Syasuoka 		 * complication.  So we call pptp_ctrl_output_flush() by the
505f0a4e295Syasuoka 		 * the next send ready event.
5060fbf3537Syasuoka 		 */
507f0a4e295Syasuoka 		_this->send_ready = 0;		/* clear 'send ready' */
508f0a4e295Syasuoka 		pptp_ctrl_set_io_event(_this);	/* wait 'send ready */
5090fbf3537Syasuoka 	}
5100fbf3537Syasuoka 
5110fbf3537Syasuoka 	return;
5120fbf3537Syasuoka }
5130fbf3537Syasuoka 
514f0a4e295Syasuoka /* Send Stop-Control-Connection-Request */
5150fbf3537Syasuoka 
516f0a4e295Syasuoka /* flush output packet */
5170fbf3537Syasuoka static int
pptp_ctrl_output_flush(pptp_ctrl * _this)5180fbf3537Syasuoka pptp_ctrl_output_flush(pptp_ctrl *_this)
5190fbf3537Syasuoka {
5200fbf3537Syasuoka 	int sz;
5210fbf3537Syasuoka 	time_t curr_time;
5220fbf3537Syasuoka 
5230fbf3537Syasuoka 	curr_time = get_monosec();
5240fbf3537Syasuoka 
5250fbf3537Syasuoka 	if (bytebuffer_position(_this->send_buf) <= 0)
526f0a4e295Syasuoka 		return 0;		/* nothing to write */
5270fbf3537Syasuoka 	if (_this->send_ready == 0) {
5280fbf3537Syasuoka 		pptp_ctrl_set_io_event(_this);
529f0a4e295Syasuoka 		return 0;		/* not ready to write */
5300fbf3537Syasuoka 	}
5310fbf3537Syasuoka 
5320fbf3537Syasuoka 	bytebuffer_flip(_this->send_buf);
5330fbf3537Syasuoka 
534821f7c56Syasuoka 	if (PPTP_CTRL_CONF(_this)->ctrl_out_pktdump != 0) {
5350fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_DEBUG, "PPTP Control output packet");
5360fbf3537Syasuoka 		show_hd(debug_get_debugfp(),
5370fbf3537Syasuoka 		    bytebuffer_pointer(_this->send_buf),
5380fbf3537Syasuoka 		    bytebuffer_remaining(_this->send_buf));
5390fbf3537Syasuoka 	}
5400fbf3537Syasuoka 	if ((sz = write(_this->sock, bytebuffer_pointer(_this->send_buf),
5410fbf3537Syasuoka 	    bytebuffer_remaining(_this->send_buf))) < 0) {
5420fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR, "write to socket failed: %m");
5430fbf3537Syasuoka 		pptp_ctrl_fini(_this);
5440fbf3537Syasuoka 
5450fbf3537Syasuoka 		return 1;
5460fbf3537Syasuoka 	}
5470fbf3537Syasuoka 	_this->last_snd_ctrl = curr_time;
5480fbf3537Syasuoka 	bytebuffer_get(_this->send_buf, NULL, sz);
5490fbf3537Syasuoka 	bytebuffer_compact(_this->send_buf);
5500fbf3537Syasuoka 	_this->send_ready = 0;
5510fbf3537Syasuoka 
5520fbf3537Syasuoka 	return 0;
5530fbf3537Syasuoka }
5540fbf3537Syasuoka 
555f0a4e295Syasuoka /* convert Start-Control-Connection-{Request,Reply} packet to strings */
5560fbf3537Syasuoka static void
pptp_ctrl_SCCRx_string(struct pptp_scc * scc,u_char * buf,int lbuf)5570fbf3537Syasuoka pptp_ctrl_SCCRx_string(struct pptp_scc *scc, u_char *buf, int lbuf)
5580fbf3537Syasuoka {
5593e92b40aSyasuoka 	char results[128];
5600fbf3537Syasuoka 
5610fbf3537Syasuoka 	if (scc->result_code != 0)
5623e92b40aSyasuoka 		snprintf(results, sizeof(results), "result=%d error=%d ",
5630fbf3537Syasuoka 		    scc->result_code, scc->error_code);
5640fbf3537Syasuoka 	else
5653e92b40aSyasuoka 		results[0] = '\0';
5660fbf3537Syasuoka 
5670fbf3537Syasuoka 	snprintf(buf, lbuf,
5680fbf3537Syasuoka 	    "protocol_version=%d.%d %sframing=%s bearer=%s max_channels=%d "
5693e92b40aSyasuoka 	    "firmware_revision=%d(0x%04x) host_name=\"%.*s\" "
5703e92b40aSyasuoka 	    "vendor_string=\"%.*s\"",
5713e92b40aSyasuoka 	    scc->protocol_version >> 8, scc->protocol_version & 0xff, results,
5720fbf3537Syasuoka 	    pptp_framing_string(scc->framing_caps),
5730fbf3537Syasuoka 	    pptp_bearer_string(scc->bearer_caps), scc->max_channels,
5743e92b40aSyasuoka 	    scc->firmware_revision, scc->firmware_revision,
5753e92b40aSyasuoka 	    (u_int)sizeof(scc->host_name), scc->host_name,
5763e92b40aSyasuoka 	    (u_int)sizeof(scc->vendor_string), scc->vendor_string);
5770fbf3537Syasuoka }
5780fbf3537Syasuoka 
579f0a4e295Syasuoka /* receive Start-Control-Connection-Request */
5800fbf3537Syasuoka static int
pptp_ctrl_recv_SCCRQ(pptp_ctrl * _this,u_char * pkt,int lpkt)5810fbf3537Syasuoka pptp_ctrl_recv_SCCRQ(pptp_ctrl *_this, u_char *pkt, int lpkt)
5820fbf3537Syasuoka {
5830fbf3537Syasuoka 	char logbuf[512];
5840fbf3537Syasuoka 	struct pptp_scc *scc;
5850fbf3537Syasuoka 
586f0a4e295Syasuoka 	/* sanity check */
5870fbf3537Syasuoka 	if (lpkt < sizeof(struct pptp_scc)) {
5880fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR, "Received bad SCCRQ: packet too "
5890fbf3537Syasuoka 		    "short: %d < %d", lpkt, (int)sizeof(struct pptp_scc));
5900fbf3537Syasuoka 		return 1;
5910fbf3537Syasuoka 	}
5920fbf3537Syasuoka 	scc = (struct pptp_scc *)pkt;
5930fbf3537Syasuoka 
5940fbf3537Syasuoka 	scc->protocol_version = ntohs(scc->protocol_version);
5950fbf3537Syasuoka 	scc->framing_caps = htonl(scc->framing_caps);
5960fbf3537Syasuoka 	scc->bearer_caps = htonl(scc->bearer_caps);
5970fbf3537Syasuoka 	scc->max_channels = htons(scc->max_channels);
5980fbf3537Syasuoka 	scc->firmware_revision = htons(scc->firmware_revision);
5990fbf3537Syasuoka 
600f0a4e295Syasuoka 	/* check protocol version */
6010fbf3537Syasuoka 	if (scc->protocol_version != PPTP_RFC_2637_VERSION) {
6020fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR, "Received bad SCCRQ: "
6030fbf3537Syasuoka 		    "unknown protocol version %d", scc->protocol_version);
6040fbf3537Syasuoka 		return 1;
6050fbf3537Syasuoka 	}
6060fbf3537Syasuoka 
6070fbf3537Syasuoka 	pptp_ctrl_SCCRx_string(scc, logbuf, sizeof(logbuf));
6080fbf3537Syasuoka 	pptp_ctrl_log(_this, LOG_INFO, "RecvSCCRQ %s", logbuf);
6090fbf3537Syasuoka 
6100fbf3537Syasuoka 	return 0;
6110fbf3537Syasuoka }
6120fbf3537Syasuoka 
613f0a4e295Syasuoka /* Receive Stop-Control-Connection-Reply */
6140fbf3537Syasuoka static int
pptp_ctrl_recv_StopCCRP(pptp_ctrl * _this,u_char * pkt,int lpkt)6150fbf3537Syasuoka pptp_ctrl_recv_StopCCRP(pptp_ctrl *_this, u_char *pkt, int lpkt)
6160fbf3537Syasuoka {
6170fbf3537Syasuoka 	struct pptp_stop_ccrp *stop_ccrp;
6180fbf3537Syasuoka 
6190fbf3537Syasuoka 	if (lpkt < sizeof(struct pptp_stop_ccrp)) {
6200fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR, "Received bad StopCCRP: packet "
6210fbf3537Syasuoka 		    "too short: %d < %d", lpkt,
6220fbf3537Syasuoka 		    (int)sizeof(struct pptp_stop_ccrp));
6230fbf3537Syasuoka 		return 1;
6240fbf3537Syasuoka 	}
6250fbf3537Syasuoka 	stop_ccrp = (struct pptp_stop_ccrp *)pkt;
6260fbf3537Syasuoka 
6270fbf3537Syasuoka 	pptp_ctrl_log(_this, LOG_INFO, "RecvStopCCRP reason=%s(%u)",
6280fbf3537Syasuoka 	    pptp_StopCCRP_result_string(stop_ccrp->result), stop_ccrp->result);
6290fbf3537Syasuoka 
6300fbf3537Syasuoka 	return 0;
6310fbf3537Syasuoka }
6320fbf3537Syasuoka 
6330fbf3537Syasuoka static int
pptp_ctrl_send_StopCCRQ(pptp_ctrl * _this,int reason)6340fbf3537Syasuoka pptp_ctrl_send_StopCCRQ(pptp_ctrl *_this, int reason)
6350fbf3537Syasuoka {
6360fbf3537Syasuoka 	int lpkt;
6370fbf3537Syasuoka 	struct pptp_stop_ccrq *stop_ccrq;
6380fbf3537Syasuoka 
6390fbf3537Syasuoka 	stop_ccrq = bytebuffer_pointer(_this->send_buf);
6400fbf3537Syasuoka 	lpkt = bytebuffer_remaining(_this->send_buf);
6410fbf3537Syasuoka 	if (lpkt < sizeof(struct pptp_stop_ccrq)) {
6420fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR,
6430fbf3537Syasuoka 		    "SendCCRP failed: No buffer space available");
6440fbf3537Syasuoka 		return -1;
6450fbf3537Syasuoka 	}
6460fbf3537Syasuoka 	memset(stop_ccrq, 0, sizeof(struct pptp_stop_ccrq));
6470fbf3537Syasuoka 
6480fbf3537Syasuoka 	pptp_init_header(&stop_ccrq->header, sizeof(struct pptp_stop_ccrq),
6490fbf3537Syasuoka 	    PPTP_CTRL_MES_CODE_StopCCRQ);
6500fbf3537Syasuoka 
6510fbf3537Syasuoka 	stop_ccrq->reason = reason;
6520fbf3537Syasuoka 
6530fbf3537Syasuoka 	pptp_ctrl_log(_this, LOG_INFO, "SendStopCCRQ reason=%s(%u)",
6540fbf3537Syasuoka 	    pptp_StopCCRQ_reason_string(stop_ccrq->reason), stop_ccrq->reason);
6550fbf3537Syasuoka 
6560fbf3537Syasuoka 	pptp_ctrl_output(_this, NULL, sizeof(struct pptp_stop_ccrq));
6570fbf3537Syasuoka 
6580fbf3537Syasuoka 	return 0;
6590fbf3537Syasuoka }
6600fbf3537Syasuoka 
661f0a4e295Syasuoka /* Receive Stop-Control-Connection-Request */
6620fbf3537Syasuoka static int
pptp_ctrl_recv_StopCCRQ(pptp_ctrl * _this,u_char * pkt,int lpkt)6630fbf3537Syasuoka pptp_ctrl_recv_StopCCRQ(pptp_ctrl *_this, u_char *pkt, int lpkt)
6640fbf3537Syasuoka {
6650fbf3537Syasuoka 	struct pptp_stop_ccrq *stop_ccrq;
6660fbf3537Syasuoka 
6670fbf3537Syasuoka 	if (lpkt < sizeof(struct pptp_stop_ccrq)) {
6680fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR, "Received bad StopCCRQ: packet "
6690fbf3537Syasuoka 		    "too short: %d < %d", lpkt,
6700fbf3537Syasuoka 		    (int)sizeof(struct pptp_stop_ccrq));
6710fbf3537Syasuoka 		return 1;
6720fbf3537Syasuoka 	}
6730fbf3537Syasuoka 	stop_ccrq = (struct pptp_stop_ccrq *)pkt;
6740fbf3537Syasuoka 
6750fbf3537Syasuoka 	pptp_ctrl_log(_this, LOG_INFO, "RecvStopCCRQ reason=%s(%u)",
6760fbf3537Syasuoka 	    pptp_StopCCRQ_reason_string(stop_ccrq->reason), stop_ccrq->reason);
6770fbf3537Syasuoka 
6780fbf3537Syasuoka 	return 0;
6790fbf3537Syasuoka }
6800fbf3537Syasuoka 
681f0a4e295Syasuoka /* Send Stop-Control-Connection-Reply */
6820fbf3537Syasuoka static int
pptp_ctrl_send_StopCCRP(pptp_ctrl * _this,int result,int error)6830fbf3537Syasuoka pptp_ctrl_send_StopCCRP(pptp_ctrl *_this, int result, int error)
6840fbf3537Syasuoka {
6850fbf3537Syasuoka 	int lpkt;
6860fbf3537Syasuoka 	struct pptp_stop_ccrp *stop_ccrp;
6870fbf3537Syasuoka 
6880fbf3537Syasuoka 	stop_ccrp = bytebuffer_pointer(_this->send_buf);
6890fbf3537Syasuoka 
6900fbf3537Syasuoka 	lpkt = bytebuffer_remaining(_this->send_buf);
6910fbf3537Syasuoka 	if (lpkt < sizeof(struct pptp_stop_ccrp)) {
6920fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR,
6930fbf3537Syasuoka 		    "SendCCRQ failed: No buffer space available");
6940fbf3537Syasuoka 		return -1;
6950fbf3537Syasuoka 	}
6960fbf3537Syasuoka 	memset(stop_ccrp, 0, sizeof(struct pptp_stop_ccrp));
6970fbf3537Syasuoka 
6980fbf3537Syasuoka 	pptp_init_header(&stop_ccrp->header, sizeof(struct pptp_stop_ccrp),
6990fbf3537Syasuoka 	    PPTP_CTRL_MES_CODE_StopCCRP);
7000fbf3537Syasuoka 
7010fbf3537Syasuoka 	stop_ccrp->result = result;
7020fbf3537Syasuoka 	stop_ccrp->error = error;
7030fbf3537Syasuoka 
7040fbf3537Syasuoka 	pptp_ctrl_log(_this, LOG_INFO,
7050fbf3537Syasuoka 	    "SendStopCCRP result=%s(%u) error=%s(%u)",
7060fbf3537Syasuoka 	    pptp_StopCCRP_result_string(stop_ccrp->result), stop_ccrp->result,
7070fbf3537Syasuoka 	    pptp_general_error_string(stop_ccrp->error), stop_ccrp->error);
7080fbf3537Syasuoka 
7090fbf3537Syasuoka 	pptp_ctrl_output(_this, NULL, sizeof(struct pptp_stop_ccrp));
7100fbf3537Syasuoka 
7110fbf3537Syasuoka 	return 0;
7120fbf3537Syasuoka }
7130fbf3537Syasuoka 
714f0a4e295Syasuoka /* Send Start-Control-Connection-Reply */
7150fbf3537Syasuoka static int
pptp_ctrl_send_SCCRP(pptp_ctrl * _this,int result,int error)7160fbf3537Syasuoka pptp_ctrl_send_SCCRP(pptp_ctrl *_this, int result, int error)
7170fbf3537Syasuoka {
7180fbf3537Syasuoka 	int lpkt;
7190fbf3537Syasuoka 	struct pptp_scc *scc;
7200fbf3537Syasuoka 	char logbuf[512];
7210fbf3537Syasuoka 	const char *val;
7220fbf3537Syasuoka 
7230fbf3537Syasuoka 	scc = bytebuffer_pointer(_this->send_buf);
7240fbf3537Syasuoka 	lpkt = bytebuffer_remaining(_this->send_buf);
7250fbf3537Syasuoka 	if (lpkt < sizeof(struct pptp_scc)) {
7260fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR,
7270fbf3537Syasuoka 		    "SendSCCRP failed: No buffer space available");
7280fbf3537Syasuoka 		return -1;
7290fbf3537Syasuoka 	}
7300fbf3537Syasuoka 	memset(scc, 0, sizeof(struct pptp_scc));
7310fbf3537Syasuoka 
7320fbf3537Syasuoka 	pptp_init_header(&scc->header, sizeof(struct pptp_scc),
7330fbf3537Syasuoka 	    PPTP_CTRL_MES_CODE_SCCRP);
7340fbf3537Syasuoka 
7350fbf3537Syasuoka 	scc->protocol_version = PPTP_RFC_2637_VERSION;
7360fbf3537Syasuoka 	scc->result_code = result;
7370fbf3537Syasuoka 	scc->error_code = error;
738f0a4e295Syasuoka 
739f0a4e295Syasuoka 	/* XXX only support sync frames */
7400fbf3537Syasuoka 	scc->framing_caps = PPTP_CTRL_FRAMING_SYNC;
7410fbf3537Syasuoka 	scc->bearer_caps = PPTP_CTRL_BEARER_DIGITAL;
7420fbf3537Syasuoka 
743f0a4e295Syasuoka 	scc->max_channels = 4;		/* XXX */
7440fbf3537Syasuoka 	scc->firmware_revision = MAJOR_VERSION << 8 | MINOR_VERSION;
7450fbf3537Syasuoka 
746f0a4e295Syasuoka 	/* this implementation only support these strings up to
747f0a4e295Syasuoka 	 * 63 character */
748f0a4e295Syasuoka 	/* host name */
749821f7c56Syasuoka 
750e402d49cSyasuoka 	if ((val = PPTP_CTRL_CONF(_this)->hostname) == NULL)
7510fbf3537Syasuoka 		val = "";
7520fbf3537Syasuoka 	strlcpy(scc->host_name, val, sizeof(scc->host_name));
7530fbf3537Syasuoka 
754*f5c2ff87Syasuoka 	/* vendor name */
755821f7c56Syasuoka 	if (PPTP_CTRL_CONF(_this)->vendor_name == NULL)
7560fbf3537Syasuoka 		val = PPTPD_DEFAULT_VENDOR_NAME;
7570fbf3537Syasuoka 	strlcpy(scc->vendor_string, val, sizeof(scc->vendor_string));
7580fbf3537Syasuoka 
7590fbf3537Syasuoka 	pptp_ctrl_SCCRx_string(scc, logbuf, sizeof(logbuf));
7600fbf3537Syasuoka 	pptp_ctrl_log(_this, LOG_INFO, "SendSCCRP %s", logbuf);
7610fbf3537Syasuoka 
7620fbf3537Syasuoka 	scc->protocol_version = htons(scc->protocol_version);
7630fbf3537Syasuoka 	scc->framing_caps = htonl(scc->framing_caps);
7640fbf3537Syasuoka 	scc->bearer_caps = htonl(scc->bearer_caps);
7650fbf3537Syasuoka 	scc->max_channels = htons(scc->max_channels);
7660fbf3537Syasuoka 	scc->firmware_revision = htons(scc->firmware_revision);
7670fbf3537Syasuoka 
7680fbf3537Syasuoka 	pptp_ctrl_output(_this, NULL, sizeof(struct pptp_scc));
7690fbf3537Syasuoka 
7700fbf3537Syasuoka 	return 0;
7710fbf3537Syasuoka }
7720fbf3537Syasuoka 
773f0a4e295Syasuoka /* receive ECHO and reply */
7740fbf3537Syasuoka static void
pptp_ctrl_process_echo_req(pptp_ctrl * _this,u_char * pkt,int lpkt)7750fbf3537Syasuoka pptp_ctrl_process_echo_req(pptp_ctrl *_this, u_char *pkt, int lpkt)
7760fbf3537Syasuoka {
7770fbf3537Syasuoka 	struct pptp_echo_rq *echo_rq;
7780fbf3537Syasuoka 	struct pptp_echo_rp *echo_rp;
7790fbf3537Syasuoka 
7800fbf3537Syasuoka 	if (lpkt < sizeof(struct pptp_echo_rq)) {
7810fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR, "Received bad EchoReq: packet "
7820fbf3537Syasuoka 		    "too short: %d < %d", lpkt,
7830fbf3537Syasuoka 		    (int)sizeof(struct pptp_echo_rq));
7840fbf3537Syasuoka 		return;
7850fbf3537Syasuoka 	}
7860fbf3537Syasuoka 	echo_rq = (struct pptp_echo_rq *)pkt;
7870fbf3537Syasuoka 
7880fbf3537Syasuoka 	PPTP_CTRL_DBG((_this, LOG_DEBUG, "RecvEchoReq"));
7890fbf3537Syasuoka 
7900fbf3537Syasuoka 	echo_rp = bytebuffer_pointer(_this->send_buf);
7910fbf3537Syasuoka 	lpkt = bytebuffer_remaining(_this->send_buf);
7920fbf3537Syasuoka 	if (echo_rp == NULL || lpkt < sizeof(struct pptp_echo_rp)) {
7930fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR,
7940fbf3537Syasuoka 		    "Failed to send EchoReq: No buffer space available");
7950fbf3537Syasuoka 		return;
7960fbf3537Syasuoka 	}
7970fbf3537Syasuoka 	memset(echo_rp, 0, sizeof(struct pptp_echo_rp));
7980fbf3537Syasuoka 
7990fbf3537Syasuoka 	pptp_init_header(&echo_rp->header, sizeof(struct pptp_echo_rp),
8000fbf3537Syasuoka 	    PPTP_CTRL_MES_CODE_ECHO_RP);
8010fbf3537Syasuoka 
8020fbf3537Syasuoka 	echo_rp->identifier = echo_rq->identifier;
8030fbf3537Syasuoka 	echo_rp->result_code = PPTP_ECHO_RP_RESULT_OK;
8040fbf3537Syasuoka 	echo_rp->error_code = PPTP_ERROR_NONE;
8050fbf3537Syasuoka 	echo_rp->reserved1 = htons(0);
8060fbf3537Syasuoka 
8070fbf3537Syasuoka 	pptp_ctrl_output(_this, NULL, sizeof(struct pptp_echo_rp));
8080fbf3537Syasuoka 	PPTP_CTRL_DBG((_this, LOG_DEBUG, "SendEchoReply"));
8090fbf3537Syasuoka }
8100fbf3537Syasuoka 
811f0a4e295Syasuoka /* receiver Echo-Reply */
8120fbf3537Syasuoka static int
pptp_ctrl_recv_echo_rep(pptp_ctrl * _this,u_char * pkt,int lpkt)8130fbf3537Syasuoka pptp_ctrl_recv_echo_rep(pptp_ctrl *_this, u_char *pkt, int lpkt)
8140fbf3537Syasuoka {
8150fbf3537Syasuoka 	struct pptp_echo_rp *echo_rp;
8160fbf3537Syasuoka 
8170fbf3537Syasuoka 	if (lpkt < sizeof(struct pptp_echo_rp)) {
8180fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR, "Received bad EchoReq: packet "
8190fbf3537Syasuoka 		    "too short: %d < %d", lpkt,
8200fbf3537Syasuoka 		    (int)sizeof(struct pptp_echo_rp));
8210fbf3537Syasuoka 		return 1;
8220fbf3537Syasuoka 	}
8230fbf3537Syasuoka 	echo_rp = (struct pptp_echo_rp *)pkt;
8240fbf3537Syasuoka 
8250fbf3537Syasuoka 	if (echo_rp->result_code != PPTP_ECHO_RP_RESULT_OK) {
8260fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR, "Received negative EchoReply: %s",
8270fbf3537Syasuoka 		    pptp_general_error_string(echo_rp->error_code));
8280fbf3537Syasuoka 		return 1;
8290fbf3537Syasuoka 	}
8300fbf3537Syasuoka 	if (_this->echo_seq != ntohl(echo_rp->identifier)) {
8310fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR, "Received bad EchoReply: "
8320fbf3537Syasuoka 		    "Identifier mismatch sent=%u recv=%u",
8330fbf3537Syasuoka 		    _this->echo_seq , ntohl(echo_rp->identifier));
8340fbf3537Syasuoka 		return 1;
8350fbf3537Syasuoka 	}
8360fbf3537Syasuoka 	PPTP_CTRL_DBG((_this, LOG_DEBUG, "RecvEchoReply"));
8370fbf3537Syasuoka 	return 0;
8380fbf3537Syasuoka }
8390fbf3537Syasuoka 
840f0a4e295Syasuoka /* send Echo-Request */
8410fbf3537Syasuoka static void
pptp_ctrl_send_echo_req(pptp_ctrl * _this)8420fbf3537Syasuoka pptp_ctrl_send_echo_req(pptp_ctrl *_this)
8430fbf3537Syasuoka {
8440fbf3537Syasuoka 	int lpkt;
8450fbf3537Syasuoka 	struct pptp_echo_rq *echo_rq;
8460fbf3537Syasuoka 
8470fbf3537Syasuoka 	echo_rq = (struct pptp_echo_rq *)bytebuffer_pointer(_this->send_buf);
8480fbf3537Syasuoka 	lpkt = bytebuffer_remaining(_this->send_buf);
8490fbf3537Syasuoka 	if (echo_rq == NULL || lpkt < sizeof(struct pptp_echo_rq)) {
8500fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR,
8510fbf3537Syasuoka 		    "SendEchoReq failed: No buffer space available");
8520fbf3537Syasuoka 		return;
8530fbf3537Syasuoka 	}
8540fbf3537Syasuoka 	memset(echo_rq, 0, sizeof(struct pptp_echo_rq));
8550fbf3537Syasuoka 
8560fbf3537Syasuoka 	pptp_init_header(&echo_rq->header, sizeof(struct pptp_echo_rq),
8570fbf3537Syasuoka 	    PPTP_CTRL_MES_CODE_ECHO_RQ);
8580fbf3537Syasuoka 
8590fbf3537Syasuoka 	echo_rq->identifier = htonl(_this->echo_seq);
8600fbf3537Syasuoka 
8610fbf3537Syasuoka 	pptp_ctrl_output(_this, NULL, sizeof(struct pptp_echo_rq));
8620fbf3537Syasuoka 	PPTP_CTRL_DBG((_this, LOG_DEBUG, "SendEchoReq"));
8630fbf3537Syasuoka }
8640fbf3537Syasuoka 
865f0a4e295Syasuoka /* send Call-Disconnect-Notify */
8660fbf3537Syasuoka static void
pptp_ctrl_send_CDN(pptp_ctrl * _this,int result,int error,int cause,const char * statistics)8670fbf3537Syasuoka pptp_ctrl_send_CDN(pptp_ctrl *_this, int result, int error, int cause,
8680fbf3537Syasuoka     const char *statistics)
8690fbf3537Syasuoka {
8700fbf3537Syasuoka 	int lpkt;
8710fbf3537Syasuoka 	struct pptp_cdn *cdn;
8720fbf3537Syasuoka 
8730fbf3537Syasuoka 	cdn = bytebuffer_pointer(_this->send_buf);
8740fbf3537Syasuoka 	lpkt = bytebuffer_remaining(_this->send_buf);
8750fbf3537Syasuoka 	if (lpkt < sizeof(struct pptp_cdn)) {
8760fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_ERR,
8770fbf3537Syasuoka 		    "SendCCR failed: No buffer space available");
8780fbf3537Syasuoka 		return;
8790fbf3537Syasuoka 	}
8800fbf3537Syasuoka 	memset(cdn, 0, sizeof(struct pptp_cdn));
8810fbf3537Syasuoka 
8820fbf3537Syasuoka 	pptp_init_header(&cdn->header, sizeof(struct pptp_cdn),
8830fbf3537Syasuoka 	    PPTP_CTRL_MES_CODE_CDN);
8840fbf3537Syasuoka 
8850fbf3537Syasuoka 	cdn->call_id = _this->id;
8860fbf3537Syasuoka 	cdn->result_code = result;
8870fbf3537Syasuoka 	cdn->error_code = error;
8880fbf3537Syasuoka 	cdn->cause_code = cause;
8890fbf3537Syasuoka 	if (statistics != NULL)
8900fbf3537Syasuoka 		strlcpy(cdn->statistics, statistics, sizeof(cdn->statistics));
8910fbf3537Syasuoka 
8920fbf3537Syasuoka 	cdn->call_id = htons(cdn->call_id);
8930fbf3537Syasuoka 	cdn->cause_code = htons(cdn->cause_code);
8940fbf3537Syasuoka 
8950fbf3537Syasuoka 	pptp_ctrl_output(_this, NULL, sizeof(struct pptp_cdn));
8960fbf3537Syasuoka }
8970fbf3537Syasuoka 
898f0a4e295Syasuoka /* receive Control-packet */
8990fbf3537Syasuoka static int
pptp_ctrl_input(pptp_ctrl * _this,u_char * pkt,int lpkt)9000fbf3537Syasuoka pptp_ctrl_input(pptp_ctrl *_this, u_char *pkt, int lpkt)
9010fbf3537Syasuoka {
9020fbf3537Syasuoka 	char errmes[256];
9030fbf3537Syasuoka 	time_t curr_time;
9040fbf3537Syasuoka 	struct pptp_ctrl_header *hdr;
9050fbf3537Syasuoka 
9060fbf3537Syasuoka 	PPTP_CTRL_ASSERT(lpkt >= sizeof(struct pptp_ctrl_header));
9070fbf3537Syasuoka 
9080fbf3537Syasuoka 	curr_time = get_monosec();
9090fbf3537Syasuoka 	hdr = (struct pptp_ctrl_header *)pkt;
9100fbf3537Syasuoka 
9110fbf3537Syasuoka 	hdr->length = ntohs(hdr->length);
9120fbf3537Syasuoka 	hdr->pptp_message_type  = ntohs(hdr->pptp_message_type);
9130fbf3537Syasuoka 	hdr->magic_cookie  = ntohl(hdr->magic_cookie);
9140fbf3537Syasuoka 	hdr->control_message_type = ntohs(hdr->control_message_type);
9150fbf3537Syasuoka 	hdr->reserved0 = ntohs(hdr->reserved0);
9160fbf3537Syasuoka 
917f0a4e295Syasuoka 	/* sanity check */
9180fbf3537Syasuoka 	PPTP_CTRL_ASSERT(hdr->length <= lpkt);
9190fbf3537Syasuoka 
9200fbf3537Syasuoka 	_this->last_rcv_ctrl = curr_time;
9210fbf3537Syasuoka 
922821f7c56Syasuoka 	if (PPTP_CTRL_CONF(_this)->ctrl_in_pktdump != 0) {
9230fbf3537Syasuoka 		pptp_ctrl_log(_this, LOG_DEBUG,
9240fbf3537Syasuoka 		    "PPTP Control input packet dump: mestype=%s(%d)",
9250fbf3537Syasuoka 		    pptp_ctrl_mes_type_string(hdr->control_message_type),
9260fbf3537Syasuoka 		    hdr->control_message_type);
9270fbf3537Syasuoka 		show_hd(debug_get_debugfp(), pkt, lpkt);
9280fbf3537Syasuoka 	}
9290fbf3537Syasuoka 
930f0a4e295Syasuoka 	/* inspect packet body */
931f0a4e295Syasuoka 	/* message type */
9320fbf3537Syasuoka 	if (hdr->pptp_message_type != PPTP_MES_TYPE_CTRL) {
9330fbf3537Syasuoka 		snprintf(errmes, sizeof(errmes), "unknown message type %d",
9340fbf3537Syasuoka 		    hdr->pptp_message_type);
9350fbf3537Syasuoka 		goto bad_packet;
9360fbf3537Syasuoka 	}
937f0a4e295Syasuoka 	/* magic cookie */
9380fbf3537Syasuoka 	if (hdr->magic_cookie != PPTP_MAGIC_COOKIE) {
9390fbf3537Syasuoka 		snprintf(errmes, sizeof(errmes), "wrong magic %08x != %08x",
9400fbf3537Syasuoka 		    hdr->magic_cookie, PPTP_MAGIC_COOKIE);
9410fbf3537Syasuoka 		goto bad_packet;
9420fbf3537Syasuoka 	}
9430fbf3537Syasuoka 
944f0a4e295Syasuoka 	/* As there is possibility of state conflicts,
945f0a4e295Syasuoka 	 * ECHO Reply requiries special care.
946f0a4e295Syasuoka 	 */
9470fbf3537Syasuoka 	switch (hdr->control_message_type) {
9480fbf3537Syasuoka 	case PPTP_CTRL_MES_CODE_ECHO_RP:
9490fbf3537Syasuoka 		if (pptp_ctrl_recv_echo_rep(_this, pkt, lpkt) != 0) {
9500fbf3537Syasuoka 			pptp_ctrl_fini(_this);
9510fbf3537Syasuoka 			return 1;
9520fbf3537Syasuoka 		}
9530fbf3537Syasuoka 		return 0;
9540fbf3537Syasuoka 	}
955f0a4e295Syasuoka 
9560fbf3537Syasuoka 	/*
957f0a4e295Syasuoka 	 * State machine
9580fbf3537Syasuoka 	 */
9590fbf3537Syasuoka 	switch (_this->state) {
9600fbf3537Syasuoka 	case PPTP_CTRL_STATE_IDLE:
9610fbf3537Syasuoka 		switch (hdr->control_message_type) {
9620fbf3537Syasuoka 		case PPTP_CTRL_MES_CODE_SCCRQ:
9630fbf3537Syasuoka 			if (pptp_ctrl_recv_SCCRQ(_this, pkt, lpkt) != 0) {
9640fbf3537Syasuoka 				return 0;
9650fbf3537Syasuoka 			}
9660fbf3537Syasuoka 			if (pptp_ctrl_send_SCCRP(_this,
9670fbf3537Syasuoka 			    PPTP_SCCRP_RESULT_SUCCESS, PPTP_ERROR_NONE) != 0) {
9680fbf3537Syasuoka 				return 0;
9690fbf3537Syasuoka 			}
9700fbf3537Syasuoka 			_this->state = PPTP_CTRL_STATE_ESTABLISHED;
9710fbf3537Syasuoka 			return 0;
9720fbf3537Syasuoka 		default:
9730fbf3537Syasuoka 			break;
9740fbf3537Syasuoka 		}
9750fbf3537Syasuoka 		break;
9760fbf3537Syasuoka 	case PPTP_CTRL_STATE_ESTABLISHED:
9770fbf3537Syasuoka 		switch (hdr->control_message_type) {
9780fbf3537Syasuoka 		case PPTP_CTRL_MES_CODE_ECHO_RQ:
9790fbf3537Syasuoka 			pptp_ctrl_process_echo_req(_this, pkt, lpkt);
9800fbf3537Syasuoka 			return 0;
981f0a4e295Syasuoka 		/* dispatch to pptp_call_input() if it is call-related-packet */
9820fbf3537Syasuoka 		case PPTP_CTRL_MES_CODE_SLI:
9830fbf3537Syasuoka 		case PPTP_CTRL_MES_CODE_ICRQ:
9840fbf3537Syasuoka 		case PPTP_CTRL_MES_CODE_ICRP:
9850fbf3537Syasuoka 		case PPTP_CTRL_MES_CODE_OCRQ:
9860fbf3537Syasuoka 		case PPTP_CTRL_MES_CODE_OCRP:
9870fbf3537Syasuoka 		case PPTP_CTRL_MES_CODE_ICCN:
9880fbf3537Syasuoka 		case PPTP_CTRL_MES_CODE_CDN:
9890fbf3537Syasuoka 		case PPTP_CTRL_MES_CODE_CCR:
9900fbf3537Syasuoka 			return pptp_ctrl_call_input(_this,
9910fbf3537Syasuoka 			    hdr->control_message_type, pkt, lpkt);
9920fbf3537Syasuoka 		case PPTP_CTRL_MES_CODE_StopCCRQ:
9930fbf3537Syasuoka 			if (pptp_ctrl_recv_StopCCRQ(_this, pkt, lpkt) != 0) {
9940fbf3537Syasuoka 				pptp_ctrl_stop(_this,
9950fbf3537Syasuoka 				    PPTP_StopCCRQ_REASON_STOP_PROTOCOL);
9960fbf3537Syasuoka 				return 0;
9970fbf3537Syasuoka 			}
9980fbf3537Syasuoka 			if (pptp_ctrl_send_StopCCRP(_this,
9990fbf3537Syasuoka 				PPTP_StopCCRP_RESULT_OK, PPTP_ERROR_NONE)!= 0) {
10000fbf3537Syasuoka 				return 0;
10010fbf3537Syasuoka 			}
10020fbf3537Syasuoka 			pptp_ctrl_fini(_this);
10030fbf3537Syasuoka 			return 1;
10040fbf3537Syasuoka 		default:
10050fbf3537Syasuoka 			break;
10060fbf3537Syasuoka 		}
10070fbf3537Syasuoka 	case PPTP_CTRL_STATE_WAIT_STOP_REPLY:
10080fbf3537Syasuoka 		switch (hdr->control_message_type) {
10090fbf3537Syasuoka 		case PPTP_CTRL_MES_CODE_StopCCRP:
10100fbf3537Syasuoka 			pptp_ctrl_recv_StopCCRP(_this, pkt, lpkt);
10110fbf3537Syasuoka 			pptp_ctrl_fini(_this);
10120fbf3537Syasuoka 			return 1;
10130fbf3537Syasuoka 		}
10140fbf3537Syasuoka 		break;
10150fbf3537Syasuoka 	case PPTP_CTRL_STATE_WAIT_CTRL_REPLY:
1016f0a4e295Syasuoka 		/* XXX this implementation only support PAC mode */
10170fbf3537Syasuoka 		break;
10180fbf3537Syasuoka 	}
10190fbf3537Syasuoka 	pptp_ctrl_log(_this, LOG_WARNING,
10200fbf3537Syasuoka 	    "Unhandled control message type=%s(%d)",
10210fbf3537Syasuoka 	    pptp_ctrl_mes_type_string(hdr->control_message_type),
10220fbf3537Syasuoka 	    hdr->control_message_type);
10230fbf3537Syasuoka 	return 0;
10240fbf3537Syasuoka 
10250fbf3537Syasuoka bad_packet:
10260fbf3537Syasuoka 	pptp_ctrl_log(_this, LOG_ERR, "Received bad packet: %s", errmes);
10270fbf3537Syasuoka 	pptp_ctrl_stop(_this, PPTP_StopCCRQ_REASON_STOP_PROTOCOL);
10280fbf3537Syasuoka 
10290fbf3537Syasuoka 	return 0;
10300fbf3537Syasuoka }
10310fbf3537Syasuoka 
1032f0a4e295Syasuoka /* receiver PPTP Call related messages */
10330fbf3537Syasuoka static int
pptp_ctrl_call_input(pptp_ctrl * _this,int mes_type,u_char * pkt,int lpkt)10340fbf3537Syasuoka pptp_ctrl_call_input(pptp_ctrl *_this, int mes_type, u_char *pkt, int lpkt)
10350fbf3537Syasuoka {
10360fbf3537Syasuoka 	int i, call_id, lpkt0;
10370fbf3537Syasuoka 	pptp_call *call;
10380fbf3537Syasuoka 	const char *reason;
10390fbf3537Syasuoka 	u_char *pkt0;
10400fbf3537Syasuoka 
10410fbf3537Syasuoka 	pkt0 = pkt;
10420fbf3537Syasuoka 	lpkt0 = lpkt;
10430fbf3537Syasuoka 	call_id = -1;
10440fbf3537Syasuoka 	pkt += sizeof(struct pptp_ctrl_header);
10450fbf3537Syasuoka 	lpkt -= sizeof(struct pptp_ctrl_header);
10460fbf3537Syasuoka 	reason = "(no reason)";
10470fbf3537Syasuoka 
1048f0a4e295Syasuoka 	/* sanity check */
10490fbf3537Syasuoka 	if (lpkt < 4) {
10500fbf3537Syasuoka 		reason = "received packet is too short";
10510fbf3537Syasuoka 		goto badpacket;
10520fbf3537Syasuoka 	}
10530fbf3537Syasuoka 	call = NULL;
10540fbf3537Syasuoka 	call_id = ntohs(*(uint16_t *)pkt);
10550fbf3537Syasuoka 
10560fbf3537Syasuoka 	switch (mes_type) {
10570fbf3537Syasuoka 	case PPTP_CTRL_MES_CODE_SLI:	/* PNS <=> PAC */
1058f0a4e295Syasuoka 		/* only SLI contains Call-ID of this peer */
10590fbf3537Syasuoka 		for (i = 0; i < slist_length(&_this->call_list); i++) {
10600fbf3537Syasuoka 			call = slist_get(&_this->call_list, i);
10610fbf3537Syasuoka 			if (call->id == call_id)
10620fbf3537Syasuoka 				break;
10630fbf3537Syasuoka 			call = NULL;
10640fbf3537Syasuoka 		}
10650fbf3537Syasuoka 		if (call == NULL) {
10660fbf3537Syasuoka 			reason = "Call Id is not associated by this control";
10670fbf3537Syasuoka 			goto badpacket;
10680fbf3537Syasuoka 		}
10690fbf3537Syasuoka 		goto call_searched;
10700fbf3537Syasuoka 	case PPTP_CTRL_MES_CODE_ICRP:	/* PNS => PAC */
10710fbf3537Syasuoka 		/*
1072f0a4e295Syasuoka 		 * as this implementation never sent ICRQ, this case
1073f0a4e295Syasuoka 		 * should not happen.
1074f0a4e295Syasuoka 		 * But just to make sure, pptp_call.c can handle this
1075f0a4e295Syasuoka 		 * message.
10760fbf3537Syasuoka 		 */
1077f0a4e295Syasuoka 		/* FALLTHROUGH */
10780fbf3537Syasuoka 	case PPTP_CTRL_MES_CODE_OCRQ:	/* PNS => PAC */
10790fbf3537Syasuoka 	case PPTP_CTRL_MES_CODE_CCR:	/* PNS => PAC */
1080f0a4e295Syasuoka 		/* liner-search will be enough */
10810fbf3537Syasuoka 		for (i = 0; i < slist_length(&_this->call_list); i++) {
10820fbf3537Syasuoka 			call = slist_get(&_this->call_list, i);
10830fbf3537Syasuoka 			if (call->peers_call_id == call_id)
10840fbf3537Syasuoka 				break;
10850fbf3537Syasuoka 			call = NULL;
10860fbf3537Syasuoka 		}
10870fbf3537Syasuoka 		if (call == NULL && mes_type == PPTP_CTRL_MES_CODE_CCR) {
10880fbf3537Syasuoka 			pptp_ctrl_send_CDN(_this, PPTP_CDN_RESULT_GENRIC_ERROR,
10890fbf3537Syasuoka 			    PPTP_ERROR_BAD_CALL, 0, NULL);
10900fbf3537Syasuoka 			goto call_searched;
10910fbf3537Syasuoka 		}
10920fbf3537Syasuoka 		if (mes_type == PPTP_CTRL_MES_CODE_OCRQ) {
1093f0a4e295Syasuoka 			/* make new call */
10940fbf3537Syasuoka 			if (call != NULL) {
10950fbf3537Syasuoka 				pptp_call_input(call, mes_type, pkt0, lpkt0);
10960fbf3537Syasuoka 				return 0;
10970fbf3537Syasuoka 			}
10980fbf3537Syasuoka 			if ((call = pptp_call_create()) == NULL) {
10990fbf3537Syasuoka 				pptp_ctrl_log(_this, LOG_ERR,
11000fbf3537Syasuoka 				    "pptp_call_create() failed: %m");
1101f0a4e295Syasuoka 				goto fail;
11020fbf3537Syasuoka 			}
11030fbf3537Syasuoka 			if (pptp_call_init(call, _this) != 0) {
11040fbf3537Syasuoka 				pptp_ctrl_log(_this, LOG_ERR,
11050fbf3537Syasuoka 				    "pptp_call_init() failed: %m");
11060fbf3537Syasuoka 				pptp_call_destroy(call);
1107f0a4e295Syasuoka 				goto fail;
11080fbf3537Syasuoka 			}
11090fbf3537Syasuoka 			slist_add(&_this->call_list, call);
11100fbf3537Syasuoka 		}
11110fbf3537Syasuoka call_searched:
11120fbf3537Syasuoka 		if (call == NULL) {
11130fbf3537Syasuoka 			reason = "Call Id is not associated by this control";
11140fbf3537Syasuoka 			goto badpacket;
11150fbf3537Syasuoka 		}
11160fbf3537Syasuoka 		pptp_call_input(call, mes_type, pkt0, lpkt0);
11170fbf3537Syasuoka 		return 0;
11180fbf3537Syasuoka 	case PPTP_CTRL_MES_CODE_OCRP:	/* PAC => PNS */
11190fbf3537Syasuoka 	case PPTP_CTRL_MES_CODE_ICRQ:	/* PAC => PNS */
11200fbf3537Syasuoka 	case PPTP_CTRL_MES_CODE_ICCN:	/* PAC => PNS */
11210fbf3537Syasuoka 	case PPTP_CTRL_MES_CODE_CDN:	/* PAC => PNS */
1122f0a4e295Syasuoka 		/* don't receive because above messages are only of PNS */
11230fbf3537Syasuoka 	default:
11240fbf3537Syasuoka 		break;
11250fbf3537Syasuoka 	}
11260fbf3537Syasuoka 	reason = "Message type is unexpected.";
1127f0a4e295Syasuoka 	/* FALLTHROUGH */
11280fbf3537Syasuoka badpacket:
11290fbf3537Syasuoka 	pptp_ctrl_log(_this, LOG_INFO,
11300fbf3537Syasuoka 	    "Received a bad %s(%d) call_id=%d: %s",
11310fbf3537Syasuoka 		pptp_ctrl_mes_type_string(mes_type), mes_type, call_id, reason);
11320fbf3537Syasuoka 	return 0;
1133f0a4e295Syasuoka fail:
11340fbf3537Syasuoka 	pptp_ctrl_stop(_this, PPTP_StopCCRQ_REASON_STOP_PROTOCOL);
11350fbf3537Syasuoka 	return 0;
11360fbf3537Syasuoka }
11370fbf3537Syasuoka 
11380fbf3537Syasuoka 
1139f0a4e295Syasuoka /*
1140f0a4e295Syasuoka  * utilities
1141f0a4e295Syasuoka  */
11420fbf3537Syasuoka 
1143f0a4e295Syasuoka /* logging with the label of the instance */
11440fbf3537Syasuoka static void
pptp_ctrl_log(pptp_ctrl * _this,int prio,const char * fmt,...)11450fbf3537Syasuoka pptp_ctrl_log(pptp_ctrl *_this, int prio, const char *fmt, ...)
11460fbf3537Syasuoka {
11470fbf3537Syasuoka 	char logbuf[BUFSIZ];
11480fbf3537Syasuoka 	va_list ap;
11490fbf3537Syasuoka 
11500fbf3537Syasuoka 	va_start(ap, fmt);
11517a7bab9dSyasuoka #ifdef	PPTPD_MULTIPLE
11520fbf3537Syasuoka 	snprintf(logbuf, sizeof(logbuf), "pptpd id=%u ctrl=%u %s",
11530fbf3537Syasuoka 	    _this->pptpd->id, _this->id, fmt);
11540fbf3537Syasuoka #else
11550fbf3537Syasuoka 	snprintf(logbuf, sizeof(logbuf), "pptpd ctrl=%u %s", _this->id, fmt);
11560fbf3537Syasuoka #endif
11570fbf3537Syasuoka 	vlog_printf(prio, logbuf, ap);
11580fbf3537Syasuoka 	va_end(ap);
11590fbf3537Syasuoka }
11600fbf3537Syasuoka 
11610fbf3537Syasuoka static const char *
pptp_ctrl_state_string(int state)11620fbf3537Syasuoka pptp_ctrl_state_string(int state)
11630fbf3537Syasuoka {
11640fbf3537Syasuoka 	switch (state) {
11650fbf3537Syasuoka 	case PPTP_CTRL_STATE_IDLE:
11660fbf3537Syasuoka 		return "idle";
11670fbf3537Syasuoka 	case PPTP_CTRL_STATE_WAIT_CTRL_REPLY:
11680fbf3537Syasuoka 		return "wait-ctrl-reply";
11690fbf3537Syasuoka 	case PPTP_CTRL_STATE_ESTABLISHED:
11700fbf3537Syasuoka 		return "established";
11710fbf3537Syasuoka 	case PPTP_CTRL_STATE_WAIT_STOP_REPLY:
11720fbf3537Syasuoka 		return "wait-stop-reply";
11730fbf3537Syasuoka 	}
11740fbf3537Syasuoka 	return "unknown";
11750fbf3537Syasuoka }
1176