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