]> git.proxmox.com Git - mirror_qemu.git/blobdiff - slirp/slirp.c
find -type f | xargs sed -i 's/[\t ]*$//g' # Yes, again. Note the star in the regex.
[mirror_qemu.git] / slirp / slirp.c
index bc2b15509aea8a347ef98a3ba4834ea40c8c741c..f535db12b03000d9412fa70db5f5dd7dd3055970 100644 (file)
@@ -9,8 +9,10 @@ struct in_addr loopback_addr;
 
 /* address for slirp virtual addresses */
 struct in_addr special_addr;
+/* virtual address alias for host */
+struct in_addr alias_addr;
 
-const uint8_t special_ethaddr[6] = { 
+const uint8_t special_ethaddr[6] = {
     0x52, 0x54, 0x00, 0x12, 0x35, 0x00
 };
 
@@ -20,10 +22,13 @@ int do_slowtimo;
 int link_up;
 struct timeval tt;
 FILE *lfd;
+struct ex_list *exec_list;
 
 /* XXX: suppress those select globals */
 fd_set *global_readfds, *global_writefds, *global_xfds;
 
+char slirp_hostname[33];
+
 #ifdef _WIN32
 
 static int get_dns_addr(struct in_addr *pdns_addr)
@@ -33,10 +38,10 @@ static int get_dns_addr(struct in_addr *pdns_addr)
     DWORD    ret;
     IP_ADDR_STRING *pIPAddr;
     struct in_addr tmp_addr;
-    
+
     FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
     BufLen = sizeof(FIXED_INFO);
-   
+
     if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
         if (FixedInfo) {
             GlobalFree(FixedInfo);
@@ -44,7 +49,7 @@ static int get_dns_addr(struct in_addr *pdns_addr)
         }
         FixedInfo = GlobalAlloc(GPTR, BufLen);
     }
-       
+
     if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
         printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
         if (FixedInfo) {
@@ -53,14 +58,14 @@ static int get_dns_addr(struct in_addr *pdns_addr)
         }
         return -1;
     }
-     
+
     pIPAddr = &(FixedInfo->DnsServerList);
     inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
     *pdns_addr = tmp_addr;
 #if 0
     printf( "DNS Servers:\n" );
     printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String );
-    
+
     pIPAddr = FixedInfo -> DnsServerList.Next;
     while ( pIPAddr ) {
             printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String );
@@ -83,7 +88,7 @@ static int get_dns_addr(struct in_addr *pdns_addr)
     FILE *f;
     int found = 0;
     struct in_addr tmp_addr;
-    
+
     f = fopen("/etc/resolv.conf", "r");
     if (!f)
         return -1;
