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