1*ff59764dSclaudio /* $OpenBSD: imsg-buffer.c,v 1.31 2024/11/26 13:57:31 claudio Exp $ */ 2dfaf6462Snicm 3dfaf6462Snicm /* 44658a150Sclaudio * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org> 5dfaf6462Snicm * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 6dfaf6462Snicm * 7dfaf6462Snicm * Permission to use, copy, modify, and distribute this software for any 8dfaf6462Snicm * purpose with or without fee is hereby granted, provided that the above 9dfaf6462Snicm * copyright notice and this permission notice appear in all copies. 10dfaf6462Snicm * 11dfaf6462Snicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12dfaf6462Snicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13dfaf6462Snicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14dfaf6462Snicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15dfaf6462Snicm * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16dfaf6462Snicm * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17dfaf6462Snicm * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18dfaf6462Snicm */ 19dfaf6462Snicm 2082ee50fdSderaadt #include <sys/types.h> 21dfaf6462Snicm #include <sys/queue.h> 22dfaf6462Snicm #include <sys/socket.h> 23dfaf6462Snicm #include <sys/uio.h> 24dfaf6462Snicm 2582ee50fdSderaadt #include <limits.h> 26dfaf6462Snicm #include <errno.h> 2719778535Sclaudio #include <endian.h> 284658a150Sclaudio #include <stdint.h> 29dfaf6462Snicm #include <stdlib.h> 30dfaf6462Snicm #include <string.h> 31dfaf6462Snicm #include <unistd.h> 32dfaf6462Snicm 33dfaf6462Snicm #include "imsg.h" 34dfaf6462Snicm 35156c3c53Sclaudio struct msgbuf { 36156c3c53Sclaudio TAILQ_HEAD(, ibuf) bufs; 3704d83f12Sclaudio TAILQ_HEAD(, ibuf) rbufs; 38156c3c53Sclaudio uint32_t queued; 3904d83f12Sclaudio char *rbuf; 4004d83f12Sclaudio struct ibuf *rpmsg; 41*ff59764dSclaudio struct ibuf *(*readhdr)(struct ibuf *, void *, int *); 4204d83f12Sclaudio void *rarg; 4304d83f12Sclaudio size_t roff; 4404d83f12Sclaudio size_t hdrsize; 45156c3c53Sclaudio }; 46156c3c53Sclaudio 4704d83f12Sclaudio static void msgbuf_read_enqueue(struct msgbuf *, struct ibuf *); 4804886c2dSclaudio static void msgbuf_enqueue(struct msgbuf *, struct ibuf *); 4904886c2dSclaudio static void msgbuf_dequeue(struct msgbuf *, struct ibuf *); 5019778535Sclaudio static void msgbuf_drain(struct msgbuf *, size_t); 51dfaf6462Snicm 5248950d6eSclaudio #define IBUF_FD_MARK_ON_STACK -2 5348950d6eSclaudio 54dfaf6462Snicm struct ibuf * 55dfaf6462Snicm ibuf_open(size_t len) 56dfaf6462Snicm { 57dfaf6462Snicm struct ibuf *buf; 58dfaf6462Snicm 59dfaf6462Snicm if ((buf = calloc(1, sizeof(struct ibuf))) == NULL) 60dfaf6462Snicm return (NULL); 6148950d6eSclaudio if (len > 0) { 62e2fc7023Sclaudio if ((buf->buf = calloc(len, 1)) == NULL) { 63dfaf6462Snicm free(buf); 64dfaf6462Snicm return (NULL); 65dfaf6462Snicm } 6648950d6eSclaudio } 67dfaf6462Snicm buf->size = buf->max = len; 68dfaf6462Snicm buf->fd = -1; 69dfaf6462Snicm 70dfaf6462Snicm return (buf); 71dfaf6462Snicm } 72dfaf6462Snicm 73dfaf6462Snicm struct ibuf * 74dfaf6462Snicm ibuf_dynamic(size_t len, size_t max) 75dfaf6462Snicm { 76dfaf6462Snicm struct ibuf *buf; 77dfaf6462Snicm 784658a150Sclaudio if (max == 0 || max < len) { 79e2fc7023Sclaudio errno = EINVAL; 80dfaf6462Snicm return (NULL); 81e2fc7023Sclaudio } 82dfaf6462Snicm 83e2fc7023Sclaudio if ((buf = calloc(1, sizeof(struct ibuf))) == NULL) 84dfaf6462Snicm return (NULL); 85e2fc7023Sclaudio if (len > 0) { 86e2fc7023Sclaudio if ((buf->buf = calloc(len, 1)) == NULL) { 87e2fc7023Sclaudio free(buf); 88e2fc7023Sclaudio return (NULL); 89e2fc7023Sclaudio } 90e2fc7023Sclaudio } 91e2fc7023Sclaudio buf->size = len; 92dfaf6462Snicm buf->max = max; 93e2fc7023Sclaudio buf->fd = -1; 94dfaf6462Snicm 95dfaf6462Snicm return (buf); 96dfaf6462Snicm } 97dfaf6462Snicm 98dfaf6462Snicm void * 99dfaf6462Snicm ibuf_reserve(struct ibuf *buf, size_t len) 100dfaf6462Snicm { 101dfaf6462Snicm void *b; 102dfaf6462Snicm 10348950d6eSclaudio if (len > SIZE_MAX - buf->wpos) { 104c1a45aedStobias errno = ERANGE; 105c1a45aedStobias return (NULL); 106c1a45aedStobias } 10748950d6eSclaudio if (buf->fd == IBUF_FD_MARK_ON_STACK) { 10848950d6eSclaudio /* can not grow stack buffers */ 10948950d6eSclaudio errno = EINVAL; 11048950d6eSclaudio return (NULL); 11148950d6eSclaudio } 112c1a45aedStobias 113013d718aSclaudio if (buf->wpos + len > buf->size) { 114013d718aSclaudio unsigned char *nb; 115013d718aSclaudio 116013d718aSclaudio /* check if buffer is allowed to grow */ 117013d718aSclaudio if (buf->wpos + len > buf->max) { 118013d718aSclaudio errno = ERANGE; 119dfaf6462Snicm return (NULL); 120013d718aSclaudio } 121013d718aSclaudio nb = realloc(buf->buf, buf->wpos + len); 122013d718aSclaudio if (nb == NULL) 123013d718aSclaudio return (NULL); 124013d718aSclaudio memset(nb + buf->size, 0, buf->wpos + len - buf->size); 125013d718aSclaudio buf->buf = nb; 126013d718aSclaudio buf->size = buf->wpos + len; 127013d718aSclaudio } 128dfaf6462Snicm 129dfaf6462Snicm b = buf->buf + buf->wpos; 130dfaf6462Snicm buf->wpos += len; 131dfaf6462Snicm return (b); 132dfaf6462Snicm } 133dfaf6462Snicm 13419778535Sclaudio int 13519778535Sclaudio ibuf_add(struct ibuf *buf, const void *data, size_t len) 13619778535Sclaudio { 13719778535Sclaudio void *b; 13819778535Sclaudio 13919778535Sclaudio if ((b = ibuf_reserve(buf, len)) == NULL) 14019778535Sclaudio return (-1); 14119778535Sclaudio 14219778535Sclaudio memcpy(b, data, len); 14319778535Sclaudio return (0); 14419778535Sclaudio } 14519778535Sclaudio 14619778535Sclaudio int 1474658a150Sclaudio ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from) 1484658a150Sclaudio { 1494658a150Sclaudio return ibuf_add(buf, ibuf_data(from), ibuf_size(from)); 1504658a150Sclaudio } 1514658a150Sclaudio 15219778535Sclaudio int 15319778535Sclaudio ibuf_add_n8(struct ibuf *buf, uint64_t value) 15419778535Sclaudio { 15519778535Sclaudio uint8_t v; 15619778535Sclaudio 15719778535Sclaudio if (value > UINT8_MAX) { 15819778535Sclaudio errno = EINVAL; 15919778535Sclaudio return (-1); 16019778535Sclaudio } 16119778535Sclaudio v = value; 16219778535Sclaudio return ibuf_add(buf, &v, sizeof(v)); 16319778535Sclaudio } 16419778535Sclaudio 16519778535Sclaudio int 16619778535Sclaudio ibuf_add_n16(struct ibuf *buf, uint64_t value) 16719778535Sclaudio { 16819778535Sclaudio uint16_t v; 16919778535Sclaudio 17019778535Sclaudio if (value > UINT16_MAX) { 17119778535Sclaudio errno = EINVAL; 17219778535Sclaudio return (-1); 17319778535Sclaudio } 17419778535Sclaudio v = htobe16(value); 17519778535Sclaudio return ibuf_add(buf, &v, sizeof(v)); 17619778535Sclaudio } 17719778535Sclaudio 17819778535Sclaudio int 17919778535Sclaudio ibuf_add_n32(struct ibuf *buf, uint64_t value) 18019778535Sclaudio { 18119778535Sclaudio uint32_t v; 18219778535Sclaudio 18319778535Sclaudio if (value > UINT32_MAX) { 18419778535Sclaudio errno = EINVAL; 18519778535Sclaudio return (-1); 18619778535Sclaudio } 18719778535Sclaudio v = htobe32(value); 18819778535Sclaudio return ibuf_add(buf, &v, sizeof(v)); 18919778535Sclaudio } 19019778535Sclaudio 19119778535Sclaudio int 19219778535Sclaudio ibuf_add_n64(struct ibuf *buf, uint64_t value) 19319778535Sclaudio { 19419778535Sclaudio value = htobe64(value); 19519778535Sclaudio return ibuf_add(buf, &value, sizeof(value)); 19619778535Sclaudio } 19719778535Sclaudio 19819778535Sclaudio int 1994658a150Sclaudio ibuf_add_h16(struct ibuf *buf, uint64_t value) 2004658a150Sclaudio { 2014658a150Sclaudio uint16_t v; 2024658a150Sclaudio 2034658a150Sclaudio if (value > UINT16_MAX) { 2044658a150Sclaudio errno = EINVAL; 2054658a150Sclaudio return (-1); 2064658a150Sclaudio } 2074658a150Sclaudio v = value; 2084658a150Sclaudio return ibuf_add(buf, &v, sizeof(v)); 2094658a150Sclaudio } 2104658a150Sclaudio 2114658a150Sclaudio int 2124658a150Sclaudio ibuf_add_h32(struct ibuf *buf, uint64_t value) 2134658a150Sclaudio { 2144658a150Sclaudio uint32_t v; 2154658a150Sclaudio 2164658a150Sclaudio if (value > UINT32_MAX) { 2174658a150Sclaudio errno = EINVAL; 2184658a150Sclaudio return (-1); 2194658a150Sclaudio } 2204658a150Sclaudio v = value; 2214658a150Sclaudio return ibuf_add(buf, &v, sizeof(v)); 2224658a150Sclaudio } 2234658a150Sclaudio 2244658a150Sclaudio int 2254658a150Sclaudio ibuf_add_h64(struct ibuf *buf, uint64_t value) 2264658a150Sclaudio { 2274658a150Sclaudio return ibuf_add(buf, &value, sizeof(value)); 2284658a150Sclaudio } 2294658a150Sclaudio 2304658a150Sclaudio int 23119778535Sclaudio ibuf_add_zero(struct ibuf *buf, size_t len) 23219778535Sclaudio { 23319778535Sclaudio void *b; 23419778535Sclaudio 23519778535Sclaudio if ((b = ibuf_reserve(buf, len)) == NULL) 23619778535Sclaudio return (-1); 2374658a150Sclaudio memset(b, 0, len); 23819778535Sclaudio return (0); 23919778535Sclaudio } 24019778535Sclaudio 241dfaf6462Snicm void * 242dfaf6462Snicm ibuf_seek(struct ibuf *buf, size_t pos, size_t len) 243dfaf6462Snicm { 2444658a150Sclaudio /* only allow seeking between rpos and wpos */ 2454658a150Sclaudio if (ibuf_size(buf) < pos || SIZE_MAX - pos < len || 2464658a150Sclaudio ibuf_size(buf) < pos + len) { 24719778535Sclaudio errno = ERANGE; 248dfaf6462Snicm return (NULL); 24919778535Sclaudio } 250dfaf6462Snicm 2514658a150Sclaudio return (buf->buf + buf->rpos + pos); 252dfaf6462Snicm } 253dfaf6462Snicm 25419778535Sclaudio int 25519778535Sclaudio ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len) 25619778535Sclaudio { 25719778535Sclaudio void *b; 25819778535Sclaudio 25919778535Sclaudio if ((b = ibuf_seek(buf, pos, len)) == NULL) 26019778535Sclaudio return (-1); 26119778535Sclaudio 26219778535Sclaudio memcpy(b, data, len); 26319778535Sclaudio return (0); 26419778535Sclaudio } 26519778535Sclaudio 26619778535Sclaudio int 26719778535Sclaudio ibuf_set_n8(struct ibuf *buf, size_t pos, uint64_t value) 26819778535Sclaudio { 26919778535Sclaudio uint8_t v; 27019778535Sclaudio 27119778535Sclaudio if (value > UINT8_MAX) { 27219778535Sclaudio errno = EINVAL; 27319778535Sclaudio return (-1); 27419778535Sclaudio } 27519778535Sclaudio v = value; 27619778535Sclaudio return (ibuf_set(buf, pos, &v, sizeof(v))); 27719778535Sclaudio } 27819778535Sclaudio 27919778535Sclaudio int 28019778535Sclaudio ibuf_set_n16(struct ibuf *buf, size_t pos, uint64_t value) 28119778535Sclaudio { 28219778535Sclaudio uint16_t v; 28319778535Sclaudio 28419778535Sclaudio if (value > UINT16_MAX) { 28519778535Sclaudio errno = EINVAL; 28619778535Sclaudio return (-1); 28719778535Sclaudio } 28819778535Sclaudio v = htobe16(value); 28919778535Sclaudio return (ibuf_set(buf, pos, &v, sizeof(v))); 29019778535Sclaudio } 29119778535Sclaudio 29219778535Sclaudio int 29319778535Sclaudio ibuf_set_n32(struct ibuf *buf, size_t pos, uint64_t value) 29419778535Sclaudio { 29519778535Sclaudio uint32_t v; 29619778535Sclaudio 29719778535Sclaudio if (value > UINT32_MAX) { 29819778535Sclaudio errno = EINVAL; 29919778535Sclaudio return (-1); 30019778535Sclaudio } 30119778535Sclaudio v = htobe32(value); 30219778535Sclaudio return (ibuf_set(buf, pos, &v, sizeof(v))); 30319778535Sclaudio } 30419778535Sclaudio 30519778535Sclaudio int 30619778535Sclaudio ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value) 30719778535Sclaudio { 30819778535Sclaudio value = htobe64(value); 30919778535Sclaudio return (ibuf_set(buf, pos, &value, sizeof(value))); 31019778535Sclaudio } 31119778535Sclaudio 3124658a150Sclaudio int 3134658a150Sclaudio ibuf_set_h16(struct ibuf *buf, size_t pos, uint64_t value) 3144658a150Sclaudio { 3154658a150Sclaudio uint16_t v; 3164658a150Sclaudio 3174658a150Sclaudio if (value > UINT16_MAX) { 3184658a150Sclaudio errno = EINVAL; 3194658a150Sclaudio return (-1); 3204658a150Sclaudio } 3214658a150Sclaudio v = value; 3224658a150Sclaudio return (ibuf_set(buf, pos, &v, sizeof(v))); 3234658a150Sclaudio } 3244658a150Sclaudio 3254658a150Sclaudio int 3264658a150Sclaudio ibuf_set_h32(struct ibuf *buf, size_t pos, uint64_t value) 3274658a150Sclaudio { 3284658a150Sclaudio uint32_t v; 3294658a150Sclaudio 3304658a150Sclaudio if (value > UINT32_MAX) { 3314658a150Sclaudio errno = EINVAL; 3324658a150Sclaudio return (-1); 3334658a150Sclaudio } 3344658a150Sclaudio v = value; 3354658a150Sclaudio return (ibuf_set(buf, pos, &v, sizeof(v))); 3364658a150Sclaudio } 3374658a150Sclaudio 3384658a150Sclaudio int 3394658a150Sclaudio ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value) 3404658a150Sclaudio { 3414658a150Sclaudio return (ibuf_set(buf, pos, &value, sizeof(value))); 3424658a150Sclaudio } 3434658a150Sclaudio 34419778535Sclaudio void * 3454658a150Sclaudio ibuf_data(const struct ibuf *buf) 34619778535Sclaudio { 3474658a150Sclaudio return (buf->buf + buf->rpos); 34819778535Sclaudio } 34919778535Sclaudio 350dfaf6462Snicm size_t 3514658a150Sclaudio ibuf_size(const struct ibuf *buf) 352dfaf6462Snicm { 3534658a150Sclaudio return (buf->wpos - buf->rpos); 354dfaf6462Snicm } 355dfaf6462Snicm 356dfaf6462Snicm size_t 3574658a150Sclaudio ibuf_left(const struct ibuf *buf) 358dfaf6462Snicm { 35948950d6eSclaudio /* on stack buffers have no space left */ 36048950d6eSclaudio if (buf->fd == IBUF_FD_MARK_ON_STACK) 3614658a150Sclaudio return (0); 362dfaf6462Snicm return (buf->max - buf->wpos); 363dfaf6462Snicm } 364dfaf6462Snicm 3654658a150Sclaudio int 3664658a150Sclaudio ibuf_truncate(struct ibuf *buf, size_t len) 3674658a150Sclaudio { 3684658a150Sclaudio if (ibuf_size(buf) >= len) { 3694658a150Sclaudio buf->wpos = buf->rpos + len; 3704658a150Sclaudio return (0); 3714658a150Sclaudio } 37248950d6eSclaudio if (buf->fd == IBUF_FD_MARK_ON_STACK) { 37348950d6eSclaudio /* only allow to truncate down for stack buffers */ 3744658a150Sclaudio errno = ERANGE; 3754658a150Sclaudio return (-1); 3764658a150Sclaudio } 3774658a150Sclaudio return ibuf_add_zero(buf, len - ibuf_size(buf)); 3784658a150Sclaudio } 3794658a150Sclaudio 3804658a150Sclaudio void 3814658a150Sclaudio ibuf_rewind(struct ibuf *buf) 3824658a150Sclaudio { 3834658a150Sclaudio buf->rpos = 0; 3844658a150Sclaudio } 3854658a150Sclaudio 386dfaf6462Snicm void 387dfaf6462Snicm ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) 388dfaf6462Snicm { 38904886c2dSclaudio msgbuf_enqueue(msgbuf, buf); 390dfaf6462Snicm } 391dfaf6462Snicm 39219778535Sclaudio void 3934658a150Sclaudio ibuf_from_buffer(struct ibuf *buf, void *data, size_t len) 3944658a150Sclaudio { 3954658a150Sclaudio memset(buf, 0, sizeof(*buf)); 3964658a150Sclaudio buf->buf = data; 3974658a150Sclaudio buf->size = buf->wpos = len; 39848950d6eSclaudio buf->fd = IBUF_FD_MARK_ON_STACK; 3994658a150Sclaudio } 4004658a150Sclaudio 4014658a150Sclaudio void 4024658a150Sclaudio ibuf_from_ibuf(struct ibuf *buf, const struct ibuf *from) 4034658a150Sclaudio { 4044658a150Sclaudio ibuf_from_buffer(buf, ibuf_data(from), ibuf_size(from)); 4054658a150Sclaudio } 4064658a150Sclaudio 4074658a150Sclaudio int 4084658a150Sclaudio ibuf_get(struct ibuf *buf, void *data, size_t len) 4094658a150Sclaudio { 4104658a150Sclaudio if (ibuf_size(buf) < len) { 4114658a150Sclaudio errno = EBADMSG; 4124658a150Sclaudio return (-1); 4134658a150Sclaudio } 4144658a150Sclaudio 4154658a150Sclaudio memcpy(data, ibuf_data(buf), len); 4164658a150Sclaudio buf->rpos += len; 4174658a150Sclaudio return (0); 4184658a150Sclaudio } 4194658a150Sclaudio 4204658a150Sclaudio int 4214658a150Sclaudio ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new) 4224658a150Sclaudio { 4234658a150Sclaudio if (ibuf_size(buf) < len) { 4244658a150Sclaudio errno = EBADMSG; 4254658a150Sclaudio return (-1); 4264658a150Sclaudio } 4274658a150Sclaudio 4284658a150Sclaudio ibuf_from_buffer(new, ibuf_data(buf), len); 4294658a150Sclaudio buf->rpos += len; 4304658a150Sclaudio return (0); 4314658a150Sclaudio } 4324658a150Sclaudio 4334658a150Sclaudio int 434442dea11Sclaudio ibuf_get_h16(struct ibuf *buf, uint16_t *value) 435442dea11Sclaudio { 436442dea11Sclaudio return ibuf_get(buf, value, sizeof(*value)); 437442dea11Sclaudio } 438442dea11Sclaudio 439442dea11Sclaudio int 440442dea11Sclaudio ibuf_get_h32(struct ibuf *buf, uint32_t *value) 441442dea11Sclaudio { 442442dea11Sclaudio return ibuf_get(buf, value, sizeof(*value)); 443442dea11Sclaudio } 444442dea11Sclaudio 445442dea11Sclaudio int 446442dea11Sclaudio ibuf_get_h64(struct ibuf *buf, uint64_t *value) 447442dea11Sclaudio { 448442dea11Sclaudio return ibuf_get(buf, value, sizeof(*value)); 449442dea11Sclaudio } 450442dea11Sclaudio 451442dea11Sclaudio int 4524658a150Sclaudio ibuf_get_n8(struct ibuf *buf, uint8_t *value) 4534658a150Sclaudio { 4544658a150Sclaudio return ibuf_get(buf, value, sizeof(*value)); 4554658a150Sclaudio } 4564658a150Sclaudio 4574658a150Sclaudio int 4584658a150Sclaudio ibuf_get_n16(struct ibuf *buf, uint16_t *value) 4594658a150Sclaudio { 4604658a150Sclaudio int rv; 4614658a150Sclaudio 4624658a150Sclaudio rv = ibuf_get(buf, value, sizeof(*value)); 4634658a150Sclaudio *value = be16toh(*value); 4644658a150Sclaudio return (rv); 4654658a150Sclaudio } 4664658a150Sclaudio 4674658a150Sclaudio int 4684658a150Sclaudio ibuf_get_n32(struct ibuf *buf, uint32_t *value) 4694658a150Sclaudio { 4704658a150Sclaudio int rv; 4714658a150Sclaudio 4724658a150Sclaudio rv = ibuf_get(buf, value, sizeof(*value)); 4734658a150Sclaudio *value = be32toh(*value); 4744658a150Sclaudio return (rv); 4754658a150Sclaudio } 4764658a150Sclaudio 4774658a150Sclaudio int 4784658a150Sclaudio ibuf_get_n64(struct ibuf *buf, uint64_t *value) 4794658a150Sclaudio { 4804658a150Sclaudio int rv; 4814658a150Sclaudio 4824658a150Sclaudio rv = ibuf_get(buf, value, sizeof(*value)); 4834658a150Sclaudio *value = be64toh(*value); 4844658a150Sclaudio return (rv); 4854658a150Sclaudio } 4864658a150Sclaudio 487442dea11Sclaudio char * 488442dea11Sclaudio ibuf_get_string(struct ibuf *buf, size_t len) 4894658a150Sclaudio { 490442dea11Sclaudio char *str; 491442dea11Sclaudio 492442dea11Sclaudio if (ibuf_size(buf) < len) { 493442dea11Sclaudio errno = EBADMSG; 494442dea11Sclaudio return (NULL); 4954658a150Sclaudio } 4964658a150Sclaudio 497442dea11Sclaudio str = strndup(ibuf_data(buf), len); 498442dea11Sclaudio if (str == NULL) 499442dea11Sclaudio return (NULL); 500442dea11Sclaudio buf->rpos += len; 501442dea11Sclaudio return (str); 5024658a150Sclaudio } 5034658a150Sclaudio 5044658a150Sclaudio int 5054658a150Sclaudio ibuf_skip(struct ibuf *buf, size_t len) 5064658a150Sclaudio { 5074658a150Sclaudio if (ibuf_size(buf) < len) { 5084658a150Sclaudio errno = EBADMSG; 5094658a150Sclaudio return (-1); 5104658a150Sclaudio } 5114658a150Sclaudio 5124658a150Sclaudio buf->rpos += len; 5134658a150Sclaudio return (0); 5144658a150Sclaudio } 5154658a150Sclaudio 5164658a150Sclaudio void 51719778535Sclaudio ibuf_free(struct ibuf *buf) 51819778535Sclaudio { 51919778535Sclaudio if (buf == NULL) 52019778535Sclaudio return; 52148950d6eSclaudio /* if buf lives on the stack abort before causing more harm */ 52248950d6eSclaudio if (buf->fd == IBUF_FD_MARK_ON_STACK) 52348950d6eSclaudio abort(); 52448950d6eSclaudio if (buf->fd >= 0) 52519778535Sclaudio close(buf->fd); 52619778535Sclaudio freezero(buf->buf, buf->size); 52719778535Sclaudio free(buf); 52819778535Sclaudio } 52919778535Sclaudio 53019778535Sclaudio int 53119778535Sclaudio ibuf_fd_avail(struct ibuf *buf) 53219778535Sclaudio { 53348950d6eSclaudio return (buf->fd >= 0); 53419778535Sclaudio } 53519778535Sclaudio 53619778535Sclaudio int 53719778535Sclaudio ibuf_fd_get(struct ibuf *buf) 53819778535Sclaudio { 53919778535Sclaudio int fd; 54019778535Sclaudio 54148950d6eSclaudio /* negative fds are internal use and equivalent to -1 */ 54248950d6eSclaudio if (buf->fd < 0) 54348950d6eSclaudio return (-1); 54419778535Sclaudio fd = buf->fd; 54519778535Sclaudio buf->fd = -1; 54619778535Sclaudio return (fd); 54719778535Sclaudio } 54819778535Sclaudio 54919778535Sclaudio void 55019778535Sclaudio ibuf_fd_set(struct ibuf *buf, int fd) 55119778535Sclaudio { 55248950d6eSclaudio /* if buf lives on the stack abort before causing more harm */ 55348950d6eSclaudio if (buf->fd == IBUF_FD_MARK_ON_STACK) 55448950d6eSclaudio abort(); 55548950d6eSclaudio if (buf->fd >= 0) 55619778535Sclaudio close(buf->fd); 55748950d6eSclaudio buf->fd = -1; 55848950d6eSclaudio if (fd >= 0) 55919778535Sclaudio buf->fd = fd; 56019778535Sclaudio } 56119778535Sclaudio 562156c3c53Sclaudio struct msgbuf * 563156c3c53Sclaudio msgbuf_new(void) 56404886c2dSclaudio { 565156c3c53Sclaudio struct msgbuf *msgbuf; 566156c3c53Sclaudio 567156c3c53Sclaudio if ((msgbuf = calloc(1, sizeof(*msgbuf))) == NULL) 568156c3c53Sclaudio return (NULL); 56904886c2dSclaudio msgbuf->queued = 0; 57004886c2dSclaudio TAILQ_INIT(&msgbuf->bufs); 57104d83f12Sclaudio TAILQ_INIT(&msgbuf->rbufs); 572156c3c53Sclaudio 573156c3c53Sclaudio return msgbuf; 574156c3c53Sclaudio } 575156c3c53Sclaudio 57604d83f12Sclaudio struct msgbuf * 577*ff59764dSclaudio msgbuf_new_reader(size_t hdrsz, 578*ff59764dSclaudio struct ibuf *(*readhdr)(struct ibuf *, void *, int *), void *arg) 57904d83f12Sclaudio { 58004d83f12Sclaudio struct msgbuf *msgbuf; 58104d83f12Sclaudio char *buf; 58204d83f12Sclaudio 58304d83f12Sclaudio if (hdrsz == 0 || hdrsz > IBUF_READ_SIZE / 2) { 58404d83f12Sclaudio errno = EINVAL; 58504d83f12Sclaudio return (NULL); 58604d83f12Sclaudio } 58704d83f12Sclaudio 58804d83f12Sclaudio if ((buf = malloc(IBUF_READ_SIZE)) == NULL) 58904d83f12Sclaudio return (NULL); 59004d83f12Sclaudio 59104d83f12Sclaudio msgbuf = msgbuf_new(); 59204d83f12Sclaudio if (msgbuf == NULL) { 59304d83f12Sclaudio free(buf); 59404d83f12Sclaudio return (NULL); 59504d83f12Sclaudio } 59604d83f12Sclaudio 59704d83f12Sclaudio msgbuf->rbuf = buf; 59804d83f12Sclaudio msgbuf->hdrsize = hdrsz; 59904d83f12Sclaudio msgbuf->readhdr = readhdr; 60004d83f12Sclaudio msgbuf->rarg = arg; 60104d83f12Sclaudio 60204d83f12Sclaudio return (msgbuf); 60304d83f12Sclaudio } 60404d83f12Sclaudio 605156c3c53Sclaudio void 606156c3c53Sclaudio msgbuf_free(struct msgbuf *msgbuf) 607156c3c53Sclaudio { 608ab837574Stb if (msgbuf == NULL) 609ab837574Stb return; 610156c3c53Sclaudio msgbuf_clear(msgbuf); 61104d83f12Sclaudio free(msgbuf->rbuf); 612156c3c53Sclaudio free(msgbuf); 61304886c2dSclaudio } 61404886c2dSclaudio 61504886c2dSclaudio uint32_t 61604886c2dSclaudio msgbuf_queuelen(struct msgbuf *msgbuf) 61704886c2dSclaudio { 61804886c2dSclaudio return (msgbuf->queued); 61904886c2dSclaudio } 62004886c2dSclaudio 62104886c2dSclaudio void 62204886c2dSclaudio msgbuf_clear(struct msgbuf *msgbuf) 62304886c2dSclaudio { 62404886c2dSclaudio struct ibuf *buf; 62504886c2dSclaudio 62604d83f12Sclaudio /* write side */ 62704886c2dSclaudio while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL) 62804886c2dSclaudio msgbuf_dequeue(msgbuf, buf); 62904d83f12Sclaudio msgbuf->queued = 0; 63004d83f12Sclaudio 63104d83f12Sclaudio /* read side */ 63204d83f12Sclaudio while ((buf = TAILQ_FIRST(&msgbuf->rbufs)) != NULL) { 63304d83f12Sclaudio TAILQ_REMOVE(&msgbuf->rbufs, buf, entry); 63404d83f12Sclaudio ibuf_free(buf); 63504d83f12Sclaudio } 63604d83f12Sclaudio msgbuf->roff = 0; 63704d83f12Sclaudio ibuf_free(msgbuf->rpmsg); 63804d83f12Sclaudio msgbuf->rpmsg = NULL; 63904d83f12Sclaudio } 64004d83f12Sclaudio 64104d83f12Sclaudio struct ibuf * 64204d83f12Sclaudio msgbuf_get(struct msgbuf *msgbuf) 64304d83f12Sclaudio { 64404d83f12Sclaudio struct ibuf *buf; 64504d83f12Sclaudio 64604d83f12Sclaudio if ((buf = TAILQ_FIRST(&msgbuf->rbufs)) != NULL) 64704d83f12Sclaudio TAILQ_REMOVE(&msgbuf->rbufs, buf, entry); 64804d83f12Sclaudio return buf; 64904886c2dSclaudio } 65004886c2dSclaudio 651dfaf6462Snicm int 6524494689aSclaudio ibuf_write(int fd, struct msgbuf *msgbuf) 653dfaf6462Snicm { 654dfaf6462Snicm struct iovec iov[IOV_MAX]; 655dfaf6462Snicm struct ibuf *buf; 656dfaf6462Snicm unsigned int i = 0; 657dfaf6462Snicm ssize_t n; 658dfaf6462Snicm 6593c384461Snicm memset(&iov, 0, sizeof(iov)); 660dfaf6462Snicm TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { 661dfaf6462Snicm if (i >= IOV_MAX) 662dfaf6462Snicm break; 6634658a150Sclaudio iov[i].iov_base = ibuf_data(buf); 6644658a150Sclaudio iov[i].iov_len = ibuf_size(buf); 665dfaf6462Snicm i++; 666dfaf6462Snicm } 667317c8015Sclaudio if (i == 0) 668317c8015Sclaudio return (0); /* nothing queued */ 669dfaf6462Snicm 670f7a9e704Sgilles again: 6714494689aSclaudio if ((n = writev(fd, iov, i)) == -1) { 672450376abSbenno if (errno == EINTR) 673f7a9e704Sgilles goto again; 674317c8015Sclaudio if (errno == EAGAIN || errno == ENOBUFS) 675317c8015Sclaudio /* lets retry later again */ 676317c8015Sclaudio return (0); 677dfaf6462Snicm return (-1); 678dfaf6462Snicm } 679dfaf6462Snicm 680dfaf6462Snicm msgbuf_drain(msgbuf, n); 681317c8015Sclaudio return (0); 682dfaf6462Snicm } 683dfaf6462Snicm 684dfaf6462Snicm int 6854494689aSclaudio msgbuf_write(int fd, struct msgbuf *msgbuf) 686dfaf6462Snicm { 687dfaf6462Snicm struct iovec iov[IOV_MAX]; 6882325ad59Seric struct ibuf *buf, *buf0 = NULL; 689dfaf6462Snicm unsigned int i = 0; 690dfaf6462Snicm ssize_t n; 691dfaf6462Snicm struct msghdr msg; 692dfaf6462Snicm struct cmsghdr *cmsg; 693dfaf6462Snicm union { 694dfaf6462Snicm struct cmsghdr hdr; 695dfaf6462Snicm char buf[CMSG_SPACE(sizeof(int))]; 696dfaf6462Snicm } cmsgbuf; 697dfaf6462Snicm 6983c384461Snicm memset(&iov, 0, sizeof(iov)); 6993c384461Snicm memset(&msg, 0, sizeof(msg)); 7003c384461Snicm memset(&cmsgbuf, 0, sizeof(cmsgbuf)); 701dfaf6462Snicm TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { 702dfaf6462Snicm if (i >= IOV_MAX) 703dfaf6462Snicm break; 7042325ad59Seric if (i > 0 && buf->fd != -1) 7052325ad59Seric break; 7064658a150Sclaudio iov[i].iov_base = ibuf_data(buf); 7074658a150Sclaudio iov[i].iov_len = ibuf_size(buf); 708dfaf6462Snicm i++; 709dfaf6462Snicm if (buf->fd != -1) 7102325ad59Seric buf0 = buf; 711dfaf6462Snicm } 712dfaf6462Snicm 713317c8015Sclaudio if (i == 0) 714317c8015Sclaudio return (0); /* nothing queued */ 715317c8015Sclaudio 716dfaf6462Snicm msg.msg_iov = iov; 717dfaf6462Snicm msg.msg_iovlen = i; 718dfaf6462Snicm 7192325ad59Seric if (buf0 != NULL) { 720dfaf6462Snicm msg.msg_control = (caddr_t)&cmsgbuf.buf; 721dfaf6462Snicm msg.msg_controllen = sizeof(cmsgbuf.buf); 722dfaf6462Snicm cmsg = CMSG_FIRSTHDR(&msg); 723dfaf6462Snicm cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 724dfaf6462Snicm cmsg->cmsg_level = SOL_SOCKET; 725dfaf6462Snicm cmsg->cmsg_type = SCM_RIGHTS; 7262325ad59Seric *(int *)CMSG_DATA(cmsg) = buf0->fd; 727dfaf6462Snicm } 728dfaf6462Snicm 729f7a9e704Sgilles again: 7304494689aSclaudio if ((n = sendmsg(fd, &msg, 0)) == -1) { 731450376abSbenno if (errno == EINTR) 732f7a9e704Sgilles goto again; 733317c8015Sclaudio if (errno == EAGAIN || errno == ENOBUFS) 734317c8015Sclaudio /* lets retry later again */ 735f7a9e704Sgilles return (0); 736317c8015Sclaudio return (-1); 737dfaf6462Snicm } 738dfaf6462Snicm 739dfaf6462Snicm /* 740dfaf6462Snicm * assumption: fd got sent if sendmsg sent anything 741dfaf6462Snicm * this works because fds are passed one at a time 742dfaf6462Snicm */ 7432325ad59Seric if (buf0 != NULL) { 7442325ad59Seric close(buf0->fd); 7452325ad59Seric buf0->fd = -1; 746dfaf6462Snicm } 747dfaf6462Snicm 748dfaf6462Snicm msgbuf_drain(msgbuf, n); 749dfaf6462Snicm 750317c8015Sclaudio return (0); 751dfaf6462Snicm } 752dfaf6462Snicm 75304d83f12Sclaudio static int 75404d83f12Sclaudio ibuf_read_process(struct msgbuf *msgbuf, int fd) 75504d83f12Sclaudio { 75604d83f12Sclaudio struct ibuf rbuf, msg; 75704d83f12Sclaudio ssize_t sz; 75804d83f12Sclaudio 75904d83f12Sclaudio ibuf_from_buffer(&rbuf, msgbuf->rbuf, msgbuf->roff); 76004d83f12Sclaudio 76104d83f12Sclaudio do { 76204d83f12Sclaudio if (msgbuf->rpmsg == NULL) { 763*ff59764dSclaudio if (ibuf_size(&rbuf) < msgbuf->hdrsize) 76404d83f12Sclaudio break; 76504d83f12Sclaudio /* get size from header */ 76604d83f12Sclaudio ibuf_from_buffer(&msg, ibuf_data(&rbuf), 76704d83f12Sclaudio msgbuf->hdrsize); 768*ff59764dSclaudio if ((msgbuf->rpmsg = msgbuf->readhdr(&msg, 769*ff59764dSclaudio msgbuf->rarg, &fd)) == NULL) 77004d83f12Sclaudio goto fail; 77104d83f12Sclaudio } 77204d83f12Sclaudio 77304d83f12Sclaudio if (ibuf_left(msgbuf->rpmsg) <= ibuf_size(&rbuf)) 77404d83f12Sclaudio sz = ibuf_left(msgbuf->rpmsg); 77504d83f12Sclaudio else 77604d83f12Sclaudio sz = ibuf_size(&rbuf); 77704d83f12Sclaudio 77804d83f12Sclaudio /* neither call below can fail */ 77904d83f12Sclaudio if (ibuf_get_ibuf(&rbuf, sz, &msg) == -1 || 78004d83f12Sclaudio ibuf_add_ibuf(msgbuf->rpmsg, &msg) == -1) 78104d83f12Sclaudio goto fail; 78204d83f12Sclaudio 78304d83f12Sclaudio if (ibuf_left(msgbuf->rpmsg) == 0) { 78404d83f12Sclaudio msgbuf_read_enqueue(msgbuf, msgbuf->rpmsg); 78504d83f12Sclaudio msgbuf->rpmsg = NULL; 78604d83f12Sclaudio } 78704d83f12Sclaudio } while (ibuf_size(&rbuf) > 0); 78804d83f12Sclaudio 78904d83f12Sclaudio if (ibuf_size(&rbuf) > 0) 79004d83f12Sclaudio memmove(msgbuf->rbuf, ibuf_data(&rbuf), ibuf_size(&rbuf)); 79104d83f12Sclaudio msgbuf->roff = ibuf_size(&rbuf); 79204d83f12Sclaudio 793*ff59764dSclaudio if (fd != -1) 794*ff59764dSclaudio close(fd); 79504d83f12Sclaudio return (1); 79604d83f12Sclaudio 79704d83f12Sclaudio fail: 798*ff59764dSclaudio /* XXX how to properly clean up is unclear */ 799*ff59764dSclaudio if (fd != -1) 800*ff59764dSclaudio close(fd); 80104d83f12Sclaudio return (-1); 80204d83f12Sclaudio } 80304d83f12Sclaudio 80404d83f12Sclaudio int 80504d83f12Sclaudio ibuf_read(int fd, struct msgbuf *msgbuf) 80604d83f12Sclaudio { 80704d83f12Sclaudio struct iovec iov; 80804d83f12Sclaudio ssize_t n; 80904d83f12Sclaudio 81004d83f12Sclaudio if (msgbuf->rbuf == NULL) { 81104d83f12Sclaudio errno = EINVAL; 81204d83f12Sclaudio return (-1); 81304d83f12Sclaudio } 81404d83f12Sclaudio 81504d83f12Sclaudio iov.iov_base = msgbuf->rbuf + msgbuf->roff; 81604d83f12Sclaudio iov.iov_len = IBUF_READ_SIZE - msgbuf->roff; 81704d83f12Sclaudio 81804d83f12Sclaudio again: 81904d83f12Sclaudio if ((n = readv(fd, &iov, 1)) == -1) { 82004d83f12Sclaudio if (errno == EINTR) 82104d83f12Sclaudio goto again; 82204d83f12Sclaudio if (errno == EAGAIN) 82304d83f12Sclaudio /* lets retry later again */ 82404d83f12Sclaudio return (1); 82504d83f12Sclaudio return (-1); 82604d83f12Sclaudio } 82704d83f12Sclaudio if (n == 0) /* connection closed */ 82804d83f12Sclaudio return (0); 82904d83f12Sclaudio 83004d83f12Sclaudio msgbuf->roff += n; 83104d83f12Sclaudio /* new data arrived, try to process it */ 83204d83f12Sclaudio return (ibuf_read_process(msgbuf, -1)); 83304d83f12Sclaudio } 83404d83f12Sclaudio 83504d83f12Sclaudio int 83604d83f12Sclaudio msgbuf_read(int fd, struct msgbuf *msgbuf) 83704d83f12Sclaudio { 83804d83f12Sclaudio struct msghdr msg; 83904d83f12Sclaudio struct cmsghdr *cmsg; 84004d83f12Sclaudio union { 84104d83f12Sclaudio struct cmsghdr hdr; 84204d83f12Sclaudio char buf[CMSG_SPACE(sizeof(int) * 1)]; 84304d83f12Sclaudio } cmsgbuf; 84404d83f12Sclaudio struct iovec iov; 84504d83f12Sclaudio ssize_t n; 84604d83f12Sclaudio int fdpass = -1; 84704d83f12Sclaudio 84804d83f12Sclaudio if (msgbuf->rbuf == NULL) { 84904d83f12Sclaudio errno = EINVAL; 85004d83f12Sclaudio return (-1); 85104d83f12Sclaudio } 85204d83f12Sclaudio 85304d83f12Sclaudio memset(&msg, 0, sizeof(msg)); 85404d83f12Sclaudio memset(&cmsgbuf, 0, sizeof(cmsgbuf)); 85504d83f12Sclaudio 85604d83f12Sclaudio iov.iov_base = msgbuf->rbuf + msgbuf->roff; 85704d83f12Sclaudio iov.iov_len = IBUF_READ_SIZE - msgbuf->roff; 85804d83f12Sclaudio msg.msg_iov = &iov; 85904d83f12Sclaudio msg.msg_iovlen = 1; 86004d83f12Sclaudio msg.msg_control = &cmsgbuf.buf; 86104d83f12Sclaudio msg.msg_controllen = sizeof(cmsgbuf.buf); 86204d83f12Sclaudio 86304d83f12Sclaudio again: 86404d83f12Sclaudio if ((n = recvmsg(fd, &msg, 0)) == -1) { 86504d83f12Sclaudio if (errno == EINTR) 86604d83f12Sclaudio goto again; 86704d83f12Sclaudio if (errno == EMSGSIZE) 86804d83f12Sclaudio /* 86904d83f12Sclaudio * Not enough fd slots: fd passing failed, retry 87004d83f12Sclaudio * to receive the message without fd. 87104d83f12Sclaudio * imsg_get_fd() will return -1 in that case. 87204d83f12Sclaudio */ 87304d83f12Sclaudio goto again; 87404d83f12Sclaudio if (errno == EAGAIN) 87504d83f12Sclaudio /* lets retry later again */ 87604d83f12Sclaudio return (1); 87704d83f12Sclaudio return (-1); 87804d83f12Sclaudio } 87904d83f12Sclaudio if (n == 0) /* connection closed */ 88004d83f12Sclaudio return (0); 88104d83f12Sclaudio 88204d83f12Sclaudio msgbuf->roff += n; 88304d83f12Sclaudio 88404d83f12Sclaudio for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 88504d83f12Sclaudio cmsg = CMSG_NXTHDR(&msg, cmsg)) { 88604d83f12Sclaudio if (cmsg->cmsg_level == SOL_SOCKET && 88704d83f12Sclaudio cmsg->cmsg_type == SCM_RIGHTS) { 88804d83f12Sclaudio int i, j, f; 88904d83f12Sclaudio 89004d83f12Sclaudio /* 89104d83f12Sclaudio * We only accept one file descriptor. Due to C 89204d83f12Sclaudio * padding rules, our control buffer might contain 89304d83f12Sclaudio * more than one fd, and we must close them. 89404d83f12Sclaudio */ 89504d83f12Sclaudio j = ((char *)cmsg + cmsg->cmsg_len - 89604d83f12Sclaudio (char *)CMSG_DATA(cmsg)) / sizeof(int); 89704d83f12Sclaudio for (i = 0; i < j; i++) { 89804d83f12Sclaudio f = ((int *)CMSG_DATA(cmsg))[i]; 89904d83f12Sclaudio if (i == 0) 90004d83f12Sclaudio fdpass = f; 90104d83f12Sclaudio else 90204d83f12Sclaudio close(f); 90304d83f12Sclaudio } 90404d83f12Sclaudio } 90504d83f12Sclaudio /* we do not handle other ctl data level */ 90604d83f12Sclaudio } 90704d83f12Sclaudio 90804d83f12Sclaudio /* new data arrived, try to process it */ 90904d83f12Sclaudio return (ibuf_read_process(msgbuf, fdpass)); 91004d83f12Sclaudio } 91104d83f12Sclaudio 91204d83f12Sclaudio static void 91304d83f12Sclaudio msgbuf_read_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) 91404d83f12Sclaudio { 91504d83f12Sclaudio /* if buf lives on the stack abort before causing more harm */ 91604d83f12Sclaudio if (buf->fd == IBUF_FD_MARK_ON_STACK) 91704d83f12Sclaudio abort(); 91804d83f12Sclaudio TAILQ_INSERT_TAIL(&msgbuf->rbufs, buf, entry); 91904d83f12Sclaudio } 92004d83f12Sclaudio 9218c897735Skettenis static void 92204886c2dSclaudio msgbuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) 923dfaf6462Snicm { 92448950d6eSclaudio /* if buf lives on the stack abort before causing more harm */ 92548950d6eSclaudio if (buf->fd == IBUF_FD_MARK_ON_STACK) 92648950d6eSclaudio abort(); 927dfaf6462Snicm TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry); 928dfaf6462Snicm msgbuf->queued++; 929dfaf6462Snicm } 930dfaf6462Snicm 9318c897735Skettenis static void 93204886c2dSclaudio msgbuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf) 933dfaf6462Snicm { 934dfaf6462Snicm TAILQ_REMOVE(&msgbuf->bufs, buf, entry); 935dfaf6462Snicm msgbuf->queued--; 936dfaf6462Snicm ibuf_free(buf); 937dfaf6462Snicm } 93804886c2dSclaudio 93904886c2dSclaudio static void 94004886c2dSclaudio msgbuf_drain(struct msgbuf *msgbuf, size_t n) 94104886c2dSclaudio { 94204886c2dSclaudio struct ibuf *buf, *next; 94304886c2dSclaudio 94404886c2dSclaudio for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; 94504886c2dSclaudio buf = next) { 94604886c2dSclaudio next = TAILQ_NEXT(buf, entry); 94704886c2dSclaudio if (n >= ibuf_size(buf)) { 94804886c2dSclaudio n -= ibuf_size(buf); 94904886c2dSclaudio msgbuf_dequeue(msgbuf, buf); 95004886c2dSclaudio } else { 95104886c2dSclaudio buf->rpos += n; 95204886c2dSclaudio n = 0; 95304886c2dSclaudio } 95404886c2dSclaudio } 95504886c2dSclaudio } 956