These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / slirp / tcp_subr.c
index 7571c5a..6b9fef2 100644 (file)
@@ -38,6 +38,7 @@
  * terms and conditions of the copyright.
  */
 
+#include "qemu/osdep.h"
 #include <slirp.h>
 
 /* patchable/settable parameters for tcp */
@@ -75,13 +76,30 @@ tcp_template(struct tcpcb *tp)
        register struct tcpiphdr *n = &tp->t_template;
 
        n->ti_mbuf = NULL;
-       n->ti_x1 = 0;
-       n->ti_pr = IPPROTO_TCP;
-       n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
-       n->ti_src = so->so_faddr;
-       n->ti_dst = so->so_laddr;
-       n->ti_sport = so->so_fport;
-       n->ti_dport = so->so_lport;
+       memset(&n->ti, 0, sizeof(n->ti));
+       n->ti_x0 = 0;
+       switch (so->so_ffamily) {
+       case AF_INET:
+           n->ti_pr = IPPROTO_TCP;
+           n->ti_len = htons(sizeof(struct tcphdr));
+           n->ti_src = so->so_faddr;
+           n->ti_dst = so->so_laddr;
+           n->ti_sport = so->so_fport;
+           n->ti_dport = so->so_lport;
+           break;
+
+       case AF_INET6:
+           n->ti_nh6 = IPPROTO_TCP;
+           n->ti_len = htons(sizeof(struct tcphdr));
+           n->ti_src6 = so->so_faddr6;
+           n->ti_dst6 = so->so_laddr6;
+           n->ti_sport = so->so_fport6;
+           n->ti_dport = so->so_lport6;
+           break;
+
+       default:
+           g_assert_not_reached();
+       }
 
        n->ti_seq = 0;
        n->ti_ack = 0;
@@ -108,7 +126,7 @@ tcp_template(struct tcpcb *tp)
  */
 void
 tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
