1 /* pptp_ctrl.c ... handle PPTP control connection.
2 * C. Scott Ananian <cananian@alumni.princeton.edu>
3 *
4 * $Id: pptp_ctrl.c,v 1.40 2011/12/19 07:15:03 quozl Exp $
5 */
6
7 #include <errno.h>
8 #if defined (__SVR4) && defined (__sun) /* Solaris */
9 #define _XPG4_2
10 #define __EXTENSIONS__
11 #endif /* Solaris */
12 #include <sys/time.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <assert.h>
19 #include <signal.h>
20 #include <string.h>
21 #include <ctype.h>
22 #include <fcntl.h>
23 #include <time.h>
24 #include "pptp_msg.h"
25 #include "pptp_ctrl.h"
26 #include "pptp_options.h"
27 #include "vector.h"
28 #include "util.h"
29 #include "pptp_quirks.h"
30
31 /* BECAUSE OF SIGNAL LIMITATIONS, EACH PROCESS CAN ONLY MANAGE ONE
32 * CONNECTION. SO THIS 'PPTP_CONN' STRUCTURE IS A BIT MISLEADING.
33 * WE'LL KEEP CONNECTION-SPECIFIC INFORMATION IN THERE ANYWAY (AS
34 * OPPOSED TO USING GLOBAL VARIABLES), BUT BEWARE THAT THE ENTIRE
35 * UNIX SIGNAL-HANDLING SEMANTICS WOULD HAVE TO CHANGE (OR THE
36 * TIME-OUT CODE DRASTICALLY REWRITTEN) BEFORE YOU COULD DO A
37 * PPTP_CONN_OPEN MORE THAN ONCE PER PROCESS AND GET AWAY WITH IT.
38 */
39
40 /* This structure contains connection-specific information that the
41 * signal handler needs to see. Thus, it needs to be in a global
42 * variable. If you end up using pthreads or something (why not
43 * just processes?), this would have to be placed in a thread-specific
44 * data area, using pthread_get|set_specific, etc., so I've
45 * conveniently encapsulated it for you.
46 * [linux threads will have to support thread-specific signals
47 * before this would work at all, which, as of this writing
48 * (linux-threads v0.6, linux kernel 2.1.72), it does not.]
49 */
50
51 /* Globals */
52
53 /* control the number of times echo packets will be logged */
54 static int nlogecho = 10;
55
56 static struct thread_specific {
57 struct sigaction old_sigaction; /* evil signals */
58 PPTP_CONN * conn;
59 } global;
60
61 #define INITIAL_BUFSIZE 512 /* initial i/o buffer size. */
62
63 struct PPTP_CONN {
64 int inet_sock;
65 /* Connection States */
66 enum {
67 CONN_IDLE,
68 CONN_WAIT_CTL_REPLY, CONN_WAIT_STOP_REPLY,
69 CONN_ESTABLISHED,
70 CONN_DEAD
71 } conn_state; /* on startup: CONN_IDLE */
72 /* Keep-alive states */
73 enum {
74 KA_NONE, KA_OUTSTANDING
75 } ka_state; /* on startup: KA_NONE */
76 /* Keep-alive ID; monotonically increasing (watch wrap-around!) */
77 u_int32_t ka_id; /* on startup: 1 */
78 /* Other properties. */
79 u_int16_t version;
80 u_int16_t firmware_rev;
81 u_int8_t hostname[64], vendor[64];
82 /* XXX these are only PNS properties, currently XXX */
83 /* Call assignment information. */
84 u_int16_t call_serial_number;
85 VECTOR *call;
86 void * closure;
87 pptp_conn_cb callback;
88 /******* IO buffers ******/
89 char * read_buffer, *write_buffer;
90 size_t read_alloc, write_alloc;
91 size_t read_size, write_size;
92 };
93
94 struct PPTP_CALL {
95 /* Call properties */
96 enum {
97 PPTP_CALL_PAC, PPTP_CALL_PNS
98 } call_type;
99 union {
100 enum pptp_pac_state {
101 PAC_IDLE, PAC_WAIT_REPLY, PAC_ESTABLISHED, PAC_WAIT_CS_ANS
102 } pac;
103 enum pptp_pns_state {
104 PNS_IDLE, PNS_WAIT_REPLY, PNS_ESTABLISHED, PNS_WAIT_DISCONNECT
105 } pns;
106 } state;
107 u_int16_t call_id, peer_call_id;
108 u_int16_t sernum;
109 u_int32_t speed;
110 /* For user data: */
111 pptp_call_cb callback;
112 void * closure;
113 };
114
115
116 /* PPTP error codes: ----------------------------------------------*/
117
118 /* (General Error Codes) */
119 static const struct {
120 const char *name, *desc;
121 } pptp_general_errors[] = {
122 #define PPTP_GENERAL_ERROR_NONE 0
123 { "(None)", "No general error" },
124 #define PPTP_GENERAL_ERROR_NOT_CONNECTED 1
125 { "(Not-Connected)", "No control connection exists yet for this "
126 "PAC-PNS pair" },
127 #define PPTP_GENERAL_ERROR_BAD_FORMAT 2
128 { "(Bad-Format)", "Length is wrong or Magic Cookie value is incorrect" },
129 #define PPTP_GENERAL_ERROR_BAD_VALUE 3
130 { "(Bad-Value)", "One of the field values was out of range or "
131 "reserved field was non-zero" },
132 #define PPTP_GENERAL_ERROR_NO_RESOURCE 4
133 { "(No-Resource)", "Insufficient resources to handle this command now" },
134 #define PPTP_GENERAL_ERROR_BAD_CALLID 5
135 { "(Bad-Call ID)", "The Call ID is invalid in this context" },
136 #define PPTP_GENERAL_ERROR_PAC_ERROR 6
137 { "(PAC-Error)", "A generic vendor-specific error occurred in the PAC" }
138 };
139
140 #define MAX_GENERAL_ERROR ( sizeof(pptp_general_errors) / \
141 sizeof(pptp_general_errors[0]) - 1)
142
143 /* Outgoing Call Reply Result Codes */
144 static const char *pptp_out_call_reply_result[] = {
145 /* 0 */ "Unknown Result Code",
146 /* 1 */ "Connected",
147 /* 2 */ "General Error",
148 /* 3 */ "No Carrier Detected",
149 /* 4 */ "Busy Signal",
150 /* 5 */ "No Dial Tone",
151 /* 6 */ "Time Out",
152 /* 7 */ "Not Accepted, Call is administratively prohibited" };
153
154 #define MAX_OUT_CALL_REPLY_RESULT 7
155
156 /* Call Disconnect Notify Result Codes */
157 static const char *pptp_call_disc_ntfy[] = {
158 /* 0 */ "Unknown Result Code",
159 /* 1 */ "Lost Carrier",
160 /* 2 */ "General Error",
161 /* 3 */ "Administrative Shutdown",
162 /* 4 */ "(your) Request" };
163
164 #define MAX_CALL_DISC_NTFY 4
165
166 /* Call Disconnect Notify Result Codes */
167 static const char *pptp_start_ctrl_conn_rply[] = {
168 /* 0 */ "Unknown Result Code",
169 /* 1 */ "Successful Channel Establishment",
170 /* 2 */ "General Error",
171 /* 3 */ "Command Channel Already Exists",
172 /* 4 */ "Requester is not Authorized" };
173
174 #define MAX_START_CTRL_CONN_REPLY 4
175
176 /* timing options */
177 int idle_wait = PPTP_TIMEOUT;
178 int max_echo_wait = PPTP_TIMEOUT;
179
180 /* Local prototypes */
181 static void pptp_reset_timer(void);
182 static void pptp_handle_timer(void);
183 /* Write/read as much as we can without blocking. */
184 int pptp_write_some(PPTP_CONN * conn);
185 int pptp_read_some(PPTP_CONN * conn);
186 /* Make valid packets from read_buffer */
187 int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size);
188 /* Add packet to write_buffer */
189 int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size);
190 /* Dispatch packets (general) */
191 int pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size);
192 /* Dispatch packets (control messages) */
193 int ctrlp_disp(PPTP_CONN * conn, void * buffer, size_t size);
194 /* Set link info, for pptp servers that need it.
195 this is a noop, unless the user specified a quirk and
196 there's a set_link hook defined in the quirks table
197 for that quirk */
198 void pptp_set_link(PPTP_CONN * conn, int peer_call_id);
199
200 /*** log error information in control packets *********************************/
ctrlp_error(int result,u_int8_t error,int cause,const char * result_text[],int max_result)201 static void ctrlp_error( int result, u_int8_t error, int cause,
202 const char *result_text[], int max_result)
203 {
204 if( cause >= 0)
205 log("Result code is %d '%s'. Error code is %d, Cause code is %d",
206 result, result_text[result <= max_result ? result : 0], error,
207 cause );
208 else
209 log("Reply result code is %d '%s'. Error code is %d",
210 result, result_text[result <= max_result ? result : 0], error);
211 if ((error > 0) && (error <= MAX_GENERAL_ERROR)){
212 if( result != PPTP_RESULT_GENERAL_ERROR )
213 log("Result code is something else then \"general error\", "
214 "so the following error is probably bogus.");
215 log("Error is '%s', Error message: '%s'",
216 pptp_general_errors[error].name,
217 pptp_general_errors[error].desc);
218 }
219 }
220
221 static const char *ctrl_msg_types[] = {
222 "invalid control message type",
223 /* (Control Connection Management) */
224 "Start-Control-Connection-Request", /* 1 */
225 "Start-Control-Connection-Reply", /* 2 */
226 "Stop-Control-Connection-Request", /* 3 */
227 "Stop-Control-Connection-Reply", /* 4 */
228 "Echo-Request", /* 5 */
229 "Echo-Reply", /* 6 */
230 /* (Call Management) */
231 "Outgoing-Call-Request", /* 7 */
232 "Outgoing-Call-Reply", /* 8 */
233 "Incoming-Call-Request", /* 9 */
234 "Incoming-Call-Reply", /* 10 */
235 "Incoming-Call-Connected", /* 11 */
236 "Call-Clear-Request", /* 12 */
237 "Call-Disconnect-Notify", /* 13 */
238 /* (Error Reporting) */
239 "WAN-Error-Notify", /* 14 */
240 /* (PPP Session Control) */
241 "Set-Link-Info" /* 15 */
242 };
243 #define MAX_CTRLMSG_TYPE 15
244
245 /*** report a sent packet ****************************************************/
ctrlp_rep(void * buffer,size_t size,int isbuff)246 static void ctrlp_rep( void * buffer, size_t size, int isbuff)
247 {
248 struct pptp_header *packet = buffer;
249 unsigned int type;
250 if(size < sizeof(struct pptp_header)) return;
251 type = ntoh16(packet->ctrl_type);
252 /* FIXME: do not report sending echo requests as long as they are
253 * sent in a signal handler. This may dead lock as the syslog call
254 * is not reentrant */
255 if( type == PPTP_ECHO_RQST ) return;
256 /* don't keep reporting sending of echo's */
257 if( (type == PPTP_ECHO_RQST || type == PPTP_ECHO_RPLY) && nlogecho <= 0 ) return;
258 log("%s control packet type is %d '%s'\n",isbuff ? "Buffered" : "Sent",
259 type, ctrl_msg_types[type <= MAX_CTRLMSG_TYPE ? type : 0]);
260
261 }
262
263
264
265 /* Open new pptp_connection. Returns NULL on failure. */
pptp_conn_open(int inet_sock,int isclient,pptp_conn_cb callback)266 PPTP_CONN * pptp_conn_open(int inet_sock, int isclient, pptp_conn_cb callback)
267 {
268 PPTP_CONN *conn;
269 /* Allocate structure */
270 if ((conn = malloc(sizeof(*conn))) == NULL) return NULL;
271 if ((conn->call = vector_create()) == NULL) { free(conn); return NULL; }
272 /* Initialize */
273 conn->inet_sock = inet_sock;
274 conn->conn_state = CONN_IDLE;
275 conn->ka_state = KA_NONE;
276 conn->ka_id = 1;
277 conn->call_serial_number = 0;
278 conn->callback = callback;
279 /* Create I/O buffers */
280 conn->read_size = conn->write_size = 0;
281 conn->read_alloc = conn->write_alloc = INITIAL_BUFSIZE;
282 conn->read_buffer =
283 malloc(sizeof(*(conn->read_buffer)) * conn->read_alloc);
284 conn->write_buffer =
285 malloc(sizeof(*(conn->write_buffer)) * conn->write_alloc);
286 if (conn->read_buffer == NULL || conn->write_buffer == NULL) {
287 if (conn->read_buffer != NULL) free(conn->read_buffer);
288 if (conn->write_buffer != NULL) free(conn->write_buffer);
289 vector_destroy(conn->call); free(conn); return NULL;
290 }
291 /* Make this socket non-blocking. */
292 fcntl(conn->inet_sock, F_SETFL, O_NONBLOCK);
293 /* Request connection from server, if this is a client */
294 if (isclient) {
295 struct pptp_start_ctrl_conn packet = {
296 PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RQST),
297 hton16(PPTP_VERSION), 0, 0,
298 hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP),
299 hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION),
300 PPTP_HOSTNAME, PPTP_VENDOR
301 };
302 /* fix this packet, if necessary */
303 int idx, rc;
304 idx = get_quirk_index();
305 if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) {
306 if ((rc = pptp_fixups[idx].start_ctrl_conn(&packet)))
307 warn("calling the start_ctrl_conn hook failed (%d)", rc);
308 }
309 if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet)))
310 conn->conn_state = CONN_WAIT_CTL_REPLY;
311 else
312 return NULL; /* could not send initial start request. */
313 }
314 /* Set up interval/keep-alive timer */
315 /* First, register handler for SIGALRM */
316 sigpipe_create();
317 sigpipe_assign(SIGALRM);
318 global.conn = conn;
319 /* Reset event timer */
320 pptp_reset_timer();
321 /* all done. */
322 return conn;
323 }
324
pptp_conn_established(PPTP_CONN * conn)325 int pptp_conn_established(PPTP_CONN *conn) {
326 return (conn->conn_state == CONN_ESTABLISHED);
327 }
328
randci()329 int randci ()
330 {
331 unsigned short int i=0;
332 int fd;
333
334 fd = open("/dev/random", O_RDONLY);
335 if (fd >= 0) {
336 read(fd, &i, 2);
337 close(fd);
338 }
339
340 if (i == 0) {
341 log("problem: opening /dev/random or getting number");
342 log("using rand()");
343 srand(time(NULL));
344 i = (unsigned short int) (rand() & 0xffff);
345 }
346 return i;
347 }
348
349 /* This currently *only* works for client call requests.
350 * We need to do something else to allocate calls for incoming requests.
351 */
pptp_call_open(PPTP_CONN * conn,pptp_call_cb callback,char * phonenr)352 PPTP_CALL * pptp_call_open(PPTP_CONN * conn, pptp_call_cb callback,
353 char *phonenr)
354 {
355 PPTP_CALL * call;
356 int i;
357 int idx, rc;
358 /* Send off the call request */
359 struct pptp_out_call_rqst packet = {
360 PPTP_HEADER_CTRL(PPTP_OUT_CALL_RQST),
361 0,0, /*call_id, sernum */
362 hton32(PPTP_BPS_MIN), hton32(PPTP_BPS_MAX),
363 hton32(PPTP_BEARER_CAP), hton32(PPTP_FRAME_CAP),
364 hton16(PPTP_WINDOW), 0, 0, 0, {0}, {0}
365 };
366 assert(conn && conn->call);
367 assert(conn->conn_state == CONN_ESTABLISHED);
368 /* Assign call id */
369 if (!vector_scan(conn->call, 0, PPTP_MAX_CHANNELS - 1, &i))
370 /* no more calls available! */
371 return NULL;
372 if (i == 0)
373 i = randci();
374 /* allocate structure. */
375 if ((call = malloc(sizeof(*call))) == NULL) return NULL;
376 /* Initialize call structure */
377 call->call_type = PPTP_CALL_PNS;
378 call->state.pns = PNS_IDLE;
379 call->call_id = (u_int16_t) i;
380 call->sernum = conn->call_serial_number++;
381 call->callback = callback;
382 call->closure = NULL;
383 packet.call_id = htons(call->call_id);
384 packet.call_sernum = htons(call->sernum);
385 /* if we have a quirk, build a new packet to fit it */
386 idx = get_quirk_index();
387 if (idx != -1 && pptp_fixups[idx].out_call_rqst_hook) {
388 if ((rc = pptp_fixups[idx].out_call_rqst_hook(&packet)))
389 warn("calling the out_call_rqst hook failed (%d)", rc);
390 }
391 /* fill in the phone number if it was specified */
392 if (phonenr) {
393 strncpy((char *)packet.phone_num, phonenr, sizeof(packet.phone_num));
394 packet.phone_len = strlen(phonenr);
395 if( packet.phone_len > sizeof(packet.phone_num))
396 packet.phone_len = sizeof(packet.phone_num);
397 packet.phone_len = hton16 (packet.phone_len);
398 }
399 if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) {
400 pptp_reset_timer();
401 call->state.pns = PNS_WAIT_REPLY;
402 /* and add it to the call vector */
403 vector_insert(conn->call, i, call);
404 return call;
405 } else { /* oops, unsuccessful. Deallocate. */
406 free(call);
407 return NULL;
408 }
409 }
410
411 /*** pptp_call_close **********************************************************/
pptp_call_close(PPTP_CONN * conn,PPTP_CALL * call)412 void pptp_call_close(PPTP_CONN * conn, PPTP_CALL * call)
413 {
414 struct pptp_call_clear_rqst rqst = {
415 PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_RQST), 0, 0
416 };
417 assert(conn && conn->call); assert(call);
418 assert(vector_contains(conn->call, call->call_id));
419 /* haven't thought about PAC yet */
420 assert(call->call_type == PPTP_CALL_PNS);
421 assert(call->state.pns != PNS_IDLE);
422 rqst.call_id = hton16(call->call_id);
423 /* don't check state against WAIT_DISCONNECT... allow multiple disconnect
424 * requests to be made.
425 */
426 if (pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst))) {
427 pptp_reset_timer();
428 call->state.pns = PNS_WAIT_DISCONNECT;
429 }
430 /* call structure will be freed when we have confirmation of disconnect. */
431 }
432
433 /*** hard close ***************************************************************/
pptp_call_destroy(PPTP_CONN * conn,PPTP_CALL * call)434 void pptp_call_destroy(PPTP_CONN *conn, PPTP_CALL *call)
435 {
436 assert(conn && conn->call); assert(call);
437 assert(vector_contains(conn->call, call->call_id));
438 /* notify */
439 if (call->callback != NULL) call->callback(conn, call, CALL_CLOSE_DONE);
440 /* deallocate */
441 vector_remove(conn->call, call->call_id);
442 free(call);
443 }
444
445 /*** this is a soft close *****************************************************/
pptp_conn_close(PPTP_CONN * conn,u_int8_t close_reason)446 void pptp_conn_close(PPTP_CONN * conn, u_int8_t close_reason)
447 {
448 struct pptp_stop_ctrl_conn rqst = {
449 PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RQST),
450 hton8(close_reason), 0, 0
451 };
452 int i;
453 assert(conn && conn->call);
454 /* avoid repeated close attempts */
455 if (conn->conn_state == CONN_IDLE || conn->conn_state == CONN_WAIT_STOP_REPLY)
456 return;
457 /* close open calls, if any */
458 for (i = 0; i < vector_size(conn->call); i++)
459 pptp_call_close(conn, vector_get_Nth(conn->call, i));
460 /* now close connection */
461 log("Closing PPTP connection");
462 if (pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst))) {
463 pptp_reset_timer(); /* wait 60 seconds for reply */
464 conn->conn_state = CONN_WAIT_STOP_REPLY;
465 }
466 return;
467 }
468
469 /*** this is a hard close *****************************************************/
pptp_conn_destroy(PPTP_CONN * conn)470 void pptp_conn_destroy(PPTP_CONN * conn)
471 {
472 int i;
473 assert(conn != NULL); assert(conn->call != NULL);
474 /* destroy all open calls */
475 for (i = 0; i < vector_size(conn->call); i++)
476 pptp_call_destroy(conn, vector_get_Nth(conn->call, i));
477 /* notify */
478 if (conn->callback != NULL) conn->callback(conn, CONN_CLOSE_DONE);
479 sigpipe_close();
480 close(conn->inet_sock);
481 /* deallocate */
482 vector_destroy(conn->call);
483 conn->conn_state = CONN_DEAD;
484 }
485
pptp_conn_is_dead(PPTP_CONN * conn)486 int pptp_conn_is_dead(PPTP_CONN * conn)
487 {
488 return conn->conn_state == CONN_DEAD;
489 }
490
pptp_conn_free(PPTP_CONN * conn)491 void pptp_conn_free(PPTP_CONN * conn)
492 {
493 free(conn);
494 }
495
496 /*** Deal with messages, in a non-blocking manner
497 * Add file descriptors used by pptp to fd_set.
498 */
pptp_fd_set(PPTP_CONN * conn,fd_set * read_set,fd_set * write_set,int * max_fd)499 void pptp_fd_set(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set,
500 int * max_fd)
501 {
502 int sig_fd;
503 assert(conn && conn->call);
504 /* Add fd to write_set if there are outstanding writes. */
505 if (conn->write_size > 0)
506 FD_SET(conn->inet_sock, write_set);
507 /* Always add fd to read_set. (always want something to read) */
508 FD_SET(conn->inet_sock, read_set);
509 if (*max_fd < conn->inet_sock) *max_fd = conn->inet_sock;
510 /* Add signal pipe file descriptor to set */
511 sig_fd = sigpipe_fd();
512 FD_SET(sig_fd, read_set);
513 if (*max_fd < sig_fd) *max_fd = sig_fd;
514 }
515
516 /*** handle any pptp file descriptors set in fd_set, and clear them ***********/
pptp_dispatch(PPTP_CONN * conn,fd_set * read_set,fd_set * write_set)517 int pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set)
518 {
519 int r = 0;
520 assert(conn && conn->call);
521 /* Check for signals */
522 if (FD_ISSET(sigpipe_fd(), read_set)) {
523 if (sigpipe_read() == SIGALRM) pptp_handle_timer();
524 FD_CLR(sigpipe_fd(), read_set);
525 }
526 /* Check write_set could be set. */
527 if (FD_ISSET(conn->inet_sock, write_set)) {
528 FD_CLR(conn->inet_sock, write_set);
529 if (conn->write_size > 0)
530 r = pptp_write_some(conn);/* write as much as we can without blocking */
531 }
532 /* Check read_set */
533 if (r >= 0 && FD_ISSET(conn->inet_sock, read_set)) {
534 void *buffer; size_t size;
535 FD_CLR(conn->inet_sock, read_set);
536 r = pptp_read_some(conn); /* read as much as we can without blocking */
537 if (r < 0)
538 return r;
539 /* make packets of the buffer, while we can. */
540 while (r >= 0 && pptp_make_packet(conn, &buffer, &size)) {
541 r = pptp_dispatch_packet(conn, buffer, size);
542 free(buffer);
543 }
544 }
545 /* That's all, folks. Simple, eh? */
546 return r;
547 }
548
549 /*** Non-blocking write *******************************************************/
pptp_write_some(PPTP_CONN * conn)550 int pptp_write_some(PPTP_CONN * conn) {
551 ssize_t retval;
552 assert(conn && conn->call);
553 retval = write(conn->inet_sock, conn->write_buffer, conn->write_size);
554 if (retval < 0) { /* error. */
555 if (errno == EAGAIN || errno == EINTR) {
556 return 0;
557 } else { /* a real error */
558 log("write error: %s", strerror(errno));
559 return -1;
560 }
561 }
562 assert((size_t)retval <= conn->write_size);
563 conn->write_size -= retval;
564 memmove(conn->write_buffer, conn->write_buffer + retval, conn->write_size);
565 ctrlp_rep(conn->write_buffer, retval, 0);
566 return 0;
567 }
568
569 /*** Non-blocking read ********************************************************/
pptp_read_some(PPTP_CONN * conn)570 int pptp_read_some(PPTP_CONN * conn)
571 {
572 ssize_t retval;
573 assert(conn && conn->call);
574 if (conn->read_size == conn->read_alloc) { /* need to alloc more memory */
575 char *new_buffer = realloc(conn->read_buffer,
576 sizeof(*(conn->read_buffer)) * conn->read_alloc * 2);
577 if (new_buffer == NULL) {
578 log("Out of memory"); return -1;
579 }
580 conn->read_alloc *= 2;
581 conn->read_buffer = new_buffer;
582 }
583 retval = read(conn->inet_sock, conn->read_buffer + conn->read_size,
584 conn->read_alloc - conn->read_size);
585 if (retval == 0) {
586 log("read returned zero, peer has closed");
587 return -1;
588 }
589 if (retval < 0) {
590 if (errno == EINTR || errno == EAGAIN)
591 return 0;
592 else { /* a real error */
593 log("read error: %s", strerror(errno));
594 return -1;
595 }
596 }
597 conn->read_size += retval;
598 assert(conn->read_size <= conn->read_alloc);
599 return 0;
600 }
601
602 /*** Packet formation *********************************************************/
pptp_make_packet(PPTP_CONN * conn,void ** buf,size_t * size)603 int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size)
604 {
605 struct pptp_header *header;
606 size_t bad_bytes = 0;
607 assert(conn && conn->call); assert(buf != NULL); assert(size != NULL);
608 /* Give up unless there are at least sizeof(pptp_header) bytes */
609 while ((conn->read_size-bad_bytes) >= sizeof(struct pptp_header)) {
610 /* Throw out bytes until we have a valid header. */
611 header = (struct pptp_header *) (conn->read_buffer + bad_bytes);
612 if (ntoh32(header->magic) != PPTP_MAGIC) goto throwitout;
613 if (ntoh16(header->reserved0) != 0)
614 log("reserved0 field is not zero! (0x%x) Cisco feature? \n",
615 ntoh16(header->reserved0));
616 if (ntoh16(header->length) < sizeof(struct pptp_header)) goto throwitout;
617 if (ntoh16(header->length) > PPTP_CTRL_SIZE_MAX) goto throwitout;
618 /* well. I guess it's good. Let's see if we've got it all. */
619 if (ntoh16(header->length) > (conn->read_size-bad_bytes))
620 /* nope. Let's wait until we've got it, then. */
621 goto flushbadbytes;
622 /* One last check: */
623 if ((ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL) &&
624 (ntoh16(header->length) !=
625 PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))))
626 goto throwitout;
627 /* well, I guess we've got it. */
628 *size = ntoh16(header->length);
629 *buf = malloc(*size);
630 if (*buf == NULL) { log("Out of memory."); return 0; /* ack! */ }
631 memcpy(*buf, conn->read_buffer + bad_bytes, *size);
632 /* Delete this packet from the read_buffer. */
633 conn->read_size -= (bad_bytes + *size);
634 memmove(conn->read_buffer, conn->read_buffer + bad_bytes + *size,
635 conn->read_size);
636 if (bad_bytes > 0)
637 log("%lu bad bytes thrown away.", (unsigned long) bad_bytes);
638 return 1;
639 throwitout:
640 bad_bytes++;
641 }
642 flushbadbytes:
643 /* no more packets. Let's get rid of those bad bytes */
644 conn->read_size -= bad_bytes;
645 memmove(conn->read_buffer, conn->read_buffer + bad_bytes, conn->read_size);
646 if (bad_bytes > 0)
647 log("%lu bad bytes thrown away.", (unsigned long) bad_bytes);
648 return 0;
649 }
650
651 /*** pptp_send_ctrl_packet ****************************************************/
pptp_send_ctrl_packet(PPTP_CONN * conn,void * buffer,size_t size)652 int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size)
653 {
654 assert(conn && conn->call); assert(buffer);
655 if( conn->write_size > 0) pptp_write_some( conn);
656 if( conn->write_size == 0) {
657 ssize_t retval;
658 retval = write(conn->inet_sock, buffer, size);
659 if (retval < 0) { /* error. */
660 if (errno == EAGAIN || errno == EINTR) {
661 /* ignore */;
662 retval = 0;
663 } else { /* a real error */
664 log("write error: %s", strerror(errno));
665 pptp_conn_destroy(conn); /* shut down fast. */
666 return 0;
667 }
668 }
669 ctrlp_rep( buffer, retval, 0);
670 size -= retval;
671 if( size <= 0) return 1;
672 }
673 /* Shove anything not written into the write buffer */
674 if (conn->write_size + size > conn->write_alloc) { /* need more memory */
675 char *new_buffer = realloc(conn->write_buffer,
676 sizeof(*(conn->write_buffer)) * conn->write_alloc * 2);
677 if (new_buffer == NULL) {
678 log("Out of memory"); return 0;
679 }
680 conn->write_alloc *= 2;
681 conn->write_buffer = new_buffer;
682 }
683 memcpy(conn->write_buffer + conn->write_size, buffer, size);
684 conn->write_size += size;
685 ctrlp_rep( buffer,size,1);
686 return 1;
687 }
688
689 /*** Packet Dispatch **********************************************************/
pptp_dispatch_packet(PPTP_CONN * conn,void * buffer,size_t size)690 int pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size)
691 {
692 int r = 0;
693 struct pptp_header *header = (struct pptp_header *)buffer;
694 assert(conn && conn->call); assert(buffer);
695 assert(ntoh32(header->magic) == PPTP_MAGIC);
696 assert(ntoh16(header->length) == size);
697 switch (ntoh16(header->pptp_type)) {
698 case PPTP_MESSAGE_CONTROL:
699 r = ctrlp_disp(conn, buffer, size);
700 break;
701 case PPTP_MESSAGE_MANAGE:
702 /* MANAGEMENT messages aren't even part of the spec right now. */
703 log("PPTP management message received, but not understood.");
704 break;
705 default:
706 log("Unknown PPTP control message type received: %u",
707 (unsigned int) ntoh16(header->pptp_type));
708 break;
709 }
710 return r;
711 }
712
713 /*** log echo request/replies *************************************************/
logecho(int type)714 static void logecho( int type)
715 {
716 /* hack to stop flooding the log files (the most interesting part is right
717 * after the connection built-up) */
718 if( nlogecho > 0) {
719 log( "Echo Re%s received.", type == PPTP_ECHO_RQST ? "quest" :"ply");
720 if( --nlogecho == 0)
721 log("no more Echo Reply/Request packets will be reported.");
722 }
723 }
724
725 /*** pptp_dispatch_ctrl_packet ************************************************/
ctrlp_disp(PPTP_CONN * conn,void * buffer,size_t size)726 int ctrlp_disp(PPTP_CONN * conn, void * buffer, size_t size)
727 {
728 struct pptp_header *header = (struct pptp_header *)buffer;
729 u_int8_t close_reason = PPTP_STOP_NONE;
730 assert(conn && conn->call); assert(buffer);
731 assert(ntoh32(header->magic) == PPTP_MAGIC);
732 assert(ntoh16(header->length) == size);
733 assert(ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL);
734 if (size < PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))) {
735 log("Invalid packet received [type: %d; length: %d].",
736 (int) ntoh16(header->ctrl_type), (int) size);
737 return 0;
738 }
739 switch (ntoh16(header->ctrl_type)) {
740 /* ----------- STANDARD Start-Session MESSAGES ------------ */
741 case PPTP_START_CTRL_CONN_RQST:
742 {
743 struct pptp_start_ctrl_conn *packet =
744 (struct pptp_start_ctrl_conn *) buffer;
745 struct pptp_start_ctrl_conn reply = {
746 PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RPLY),
747 hton16(PPTP_VERSION), 0, 0,
748 hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP),
749 hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION),
750 PPTP_HOSTNAME, PPTP_VENDOR };
751 int idx, rc;
752 log("Received Start Control Connection Request");
753 /* fix this packet, if necessary */
754 idx = get_quirk_index();
755 if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) {
756 if ((rc = pptp_fixups[idx].start_ctrl_conn(&reply)))
757 warn("calling the start_ctrl_conn hook failed (%d)", rc);
758 }
759 if (conn->conn_state == CONN_IDLE) {
760 if (ntoh16(packet->version) < PPTP_VERSION) {
761 /* Can't support this (earlier) PPTP_VERSION */
762 reply.version = packet->version;
763 /* protocol version not supported */
764 reply.result_code = hton8(5);
765 if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply)))
766 pptp_reset_timer(); /* give sender a chance for a retry */
767 } else { /* same or greater version */
768 if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) {
769 conn->conn_state = CONN_ESTABLISHED;
770 log("server connection ESTABLISHED.");
771 pptp_reset_timer();
772 }
773 }
774 }
775 break;
776 }
777 case PPTP_START_CTRL_CONN_RPLY:
778 {
779 struct pptp_start_ctrl_conn *packet =
780 (struct pptp_start_ctrl_conn *) buffer;
781 log("Received Start Control Connection Reply");
782 if (conn->conn_state == CONN_WAIT_CTL_REPLY) {
783 /* XXX handle collision XXX [see rfc] */
784 if (ntoh16(packet->version) != PPTP_VERSION) {
785 if (conn->callback != NULL)
786 conn->callback(conn, CONN_OPEN_FAIL);
787 close_reason = PPTP_STOP_PROTOCOL;
788 goto pptp_conn_close;
789 }
790 if (ntoh8(packet->result_code) != 1 &&
791 /* J'ai change le if () afin que la connection ne se ferme
792 * pas pour un "rien" :p adel@cybercable.fr -
793 *
794 * Don't close the connection if the result code is zero
795 * (feature found in certain ADSL modems)
796 */
797 ntoh8(packet->result_code) != 0) {
798 log("Negative reply received to our Start Control "
799 "Connection Request");
800 ctrlp_error(packet->result_code, packet->error_code,
801 -1, pptp_start_ctrl_conn_rply,
802 MAX_START_CTRL_CONN_REPLY);
803 if (conn->callback != NULL)
804 conn->callback(conn, CONN_OPEN_FAIL);
805 close_reason = PPTP_STOP_PROTOCOL;
806 goto pptp_conn_close;
807 }
808 conn->conn_state = CONN_ESTABLISHED;
809 /* log session properties */
810 conn->version = ntoh16(packet->version);
811 conn->firmware_rev = ntoh16(packet->firmware_rev);
812 memcpy(conn->hostname, packet->hostname, sizeof(conn->hostname));
813 memcpy(conn->vendor, packet->vendor, sizeof(conn->vendor));
814 pptp_reset_timer(); /* 60 seconds until keep-alive */
815 log("Client connection established.");
816 if (conn->callback != NULL)
817 conn->callback(conn, CONN_OPEN_DONE);
818 } /* else goto pptp_conn_close; */
819 break;
820 }
821 /* ----------- STANDARD Stop-Session MESSAGES ------------ */
822 case PPTP_STOP_CTRL_CONN_RQST:
823 {
824 /* conn_state should be CONN_ESTABLISHED, but it could be
825 * something else */
826 struct pptp_stop_ctrl_conn reply = {
827 PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RPLY),
828 hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0
829 };
830 log("Received Stop Control Connection Request.");
831 if (conn->conn_state == CONN_IDLE) break;
832 if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) {
833 if (conn->callback != NULL)
834 conn->callback(conn, CONN_CLOSE_RQST);
835 conn->conn_state = CONN_IDLE;
836 return -1;
837 }
838 break;
839 }
840 case PPTP_STOP_CTRL_CONN_RPLY:
841 {
842 log("Received Stop Control Connection Reply.");
843 /* conn_state should be CONN_WAIT_STOP_REPLY, but it
844 * could be something else */
845 if (conn->conn_state == CONN_IDLE) break;
846 conn->conn_state = CONN_IDLE;
847 return -1;
848 }
849 /* ----------- STANDARD Echo/Keepalive MESSAGES ------------ */
850 case PPTP_ECHO_RPLY:
851 {
852 struct pptp_echo_rply *packet =
853 (struct pptp_echo_rply *) buffer;
854 logecho( PPTP_ECHO_RPLY);
855 if ((conn->ka_state == KA_OUTSTANDING) &&
856 (ntoh32(packet->identifier) == conn->ka_id)) {
857 conn->ka_id++;
858 conn->ka_state = KA_NONE;
859 pptp_reset_timer();
860 }
861 break;
862 }
863 case PPTP_ECHO_RQST:
864 {
865 struct pptp_echo_rqst *packet =
866 (struct pptp_echo_rqst *) buffer;
867 struct pptp_echo_rply reply = {
868 PPTP_HEADER_CTRL(PPTP_ECHO_RPLY),
869 packet->identifier, /* skip hton32(ntoh32(id)) */
870 hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0
871 };
872 logecho( PPTP_ECHO_RQST);
873 if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply)))
874 pptp_reset_timer();
875 break;
876 }
877 /* ----------- OUTGOING CALL MESSAGES ------------ */
878 case PPTP_OUT_CALL_RQST:
879 {
880 struct pptp_out_call_rqst *packet =
881 (struct pptp_out_call_rqst *)buffer;
882 struct pptp_out_call_rply reply = {
883 PPTP_HEADER_CTRL(PPTP_OUT_CALL_RPLY),
884 0 /* callid */, packet->call_id, 1, PPTP_GENERAL_ERROR_NONE, 0,
885 hton32(PPTP_CONNECT_SPEED),
886 hton16(PPTP_WINDOW), hton16(PPTP_DELAY), 0
887 };
888 log("Received Outgoing Call Request.");
889 /* XXX PAC: eventually this should make an outgoing call. XXX */
890 reply.result_code = hton8(7); /* outgoing calls verboten */
891 pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
892 break;
893 }
894 case PPTP_OUT_CALL_RPLY:
895 {
896 struct pptp_out_call_rply *packet =
897 (struct pptp_out_call_rply *)buffer;
898 PPTP_CALL * call;
899 u_int16_t callid = ntoh16(packet->call_id_peer);
900 log("Received Outgoing Call Reply.");
901 if (!vector_search(conn->call, (int) callid, &call)) {
902 log("PPTP_OUT_CALL_RPLY received for non-existant call: "
903 "peer call ID (us) %d call ID (them) %d.",
904 callid, ntoh16(packet->call_id));
905 break;
906 }
907 if (call->call_type != PPTP_CALL_PNS) {
908 log("Ack! How did this call_type get here?"); /* XXX? */
909 break;
910 }
911 if (call->state.pns != PNS_WAIT_REPLY) {
912 warn("Unexpected(?) Outgoing Call Reply will be ignored.");
913 break;
914 }
915 /* check for errors */
916 if (packet->result_code != 1) {
917 /* An error. Log it verbosely. */
918 log("Our outgoing call request [callid %d] has not been "
919 "accepted.", (int) callid);
920 ctrlp_error(packet->result_code, packet->error_code,
921 packet->cause_code, pptp_out_call_reply_result,
922 MAX_OUT_CALL_REPLY_RESULT);
923 call->state.pns = PNS_IDLE;
924 if (call->callback != NULL)
925 call->callback(conn, call, CALL_OPEN_FAIL);
926 pptp_call_destroy(conn, call);
927 } else {
928 /* connection established */
929 call->state.pns = PNS_ESTABLISHED;
930 call->peer_call_id = ntoh16(packet->call_id);
931 call->speed = ntoh32(packet->speed);
932 pptp_reset_timer();
933 /* call pptp_set_link. unless the user specified a quirk
934 and this quirk has a set_link hook, this is a noop */
935 pptp_set_link(conn, call->peer_call_id);
936 if (call->callback != NULL)
937 call->callback(conn, call, CALL_OPEN_DONE);
938 log("Outgoing call established (call ID %u, peer's "
939 "call ID %u).\n", call->call_id, call->peer_call_id);
940 }
941 break;
942 }
943 /* ----------- INCOMING CALL MESSAGES ------------ */
944 /* XXX write me XXX */
945 /* ----------- CALL CONTROL MESSAGES ------------ */
946 case PPTP_CALL_CLEAR_RQST:
947 {
948 struct pptp_call_clear_rqst *packet =
949 (struct pptp_call_clear_rqst *)buffer;
950 struct pptp_call_clear_ntfy reply = {
951 PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_NTFY), packet->call_id,
952 1, PPTP_GENERAL_ERROR_NONE, 0, 0, {0}
953 };
954 int i;
955 log("Received Call Clear Request.");
956 if (vector_contains(conn->call, ntoh16(packet->call_id))) {
957 PPTP_CALL * call;
958 vector_search(conn->call, ntoh16(packet->call_id), &call);
959 if (call->callback != NULL)
960 call->callback(conn, call, CALL_CLOSE_RQST);
961 if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) {
962 i = call->call_id;
963 pptp_call_destroy(conn, call);
964 log("Call closed (RQST) (call id %d)", i);
965 }
966 }
967 break;
968 }
969 case PPTP_CALL_CLEAR_NTFY:
970 {
971 struct pptp_call_clear_ntfy *packet =
972 (struct pptp_call_clear_ntfy *)buffer;
973 int i;
974 u_int16_t our_call_id;
975 u_int16_t peer_call_id = ntoh16(packet->call_id);
976 log("Call disconnect notification received (call id %d)",
977 (int) peer_call_id);
978 /* See if we can map the peer's call id to our own */
979 for (i = 0; i < vector_size(conn->call); i++) {
980 PPTP_CALL * call = vector_get_Nth(conn->call, i);
981 if (call->peer_call_id == peer_call_id) {
982 our_call_id = call->call_id;
983 if (vector_contains(conn->call, our_call_id)) {
984 ctrlp_error(packet->result_code, packet->error_code,
985 packet->cause_code, pptp_call_disc_ntfy,
986 MAX_CALL_DISC_NTFY);
987 vector_search(conn->call, our_call_id, &call);
988 pptp_call_destroy(conn, call);
989 }
990 break;
991 }
992 }
993 /* XXX we could log call stats here XXX */
994 /* XXX not all servers send this XXX */
995 break;
996 }
997 case PPTP_SET_LINK_INFO:
998 {
999 /* I HAVE NO CLUE WHAT TO DO IF send_accm IS NOT 0! */
1000 /* this is really dealt with in the HDLC deencapsulation, anyway. */
1001 struct pptp_set_link_info *packet =
1002 (struct pptp_set_link_info *)buffer;
1003 /* log it. */
1004 log("PPTP_SET_LINK_INFO received from peer_callid %u",
1005 (unsigned int) ntoh16(packet->call_id_peer));
1006 log(" send_accm is %08lX, recv_accm is %08lX",
1007 (unsigned long) ntoh32(packet->send_accm),
1008 (unsigned long) ntoh32(packet->recv_accm));
1009 if (!(ntoh32(packet->send_accm) == 0 &&
1010 ntoh32(packet->recv_accm) == 0))
1011 warn("Non-zero Async Control Character Maps are not supported!");
1012 break;
1013 }
1014 default:
1015 log("Unrecognized Packet %d received.",
1016 (int) ntoh16(((struct pptp_header *)buffer)->ctrl_type));
1017 /* goto pptp_conn_close; */
1018 break;
1019 }
1020 return 0;
1021 pptp_conn_close:
1022 warn("pptp_conn_close(%d)", (int) close_reason);
1023 pptp_conn_close(conn, close_reason);
1024 return 0;
1025 }
1026
1027 /*** pptp_set_link **************************************************************/
pptp_set_link(PPTP_CONN * conn,int peer_call_id)1028 void pptp_set_link(PPTP_CONN* conn, int peer_call_id)
1029 {
1030 int idx, rc;
1031 /* if we need to send a set_link packet because of buggy
1032 hardware or pptp server, do it now */
1033 if ((idx = get_quirk_index()) != -1 && pptp_fixups[idx].set_link_hook) {
1034 struct pptp_set_link_info packet;
1035 if ((rc = pptp_fixups[idx].set_link_hook(&packet, peer_call_id)))
1036 warn("calling the set_link hook failed (%d)", rc);
1037 if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) {
1038 pptp_reset_timer();
1039 }
1040 }
1041 }
1042
1043 /*** Get info from call structure *********************************************/
1044 /* NOTE: The peer_call_id is undefined until we get a server response. */
pptp_call_get_ids(PPTP_CONN * conn,PPTP_CALL * call,u_int16_t * call_id,u_int16_t * peer_call_id)1045 void pptp_call_get_ids(PPTP_CONN * conn, PPTP_CALL * call,
1046 u_int16_t * call_id, u_int16_t * peer_call_id)
1047 {
1048 assert(conn != NULL); assert(call != NULL);
1049 *call_id = call->call_id;
1050 *peer_call_id = call->peer_call_id;
1051 }
1052
1053 /*** pptp_call_closure_put ****************************************************/
pptp_call_closure_put(PPTP_CONN * conn,PPTP_CALL * call,void * cl)1054 void pptp_call_closure_put(PPTP_CONN * conn, PPTP_CALL * call, void *cl)
1055 {
1056 assert(conn != NULL); assert(call != NULL);
1057 call->closure = cl;
1058 }
1059
1060 /*** pptp_call_closure_get ****************************************************/
pptp_call_closure_get(PPTP_CONN * conn,PPTP_CALL * call)1061 void * pptp_call_closure_get(PPTP_CONN * conn, PPTP_CALL * call)
1062 {
1063 assert(conn != NULL); assert(call != NULL);
1064 return call->closure;
1065 }
1066
1067 /*** pptp_conn_closure_put ****************************************************/
pptp_conn_closure_put(PPTP_CONN * conn,void * cl)1068 void pptp_conn_closure_put(PPTP_CONN * conn, void *cl)
1069 {
1070 assert(conn != NULL);
1071 conn->closure = cl;
1072 }
1073
1074 /*** pptp_conn_closure_get ****************************************************/
pptp_conn_closure_get(PPTP_CONN * conn)1075 void * pptp_conn_closure_get(PPTP_CONN * conn)
1076 {
1077 assert(conn != NULL);
1078 return conn->closure;
1079 }
1080
1081 /*** Reset keep-alive timer ***************************************************/
pptp_reset_timer(void)1082 static void pptp_reset_timer(void)
1083 {
1084 const struct itimerval tv = { { 0, 0 }, /* stop on time-out */
1085 { idle_wait, 0 } };
1086 if (idle_wait) setitimer(ITIMER_REAL, &tv, NULL);
1087 }
1088
1089
1090 /*** Handle keep-alive timer **************************************************/
pptp_handle_timer(void)1091 static void pptp_handle_timer(void)
1092 {
1093 int i;
1094 /* "Keep Alives and Timers, 1": check connection state */
1095 if (global.conn->conn_state != CONN_ESTABLISHED) {
1096 if (global.conn->conn_state == CONN_WAIT_STOP_REPLY) {
1097 /* hard close. */
1098 pptp_conn_destroy(global.conn);
1099 return;
1100 }
1101 /* soft close */
1102 pptp_conn_close(global.conn, PPTP_STOP_NONE);
1103 }
1104 /* "Keep Alives and Timers, 2": check echo status */
1105 if (global.conn->ka_state == KA_OUTSTANDING) {
1106 /* no response to keep-alive */
1107 log ("closing control connection due to missing echo reply");
1108 pptp_conn_close(global.conn, PPTP_STOP_NONE);
1109 } else { /* ka_state == NONE */ /* send keep-alive */
1110 struct pptp_echo_rqst rqst = {
1111 PPTP_HEADER_CTRL(PPTP_ECHO_RQST), hton32(global.conn->ka_id) };
1112 if (pptp_send_ctrl_packet(global.conn, &rqst, sizeof(rqst))) {
1113 global.conn->ka_state = KA_OUTSTANDING;
1114 }
1115 }
1116 /* check incoming/outgoing call states for !IDLE && !ESTABLISHED */
1117 for (i = 0; i < vector_size(global.conn->call); i++) {
1118 PPTP_CALL * call = vector_get_Nth(global.conn->call, i);
1119 if (call->call_type == PPTP_CALL_PNS) {
1120 if (call->state.pns == PNS_WAIT_REPLY) {
1121 /* send close request */
1122 pptp_call_close(global.conn, call);
1123 assert(call->state.pns == PNS_WAIT_DISCONNECT);
1124 } else if (call->state.pns == PNS_WAIT_DISCONNECT) {
1125 /* hard-close the call */
1126 pptp_call_destroy(global.conn, call);
1127 }
1128 } else if (call->call_type == PPTP_CALL_PAC) {
1129 if (call->state.pac == PAC_WAIT_REPLY) {
1130 /* XXX FIXME -- drop the PAC connection XXX */
1131 } else if (call->state.pac == PAC_WAIT_CS_ANS) {
1132 /* XXX FIXME -- drop the PAC connection XXX */
1133 }
1134 }
1135 }
1136 pptp_reset_timer();
1137 }
1138