This is an additional patch against the Nautilus6-patched rp-l2tp (rp-l2tp.tgz obtained from http://software.nautilus6.org/packages/rp-l2tp/ on 2006-01-13) to support large frame that cannot be read from pty at one time. /*********************************************************************** * * async-pppd.c * * An LNS handler which starts pppd attached to a PTY in * asynchronous mode. * * Copyright (C) 2002 by Roaring Penguin Software Inc. * * This software may be distributed under the terms of the GNU General * Public License, Version 2, or (at your option) any later version. * * LIC: GPL * ***********************************************************************/ --- rp-l2tp-0.4.nautilus6/handlers/async-pppd.c 2005-03-26 08:41:42.000000000 +0900 +++ rp-l2tp-0.4/handlers/async-pppd.c 2006-01-20 18:58:03.000000000 +0900 @@ -67,6 +67,8 @@ pid_t pid; /* PID of child PPPD process */ int fd; /* File descriptor for event-handler loop */ EventHandler *event; /* Event handler */ + unsigned char buf[2 * 4096];/* Buffer for PPP to L2TP tunnel */ + size_t buflen; }; static int handle_lac_opts(EventSelector *es, l2tp_opt_descriptor *desc, char const *value); @@ -304,42 +306,74 @@ readable(EventSelector *es, int fd, unsigned int flags, void *data) { unsigned char real_buf[4096+EXTRA_HEADER_ROOM]; - unsigned char buf[2*4096]; + unsigned char *buf; unsigned char *p, *q, c; int escaped = 0; int n, l = 0; l2tp_session *ses = (l2tp_session *) data; int iters = 5; + struct slave *sl; + unsigned char *sync, *scan, *end; + + if (ses == NULL) { + (void)read(fd, real_buf, sizeof(real_buf)); + return; + } + sl = ses->private; /* It seems to be better to read in a loop than to go back to select loop. However, don't loop forever, or we could have a DoS potential */ while(iters--) { - n = read(fd, buf, sizeof(buf)); - - /* TODO: Check this.... */ - if ((n <= 4) || (buf[0] != HDLC_SYNC) || (buf[n-1] != HDLC_SYNC)) + n = read(fd, sl->buf + sl->buflen, sizeof(sl->buf) - sl->buflen); + if (n < 0) return; + scan = sl->buf + sl->buflen; + sl->buflen += n; + sync = sl->buf; + end = sl->buf + sl->buflen; + while (sync < end) { + if ((scan = memchr(scan, HDLC_SYNC, end - scan)) == NULL) { + if (sl->buf != sync) { + sl->buflen = end - sync; + memmove(sl->buf, sync, sl->buflen); + } else if (sl->buflen == sizeof(sl->buf)) { + sl->buflen = 0; + } + return; + } + if (*sync != HDLC_SYNC) { + /* discard out of sync data */ + sync = scan++; + continue; + } + buf = sync + 1; + n = scan - buf; + sync = scan++; + + l = 0; + /* EXTRA_HEADER_ROOM bytes extra space for l2tp header */ + q = real_buf+EXTRA_HEADER_ROOM; + for (p = buf; p < buf + n; p++) { + c = *p; + if (escaped) { + escaped = 0; + *q++ = c ^ HDLC_XOR; + l++; + } else if (c == HDLC_ESC) + escaped = 1; + else { + *q++ = c; + l++; + } + } - if (!ses) continue; + if (l <= 4) + continue; - /* EXTRA_HEADER_ROOM bytes extra space for l2tp header */ - q = real_buf+EXTRA_HEADER_ROOM; - for (p = buf + 1; p < buf + n - 1; p++) { - c = *p; - if (escaped) { - escaped = 0; - *q++ = c ^ HDLC_XOR; - l++; - } else if (c == HDLC_ESC) - escaped = 1; - else { - *q++ = c; - l++; - } + /* Chop off framing and FCS bytes */ + l2tp_dgram_send_ppp_frame(ses, real_buf+EXTRA_HEADER_ROOM+2, l-4); } - /* Chop off framing and FCS bytes */ - l2tp_dgram_send_ppp_frame(ses, real_buf+EXTRA_HEADER_ROOM+2, l-4); } } @@ -366,6 +400,7 @@ if (!sl) return -1; sl->ses = ses; sl->es = es; + sl->buflen = 0; /* Get pty */ if (pty_get(&m_pty, &s_pty) < 0) {