Skip to content

Commit

Permalink
slirp: Handle IPv6 in TCP functions
Browse files Browse the repository at this point in the history
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: Guillaume Subiron <maethor@subiron.org>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Reviewed-by: Thomas Huth <thuth@redhat.com>
  • Loading branch information
Guillaume Subiron authored and sthibaul committed Mar 15, 2016
1 parent 1252cf4 commit 3feea44
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 9 deletions.
3 changes: 2 additions & 1 deletion slirp/ip6_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions slirp/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
72 changes: 66 additions & 6 deletions slirp/tcp_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,8 @@ tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti,
void
tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
{
struct ip save_ip, *ip;
struct ip save_ip, *ip;
struct ip6 save_ip6, *ip6;
register struct tcpiphdr *ti;
caddr_t optp = NULL;
int optlen = 0;
Expand All @@ -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;

Expand All @@ -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)) {
Expand All @@ -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;

Expand All @@ -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
Expand Down Expand Up @@ -350,6 +382,14 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
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();
}
Expand Down Expand Up @@ -408,6 +448,8 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
case AF_INET:
so->so_iptos = ((struct ip *)ti)->ip_tos;
break;
case AF_INET6:
break;
default:
g_assert_not_reached();
}
Expand Down Expand Up @@ -634,6 +676,12 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
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();
}
Expand All @@ -652,6 +700,14 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
*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();
}
Expand Down Expand Up @@ -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();
}
Expand Down
16 changes: 16 additions & 0 deletions slirp/tcp_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -468,6 +469,21 @@ tcp_output(struct tcpcb *tp)
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();
}
Expand Down
32 changes: 30 additions & 2 deletions slirp/tcp_subr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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();
}
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions slirp/tcpip.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ struct tcpiphdr {
uint8_t ih_x1; /* (unused) */
uint8_t ih_pr; /* protocol */
} ti_i4;
struct {
struct in6_addr ih_src;
struct in6_addr ih_dst;
uint8_t ih_x1;
uint8_t ih_nh;
} ti_i6;
} ti;
uint16_t ti_x0;
uint16_t ti_len; /* protocol length */
Expand All @@ -54,6 +60,9 @@ struct tcpiphdr {
#define ti_pr ti.ti_i4.ih_pr
#define ti_src ti.ti_i4.ih_src
#define ti_dst ti.ti_i4.ih_dst
#define ti_src6 ti.ti_i6.ih_src
#define ti_dst6 ti.ti_i6.ih_dst
#define ti_nh6 ti.ti_i6.ih_nh
#define ti_sport ti_t.th_sport
#define ti_dport ti_t.th_dport
#define ti_seq ti_t.th_seq
Expand Down

0 comments on commit 3feea44

Please sign in to comment.