summary refs log tree commit diff stats
path: root/slirp/slirp.c
diff options
context:
space:
mode:
Diffstat (limited to 'slirp/slirp.c')
-rw-r--r--slirp/slirp.c142
1 files changed, 83 insertions, 59 deletions
diff --git a/slirp/slirp.c b/slirp/slirp.c
index b0a092c14c..8affd46c7c 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -33,13 +33,16 @@ struct in_addr dns_addr;
 /* host loopback address */
 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;
-
+/* virtual network configuration */
+struct in_addr vnetwork_addr;
+struct in_addr vnetwork_mask;
+struct in_addr vhost_addr;
+struct in_addr vdhcp_startaddr;
+struct in_addr vnameserver_addr;
+
+/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
 static const uint8_t special_ethaddr[6] = {
-    0x52, 0x54, 0x00, 0x12, 0x35, 0x00
+    0x52, 0x55, 0x00, 0x00, 0x00, 0x00
 };
 
 /* ARP cache for the guest IP addresses (XXX: allow many entries) */
@@ -48,7 +51,6 @@ static struct in_addr client_ipaddr;
 
 static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
 
-const char *slirp_special_ip = CTL_SPECIAL;
 int slirp_restrict;
 static int do_slowtimo;
 int link_up;
@@ -176,12 +178,12 @@ void slirp_init(int restricted, const char *special_ip, const char *tftp_path,
 {
     //    debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
 
+    struct in_addr special_addr = { .s_addr = htonl(0x0a000200) };
 #ifdef _WIN32
-    {
-        WSADATA Data;
-        WSAStartup(MAKEWORD(2,0), &Data);
-	atexit(slirp_cleanup);
-    }
+    WSADATA Data;
+
+    WSAStartup(MAKEWORD(2,0), &Data);
+    atexit(slirp_cleanup);
 #endif
 
     link_up = 1;
@@ -201,9 +203,9 @@ void slirp_init(int restricted, const char *special_ip, const char *tftp_path,
         fprintf (stderr, "Warning: No DNS servers found\n");
     }
 
-    if (special_ip)
-        slirp_special_ip = special_ip;
-
+    if (special_ip) {
+        inet_aton(special_ip, &special_addr);
+    }
     qemu_free(tftp_prefix);
     tftp_prefix = NULL;
     if (tftp_path) {
@@ -215,8 +217,11 @@ void slirp_init(int restricted, const char *special_ip, const char *tftp_path,
         bootp_filename = qemu_strdup(bootfile);
     }
 
-    inet_aton(slirp_special_ip, &special_addr);
-    alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
+    vnetwork_addr = special_addr;
+    vnetwork_mask.s_addr = htonl(0xffffff00);
+    vhost_addr.s_addr = special_addr.s_addr | htonl(2);
+    vdhcp_startaddr.s_addr = special_addr.s_addr | htonl(15);
+    vnameserver_addr.s_addr = special_addr.s_addr | htonl(3);
     getouraddr();
     register_savevm("slirp", 0, 1, slirp_state_save, slirp_state_load, NULL);
 }
@@ -601,10 +606,10 @@ struct arphdr
 	  *	 Ethernet looks like this : This bit is variable sized however...
 	  */
 	unsigned char		ar_sha[ETH_ALEN];	/* sender hardware address	*/
-	unsigned char		ar_sip[4];		/* sender IP address		*/
+	uint32_t		ar_sip;			/* sender IP address		*/
 	unsigned char		ar_tha[ETH_ALEN];	/* target hardware address	*/
-	unsigned char		ar_tip[4];		/* target IP address		*/
-};
+	uint32_t		ar_tip	;		/* target IP address		*/
+} __attribute__((packed));
 
 static void arp_input(const uint8_t *pkt, int pkt_len)
 {
@@ -619,11 +624,12 @@ static void arp_input(const uint8_t *pkt, int pkt_len)
     ar_op = ntohs(ah->ar_op);
     switch(ar_op) {
     case ARPOP_REQUEST:
-        if (!memcmp(ah->ar_tip, &special_addr, 3)) {
-            if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)
+        if ((ah->ar_tip & vnetwork_mask.s_addr) == vnetwork_addr.s_addr) {
+            if (ah->ar_tip == vnameserver_addr.s_addr ||
+                ah->ar_tip == vhost_addr.s_addr)
                 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])
+                if (ex_ptr->ex_addr.s_addr == ah->ar_tip)
                     goto arp_ok;
             }
             return;