@@ -125,7 +130,7 @@ void slirp_cleanup(void)
 void slirp_init(void)
 {
     //    debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
-    
+
 #ifdef _WIN32
     {
         WSADATA Data;
@@ -143,15 +148,16 @@ void slirp_init(void)
     m_init();
 
     /* set default addresses */
-    getouraddr();
     inet_aton("127.0.0.1", &loopback_addr);
 
     if (get_dns_addr(&dns_addr) < 0) {
-        fprintf(stderr, "Could not get DNS address\n");
-        exit(1);
+        dns_addr = loopback_addr;
+        fprintf (stderr, "Warning: No DNS servers found\n");
     }
 
     inet_aton(CTL_SPECIAL, &special_addr);
+    alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
+    getouraddr();
 }
 
 #define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
@@ -174,16 +180,16 @@ static void updtime(void)
 static void updtime(void)
 {
        gettimeofday(&tt, 0);
-       
+
        curtime = (u_int)tt.tv_sec * (u_int)1000;
        curtime += (u_int)tt.tv_usec / (u_int)1000;
-       
+
        if ((tt.tv_usec % 1000) >= 500)
           curtime++;
 }
 #endif
 
-void slirp_select_fill(int *pnfds, 
+void slirp_select_fill(int *pnfds,
                        fd_set *readfds, fd_set *writefds, fd_set *xfds)
 {
     struct socket *so, *so_next;
@@ -195,36 +201,36 @@ void slirp_select_fill(int *pnfds,
     global_readfds = NULL;
     global_writefds = NULL;
     global_xfds = NULL;
-    
+
     nfds = *pnfds;
        /*
         * First, TCP sockets
         */
        do_slowtimo = 0;
        if (link_up) {
-               /* 
+               /*
                 * *_slowtimo needs calling if there are IP fragments
                 * in the fragment queue, or there are TCP connections active
                 */
                do_slowtimo = ((tcb.so_next != &tcb) ||
                               ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next));
-               
+
                for (so = tcb.so_next; so != &tcb; so = so_next) {
                        so_next = so->so_next;
-                       
+
                        /*
                         * See if we need a tcp_fasttimo
                         */
                        if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
                           time_fasttimo = curtime; /* Flag when we want a fasttimo */
-                       
+
                        /*
                         * NOFDREF can include still connecting to local-host,
                         * newly socreated() sockets etc. Don't want to select these.
                         */
                        if (so->so_state & SS_NOFDREF || so->s == -1)
                           continue;
-                       
+
                        /*
                         * Set for reading sockets which are accepting
                         */
@@ -233,7 +239,7 @@ void slirp_select_fill(int *pnfds,
                                UPD_NFDS(so->s);
                                continue;
                        }
-                       
+
                        /*
                         * Set for writing sockets which are connecting
                         */
@@ -242,7 +248,7 @@ void slirp_select_fill(int *pnfds,
                                UPD_NFDS(so->s);
                                continue;
                        }
-                       
+
                        /*
                         * Set for writing if we are connected, can send more, and
                         * we have something to send
@@ -251,7 +257,7 @@ void slirp_select_fill(int *pnfds,
                                FD_SET(so->s, writefds);
                                UPD_NFDS(so->s);
                        }
-                       
+
                        /*
                         * Set for reading (and urgent data) if we are connected, can
                         * receive more, and we have room for it XXX /2 ?
@@ -262,13 +268,13 @@ void slirp_select_fill(int *pnfds,
                                UPD_NFDS(so->s);
                        }
                }
-               
+
                /*
                 * UDP sockets
                 */
                for (so = udb.so_next; so != &udb; so = so_next) {
                        so_next = so->so_next;
-                       
+
                        /*
                         * See if it's timed out
                         */
@@ -279,7 +285,7 @@ void slirp_select_fill(int *pnfds,
                                } else
                                        do_slowtimo = 1; /* Let socket expire */
                        }
-                       
+
                        /*
                         * When UDP packets are received from over the
                         * link, they're sendto()'d straight away, so
@@ -296,12 +302,12 @@ void slirp_select_fill(int *pnfds,
                        }
                }
        }
-       
+
        /*
         * Setup timeout to use minimum CPU usage, especially when idle
         */
-       
-       /* 
+
+       /*
         * First, see the timeout needed by *timo
         */
        timeout.tv_sec = 0;
@@ -318,20 +324,20 @@ void slirp_select_fill(int *pnfds,
                   timeout.tv_usec = 0;
                else if (timeout.tv_usec > 510000)
                   timeout.tv_usec = 510000;
-               
+
                /* Can only fasttimo if we also slowtimo */
                if (time_fasttimo) {
                        tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
                        if (tmp_time < 0)
                           tmp_time = 0;
-                       
+
                        /* Choose the smallest of the 2 */
                        if (tmp_time < timeout.tv_usec)
                           timeout.tv_usec = (u_int)tmp_time;
                }
        }
         *pnfds = nfds;
-}      
+}
 
 void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
 {
@@ -344,12 +350,12 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
 
        /* Update time */
        updtime();
-       
+
        /*
-        * See if anything has timed out 
+        * See if anything has timed out
         */
        if (link_up) {
-               if (time_fasttimo && ((curtime - time_fasttimo) >= 199)) {
+               if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
                        tcp_fasttimo();
                        time_fasttimo = 0;
                }
@@ -359,7 +365,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
                        last_slowtimo = curtime;
                }
        }
-       
+
        /*
         * Check sockets
         */
@@ -369,14 +375,14 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
                 */
                for (so = tcb.so_next; so != &tcb; so = so_next) {
                        so_next = so->so_next;
-                       
+
                        /*
                         * FD_ISSET is meaningless on these sockets
                         * (and they can crash the program)
                         */
                        if (so->so_state & SS_NOFDREF || so->s == -1)
                           continue;
-                       
+
                        /*
                         * Check for URG data
                         * This will soread as well, so no need to
@@ -396,12 +402,12 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
                                        continue;
                                } /* else */
                                ret = soread(so);
-                               
+
                                /* Output it if we read something */
                                if (ret > 0)
                                   tcp_output(sototcpcb(so));
                        }
-                       
+
                        /*
                         * Check sockets for writing
                         */
@@ -412,19 +418,19 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
                          if (so->so_state & SS_ISFCONNECTING) {
                            /* Connected */
                            so->so_state &= ~SS_ISFCONNECTING;
-                           
-                           ret = write(so->s, &ret, 0);
+
+                           ret = send(so->s, &ret, 0, 0);
                            if (ret < 0) {
                              /* XXXXX Must fix, zero bytes is a NOP */
                              if (errno == EAGAIN || errno == EWOULDBLOCK ||
                                  errno == EINPROGRESS || errno == ENOTCONN)
                                continue;
-                             
+
                              /* else failed */
                              so->so_state = SS_NOFDREF;
                            }
                            /* else so->so_state &= ~SS_ISFCONNECTING; */
-                           
+
                            /*
                             * Continue tcp_input
                             */
@@ -433,33 +439,33 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
                          } else
                            ret = sowrite(so);
                          /*
-                          * XXXXX If we wrote something (a lot), there 
+                          * XXXXX If we wrote something (a lot), there
                           * could be a need for a window update.
                           * In the worst case, the remote will send
                           * a window probe to get things going again
                           */
                        }
-                       
+
                        /*
                         * Probe a still-connecting, non-blocking socket
                         * to check if it's still alive
                         */
 #ifdef PROBE_CONN
                        if (so->so_state & SS_ISFCONNECTING) {
-                         ret = read(so->s, (char *)&ret, 0);
-                         
+                         ret = recv(so->s, (char *)&ret, 0,0);
+
                          if (ret < 0) {
                            /* XXX */
                            if (errno == EAGAIN || errno == EWOULDBLOCK ||
                                errno == EINPROGRESS || errno == ENOTCONN)
                              continue; /* Still connecting, continue */
-                           
+
                            /* else failed */
                            so->so_state = SS_NOFDREF;
-                           
+
                            /* tcp_input will take care of it */
                          } else {
-                           ret = write(so->s, &ret, 0);
+                           ret = send(so->s, &ret, 0,0);
                            if (ret < 0) {
                              /* XXX */
                              if (errno == EAGAIN || errno == EWOULDBLOCK ||
@@ -469,13 +475,13 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
                              so->so_state = SS_NOFDREF;
                            } else
                              so->so_state &= ~SS_ISFCONNECTING;
-                           
+
                          }
                          tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
                        } /* SS_ISFCONNECTING */
 #endif
                }
-               
+
                /*
                 * Now UDP sockets.
                 * Incoming packets are sent straight away, they're not buffered.
@@ -483,18 +489,27 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
                 */
                for (so = udb.so_next; so != &udb; so = so_next) {
                        so_next = so->so_next;
-                       
+
                        if (so->s != -1 && FD_ISSET(so->s, readfds)) {
                             sorecvfrom(so);
                         }
                }
        }
-       
+
        /*
         * See if we can start outputting
         */
        if (if_queued && link_up)
           if_start();
+
+       /* clear global file descriptor sets.
+        * these reside on the stack in vl.c
+        * so they're unusable if we're not in
+        * slirp_select_fill or slirp_select_poll.
+        */
+        global_readfds = NULL;
+        global_writefds = NULL;
+        global_xfds = NULL;
 }
 
 #define ETH_ALEN 6
