aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Subiron <maethor@subiron.org>2016-03-15 10:31:20 +0100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2016-03-15 10:35:11 +0100
commit59ec4a16cee98e0103d008f5d49ea0236ac49bbd (patch)
treedc7be38090b148bd49043716b0916bfe1d4a41d6
parent5323d22ecdfcdde00865c9af9eb8e03a9d759762 (diff)
downloadslirp-59ec4a16cee98e0103d008f5d49ea0236ac49bbd.zip
slirp-59ec4a16cee98e0103d008f5d49ea0236ac49bbd.tar.gz
slirp-59ec4a16cee98e0103d008f5d49ea0236ac49bbd.tar.bz2
slirp: Factorizing tcpiphdr structure with an union
This patch factorizes the tcpiphdr structure to put the IPv4 fields in an union, for addition of version 6 in further patch. Using some macros, retrocompatibility of the existing code is assured. This patch also fixes the SLIRP_MSIZE and margin computation in various functions, and makes them compatible with the new tcpiphdr structure, whose size will be bigger than sizeof(struct tcphdr) + sizeof(struct ip) 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>
-rw-r--r--if.h4
-rw-r--r--mbuf.c4
-rw-r--r--slirp.c15
-rw-r--r--socket.c13
-rw-r--r--tcp_input.c33
-rw-r--r--tcp_output.c21
-rw-r--r--tcp_subr.c29
-rw-r--r--tcpip.h29
8 files changed, 105 insertions, 43 deletions
diff --git a/if.h b/if.h
index 6ee566d..44e4774 100644
--- a/if.h
+++ b/if.h
@@ -17,7 +17,7 @@
#define IF_MRU 1500
#define IF_COMP IF_AUTOCOMP /* Flags for compression */
-/* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
-#define IF_MAXLINKHDR (2 + 14 + 40)
+/* 2 for alignment, 14 for ethernet */
+#define IF_MAXLINKHDR (2 + ETH_HLEN)
#endif
diff --git a/mbuf.c b/mbuf.c
index bdda609..cfaa92c 100644
--- a/mbuf.c
+++ b/mbuf.c
@@ -22,9 +22,9 @@
/*
* Find a nice value for msize
- * XXX if_maxlinkhdr already in mtu
*/
-#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + offsetof(struct mbuf, m_dat) + 6)
+#define SLIRP_MSIZE \
+ (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + IF_MTU)
void m_init(Slirp *slirp)
{
diff --git a/slirp.c b/slirp.c
index c5037e3..65b4a22 100644
--- a/slirp.c
+++ b/slirp.c
@@ -760,15 +760,16 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
m = m_get(slirp);
if (!m)
return;
- /* Note: we add to align the IP header */
- if (M_FREEROOM(m) < pkt_len + 2) {
- m_inc(m, pkt_len + 2);
+ /* Note: we add 2 to align the IP header on 4 bytes,
+ * and add the margin for the tcpiphdr overhead */
+ if (M_FREEROOM(m) < pkt_len + TCPIPHDR_DELTA + 2) {
+ m_inc(m, pkt_len + TCPIPHDR_DELTA + 2);
}
- m->m_len = pkt_len + 2;
- memcpy(m->m_data + 2, pkt, pkt_len);
+ m->m_len = pkt_len + TCPIPHDR_DELTA + 2;
+ memcpy(m->m_data + TCPIPHDR_DELTA + 2, pkt, pkt_len);
- m->m_data += 2 + ETH_HLEN;
- m->m_len -= 2 + ETH_HLEN;
+ m->m_data += TCPIPHDR_DELTA + 2 + ETH_HLEN;
+ m->m_len -= TCPIPHDR_DELTA + 2 + ETH_HLEN;
if (proto == ETH_P_IP) {
ip_input(m);
diff --git a/socket.c b/socket.c
index dcc2f05..48d8893 100644
--- a/socket.c
+++ b/socket.c
@@ -492,7 +492,18 @@ void sorecvfrom(struct socket *so)
if (!m) {
return;
}
- m->m_data += IF_MAXLINKHDR;
+ switch (so->so_ffamily) {
+ case AF_INET:
+ m->m_data += IF_MAXLINKHDR + sizeof(struct udpiphdr);
+ break;
+ case AF_INET6:
+ m->m_data +=
+ IF_MAXLINKHDR + sizeof(struct ip6) + sizeof(struct udphdr);
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
/*
* XXX Shouldn't FIONREAD packets destined for port 53,
diff --git a/tcp_input.c b/tcp_input.c
index 4ad3f8b..3b02559 100644
--- a/tcp_input.c
+++ b/tcp_input.c
@@ -256,11 +256,6 @@ void tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
}
slirp = m->slirp;
- /*
- * Get IP and TCP header together in first mbuf.
- * Note: IP leaves IP header in first mbuf.
- */
- ti = mtod(m, struct tcpiphdr *);
if (iphlen > sizeof(struct ip)) {
ip_stripoptions(m, (struct mbuf *)0);
iphlen = sizeof(struct ip);
@@ -277,14 +272,28 @@ void tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
save_ip.ip_len += iphlen;
/*
+ * 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 ip) - sizeof(struct tcphdr);
+ m->m_len +=
+ sizeof(struct tcpiphdr) - sizeof(struct ip) - sizeof(struct tcphdr);
+ ti = mtod(m, struct tcpiphdr *);
+
+ /*
* Checksum extended TCP header and data.
*/
- tlen = ((struct ip *)ti)->ip_len;
+ tlen = ip->ip_len;
tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
- memset(&ti->ti_i.ih_mbuf, 0, sizeof(struct mbuf_ptr));
- ti->ti_x1 = 0;
+ memset(&ti->ih_mbuf, 0, sizeof(struct mbuf_ptr));
+ memset(&ti->ti, 0, sizeof(ti->ti));
+ ti->ti_x0 = 0;
+ ti->ti_src = save_ip.ip_src;
+ ti->ti_dst = save_ip.ip_dst;
+ ti->ti_pr = save_ip.ip_p;
ti->ti_len = htons((uint16_t)tlen);
- len = sizeof(struct ip) + tlen;
+ len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
if (cksum(m, len)) {
goto drop;
}
@@ -602,6 +611,10 @@ findso:
sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr);
m->m_len +=
sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr);
+ m->m_data += sizeof(struct tcpiphdr) - sizeof(struct ip) -
+ sizeof(struct tcphdr);
+ m->m_len -= sizeof(struct tcpiphdr) - sizeof(struct ip) -
+ sizeof(struct tcphdr);
*ip = save_ip;
icmp_send_error(m, ICMP_UNREACH, code, 0, strerror(errno));
}
@@ -1457,7 +1470,7 @@ int tcp_mss(struct tcpcb *tp, u_int offer)
DEBUG_ARG("tp = %p", tp);
DEBUG_ARG("offer = %d", offer);
- mss = min(IF_MTU, IF_MRU) - sizeof(struct tcpiphdr);
+ mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr) + sizeof(struct ip);
if (offer)
mss = min(mss, offer);
mss = max(mss, 32);
diff --git a/tcp_output.c b/tcp_output.c
index cbe4fa6..808df35 100644
--- a/tcp_output.c
+++ b/tcp_output.c
@@ -444,14 +444,23 @@ send:
*/
m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */
- {
- ((struct ip *)ti)->ip_len = m->m_len;
+ struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
+ m->m_data +=
+ sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - sizeof(struct ip);
+ m->m_len -=
+ sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - sizeof(struct ip);
+ struct ip *ip = mtod(m, struct ip *);
- ((struct ip *)ti)->ip_ttl = IPDEFTTL;
- ((struct ip *)ti)->ip_tos = so->so_iptos;
+ ip->ip_len = m->m_len;
+ ip->ip_dst = tcpiph_save.ti_dst;
+ ip->ip_src = tcpiph_save.ti_src;
+ ip->ip_p = tcpiph_save.ti_pr;
+
+ ip->ip_ttl = IPDEFTTL;
+ ip->ip_tos = so->so_iptos;
+
+ error = ip_output(so, m);
- error = ip_output(so, m);
- }
if (error) {
out:
return (error);
diff --git a/tcp_subr.c b/tcp_subr.c
index 5d1d3be..8a4a6e7 100644
--- a/tcp_subr.c
+++ b/tcp_subr.c
@@ -74,9 +74,10 @@ void tcp_template(struct tcpcb *tp)
register struct tcpiphdr *n = &tp->t_template;
n->ti_mbuf = NULL;
- n->ti_x1 = 0;
+ memset(&n->ti, 0, sizeof(n->ti));
+ n->ti_x0 = 0;
n->ti_pr = IPPROTO_TCP;
- n->ti_len = htons(sizeof(struct tcpiphdr) - sizeof(struct ip));
+ 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;
@@ -128,6 +129,7 @@ void 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 {
/*
@@ -154,7 +156,7 @@ void tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
m->m_len = tlen;
ti->ti_mbuf = NULL;
- ti->ti_x1 = 0;
+ ti->ti_x0 = 0;
ti->ti_seq = htonl(seq);
ti->ti_ack = htonl(ack);
ti->ti_x2 = 0;
@@ -167,12 +169,23 @@ void 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;
+ struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
+ m->m_data +=
+ sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - sizeof(struct ip);
+ m->m_len -=
+ sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - sizeof(struct ip);
+ 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;
+ }
(void)ip_output((struct socket *)0, m);
}
diff --git a/tcpip.h b/tcpip.h
index 6c88289..edc4ed1 100644
--- a/tcpip.h
+++ b/tcpip.h
@@ -37,15 +37,23 @@
* Tcp+ip header, after ip options removed.
*/
struct tcpiphdr {
- struct ipovly ti_i; /* overlaid ip structure */
+ struct mbuf_ptr ih_mbuf; /* backpointer to mbuf */
+ union {
+ struct {
+ struct in_addr ih_src; /* source internet address */
+ struct in_addr ih_dst; /* destination internet address */
+ uint8_t ih_x1; /* (unused) */
+ uint8_t ih_pr; /* protocol */
+ } ti_i4;
+ } ti;
+ uint16_t ti_x0;
+ uint16_t ti_len; /* protocol length */
struct tcphdr ti_t; /* tcp header */
};
-#define ti_mbuf ti_i.ih_mbuf.mptr
-#define ti_x1 ti_i.ih_x1
-#define ti_pr ti_i.ih_pr
-#define ti_len ti_i.ih_len
-#define ti_src ti_i.ih_src
-#define ti_dst ti_i.ih_dst
+#define ti_mbuf ih_mbuf.mptr
+#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_sport ti_t.th_sport
#define ti_dport ti_t.th_dport
#define ti_seq ti_t.th_seq
@@ -67,6 +75,13 @@ struct tcpiphdr {
#define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink *)(T))
#define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr *)(T))
+/* This is the difference between the size of a tcpiphdr structure, and the
+ * size of actual ip+tcp headers, rounded up since we need to align data. */
+#define TCPIPHDR_DELTA \
+ (max(0, (sizeof(struct tcpiphdr) - sizeof(struct ip) - \
+ sizeof(struct tcphdr) + 3) & \
+ ~3))
+
/*
* Just a clean way to get to the first byte
* of the packet