xref: /netbsd-src/external/bsd/tmux/dist/compat/imsg-buffer.c (revision f844e94ef29eebc7999c12636b87f541bb86868b)
1 /*	$OpenBSD: imsg-buffer.c,v 1.18 2023/12/12 15:47:41 claudio Exp $	*/
2 
3 /*
4  * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
5  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/uio.h>
23 #include <arpa/inet.h>
24 
25 #include <limits.h>
26 #include <errno.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 
32 #include "compat.h"
33 #include "imsg.h"
34 
35 #undef htobe16
36 #define htobe16 htons
37 #undef htobe32
38 #define htobe32 htonl
39 #undef htobe64
40 #define htobe64 htonll
41 #undef be16toh
42 #define be16toh ntohs
43 #undef be32toh
44 #define be32toh ntohl
45 #undef be64toh
46 #define be64toh ntohll
47 
48 static int	ibuf_realloc(struct ibuf *, size_t);
49 static void	ibuf_enqueue(struct msgbuf *, struct ibuf *);
50 static void	ibuf_dequeue(struct msgbuf *, struct ibuf *);
51 static void	msgbuf_drain(struct msgbuf *, size_t);
52 
53 struct ibuf *
ibuf_open(size_t len)54 ibuf_open(size_t len)
55 {
56 	struct ibuf	*buf;
57 
58 	if (len == 0) {
59 		errno = EINVAL;
60 		return (NULL);
61 	}
62 	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
63 		return (NULL);
64 	if ((buf->buf = calloc(len, 1)) == NULL) {
65 		free(buf);
66 		return (NULL);
67 	}
68 	buf->size = buf->max = len;
69 	buf->fd = -1;
70 
71 	return (buf);
72 }
73 
74 struct ibuf *
ibuf_dynamic(size_t len,size_t max)75 ibuf_dynamic(size_t len, size_t max)
76 {
77 	struct ibuf	*buf;
78 
79 	if (max == 0 || max < len) {
80 		errno = EINVAL;
81 		return (NULL);
82 	}
83 
84 	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
85 		return (NULL);
86 	if (len > 0) {
87 		if ((buf->buf = calloc(len, 1)) == NULL) {
88 			free(buf);
89 			return (NULL);
90 		}
91 	}
92 	buf->size = len;
93 	buf->max = max;
94 	buf->fd = -1;
95 
96 	return (buf);
97 }
98 
99 static int
ibuf_realloc(struct ibuf * buf,size_t len)100 ibuf_realloc(struct ibuf *buf, size_t len)
101 {
102 	unsigned char	*b;
103 
104 	/* on static buffers max is eq size and so the following fails */
105 	if (len > SIZE_MAX - buf->wpos || buf->wpos + len > buf->max) {
106 		errno = ERANGE;
107 		return (-1);
108 	}
109 
110 	b = recallocarray(buf->buf, buf->size, buf->wpos + len, 1);
111 	if (b == NULL)
112 		return (-1);
113 	buf->buf = b;
114 	buf->size = buf->wpos + len;
115 
116 	return (0);
117 }
118 
119 void *
ibuf_reserve(struct ibuf * buf,size_t len)120 ibuf_reserve(struct ibuf *buf, size_t len)
121 {
122 	void	*b;
123 
124 	if (len > SIZE_MAX - buf->wpos || buf->max == 0) {
125 		errno = ERANGE;
126 		return (NULL);
127 	}
128 
129 	if (buf->wpos + len > buf->size)
130 		if (ibuf_realloc(buf, len) == -1)
131 			return (NULL);
132 
133 	b = buf->buf + buf->wpos;
134 	buf->wpos += len;
135 	return (b);
136 }
137 
138 int
ibuf_add(struct ibuf * buf,const void * data,size_t len)139 ibuf_add(struct ibuf *buf, const void *data, size_t len)
140 {
141 	void *b;
142 
143 	if ((b = ibuf_reserve(buf, len)) == NULL)
144 		return (-1);
145 
146 	memcpy(b, data, len);
147 	return (0);
148 }
149 
150 int
ibuf_add_ibuf(struct ibuf * buf,const struct ibuf * from)151 ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from)
152 {
153 	return ibuf_add(buf, ibuf_data(from), ibuf_size(from));
154 }
155 
156 /* remove after tree is converted */
157 int
ibuf_add_buf(struct ibuf * buf,const struct ibuf * from)158 ibuf_add_buf(struct ibuf *buf, const struct ibuf *from)
159 {
160 	return ibuf_add_ibuf(buf, from);
161 }
162 
163 int
ibuf_add_n8(struct ibuf * buf,uint64_t value)164 ibuf_add_n8(struct ibuf *buf, uint64_t value)
165 {
166 	uint8_t v;
167 
168 	if (value > UINT8_MAX) {
169 		errno = EINVAL;
170 		return (-1);
171 	}
172 	v = value;
173 	return ibuf_add(buf, &v, sizeof(v));
174 }
175 
176 int
ibuf_add_n16(struct ibuf * buf,uint64_t value)177 ibuf_add_n16(struct ibuf *buf, uint64_t value)
178 {
179 	uint16_t v;
180 
181 	if (value > UINT16_MAX) {
182 		errno = EINVAL;
183 		return (-1);
184 	}
185 	v = htobe16(value);
186 	return ibuf_add(buf, &v, sizeof(v));
187 }
188 
189 int
ibuf_add_n32(struct ibuf * buf,uint64_t value)190 ibuf_add_n32(struct ibuf *buf, uint64_t value)
191 {
192 	uint32_t v;
193 
194 	if (value > UINT32_MAX) {
195 		errno = EINVAL;
196 		return (-1);
197 	}
198 	v = htobe32(value);
199 	return ibuf_add(buf, &v, sizeof(v));
200 }
201 
202 int
ibuf_add_n64(struct ibuf * buf,uint64_t value)203 ibuf_add_n64(struct ibuf *buf, uint64_t value)
204 {
205 	value = htobe64(value);
206 	return ibuf_add(buf, &value, sizeof(value));
207 }
208 
209 int
ibuf_add_h16(struct ibuf * buf,uint64_t value)210 ibuf_add_h16(struct ibuf *buf, uint64_t value)
211 {
212 	uint16_t v;
213 
214 	if (value > UINT16_MAX) {
215 		errno = EINVAL;
216 		return (-1);
217 	}
218 	v = value;
219 	return ibuf_add(buf, &v, sizeof(v));
220 }
221 
222 int
ibuf_add_h32(struct ibuf * buf,uint64_t value)223 ibuf_add_h32(struct ibuf *buf, uint64_t value)
224 {
225 	uint32_t v;
226 
227 	if (value > UINT32_MAX) {
228 		errno = EINVAL;
229 		return (-1);
230 	}
231 	v = value;
232 	return ibuf_add(buf, &v, sizeof(v));
233 }
234 
235 int
ibuf_add_h64(struct ibuf * buf,uint64_t value)236 ibuf_add_h64(struct ibuf *buf, uint64_t value)
237 {
238 	return ibuf_add(buf, &value, sizeof(value));
239 }
240 
241 int
ibuf_add_zero(struct ibuf * buf,size_t len)242 ibuf_add_zero(struct ibuf *buf, size_t len)
243 {
244 	void *b;
245 
246 	if ((b = ibuf_reserve(buf, len)) == NULL)
247 		return (-1);
248 	memset(b, 0, len);
249 	return (0);
250 }
251 
252 void *
ibuf_seek(struct ibuf * buf,size_t pos,size_t len)253 ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
254 {
255 	/* only allow seeking between rpos and wpos */
256 	if (ibuf_size(buf) < pos || SIZE_MAX - pos < len ||
257 	    ibuf_size(buf) < pos + len) {
258 		errno = ERANGE;
259 		return (NULL);
260 	}
261 
262 	return (buf->buf + buf->rpos + pos);
263 }
264 
265 int
ibuf_set(struct ibuf * buf,size_t pos,const void * data,size_t len)266 ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len)
267 {
268 	void *b;
269 
270 	if ((b = ibuf_seek(buf, pos, len)) == NULL)
271 		return (-1);
272 
273 	memcpy(b, data, len);
274 	return (0);
275 }
276 
277 int
ibuf_set_n8(struct ibuf * buf,size_t pos,uint64_t value)278 ibuf_set_n8(struct ibuf *buf, size_t pos, uint64_t value)
279 {
280 	uint8_t v;
281 
282 	if (value > UINT8_MAX) {
283 		errno = EINVAL;
284 		return (-1);
285 	}
286 	v = value;
287 	return (ibuf_set(buf, pos, &v, sizeof(v)));
288 }
289 
290 int
ibuf_set_n16(struct ibuf * buf,size_t pos,uint64_t value)291 ibuf_set_n16(struct ibuf *buf, size_t pos, uint64_t value)
292 {
293 	uint16_t v;
294 
295 	if (value > UINT16_MAX) {
296 		errno = EINVAL;
297 		return (-1);
298 	}
299 	v = htobe16(value);
300 	return (ibuf_set(buf, pos, &v, sizeof(v)));
301 }
302 
303 int
ibuf_set_n32(struct ibuf * buf,size_t pos,uint64_t value)304 ibuf_set_n32(struct ibuf *buf, size_t pos, uint64_t value)
305 {
306 	uint32_t v;
307 
308 	if (value > UINT32_MAX) {
309 		errno = EINVAL;
310 		return (-1);
311 	}
312 	v = htobe32(value);
313 	return (ibuf_set(buf, pos, &v, sizeof(v)));
314 }
315 
316 int
ibuf_set_n64(struct ibuf * buf,size_t pos,uint64_t value)317 ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value)
318 {
319 	value = htobe64(value);
320 	return (ibuf_set(buf, pos, &value, sizeof(value)));
321 }
322 
323 int
ibuf_set_h16(struct ibuf * buf,size_t pos,uint64_t value)324 ibuf_set_h16(struct ibuf *buf, size_t pos, uint64_t value)
325 {
326 	uint16_t v;
327 
328 	if (value > UINT16_MAX) {
329 		errno = EINVAL;
330 		return (-1);
331 	}
332 	v = value;
333 	return (ibuf_set(buf, pos, &v, sizeof(v)));
334 }
335 
336 int
ibuf_set_h32(struct ibuf * buf,size_t pos,uint64_t value)337 ibuf_set_h32(struct ibuf *buf, size_t pos, uint64_t value)
338 {
339 	uint32_t v;
340 
341 	if (value > UINT32_MAX) {
342 		errno = EINVAL;
343 		return (-1);
344 	}
345 	v = value;
346 	return (ibuf_set(buf, pos, &v, sizeof(v)));
347 }
348 
349 int
ibuf_set_h64(struct ibuf * buf,size_t pos,uint64_t value)350 ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value)
351 {
352 	return (ibuf_set(buf, pos, &value, sizeof(value)));
353 }
354 
355 void *
ibuf_data(const struct ibuf * buf)356 ibuf_data(const struct ibuf *buf)
357 {
358 	return (buf->buf + buf->rpos);
359 }
360 
361 size_t
ibuf_size(const struct ibuf * buf)362 ibuf_size(const struct ibuf *buf)
363 {
364 	return (buf->wpos - buf->rpos);
365 }
366 
367 size_t
ibuf_left(const struct ibuf * buf)368 ibuf_left(const struct ibuf *buf)
369 {
370 	if (buf->max == 0)
371 		return (0);
372 	return (buf->max - buf->wpos);
373 }
374 
375 int
ibuf_truncate(struct ibuf * buf,size_t len)376 ibuf_truncate(struct ibuf *buf, size_t len)
377 {
378 	if (ibuf_size(buf) >= len) {
379 		buf->wpos = buf->rpos + len;
380 		return (0);
381 	}
382 	if (buf->max == 0) {
383 		/* only allow to truncate down */
384 		errno = ERANGE;
385 		return (-1);
386 	}
387 	return ibuf_add_zero(buf, len - ibuf_size(buf));
388 }
389 
390 void
ibuf_rewind(struct ibuf * buf)391 ibuf_rewind(struct ibuf *buf)
392 {
393 	buf->rpos = 0;
394 }
395 
396 void
ibuf_close(struct msgbuf * msgbuf,struct ibuf * buf)397 ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
398 {
399 	ibuf_enqueue(msgbuf, buf);
400 }
401 
402 void
ibuf_from_buffer(struct ibuf * buf,void * data,size_t len)403 ibuf_from_buffer(struct ibuf *buf, void *data, size_t len)
404 {
405 	memset(buf, 0, sizeof(*buf));
406 	buf->buf = data;
407 	buf->size = buf->wpos = len;
408 	buf->fd = -1;
409 }
410 
411 void
ibuf_from_ibuf(struct ibuf * buf,const struct ibuf * from)412 ibuf_from_ibuf(struct ibuf *buf, const struct ibuf *from)
413 {
414 	ibuf_from_buffer(buf, ibuf_data(from), ibuf_size(from));
415 }
416 
417 int
ibuf_get(struct ibuf * buf,void * data,size_t len)418 ibuf_get(struct ibuf *buf, void *data, size_t len)
419 {
420 	if (ibuf_size(buf) < len) {
421 		errno = EBADMSG;
422 		return (-1);
423 	}
424 
425 	memcpy(data, ibuf_data(buf), len);
426 	buf->rpos += len;
427 	return (0);
428 }
429 
430 int
ibuf_get_ibuf(struct ibuf * buf,size_t len,struct ibuf * new)431 ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new)
432 {
433 	if (ibuf_size(buf) < len) {
434 		errno = EBADMSG;
435 		return (-1);
436 	}
437 
438 	ibuf_from_buffer(new, ibuf_data(buf), len);
439 	buf->rpos += len;
440 	return (0);
441 }
442 
443 int
ibuf_get_n8(struct ibuf * buf,uint8_t * value)444 ibuf_get_n8(struct ibuf *buf, uint8_t *value)
445 {
446 	return ibuf_get(buf, value, sizeof(*value));
447 }
448 
449 int
ibuf_get_n16(struct ibuf * buf,uint16_t * value)450 ibuf_get_n16(struct ibuf *buf, uint16_t *value)
451 {
452 	int rv;
453 
454 	rv = ibuf_get(buf, value, sizeof(*value));
455 	*value = be16toh(*value);
456 	return (rv);
457 }
458 
459 int
ibuf_get_n32(struct ibuf * buf,uint32_t * value)460 ibuf_get_n32(struct ibuf *buf, uint32_t *value)
461 {
462 	int rv;
463 
464 	rv = ibuf_get(buf, value, sizeof(*value));
465 	*value = be32toh(*value);
466 	return (rv);
467 }
468 
469 int
ibuf_get_n64(struct ibuf * buf,uint64_t * value)470 ibuf_get_n64(struct ibuf *buf, uint64_t *value)
471 {
472 	int rv;
473 
474 	rv = ibuf_get(buf, value, sizeof(*value));
475 	*value = be64toh(*value);
476 	return (rv);
477 }
478 
479 int
ibuf_get_h16(struct ibuf * buf,uint16_t * value)480 ibuf_get_h16(struct ibuf *buf, uint16_t *value)
481 {
482 	return ibuf_get(buf, value, sizeof(*value));
483 }
484 
485 int
ibuf_get_h32(struct ibuf * buf,uint32_t * value)486 ibuf_get_h32(struct ibuf *buf, uint32_t *value)
487 {
488 	return ibuf_get(buf, value, sizeof(*value));
489 }
490 
491 int
ibuf_get_h64(struct ibuf * buf,uint64_t * value)492 ibuf_get_h64(struct ibuf *buf, uint64_t *value)
493 {
494 	return ibuf_get(buf, value, sizeof(*value));
495 }
496 
497 int
ibuf_skip(struct ibuf * buf,size_t len)498 ibuf_skip(struct ibuf *buf, size_t len)
499 {
500 	if (ibuf_size(buf) < len) {
501 		errno = EBADMSG;
502 		return (-1);
503 	}
504 
505 	buf->rpos += len;
506 	return (0);
507 }
508 
509 void
ibuf_free(struct ibuf * buf)510 ibuf_free(struct ibuf *buf)
511 {
512 	if (buf == NULL)
513 		return;
514 	if (buf->max == 0)	/* if buf lives on the stack */
515 		abort();	/* abort before causing more harm */
516 	if (buf->fd != -1)
517 		close(buf->fd);
518 	freezero(buf->buf, buf->size);
519 	free(buf);
520 }
521 
522 int
ibuf_fd_avail(struct ibuf * buf)523 ibuf_fd_avail(struct ibuf *buf)
524 {
525 	return (buf->fd != -1);
526 }
527 
528 int
ibuf_fd_get(struct ibuf * buf)529 ibuf_fd_get(struct ibuf *buf)
530 {
531 	int fd;
532 
533 	fd = buf->fd;
534 	buf->fd = -1;
535 	return (fd);
536 }
537 
538 void
ibuf_fd_set(struct ibuf * buf,int fd)539 ibuf_fd_set(struct ibuf *buf, int fd)
540 {
541 	if (buf->max == 0)	/* if buf lives on the stack */
542 		abort();	/* abort before causing more harm */
543 	if (buf->fd != -1)
544 		close(buf->fd);
545 	buf->fd = fd;
546 }
547 
548 int
ibuf_write(struct msgbuf * msgbuf)549 ibuf_write(struct msgbuf *msgbuf)
550 {
551 	struct iovec	 iov[IOV_MAX];
552 	struct ibuf	*buf;
553 	unsigned int	 i = 0;
554 	ssize_t	n;
555 
556 	memset(&iov, 0, sizeof(iov));
557 	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
558 		if (i >= IOV_MAX)
559 			break;
560 		iov[i].iov_base = ibuf_data(buf);
561 		iov[i].iov_len = ibuf_size(buf);
562 		i++;
563 	}
564 
565 again:
566 	if ((n = writev(msgbuf->fd, iov, i)) == -1) {
567 		if (errno == EINTR)
568 			goto again;
569 		if (errno == ENOBUFS)
570 			errno = EAGAIN;
571 		return (-1);
572 	}
573 
574 	if (n == 0) {			/* connection closed */
575 		errno = 0;
576 		return (0);
577 	}
578 
579 	msgbuf_drain(msgbuf, n);
580 
581 	return (1);
582 }
583 
584 void
msgbuf_init(struct msgbuf * msgbuf)585 msgbuf_init(struct msgbuf *msgbuf)
586 {
587 	msgbuf->queued = 0;
588 	msgbuf->fd = -1;
589 	TAILQ_INIT(&msgbuf->bufs);
590 }
591 
592 static void
msgbuf_drain(struct msgbuf * msgbuf,size_t n)593 msgbuf_drain(struct msgbuf *msgbuf, size_t n)
594 {
595 	struct ibuf	*buf, *next;
596 
597 	for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
598 	    buf = next) {
599 		next = TAILQ_NEXT(buf, entry);
600 		if (n >= ibuf_size(buf)) {
601 			n -= ibuf_size(buf);
602 			ibuf_dequeue(msgbuf, buf);
603 		} else {
604 			buf->rpos += n;
605 			n = 0;
606 		}
607 	}
608 }
609 
610 void
msgbuf_clear(struct msgbuf * msgbuf)611 msgbuf_clear(struct msgbuf *msgbuf)
612 {
613 	struct ibuf	*buf;
614 
615 	while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
616 		ibuf_dequeue(msgbuf, buf);
617 }
618 
619 int
msgbuf_write(struct msgbuf * msgbuf)620 msgbuf_write(struct msgbuf *msgbuf)
621 {
622 	struct iovec	 iov[IOV_MAX];
623 	struct ibuf	*buf, *buf0 = NULL;
624 	unsigned int	 i = 0;
625 	ssize_t		 n;
626 	struct msghdr	 msg;
627 	struct cmsghdr	*cmsg;
628 	union {
629 		struct cmsghdr	hdr;
630 		char		buf[CMSG_SPACE(sizeof(int))];
631 	} cmsgbuf;
632 
633 	memset(&iov, 0, sizeof(iov));
634 	memset(&msg, 0, sizeof(msg));
635 	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
636 	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
637 		if (i >= IOV_MAX)
638 			break;
639 		if (i > 0 && buf->fd != -1)
640 			break;
641 		iov[i].iov_base = ibuf_data(buf);
642 		iov[i].iov_len = ibuf_size(buf);
643 		i++;
644 		if (buf->fd != -1)
645 			buf0 = buf;
646 	}
647 
648 	msg.msg_iov = iov;
649 	msg.msg_iovlen = i;
650 
651 	if (buf0 != NULL) {
652 		msg.msg_control = (caddr_t)&cmsgbuf.buf;
653 		msg.msg_controllen = CMSG_SPACE(sizeof(int));
654 		cmsg = CMSG_FIRSTHDR(&msg);
655 		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
656 		cmsg->cmsg_level = SOL_SOCKET;
657 		cmsg->cmsg_type = SCM_RIGHTS;
658 		*(int *)CMSG_DATA(cmsg) = buf0->fd;
659 	}
660 
661 again:
662 	if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
663 		if (errno == EINTR)
664 			goto again;
665 		if (errno == ENOBUFS)
666 			errno = EAGAIN;
667 		return (-1);
668 	}
669 
670 	if (n == 0) {			/* connection closed */
671 		errno = 0;
672 		return (0);
673 	}
674 
675 	/*
676 	 * assumption: fd got sent if sendmsg sent anything
677 	 * this works because fds are passed one at a time
678 	 */
679 	if (buf0 != NULL) {
680 		close(buf0->fd);
681 		buf0->fd = -1;
682 	}
683 
684 	msgbuf_drain(msgbuf, n);
685 
686 	return (1);
687 }
688 
689 uint32_t
msgbuf_queuelen(struct msgbuf * msgbuf)690 msgbuf_queuelen(struct msgbuf *msgbuf)
691 {
692 	return (msgbuf->queued);
693 }
694 
695 static void
ibuf_enqueue(struct msgbuf * msgbuf,struct ibuf * buf)696 ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
697 {
698 	if (buf->max == 0)	/* if buf lives on the stack */
699 		abort();	/* abort before causing more harm */
700 	TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
701 	msgbuf->queued++;
702 }
703 
704 static void
ibuf_dequeue(struct msgbuf * msgbuf,struct ibuf * buf)705 ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
706 {
707 	TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
708 	msgbuf->queued--;
709 	ibuf_free(buf);
710 }
711