@@ -506,7 +521,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
 #define        ARPOP_REQUEST   1               /* ARP request                  */
 #define        ARPOP_REPLY     2               /* ARP reply                    */
 
-struct ethhdr 
+struct ethhdr
 {
        unsigned char   h_dest[ETH_ALEN];       /* destination eth addr */
        unsigned char   h_source[ETH_ALEN];     /* source ether addr    */
@@ -538,13 +553,20 @@ void arp_input(const uint8_t *pkt, int pkt_len)
     struct ethhdr *reh = (struct ethhdr *)arp_reply;
     struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
     int ar_op;
+    struct ex_list *ex_ptr;
 
     ar_op = ntohs(ah->ar_op);
     switch(ar_op) {
     case ARPOP_REQUEST:
-        if (!memcmp(ah->ar_tip, &special_addr, 3) &&
-            (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)) {
-
+        if (!memcmp(ah->ar_tip, &special_addr, 3)) {
+            if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)
+                goto arp_ok;
+            for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+                if (ex_ptr->ex_addr == ah->ar_tip[3])
+                    goto arp_ok;
+            }
+            return;
+        arp_ok:
             /* XXX: make an ARP request to have the client address */
             memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
 
@@ -578,7 +600,7 @@ void slirp_input(const uint8_t *pkt, int pkt_len)
 
     if (pkt_len < ETH_HLEN)
         return;
-    
+
     proto = ntohs(*(uint16_t *)(pkt + 12));
     switch(proto) {
     case ETH_P_ARP:
@@ -588,11 +610,12 @@ void slirp_input(const uint8_t *pkt, int pkt_len)
         m = m_get();
         if (!m)
             return;
-        m->m_len = pkt_len;
-        memcpy(m->m_data, pkt, pkt_len);
+        /* Note: we add to align the IP header */
+        m->m_len = pkt_len + 2;
+        memcpy(m->m_data + 2, pkt, pkt_len);
 
-        m->m_data += ETH_HLEN;
-        m->m_len -= ETH_HLEN;
+        m->m_data += 2 + ETH_HLEN;
+        m->m_len -= 2 + ETH_HLEN;
 
         ip_input(m);
         break;
@@ -612,23 +635,31 @@ void if_encap(const uint8_t *ip_data, int ip_data_len)
 
     memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
     memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
+    /* XXX: not correct */
     eh->h_source[5] = CTL_ALIAS;
     eh->h_proto = htons(ETH_P_IP);
     memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
     slirp_output(buf, ip_data_len + ETH_HLEN);
 }
 
-int slirp_redir(int is_udp, int host_port, 
+int slirp_redir(int is_udp, int host_port,
                 struct in_addr guest_addr, int guest_port)
 {
     if (is_udp) {
-        if (!udp_listen(htons(host_port), guest_addr.s_addr, 
+        if (!udp_listen(htons(host_port), guest_addr.s_addr,
                         htons(guest_port), 0))
             return -1;
     } else {
-        if (!solisten(htons(host_port), guest_addr.s_addr, 
+        if (!solisten(htons(host_port), guest_addr.s_addr,
                       htons(guest_port), 0))
             return -1;
     }
     return 0;
 }
+
+int slirp_add_exec(int do_pty, const char *args, int addr_low_byte,
+                  int guest_port)
+{
+    return add_exec(&exec_list, do_pty, (char *)args,
+                    addr_low_byte, htons(guest_port));
+}