--- When a previous call to sbsndptr() leaves sb->sb_sndptroff at the start of --- an mbuf that was fully consumed by the previous call, the mbuf ptr returned --- by the current call ends up being the previous mbuf in the sb chain to the --- one that contains the data we want. --- --- This does not cause any observable issues because the mbuf copy routines --- happily walk the mbuf chain to get to the data at the moff offset, which in --- this case means they effectively skip over the mbuf returned by sbsndptr(). --- --- We can't adjust sb->sb_sndptr during the previous call for this case because --- the next mbuf in the chain may not exist yet. We therefore need to detect --- the condition and make the adjustment during the current call. --- --- Fix by detecting the special case of moff being at the start of the next --- mbuf in the chain and adjust the required accounting variables accordingly. --- --- Reviewed by: andre --- MFC after: 1 week --- Index: sys/kern/uipc_sockbuf.c =================================================================== --- sys/kern/uipc_sockbuf.c (revision 247314) +++ sys/kern/uipc_sockbuf.c (working copy) @@ -932,20 +932,27 @@ sbsndptr(struct sockbuf *sb, u_int off, * Just return, we can't help here. */ if (sb->sb_sndptroff > off) { *moff = off; return (sb->sb_mb); } /* Return closest mbuf in chain for current offset. */ *moff = off - sb->sb_sndptroff; m = ret = sb->sb_sndptr ? sb->sb_sndptr : sb->sb_mb; + if (*moff == m->m_len) { + *moff = 0; + sb->sb_sndptroff += m->m_len; + m = ret = m->m_next; + KASSERT(ret->m_len > 0, + ("mbuf %p in sockbuf %p chain has no valid data", ret, sb)); + } /* Advance by len to be as close as possible for the next transmit. */ for (off = off - sb->sb_sndptroff + len - 1; off > 0 && m != NULL && off >= m->m_len; m = m->m_next) { sb->sb_sndptroff += m->m_len; off -= m->m_len; } if (off > 0 && m == NULL) panic("%s: sockbuf %p and mbuf %p clashing", __func__, sb, ret);