usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src / router / pptpd / pptpgre.c
blob9efabae63b1b02dad93d7bc4c147e1b5f05f0102
1 /*
2 * pptpgre.c
4 * originally by C. S. Ananian
5 * Modified for PoPToP
7 * $Id: pptpgre.c,v 1.9 2007/04/16 00:21:02 quozl Exp $
8 */
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
14 #ifdef __linux__
15 #define _GNU_SOURCE 1 /* broken arpa/inet.h */
16 #endif
18 #include "our_syslog.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <sys/stat.h>
27 #include <time.h>
28 #include <sys/time.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #ifdef HAVE_SYS_UIO_H
34 #include <sys/uio.h>
35 #endif
37 #include "ppphdlc.h"
38 #include "pptpgre.h"
39 #include "pptpdefs.h"
40 #include "pptpctrl.h"
41 #include "defaults.h"
42 #include "pqueue.h"
44 #ifndef HAVE_STRERROR
45 #include "compat.h"
46 #endif
48 #define PACKET_MAX 8196
50 typedef int (*callback_t)(int cl, void *pack, unsigned int len);
52 /* test for a 32 bit counter overflow */
53 #define WRAPPED( curseq, lastseq) \
54 ((((curseq) & 0xffffff00) == 0) && \
55 (((lastseq) & 0xffffff00 ) == 0xffffff00))
57 static struct gre_state gre;
58 gre_stats_t stats;
60 static uint64_t time_now_usecs()
62 struct timeval tv;
63 gettimeofday(&tv, NULL);
64 return (tv.tv_sec * 1000000) + tv.tv_usec;
67 int pptp_gre_init(u_int32_t call_id_pair, int pty_fd, struct in_addr *inetaddrs)
69 struct sockaddr_in addr;
70 int gre_fd;
72 /* Open IP protocol socket */
73 gre_fd = socket(AF_INET, SOCK_RAW, PPTP_PROTO);
74 if (gre_fd < 0) {
75 syslog(LOG_ERR, "GRE: socket() failed");
76 return -1;
79 memset(&addr, 0, sizeof(addr));
81 addr.sin_family = AF_INET;
82 addr.sin_addr = inetaddrs[0];
83 addr.sin_port = 0;
84 if (bind(gre_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
85 syslog(LOG_ERR, "GRE: bind() failed: %s", strerror(errno));
86 syslog(LOG_ERR, "GRE: continuing, but may not work if multi-homed");
89 addr.sin_family = AF_INET;
90 addr.sin_addr = inetaddrs[1];
91 addr.sin_port = 0;
92 if (connect(gre_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
93 syslog(LOG_ERR, "GRE: connect() failed: %s", strerror(errno));
94 return -1;
97 gre.seq_sent = 0;
98 gre.ack_sent = gre.ack_recv = gre.seq_recv = 0xFFFFFFFF;
99 /* seq_recv is -1, therefore next packet expected is seq 0,
100 to comply with RFC 2637: 'The sequence number for each
101 user session is set to zero at session startup.' */
103 gre.call_id_pair = call_id_pair; /* network byte order */
104 return gre_fd;
107 /* ONE blocking read per call; dispatches all packets possible */
108 /* returns 0 on success, or <0 on read failure */
109 int decaps_hdlc(int fd, int (*cb) (int cl, void *pack, unsigned len), int cl)
111 static unsigned char buffer[PACKET_MAX], copy[PACKET_MAX];
112 static unsigned start = 0, end = 0;
113 static unsigned len = 0, escape = 0;
114 static u_int16_t fcs = PPPINITFCS16;
115 static unsigned char err = 0;
116 unsigned char c;
117 int status;
119 /* we do one read only, since it may block. and only if the
120 * buffer is empty (start == end)
123 if (fd == -1) {
124 if(cb == NULL) {
125 /* peek mode */
126 return err ? -1 : 0;
127 } else if (!err) {
128 /* re-xmit and nothing queued */
129 syslog(LOG_ERR, "GRE: Re-xmit called with nothing queued");
130 return -1;
134 if (!err) {
135 /* All known data is processed. This true unless the last
136 * network write failed.
138 if ((status = read(fd, buffer, sizeof(buffer))) <= 0) {
139 syslog(LOG_ERR, "GRE: read(fd=%d,buffer=%lx,len=%d) from PTY failed: status = %d error = %s%s",
140 fd, (unsigned long) buffer, sizeof(buffer),
141 status, status ? strerror(errno) : "No error",
142 errno != EIO ? "" : ", usually caused by unexpected termination of pppd, check option syntax and pppd logs");
143 /* FAQ: mistakes in pppd option spelling in
144 * /etc/ppp/options.pptpd often cause EIO,
145 * with pppd not reporting the problem to any
146 * logs. Termination of pppd by signal can
147 * *also* cause this situation. -- James Cameron
149 return -1;
151 end = status;
152 start = 0;
153 } else {
154 /* We're here because of a network write failure. Try again.
155 * Then do what we would do normally and enter the loop as if
156 * just continuing the while(1). Not sure that this ever
157 * really happens, but since we error-check status then we
158 * should have the code to handle an error :-)
160 err = 0;
161 if ((status = cb(cl, copy, len)) < 0) {
162 syslog(LOG_ERR, "GRE: re-xmit failed from decaps_hdlc: %s", strerror(errno));
163 err = 1;
164 return status; /* return error */
166 /* Great! Let's do more! */
167 fcs = PPPINITFCS16;
168 len = 0;
169 escape = 0;
172 while (1) {
173 /* Infinite loop, we return when we're out of data */
175 /* Check if out of data */
176 if (start == end)
177 return 0;
179 /* Add to the packet up till the next HDLC_FLAG (start/end of
180 * packet marker). Copy to 'copy', un-escape and checksum as we go.
182 while (buffer[start] != HDLC_FLAG) {
184 /* Dispose of 'too long' packets */
185 if (len >= PACKET_MAX) {
186 syslog(LOG_ERR, "GRE: Received too long packet from pppd.");
187 while (buffer[start] != HDLC_FLAG && start < end)
188 start++;
189 if (start < end) {
190 goto newpacket;
191 } else
192 return 0;
194 /* Read a character, un-escaping if needed */
195 if (buffer[start] == HDLC_ESCAPE && !escape)
196 escape = 1;
197 else {
198 if (escape) {
199 copy[len] = c = buffer[start] ^ 0x20;
200 escape = 0;
201 } else
202 copy[len] = c = buffer[start];
203 fcs = (fcs >> 8) ^ fcstab[(fcs ^ c) & 0xff];
204 len++;
206 start++;
208 /* Check if out of data */
209 if (start == end)
210 return 0;
213 /* Found flag. Skip past it */
214 start++;
216 /* Check for over-short packets and silently discard, as per RFC1662 */
217 if ((len < 4) || (escape == 1)) {
218 /* len == 0 is possible, we generate it :-) [using HDLC_ESCAPE at
219 * start and end of packet]. Others are worth recording.
221 if (len && len < 4)
222 syslog(LOG_ERR, "GRE: Received too short packet from pppd.");
223 if (escape)
224 syslog(LOG_ERR, "GRE: Received bad packet from pppd.");
225 goto newpacket;
227 /* Check, then remove the 16-bit FCS checksum field */
228 if (fcs != PPPGOODFCS16) {
229 syslog(LOG_ERR, "GRE: Bad checksum from pppd.");
230 goto newpacket;
232 len -= sizeof(u_int16_t);
234 /* So now we have a packet of length 'len' in 'copy' */
235 if ((status = cb(cl, copy, len)) < 0) {
236 syslog(LOG_ERR, "GRE: xmit failed from decaps_hdlc: %s", strerror(errno));
237 err = 1;
238 return status; /* return error */
240 newpacket:
241 /* Great! Let's do more! */
242 fcs = PPPINITFCS16;
243 len = 0;
244 escape = 0;
248 #define seq_greater(A,B) ((A)>(B) || \
249 (((u_int32_t)(A)<0xff) && ((~((u_int32_t)(B)))<0xff)))
251 /* Macro used in encaps_hdlc(). add "val" to "dest" at position "pos",
252 * incrementing "pos" to point after the added value. set "tmp" to "val"
253 * as a side-effect.
255 #define ADD_CHAR(dest, pos, val, tmp) \
256 tmp = (val); \
257 if ((tmp<0x20) || (tmp==HDLC_FLAG) || (tmp==HDLC_ESCAPE)) { \
258 dest[pos++]=HDLC_ESCAPE; \
259 dest[pos++]=tmp^0x20; \
260 } else \
261 dest[pos++]=tmp
263 /* Make stripped packet into HDLC packet */
264 int encaps_hdlc(int fd, void *pack, unsigned len)
266 unsigned char *source = (unsigned char *) pack;
267 /* largest expansion possible - double all + double fcs + 2 flags */
268 static unsigned char dest[2 * PACKET_MAX + 6];
269 unsigned pos = 1, i;
270 u_int16_t fcs;
271 unsigned char c;
273 fcs = PPPINITFCS16;
275 /* make sure overflow is impossible so we don't have to bounds check
276 * in loop. drop large packets.
278 if (len > PACKET_MAX) {
279 syslog(LOG_ERR, "GRE: Asked to encapsulate too large packet (len = %d)", len);
280 return -1;
282 /* start character */
283 dest[0] = HDLC_FLAG;
285 /* escape the payload */
286 for (i = 0; i < len; i++) {
287 ADD_CHAR(dest, pos, source[i], c);
288 fcs = (fcs >> 8) ^ fcstab[(fcs ^ c) & 0xff];
291 fcs ^= 0xFFFF;
293 ADD_CHAR(dest, pos, fcs & 0xFF, c);
294 ADD_CHAR(dest, pos, fcs >> 8, c);
296 /* tack on the end-flag */
297 dest[pos++] = HDLC_FLAG;
299 /* now write this packet */
300 return write(fd, dest, pos);
303 #undef ADD_CHAR
306 static int dequeue_gre (callback_t callback, int cl)
308 pqueue_t *head;
309 int status;
310 /* process packets in the queue that either are expected or
311 have timed out. */
312 head = pqueue_head();
313 while ( head != NULL &&
314 ( (head->seq == gre.seq_recv + 1) || /* wrap-around safe */
315 (pqueue_expiry_time(head) <= 0)
318 /* if it is timed out... */
319 if (head->seq != gre.seq_recv + 1 ) { /* wrap-around safe */
320 stats.rx_lost += head->seq - gre.seq_recv - 1;
321 if (pptpctrl_debug)
322 syslog(LOG_DEBUG,
323 "GRE: timeout waiting for %d packets",
324 head->seq - gre.seq_recv - 1);
326 if (pptpctrl_debug)
327 syslog(LOG_DEBUG, "GRE: accepting #%d from queue",
328 head->seq);
329 gre.seq_recv = head->seq;
330 status = callback(cl, head->packet, head->packlen);
331 pqueue_del(head);
332 if (status < 0) return status;
333 head = pqueue_head();
335 return 0;
339 int decaps_gre(int fd, int (*cb) (int cl, void *pack, unsigned len), int cl)
341 static unsigned char buffer[PACKET_MAX + 64 /*ip header */ ];
342 struct pptp_gre_header *header;
343 int status, ip_len = 0;
345 dequeue_gre(cb, cl);
346 if ((status = read(fd, buffer, sizeof(buffer))) <= 0) {
347 syslog(LOG_ERR, "GRE: read(fd=%d,buffer=%lx,len=%d) from network failed: status = %d error = %s",
348 fd, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error");
349 stats.rx_errors++;
350 return -1;
352 /* strip off IP header, if present */
353 if ((buffer[0] & 0xF0) == 0x40)
354 ip_len = (buffer[0] & 0xF) * 4;
355 header = (struct pptp_gre_header *) (buffer + ip_len);
357 /* verify packet (else discard) */
358 if (((ntoh8(header->ver) & 0x7F) != PPTP_GRE_VER) || /* version should be 1 */
359 (ntoh16(header->protocol) != PPTP_GRE_PROTO) || /* GRE protocol for PPTP */
360 PPTP_GRE_IS_C(ntoh8(header->flags)) || /* flag C should be clear */
361 PPTP_GRE_IS_R(ntoh8(header->flags)) || /* flag R should be clear */
362 (!PPTP_GRE_IS_K(ntoh8(header->flags))) || /* flag K should be set */
363 ((ntoh8(header->flags) & 0xF) != 0)) { /* routing and recursion ctrl = 0 */
364 /* if invalid, discard this packet */
365 syslog(LOG_ERR, "GRE: Discarding packet by header check");
366 stats.rx_invalid++;
367 return 0;
369 if (header->call_id != GET_VALUE(PAC, gre.call_id_pair)) {
371 * Discard silently to allow more than one GRE tunnel from
372 * the same IP address in case clients are behind the
373 * firewall.
375 * syslog(LOG_ERR, "GRE: Discarding for incorrect call");
377 return 0;
379 if (PPTP_GRE_IS_A(ntoh8(header->ver))) { /* acknowledgement present */
380 u_int32_t ack = (PPTP_GRE_IS_S(ntoh8(header->flags))) ?
381 ntoh32(header->ack) : ntoh32(header->seq);
382 /* ack in different place if S=0 */
384 if (seq_greater(ack, gre.ack_recv))
385 gre.ack_recv = ack;
387 /* also handle sequence number wrap-around */
388 if (WRAPPED(ack,gre.ack_recv)) gre.ack_recv = ack;
389 if (gre.ack_recv == stats.pt.seq) {
390 int rtt = time_now_usecs() - stats.pt.time;
391 stats.rtt = (stats.rtt + rtt) / 2;
394 if (PPTP_GRE_IS_S(ntoh8(header->flags))) { /* payload present */
395 unsigned headersize = sizeof(*header);
396 unsigned payload_len = ntoh16(header->payload_len);
397 u_int32_t seq = ntoh32(header->seq);
399 if (!PPTP_GRE_IS_A(ntoh8(header->ver)))
400 headersize -= sizeof(header->ack);
401 /* check for incomplete packet (length smaller than expected) */
402 if (status - headersize < payload_len) {
403 stats.rx_truncated++;
404 return 0;
406 /* check for out-of-order sequence number */
407 if (seq == gre.seq_recv + 1) {
408 if (pptpctrl_debug)
409 syslog(LOG_DEBUG, "GRE: accepting packet #%d",
410 seq);
411 stats.rx_accepted++;
412 gre.seq_recv = seq;
413 return cb(cl, buffer + ip_len + headersize, payload_len);
414 } else if (seq == gre.seq_recv) {
415 if (pptpctrl_debug)
416 syslog(LOG_DEBUG,
417 "GRE: discarding duplicate or old packet #%d (expecting #%d)",
418 seq, gre.seq_recv + 1);
419 return 0; /* discard duplicate packets */
420 } else {
421 stats.rx_buffered++;
422 if (pptpctrl_debug)
423 syslog(LOG_DEBUG,
424 "GRE: buffering packet #%d (expecting #%d, lost or reordered)",
425 seq, gre.seq_recv + 1);
426 pqueue_add(seq, buffer + ip_len + headersize, payload_len);
427 return 0; /* discard out-of-order packets */
430 return 0; /* ack, but no payload */
434 int encaps_gre(int fd, void *pack, unsigned len)
436 static union {
437 struct pptp_gre_header header;
438 unsigned char buffer[PACKET_MAX + sizeof(struct pptp_gre_header)];
439 } u;
440 unsigned header_len;
441 #ifdef HAVE_WRITEV
442 struct iovec iovec[2];
443 #endif
445 if(fd == -1)
446 /* peek mode */
447 return (gre.ack_sent == gre.seq_recv) ? 0 : -1;
449 /* package this up in a GRE shell. */
450 u.header.flags = hton8(PPTP_GRE_FLAG_K);
451 u.header.ver = hton8(PPTP_GRE_VER);
452 u.header.protocol = hton16(PPTP_GRE_PROTO);
453 u.header.payload_len = hton16(len);
454 u.header.call_id = GET_VALUE(PNS, gre.call_id_pair);
456 /* special case ACK with no payload */
457 if (pack == NULL) {
458 if (gre.ack_sent != gre.seq_recv) {
459 u.header.ver |= hton8(PPTP_GRE_FLAG_A);
460 u.header.payload_len = hton16(0);
461 u.header.seq = hton32(gre.seq_recv); /* ack is in odd place because S=0 */
462 gre.ack_sent = gre.seq_recv;
463 /* don't sent ACK field, ACK is in SYN field */
464 return write(fd, u.buffer, sizeof(u.header) - sizeof(u.header.ack));
465 } else
466 return 0; /* we don't need to send ACK */
468 /* send packet with payload */
469 u.header.flags |= hton8(PPTP_GRE_FLAG_S);
470 u.header.seq = hton32(gre.seq_sent);
471 gre.seq_sent++;
472 if (gre.ack_sent != gre.seq_recv) { /* send ack with this message */
473 u.header.ver |= hton8(PPTP_GRE_FLAG_A);
474 u.header.ack = hton32(gre.seq_recv);
475 gre.ack_sent = gre.seq_recv;
476 header_len = sizeof(u.header);
477 } else { /* don't send ack */
478 header_len = sizeof(u.header) - sizeof(u.header.ack);
480 if (len > PACKET_MAX) {
481 syslog(LOG_ERR, "GRE: packet is too large %d", len);
482 stats.tx_oversize++;
483 return 0; /* drop this, it's too big */
485 #ifdef HAVE_WRITEV
486 /* write header and buffer without copying. */
487 iovec[0].iov_base = u.buffer;
488 iovec[0].iov_len = header_len;
489 iovec[1].iov_base = pack;
490 iovec[1].iov_len = len;
491 return writev(fd, iovec, 2);
492 #else
493 /* copy payload into buffer */
494 memcpy(u.buffer + header_len, pack, len);
495 /* record and increment sequence numbers */
496 /* write this baby out to the net */
497 return write(fd, u.buffer, header_len + len);
498 #endif