xref: /netbsd-src/sys/dev/kttcp.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: kttcp.c,v 1.33 2014/05/18 14:46:15 rmind 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.33 2014/05/18 14:46:15 rmind 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 	.d_open = nullopen,
79 	.d_close = nullclose,
80 	.d_read = noread,
81 	.d_write = nowrite,
82 	.d_ioctl = kttcpioctl,
83 	.d_stop = nostop,
84 	.d_tty = notty,
85 	.d_poll = nopoll,
86 	.d_mmap = nommap,
87 	.d_kqfilter = nokqfilter,
88 	.d_flag = D_OTHER
89 };
90 
91 void
92 kttcpattach(int count)
93 {
94 	/* Do nothing. */
95 }
96 
97 int
98 kttcpioctl(dev_t dev, u_long cmd, void *data, int flag,
99     struct lwp *l)
100 {
101 	int error;
102 
103 	if ((flag & FWRITE) == 0)
104 		return EPERM;
105 
106 	switch (cmd) {
107 	case KTTCP_IO_SEND:
108 		error = kttcp_send(l, (struct kttcp_io_args *) data);
109 		break;
110 
111 	case KTTCP_IO_RECV:
112 		error = kttcp_recv(l, (struct kttcp_io_args *) data);
113 		break;
114 
115 	default:
116 		return EINVAL;
117 	}
118 
119 	return error;
120 }
121 
122 static int
123 kttcp_send(struct lwp *l, struct kttcp_io_args *kio)
124 {
125 	struct socket *so;
126 	int error;
127 	struct timeval t0, t1;
128 	unsigned long long len, done;
129 
130 	if (kio->kio_totalsize >= KTTCP_MAX_XMIT)
131 		return EINVAL;
132 
133 	if ((error = fd_getsock(kio->kio_socket, &so)) != 0)
134 		return error;
135 
136 	len = kio->kio_totalsize;
137 	microtime(&t0);
138 	do {
139 		error = kttcp_sosend(so, len, &done, l, 0);
140 		len -= done;
141 	} while (error == 0 && len > 0);
142 
143 	fd_putfile(kio->kio_socket);
144 
145 	microtime(&t1);
146 	if (error != 0)
147 		return error;
148 	timersub(&t1, &t0, &kio->kio_elapsed);
149 
150 	kio->kio_bytesdone = kio->kio_totalsize - len;
151 
152 	return 0;
153 }
154 
155 static int
156 kttcp_recv(struct lwp *l, struct kttcp_io_args *kio)
157 {
158 	struct socket *so;
159 	int error;
160 	struct timeval t0, t1;
161 	unsigned long long len, done;
162 
163 	done = 0;	/* XXX gcc */
164 
165 	if (kio->kio_totalsize > KTTCP_MAX_XMIT)
166 		return EINVAL;
167 
168 	if ((error = fd_getsock(kio->kio_socket, &so)) != 0)
169 		return error;
170 	len = kio->kio_totalsize;
171 	microtime(&t0);
172 	do {
173 		error = kttcp_soreceive(so, len, &done, l, NULL);
174 		len -= done;
175 	} while (error == 0 && len > 0 && done > 0);
176 
177 	fd_putfile(kio->kio_socket);
178 
179 	microtime(&t1);
180 	if (error == EPIPE)
181 		error = 0;
182 	if (error != 0)
183 		return error;
184 	timersub(&t1, &t0, &kio->kio_elapsed);
185 
186 	kio->kio_bytesdone = kio->kio_totalsize - len;
187 
188 	return 0;
189 }
190 
191 #define SBLOCKWAIT(f)   (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK)
192 
193 /*
194  * Slightly changed version of sosend()
195  */
196 static int
197 kttcp_sosend(struct socket *so, unsigned long long slen,
198 	     unsigned long long *done, struct lwp *l, int flags)
199 {
200 	struct mbuf **mp, *m, *top;
201 	long space, len, mlen;
202 	int error, dontroute, atomic;
203 	long long resid;
204 
205 	atomic = sosendallatonce(so);
206 	resid = slen;
207 	top = NULL;
208 	/*
209 	 * In theory resid should be unsigned.
210 	 * However, space must be signed, as it might be less than 0
211 	 * if we over-committed, and we must use a signed comparison
212 	 * of space and resid.  On the other hand, a negative resid
213 	 * causes us to loop sending 0-length segments to the protocol.
214 	 */
215 	if (resid < 0) {
216 		error = EINVAL;
217 		goto out;
218 	}
219 	dontroute =
220 	    (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
221 	    (so->so_proto->pr_flags & PR_ATOMIC);
222 	l->l_ru.ru_msgsnd++;
223 #define	snderr(errno)	{ error = errno; goto release; }
224 	solock(so);
225  restart:
226 	if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags))) != 0)
227 		goto out;
228 	do {
229 		if (so->so_state & SS_CANTSENDMORE)
230 			snderr(EPIPE);
231 		if (so->so_error) {
232 			error = so->so_error;
233 			so->so_error = 0;
234 			goto release;
235 		}
236 		if ((so->so_state & SS_ISCONNECTED) == 0) {
237 			if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
238 				snderr(ENOTCONN);
239 			} else {
240 				snderr(EDESTADDRREQ);
241 			}
242 		}
243 		space = sbspace(&so->so_snd);
244 		if (flags & MSG_OOB)
245 			space += 1024;
246 		if ((atomic && resid > so->so_snd.sb_hiwat))
247 			snderr(EMSGSIZE);
248 		if (space < resid && (atomic || space < so->so_snd.sb_lowat)) {
249 			if (so->so_state & SS_NBIO)
250 				snderr(EWOULDBLOCK);
251 			SBLASTRECORDCHK(&so->so_rcv,
252 			    "kttcp_soreceive sbwait 1");
253 			SBLASTMBUFCHK(&so->so_rcv,
254 			    "kttcp_soreceive sbwait 1");
255 			sbunlock(&so->so_snd);
256 			error = sbwait(&so->so_snd);
257 			if (error)
258 				goto out;
259 			goto restart;
260 		}
261 		mp = &top;
262 		do {
263 			sounlock(so);
264 			do {
265 				if (top == 0) {
266 					m = m_gethdr(M_WAIT, MT_DATA);
267 					mlen = MHLEN;
268 					m->m_pkthdr.len = 0;
269 					m->m_pkthdr.rcvif = NULL;
270 				} else {
271 					m = m_get(M_WAIT, MT_DATA);
272 					mlen = MLEN;
273 				}
274 				if (resid >= MINCLSIZE && space >= MCLBYTES) {
275 					m_clget(m, M_WAIT);
276 					if ((m->m_flags & M_EXT) == 0)
277 						goto nopages;
278 					mlen = MCLBYTES;
279 #ifdef	MAPPED_MBUFS
280 					len = lmin(MCLBYTES, resid);
281 #else
282 					if (atomic && top == 0) {
283 						len = lmin(MCLBYTES - max_hdr,
284 						    resid);
285 						m->m_data += max_hdr;
286 					} else
287 						len = lmin(MCLBYTES, resid);
288 #endif
289 					space -= len;
290 				} else {
291 nopages:
292 					len = lmin(lmin(mlen, resid), space);
293 					space -= len;
294 					/*
295 					 * For datagram protocols, leave room
296 					 * for protocol headers in first mbuf.
297 					 */
298 					if (atomic && top == 0 && len < mlen)
299 						MH_ALIGN(m, len);
300 				}
301 				resid -= len;
302 				m->m_len = len;
303 				*mp = m;
304 				top->m_pkthdr.len += len;
305 				if (error)
306 					goto release;
307 				mp = &m->m_next;
308 				if (resid <= 0) {
309 					if (flags & MSG_EOR)
310 						top->m_flags |= M_EOR;
311 					break;
312 				}
313 			} while (space > 0 && atomic);
314 			solock(so);
315 
316 			if (so->so_state & SS_CANTSENDMORE)
317 				snderr(EPIPE);
318 			if (dontroute)
319 				so->so_options |= SO_DONTROUTE;
320 			if (resid > 0)
321 				so->so_state |= SS_MORETOCOME;
322 			error = (*so->so_proto->pr_usrreqs->pr_generic)(so,
323 			    (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
324 			    top, NULL, NULL, l);
325 			if (dontroute)
326 				so->so_options &= ~SO_DONTROUTE;
327 			if (resid > 0)
328 				so->so_state &= ~SS_MORETOCOME;
329 			top = 0;
330 			mp = &top;
331 			if (error)
332 				goto release;
333 		} while (resid && space > 0);
334 	} while (resid);
335 
336  release:
337 	sbunlock(&so->so_snd);
338  out:
339  	sounlock(so);
340 	if (top)
341 		m_freem(top);
342 	*done = slen - resid;
343 #if 0
344 	printf("sosend: error %d slen %llu resid %lld\n", error, slen, resid);
345 #endif
346 	return (error);
347 }
348 
349 static int
350 kttcp_soreceive(struct socket *so, unsigned long long slen,
351     unsigned long long *done, struct lwp *l, int *flagsp)
352 {
353 	struct mbuf *m, **mp;
354 	int flags, len, error, offset, moff, type;
355 	long long orig_resid, resid;
356 	const struct protosw *pr;
357 	struct mbuf *nextrecord;
358 
359 	pr = so->so_proto;
360 	mp = NULL;
361 	type = 0;
362 	resid = orig_resid = slen;
363 	if (flagsp)
364 		flags = *flagsp &~ MSG_EOR;
365 	else
366  		flags = 0;
367 	if (flags & MSG_OOB) {
368 		m = m_get(M_WAIT, MT_DATA);
369 		solock(so);
370 		error = (*pr->pr_usrreqs->pr_generic)(so, PRU_RCVOOB, m,
371 		    (struct mbuf *)(long)(flags & MSG_PEEK), NULL, NULL);
372 		sounlock(so);
373 		if (error)
374 			goto bad;
375 		do {
376 			resid -= min(resid, m->m_len);
377 			m = m_free(m);
378 		} while (resid && error == 0 && m);
379  bad:
380 		if (m)
381 			m_freem(m);
382 		return (error);
383 	}
384 	if (mp)
385 		*mp = NULL;
386 	solock(so);
387  restart:
388 	if ((error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) != 0)
389 		return (error);
390 	m = so->so_rcv.sb_mb;
391 	/*
392 	 * If we have less data than requested, block awaiting more
393 	 * (subject to any timeout) if:
394 	 *   1. the current count is less than the low water mark,
395 	 *   2. MSG_WAITALL is set, and it is possible to do the entire
396 	 *	receive operation at once if we block (resid <= hiwat), or
397 	 *   3. MSG_DONTWAIT is not set.
398 	 * If MSG_WAITALL is set but resid is larger than the receive buffer,
399 	 * we have to do the receive in sections, and thus risk returning
400 	 * a short count if a timeout or signal occurs after we start.
401 	 */
402 	if (m == NULL || (((flags & MSG_DONTWAIT) == 0 &&
403 	    so->so_rcv.sb_cc < resid) &&
404 	    (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
405 	    ((flags & MSG_WAITALL) && resid <= so->so_rcv.sb_hiwat)) &&
406 	    m->m_nextpkt == NULL && (pr->pr_flags & PR_ATOMIC) == 0)) {
407 #ifdef DIAGNOSTIC
408 		if (m == NULL && so->so_rcv.sb_cc)
409 			panic("receive 1");
410 #endif
411 		if (so->so_error) {
412 			if (m)
413 				goto dontblock;
414 			error = so->so_error;
415 			if ((flags & MSG_PEEK) == 0)
416 				so->so_error = 0;
417 			goto release;
418 		}
419 		if (so->so_state & SS_CANTRCVMORE) {
420 			if (m)
421 				goto dontblock;
422 			else
423 				goto release;
424 		}
425 		for (; m; m = m->m_next)
426 			if (m->m_type == MT_OOBDATA  || (m->m_flags & M_EOR)) {
427 				m = so->so_rcv.sb_mb;
428 				goto dontblock;
429 			}
430 		if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
431 		    (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
432 			error = ENOTCONN;
433 			goto release;
434 		}
435 		if (resid == 0)
436 			goto release;
437 		if ((so->so_state & SS_NBIO) ||
438 		    (flags & (MSG_DONTWAIT|MSG_NBIO))) {
439 			error = EWOULDBLOCK;
440 			goto release;
441 		}
442 		sbunlock(&so->so_rcv);
443 		error = sbwait(&so->so_rcv);
444 		if (error) {
445 			sounlock(so);
446 			return (error);
447 		}
448 		goto restart;
449 	}
450  dontblock:
451 	/*
452 	 * On entry here, m points to the first record of the socket buffer.
453 	 * While we process the initial mbufs containing address and control
454 	 * info, we save a copy of m->m_nextpkt into nextrecord.
455 	 */
456 #ifdef notyet /* XXXX */
457 	if (uio->uio_lwp)
458 		uio->uio_lwp->l_ru.ru_msgrcv++;
459 #endif
460 	KASSERT(m == so->so_rcv.sb_mb);
461 	SBLASTRECORDCHK(&so->so_rcv, "kttcp_soreceive 1");
462 	SBLASTMBUFCHK(&so->so_rcv, "kttcp_soreceive 1");
463 	nextrecord = m->m_nextpkt;
464 	if (pr->pr_flags & PR_ADDR) {
465 #ifdef DIAGNOSTIC
466 		if (m->m_type != MT_SONAME)
467 			panic("receive 1a");
468 #endif
469 		orig_resid = 0;
470 		if (flags & MSG_PEEK) {
471 			m = m->m_next;
472 		} else {
473 			sbfree(&so->so_rcv, m);
474 			MFREE(m, so->so_rcv.sb_mb);
475 			m = so->so_rcv.sb_mb;
476 		}
477 	}
478 	while (m && m->m_type == MT_CONTROL && error == 0) {
479 		if (flags & MSG_PEEK) {
480 			m = m->m_next;
481 		} else {
482 			sbfree(&so->so_rcv, m);
483 			MFREE(m, so->so_rcv.sb_mb);
484 			m = so->so_rcv.sb_mb;
485 		}
486 	}
487 
488 	/*
489 	 * If m is non-NULL, we have some data to read.  From now on,
490 	 * make sure to keep sb_lastrecord consistent when working on
491 	 * the last packet on the chain (nextrecord == NULL) and we
492 	 * change m->m_nextpkt.
493 	 */
494 	if (m) {
495 		if ((flags & MSG_PEEK) == 0) {
496 			m->m_nextpkt = nextrecord;
497 			/*
498 			 * If nextrecord == NULL (this is a single chain),
499 			 * then sb_lastrecord may not be valid here if m
500 			 * was changed earlier.
501 			 */
502 			if (nextrecord == NULL) {
503 				KASSERT(so->so_rcv.sb_mb == m);
504 				so->so_rcv.sb_lastrecord = m;
505 			}
506 		}
507 		type = m->m_type;
508 		if (type == MT_OOBDATA)
509 			flags |= MSG_OOB;
510 	} else {
511 		if ((flags & MSG_PEEK) == 0) {
512 			KASSERT(so->so_rcv.sb_mb == m);
513 			so->so_rcv.sb_mb = nextrecord;
514 			SB_EMPTY_FIXUP(&so->so_rcv);
515 		}
516 	}
517 	SBLASTRECORDCHK(&so->so_rcv, "kttcp_soreceive 2");
518 	SBLASTMBUFCHK(&so->so_rcv, "kttcp_soreceive 2");
519 
520 	moff = 0;
521 	offset = 0;
522 	while (m && resid > 0 && error == 0) {
523 		if (m->m_type == MT_OOBDATA) {
524 			if (type != MT_OOBDATA)
525 				break;
526 		} else if (type == MT_OOBDATA)
527 			break;
528 #ifdef DIAGNOSTIC
529 		else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
530 			panic("receive 3");
531 #endif
532 		so->so_state &= ~SS_RCVATMARK;
533 		len = resid;
534 		if (so->so_oobmark && len > so->so_oobmark - offset)
535 			len = so->so_oobmark - offset;
536 		if (len > m->m_len - moff)
537 			len = m->m_len - moff;
538 		/*
539 		 * If mp is set, just pass back the mbufs.
540 		 * Otherwise copy them out via the uio, then free.
541 		 * Sockbuf must be consistent here (points to current mbuf,
542 		 * it points to next record) when we drop priority;
543 		 * we must note any additions to the sockbuf when we
544 		 * block interrupts again.
545 		 */
546 		resid -= len;
547 		if (len == m->m_len - moff) {
548 			if (m->m_flags & M_EOR)
549 				flags |= MSG_EOR;
550 			if (flags & MSG_PEEK) {
551 				m = m->m_next;
552 				moff = 0;
553 			} else {
554 				nextrecord = m->m_nextpkt;
555 				sbfree(&so->so_rcv, m);
556 				if (mp) {
557 					*mp = m;
558 					mp = &m->m_next;
559 					so->so_rcv.sb_mb = m = m->m_next;
560 					*mp = NULL;
561 				} else {
562 					MFREE(m, so->so_rcv.sb_mb);
563 					m = so->so_rcv.sb_mb;
564 				}
565 				/*
566 				 * If m != NULL, we also know that
567 				 * so->so_rcv.sb_mb != NULL.
568 				 */
569 				KASSERT(so->so_rcv.sb_mb == m);
570 				if (m) {
571 					m->m_nextpkt = nextrecord;
572 					if (nextrecord == NULL)
573 						so->so_rcv.sb_lastrecord = m;
574 				} else {
575 					so->so_rcv.sb_mb = nextrecord;
576 					SB_EMPTY_FIXUP(&so->so_rcv);
577 				}
578 				SBLASTRECORDCHK(&so->so_rcv,
579 				    "kttcp_soreceive 3");
580 				SBLASTMBUFCHK(&so->so_rcv,
581 				    "kttcp_soreceive 3");
582 			}
583 		} else {
584 			if (flags & MSG_PEEK)
585 				moff += len;
586 			else {
587 				if (mp) {
588 					sounlock(so);
589 					*mp = m_copym(m, 0, len, M_WAIT);
590 					solock(so);
591 				}
592 				m->m_data += len;
593 				m->m_len -= len;
594 				so->so_rcv.sb_cc -= len;
595 			}
596 		}
597 		if (so->so_oobmark) {
598 			if ((flags & MSG_PEEK) == 0) {
599 				so->so_oobmark -= len;
600 				if (so->so_oobmark == 0) {
601 					so->so_state |= SS_RCVATMARK;
602 					break;
603 				}
604 			} else {
605 				offset += len;
606 				if (offset == so->so_oobmark)
607 					break;
608 			}
609 		}
610 		if (flags & MSG_EOR)
611 			break;
612 		/*
613 		 * If the MSG_WAITALL flag is set (for non-atomic socket),
614 		 * we must not quit until "uio->uio_resid == 0" or an error
615 		 * termination.  If a signal/timeout occurs, return
616 		 * with a short count but without error.
617 		 * Keep sockbuf locked against other readers.
618 		 */
619 		while (flags & MSG_WAITALL && m == NULL && resid > 0 &&
620 		    !sosendallatonce(so) && !nextrecord) {
621 			if (so->so_error || so->so_state & SS_CANTRCVMORE)
622 				break;
623 			/*
624 			 * If we are peeking and the socket receive buffer is
625 			 * full, stop since we can't get more data to peek at.
626 			 */
627 			if ((flags & MSG_PEEK) && sbspace(&so->so_rcv) <= 0)
628 				break;
629 			/*
630 			 * If we've drained the socket buffer, tell the
631 			 * protocol in case it needs to do something to
632 			 * get it filled again.
633 			 */
634 			if ((pr->pr_flags & PR_WANTRCVD) && so->so_pcb) {
635 				(*pr->pr_usrreqs->pr_generic)(so, PRU_RCVD, NULL,
636 				    (struct mbuf *)(long)flags, NULL, NULL);
637 			}
638 			SBLASTRECORDCHK(&so->so_rcv,
639 			    "kttcp_soreceive sbwait 2");
640 			SBLASTMBUFCHK(&so->so_rcv,
641 			    "kttcp_soreceive sbwait 2");
642 			error = sbwait(&so->so_rcv);
643 			if (error) {
644 				sbunlock(&so->so_rcv);
645 				sounlock(so);
646 				return (0);
647 			}
648 			if ((m = so->so_rcv.sb_mb) != NULL)
649 				nextrecord = m->m_nextpkt;
650 		}
651 	}
652 
653 	if (m && pr->pr_flags & PR_ATOMIC) {
654 		flags |= MSG_TRUNC;
655 		if ((flags & MSG_PEEK) == 0)
656 			(void) sbdroprecord(&so->so_rcv);
657 	}
658 	if ((flags & MSG_PEEK) == 0) {
659 		if (m == NULL) {
660 			/*
661 			 * First part is an SB_EMPTY_FIXUP().  Second part
662 			 * makes sure sb_lastrecord is up-to-date if
663 			 * there is still data in the socket buffer.
664 			 */
665 			so->so_rcv.sb_mb = nextrecord;
666 			if (so->so_rcv.sb_mb == NULL) {
667 				so->so_rcv.sb_mbtail = NULL;
668 				so->so_rcv.sb_lastrecord = NULL;
669 			} else if (nextrecord->m_nextpkt == NULL)
670 				so->so_rcv.sb_lastrecord = nextrecord;
671 		}
672 		SBLASTRECORDCHK(&so->so_rcv, "kttcp_soreceive 4");
673 		SBLASTMBUFCHK(&so->so_rcv, "kttcp_soreceive 4");
674 		if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) {
675 			(*pr->pr_usrreqs->pr_generic)(so, PRU_RCVD, NULL,
676 			    (struct mbuf *)(long)flags, NULL, NULL);
677 		}
678 	}
679 	if (orig_resid == resid && orig_resid &&
680 	    (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {
681 		sbunlock(&so->so_rcv);
682 		goto restart;
683 	}
684 
685 	if (flagsp)
686 		*flagsp |= flags;
687  release:
688 	sbunlock(&so->so_rcv);
689 	sounlock(so);
690 	*done = slen - resid;
691 #if 0
692 	printf("soreceive: error %d slen %llu resid %lld\n", error, slen, resid);
693 #endif
694 	return (error);
695 }
696