@@ -633,8 +639,8 @@ static void arp_input(const uint8_t *pkt, int pkt_len)
 
             /* ARP request for alias/dns mac address */
             memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
-            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
-            reh->h_source[5] = ah->ar_tip[3];
+            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
+            memcpy(&reh->h_source[2], &ah->ar_tip, 4);
             reh->h_proto = htons(ETH_P_ARP);
 
             rah->ar_hrd = htons(1);
@@ -643,16 +649,16 @@ static void arp_input(const uint8_t *pkt, int pkt_len)
             rah->ar_pln = 4;
             rah->ar_op = htons(ARPOP_REPLY);
             memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
-            memcpy(rah->ar_sip, ah->ar_tip, 4);
+            rah->ar_sip = ah->ar_tip;
             memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
-            memcpy(rah->ar_tip, ah->ar_sip, 4);
+            rah->ar_tip = ah->ar_sip;
             slirp_output(arp_reply, sizeof(arp_reply));
         }
         break;
     case ARPOP_REPLY:
         /* reply to request of client mac address ? */
         if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) &&
-            !memcmp(ah->ar_sip, &client_ipaddr.s_addr, 4)) {
+            ah->ar_sip == client_ipaddr.s_addr) {
             memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN);
         }
         break;
@@ -716,8 +722,8 @@ void if_encap(const uint8_t *ip_data, int ip_data_len)
            in place of sending the packet and we hope that the sender
            will retry sending its packet. */
         memset(reh->h_dest, 0xff, ETH_ALEN);
-        memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
-        reh->h_source[5] = CTL_ALIAS;
+        memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
+        memcpy(&reh->h_source[2], &vhost_addr, 4);
         reh->h_proto = htons(ETH_P_ARP);
         rah->ar_hrd = htons(1);
         rah->ar_pro = htons(ETH_P_IP);
@@ -725,21 +731,21 @@ void if_encap(const uint8_t *ip_data, int ip_data_len)
         rah->ar_pln = 4;
         rah->ar_op = htons(ARPOP_REQUEST);
         /* source hw addr */
-        memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 1);
-        rah->ar_sha[5] = CTL_ALIAS;
+        memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
+        memcpy(&rah->ar_sha[2], &vhost_addr, 4);
         /* source IP */
-        memcpy(rah->ar_sip, &alias_addr, 4);
+        rah->ar_sip = vhost_addr.s_addr;
         /* target hw addr (none) */
         memset(rah->ar_tha, 0, ETH_ALEN);
         /* target IP */
-        memcpy(rah->ar_tip, &iph->ip_dst, 4);
+        rah->ar_tip = iph->ip_dst.s_addr;
         client_ipaddr = iph->ip_dst;
         slirp_output(arp_req, sizeof(arp_req));
     } else {
         memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
-        memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
+        memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
         /* XXX: not correct */
-        eh->h_source[5] = CTL_ALIAS;
+        memcpy(&eh->h_source[2], &vhost_addr, 4);
         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);
