aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/sfxge/sfxge_tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/sfxge/sfxge_tx.c')
-rw-r--r--sys/dev/sfxge/sfxge_tx.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/sys/dev/sfxge/sfxge_tx.c b/sys/dev/sfxge/sfxge_tx.c
index 988e119d0012..7a5480ba9ee5 100644
--- a/sys/dev/sfxge/sfxge_tx.c
+++ b/sys/dev/sfxge/sfxge_tx.c
@@ -865,6 +865,8 @@ static void tso_fini(struct sfxge_txq *txq)
static void tso_start(struct sfxge_tso_state *tso, struct mbuf *mbuf)
{
struct ether_header *eh = mtod(mbuf, struct ether_header *);
+ const struct tcphdr *th;
+ struct tcphdr th_copy;
tso->mbuf = mbuf;
@@ -892,13 +894,24 @@ static void tso_start(struct sfxge_tso_state *tso, struct mbuf *mbuf)
tso->tcph_off = tso->nh_off + sizeof(struct ip6_hdr);
}
- tso->header_len = tso->tcph_off + 4 * tso_tcph(tso)->th_off;
+ KASSERT(mbuf->m_len >= tso->tcph_off,
+ ("network header is fragmented in mbuf"));
+ /* We need TCP header including flags (window is the next) */
+ if (mbuf->m_len < tso->tcph_off + offsetof(struct tcphdr, th_win)) {
+ m_copydata(tso->mbuf, tso->tcph_off, sizeof(th_copy),
+ (caddr_t)&th_copy);
+ th = &th_copy;
+ } else {
+ th = tso_tcph(tso);
+ }
+
+ tso->header_len = tso->tcph_off + 4 * th->th_off;
tso->seg_size = mbuf->m_pkthdr.tso_segsz;
- tso->seqnum = ntohl(tso_tcph(tso)->th_seq);
+ tso->seqnum = ntohl(th->th_seq);
/* These flags must not be duplicated */
- KASSERT(!(tso_tcph(tso)->th_flags & (TH_URG | TH_SYN | TH_RST)),
+ KASSERT(!(th->th_flags & (TH_URG | TH_SYN | TH_RST)),
("incompatible TCP flag on TSO packet"));
tso->out_len = mbuf->m_pkthdr.len - tso->header_len;