Commit 3feea444 authored by Guillaume Subiron's avatar Guillaume Subiron Committed by Samuel Thibault
Browse files

slirp: Handle IPv6 in TCP functions



This patch adds IPv6 case in TCP functions refactored by the last
patches.
This also adds IPv6 pseudo-header in tcpiphdr structure.
Finally, tcp_input() is called by ip6_input().

Signed-off-by: default avatarGuillaume Subiron <maethor@subiron.org>
Signed-off-by: default avatarSamuel Thibault <samuel.thibault@ens-lyon.org>
Reviewed-by: default avatarThomas Huth <thuth@redhat.com>
parent 1252cf40
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -55,7 +55,8 @@ void ip6_input(struct mbuf *m)
     */
    switch (ip6->ip_nh) {
    case IPPROTO_TCP:
        icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
        NTOHS(ip6->ip_pl);
        tcp_input(m, sizeof(struct ip6), (struct socket *)NULL, AF_INET6);
        break;
    case IPPROTO_UDP:
        udp6_input(m);
+2 −0
Original line number Diff line number Diff line
@@ -106,6 +106,8 @@ struct tcphdr {
 */
#undef TCP_MSS
#define	TCP_MSS	1460
#undef TCP6_MSS
#define TCP6_MSS 1440

#undef TCP_MAXWIN
#define	TCP_MAXWIN	65535	/* largest value for (unscaled) window */
+66 −6
Original line number Diff line number Diff line
@@ -217,6 +217,7 @@ void
tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
{
	struct ip save_ip, *ip;
	struct ip6 save_ip6, *ip6;
	register struct tcpiphdr *ti;
	caddr_t optp = NULL;
	int optlen = 0;
@@ -230,6 +231,7 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
	int ret;
	struct sockaddr_storage lhost, fhost;
	struct sockaddr_in *lhost4, *fhost4;
	struct sockaddr_in6 *lhost6, *fhost6;
    struct ex_list *ex_ptr;
    Slirp *slirp;

@@ -256,6 +258,9 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
	}
	slirp = m->slirp;

	ip = mtod(m, struct ip *);
	ip6 = mtod(m, struct ip6 *);

	switch (af) {
	case AF_INET:
	    if (iphlen > sizeof(struct ip)) {
@@ -269,7 +274,6 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
	     * Save a copy of the IP header in case we want restore it
	     * for sending an ICMP error message in response.
	     */
	    ip = mtod(m, struct ip *);
	    save_ip = *ip;
	    save_ip.ip_len += iphlen;

@@ -295,16 +299,44 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
	    ti->ti_dst = save_ip.ip_dst;
	    ti->ti_pr = save_ip.ip_p;
	    ti->ti_len = htons((uint16_t)tlen);
	    len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
	    if (cksum(m, len)) {
	        goto drop;
	    }
	    break;

	case AF_INET6:
	    /*
	     * Save a copy of the IP header in case we want restore it
	     * for sending an ICMP error message in response.
	     */
	    save_ip6 = *ip6;
	    /*
	     * Get IP and TCP header together in first mbuf.
	     * Note: IP leaves IP header in first mbuf.
	     */
	    m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip6)
	                                         + sizeof(struct tcphdr));
	    m->m_len  += sizeof(struct tcpiphdr) - (sizeof(struct ip6)
	                                         + sizeof(struct tcphdr));
	    ti = mtod(m, struct tcpiphdr *);

	    tlen = ip6->ip_pl;
	    tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
	    memset(&ti->ih_mbuf, 0 , sizeof(struct mbuf_ptr));
	    memset(&ti->ti, 0, sizeof(ti->ti));
	    ti->ti_x0 = 0;
	    ti->ti_src6 = save_ip6.ip_src;
	    ti->ti_dst6 = save_ip6.ip_dst;
	    ti->ti_nh6 = save_ip6.ip_nh;
	    ti->ti_len = htons((uint16_t)tlen);
	    break;

	default:
	    g_assert_not_reached();
	}

	len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
	if (cksum(m, len)) {
	    goto drop;
	}

	/*
	 * Check that TCP offset makes sense,
	 * pull out TCP options and adjust length.		XXX
@@ -350,6 +382,14 @@ findso:
	    fhost4->sin_addr = ti->ti_dst;
	    fhost4->sin_port = ti->ti_dport;
	    break;
	case AF_INET6:
	    lhost6 = (struct sockaddr_in6 *) &lhost;
	    lhost6->sin6_addr = ti->ti_src6;
	    lhost6->sin6_port = ti->ti_sport;
	    fhost6 = (struct sockaddr_in6 *) &fhost;
	    fhost6->sin6_addr = ti->ti_dst6;
	    fhost6->sin6_port = ti->ti_dport;
	    break;
	default:
	    g_assert_not_reached();
	}
@@ -408,6 +448,8 @@ findso:
	      case AF_INET:
	          so->so_iptos = ((struct ip *)ti)->ip_tos;
	          break;
	      case AF_INET6:
	          break;
	      default:
	          g_assert_not_reached();
	      }
@@ -634,6 +676,12 @@ findso:
		  code = ICMP_UNREACH_HOST;
		}
		break;
	      case AF_INET6:
		code = ICMP6_UNREACH_NO_ROUTE;
		if (errno == EHOSTUNREACH) {
		  code = ICMP6_UNREACH_ADDRESS;
		}
		break;
	      default:
		g_assert_not_reached();
	      }
@@ -652,6 +700,14 @@ findso:
		*ip = save_ip;
		icmp_send_error(m, ICMP_UNREACH, code, 0, strerror(errno));
		break;
	      case AF_INET6:
		m->m_data += sizeof(struct tcpiphdr) - (sizeof(struct ip6)
						     + sizeof(struct tcphdr));
		m->m_len  -= sizeof(struct tcpiphdr) - (sizeof(struct ip6)
						     + sizeof(struct tcphdr));
		*ip6 = save_ip6;
		icmp6_send_error(m, ICMP6_UNREACH, code);
		break;
	      default:
		g_assert_not_reached();
	      }
@@ -1526,6 +1582,10 @@ tcp_mss(struct tcpcb *tp, u_int offer)
	    mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr)
	                              + sizeof(struct ip);
	    break;
	case AF_INET6:
	    mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr)
	                              + sizeof(struct ip6);
	    break;
	default:
	    g_assert_not_reached();
	}
+16 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ tcp_output(struct tcpcb *tp)
	register struct mbuf *m;
	register struct tcpiphdr *ti, tcpiph_save;
	struct ip *ip;
	struct ip6 *ip6;
	u_char opt[MAX_TCPOPTLEN];
	unsigned optlen, hdrlen;
	int idle, sendalot;
@@ -468,6 +469,21 @@ send:
	    error = ip_output(so, 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 = tcpiph_save.ti_len;
	    ip6->ip_dst = tcpiph_save.ti_dst6;
	    ip6->ip_src = tcpiph_save.ti_src6;
	    ip6->ip_nh = tcpiph_save.ti_nh6;

	    error = ip6_output(so, m, 0);
	    break;

	default:
	    g_assert_not_reached();
	}
+30 −2
Original line number Diff line number Diff line
@@ -88,6 +88,15 @@ tcp_template(struct tcpcb *tp)
	    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();
	}
@@ -156,6 +165,10 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
		    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();
		}
@@ -182,6 +195,7 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,

	struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
	struct ip *ip;
	struct ip6 *ip6;

	switch (af) {
	case AF_INET:
@@ -201,7 +215,21 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
	        ip->ip_ttl = IPDEFTTL;
	    }

	    (void) ip_output((struct socket *)0, m);
	    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:
@@ -225,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;
Loading