@@ -772,6 +778,9 @@ int slirp_redir_rm(int is_udp, int host_port)
 int slirp_redir(int is_udp, int host_port,
                 struct in_addr guest_addr, int guest_port)
 {
+    if (!guest_addr.s_addr) {
+        guest_addr = vdhcp_startaddr;
+    }
     if (is_udp) {
         if (!udp_listen(htons(host_port), guest_addr.s_addr,
                         htons(guest_port), 0))
@@ -787,8 +796,17 @@ int slirp_redir(int is_udp, int host_port,
 int slirp_add_exec(int do_pty, const void *args, int addr_low_byte,
                   int guest_port)
 {
-    return add_exec(&exec_list, do_pty, (char *)args,
-                    addr_low_byte, htons(guest_port));
+    struct in_addr guest_addr = {
+        .s_addr = vnetwork_addr.s_addr | htonl(addr_low_byte)
+    };
+
+    if ((guest_addr.s_addr & vnetwork_mask.s_addr) != vnetwork_addr.s_addr ||
+        guest_addr.s_addr == vhost_addr.s_addr ||
+        guest_addr.s_addr == vnameserver_addr.s_addr) {
+        return -1;
+    }
+    return add_exec(&exec_list, do_pty, (char *)args, guest_addr,
+                    htons(guest_port));
 }
 
 ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
@@ -801,31 +819,32 @@ ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
 	return send(so->s, buf, len, flags);
 }
 
-static struct socket *slirp_find_ctl_socket(int addr_low_byte, int guest_port)
+static struct socket *
+slirp_find_ctl_socket(struct in_addr guest_addr, int guest_port)
 {
-	struct socket *so;
-
-	for (so = tcb.so_next; so != &tcb; so = so->so_next) {
-		if ((so->so_faddr.s_addr & htonl(0xffffff00)) ==
-				special_addr.s_addr
-				&& (ntohl(so->so_faddr.s_addr) & 0xff) ==
-				addr_low_byte
-				&& htons(so->so_fport) == guest_port)
-			return so;
-	}
+    struct socket *so;
 
-	return NULL;
+    for (so = tcb.so_next; so != &tcb; so = so->so_next) {
+        if (so->so_faddr.s_addr == guest_addr.s_addr &&
+            htons(so->so_fport) == guest_port) {
+            return so;
+        }
+    }
+    return NULL;
 }
 
 size_t slirp_socket_can_recv(int addr_low_byte, int guest_port)
 {
+    struct in_addr guest_addr = {
+        .s_addr = vnetwork_addr.s_addr | htonl(addr_low_byte)
+    };
 	struct iovec iov[2];
 	struct socket *so;
 
     if (!link_up)
         return 0;
 
-	so = slirp_find_ctl_socket(addr_low_byte, guest_port);
+	so = slirp_find_ctl_socket(guest_addr, guest_port);
 
 	if (!so || so->so_state & SS_NOFDREF)
 		return 0;
@@ -840,8 +859,11 @@ void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf,
         int size)
 {
     int ret;
-    struct socket *so = slirp_find_ctl_socket(addr_low_byte, guest_port);
-   
+    struct in_addr guest_addr = {
+        .s_addr = vnetwork_addr.s_addr | htonl(addr_low_byte)
+    };
+    struct socket *so = slirp_find_ctl_socket(guest_addr, guest_port);
+
     if (!so)
         return;
 
@@ -1055,15 +1077,17 @@ static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
         if (ret < 0)
             return ret;
 
-        if ((so->so_faddr.s_addr & htonl(0xffffff00)) != special_addr.s_addr)
+        if ((so->so_faddr.s_addr & vnetwork_mask.s_addr) !=
+            vnetwork_addr.s_addr) {
             return -EINVAL;
-
-        for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
+        }
+        for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
             if (ex_ptr->ex_pty == 3 &&
-                    (ntohl(so->so_faddr.s_addr) & 0xff) == ex_ptr->ex_addr &&
-                    so->so_fport == ex_ptr->ex_fport)
+                so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
+                so->so_fport == ex_ptr->ex_fport) {
                 break;
-
+            }
+        }
         if (!ex_ptr)
             return -EINVAL;