1 /* $OpenBSD: pptp_ctrl.c,v 1.13 2021/03/29 03:54:40 yasuoka Exp $ */
2
3 /*-
4 * Copyright (c) 2009 Internet Initiative Japan Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28 /**@file
29 * PPTP(RFC 2637) control connection implementation.
30 * currently it only support PAC part
31 */
32 /* $Id: pptp_ctrl.c,v 1.13 2021/03/29 03:54:40 yasuoka Exp $ */
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <stdio.h>
37 #include <stdarg.h>
38 #include <stdlib.h>
39 #include <netdb.h>
40 #include <unistd.h>
41 #include <syslog.h>
42 #include <time.h>
43 #include <fcntl.h>
44 #include <errno.h>
45 #include <string.h>
46 #include <event.h>
47
48 #include "bytebuf.h"
49 #include "debugutil.h"
50 #include "hash.h"
51 #include "slist.h"
52 #include "time_utils.h"
53
54 #include "version.h"
55
56 #include "pptp.h"
57 #include "pptp_local.h"
58 #include "pptp_subr.h"
59
60 #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
61 #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
62
63 /* periods of pptp_ctrl_timeout */
64 #define PPTP_CTRL_TIMEOUT_IVAL_SEC 2
65
66 #ifdef PPTP_CTRL_DEBUG
67 #define PPTP_CTRL_ASSERT(x) ASSERT(x)
68 #define PPTP_CTRL_DBG(x) pptp_ctrl_log x
69 #else
70 #define PPTP_CTRL_ASSERT(x)
71 #define PPTP_CTRL_DBG(x)
72 #endif
73
74 static unsigned pptp_ctrl_seqno = 0;
75
76 static void pptp_ctrl_log (pptp_ctrl *, int, const char *, ...) __printflike(3,4);
77 static void pptp_ctrl_timeout (int, short, void *);
78 static void pptp_ctrl_reset_timeout (pptp_ctrl *);
79 static void pptp_ctrl_io_event (int, short, void *);
80 static void pptp_ctrl_set_io_event (pptp_ctrl *);
81 static int pptp_ctrl_output_flush (pptp_ctrl *);
82 static void pptp_ctrl_SCCRx_string (struct pptp_scc *, u_char *, int);
83 static int pptp_ctrl_recv_SCCRQ (pptp_ctrl *, u_char *, int);
84 static int pptp_ctrl_recv_StopCCRP (pptp_ctrl *, u_char *, int);
85 static int pptp_ctrl_send_StopCCRQ (pptp_ctrl *, int);
86 static int pptp_ctrl_recv_StopCCRQ (pptp_ctrl *, u_char *, int);
87 static int pptp_ctrl_send_StopCCRP (pptp_ctrl *, int, int);
88 static int pptp_ctrl_send_SCCRP (pptp_ctrl *, int, int);
89 static void pptp_ctrl_send_CDN (pptp_ctrl *, int, int, int, const char *);
90 static void pptp_ctrl_process_echo_req (pptp_ctrl *, u_char *, int);
91 static int pptp_ctrl_recv_echo_rep (pptp_ctrl *, u_char *, int);
92 static void pptp_ctrl_send_echo_req (pptp_ctrl *);
93 static int pptp_ctrl_input (pptp_ctrl *, u_char *, int);
94 static int pptp_ctrl_call_input (pptp_ctrl *, int, u_char *, int);
95 static const char *pptp_ctrl_state_string (int);
96 static void pptp_ctrl_fini(pptp_ctrl *);
97
98 /*
99 * pptp_ctrl instance operation functions
100 */
101 pptp_ctrl *
pptp_ctrl_create(void)102 pptp_ctrl_create(void)
103 {
104 pptp_ctrl *_this;
105
106 if ((_this = malloc(sizeof(pptp_ctrl))) == NULL)
107 return NULL;
108
109 return _this;
110 }
111
112 int
pptp_ctrl_init(pptp_ctrl * _this)113 pptp_ctrl_init(pptp_ctrl *_this)
114 {
115 time_t curr_time;
116
117 PPTP_CTRL_ASSERT(_this != NULL);
118 curr_time = get_monosec();
119 memset(_this, 0, sizeof(pptp_ctrl));
120 _this->id = pptp_ctrl_seqno++;
121 _this->sock = -1;
122
123 if ((_this->recv_buf = bytebuffer_create(PPTP_BUFSIZ)) == NULL) {
124 pptp_ctrl_log(_this, LOG_ERR, "bytebuffer_create() failed at "
125 "%s(): %m", __func__);
126 goto fail;
127 }
128 if ((_this->send_buf = bytebuffer_create(PPTP_BUFSIZ)) == NULL) {
129 pptp_ctrl_log(_this, LOG_ERR, "bytebuffer_create() failed at "
130 "%s(): %m", __func__);
131 goto fail;
132 }
133 _this->last_rcv_ctrl = curr_time;
134 _this->last_snd_ctrl = curr_time;
135 _this->echo_seq = arc4random();
136 _this->echo_interval = PPTP_CTRL_DEFAULT_ECHO_INTERVAL;
137 _this->echo_timeout = PPTP_CTRL_DEFAULT_ECHO_TIMEOUT;
138 slist_init(&_this->call_list);
139 evtimer_set(&_this->ev_timer, pptp_ctrl_timeout, _this);
140
141 return 0;
142 fail:
143 return 1;
144 }
145
146 int
pptp_ctrl_start(pptp_ctrl * _this)147 pptp_ctrl_start(pptp_ctrl *_this)
148 {
149 int ival;
150 char hbuf0[NI_MAXHOST], sbuf0[NI_MAXSERV];
151 char hbuf1[NI_MAXHOST], sbuf1[NI_MAXSERV];
152 struct sockaddr_storage sock;
153 socklen_t socklen;
154
155 PPTP_CTRL_ASSERT(_this != NULL);
156 PPTP_CTRL_ASSERT(_this->sock >= 0);
157
158 /* convert address to strings for logging */
159 strlcpy(hbuf0, "<unknown>", sizeof(hbuf0));
160 strlcpy(sbuf0, "<unknown>", sizeof(sbuf0));
161 strlcpy(hbuf1, "<unknown>", sizeof(hbuf1));
162 strlcpy(sbuf1, "<unknown>", sizeof(sbuf1));
163 if (getnameinfo((struct sockaddr *)&_this->peer, _this->peer.ss_len,
164 hbuf0, sizeof(hbuf0), sbuf0, sizeof(sbuf0),
165 NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
166 pptp_ctrl_log(_this, LOG_ERR,
167 "getnameinfo() failed at %s(): %m", __func__);
168 }
169 socklen = sizeof(sock);
170 if (getsockname(_this->sock, (struct sockaddr *)&sock, &socklen) != 0) {
171 pptp_ctrl_log(_this, LOG_ERR,
172 "getsockname() failed at %s(): %m", __func__);
173 goto fail;
174 }
175 if (getnameinfo((struct sockaddr *)&sock, sock.ss_len, hbuf1,
176 sizeof(hbuf1), sbuf1, sizeof(sbuf1),
177 NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
178 pptp_ctrl_log(_this, LOG_ERR,
179 "getnameinfo() failed at %s(): %m", __func__);
180 }
181 pptp_ctrl_log(_this, LOG_INFO, "Starting peer=%s:%s/tcp "
182 "sock=%s:%s/tcp", hbuf0, sbuf0, hbuf1, sbuf1);
183
184 if ((ival = fcntl(_this->sock, F_GETFL)) < 0) {
185 pptp_ctrl_log(_this, LOG_ERR,
186 "fcntl(F_GET_FL) failed at %s(): %m", __func__);
187 goto fail;
188 } else if (fcntl(_this->sock, F_SETFL, ival | O_NONBLOCK) < 0) {
189 pptp_ctrl_log(_this, LOG_ERR,
190 "fcntl(F_SET_FL) failed at %s(): %m", __func__);
191 goto fail;
192 }
193 pptp_ctrl_set_io_event(_this);
194 pptp_ctrl_reset_timeout(_this);
195
196 return 0;
197 fail:
198 return 1;
199 }
200
201 /* Timer */
202 static void
pptp_ctrl_timeout(int fd,short event,void * ctx)203 pptp_ctrl_timeout(int fd, short event, void *ctx)
204 {
205 int i;
206 pptp_call *call;
207 pptp_ctrl *_this;
208 time_t last, curr_time;
209
210 _this = ctx;
211 curr_time = get_monosec();
212
213 PPTP_CTRL_DBG((_this, DEBUG_LEVEL_3, "enter %s()", __func__));
214 /* clean up call */
215 i = 0;
216 while (i < slist_length(&_this->call_list)) {
217 call = slist_get(&_this->call_list, i);
218 if (call->state == PPTP_CALL_STATE_CLEANUP_WAIT &&
219 curr_time - call->last_io > PPTP_CALL_CLEANUP_WAIT_TIME) {
220 pptp_call_stop(call);
221 pptp_call_destroy(call);
222 slist_remove(&_this->call_list, i);
223 } else
224 i++;
225 }
226
227 /* State machine: Timeout */
228 switch (_this->state) {
229 default:
230 case PPTP_CTRL_STATE_WAIT_CTRL_REPLY:
231 case PPTP_CTRL_STATE_IDLE:
232 if (curr_time - _this->last_rcv_ctrl > PPTPD_IDLE_TIMEOUT) {
233 pptp_ctrl_log(_this, LOG_ERR,
234 "Timeout in state %s",
235 pptp_ctrl_state_string(_this->state));
236 pptp_ctrl_fini(_this);
237 return;
238 }
239 break;
240 case PPTP_CTRL_STATE_ESTABLISHED:
241 last = MAXIMUM(_this->last_rcv_ctrl, _this->last_snd_ctrl);
242
243 if (curr_time - _this->last_rcv_ctrl
244 >= _this->echo_interval + _this->echo_timeout) {
245 pptp_ctrl_log(_this, LOG_INFO,
246 "Timeout waiting for echo reply");
247 pptp_ctrl_fini(_this);
248 return;
249 }
250 if (curr_time - last >= _this->echo_interval) {
251 PPTP_CTRL_DBG((_this, LOG_DEBUG, "Echo"));
252 _this->echo_seq++;
253 pptp_ctrl_send_echo_req(_this);
254 }
255 break;
256 case PPTP_CTRL_STATE_WAIT_STOP_REPLY:
257 if (curr_time - _this->last_snd_ctrl >
258 PPTP_CTRL_StopCCRP_WAIT_TIME) {
259 pptp_ctrl_log(_this, LOG_WARNING,
260 "Timeout waiting for StopCCRP");
261 pptp_ctrl_fini(_this);
262 return;
263 }
264 break;
265 case PPTP_CTRL_STATE_DISPOSING:
266 pptp_ctrl_fini(_this);
267 return;
268 }
269 pptp_ctrl_reset_timeout(_this);
270 }
271
272 static void
pptp_ctrl_reset_timeout(pptp_ctrl * _this)273 pptp_ctrl_reset_timeout(pptp_ctrl *_this)
274 {
275 struct timeval tv;
276
277 switch (_this->state) {
278 case PPTP_CTRL_STATE_DISPOSING:
279 /* call back immediately */
280 timerclear(&tv);
281 break;
282 default:
283 tv.tv_sec = PPTP_CTRL_TIMEOUT_IVAL_SEC;
284 tv.tv_usec = 0;
285 break;
286 }
287 evtimer_add(&_this->ev_timer, &tv);
288 }
289
290 /**
291 * Terminate PPTP control connection
292 * @result The value for Stop-Control-Connection-Request(StopCCRQ) result.
293 This function will not sent StopCCRQ when the value == 0 and
294 the specification does not require to sent it.
295 * @see ::#PPTP_StopCCRQ_REASON_STOP_PROTOCOL
296 * @see ::#PPTP_StopCCRQ_REASON_STOP_LOCAL_SHUTDOWN
297 */
298 void
pptp_ctrl_stop(pptp_ctrl * _this,int result)299 pptp_ctrl_stop(pptp_ctrl *_this, int result)
300 {
301 int i;
302 pptp_call *call;
303
304 switch (_this->state) {
305 case PPTP_CTRL_STATE_WAIT_STOP_REPLY:
306 /* waiting response. */
307 /* this state will timeout by pptp_ctrl_timeout */
308 break;
309 case PPTP_CTRL_STATE_ESTABLISHED:
310 if (result != 0) {
311 for (i = 0; i < slist_length(&_this->call_list); i++) {
312 call = slist_get(&_this->call_list, i);
313 pptp_call_disconnect(call,
314 PPTP_CDN_RESULT_ADMIN_SHUTDOWN, 0, NULL);
315 }
316 pptp_ctrl_send_StopCCRQ(_this, result);
317 _this->state = PPTP_CTRL_STATE_WAIT_STOP_REPLY;
318 break;
319 }
320 /* FALLTHROUGH */
321 default:
322 pptp_ctrl_fini(_this);
323 }
324 return;
325 }
326
327
328 /* finish PPTP control */
329 static void
pptp_ctrl_fini(pptp_ctrl * _this)330 pptp_ctrl_fini(pptp_ctrl *_this)
331 {
332 pptp_call *call;
333
334 PPTP_CTRL_ASSERT(_this != NULL);
335
336 if (_this->sock >= 0) {
337 event_del(&_this->ev_sock);
338 close(_this->sock);
339 _this->sock = -1;
340 }
341 for (slist_itr_first(&_this->call_list);
342 slist_itr_has_next(&_this->call_list);) {
343 call = slist_itr_next(&_this->call_list);
344 pptp_call_stop(call);
345 pptp_call_destroy(call);
346 slist_itr_remove(&_this->call_list);
347 }
348
349 if (_this->on_io_event != 0) {
350 /*
351 * as the complete terminate process needs complicated
352 * exception handling, do partially at here.
353 * rest of part will be handled by timer-event-handler.
354 */
355 PPTP_CTRL_DBG((_this, LOG_DEBUG, "Disposing"));
356 _this->state = PPTP_CTRL_STATE_DISPOSING;
357 pptp_ctrl_reset_timeout(_this);
358 return;
359 }
360
361 evtimer_del(&_this->ev_timer);
362 slist_fini(&_this->call_list);
363
364 pptp_ctrl_log (_this, LOG_NOTICE, "logtype=Finished");
365
366 /* disable _this */
367 pptpd_ctrl_finished_notify(_this->pptpd, _this);
368 }
369
370 /* free PPTP control context */
371 void
pptp_ctrl_destroy(pptp_ctrl * _this)372 pptp_ctrl_destroy(pptp_ctrl *_this)
373 {
374 if (_this->send_buf != NULL) {
375 bytebuffer_destroy(_this->send_buf);
376 _this->send_buf = NULL;
377 }
378 if (_this->recv_buf != NULL) {
379 bytebuffer_destroy(_this->recv_buf);
380 _this->recv_buf = NULL;
381 }
382 free(_this);
383 }
384
385 /*
386 * network I/O
387 */
388 /* I/O event dispather */
389 static void
pptp_ctrl_io_event(int fd,short evmask,void * ctx)390 pptp_ctrl_io_event(int fd, short evmask, void *ctx)
391 {
392 int sz, lpkt, hdrlen;
393 u_char *pkt;
394 pptp_ctrl *_this;
395
396 _this = ctx;
397 PPTP_CTRL_ASSERT(_this != NULL);
398
399 _this->on_io_event = 1;
400 if ((evmask & EV_WRITE) != 0) {
401 if (pptp_ctrl_output_flush(_this) != 0 ||
402 _this->state == PPTP_CTRL_STATE_DISPOSING)
403 goto fail;
404 _this->send_ready = 1;
405 }
406 if ((evmask & EV_READ) != 0) {
407 sz = read(_this->sock, bytebuffer_pointer(_this->recv_buf),
408 bytebuffer_remaining(_this->recv_buf));
409 if (sz <= 0) {
410 if (sz == 0 || errno == ECONNRESET) {
411 pptp_ctrl_log(_this, LOG_INFO,
412 "Connection closed by foreign host");
413 pptp_ctrl_fini(_this);
414 goto fail;
415 } else if (errno != EAGAIN && errno != EINTR) {
416 pptp_ctrl_log(_this, LOG_INFO,
417 "read() failed at %s(): %m", __func__);
418 pptp_ctrl_fini(_this);
419 goto fail;
420 }
421 }
422 bytebuffer_put(_this->recv_buf, BYTEBUFFER_PUT_DIRECT, sz);
423 bytebuffer_flip(_this->recv_buf);
424
425 for (;;) {
426 pkt = bytebuffer_pointer(_this->recv_buf);
427 lpkt = bytebuffer_remaining(_this->recv_buf);
428 if (pkt == NULL ||
429 lpkt < sizeof(struct pptp_ctrl_header))
430 break; /* read again */
431
432 hdrlen = pkt[0] << 8 | pkt[1];
433 if (lpkt < hdrlen)
434 break; /* read again */
435
436 bytebuffer_get(_this->recv_buf, NULL, hdrlen);
437 if (pptp_ctrl_input(_this, pkt, hdrlen) != 0 ||
438 _this->state == PPTP_CTRL_STATE_DISPOSING) {
439 bytebuffer_compact(_this->recv_buf);
440 goto fail;
441 }
442 }
443 bytebuffer_compact(_this->recv_buf);
444 }
445 if (pptp_ctrl_output_flush(_this) != 0)
446 goto fail;
447 pptp_ctrl_set_io_event(_this);
448 fail:
449 _this->on_io_event = 0;
450 }
451
452
453 /* set i/o event mask */
454 static void
pptp_ctrl_set_io_event(pptp_ctrl * _this)455 pptp_ctrl_set_io_event(pptp_ctrl *_this)
456 {
457 int evmask;
458
459 PPTP_CTRL_ASSERT(_this != NULL);
460 PPTP_CTRL_ASSERT(_this->sock >= 0);
461
462 evmask = 0;
463 if (bytebuffer_remaining(_this->recv_buf) > 128)
464 evmask |= EV_READ;
465 if (_this->send_ready == 0)
466 evmask |= EV_WRITE;
467
468 event_del(&_this->ev_sock);
469 if (evmask != 0) {
470 event_set(&_this->ev_sock, _this->sock, evmask,
471 pptp_ctrl_io_event, _this);
472 event_add(&_this->ev_sock, NULL);
473 }
474 }
475
476 /**
477 * Output PPTP control packet
478 * @param pkt pointer to packet buffer.
479 * when it was appended by _this-.send_buf using bytebuffer,
480 * specify NULL.
481 * @param lpkt packet length
482 */
483 void
pptp_ctrl_output(pptp_ctrl * _this,u_char * pkt,int lpkt)484 pptp_ctrl_output(pptp_ctrl *_this, u_char *pkt, int lpkt)
485 {
486 PPTP_CTRL_ASSERT(_this != NULL);
487 PPTP_CTRL_ASSERT(lpkt > 0);
488
489 /* just put the packet into the buffer now. send it later */
490 bytebuffer_put(_this->send_buf, pkt, lpkt);
491
492 if (_this->on_io_event != 0) {
493 /*
494 * pptp_ctrl_output_flush() will be called by the end of
495 * the I/O event handler.
496 */
497 } else {
498 /*
499 * When this function is called by other than I/O event handler,
500 * we need to call pptp_ctrl_output_flush(). However if we do
501 * it here, then we need to consider the situation
502 * 'flush => write failure => finalize'. The situation requires
503 * the caller function to handle the exception and causes
504 * complication. So we call pptp_ctrl_output_flush() by the
505 * the next send ready event.
506 */
507 _this->send_ready = 0; /* clear 'send ready' */
508 pptp_ctrl_set_io_event(_this); /* wait 'send ready */
509 }
510
511 return;
512 }
513
514 /* Send Stop-Control-Connection-Request */
515
516 /* flush output packet */
517 static int
pptp_ctrl_output_flush(pptp_ctrl * _this)518 pptp_ctrl_output_flush(pptp_ctrl *_this)
519 {
520 int sz;
521 time_t curr_time;
522
523 curr_time = get_monosec();
524
525 if (bytebuffer_position(_this->send_buf) <= 0)
526 return 0; /* nothing to write */
527 if (_this->send_ready == 0) {
528 pptp_ctrl_set_io_event(_this);
529 return 0; /* not ready to write */
530 }
531
532 bytebuffer_flip(_this->send_buf);
533
534 if (PPTP_CTRL_CONF(_this)->ctrl_out_pktdump != 0) {
535 pptp_ctrl_log(_this, LOG_DEBUG, "PPTP Control output packet");
536 show_hd(debug_get_debugfp(),
537 bytebuffer_pointer(_this->send_buf),
538 bytebuffer_remaining(_this->send_buf));
539 }
540 if ((sz = write(_this->sock, bytebuffer_pointer(_this->send_buf),
541 bytebuffer_remaining(_this->send_buf))) < 0) {
542 pptp_ctrl_log(_this, LOG_ERR, "write to socket failed: %m");
543 pptp_ctrl_fini(_this);
544
545 return 1;
546 }
547 _this->last_snd_ctrl = curr_time;
548 bytebuffer_get(_this->send_buf, NULL, sz);
549 bytebuffer_compact(_this->send_buf);
550 _this->send_ready = 0;
551
552 return 0;
553 }
554
555 /* convert Start-Control-Connection-{Request,Reply} packet to strings */
556 static void
pptp_ctrl_SCCRx_string(struct pptp_scc * scc,u_char * buf,int lbuf)557 pptp_ctrl_SCCRx_string(struct pptp_scc *scc, u_char *buf, int lbuf)
558 {
559 char results[128];
560
561 if (scc->result_code != 0)
562 snprintf(results, sizeof(results), "result=%d error=%d ",
563 scc->result_code, scc->error_code);
564 else
565 results[0] = '\0';
566
567 snprintf(buf, lbuf,
568 "protocol_version=%d.%d %sframing=%s bearer=%s max_channels=%d "
569 "firmware_revision=%d(0x%04x) host_name=\"%.*s\" "
570 "vendor_string=\"%.*s\"",
571 scc->protocol_version >> 8, scc->protocol_version & 0xff, results,
572 pptp_framing_string(scc->framing_caps),
573 pptp_bearer_string(scc->bearer_caps), scc->max_channels,
574 scc->firmware_revision, scc->firmware_revision,
575 (u_int)sizeof(scc->host_name), scc->host_name,
576 (u_int)sizeof(scc->vendor_string), scc->vendor_string);
577 }
578
579 /* receive Start-Control-Connection-Request */
580 static int
pptp_ctrl_recv_SCCRQ(pptp_ctrl * _this,u_char * pkt,int lpkt)581 pptp_ctrl_recv_SCCRQ(pptp_ctrl *_this, u_char *pkt, int lpkt)
582 {
583 char logbuf[512];
584 struct pptp_scc *scc;
585
586 /* sanity check */
587 if (lpkt < sizeof(struct pptp_scc)) {
588 pptp_ctrl_log(_this, LOG_ERR, "Received bad SCCRQ: packet too "
589 "short: %d < %d", lpkt, (int)sizeof(struct pptp_scc));
590 return 1;
591 }
592 scc = (struct pptp_scc *)pkt;
593
594 scc->protocol_version = ntohs(scc->protocol_version);
595 scc->framing_caps = htonl(scc->framing_caps);
596 scc->bearer_caps = htonl(scc->bearer_caps);
597 scc->max_channels = htons(scc->max_channels);
598 scc->firmware_revision = htons(scc->firmware_revision);
599
600 /* check protocol version */
601 if (scc->protocol_version != PPTP_RFC_2637_VERSION) {
602 pptp_ctrl_log(_this, LOG_ERR, "Received bad SCCRQ: "
603 "unknown protocol version %d", scc->protocol_version);
604 return 1;
605 }
606
607 pptp_ctrl_SCCRx_string(scc, logbuf, sizeof(logbuf));
608 pptp_ctrl_log(_this, LOG_INFO, "RecvSCCRQ %s", logbuf);
609
610 return 0;
611 }
612
613 /* Receive Stop-Control-Connection-Reply */
614 static int
pptp_ctrl_recv_StopCCRP(pptp_ctrl * _this,u_char * pkt,int lpkt)615 pptp_ctrl_recv_StopCCRP(pptp_ctrl *_this, u_char *pkt, int lpkt)
616 {
617 struct pptp_stop_ccrp *stop_ccrp;
618
619 if (lpkt < sizeof(struct pptp_stop_ccrp)) {
620 pptp_ctrl_log(_this, LOG_ERR, "Received bad StopCCRP: packet "
621 "too short: %d < %d", lpkt,
622 (int)sizeof(struct pptp_stop_ccrp));
623 return 1;
624 }
625 stop_ccrp = (struct pptp_stop_ccrp *)pkt;
626
627 pptp_ctrl_log(_this, LOG_INFO, "RecvStopCCRP reason=%s(%u)",
628 pptp_StopCCRP_result_string(stop_ccrp->result), stop_ccrp->result);
629
630 return 0;
631 }
632
633 static int
pptp_ctrl_send_StopCCRQ(pptp_ctrl * _this,int reason)634 pptp_ctrl_send_StopCCRQ(pptp_ctrl *_this, int reason)
635 {
636 int lpkt;
637 struct pptp_stop_ccrq *stop_ccrq;
638
639 stop_ccrq = bytebuffer_pointer(_this->send_buf);
640 lpkt = bytebuffer_remaining(_this->send_buf);
641 if (lpkt < sizeof(struct pptp_stop_ccrq)) {
642 pptp_ctrl_log(_this, LOG_ERR,
643 "SendCCRP failed: No buffer space available");
644 return -1;
645 }
646 memset(stop_ccrq, 0, sizeof(struct pptp_stop_ccrq));
647
648 pptp_init_header(&stop_ccrq->header, sizeof(struct pptp_stop_ccrq),
649 PPTP_CTRL_MES_CODE_StopCCRQ);
650
651 stop_ccrq->reason = reason;
652
653 pptp_ctrl_log(_this, LOG_INFO, "SendStopCCRQ reason=%s(%u)",
654 pptp_StopCCRQ_reason_string(stop_ccrq->reason), stop_ccrq->reason);
655
656 pptp_ctrl_output(_this, NULL, sizeof(struct pptp_stop_ccrq));
657
658 return 0;
659 }
660
661 /* Receive Stop-Control-Connection-Request */
662 static int
pptp_ctrl_recv_StopCCRQ(pptp_ctrl * _this,u_char * pkt,int lpkt)663 pptp_ctrl_recv_StopCCRQ(pptp_ctrl *_this, u_char *pkt, int lpkt)
664 {
665 struct pptp_stop_ccrq *stop_ccrq;
666
667 if (lpkt < sizeof(struct pptp_stop_ccrq)) {
668 pptp_ctrl_log(_this, LOG_ERR, "Received bad StopCCRQ: packet "
669 "too short: %d < %d", lpkt,
670 (int)sizeof(struct pptp_stop_ccrq));
671 return 1;
672 }
673 stop_ccrq = (struct pptp_stop_ccrq *)pkt;
674
675 pptp_ctrl_log(_this, LOG_INFO, "RecvStopCCRQ reason=%s(%u)",
676 pptp_StopCCRQ_reason_string(stop_ccrq->reason), stop_ccrq->reason);
677
678 return 0;
679 }
680
681 /* Send Stop-Control-Connection-Reply */
682 static int
pptp_ctrl_send_StopCCRP(pptp_ctrl * _this,int result,int error)683 pptp_ctrl_send_StopCCRP(pptp_ctrl *_this, int result, int error)
684 {
685 int lpkt;
686 struct pptp_stop_ccrp *stop_ccrp;
687
688 stop_ccrp = bytebuffer_pointer(_this->send_buf);
689
690 lpkt = bytebuffer_remaining(_this->send_buf);
691 if (lpkt < sizeof(struct pptp_stop_ccrp)) {
692 pptp_ctrl_log(_this, LOG_ERR,
693 "SendCCRQ failed: No buffer space available");
694 return -1;
695 }
696 memset(stop_ccrp, 0, sizeof(struct pptp_stop_ccrp));
697
698 pptp_init_header(&stop_ccrp->header, sizeof(struct pptp_stop_ccrp),
699 PPTP_CTRL_MES_CODE_StopCCRP);
700
701 stop_ccrp->result = result;
702 stop_ccrp->error = error;
703
704 pptp_ctrl_log(_this, LOG_INFO,
705 "SendStopCCRP result=%s(%u) error=%s(%u)",
706 pptp_StopCCRP_result_string(stop_ccrp->result), stop_ccrp->result,
707 pptp_general_error_string(stop_ccrp->error), stop_ccrp->error);
708
709 pptp_ctrl_output(_this, NULL, sizeof(struct pptp_stop_ccrp));
710
711 return 0;
712 }
713
714 /* Send Start-Control-Connection-Reply */
715 static int
pptp_ctrl_send_SCCRP(pptp_ctrl * _this,int result,int error)716 pptp_ctrl_send_SCCRP(pptp_ctrl *_this, int result, int error)
717 {
718 int lpkt;
719 struct pptp_scc *scc;
720 char logbuf[512];
721 const char *val;
722
723 scc = bytebuffer_pointer(_this->send_buf);
724 lpkt = bytebuffer_remaining(_this->send_buf);
725 if (lpkt < sizeof(struct pptp_scc)) {
726 pptp_ctrl_log(_this, LOG_ERR,
727 "SendSCCRP failed: No buffer space available");
728 return -1;
729 }
730 memset(scc, 0, sizeof(struct pptp_scc));
731
732 pptp_init_header(&scc->header, sizeof(struct pptp_scc),
733 PPTP_CTRL_MES_CODE_SCCRP);
734
735 scc->protocol_version = PPTP_RFC_2637_VERSION;
736 scc->result_code = result;
737 scc->error_code = error;
738
739 /* XXX only support sync frames */
740 scc->framing_caps = PPTP_CTRL_FRAMING_SYNC;
741 scc->bearer_caps = PPTP_CTRL_BEARER_DIGITAL;
742
743 scc->max_channels = 4; /* XXX */
744 scc->firmware_revision = MAJOR_VERSION << 8 | MINOR_VERSION;
745
746 /* this implementation only support these strings up to
747 * 63 character */
748 /* host name */
749
750 if ((val = PPTP_CTRL_CONF(_this)->hostname) == NULL)
751 val = "";
752 strlcpy(scc->host_name, val, sizeof(scc->host_name));
753
754 /* vendor name */
755 if (PPTP_CTRL_CONF(_this)->vendor_name == NULL)
756 val = PPTPD_DEFAULT_VENDOR_NAME;
757 strlcpy(scc->vendor_string, val, sizeof(scc->vendor_string));
758
759 pptp_ctrl_SCCRx_string(scc, logbuf, sizeof(logbuf));
760 pptp_ctrl_log(_this, LOG_INFO, "SendSCCRP %s", logbuf);
761
762 scc->protocol_version = htons(scc->protocol_version);
763 scc->framing_caps = htonl(scc->framing_caps);
764 scc->bearer_caps = htonl(scc->bearer_caps);
765 scc->max_channels = htons(scc->max_channels);
766 scc->firmware_revision = htons(scc->firmware_revision);
767
768 pptp_ctrl_output(_this, NULL, sizeof(struct pptp_scc));
769
770 return 0;
771 }
772
773 /* receive ECHO and reply */
774 static void
pptp_ctrl_process_echo_req(pptp_ctrl * _this,u_char * pkt,int lpkt)775 pptp_ctrl_process_echo_req(pptp_ctrl *_this, u_char *pkt, int lpkt)
776 {
777 struct pptp_echo_rq *echo_rq;
778 struct pptp_echo_rp *echo_rp;
779
780 if (lpkt < sizeof(struct pptp_echo_rq)) {
781 pptp_ctrl_log(_this, LOG_ERR, "Received bad EchoReq: packet "
782 "too short: %d < %d", lpkt,
783 (int)sizeof(struct pptp_echo_rq));
784 return;
785 }
786 echo_rq = (struct pptp_echo_rq *)pkt;
787
788 PPTP_CTRL_DBG((_this, LOG_DEBUG, "RecvEchoReq"));
789
790 echo_rp = bytebuffer_pointer(_this->send_buf);
791 lpkt = bytebuffer_remaining(_this->send_buf);
792 if (echo_rp == NULL || lpkt < sizeof(struct pptp_echo_rp)) {
793 pptp_ctrl_log(_this, LOG_ERR,
794 "Failed to send EchoReq: No buffer space available");
795 return;
796 }
797 memset(echo_rp, 0, sizeof(struct pptp_echo_rp));
798
799 pptp_init_header(&echo_rp->header, sizeof(struct pptp_echo_rp),
800 PPTP_CTRL_MES_CODE_ECHO_RP);
801
802 echo_rp->identifier = echo_rq->identifier;
803 echo_rp->result_code = PPTP_ECHO_RP_RESULT_OK;
804 echo_rp->error_code = PPTP_ERROR_NONE;
805 echo_rp->reserved1 = htons(0);
806
807 pptp_ctrl_output(_this, NULL, sizeof(struct pptp_echo_rp));
808 PPTP_CTRL_DBG((_this, LOG_DEBUG, "SendEchoReply"));
809 }
810
811 /* receiver Echo-Reply */
812 static int
pptp_ctrl_recv_echo_rep(pptp_ctrl * _this,u_char * pkt,int lpkt)813 pptp_ctrl_recv_echo_rep(pptp_ctrl *_this, u_char *pkt, int lpkt)
814 {
815 struct pptp_echo_rp *echo_rp;
816
817 if (lpkt < sizeof(struct pptp_echo_rp)) {
818 pptp_ctrl_log(_this, LOG_ERR, "Received bad EchoReq: packet "
819 "too short: %d < %d", lpkt,
820 (int)sizeof(struct pptp_echo_rp));
821 return 1;
822 }
823 echo_rp = (struct pptp_echo_rp *)pkt;
824
825 if (echo_rp->result_code != PPTP_ECHO_RP_RESULT_OK) {
826 pptp_ctrl_log(_this, LOG_ERR, "Received negative EchoReply: %s",
827 pptp_general_error_string(echo_rp->error_code));
828 return 1;
829 }
830 if (_this->echo_seq != ntohl(echo_rp->identifier)) {
831 pptp_ctrl_log(_this, LOG_ERR, "Received bad EchoReply: "
832 "Identifier mismatch sent=%u recv=%u",
833 _this->echo_seq , ntohl(echo_rp->identifier));
834 return 1;
835 }
836 PPTP_CTRL_DBG((_this, LOG_DEBUG, "RecvEchoReply"));
837 return 0;
838 }
839
840 /* send Echo-Request */
841 static void
pptp_ctrl_send_echo_req(pptp_ctrl * _this)842 pptp_ctrl_send_echo_req(pptp_ctrl *_this)
843 {
844 int lpkt;
845 struct pptp_echo_rq *echo_rq;
846
847 echo_rq = (struct pptp_echo_rq *)bytebuffer_pointer(_this->send_buf);
848 lpkt = bytebuffer_remaining(_this->send_buf);
849 if (echo_rq == NULL || lpkt < sizeof(struct pptp_echo_rq)) {
850 pptp_ctrl_log(_this, LOG_ERR,
851 "SendEchoReq failed: No buffer space available");
852 return;
853 }
854 memset(echo_rq, 0, sizeof(struct pptp_echo_rq));
855
856 pptp_init_header(&echo_rq->header, sizeof(struct pptp_echo_rq),
857 PPTP_CTRL_MES_CODE_ECHO_RQ);
858
859 echo_rq->identifier = htonl(_this->echo_seq);
860
861 pptp_ctrl_output(_this, NULL, sizeof(struct pptp_echo_rq));
862 PPTP_CTRL_DBG((_this, LOG_DEBUG, "SendEchoReq"));
863 }
864
865 /* send Call-Disconnect-Notify */
866 static void
pptp_ctrl_send_CDN(pptp_ctrl * _this,int result,int error,int cause,const char * statistics)867 pptp_ctrl_send_CDN(pptp_ctrl *_this, int result, int error, int cause,
868 const char *statistics)
869 {
870 int lpkt;
871 struct pptp_cdn *cdn;
872
873 cdn = bytebuffer_pointer(_this->send_buf);
874 lpkt = bytebuffer_remaining(_this->send_buf);
875 if (lpkt < sizeof(struct pptp_cdn)) {
876 pptp_ctrl_log(_this, LOG_ERR,
877 "SendCCR failed: No buffer space available");
878 return;
879 }
880 memset(cdn, 0, sizeof(struct pptp_cdn));
881
882 pptp_init_header(&cdn->header, sizeof(struct pptp_cdn),
883 PPTP_CTRL_MES_CODE_CDN);
884
885 cdn->call_id = _this->id;
886 cdn->result_code = result;
887 cdn->error_code = error;
888 cdn->cause_code = cause;
889 if (statistics != NULL)
890 strlcpy(cdn->statistics, statistics, sizeof(cdn->statistics));
891
892 cdn->call_id = htons(cdn->call_id);
893 cdn->cause_code = htons(cdn->cause_code);
894
895 pptp_ctrl_output(_this, NULL, sizeof(struct pptp_cdn));
896 }
897
898 /* receive Control-packet */
899 static int
pptp_ctrl_input(pptp_ctrl * _this,u_char * pkt,int lpkt)900 pptp_ctrl_input(pptp_ctrl *_this, u_char *pkt, int lpkt)
901 {
902 char errmes[256];
903 time_t curr_time;
904 struct pptp_ctrl_header *hdr;
905
906 PPTP_CTRL_ASSERT(lpkt >= sizeof(struct pptp_ctrl_header));
907
908 curr_time = get_monosec();
909 hdr = (struct pptp_ctrl_header *)pkt;
910
911 hdr->length = ntohs(hdr->length);
912 hdr->pptp_message_type = ntohs(hdr->pptp_message_type);
913 hdr->magic_cookie = ntohl(hdr->magic_cookie);
914 hdr->control_message_type = ntohs(hdr->control_message_type);
915 hdr->reserved0 = ntohs(hdr->reserved0);
916
917 /* sanity check */
918 PPTP_CTRL_ASSERT(hdr->length <= lpkt);
919
920 _this->last_rcv_ctrl = curr_time;
921
922 if (PPTP_CTRL_CONF(_this)->ctrl_in_pktdump != 0) {
923 pptp_ctrl_log(_this, LOG_DEBUG,
924 "PPTP Control input packet dump: mestype=%s(%d)",
925 pptp_ctrl_mes_type_string(hdr->control_message_type),
926 hdr->control_message_type);
927 show_hd(debug_get_debugfp(), pkt, lpkt);
928 }
929
930 /* inspect packet body */
931 /* message type */
932 if (hdr->pptp_message_type != PPTP_MES_TYPE_CTRL) {
933 snprintf(errmes, sizeof(errmes), "unknown message type %d",
934 hdr->pptp_message_type);
935 goto bad_packet;
936 }
937 /* magic cookie */
938 if (hdr->magic_cookie != PPTP_MAGIC_COOKIE) {
939 snprintf(errmes, sizeof(errmes), "wrong magic %08x != %08x",
940 hdr->magic_cookie, PPTP_MAGIC_COOKIE);
941 goto bad_packet;
942 }
943
944 /* As there is possibility of state conflicts,
945 * ECHO Reply requiries special care.
946 */
947 switch (hdr->control_message_type) {
948 case PPTP_CTRL_MES_CODE_ECHO_RP:
949 if (pptp_ctrl_recv_echo_rep(_this, pkt, lpkt) != 0) {
950 pptp_ctrl_fini(_this);
951 return 1;
952 }
953 return 0;
954 }
955
956 /*
957 * State machine
958 */
959 switch (_this->state) {
960 case PPTP_CTRL_STATE_IDLE:
961 switch (hdr->control_message_type) {
962 case PPTP_CTRL_MES_CODE_SCCRQ:
963 if (pptp_ctrl_recv_SCCRQ(_this, pkt, lpkt) != 0) {
964 return 0;
965 }
966 if (pptp_ctrl_send_SCCRP(_this,
967 PPTP_SCCRP_RESULT_SUCCESS, PPTP_ERROR_NONE) != 0) {
968 return 0;
969 }
970 _this->state = PPTP_CTRL_STATE_ESTABLISHED;
971 return 0;
972 default:
973 break;
974 }
975 break;
976 case PPTP_CTRL_STATE_ESTABLISHED:
977 switch (hdr->control_message_type) {
978 case PPTP_CTRL_MES_CODE_ECHO_RQ:
979 pptp_ctrl_process_echo_req(_this, pkt, lpkt);
980 return 0;
981 /* dispatch to pptp_call_input() if it is call-related-packet */
982 case PPTP_CTRL_MES_CODE_SLI:
983 case PPTP_CTRL_MES_CODE_ICRQ:
984 case PPTP_CTRL_MES_CODE_ICRP:
985 case PPTP_CTRL_MES_CODE_OCRQ:
986 case PPTP_CTRL_MES_CODE_OCRP:
987 case PPTP_CTRL_MES_CODE_ICCN:
988 case PPTP_CTRL_MES_CODE_CDN:
989 case PPTP_CTRL_MES_CODE_CCR:
990 return pptp_ctrl_call_input(_this,
991 hdr->control_message_type, pkt, lpkt);
992 case PPTP_CTRL_MES_CODE_StopCCRQ:
993 if (pptp_ctrl_recv_StopCCRQ(_this, pkt, lpkt) != 0) {
994 pptp_ctrl_stop(_this,
995 PPTP_StopCCRQ_REASON_STOP_PROTOCOL);
996 return 0;
997 }
998 if (pptp_ctrl_send_StopCCRP(_this,
999 PPTP_StopCCRP_RESULT_OK, PPTP_ERROR_NONE)!= 0) {
1000 return 0;
1001 }
1002 pptp_ctrl_fini(_this);
1003 return 1;
1004 default:
1005 break;
1006 }
1007 case PPTP_CTRL_STATE_WAIT_STOP_REPLY:
1008 switch (hdr->control_message_type) {
1009 case PPTP_CTRL_MES_CODE_StopCCRP:
1010 pptp_ctrl_recv_StopCCRP(_this, pkt, lpkt);
1011 pptp_ctrl_fini(_this);
1012 return 1;
1013 }
1014 break;
1015 case PPTP_CTRL_STATE_WAIT_CTRL_REPLY:
1016 /* XXX this implementation only support PAC mode */
1017 break;
1018 }
1019 pptp_ctrl_log(_this, LOG_WARNING,
1020 "Unhandled control message type=%s(%d)",
1021 pptp_ctrl_mes_type_string(hdr->control_message_type),
1022 hdr->control_message_type);
1023 return 0;
1024
1025 bad_packet:
1026 pptp_ctrl_log(_this, LOG_ERR, "Received bad packet: %s", errmes);
1027 pptp_ctrl_stop(_this, PPTP_StopCCRQ_REASON_STOP_PROTOCOL);
1028
1029 return 0;
1030 }
1031
1032 /* receiver PPTP Call related messages */
1033 static int
pptp_ctrl_call_input(pptp_ctrl * _this,int mes_type,u_char * pkt,int lpkt)1034 pptp_ctrl_call_input(pptp_ctrl *_this, int mes_type, u_char *pkt, int lpkt)
1035 {
1036 int i, call_id, lpkt0;
1037 pptp_call *call;
1038 const char *reason;
1039 u_char *pkt0;
1040
1041 pkt0 = pkt;
1042 lpkt0 = lpkt;
1043 call_id = -1;
1044 pkt += sizeof(struct pptp_ctrl_header);
1045 lpkt -= sizeof(struct pptp_ctrl_header);
1046 reason = "(no reason)";
1047
1048 /* sanity check */
1049 if (lpkt < 4) {
1050 reason = "received packet is too short";
1051 goto badpacket;
1052 }
1053 call = NULL;
1054 call_id = ntohs(*(uint16_t *)pkt);
1055
1056 switch (mes_type) {
1057 case PPTP_CTRL_MES_CODE_SLI: /* PNS <=> PAC */
1058 /* only SLI contains Call-ID of this peer */
1059 for (i = 0; i < slist_length(&_this->call_list); i++) {
1060 call = slist_get(&_this->call_list, i);
1061 if (call->id == call_id)
1062 break;
1063 call = NULL;
1064 }
1065 if (call == NULL) {
1066 reason = "Call Id is not associated by this control";
1067 goto badpacket;
1068 }
1069 goto call_searched;
1070 case PPTP_CTRL_MES_CODE_ICRP: /* PNS => PAC */
1071 /*
1072 * as this implementation never sent ICRQ, this case
1073 * should not happen.
1074 * But just to make sure, pptp_call.c can handle this
1075 * message.
1076 */
1077 /* FALLTHROUGH */
1078 case PPTP_CTRL_MES_CODE_OCRQ: /* PNS => PAC */
1079 case PPTP_CTRL_MES_CODE_CCR: /* PNS => PAC */
1080 /* liner-search will be enough */
1081 for (i = 0; i < slist_length(&_this->call_list); i++) {
1082 call = slist_get(&_this->call_list, i);
1083 if (call->peers_call_id == call_id)
1084 break;
1085 call = NULL;
1086 }
1087 if (call == NULL && mes_type == PPTP_CTRL_MES_CODE_CCR) {
1088 pptp_ctrl_send_CDN(_this, PPTP_CDN_RESULT_GENRIC_ERROR,
1089 PPTP_ERROR_BAD_CALL, 0, NULL);
1090 goto call_searched;
1091 }
1092 if (mes_type == PPTP_CTRL_MES_CODE_OCRQ) {
1093 /* make new call */
1094 if (call != NULL) {
1095 pptp_call_input(call, mes_type, pkt0, lpkt0);
1096 return 0;
1097 }
1098 if ((call = pptp_call_create()) == NULL) {
1099 pptp_ctrl_log(_this, LOG_ERR,
1100 "pptp_call_create() failed: %m");
1101 goto fail;
1102 }
1103 if (pptp_call_init(call, _this) != 0) {
1104 pptp_ctrl_log(_this, LOG_ERR,
1105 "pptp_call_init() failed: %m");
1106 pptp_call_destroy(call);
1107 goto fail;
1108 }
1109 slist_add(&_this->call_list, call);
1110 }
1111 call_searched:
1112 if (call == NULL) {
1113 reason = "Call Id is not associated by this control";
1114 goto badpacket;
1115 }
1116 pptp_call_input(call, mes_type, pkt0, lpkt0);
1117 return 0;
1118 case PPTP_CTRL_MES_CODE_OCRP: /* PAC => PNS */
1119 case PPTP_CTRL_MES_CODE_ICRQ: /* PAC => PNS */
1120 case PPTP_CTRL_MES_CODE_ICCN: /* PAC => PNS */
1121 case PPTP_CTRL_MES_CODE_CDN: /* PAC => PNS */
1122 /* don't receive because above messages are only of PNS */
1123 default:
1124 break;
1125 }
1126 reason = "Message type is unexpected.";
1127 /* FALLTHROUGH */
1128 badpacket:
1129 pptp_ctrl_log(_this, LOG_INFO,
1130 "Received a bad %s(%d) call_id=%d: %s",
1131 pptp_ctrl_mes_type_string(mes_type), mes_type, call_id, reason);
1132 return 0;
1133 fail:
1134 pptp_ctrl_stop(_this, PPTP_StopCCRQ_REASON_STOP_PROTOCOL);
1135 return 0;
1136 }
1137
1138
1139 /*
1140 * utilities
1141 */
1142
1143 /* logging with the label of the instance */
1144 static void
pptp_ctrl_log(pptp_ctrl * _this,int prio,const char * fmt,...)1145 pptp_ctrl_log(pptp_ctrl *_this, int prio, const char *fmt, ...)
1146 {
1147 char logbuf[BUFSIZ];
1148 va_list ap;
1149
1150 va_start(ap, fmt);
1151 #ifdef PPTPD_MULTIPLE
1152 snprintf(logbuf, sizeof(logbuf), "pptpd id=%u ctrl=%u %s",
1153 _this->pptpd->id, _this->id, fmt);
1154 #else
1155 snprintf(logbuf, sizeof(logbuf), "pptpd ctrl=%u %s", _this->id, fmt);
1156 #endif
1157 vlog_printf(prio, logbuf, ap);
1158 va_end(ap);
1159 }
1160
1161 static const char *
pptp_ctrl_state_string(int state)1162 pptp_ctrl_state_string(int state)
1163 {
1164 switch (state) {
1165 case PPTP_CTRL_STATE_IDLE:
1166 return "idle";
1167 case PPTP_CTRL_STATE_WAIT_CTRL_REPLY:
1168 return "wait-ctrl-reply";
1169 case PPTP_CTRL_STATE_ESTABLISHED:
1170 return "established";
1171 case PPTP_CTRL_STATE_WAIT_STOP_REPLY:
1172 return "wait-stop-reply";
1173 }
1174 return "unknown";
1175 }
1176