15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * libslirp glue
35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright (c) 2004-2008 Fabrice Bellard
55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Permission is hereby granted, free of charge, to any person obtaining a copy
75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * of this software and associated documentation files (the "Software"), to deal
85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * in the Software without restriction, including without limitation the rights
95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * copies of the Software, and to permit persons to whom the Software is
115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * furnished to do so, subject to the following conditions:
125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * The above copyright notice and this permission notice shall be included in
145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * all copies or substantial portions of the Software.
155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE SOFTWARE.
235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-common.h"
255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-char.h"
265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "slirp.h"
275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "proxy_common.h"
285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "hw/hw.h"
295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "android/utils/debug.h"  /* for dprint */
315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "android/utils/bufprint.h"
325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "android/android.h"
335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "sockets.h"
345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define  D(...)   VERBOSE_PRINT(slirp,__VA_ARGS__)
365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define  DN(...)  do { if (VERBOSE_CHECK(slirp)) dprintn(__VA_ARGS__); } while (0)
375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* host address */
395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneruint32_t our_addr_ip;
405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* host dns address */
415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneruint32_t dns_addr[DNS_ADDR_MAX];
425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint      dns_addr_count;
435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* host loopback address */
455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneruint32_t loopback_addr_ip;
465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* address for slirp virtual addresses */
485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneruint32_t  special_addr_ip;
495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* virtual address alias for host */
515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneruint32_t alias_addr_ip;
525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const uint8_t special_ethaddr[6] = {
545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    0x52, 0x54, 0x00, 0x12, 0x35, 0x00
555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner};
565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* ARP cache for the guest IP addresses (XXX: allow many entries) */
585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneruint8_t client_ethaddr[6];
595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ipaddr_t  client_ip;
605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerconst char *slirp_special_ip = CTL_SPECIAL;
645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint slirp_restrict;
655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int do_slowtimo;
665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint link_up;
675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct timeval tt;
685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerFILE *lfd;
695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct ex_list *exec_list;
705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* XXX: suppress those select globals */
725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerfd_set *global_readfds, *global_writefds, *global_xfds;
735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerchar slirp_hostname[33];
755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint slirp_add_dns_server(const SockAddress*  new_dns_addr)
775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int   dns_ip;
795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (dns_addr_count >= DNS_ADDR_MAX)
815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    dns_ip = sock_address_get_ip(new_dns_addr);
845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (dns_ip < 0)
855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    dns_addr[dns_addr_count++] = dns_ip;
885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32
935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint slirp_get_system_dns_servers(void)
955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    FIXED_INFO *FixedInfo=NULL;
975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ULONG    BufLen;
985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DWORD    ret;
995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    IP_ADDR_STRING *pIPAddr;
1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (dns_addr_count > 0)
1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return dns_addr_count;
1035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
1055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BufLen = sizeof(FIXED_INFO);
1065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
1085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (FixedInfo) {
1095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            GlobalFree(FixedInfo);
1105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            FixedInfo = NULL;
1115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        FixedInfo = GlobalAlloc(GPTR, BufLen);
1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
1165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (FixedInfo) {
1185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            GlobalFree(FixedInfo);
1195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            FixedInfo = NULL;
1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
1225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    D( "DNS Servers:");
1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pIPAddr = &(FixedInfo->DnsServerList);
1265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (pIPAddr && dns_addr_count < DNS_ADDR_MAX) {
1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        uint32_t  ip;
1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        D( "  %s", pIPAddr->IpAddress.String );
1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (inet_strtoip(pIPAddr->IpAddress.String, &ip) == 0) {
1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (ip == loopback_addr_ip)
1315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ip = our_addr_ip;
1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (dns_addr_count < DNS_ADDR_MAX)
1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                dns_addr[dns_addr_count++] = ip;
1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pIPAddr = pIPAddr->Next;
1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (FixedInfo) {
1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        GlobalFree(FixedInfo);
1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        FixedInfo = NULL;
1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (dns_addr_count <= 0)
1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return dns_addr_count;
1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint slirp_get_system_dns_servers(void)
1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char buff[512];
1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char buff2[257];
1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    FILE *f;
1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (dns_addr_count > 0)
1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return dns_addr_count;
1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_DARWIN
1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* on Darwin /etc/resolv.conf is a symlink to /private/var/run/resolv.conf
1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * in some siutations, the symlink can be destroyed and the system will not
1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * re-create it. Darwin-aware applications will continue to run, but "legacy"
1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * Unix ones will not.
1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     */
1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     f = fopen("/private/var/run/resolv.conf", "r");
1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     if (!f)
1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        f = fopen("/etc/resolv.conf", "r");  /* desperate attempt to sanity */
1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    f = fopen("/etc/resolv.conf", "r");
1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!f)
1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DN("emulator: IP address of your DNS(s): ");
1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (fgets(buff, 512, f) != NULL) {
1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            uint32_t  tmp_ip;
1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (inet_strtoip(buff2, &tmp_ip) < 0)
1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                continue;
1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (tmp_ip == loopback_addr_ip)
1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                tmp_ip = our_addr_ip;
1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (dns_addr_count < DNS_ADDR_MAX) {
1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                dns_addr[dns_addr_count++] = tmp_ip;
1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (dns_addr_count > 1)
1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    DN(", ");
1875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                DN("%s", inet_iptostr(tmp_ip));
1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            } else {
1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                DN("(more)");
1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DN("\n");
1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fclose(f);
1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!dns_addr_count)
1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return dns_addr_count;
2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void slirp_state_save(QEMUFile *f, void *opaque);
2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int slirp_state_load(QEMUFile *f, void *opaque, int version_id);
2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid slirp_init(int restricted, const char *special_ip)
2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if DEBUG
2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int   slirp_logmask = 0;
2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char  slirp_logfile[512];
2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    {
2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        const char*  env = getenv( "ANDROID_SLIRP_LOGMASK" );
2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (env != NULL)
2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            slirp_logmask = atoi(env);
2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         else if (VERBOSE_CHECK(slirp))
2185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            slirp_logmask = DEBUG_DEFAULT;
2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    {
2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        char*  p   = slirp_logfile;
2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        char*  end = p + sizeof(slirp_logfile);
2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        p = bufprint_temp_file( p, end, "slirp.log" );
2265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (p >= end) {
2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            dprint( "cannot create slirp log file in temporary directory" );
2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            slirp_logmask = 0;
2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
2305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (slirp_logmask) {
2325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        dprint( "sending slirp logs with mask %x to %s", slirp_logmask, slirp_logfile );
2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        debug_init( slirp_logfile, slirp_logmask );
2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
2365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    link_up = 1;
2385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_restrict = restricted;
2395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if_init();
2415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ip_init();
2425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Initialise mbufs *after* setting the MTU */
2445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    m_init();
2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* set default addresses */
2475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    inet_strtoip("127.0.0.1", &loopback_addr_ip);
2485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (dns_addr_count == 0) {
2505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (slirp_get_system_dns_servers() < 0) {
2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            dns_addr[0]    = loopback_addr_ip;
2525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            dns_addr_count = 1;
2535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fprintf (stderr, "Warning: No DNS servers found\n");
2545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
2555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    inet_strtoip(CTL_SPECIAL, &special_addr_ip);
2585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    alias_addr_ip = special_addr_ip | CTL_ALIAS;
2605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    getouraddr();
2615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    register_savevm("slirp", 0, 1, slirp_state_save, slirp_state_load, NULL);
2625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
2655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
2665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
2675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
2695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * curtime kept to an accuracy of 1ms
2705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
2715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32
2725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void updtime(void)
2735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct _timeb tb;
2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    _ftime(&tb);
2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    curtime = (u_int)tb.time * (u_int)1000;
2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    curtime += (u_int)tb.millitm;
2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void updtime(void)
2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        gettimeofday(&tt, NULL);
2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	curtime = (u_int)tt.tv_sec * (u_int)1000;
2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	curtime += (u_int)tt.tv_usec / (u_int)1000;
2875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if ((tt.tv_usec % 1000) >= 500)
2895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   curtime++;
2905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid slirp_select_fill(int *pnfds,
2945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                       fd_set *readfds, fd_set *writefds, fd_set *xfds)
2955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct socket *so, *so_next;
2975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct timeval timeout;
2985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int nfds;
2995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int tmp_time;
3005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* fail safe */
3025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    global_readfds = NULL;
3035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    global_writefds = NULL;
3045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    global_xfds = NULL;
3055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    nfds = *pnfds;
3075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
3085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * First, TCP sockets
3095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
3105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	do_slowtimo = 0;
3115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (link_up) {
3125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		/*
3135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * *_slowtimo needs calling if there are IP fragments
3145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * in the fragment queue, or there are TCP connections active
3155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 */
3165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		do_slowtimo = ((tcb.so_next != &tcb) ||
3175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                (&ipq.ip_link != ipq.ip_link.next));
3185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		for (so = tcb.so_next; so != &tcb; so = so_next) {
3205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			so_next = so->so_next;
3215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/*
3235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * See if we need a tcp_fasttimo
3245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 */
3255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
3265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			   time_fasttimo = curtime; /* Flag when we want a fasttimo */
3275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/*
3295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * NOFDREF can include still connecting to local-host,
3305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * newly socreated() sockets etc. Don't want to select these.
3315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 		 */
3325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (so->so_state & SS_NOFDREF || so->s == -1)
3335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			   continue;
3345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /*
3365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             * don't register proxified socked connections here
3375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             */
3385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if ((so->so_state & SS_PROXIFIED) != 0)
3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	            continue;
3405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/*
3425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * Set for reading sockets which are accepting
3435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 */
3445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (so->so_state & SS_FACCEPTCONN) {
3455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                FD_SET(so->s, readfds);
3465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				UPD_NFDS(so->s);
3475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				continue;
3485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			}
3495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/*
3515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * Set for writing sockets which are connecting
3525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 */
3535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (so->so_state & SS_ISFCONNECTING) {
3545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				FD_SET(so->s, writefds);
3555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				UPD_NFDS(so->s);
3565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				continue;
3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			}
3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/*
3605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * Set for writing if we are connected, can send more, and
3615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * we have something to send
3625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 */
3635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
3645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				FD_SET(so->s, writefds);
3655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				UPD_NFDS(so->s);
3665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			}
3675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/*
3695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * Set for reading (and urgent data) if we are connected, can
3705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * receive more, and we have room for it XXX /2 ?
3715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 */
3725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
3735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				FD_SET(so->s, readfds);
3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				FD_SET(so->s, xfds);
3755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				UPD_NFDS(so->s);
3765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			}
3775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
3785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		/*
3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * UDP sockets
3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 */
3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		for (so = udb.so_next; so != &udb; so = so_next) {
3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			so_next = so->so_next;
3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if ((so->so_state & SS_PROXIFIED) != 0)
3865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                continue;
3875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/*
3895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * See if it's timed out
3905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 */
3915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (so->so_expire) {
3925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				if (so->so_expire <= curtime) {
3935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					udp_detach(so);
3945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					continue;
3955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				} else
3965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					do_slowtimo = 1; /* Let socket expire */
3975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			}
3985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/*
4005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * When UDP packets are received from over the
4015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * link, they're sendto()'d straight away, so
4025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * no need for setting for writing
4035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * Limit the number of packets queued by this session
4045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * to 4.  Note that even though we try and limit this
4055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * to 4 packets, the session could have more queued
4065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * if the packets needed to be fragmented
4075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * (XXX <= 4 ?)
4085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 */
4095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
4105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				FD_SET(so->s, readfds);
4115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				UPD_NFDS(so->s);
4125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			}
4135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
4145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
4155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
4175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * Setup timeout to use minimum CPU usage, especially when idle
4185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
4195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
4215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * First, see the timeout needed by *timo
4225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
4235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	timeout.tv_sec = 0;
4245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	timeout.tv_usec = -1;
4255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
4265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * If a slowtimo is needed, set timeout to 500ms from the last
4275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * slow timeout. If a fast timeout is needed, set timeout within
4285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * 200ms of when it was requested.
4295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
4305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (do_slowtimo) {
4315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		/* XXX + 10000 because some select()'s aren't that accurate */
4325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000;
4335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if (timeout.tv_usec < 0)
4345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		   timeout.tv_usec = 0;
4355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		else if (timeout.tv_usec > 510000)
4365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		   timeout.tv_usec = 510000;
4375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		/* Can only fasttimo if we also slowtimo */
4395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if (time_fasttimo) {
4405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
4415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (tmp_time < 0)
4425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			   tmp_time = 0;
4435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/* Choose the smallest of the 2 */
4455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (tmp_time < timeout.tv_usec)
4465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			   timeout.tv_usec = (u_int)tmp_time;
4475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
4485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
4495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /*
4505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * now, the proxified sockets
4515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     */
4525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    proxy_manager_select_fill(&nfds, readfds, writefds, xfds);
4535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *pnfds = nfds;
4555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
4585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct socket *so, *so_next;
4605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret;
4615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    global_readfds = readfds;
4635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    global_writefds = writefds;
4645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    global_xfds = xfds;
4655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/* Update time */
4675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	updtime();
4685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
4705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * See if anything has timed out
4715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
4725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (link_up) {
4735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
4745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			tcp_fasttimo();
4755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			time_fasttimo = 0;
4765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
4775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
4785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			ip_slowtimo();
4795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			tcp_slowtimo();
4805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			last_slowtimo = curtime;
4815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
4825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
4835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
4855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * Check sockets
4865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
4875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (link_up) {
4885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		/*
4895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * Check TCP sockets
4905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 */
4915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		for (so = tcb.so_next; so != &tcb; so = so_next) {
4925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			so_next = so->so_next;
4935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/*
4955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * FD_ISSET is meaningless on these sockets
4965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * (and they can crash the program)
4975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 */
4985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (so->so_state & SS_NOFDREF || so->s == -1)
4995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			   continue;
5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /*
5025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             * proxified sockets are polled later in this
5035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             * function.
5045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             */
5055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if ((so->so_state & SS_PROXIFIED) != 0)
5065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                continue;
5075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/*
5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * Check for URG data
5105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * This will soread as well, so no need to
5115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * test for readfds below if this succeeds
5125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 */
5135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (FD_ISSET(so->s, xfds))
5145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			   sorecvoob(so);
5155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/*
5165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * Check sockets for reading
5175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 */
5185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			else if (FD_ISSET(so->s, readfds)) {
5195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				/*
5205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				 * Check for incoming connections
5215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				 */
5225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				if (so->so_state & SS_FACCEPTCONN) {
5235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					tcp_connect(so);
5245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					continue;
5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				} /* else */
5265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				ret = soread(so);
5275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				/* Output it if we read something */
5295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				if (ret > 0)
5305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				   tcp_output(sototcpcb(so));
5315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			}
5325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/*
5345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * Check sockets for writing
5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 */
5365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (FD_ISSET(so->s, writefds)) {
5375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			  /*
5385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			   * Check for non-blocking, still-connecting sockets
5395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			   */
5405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			  if (so->so_state & SS_ISFCONNECTING) {
5415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    /* Connected */
5425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    so->so_state &= ~SS_ISFCONNECTING;
5435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    ret = socket_send(so->s, (const void *)&ret, 0);
5455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    if (ret < 0) {
5465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      /* XXXXX Must fix, zero bytes is a NOP */
5475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      if (errno == EAGAIN || errno == EWOULDBLOCK ||
5485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				  errno == EINPROGRESS || errno == ENOTCONN)
5495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				continue;
5505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      /* else failed */
5525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      so->so_state = SS_NOFDREF;
5535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    }
5545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    /* else so->so_state &= ~SS_ISFCONNECTING; */
5555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    /*
5575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			     * Continue tcp_input
5585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			     */
5595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
5605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    /* continue; */
5615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			  } else
5625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    ret = sowrite(so);
5635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			  /*
5645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			   * XXXXX If we wrote something (a lot), there
5655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			   * could be a need for a window update.
5665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			   * In the worst case, the remote will send
5675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			   * a window probe to get things going again
5685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			   */
5695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			}
5705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/*
5725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * Probe a still-connecting, non-blocking socket
5735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			 * to check if it's still alive
5745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 	 	 */
5755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef PROBE_CONN
5765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (so->so_state & SS_ISFCONNECTING) {
5775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			  ret = socket_recv(so->s, (char *)&ret, 0);
5785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			  if (ret < 0) {
5805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    /* XXX */
5815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    if (errno == EAGAIN || errno == EWOULDBLOCK ||
5825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				errno == EINPROGRESS || errno == ENOTCONN)
5835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      continue; /* Still connecting, continue */
5845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    /* else failed */
5865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    so->so_state = SS_NOFDREF;
5875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    /* tcp_input will take care of it */
5895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			  } else {
5905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    ret = socket_send(so->s, &ret, 0);
5915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    if (ret < 0) {
5925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      /* XXX */
5935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      if (errno == EAGAIN || errno == EWOULDBLOCK ||
5945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				  errno == EINPROGRESS || errno == ENOTCONN)
5955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				continue;
5965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      /* else failed */
5975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      so->so_state = SS_NOFDREF;
5985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    } else
5995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      so->so_state &= ~SS_ISFCONNECTING;
6005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			  }
6025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			  tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
6035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			} /* SS_ISFCONNECTING */
6045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
6055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
6065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		/*
6085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * Now UDP sockets.
6095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * Incoming packets are sent straight away, they're not buffered.
6105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * Incoming UDP data isn't buffered either.
6115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 */
6125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		for (so = udb.so_next; so != &udb; so = so_next) {
6135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			so_next = so->so_next;
6145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if ((so->so_state & SS_PROXIFIED) != 0)
6165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                continue;
6175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (so->s != -1 && FD_ISSET(so->s, readfds)) {
6195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            sorecvfrom(so);
6205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        }
6215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
6225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
6235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /*
6255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * Now the proxified sockets
6265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     */
6275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    proxy_manager_poll(readfds, writefds, xfds);
6285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
6305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * See if we can start outputting
6315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
6325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (if_queued && link_up)
6335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   if_start();
6345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/* clear global file descriptor sets.
6365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * these reside on the stack in vl.c
6375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * so they're unusable if we're not in
6385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * slirp_select_fill or slirp_select_poll.
6395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
6405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 global_readfds = NULL;
6415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 global_writefds = NULL;
6425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 global_xfds = NULL;
6435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define ETH_ALEN 6
6465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define ETH_HLEN 14
6475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
6495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
6505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define	ARPOP_REQUEST	1		/* ARP request			*/
6525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define	ARPOP_REPLY	2		/* ARP reply			*/
6535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct ethhdr
6555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
6575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
6585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	unsigned short	h_proto;		/* packet type ID field	*/
6595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner};
6605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct arphdr
6625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	unsigned short	ar_hrd;		/* format of hardware address	*/
6645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	unsigned short	ar_pro;		/* format of protocol address	*/
6655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	unsigned char	ar_hln;		/* length of hardware address	*/
6665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	unsigned char	ar_pln;		/* length of protocol address	*/
6675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	unsigned short	ar_op;		/* ARP opcode (command)		*/
6685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 /*
6705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  *	 Ethernet looks like this : This bit is variable sized however...
6715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  */
6725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	unsigned char		ar_sha[ETH_ALEN];	/* sender hardware address	*/
6735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	unsigned char		ar_sip[4];		/* sender IP address		*/
6745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	unsigned char		ar_tha[ETH_ALEN];	/* target hardware address	*/
6755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	unsigned char		ar_tip[4];		/* target IP address		*/
6765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner};
6775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void arp_input(const uint8_t *pkt, int pkt_len)
6795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct ethhdr *eh = (struct ethhdr *)pkt;
6815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
6825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)];
6835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct ethhdr *reh = (struct ethhdr *)arp_reply;
6845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
6855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ar_op;
6865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct ex_list *ex_ptr;
6875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ar_op = ntohs(ah->ar_op);
6895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    switch(ar_op) {
6905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        uint32_t    ar_tip_ip;
6915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case ARPOP_REQUEST:
6935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ar_tip_ip = ip_read32h(ah->ar_tip);
6945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if ((ar_tip_ip & 0xffffff00) == special_addr_ip) {
6955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            uint32_t  ar_tip_low = ar_tip_ip & 0xff;
6965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if ( CTL_IS_DNS(ar_tip_low) || ar_tip_low == CTL_ALIAS)
6975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto arp_ok;
6985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
6995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (ex_ptr->ex_addr == ar_tip_low)
7005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    goto arp_ok;
7015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
7025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return;
7035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        arp_ok:
7045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /* XXX: make an ARP request to have the client address */
7055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
7065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /* ARP request for alias/dns mac address */
7085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
7095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
7105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            reh->h_source[5] = ar_tip_low;
7115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            reh->h_proto = htons(ETH_P_ARP);
7125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            rah->ar_hrd = htons(1);
7145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            rah->ar_pro = htons(ETH_P_IP);
7155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            rah->ar_hln = ETH_ALEN;
7165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            rah->ar_pln = 4;
7175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            rah->ar_op = htons(ARPOP_REPLY);
7185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
7195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            memcpy(rah->ar_sip, ah->ar_tip, 4);
7205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
7215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            memcpy(rah->ar_tip, ah->ar_sip, 4);
7225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            slirp_output(arp_reply, sizeof(arp_reply));
7235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
7245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
7255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case ARPOP_REPLY:
7265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* reply to request of client mac address ? */
7275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) &&
7285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ip_equal( ip_read(ah->ar_sip), client_ip )) {
7295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN);
7305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
7315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
7325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    default:
7335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
7345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
7355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
7365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid slirp_input(const uint8_t *pkt, int pkt_len)
7385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
7395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct mbuf *m;
7405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int proto;
7415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (pkt_len < ETH_HLEN)
7435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
7445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    proto = ntohs(*(uint16_t *)(pkt + 12));
7465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    switch(proto) {
7475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case ETH_P_ARP:
7485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        arp_input(pkt, pkt_len);
7495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
7505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case ETH_P_IP:
7515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        m = m_get();
7525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!m)
7535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return;
7545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* Note: we add to align the IP header */
7555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (M_FREEROOM(m) < pkt_len + 2) {
7565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            m_inc(m, pkt_len + 2);
7575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
7585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        m->m_len = pkt_len + 2;
7595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(m->m_data + 2, pkt, pkt_len);
7605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        m->m_data += 2 + ETH_HLEN;
7625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        m->m_len -= 2 + ETH_HLEN;
7635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ip_input(m);
7655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
7665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    default:
7675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
7685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
7695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
7705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* output the IP packet to the ethernet device */
7725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid if_encap(const uint8_t *ip_data, int ip_data_len)
7735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
7745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t buf[1600];
7755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct ethhdr *eh = (struct ethhdr *)buf;
7765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ip_data_len + ETH_HLEN > sizeof(buf))
7785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
7795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN)) {
7815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
7825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        struct ethhdr *reh = (struct ethhdr *)arp_req;
7835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
7845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        const struct ip *iph = (const struct ip *)ip_data;
7855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* If the client addr is not known, there is no point in
7875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           sending the packet to it. Normally the sender should have
7885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           done an ARP request to get its MAC address. Here we do it
7895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           in place of sending the packet and we hope that the sender
7905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           will retry sending its packet. */
7915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memset(reh->h_dest, 0xff, ETH_ALEN);
7925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
7935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        reh->h_source[5] = CTL_ALIAS;
7945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        reh->h_proto = htons(ETH_P_ARP);
7955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        rah->ar_hrd = htons(1);
7965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        rah->ar_pro = htons(ETH_P_IP);
7975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        rah->ar_hln = ETH_ALEN;
7985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        rah->ar_pln = 4;
7995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        rah->ar_op = htons(ARPOP_REQUEST);
8005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* source hw addr */
8015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 1);
8025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        rah->ar_sha[5] = CTL_ALIAS;
8035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* source IP */
8045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ip_write32h(alias_addr_ip, rah->ar_sip);
8055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* target hw addr (none) */
8065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memset(rah->ar_tha, 0, ETH_ALEN);
8075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* target IP */
8085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ip_write( iph->ip_dst, rah->ar_tip );
8095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        client_ip   = iph->ip_dst;
8105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        slirp_output(arp_req, sizeof(arp_req));
8115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
8125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
8135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
8145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* XXX: not correct */
8155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        eh->h_source[5] = CTL_ALIAS;
8165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        eh->h_proto = htons(ETH_P_IP);
8175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
8185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        slirp_output(buf, ip_data_len + ETH_HLEN);
8195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void _slirp_redir_loop(void (*func)(void *opaque, int is_udp,
8235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                           const SockAddress *laddr,
8245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                           const SockAddress *faddr),
8255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                              void *opaque, int is_udp)
8265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct socket *head = (is_udp ? &udb : &tcb);
8285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct socket *so;
8295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (so = head->so_next; so != head; so = so->so_next) {
8315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        SockAddress  local, foreign;
8325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		sock_address_init_inet(&local, so->so_laddr_ip, so->so_laddr_port);
8345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		sock_address_init_inet(&foreign, so->so_faddr_ip, so->so_faddr_port);
8355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        func(opaque, is_udp,
8365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             &local, &foreign);
8375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid slirp_redir_loop(void (*func)(void *opaque, int is_udp,
8415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   const SockAddress *laddr,
8425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   const SockAddress *faddr),
8435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                     void *opaque)
8445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    _slirp_redir_loop(func, opaque, 0);
8465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    _slirp_redir_loop(func, opaque, 1);
8475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* Unlistens a redirection
8505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
8515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Return value: number of redirs removed */
8525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint slirp_redir_rm(int is_udp, int host_port)
8535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct socket *so;
8555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct socket *head = (is_udp ? &udb : &tcb);
8565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int n = 0;
8575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner loop_again:
8595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (so = head->so_next; so != head; so = so->so_next) {
8605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (so->so_faddr_port == host_port) {
8615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            close(so->s);
8625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            sofree(so);
8635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            n++;
8645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto loop_again;
8655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
8665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return n;
8695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint slirp_redir(int is_udp, int host_port,
8725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                uint32_t  guest_ip, int guest_port)
8735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (is_udp) {
8755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!udp_listen(host_port,
8765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        guest_ip,
8775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        guest_port, 0))
8785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -1;
8795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
8805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!solisten(host_port, guest_ip, guest_port, 0))
8815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -1;
8825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
8845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint  slirp_unredir(int  is_udp, int  host_port)
8875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (is_udp)
8895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return udp_unlisten( host_port );
8905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else
8915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return sounlisten( host_port );
8925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint slirp_add_exec(int do_pty, const void *args, int addr_low_byte,
8955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                  int guest_port)
8965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return add_exec(&exec_list, do_pty, (char *)args,
8985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    addr_low_byte, htons(guest_port));
8995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
9025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (so->s == -1 && so->extra) {
9045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		qemu_chr_write(so->extra, buf, len);
9055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		return len;
9065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
9075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return send(so->s, buf, len, flags);
9095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic struct socket *slirp_find_ctl_socket(int addr_low_byte, int guest_port)
9125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	struct socket *so;
9145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	for (so = tcb.so_next; so != &tcb; so = so->so_next) {
9165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if ((so->so_faddr_ip & 0xffffff00) ==
9175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				special_addr_ip
9185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				&& ((so->so_faddr_port & 0xff) ==
9195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				addr_low_byte)
9205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				&& so->so_faddr_port == guest_port)
9215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			return so;
9225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
9235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return NULL;
9255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnersize_t slirp_socket_can_recv(int addr_low_byte, int guest_port)
9285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	struct iovec iov[2];
9305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	struct socket *so;
9315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!link_up)
9335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
9345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	so = slirp_find_ctl_socket(addr_low_byte, guest_port);
9365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (!so || so->so_state & SS_NOFDREF)
9385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		return 0;
9395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2))
9415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		return 0;
9425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return sopreprbuf(so, iov, NULL);
9445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf,
9475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int size)
9485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret;
9505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct socket *so = slirp_find_ctl_socket(addr_low_byte, guest_port);
9515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!so)
9535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
9545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = soreadbuf(so, (const char *)buf, size);
9565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret > 0)
9585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        tcp_output(sototcpcb(so));
9595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void slirp_tcp_save(QEMUFile *f, struct tcpcb *tp)
9625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
9645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_sbe16(f, tp->t_state);
9665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < TCPT_NTIMERS; i++)
9675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_sbe16(f, tp->t_timer[i]);
9685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_sbe16(f, tp->t_rxtshift);
9695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_sbe16(f, tp->t_rxtcur);
9705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_sbe16(f, tp->t_dupacks);
9715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be16(f, tp->t_maxseg);
9725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_sbyte(f, tp->t_force);
9735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be16(f, tp->t_flags);
9745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->snd_una);
9755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->snd_nxt);
9765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->snd_up);
9775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->snd_wl1);
9785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->snd_wl2);
9795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->iss);
9805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->snd_wnd);
9815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->rcv_wnd);
9825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->rcv_nxt);
9835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->rcv_up);
9845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->irs);
9855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->rcv_adv);
9865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->snd_max);
9875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->snd_cwnd);
9885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->snd_ssthresh);
9895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_sbe16(f, tp->t_idle);
9905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_sbe16(f, tp->t_rtt);
9915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->t_rtseq);
9925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_sbe16(f, tp->t_srtt);
9935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_sbe16(f, tp->t_rttvar);
9945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be16(f, tp->t_rttmin);
9955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->max_sndwnd);
9965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, tp->t_oobflags);
9975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, tp->t_iobc);
9985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_sbe16(f, tp->t_softerror);
9995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, tp->snd_scale);
10005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, tp->rcv_scale);
10015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, tp->request_r_scale);
10025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, tp->requested_s_scale);
10035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->ts_recent);
10045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->ts_recent_age);
10055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, tp->last_ack_sent);
10065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf)
10095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t off;
10115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, sbuf->sb_cc);
10135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, sbuf->sb_datalen);
10145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    off = (uint32_t)(sbuf->sb_wptr - sbuf->sb_data);
10155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_sbe32(f, off);
10165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    off = (uint32_t)(sbuf->sb_rptr - sbuf->sb_data);
10175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_sbe32(f, off);
10185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
10195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void slirp_socket_save(QEMUFile *f, struct socket *so)
10225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, so->so_urgc);
10245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, so->so_faddr_ip);
10255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, so->so_laddr_ip);
10265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be16(f, so->so_faddr_port);
10275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be16(f, so->so_laddr_port);
10285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, so->so_iptos);
10295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, so->so_emu);
10305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, so->so_type);
10315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, so->so_state);
10325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_sbuf_save(f, &so->so_rcv);
10335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_sbuf_save(f, &so->so_snd);
10345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_tcp_save(f, so->so_tcpcb);
10355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void slirp_state_save(QEMUFile *f, void *opaque)
10385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct ex_list *ex_ptr;
10405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
10425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ex_ptr->ex_pty == 3) {
10435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            struct socket *so;
10445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            so = slirp_find_ctl_socket(ex_ptr->ex_addr, ntohs(ex_ptr->ex_fport));
10455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (!so)
10465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                continue;
10475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_put_byte(f, 42);
10495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            slirp_socket_save(f, so);
10505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
10515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, 0);
10525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void slirp_tcp_load(QEMUFile *f, struct tcpcb *tp)
10555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
10575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_state = qemu_get_sbe16(f);
10595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < TCPT_NTIMERS; i++)
10605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        tp->t_timer[i] = qemu_get_sbe16(f);
10615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_rxtshift = qemu_get_sbe16(f);
10625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_rxtcur = qemu_get_sbe16(f);
10635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_dupacks = qemu_get_sbe16(f);
10645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_maxseg = qemu_get_be16(f);
10655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_force = qemu_get_sbyte(f);
10665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_flags = qemu_get_be16(f);
10675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->snd_una = qemu_get_be32(f);
10685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->snd_nxt = qemu_get_be32(f);
10695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->snd_up = qemu_get_be32(f);
10705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->snd_wl1 = qemu_get_be32(f);
10715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->snd_wl2 = qemu_get_be32(f);
10725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->iss = qemu_get_be32(f);
10735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->snd_wnd = qemu_get_be32(f);
10745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->rcv_wnd = qemu_get_be32(f);
10755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->rcv_nxt = qemu_get_be32(f);
10765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->rcv_up = qemu_get_be32(f);
10775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->irs = qemu_get_be32(f);
10785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->rcv_adv = qemu_get_be32(f);
10795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->snd_max = qemu_get_be32(f);
10805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->snd_cwnd = qemu_get_be32(f);
10815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->snd_ssthresh = qemu_get_be32(f);
10825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_idle = qemu_get_sbe16(f);
10835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_rtt = qemu_get_sbe16(f);
10845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_rtseq = qemu_get_be32(f);
10855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_srtt = qemu_get_sbe16(f);
10865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_rttvar = qemu_get_sbe16(f);
10875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_rttmin = qemu_get_be16(f);
10885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->max_sndwnd = qemu_get_be32(f);
10895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_oobflags = qemu_get_byte(f);
10905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_iobc = qemu_get_byte(f);
10915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->t_softerror = qemu_get_sbe16(f);
10925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->snd_scale = qemu_get_byte(f);
10935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->rcv_scale = qemu_get_byte(f);
10945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->request_r_scale = qemu_get_byte(f);
10955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->requested_s_scale = qemu_get_byte(f);
10965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->ts_recent = qemu_get_be32(f);
10975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->ts_recent_age = qemu_get_be32(f);
10985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tp->last_ack_sent = qemu_get_be32(f);
10995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tcp_template(tp);
11005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
11015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int slirp_sbuf_load(QEMUFile *f, struct sbuf *sbuf)
11035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
11045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t off, sb_cc, sb_datalen;
11055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sb_cc = qemu_get_be32(f);
11075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sb_datalen = qemu_get_be32(f);
11085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sbreserve(sbuf, sb_datalen);
11105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (sbuf->sb_datalen != sb_datalen)
11125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -ENOMEM;
11135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sbuf->sb_cc = sb_cc;
11155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    off = qemu_get_sbe32(f);
11175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sbuf->sb_wptr = sbuf->sb_data + off;
11185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    off = qemu_get_sbe32(f);
11195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sbuf->sb_rptr = sbuf->sb_data + off;
11205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_get_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
11215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
11235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
11245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int slirp_socket_load(QEMUFile *f, struct socket *so)
11265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
11275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (tcp_attach(so) < 0)
11285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -ENOMEM;
11295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    so->so_urgc = qemu_get_be32(f);
11315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    so->so_faddr_ip = qemu_get_be32(f);
11325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    so->so_laddr_ip = qemu_get_be32(f);
11335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    so->so_faddr_port = qemu_get_be16(f);
11345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    so->so_laddr_port = qemu_get_be16(f);
11355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    so->so_iptos = qemu_get_byte(f);
11365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    so->so_emu = qemu_get_byte(f);
11375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    so->so_type = qemu_get_byte(f);
11385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    so->so_state = qemu_get_be32(f);
11395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (slirp_sbuf_load(f, &so->so_rcv) < 0)
11405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -ENOMEM;
11415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (slirp_sbuf_load(f, &so->so_snd) < 0)
11425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -ENOMEM;
11435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_tcp_load(f, so->so_tcpcb);
11445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
11465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
11475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
11495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
11505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct ex_list *ex_ptr;
11515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int r;
11525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while ((r = qemu_get_byte(f))) {
11545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int ret;
11555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        struct socket *so = socreate();
11565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!so)
11585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -ENOMEM;
11595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = slirp_socket_load(f, so);
11615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ret < 0)
11635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return ret;
11645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if ((so->so_faddr_ip & 0xffffff00) != special_addr_ip)
11665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -EINVAL;
11675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
11695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (ex_ptr->ex_pty == 3 &&
11705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    (so->so_faddr_ip & 0xff) == ex_ptr->ex_addr &&
11715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    so->so_faddr_port == ex_ptr->ex_fport)
11725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
11735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!ex_ptr)
11755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -EINVAL;
11765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        so->extra = (void *)ex_ptr->ex_exec;
11785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
11795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
11815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1182