xref: /netbsd-src/sys/dev/kttcp.c (revision b757af438b42b93f8c6571f026d8b8ef3eaf5fc9)
1 /*	$NetBSD: kttcp.c,v 1.30 2011/12/22 02:00:19 jakllsch Exp $	*/
2 
3 /*
4  * Copyright (c) 2002 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Frank van der Linden and Jason R. Thorpe for
8  * Wasabi Systems, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed for the NetBSD Project by
21  *	Wasabi Systems, Inc.
22  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
23  *    or promote products derived from this software without specific prior
24  *    written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * kttcp.c -- provides kernel support for testing network testing,
41  *            see kttcp(4)
42  */
43 
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: kttcp.c,v 1.30 2011/12/22 02:00:19 jakllsch Exp $");
46 
47 #include <sys/param.h>
48 #include <sys/types.h>
49 #include <sys/ioctl.h>
50 #include <sys/file.h>
51 #include <sys/filedesc.h>
52 #include <sys/conf.h>
53 #include <sys/systm.h>
54 #include <sys/protosw.h>
55 #include <sys/proc.h>
56 #include <sys/resourcevar.h>
57 #include <sys/signal.h>
58 #include <sys/socketvar.h>
59 #include <sys/socket.h>
60 #include <sys/mbuf.h>
61 #include <sys/mount.h>
62 #include <sys/syscallargs.h>
63 
64 #include <dev/kttcpio.h>
65 
66 static int kttcp_send(struct lwp *l, struct kttcp_io_args *);
67 static int kttcp_recv(struct lwp *l, struct kttcp_io_args *);
68 static int kttcp_sosend(struct socket *, unsigned long long,
69 			unsigned long long *, struct lwp *, int);
70 static int kttcp_soreceive(struct socket *, unsigned long long,
71 			   unsigned long long *, struct lwp *, int *);
72 
73 void	kttcpattach(int);
74 
75 dev_type_ioctl(kttcpioctl);
76 
77 const struct cdevsw kttcp_cdevsw = {
78 	nullopen, nullclose, noread, nowrite, kttcpioctl,
79 	nostop, notty, nopoll, nommap, nokqfilter, D_OTHER
80 };
81 
82 void
83 kttcpattach(int count)
84 {
85 	/* Do nothing. */
86 }
87 
88 int
89 kttcpioctl(dev_t dev, u_long cmd, void *data, int flag,
90     struct lwp *l)
91 {
92 	int error;
93 
94 	if ((flag & FWRITE) == 0)
95 		return EPERM;
96 
97 	switch (cmd) {
98 	case KTTCP_IO_SEND:
99 		error = kttcp_send(l, (struct kttcp_io_args *) data);
100 		break;
101 
102 	case KTTCP_IO_RECV:
103 		error = kttcp_recv(l, (struct kttcp_io_args *) data);
104 		break;
105 
106 	default:
107 		return EINVAL;
108 	}
109 
110 	return error;
111 }
112 
113 static int
114 kttcp_send(struct lwp *l, struct kttcp_io_args *kio)
115 {
116 	struct socket *so;
117 	int error;
118 	struct timeval t0, t1;
119 	unsigned long long len, done;
120 
121 	if (kio->kio_totalsize >= KTTCP_MAX_XMIT)
122 		return EINVAL;
123 
124 	if ((error = fd_getsock(kio->kio_socket, &so)) != 0)
125 		return error;
126 
127 	len = kio->kio_totalsize;
128 	microtime(&t0);
129 	do {
130 		error = kttcp_sosend(so, len, &done, l, 0);
131 		len -= done;
132 	} while (error == 0 && len > 0);
133 
134 	fd_putfile(kio->kio_socket);
135 
136 	microtime(&t1);
137 	if (error != 0)
138 		return error;
139 	timersub(&t1, &t0, &kio->kio_elapsed);
140 
141 	kio->kio_bytesdone = kio->kio_totalsize - len;
142 
143 	return 0;
144 }
145 
146 static int
147 kttcp_recv(struct lwp *l, struct kttcp_io_args *kio)
148 {
149 	struct socket *so;
150 	int error;
151 	struct timeval t0, t1;
152 	unsigned long long len, done;
153 
154 	done = 0;	/* XXX gcc */
155 
156 	if (kio->kio_totalsize > KTTCP_MAX_XMIT)
157 		return EINVAL;
158 
159 	if ((error = fd_getsock(kio->kio_socket, &so)) != 0)
160 		return error;
161 	len = kio->kio_totalsize;
162 	microtime(&t0);
163 	do {
164 		error = kttcp_soreceive(so, len, &done, l, NULL);
165 		len -= done;
166 	} while (error == 0 && len > 0 && done > 0);
167 
168 	fd_putfile(kio->kio_socket);
169 
170 	microtime(&t1);
171 	if (error == EPIPE)
172 		error = 0;
173 	if (error != 0)
174 		return error;
175 	timersub(&t1, &t0, &kio->kio_elapsed);
176 
177 	kio->kio_bytesdone = kio->kio_totalsize - len;
178 
179 	return 0;
180 }
181 
182 #define SBLOCKWAIT(f)   (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK)
183 
184 /*
185  * Slightly changed version of sosend()
186  */
187 static int
188 kttcp_sosend(struct socket *so, unsigned long long slen,
189 	     unsigned long long *done, struct lwp *l, int flags)
190 {
191 	struct mbuf **mp, *m, *top;
192 	long space, len, mlen;
193 	int error, dontroute, atomic;
194 	long long resid;
195 
196 	atomic = sosendallatonce(so);
197 	resid = slen;
198 	top = NULL;
199 	/*
200 	 * In theory resid should be unsigned.
201 	 * However, space must be signed, as it might be less than 0
202 	 * if we over-committed, and we must use a signed comparison
203 	 * of space and resid.  On the other hand, a negative resid
204 	 * causes us to loop sending 0-length segments to the protocol.
205 	 */
206 	if (resid < 0) {
207 		error = EINVAL;
208 		goto out;
209 	}
210 	dontroute =
211 	    (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
212 	    (so->so_proto->pr_flags & PR_ATOMIC);
213 	l->l_ru.ru_msgsnd++;
214 #define	snderr(errno)	{ error = errno; goto release; }
215 	solock(so);
216  restart:
217 	if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags))) != 0)
218 		goto out;
219 	do {
220 		if (so->so_state & SS_CANTSENDMORE)
221 			snderr(EPIPE);
222 		if (so->so_error) {
223 			error = so->so_error;
224 			so->so_error = 0;
225 			goto release;
226 		}
227 		if ((so->so_state & SS_ISCONNECTED) == 0) {
228 			if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
229 				if ((so->so_state & SS_ISCONFIRMING) == 0)
230 					snderr(ENOTCONN);
231 			} else
232 				snderr(EDESTADDRREQ);
233 		}
234 		space = sbspace(&so->so_snd);
235 		if (flags & MSG_OOB)
236 			space += 1024;
237 		if ((atomic && resid > so->so_snd.sb_hiwat))
238 			snderr(EMSGSIZE);
239 		if (space < resid && (atomic || space < so->so_snd.sb_lowat)) {
240 			if (so->so_state & SS_NBIO)
241 				snderr(EWOULDBLOCK);
242 			SBLASTRECORDCHK(&so->so_rcv,
243 			    "kttcp_soreceive sbwait 1");
244 			SBLASTMBUFCHK(&so->so_rcv,
245 			    "kttcp_soreceive sbwait 1");
246 			sbunlock(&so->so_snd);
247 			error = sbwait(&so->so_snd);
248 			if (error)
249 				goto out;
250 			goto restart;
251 		}
252 		mp = &top;
253 		do {
254 			sounlock(so);
255 			do {
256 				if (top == 0) {
257 					m = m_gethdr(M_WAIT, MT_DATA);
258 					mlen = MHLEN;
259 					m->m_pkthdr.len = 0;
260 					m->m_pkthdr.rcvif = NULL;
261 				} else {
262 					m = m_get(M_WAIT, MT_DATA);
263 					mlen = MLEN;
264 				}
265 				if (resid >= MINCLSIZE && space >= MCLBYTES) {
266 					m_clget(m, M_WAIT);
267 					if ((m->m_flags & M_EXT) == 0)
268 						goto nopages;
269 					mlen = MCLBYTES;
270 #ifdef	MAPPED_MBUFS
271 					len = lmin(MCLBYTES, resid);
272 #else
273 					if (atomic && top == 0) {
274 						len = lmin(MCLBYTES - max_hdr,
275 						    resid);
276 						m->m_data += max_hdr;
277 					} else
278 						len = lmin(MCLBYTES, resid);
279 #endif
280 					space -= len;
281 				} else {
282 nopages:
283 					len = lmin(lmin(mlen, resid), space);
284 					space -= len;
285 					/*
286 					 * For datagram protocols, leave room
287 					 * for protocol headers in first mbuf.
288 					 */
289 					if (atomic && top == 0 && len < mlen)
290 						MH_ALIGN(m, len);
291 				}
292 				resid -= len;
293 				m->m_len = len;
294 				*mp = m;
295 				top->m_pkthdr.len += len;
296 				if (error)
297 					goto release;
298 				mp = &m->m_next;
299 				if (resid <= 0) {
300 					if (flags & MSG_EOR)
301 						top->m_flags |= M_EOR;
302 					break;
303 				}
304 			} while (space > 0 && atomic);
305 			solock(so);
306 
307 			if (so->so_state & SS_CANTSENDMORE)
308 				snderr(EPIPE);
309 			if (dontroute)
310 				so->so_options |= SO_DONTROUTE;
311 			if (resid > 0)
312 				so->so_state |= SS_MORETOCOME;
313 			error = (*so->so_proto->pr_usrreq)(so,
314 			    (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
315 			    top, NULL, NULL, l);
316 			if (dontroute)
317 				so->so_options &= ~SO_DONTROUTE;
318 			if (resid > 0)
319 				so->so_state &= ~SS_MORETOCOME;
320 			top = 0;
321 			mp = &top;
322 			if (error)
323 				goto release;
324 		} while (resid && space > 0);
325 	} while (resid);
326 
327  release:
328 	sbunlock(&so->so_snd);
329  out:
330  	sounlock(so);
331 	if (top)
332 		m_freem(top);
333 	*done = slen - resid;
334 #if 0
335 	printf("sosend: error %d slen %llu resid %lld\n", error, slen, resid);
336 #endif
337 	return (error);
338 }
339 
340 static int
341 kttcp_soreceive(struct socket *so, unsigned long long slen,
342     unsigned long long *done, struct lwp *l, int *flagsp)
343 {
344 	struct mbuf *m, **mp;
345 	int flags, len, error, offset, moff, type;
346 	long long orig_resid, resid;
347 	const struct protosw *pr;
348 	struct mbuf *nextrecord;
349 
350 	pr = so->so_proto;
351 	mp = NULL;
352 	type = 0;
353 	resid = orig_resid = slen;
354 	if (flagsp)
355 		flags = *flagsp &~ MSG_EOR;
356 	else
357  		flags = 0;
358 	if (flags & MSG_OOB) {
359 		m = m_get(M_WAIT, MT_DATA);
360 		solock(so);
361 		error = (*pr->pr_usrreq)(so, PRU_RCVOOB, m,
362 		    (struct mbuf *)(long)(flags & MSG_PEEK), NULL, NULL);
363 		sounlock(so);
364 		if (error)
365 			goto bad;
366 		do {
367 			resid -= min(resid, m->m_len);
368 			m = m_free(m);
369 		} while (resid && error == 0 && m);
370  bad:
371 		if (m)
372 			m_freem(m);
373 		return (error);
374 	}
375 	if (mp)
376 		*mp = NULL;
377 	solock(so);
378 	if (so->so_state & SS_ISCONFIRMING && resid)
379 		(*pr->pr_usrreq)(so, PRU_RCVD, NULL, NULL, NULL, NULL);
380  restart:
381 	if ((error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) != 0)
382 		return (error);
383 	m = so->so_rcv.sb_mb;
384 	/*
385 	 * If we have less data than requested, block awaiting more
386 	 * (subject to any timeout) if:
387 	 *   1. the current count is less than the low water mark,
388 	 *   2. MSG_WAITALL is set, and it is possible to do the entire
389 	 *	receive operation at once if we block (resid <= hiwat), or
390 	 *   3. MSG_DONTWAIT is not set.
391 	 * If MSG_WAITALL is set but resid is larger than the receive buffer,
392 	 * we have to do the receive in sections, and thus risk returning
393 	 * a short count if a timeout or signal occurs after we start.
394 	 */
395 	if (m == NULL || (((flags & MSG_DONTWAIT) == 0 &&
396 	    so->so_rcv.sb_cc < resid) &&
397 	    (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
398 	    ((flags & MSG_WAITALL) && resid <= so->so_rcv.sb_hiwat)) &&
399 	    m->m_nextpkt == NULL && (pr->pr_flags & PR_ATOMIC) == 0)) {
400 #ifdef DIAGNOSTIC
401 		if (m == NULL && so->so_rcv.sb_cc)
402 			panic("receive 1");
403 #endif
404 		if (so->so_error) {
405 			if (m)
406 				goto dontblock;
407 			error = so->so_error;
408 			if ((flags & MSG_PEEK) == 0)
409 				so->so_error = 0;
410 			goto release;
411 		}
412 		if (so->so_state & SS_CANTRCVMORE) {
413 			if (m)
414 				goto dontblock;
415 			else
416 				goto release;
417 		}
418 		for (; m; m = m->m_next)
419 			if (m->m_type == MT_OOBDATA  || (m->m_flags & M_EOR)) {
420 				m = so->so_rcv.sb_mb;
421 				goto dontblock;
422 			}
423 		if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
424 		    (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
425 			error = ENOTCONN;
426 			goto release;
427 		}
428 		if (resid == 0)
429 			goto release;
430 		if ((so->so_state & SS_NBIO) ||
431 		    (flags & (MSG_DONTWAIT|MSG_NBIO))) {
432 			error = EWOULDBLOCK;
433 			goto release;
434 		}
435 		sbunlock(&so->so_rcv);
436 		error = sbwait(&so->so_rcv);
437 		if (error) {
438 			sounlock(so);
439 			return (error);
440 		}
441 		goto restart;
442 	}
443  dontblock:
444 	/*
445 	 * On entry here, m points to the first record of the socket buffer.
446 	 * While we process the initial mbufs containing address and control
447 	 * info, we save a copy of m->m_nextpkt into nextrecord.
448 	 */
449 #ifdef notyet /* XXXX */
450 	if (uio->uio_lwp)
451 		uio->uio_lwp->l_ru.ru_msgrcv++;
452 #endif
453 	KASSERT(m == so->so_rcv.sb_mb);
454 	SBLASTRECORDCHK(&so->so_rcv, "kttcp_soreceive 1");
455 	SBLASTMBUFCHK(&so->so_rcv, "kttcp_soreceive 1");
456 	nextrecord = m->m_nextpkt;
457 	if (pr->pr_flags & PR_ADDR) {
458 #ifdef DIAGNOSTIC
459 		if (m->m_type != MT_SONAME)
460 			panic("receive 1a");
461 #endif
462 		orig_resid = 0;
463 		if (flags & MSG_PEEK) {
464 			m = m->m_next;
465 		} else {
466 			sbfree(&so->so_rcv, m);
467 			MFREE(m, so->so_rcv.sb_mb);
468 			m = so->so_rcv.sb_mb;
469 		}
470 	}
471 	while (m && m->m_type == MT_CONTROL && error == 0) {
472 		if (flags & MSG_PEEK) {
473 			m = m->m_next;
474 		} else {
475 			sbfree(&so->so_rcv, m);
476 			MFREE(m, so->so_rcv.sb_mb);
477 			m = so->so_rcv.sb_mb;
478 		}
479 	}
480 
481 	/*
482 	 * If m is non-NULL, we have some data to read.  From now on,
483 	 * make sure to keep sb_lastrecord consistent when working on
484 	 * the last packet on the chain (nextrecord == NULL) and we
485 	 * change m->m_nextpkt.
486 	 */
487 	if (m) {
488 		if ((flags & MSG_PEEK) == 0) {
489 			m->m_nextpkt = nextrecord;
490 			/*
491 			 * If nextrecord == NULL (this is a single chain),
492 			 * then sb_lastrecord may not be valid here if m
493 			 * was changed earlier.
494 			 */
495 			if (nextrecord == NULL) {
496 				KASSERT(so->so_rcv.sb_mb == m);
497 				so->so_rcv.sb_lastrecord = m;
498 			}
499 		}
500 		type = m->m_type;
501 		if (type == MT_OOBDATA)
502 			flags |= MSG_OOB;
503 	} else {
504 		if ((flags & MSG_PEEK) == 0) {
505 			KASSERT(so->so_rcv.sb_mb == m);
506 			so->so_rcv.sb_mb = nextrecord;
507 			SB_EMPTY_FIXUP(&so->so_rcv);
508 		}
509 	}
510 	SBLASTRECORDCHK(&so->so_rcv, "kttcp_soreceive 2");
511 	SBLASTMBUFCHK(&so->so_rcv, "kttcp_soreceive 2");
512 
513 	moff = 0;
514 	offset = 0;
515 	while (m && resid > 0 && error == 0) {
516 		if (m->m_type == MT_OOBDATA) {
517 			if (type != MT_OOBDATA)
518 				break;
519 		} else if (type == MT_OOBDATA)
520 			break;
521 #ifdef DIAGNOSTIC
522 		else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
523 			panic("receive 3");
524 #endif
525 		so->so_state &= ~SS_RCVATMARK;
526 		len = resid;
527 		if (so->so_oobmark && len > so->so_oobmark - offset)
528 			len = so->so_oobmark - offset;
529 		if (len > m->m_len - moff)
530 			len = m->m_len - moff;
531 		/*
532 		 * If mp is set, just pass back the mbufs.
533 		 * Otherwise copy them out via the uio, then free.
534 		 * Sockbuf must be consistent here (points to current mbuf,
535 		 * it points to next record) when we drop priority;
536 		 * we must note any additions to the sockbuf when we
537 		 * block interrupts again.
538 		 */
539 		resid -= len;
540 		if (len == m->m_len - moff) {
541 			if (m->m_flags & M_EOR)
542 				flags |= MSG_EOR;
543 			if (flags & MSG_PEEK) {
544 				m = m->m_next;
545 				moff = 0;
546 			} else {
547 				nextrecord = m->m_nextpkt;
548 				sbfree(&so->so_rcv, m);
549 				if (mp) {
550 					*mp = m;
551 					mp = &m->m_next;
552 					so->so_rcv.sb_mb = m = m->m_next;
553 					*mp = NULL;
554 				} else {
555 					MFREE(m, so->so_rcv.sb_mb);
556 					m = so->so_rcv.sb_mb;
557 				}
558 				/*
559 				 * If m != NULL, we also know that
560 				 * so->so_rcv.sb_mb != NULL.
561 				 */
562 				KASSERT(so->so_rcv.sb_mb == m);
563 				if (m) {
564 					m->m_nextpkt = nextrecord;
565 					if (nextrecord == NULL)
566 						so->so_rcv.sb_lastrecord = m;
567 				} else {
568 					so->so_rcv.sb_mb = nextrecord;
569 					SB_EMPTY_FIXUP(&so->so_rcv);
570 				}
571 				SBLASTRECORDCHK(&so->so_rcv,
572 				    "kttcp_soreceive 3");
573 				SBLASTMBUFCHK(&so->so_rcv,
574 				    "kttcp_soreceive 3");
575 			}
576 		} else {
577 			if (flags & MSG_PEEK)
578 				moff += len;
579 			else {
580 				if (mp) {
581 					sounlock(so);
582 					*mp = m_copym(m, 0, len, M_WAIT);
583 					solock(so);
584 				}
585 				m->m_data += len;
586 				m->m_len -= len;
587 				so->so_rcv.sb_cc -= len;
588 			}
589 		}
590 		if (so->so_oobmark) {
591 			if ((flags & MSG_PEEK) == 0) {
592 				so->so_oobmark -= len;
593 				if (so->so_oobmark == 0) {
594 					so->so_state |= SS_RCVATMARK;
595 					break;
596 				}
597 			} else {
598 				offset += len;
599 				if (offset == so->so_oobmark)
600 					break;
601 			}
602 		}
603 		if (flags & MSG_EOR)
604 			break;
605 		/*
606 		 * If the MSG_WAITALL flag is set (for non-atomic socket),
607 		 * we must not quit until "uio->uio_resid == 0" or an error
608 		 * termination.  If a signal/timeout occurs, return
609 		 * with a short count but without error.
610 		 * Keep sockbuf locked against other readers.
611 		 */
612 		while (flags & MSG_WAITALL && m == NULL && resid > 0 &&
613 		    !sosendallatonce(so) && !nextrecord) {
614 			if (so->so_error || so->so_state & SS_CANTRCVMORE)
615 				break;
616 			/*
617 			 * If we are peeking and the socket receive buffer is
618 			 * full, stop since we can't get more data to peek at.
619 			 */
620 			if ((flags & MSG_PEEK) && sbspace(&so->so_rcv) <= 0)
621 				break;
622 			/*
623 			 * If we've drained the socket buffer, tell the
624 			 * protocol in case it needs to do something to
625 			 * get it filled again.
626 			 */
627 			if ((pr->pr_flags & PR_WANTRCVD) && so->so_pcb)
628 				(*pr->pr_usrreq)(so, PRU_RCVD, NULL,
629 				    (struct mbuf *)(long)flags, NULL, NULL);
630 			SBLASTRECORDCHK(&so->so_rcv,
631 			    "kttcp_soreceive sbwait 2");
632 			SBLASTMBUFCHK(&so->so_rcv,
633 			    "kttcp_soreceive sbwait 2");
634 			error = sbwait(&so->so_rcv);
635 			if (error) {
636 				sbunlock(&so->so_rcv);
637 				sounlock(so);
638 				return (0);
639 			}
640 			if ((m = so->so_rcv.sb_mb) != NULL)
641 				nextrecord = m->m_nextpkt;
642 		}
643 	}
644 
645 	if (m && pr->pr_flags & PR_ATOMIC) {
646 		flags |= MSG_TRUNC;
647 		if ((flags & MSG_PEEK) == 0)
648 			(void) sbdroprecord(&so->so_rcv);
649 	}
650 	if ((flags & MSG_PEEK) == 0) {
651 		if (m == NULL) {
652 			/*
653 			 * First part is an SB_EMPTY_FIXUP().  Second part
654 			 * makes sure sb_lastrecord is up-to-date if
655 			 * there is still data in the socket buffer.
656 			 */
657 			so->so_rcv.sb_mb = nextrecord;
658 			if (so->so_rcv.sb_mb == NULL) {
659 				so->so_rcv.sb_mbtail = NULL;
660 				so->so_rcv.sb_lastrecord = NULL;
661 			} else if (nextrecord->m_nextpkt == NULL)
662 				so->so_rcv.sb_lastrecord = nextrecord;
663 		}
664 		SBLASTRECORDCHK(&so->so_rcv, "kttcp_soreceive 4");
665 		SBLASTMBUFCHK(&so->so_rcv, "kttcp_soreceive 4");
666 		if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
667 			(*pr->pr_usrreq)(so, PRU_RCVD, NULL,
668 			    (struct mbuf *)(long)flags, NULL, NULL);
669 	}
670 	if (orig_resid == resid && orig_resid &&
671 	    (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {
672 		sbunlock(&so->so_rcv);
673 		goto restart;
674 	}
675 
676 	if (flagsp)
677 		*flagsp |= flags;
678  release:
679 	sbunlock(&so->so_rcv);
680 	sounlock(so);
681 	*done = slen - resid;
682 #if 0
683 	printf("soreceive: error %d slen %llu resid %lld\n", error, slen, resid);
684 #endif
685 	return (error);
686 }
687