-            tcp_seq ack, tcp_seq seq, int flags)
+            tcp_seq ack, tcp_seq seq, int flags, unsigned short af)
 {
        register int tlen;
        int win = 0;
@@ -130,6 +148,7 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
                m->m_data += IF_MAXLINKHDR;
                *mtod(m, struct tcpiphdr *) = *ti;
                ti = mtod(m, struct tcpiphdr *);
+               memset(&ti->ti, 0, sizeof(ti->ti));
                flags = TH_ACK;
        } else {
                /*
@@ -141,16 +160,26 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
                m->m_len = sizeof (struct tcpiphdr);
                tlen = 0;
 #define xchg(a,b,type) { type t; t=a; a=b; b=t; }
-               xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32_t);
-               xchg(ti->ti_dport, ti->ti_sport, uint16_t);
+               switch (af) {
+               case AF_INET:
+                   xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32_t);
+                   xchg(ti->ti_dport, ti->ti_sport, uint16_t);
+                   break;
+               case AF_INET6:
+                   xchg(ti->ti_dst6, ti->ti_src6, struct in6_addr);
+                   xchg(ti->ti_dport, ti->ti_sport, uint16_t);
+                   break;
+               default:
+                   g_assert_not_reached();
+               }
 #undef xchg
        }
        ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
        tlen += sizeof (struct tcpiphdr);
        m->m_len = tlen;
 
-        ti->ti_mbuf = NULL;
-       ti->ti_x1 = 0;
+       ti->ti_mbuf = NULL;
+       ti->ti_x0 = 0;
        ti->ti_seq = htonl(seq);
        ti->ti_ack = htonl(ack);
        ti->ti_x2 = 0;
@@ -163,14 +192,49 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
        ti->ti_urp = 0;
        ti->ti_sum = 0;
        ti->ti_sum = cksum(m, tlen);
-       ((struct ip *)ti)->ip_len = tlen;
-
-       if(flags & TH_RST)
-         ((struct ip *)ti)->ip_ttl = MAXTTL;
-       else
-         ((struct ip *)ti)->ip_ttl = IPDEFTTL;
 
-       (void) ip_output((struct socket *)0, m);
+       struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
+       struct ip *ip;
+       struct ip6 *ip6;
+
+       switch (af) {
+       case AF_INET:
+           m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+                                                - sizeof(struct ip);
+           m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+                                                - sizeof(struct ip);
+           ip = mtod(m, struct ip *);
+           ip->ip_len = tlen;
+           ip->ip_dst = tcpiph_save.ti_dst;
+           ip->ip_src = tcpiph_save.ti_src;
+           ip->ip_p = tcpiph_save.ti_pr;
+
+           if (flags & TH_RST) {
+               ip->ip_ttl = MAXTTL;
+           } else {
+               ip->ip_ttl = IPDEFTTL;
+           }
+
+           ip_output(NULL, m);
+           break;
+
+       case AF_INET6:
+           m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+                                                - sizeof(struct ip6);
+           m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+                                                - sizeof(struct ip6);
+           ip6 = mtod(m, struct ip6 *);
+           ip6->ip_pl = tlen;
+           ip6->ip_dst = tcpiph_save.ti_dst6;
+           ip6->ip_src = tcpiph_save.ti_src6;
+           ip6->ip_nh = tcpiph_save.ti_nh6;
+
+           ip6_output(NULL, m, 0);
+           break;
+
+       default:
+           g_assert_not_reached();
+       }
 }
 
 /*
@@ -189,7 +253,7 @@ tcp_newtcpcb(struct socket *so)
 
        memset((char *) tp, 0, sizeof(struct tcpcb));
        tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp;
-       tp->t_maxseg = TCP_MSS;
+       tp->t_maxseg = (so->so_ffamily == AF_INET) ? TCP_MSS : TCP6_MSS;
 
        tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
        tp->t_socket = so;
@@ -224,7 +288,7 @@ tcp_newtcpcb(struct socket *so)
 struct tcpcb *tcp_drop(struct tcpcb *tp, int err)
 {
        DEBUG_CALL("tcp_drop");
-       DEBUG_ARG("tp = %lx", (long)tp);
+       DEBUG_ARG("tp = %p", tp);
        DEBUG_ARG("errno = %d", errno);
 
        if (TCPS_HAVERCVDSYN(tp->t_state)) {
@@ -249,7 +313,7 @@ tcp_close(struct tcpcb *tp)
        register struct mbuf *m;
 
        DEBUG_CALL("tcp_close");
-       DEBUG_ARG("tp = %lx", (long )tp);
+       DEBUG_ARG("tp = %p", tp);
 
        /* free the reassembly queue, if any */
        t = tcpfrag_list_first(tp);
@@ -290,7 +354,11 @@ tcp_sockclosed(struct tcpcb *tp)
 {
 
        DEBUG_CALL("tcp_sockclosed");
-       DEBUG_ARG("tp = %lx", (long)tp);
+       DEBUG_ARG("tp = %p", tp);
+
+       if (!tp) {
+               return;
+       }
 
        switch (tp->t_state) {
 
@@ -310,8 +378,7 @@ tcp_sockclosed(struct tcpcb *tp)
                tp->t_state = TCPS_LAST_ACK;
                break;
        }
-       if (tp)
-               tcp_output(tp);
+       tcp_output(tp);
 }
 
 /*
@@ -324,42 +391,29 @@ tcp_sockclosed(struct tcpcb *tp)
  * nonblocking.  Connect returns after the SYN is sent, and does
  * not wait for ACK+SYN.
  */
-int tcp_fconnect(struct socket *so)
+int tcp_fconnect(struct socket *so, unsigned short af)
 {
-  Slirp *slirp = so->slirp;
   int ret=0;
 
   DEBUG_CALL("tcp_fconnect");
-  DEBUG_ARG("so = %lx", (long )so);
+  DEBUG_ARG("so = %p", so);
 
-  if( (ret = so->s = qemu_socket(AF_INET,SOCK_STREAM,0)) >= 0) {
+  ret = so->s = qemu_socket(af, SOCK_STREAM, 0);
+  if (ret >= 0) {
     int opt, s=so->s;
-    struct sockaddr_in addr;
+    struct sockaddr_storage addr;
 
     qemu_set_nonblock(s);
     socket_set_fast_reuse(s);
     opt = 1;
     qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
 
-    addr.sin_family = AF_INET;
-    if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
-        slirp->vnetwork_addr.s_addr) {
-      /* It's an alias */
-      if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
-       if (get_dns_addr(&addr.sin_addr) < 0)
-         addr.sin_addr = loopback_addr;
-      } else {
-       addr.sin_addr = loopback_addr;
-      }
-    } else
-      addr.sin_addr = so->so_faddr;
-    addr.sin_port = so->so_fport;
-
-    DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, "
-               "addr.sin_addr.s_addr=%.16s\n",
-               ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
+    addr = so->fhost.ss;
+    DEBUG_CALL(" connect()ing")
+    sotranslate_out(so, &addr);
+
     /* We don't care what port we get */
-    ret = connect(s,(struct sockaddr *)&addr,sizeof (addr));
+    ret = connect(s, (struct sockaddr *)&addr, sockaddr_size(&addr));
 
     /*
      * If it's not in progress, it failed, so we just return 0,
@@ -387,13 +441,13 @@ void tcp_connect(struct socket *inso)
 {
     Slirp *slirp = inso->slirp;
     struct socket *so;
-    struct sockaddr_in addr;
-    socklen_t addrlen = sizeof(struct sockaddr_in);
+    struct sockaddr_storage addr;
+    socklen_t addrlen = sizeof(struct sockaddr_storage);
     struct tcpcb *tp;
     int s, opt;
 
     DEBUG_CALL("tcp_connect");
-    DEBUG_ARG("inso = %lx", (long)inso);
+    DEBUG_ARG("inso = %p", inso);
 
     /*
      * If it's an SS_ACCEPTONCE socket, no need to socreate()
@@ -413,8 +467,8 @@ void tcp_connect(struct socket *inso)
             free(so); /* NOT sofree */
             return;
         }
-        so->so_laddr = inso->so_laddr;
-        so->so_lport = inso->so_lport;
+        so->lhost = inso->lhost;
+        so->so_ffamily = inso->so_ffamily;
     }
 
     tcp_mss(sototcpcb(so), 0);
