Hi, Apparently soreceive_stream() has an issue if it is called to receive data as a mbuf chain (by supplying an non zero mbuf **mp0) and with MSG_WAITALL set.
I ran into this issue with smbfs, which uses soreceive() exactly in this way (see netsmb/smb_trantcp.c:nbssn_recv()). If MSG_WAITALL is set and not all data is received it loops again but on the next run mb0 is set to sb->sb_mb again loosing all previously received mbufs. It looks like it should be set to the end of mb0 chain instead. See the attached path. Also, in the "copy the remainder" block we reduce uio_resid by m->m_len (the length of the last mbuf in the chain), but it looks like for the MSG_PEEK case the remainder may have more than one mbuf in the chain and we have to reduce by len (the length of the copied chain). I don't have a test case to check MSG_PEEK issue, but the patch fixes the issue with smbfs for me. -- Mikolaj Golub
Index: sys/kern/uipc_socket.c =================================================================== --- sys/kern/uipc_socket.c (revision 225368) +++ sys/kern/uipc_socket.c (working copy) @@ -2030,7 +2030,11 @@ deliver: if (mp0 != NULL) { /* Dequeue as many mbufs as possible. */ if (!(flags & MSG_PEEK) && len >= sb->sb_mb->m_len) { - for (*mp0 = m = sb->sb_mb; + if (*mp0 == NULL) + *mp0 = sb->sb_mb; + else + n->m_next = sb->sb_mb; + for (m = sb->sb_mb; m != NULL && m->m_len <= len; m = m->m_next) { len -= m->m_len; @@ -2052,7 +2056,7 @@ deliver: if (m == NULL) len = 0; /* Don't flush data from sockbuf. */ else - uio->uio_resid -= m->m_len; + uio->uio_resid -= len; if (*mp0 != NULL) n->m_next = m; else @@ -2061,6 +2065,9 @@ deliver: error = ENOBUFS; goto out; } + /* Update n to point to the last mbuf. */ + for (; m != NULL; m = m->m_next) + n = m; } } else { /* NB: Must unlock socket buffer as uiomove may sleep. */
_______________________________________________ freebsd-net@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-net To unsubscribe, send any mail to "freebsd-net-unsubscr...@freebsd.org"