Message ID | 06d461a76323aec31c62db291e292da1c78107a5.1454927009.git.samuel.thibault@ens-lyon.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 08.02.2016 11:28, Samuel Thibault wrote: > From: Guillaume Subiron <maethor@subiron.org> > > 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> > --- ... > diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c > index eb0df81..5840471 100644 > --- a/slirp/tcp_input.c > +++ b/slirp/tcp_input.c > @@ -216,7 +216,8 @@ present: > 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; > @@ -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,11 @@ 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 *); > + save_ip = *ip; > + save_ip6 = *ip6; Could you do the "save_ip = *ip" within the "case AF_INET" below, and the "save_ip6 = *ip6" within the case AF_INET6 ? That would avoid to copy bytes that are not required. > switch (af) { > case AF_INET: > if (iphlen > sizeof(struct ip)) { > @@ -264,13 +271,6 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af) > } > /* XXX Check if too short */ > > - > - /* > - * 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 +295,35 @@ 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: > + 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: > goto drop; > } > > + 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 +369,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: > goto drop; > } > @@ -409,7 +436,6 @@ findso: > so->so_iptos = ((struct ip *)ti)->ip_tos; > break; > default: > - goto drop; > break; > } > } > @@ -643,6 +669,9 @@ findso: > case AF_INET: > *ip = save_ip; > break; > + case AF_INET6: > + *ip6 = save_ip6; > + break; > default: > goto drop; > } > @@ -1518,7 +1547,12 @@ 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(); > break; > } ... Thomas
Thomas Huth, on Wed 10 Feb 2016 11:47:05 +0100, wrote: > > + ip = mtod(m, struct ip *); > > + ip6 = mtod(m, struct ip6 *); > > + save_ip = *ip; > > + save_ip6 = *ip6; > > Could you do the "save_ip = *ip" within the "case AF_INET" below, and > the "save_ip6 = *ip6" within the case AF_INET6 ? That would avoid to > copy bytes that are not required. The issue is that when save_ip is used later on in another switch/case, the compiler will warn that save_ip may be used uninitialized, because the compiler is not smart enough to realize that the two codes are under the same conditions. It seems to happen that my current version of gcc doesn't warn about save_ip, but it does warn about ip if I moved that too for instance. So we can move the assignment indeed, but there will probably be some compilers which will emit a warning here, I don't know what we prefer. Samuel
On 10.02.2016 13:30, Samuel Thibault wrote: > Thomas Huth, on Wed 10 Feb 2016 11:47:05 +0100, wrote: >>> + ip = mtod(m, struct ip *); >>> + ip6 = mtod(m, struct ip6 *); >>> + save_ip = *ip; >>> + save_ip6 = *ip6; >> >> Could you do the "save_ip = *ip" within the "case AF_INET" below, and >> the "save_ip6 = *ip6" within the case AF_INET6 ? That would avoid to >> copy bytes that are not required. > > The issue is that when save_ip is used later on in another switch/case, > the compiler will warn that save_ip may be used uninitialized, because > the compiler is not smart enough to realize that the two codes are under > the same conditions. It seems to happen that my current version of gcc > doesn't warn about save_ip, but it does warn about ip if I moved that > too for instance. So we can move the assignment indeed, but there will > probably be some compilers which will emit a warning here, I don't know > what we prefer. If current compilers only complain about the "ip = ..." statement, then I'd suggest to give it a try to only move the "save_ip = ..." statements into the switch cases (I think it's worth a try since this is the more expensive operation). If that causes trouble later, we can still move the statements back (or maybe fix the warnings by other means). Thomas
diff --git a/slirp/ip6_input.c b/slirp/ip6_input.c index d7c612e..b03b795 100644 --- a/slirp/ip6_input.c +++ b/slirp/ip6_input.c @@ -58,7 +58,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); diff --git a/slirp/tcp.h b/slirp/tcp.h index 2e2b403..61befcd 100644 --- a/slirp/tcp.h +++ b/slirp/tcp.h @@ -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 */ diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index eb0df81..5840471 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -216,7 +216,8 @@ present: 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; @@ -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,11 @@ 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 *); + save_ip = *ip; + save_ip6 = *ip6; + switch (af) { case AF_INET: if (iphlen > sizeof(struct ip)) { @@ -264,13 +271,6 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af) } /* XXX Check if too short */ - - /* - * 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 +295,35 @@ 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: + 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: goto drop; } + 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 +369,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: goto drop; } @@ -409,7 +436,6 @@ findso: so->so_iptos = ((struct ip *)ti)->ip_tos; break; default: - goto drop; break; } } @@ -643,6 +669,9 @@ findso: case AF_INET: *ip = save_ip; break; + case AF_INET6: + *ip6 = save_ip6; + break; default: goto drop; } @@ -1518,7 +1547,12 @@ 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(); break; } diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c index 429018a..b016a56 100644 --- a/slirp/tcp_output.c +++ b/slirp/tcp_output.c @@ -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: goto out; } diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index f2ef8f3..b18e0da 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -88,7 +88,17 @@ 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(); break; } @@ -156,7 +166,12 @@ 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(); break; } #undef xchg @@ -182,6 +197,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: @@ -204,7 +220,22 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m, (void) ip_output((struct socket *)0, 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; + + (void) ip6_output((struct socket *)0, m, 0); + break; + default: + g_assert_not_reached(); break; } } @@ -225,7 +256,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; diff --git a/slirp/tcpip.h b/slirp/tcpip.h index d9b5d70..4a2987f 100644 --- a/slirp/tcpip.h +++ b/slirp/tcpip.h @@ -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 */ @@ -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