Use getmsg() intead of read() on Solaris tun device
authorKazuyoshi Aizawa <admin2@whiteboard.ne.jp>
Wed, 23 Nov 2011 13:25:36 +0000 (13:25 +0000)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Wed, 23 Nov 2011 13:29:40 +0000 (13:29 +0000)
On Solaris, a read from the tun device can return parts of multiple
packets, and there's no safe way to tell where one ends and the next
starts. Use getmsg() instead, which will only return one packet.

[dwmw2: Mangled a little to cope with script_tun mode and simplify loop]
Signed-off-by: Kazuyoshi Aizawa <admin2@whiteboard.ne.jp>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
tun.c
www/changelog.xml

diff --git a/tun.c b/tun.c
index 83c712d..a66a196 100644 (file)
--- a/tun.c
+++ b/tun.c
@@ -579,10 +579,39 @@ int tun_mainloop(struct openconnect_info *vpninfo, int *timeout)
        unsigned char buf[2000];
        int len;
        int work_done = 0;
+       int moredata = 1;
 
        if (FD_ISSET(vpninfo->tun_fd, &vpninfo->select_rfds)) {
-               while ((len = read(vpninfo->tun_fd, buf, sizeof(buf))) > 0) {
+               while (moredata) {
                        unsigned char *pkt = buf;
+#ifdef __sun__
+                       /* On Solaris, if we're actually using tuntap and *not* just
+                          passing packets through a UNIX socket to a child process,
+                          we have to use getmsg() to ensure that we only get *one*
+                          packet at a time. */
+                       if (!vpninfo->script_tun) {
+                               struct strbuf strb;
+                               int flags = 0;
+                               int ret;
+                               
+                               strb.buf = buf;
+                               strb.maxlen = sizeof(buf);
+                               strb.len = 0;
+                               ret = getmsg(vpninfo->tun_fd, NULL, &strb, &flags);
+                               if (ret < 0)
+                                       break;
+
+                               if (!(ret & MOREDATA))
+                                       moredata = 0;
+                               len = strb.len;
+                       } else
+#endif /* __sun__ ... */
+                       {
+                               len = read(vpninfo->tun_fd, buf, sizeof(buf));
+                               if (len <= 0)
+                                       break;
+                       }
+
 #ifdef TUN_HAS_AF_PREFIX
                        if (!vpninfo->script_tun) {
                                pkt += 4;
index cce42a2..26fbb21 100644 (file)
@@ -17,7 +17,7 @@
 <ul>
    <li><b>OpenConnect HEAD</b>
      <ul>
-       <li><i>No changelog entries yet</i></li>
+       <li>Fix for reading multiple packets from Solaris tun device.</li>
      </ul><br/>
   </li>
   <li><b><a href="ftp://ftp.infradead.org/pub/openconnect/openconnect-3.14.tar.gz">OpenConnect v3.14</a></b>