diff --git a/tun.c b/tun.c index 83c712d..0c51805 100644 --- a/tun.c +++ b/tun.c @@ -574,32 +574,99 @@ int setup_tun(struct openconnect_info *vpninfo) return 0; } -int tun_mainloop(struct openconnect_info *vpninfo, int *timeout) +#if 1//def __sun__ +/* It's not clear this is really safe; what if the length field lies? */ +static int pkt_len(unsigned char *buf) +{ + switch (buf[0] >> 4) { + case 4: + return (buf[2] << 8) + buf[3]; + break; + case 6: + /* IPv6 payload length; need to add header size */ + return (buf[4] << 8) + buf[5] + 0x28; + break; + default: + return -1; + } +} + +static int tun_read(struct openconnect_info *vpninfo) { - unsigned char buf[2000]; - int len; int work_done = 0; + unsigned char buf[64000]; + int len, plen = 0; - if (FD_ISSET(vpninfo->tun_fd, &vpninfo->select_rfds)) { - while ((len = read(vpninfo->tun_fd, buf, sizeof(buf))) > 0) { - unsigned char *pkt = buf; -#ifdef TUN_HAS_AF_PREFIX - if (!vpninfo->script_tun) { - pkt += 4; - len -= 4; + while ((len = read(vpninfo->tun_fd, buf + plen, + sizeof(buf) - plen)) > 0) { + unsigned char *pkt = buf; + + len += plen; + while (len > 8) { + int pktlen = pkt_len (pkt); + if (pktlen < 0) { + static int complained = 0; + if (!complained) { + complained = 1; + vpn_progress(vpninfo, PRG_ERR, + _("Unknown packet from tun: %02x %02x %02x %02x...\n"), + buf[0], buf[1], buf[2], buf[3]); + } + return 1; } -#endif - if (queue_new_packet(&vpninfo->outgoing_queue, pkt, - len)) + if (len < pktlen) break; + printf("send pkt of len %d\n", pktlen); + if (queue_new_packet(&vpninfo->outgoing_queue, pkt, + pktlen)) + return 1; work_done = 1; vpninfo->outgoing_qlen++; - if (vpninfo->outgoing_qlen == vpninfo->max_qlen) { - FD_CLR(vpninfo->tun_fd, &vpninfo->select_rfds); - break; - } + pkt += pktlen; + len -= pktlen; + } + memmove(buf, pkt, len); + plen = len; + printf("After tun read, %d bytes left\n", plen); + } + return work_done; +} + +#else /* !__sun__ */ + +static int tun_read(struct openconnect_info *vpninfo) +{ + int work_done = 0; + unsigned char buf[2000]; + int len; + + while ((len = read(vpninfo->tun_fd, buf, sizeof(buf))) > 0) { + unsigned char *pkt = buf; +#ifdef TUN_HAS_AF_PREFIX + if (!vpninfo->script_tun) { + pkt += 4; + len -= 4; } +#endif + if (queue_new_packet(&vpninfo->outgoing_queue, pkt, + len)) + break; + work_done = 1; + vpninfo->outgoing_qlen++; + } + return work_done; +} +#endif /* __sun__ */ + +int tun_mainloop(struct openconnect_info *vpninfo, int *timeout) +{ + int work_done = 0; + + if (FD_ISSET(vpninfo->tun_fd, &vpninfo->select_rfds)) { + work_done = tun_read(vpninfo); + if (vpninfo->outgoing_qlen >= vpninfo->max_qlen) + FD_CLR(vpninfo->tun_fd, &vpninfo->select_rfds); } else if (vpninfo->outgoing_qlen < vpninfo->max_qlen) { FD_SET(vpninfo->tun_fd, &vpninfo->select_rfds); }