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