Allow IPv6 address entry in tools>ping - Loosens valid character check
[tomato/davidwu.git] / release / src / router / pptp-client / pptp_ctrl.c
blob64ea0b96989e7d56009d27c2583570ef3541bdd5
1 /* pptp_ctrl.c ... handle PPTP control connection.
2 * C. Scott Ananian <cananian@alumni.princeton.edu>
4 * $Id: pptp_ctrl.c,v 1.31 2005/03/31 07:42:39 quozl Exp $
5 */
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 <unistd.h>
13 #include <stdlib.h>
14 #include <assert.h>
15 #include <signal.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <fcntl.h>
19 #include "pptp_msg.h"
20 #include "pptp_ctrl.h"
21 #include "pptp_options.h"
22 #include "vector.h"
23 #include "util.h"
24 #include "pptp_quirks.h"
26 /* BECAUSE OF SIGNAL LIMITATIONS, EACH PROCESS CAN ONLY MANAGE ONE
27 * CONNECTION. SO THIS 'PPTP_CONN' STRUCTURE IS A BIT MISLEADING.
28 * WE'LL KEEP CONNECTION-SPECIFIC INFORMATION IN THERE ANYWAY (AS
29 * OPPOSED TO USING GLOBAL VARIABLES), BUT BEWARE THAT THE ENTIRE
30 * UNIX SIGNAL-HANDLING SEMANTICS WOULD HAVE TO CHANGE (OR THE
31 * TIME-OUT CODE DRASTICALLY REWRITTEN) BEFORE YOU COULD DO A
32 * PPTP_CONN_OPEN MORE THAN ONCE PER PROCESS AND GET AWAY WITH IT.
35 /* This structure contains connection-specific information that the
36 * signal handler needs to see. Thus, it needs to be in a global
37 * variable. If you end up using pthreads or something (why not
38 * just processes?), this would have to be placed in a thread-specific
39 * data area, using pthread_get|set_specific, etc., so I've
40 * conveniently encapsulated it for you.
41 * [linux threads will have to support thread-specific signals
42 * before this would work at all, which, as of this writing
43 * (linux-threads v0.6, linux kernel 2.1.72), it does not.]
46 /* Globals */
47 extern int syncppp;
49 /* control the number of times echo packets will be logged */
50 static int nlogecho = 10;
52 static struct thread_specific {
53 struct sigaction old_sigaction; /* evil signals */
54 PPTP_CONN * conn;
55 } global;
57 #define INITIAL_BUFSIZE 512 /* initial i/o buffer size. */
59 struct PPTP_CONN {
60 int inet_sock;
61 /* Connection States */
62 enum {
63 CONN_IDLE, CONN_WAIT_CTL_REPLY, CONN_WAIT_STOP_REPLY, CONN_ESTABLISHED
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;
87 struct 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;
109 /* PPTP error codes: ----------------------------------------------*/
111 /* (General Error Codes) */
112 static 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" }
133 #define MAX_GENERAL_ERROR ( sizeof(pptp_general_errors) / \
134 sizeof(pptp_general_errors[0]) - 1)
136 /* Outgoing Call Reply Result Codes */
137 static 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" };
147 #define MAX_OUT_CALL_REPLY_RESULT 7
149 /* Call Disconnect Notify Result Codes */
150 static 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" };
157 #define MAX_CALL_DISC_NTFY 4
159 /* Call Disconnect Notify Result Codes */
160 static 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" };
167 #define MAX_START_CTRL_CONN_REPLY 4
169 /* timing options */
170 int idle_wait = PPTP_TIMEOUT;
171 int max_echo_wait = PPTP_TIMEOUT;
173 /* Local prototypes */
174 static void pptp_reset_timer(void);
175 static void pptp_handle_timer();
176 /* Write/read as much as we can without blocking. */
177 int pptp_write_some(PPTP_CONN * conn);
178 int pptp_read_some(PPTP_CONN * conn);
179 /* Make valid packets from read_buffer */
180 int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size);
181 /* Add packet to write_buffer */
182 int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size);
183 /* Dispatch packets (general) */
184 int pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size);
185 /* Dispatch packets (control messages) */
186 int 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 */
191 void pptp_set_link(PPTP_CONN * conn, int peer_call_id);
193 /*** log error information in control packets *********************************/
194 static void ctrlp_error( int result, int error, int cause,
195 const char *result_text[], int max_result)
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);
214 static 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 */
236 #define MAX_CTRLMSG_TYPE 15
238 /*** report a sent packet ****************************************************/
239 static void ctrlp_rep( void * buffer, int size, int isbuff)
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]);
258 /* Open new pptp_connection. Returns NULL on failure. */
259 PPTP_CONN * pptp_conn_open(int inet_sock, int isclient, pptp_conn_cb callback)
261 PPTP_CONN *conn;
262 /* Allocate structure */
263 if ((conn = malloc(sizeof(*conn))) == NULL) return NULL;
264 if ((conn->call = vector_create()) == NULL) { free(conn); return NULL; }
265 /* Initialize */
266 conn->inet_sock = inet_sock;
267 conn->conn_state = CONN_IDLE;
268 conn->ka_state = KA_NONE;
269 conn->ka_id = 1;
270 conn->call_serial_number = 0;
271 conn->callback = callback;
272 /* Create I/O buffers */
273 conn->read_size = conn->write_size = 0;
274 conn->read_alloc = conn->write_alloc = INITIAL_BUFSIZE;
275 conn->read_buffer =
276 malloc(sizeof(*(conn->read_buffer)) * conn->read_alloc);
277 conn->write_buffer =
278 malloc(sizeof(*(conn->write_buffer)) * conn->write_alloc);
279 if (conn->read_buffer == NULL || conn->write_buffer == NULL) {
280 if (conn->read_buffer != NULL) free(conn->read_buffer);
281 if (conn->write_buffer != NULL) free(conn->write_buffer);
282 vector_destroy(conn->call); free(conn); return NULL;
284 /* Make this socket non-blocking. */
285 fcntl(conn->inet_sock, F_SETFL, O_NONBLOCK);
286 /* Request connection from server, if this is a client */
287 if (isclient) {
288 struct pptp_start_ctrl_conn packet = {
289 PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RQST),
290 hton16(PPTP_VERSION), 0, 0,
291 hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP),
292 hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION),
293 PPTP_HOSTNAME, PPTP_VENDOR
295 /* fix this packet, if necessary */
296 int idx, rc;
297 idx = get_quirk_index();
298 if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) {
299 if ((rc = pptp_fixups[idx].start_ctrl_conn(&packet)))
300 warn("calling the start_ctrl_conn hook failed (%d)", rc);
302 if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet)))
303 conn->conn_state = CONN_WAIT_CTL_REPLY;
304 else
305 return NULL; /* could not send initial start request. */
307 /* Set up interval/keep-alive timer */
308 /* First, register handler for SIGALRM */
309 sigpipe_create();
310 sigpipe_assign(SIGALRM);
311 global.conn = conn;
312 /* Reset event timer */
313 pptp_reset_timer();
314 /* all done. */
315 return conn;
318 int pptp_conn_established(PPTP_CONN *conn) {
319 return (conn->conn_state == CONN_ESTABLISHED);
322 /* This currently *only* works for client call requests.
323 * We need to do something else to allocate calls for incoming requests.
325 PPTP_CALL * pptp_call_open(PPTP_CONN * conn, pptp_call_cb callback,
326 char *phonenr)
328 PPTP_CALL * call;
329 int i;
330 int idx, rc;
331 /* Send off the call request */
332 struct pptp_out_call_rqst packet = {
333 PPTP_HEADER_CTRL(PPTP_OUT_CALL_RQST),
334 0,0, /*call_id, sernum */
335 hton32(PPTP_BPS_MIN), hton32(PPTP_BPS_MAX),
336 hton32(PPTP_BEARER_CAP), hton32(PPTP_FRAME_CAP),
337 hton16(PPTP_WINDOW), 0, 0, 0, {0}, {0}
339 assert(conn && conn->call);
340 assert(conn->conn_state == CONN_ESTABLISHED);
341 /* Assign call id */
342 if (!vector_scan(conn->call, 0, PPTP_MAX_CHANNELS - 1, &i))
343 /* no more calls available! */
344 return NULL;
345 /* allocate structure. */
346 if ((call = malloc(sizeof(*call))) == NULL) return NULL;
347 /* Initialize call structure */
348 call->call_type = PPTP_CALL_PNS;
349 call->state.pns = PNS_IDLE;
350 call->call_id = (u_int16_t) i;
351 call->sernum = conn->call_serial_number++;
352 call->callback = callback;
353 call->closure = NULL;
354 packet.call_id = htons(call->call_id);
355 packet.call_sernum = htons(call->sernum);
356 /* if we have a quirk, build a new packet to fit it */
357 idx = get_quirk_index();
358 if (idx != -1 && pptp_fixups[idx].out_call_rqst_hook) {
359 if ((rc = pptp_fixups[idx].out_call_rqst_hook(&packet)))
360 warn("calling the out_call_rqst hook failed (%d)", rc);
362 /* fill in the phone number if it was specified */
363 if (phonenr) {
364 strncpy(packet.phone_num, phonenr, sizeof(packet.phone_num));
365 packet.phone_len = strlen(phonenr);
366 if( packet.phone_len > sizeof(packet.phone_num))
367 packet.phone_len = sizeof(packet.phone_num);
368 packet.phone_len = hton16 (packet.phone_len);
370 if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) {
371 pptp_reset_timer();
372 call->state.pns = PNS_WAIT_REPLY;
373 /* and add it to the call vector */
374 vector_insert(conn->call, i, call);
375 return call;
376 } else { /* oops, unsuccessful. Deallocate. */
377 free(call);
378 return NULL;
382 /*** pptp_call_close **********************************************************/
383 void pptp_call_close(PPTP_CONN * conn, PPTP_CALL * call)
385 struct pptp_call_clear_rqst rqst = {
386 PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_RQST), 0, 0
388 assert(conn && conn->call); assert(call);
389 assert(vector_contains(conn->call, call->call_id));
390 /* haven't thought about PAC yet */
391 assert(call->call_type == PPTP_CALL_PNS);
392 assert(call->state.pns != PNS_IDLE);
393 rqst.call_id = hton16(call->call_id);
394 /* don't check state against WAIT_DISCONNECT... allow multiple disconnect
395 * requests to be made.
397 pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst));
398 pptp_reset_timer();
399 call->state.pns = PNS_WAIT_DISCONNECT;
400 /* call structure will be freed when we have confirmation of disconnect. */
403 /*** hard close ***************************************************************/
404 void pptp_call_destroy(PPTP_CONN *conn, PPTP_CALL *call)
406 assert(conn && conn->call); assert(call);
407 assert(vector_contains(conn->call, call->call_id));
408 /* notify */
409 if (call->callback != NULL) call->callback(conn, call, CALL_CLOSE_DONE);
410 /* deallocate */
411 vector_remove(conn->call, call->call_id);
412 free(call);
415 /*** this is a soft close *****************************************************/
416 void pptp_conn_close(PPTP_CONN * conn, u_int8_t close_reason)
418 struct pptp_stop_ctrl_conn rqst = {
419 PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RQST),
420 hton8(close_reason), 0, 0
422 int i;
423 assert(conn && conn->call);
424 /* avoid repeated close attempts */
425 if (conn->conn_state == CONN_IDLE || conn->conn_state == CONN_WAIT_STOP_REPLY)
426 return;
427 /* close open calls, if any */
428 for (i = 0; i < vector_size(conn->call); i++)
429 pptp_call_close(conn, vector_get_Nth(conn->call, i));
430 /* now close connection */
431 log("Closing PPTP connection");
432 pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst));
433 pptp_reset_timer(); /* wait 60 seconds for reply */
434 conn->conn_state = CONN_WAIT_STOP_REPLY;
435 return;
438 /*** this is a hard close *****************************************************/
439 void pptp_conn_destroy(PPTP_CONN * conn)
441 int i;
442 assert(conn != NULL); assert(conn->call != NULL);
443 /* destroy all open calls */
444 for (i = 0; i < vector_size(conn->call); i++)
445 pptp_call_destroy(conn, vector_get_Nth(conn->call, i));
446 /* notify */
447 if (conn->callback != NULL) conn->callback(conn, CONN_CLOSE_DONE);
448 sigpipe_close();
449 close(conn->inet_sock);
450 /* deallocate */
451 vector_destroy(conn->call);
452 free(conn);
455 /*** Deal with messages, in a non-blocking manner
456 * Add file descriptors used by pptp to fd_set.
458 void pptp_fd_set(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set,
459 int * max_fd)
461 assert(conn && conn->call);
462 /* Add fd to write_set if there are outstanding writes. */
463 if (conn->write_size > 0)
464 FD_SET(conn->inet_sock, write_set);
465 /* Always add fd to read_set. (always want something to read) */
466 FD_SET(conn->inet_sock, read_set);
467 if (*max_fd < conn->inet_sock) *max_fd = conn->inet_sock;
468 /* Add signal pipe file descriptor to set */
469 int sig_fd = sigpipe_fd();
470 FD_SET(sig_fd, read_set);
471 if (*max_fd < sig_fd) *max_fd = sig_fd;
474 /*** handle any pptp file descriptors set in fd_set, and clear them ***********/
475 int pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set)
477 int r = 0;
478 assert(conn && conn->call);
479 /* Check for signals */
480 if (FD_ISSET(sigpipe_fd(), read_set)) {
481 if (sigpipe_read() == SIGALRM) pptp_handle_timer();
482 FD_CLR(sigpipe_fd(), read_set);
484 /* Check write_set could be set. */
485 if (FD_ISSET(conn->inet_sock, write_set)) {
486 FD_CLR(conn->inet_sock, write_set);
487 if (conn->write_size > 0)
488 r = pptp_write_some(conn);/* write as much as we can without blocking */
490 /* Check read_set */
491 if (r >= 0 && FD_ISSET(conn->inet_sock, read_set)) {
492 void *buffer; size_t size;
493 FD_CLR(conn->inet_sock, read_set);
494 r = pptp_read_some(conn); /* read as much as we can without blocking */
495 if (r < 0)
496 return r;
497 /* make packets of the buffer, while we can. */
498 while (r >= 0 && pptp_make_packet(conn, &buffer, &size)) {
499 r = pptp_dispatch_packet(conn, buffer, size);
500 free(buffer);
503 /* That's all, folks. Simple, eh? */
504 return r;
507 /*** Non-blocking write *******************************************************/
508 int pptp_write_some(PPTP_CONN * conn) {
509 ssize_t retval;
510 assert(conn && conn->call);
511 retval = write(conn->inet_sock, conn->write_buffer, conn->write_size);
512 if (retval < 0) { /* error. */
513 if (errno == EAGAIN || errno == EINTR) {
514 return 0;
515 } else { /* a real error */
516 log("write error: %s", strerror(errno));
517 return -1;
520 assert(retval <= conn->write_size);
521 conn->write_size -= retval;
522 memmove(conn->write_buffer, conn->write_buffer + retval, conn->write_size);
523 ctrlp_rep(conn->write_buffer, retval, 0);
524 return 0;
527 /*** Non-blocking read ********************************************************/
528 int pptp_read_some(PPTP_CONN * conn)
530 ssize_t retval;
531 assert(conn && conn->call);
532 if (conn->read_size == conn->read_alloc) { /* need to alloc more memory */
533 char *new_buffer = realloc(conn->read_buffer,
534 sizeof(*(conn->read_buffer)) * conn->read_alloc * 2);
535 if (new_buffer == NULL) {
536 log("Out of memory"); return -1;
538 conn->read_alloc *= 2;
539 conn->read_buffer = new_buffer;
541 retval = read(conn->inet_sock, conn->read_buffer + conn->read_size,
542 conn->read_alloc - conn->read_size);
543 if (retval == 0) {
544 log("read returned zero, peer has closed");
545 return -1;
547 if (retval < 0) {
548 if (errno == EINTR || errno == EAGAIN)
549 return 0;
550 else { /* a real error */
551 log("read error: %s", strerror(errno));
552 return -1;
555 conn->read_size += retval;
556 assert(conn->read_size <= conn->read_alloc);
557 return 0;
560 /*** Packet formation *********************************************************/
561 int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size)
563 struct pptp_header *header;
564 size_t bad_bytes = 0;
565 assert(conn && conn->call); assert(buf != NULL); assert(size != NULL);
566 /* Give up unless there are at least sizeof(pptp_header) bytes */
567 while ((conn->read_size-bad_bytes) >= sizeof(struct pptp_header)) {
568 /* Throw out bytes until we have a valid header. */
569 header = (struct pptp_header *) (conn->read_buffer + bad_bytes);
570 if (ntoh32(header->magic) != PPTP_MAGIC) goto throwitout;
571 if (ntoh16(header->reserved0) != 0)
572 log("reserved0 field is not zero! (0x%x) Cisco feature? \n",
573 ntoh16(header->reserved0));
574 if (ntoh16(header->length) < sizeof(struct pptp_header)) goto throwitout;
575 if (ntoh16(header->length) > PPTP_CTRL_SIZE_MAX) goto throwitout;
576 /* well. I guess it's good. Let's see if we've got it all. */
577 if (ntoh16(header->length) > (conn->read_size-bad_bytes))
578 /* nope. Let's wait until we've got it, then. */
579 goto flushbadbytes;
580 /* One last check: */
581 if ((ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL) &&
582 (ntoh16(header->length) !=
583 PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))))
584 goto throwitout;
585 /* well, I guess we've got it. */
586 *size = ntoh16(header->length);
587 *buf = malloc(*size);
588 if (*buf == NULL) { log("Out of memory."); return 0; /* ack! */ }
589 memcpy(*buf, conn->read_buffer + bad_bytes, *size);
590 /* Delete this packet from the read_buffer. */
591 conn->read_size -= (bad_bytes + *size);
592 memmove(conn->read_buffer, conn->read_buffer + bad_bytes + *size,
593 conn->read_size);
594 if (bad_bytes > 0)
595 log("%lu bad bytes thrown away.", (unsigned long) bad_bytes);
596 return 1;
597 throwitout:
598 bad_bytes++;
600 flushbadbytes:
601 /* no more packets. Let's get rid of those bad bytes */
602 conn->read_size -= bad_bytes;
603 memmove(conn->read_buffer, conn->read_buffer + bad_bytes, conn->read_size);
604 if (bad_bytes > 0)
605 log("%lu bad bytes thrown away.", (unsigned long) bad_bytes);
606 return 0;
609 /*** pptp_send_ctrl_packet ****************************************************/
610 int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size)
612 assert(conn && conn->call); assert(buffer);
613 if( conn->write_size > 0) pptp_write_some( conn);
614 if( conn->write_size == 0) {
615 ssize_t retval;
616 retval = write(conn->inet_sock, buffer, size);
617 if (retval < 0) { /* error. */
618 if (errno == EAGAIN || errno == EINTR) {
619 /* ignore */;
620 retval = 0;
621 } else { /* a real error */
622 log("write error: %s", strerror(errno));
623 pptp_conn_destroy(conn); /* shut down fast. */
624 return 0;
627 ctrlp_rep( buffer, retval, 0);
628 size -= retval;
629 if( size <= 0) return 1;
631 /* Shove anything not written into the write buffer */
632 if (conn->write_size + size > conn->write_alloc) { /* need more memory */
633 char *new_buffer = realloc(conn->write_buffer,
634 sizeof(*(conn->write_buffer)) * conn->write_alloc * 2);
635 if (new_buffer == NULL) {
636 log("Out of memory"); return 0;
638 conn->write_alloc *= 2;
639 conn->write_buffer = new_buffer;
641 memcpy(conn->write_buffer + conn->write_size, buffer, size);
642 conn->write_size += size;
643 ctrlp_rep( buffer,size,1);
644 return 1;
647 /*** Packet Dispatch **********************************************************/
648 int pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size)
650 int r = 0;
651 struct pptp_header *header = (struct pptp_header *)buffer;
652 assert(conn && conn->call); assert(buffer);
653 assert(ntoh32(header->magic) == PPTP_MAGIC);
654 assert(ntoh16(header->length) == size);
655 switch (ntoh16(header->pptp_type)) {
656 case PPTP_MESSAGE_CONTROL:
657 r = ctrlp_disp(conn, buffer, size);
658 break;
659 case PPTP_MESSAGE_MANAGE:
660 /* MANAGEMENT messages aren't even part of the spec right now. */
661 log("PPTP management message received, but not understood.");
662 break;
663 default:
664 log("Unknown PPTP control message type received: %u",
665 (unsigned int) ntoh16(header->pptp_type));
666 break;
668 return r;
671 /*** log echo request/replies *************************************************/
672 static void logecho( int type)
674 /* hack to stop flooding the log files (the most interesting part is right
675 * after the connection built-up) */
676 if( nlogecho > 0) {
677 log( "Echo Re%s received.", type == PPTP_ECHO_RQST ? "quest" :"ply");
678 if( --nlogecho == 0)
679 log("no more Echo Reply/Request packets will be reported.");
683 /*** pptp_dispatch_ctrl_packet ************************************************/
684 int ctrlp_disp(PPTP_CONN * conn, void * buffer, size_t size)
686 struct pptp_header *header = (struct pptp_header *)buffer;
687 u_int8_t close_reason = PPTP_STOP_NONE;
688 assert(conn && conn->call); assert(buffer);
689 assert(ntoh32(header->magic) == PPTP_MAGIC);
690 assert(ntoh16(header->length) == size);
691 assert(ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL);
692 if (size < PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))) {
693 log("Invalid packet received [type: %d; length: %d].",
694 (int) ntoh16(header->ctrl_type), (int) size);
695 return 0;
697 switch (ntoh16(header->ctrl_type)) {
698 /* ----------- STANDARD Start-Session MESSAGES ------------ */
699 case PPTP_START_CTRL_CONN_RQST:
701 struct pptp_start_ctrl_conn *packet =
702 (struct pptp_start_ctrl_conn *) buffer;
703 struct pptp_start_ctrl_conn reply = {
704 PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RPLY),
705 hton16(PPTP_VERSION), 0, 0,
706 hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP),
707 hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION),
708 PPTP_HOSTNAME, PPTP_VENDOR };
709 int idx, rc;
710 log("Received Start Control Connection Request");
711 /* fix this packet, if necessary */
712 idx = get_quirk_index();
713 if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) {
714 if ((rc = pptp_fixups[idx].start_ctrl_conn(&reply)))
715 warn("calling the start_ctrl_conn hook failed (%d)", rc);
717 if (conn->conn_state == CONN_IDLE) {
718 if (ntoh16(packet->version) < PPTP_VERSION) {
719 /* Can't support this (earlier) PPTP_VERSION */
720 reply.version = packet->version;
721 /* protocol version not supported */
722 reply.result_code = hton8(5);
723 pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
724 pptp_reset_timer(); /* give sender a chance for a retry */
725 } else { /* same or greater version */
726 if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) {
727 conn->conn_state = CONN_ESTABLISHED;
728 log("server connection ESTABLISHED.");
729 pptp_reset_timer();
733 break;
735 case PPTP_START_CTRL_CONN_RPLY:
737 struct pptp_start_ctrl_conn *packet =
738 (struct pptp_start_ctrl_conn *) buffer;
739 log("Received Start Control Connection Reply");
740 if (conn->conn_state == CONN_WAIT_CTL_REPLY) {
741 /* XXX handle collision XXX [see rfc] */
742 if (ntoh16(packet->version) != PPTP_VERSION) {
743 if (conn->callback != NULL)
744 conn->callback(conn, CONN_OPEN_FAIL);
745 close_reason = PPTP_STOP_PROTOCOL;
746 goto pptp_conn_close;
748 if (ntoh8(packet->result_code) != 1 &&
749 /* J'ai change le if () afin que la connection ne se ferme
750 * pas pour un "rien" :p adel@cybercable.fr -
752 * Don't close the connection if the result code is zero
753 * (feature found in certain ADSL modems)
755 ntoh8(packet->result_code) != 0) {
756 log("Negative reply received to our Start Control "
757 "Connection Request");
758 ctrlp_error(packet->result_code, packet->error_code,
759 -1, pptp_start_ctrl_conn_rply,
760 MAX_START_CTRL_CONN_REPLY);
761 if (conn->callback != NULL)
762 conn->callback(conn, CONN_OPEN_FAIL);
763 close_reason = PPTP_STOP_PROTOCOL;
764 goto pptp_conn_close;
766 conn->conn_state = CONN_ESTABLISHED;
767 /* log session properties */
768 conn->version = ntoh16(packet->version);
769 conn->firmware_rev = ntoh16(packet->firmware_rev);
770 memcpy(conn->hostname, packet->hostname, sizeof(conn->hostname));
771 memcpy(conn->vendor, packet->vendor, sizeof(conn->vendor));
772 pptp_reset_timer(); /* 60 seconds until keep-alive */
773 log("Client connection established.");
774 if (conn->callback != NULL)
775 conn->callback(conn, CONN_OPEN_DONE);
776 } /* else goto pptp_conn_close; */
777 break;
779 /* ----------- STANDARD Stop-Session MESSAGES ------------ */
780 case PPTP_STOP_CTRL_CONN_RQST:
782 /* conn_state should be CONN_ESTABLISHED, but it could be
783 * something else */
784 struct pptp_stop_ctrl_conn reply = {
785 PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RPLY),
786 hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0
788 log("Received Stop Control Connection Request.");
789 if (conn->conn_state == CONN_IDLE) break;
790 if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) {
791 if (conn->callback != NULL)
792 conn->callback(conn, CONN_CLOSE_RQST);
793 conn->conn_state = CONN_IDLE;
794 return -1;
796 break;
798 case PPTP_STOP_CTRL_CONN_RPLY:
800 log("Received Stop Control Connection Reply.");
801 /* conn_state should be CONN_WAIT_STOP_REPLY, but it
802 * could be something else */
803 if (conn->conn_state == CONN_IDLE) break;
804 conn->conn_state = CONN_IDLE;
805 return -1;
807 /* ----------- STANDARD Echo/Keepalive MESSAGES ------------ */
808 case PPTP_ECHO_RPLY:
810 struct pptp_echo_rply *packet =
811 (struct pptp_echo_rply *) buffer;
812 logecho( PPTP_ECHO_RPLY);
813 if ((conn->ka_state == KA_OUTSTANDING) &&
814 (ntoh32(packet->identifier) == conn->ka_id)) {
815 conn->ka_id++;
816 conn->ka_state = KA_NONE;
817 pptp_reset_timer();
819 break;
821 case PPTP_ECHO_RQST:
823 struct pptp_echo_rqst *packet =
824 (struct pptp_echo_rqst *) buffer;
825 struct pptp_echo_rply reply = {
826 PPTP_HEADER_CTRL(PPTP_ECHO_RPLY),
827 packet->identifier, /* skip hton32(ntoh32(id)) */
828 hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0
830 logecho( PPTP_ECHO_RQST);
831 pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
832 pptp_reset_timer();
833 break;
835 /* ----------- OUTGOING CALL MESSAGES ------------ */
836 case PPTP_OUT_CALL_RQST:
838 struct pptp_out_call_rqst *packet =
839 (struct pptp_out_call_rqst *)buffer;
840 struct pptp_out_call_rply reply = {
841 PPTP_HEADER_CTRL(PPTP_OUT_CALL_RPLY),
842 0 /* callid */, packet->call_id, 1, PPTP_GENERAL_ERROR_NONE, 0,
843 hton32(PPTP_CONNECT_SPEED),
844 hton16(PPTP_WINDOW), hton16(PPTP_DELAY), 0
846 log("Received Outgoing Call Request.");
847 /* XXX PAC: eventually this should make an outgoing call. XXX */
848 reply.result_code = hton8(7); /* outgoing calls verboten */
849 pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
850 break;
852 case PPTP_OUT_CALL_RPLY:
854 struct pptp_out_call_rply *packet =
855 (struct pptp_out_call_rply *)buffer;
856 PPTP_CALL * call;
857 u_int16_t callid = ntoh16(packet->call_id_peer);
858 log("Received Outgoing Call Reply.");
859 if (!vector_search(conn->call, (int) callid, &call)) {
860 log("PPTP_OUT_CALL_RPLY received for non-existant call: "
861 "peer call ID (us) %d call ID (them) %d.",
862 callid, ntoh16(packet->call_id));
863 break;
865 if (call->call_type != PPTP_CALL_PNS) {
866 log("Ack! How did this call_type get here?"); /* XXX? */
867 break;
869 if (call->state.pns != PNS_WAIT_REPLY) {
870 warn("Unexpected(?) Outgoing Call Reply will be ignored.");
871 break;
873 /* check for errors */
874 if (packet->result_code != 1) {
875 /* An error. Log it verbosely. */
876 log("Our outgoing call request [callid %d] has not been "
877 "accepted.", (int) callid);
878 ctrlp_error(packet->result_code, packet->error_code,
879 packet->cause_code, pptp_out_call_reply_result,
880 MAX_OUT_CALL_REPLY_RESULT);
881 call->state.pns = PNS_IDLE;
882 if (call->callback != NULL)
883 call->callback(conn, call, CALL_OPEN_FAIL);
884 pptp_call_destroy(conn, call);
885 } else {
886 /* connection established */
887 call->state.pns = PNS_ESTABLISHED;
888 call->peer_call_id = ntoh16(packet->call_id);
889 call->speed = ntoh32(packet->speed);
890 pptp_reset_timer();
891 /* call pptp_set_link. unless the user specified a quirk
892 and this quirk has a set_link hook, this is a noop */
893 pptp_set_link(conn, call->peer_call_id);
894 if (call->callback != NULL)
895 call->callback(conn, call, CALL_OPEN_DONE);
896 log("Outgoing call established (call ID %u, peer's "
897 "call ID %u).\n", call->call_id, call->peer_call_id);
899 break;
901 /* ----------- INCOMING CALL MESSAGES ------------ */
902 /* XXX write me XXX */
903 /* ----------- CALL CONTROL MESSAGES ------------ */
904 case PPTP_CALL_CLEAR_RQST:
906 struct pptp_call_clear_rqst *packet =
907 (struct pptp_call_clear_rqst *)buffer;
908 struct pptp_call_clear_ntfy reply = {
909 PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_NTFY), packet->call_id,
910 1, PPTP_GENERAL_ERROR_NONE, 0, 0, {0}
912 log("Received Call Clear Request.");
913 if (vector_contains(conn->call, ntoh16(packet->call_id))) {
914 PPTP_CALL * call;
915 vector_search(conn->call, ntoh16(packet->call_id), &call);
916 if (call->callback != NULL)
917 call->callback(conn, call, CALL_CLOSE_RQST);
918 pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
919 pptp_call_destroy(conn, call);
920 log("Call closed (RQST) (call id %d)", (int) call->call_id);
922 break;
924 case PPTP_CALL_CLEAR_NTFY:
926 struct pptp_call_clear_ntfy *packet =
927 (struct pptp_call_clear_ntfy *)buffer;
928 log("Call disconnect notification received (call id %d)",
929 ntoh16(packet->call_id));
930 if (vector_contains(conn->call, ntoh16(packet->call_id))) {
931 PPTP_CALL * call;
932 ctrlp_error(packet->result_code, packet->error_code,
933 packet->cause_code, pptp_call_disc_ntfy,
934 MAX_CALL_DISC_NTFY);
935 vector_search(conn->call, ntoh16(packet->call_id), &call);
936 pptp_call_destroy(conn, call);
938 /* XXX we could log call stats here XXX */
939 /* XXX not all servers send this XXX */
940 break;
942 case PPTP_SET_LINK_INFO:
944 /* I HAVE NO CLUE WHAT TO DO IF send_accm IS NOT 0! */
945 /* this is really dealt with in the HDLC deencapsulation, anyway. */
946 struct pptp_set_link_info *packet =
947 (struct pptp_set_link_info *)buffer;
948 /* log it. */
949 log("PPTP_SET_LINK_INFO received from peer_callid %u",
950 (unsigned int) ntoh16(packet->call_id_peer));
951 log(" send_accm is %08lX, recv_accm is %08lX",
952 (unsigned long) ntoh32(packet->send_accm),
953 (unsigned long) ntoh32(packet->recv_accm));
954 if (syncppp && !(ntoh32(packet->send_accm) == 0 &&
955 ntoh32(packet->recv_accm) == 0))
956 warn("Non-zero Async Control Character Maps are not supported!");
957 break;
959 default:
960 log("Unrecognized Packet %d received.",
961 (int) ntoh16(((struct pptp_header *)buffer)->ctrl_type));
962 /* goto pptp_conn_close; */
963 break;
965 return 0;
966 pptp_conn_close:
967 warn("pptp_conn_close(%d)", (int) close_reason);
968 pptp_conn_close(conn, close_reason);
969 return 0;
972 /*** pptp_set_link **************************************************************/
973 void pptp_set_link(PPTP_CONN* conn, int peer_call_id)
975 int idx, rc;
976 /* if we need to send a set_link packet because of buggy
977 hardware or pptp server, do it now */
978 if ((idx = get_quirk_index()) != -1 && pptp_fixups[idx].set_link_hook) {
979 struct pptp_set_link_info packet;
980 if ((rc = pptp_fixups[idx].set_link_hook(&packet, peer_call_id)))
981 warn("calling the set_link hook failed (%d)", rc);
982 if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) {
983 pptp_reset_timer();
988 /*** Get info from call structure *********************************************/
989 /* NOTE: The peer_call_id is undefined until we get a server response. */
990 void pptp_call_get_ids(PPTP_CONN * conn, PPTP_CALL * call,
991 u_int16_t * call_id, u_int16_t * peer_call_id)
993 assert(conn != NULL); assert(call != NULL);
994 *call_id = call->call_id;
995 *peer_call_id = call->peer_call_id;
998 /*** pptp_call_closure_put ****************************************************/
999 void pptp_call_closure_put(PPTP_CONN * conn, PPTP_CALL * call, void *cl)
1001 assert(conn != NULL); assert(call != NULL);
1002 call->closure = cl;
1005 /*** pptp_call_closure_get ****************************************************/
1006 void * pptp_call_closure_get(PPTP_CONN * conn, PPTP_CALL * call)
1008 assert(conn != NULL); assert(call != NULL);
1009 return call->closure;
1012 /*** pptp_conn_closure_put ****************************************************/
1013 void pptp_conn_closure_put(PPTP_CONN * conn, void *cl)
1015 assert(conn != NULL);
1016 conn->closure = cl;
1019 /*** pptp_conn_closure_get ****************************************************/
1020 void * pptp_conn_closure_get(PPTP_CONN * conn)
1022 assert(conn != NULL);
1023 return conn->closure;
1026 /*** Reset keep-alive timer ***************************************************/
1027 static void pptp_reset_timer(void)
1029 const struct itimerval tv = { { 0, 0 }, /* stop on time-out */
1030 { idle_wait, 0 } };
1031 if (idle_wait) setitimer(ITIMER_REAL, &tv, NULL);
1035 /*** Handle keep-alive timer **************************************************/
1036 static void pptp_handle_timer()
1038 int i;
1039 /* "Keep Alives and Timers, 1": check connection state */
1040 if (global.conn->conn_state != CONN_ESTABLISHED) {
1041 if (global.conn->conn_state == CONN_WAIT_STOP_REPLY)
1042 /* hard close. */
1043 pptp_conn_destroy(global.conn);
1044 else /* soft close */
1045 pptp_conn_close(global.conn, PPTP_STOP_NONE);
1047 /* "Keep Alives and Timers, 2": check echo status */
1048 if (global.conn->ka_state == KA_OUTSTANDING) {
1049 /* no response to keep-alive */
1050 log ("closing control connection due to missing echo reply");
1051 pptp_conn_close(global.conn, PPTP_STOP_NONE);
1052 } else { /* ka_state == NONE */ /* send keep-alive */
1053 struct pptp_echo_rqst rqst = {
1054 PPTP_HEADER_CTRL(PPTP_ECHO_RQST), hton32(global.conn->ka_id) };
1055 pptp_send_ctrl_packet(global.conn, &rqst, sizeof(rqst));
1056 global.conn->ka_state = KA_OUTSTANDING;
1058 /* check incoming/outgoing call states for !IDLE && !ESTABLISHED */
1059 for (i = 0; i < vector_size(global.conn->call); i++) {
1060 PPTP_CALL * call = vector_get_Nth(global.conn->call, i);
1061 if (call->call_type == PPTP_CALL_PNS) {
1062 if (call->state.pns == PNS_WAIT_REPLY) {
1063 /* send close request */
1064 pptp_call_close(global.conn, call);
1065 assert(call->state.pns == PNS_WAIT_DISCONNECT);
1066 } else if (call->state.pns == PNS_WAIT_DISCONNECT) {
1067 /* hard-close the call */
1068 pptp_call_destroy(global.conn, call);
1070 } else if (call->call_type == PPTP_CALL_PAC) {
1071 if (call->state.pac == PAC_WAIT_REPLY) {
1072 /* XXX FIXME -- drop the PAC connection XXX */
1073 } else if (call->state.pac == PAC_WAIT_CS_ANS) {
1074 /* XXX FIXME -- drop the PAC connection XXX */
1078 pptp_reset_timer();