@@ -430,14 +484,8 @@ void tcp_connect(struct socket *inso)
     qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
     socket_set_nodelay(s);
 
-    so->so_fport = addr.sin_port;
-    so->so_faddr = addr.sin_addr;
-    /* Translate connections from localhost to the real hostname */
-    if (so->so_faddr.s_addr == 0 ||
-        (so->so_faddr.s_addr & loopback_mask) ==
-        (loopback_addr.s_addr & loopback_mask)) {
-        so->so_faddr = slirp->vhost_addr;
-    }
+    so->fhost.ss = addr;
+    sotranslate_accept(so);
 
     /* Close the accept() socket, set right state */
     if (inso->so_state & SS_FACCEPTONCE) {
@@ -564,8 +612,8 @@ tcp_emu(struct socket *so, struct mbuf *m)
        char *bptr;
 
        DEBUG_CALL("tcp_emu");
-       DEBUG_ARG("so = %lx", (long)so);
-       DEBUG_ARG("m = %lx", (long)m);
+       DEBUG_ARG("so = %p", so);
+       DEBUG_ARG("m = %p", m);
 
        switch(so->so_emu) {
                int x, i;
@@ -900,7 +948,7 @@ int tcp_ctl(struct socket *so)
     int do_pty;
 
     DEBUG_CALL("tcp_ctl");
-    DEBUG_ARG("so = %lx", (long )so);
+    DEBUG_ARG("so = %p", so);
 
     if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
         /* Check if it's pty_exec */