1*f8e180f0Sclaudio /* $OpenBSD: pdu.c,v 1.15 2025/01/23 12:17:48 claudio Exp $ */ 2bde1ae23Sclaudio 3bde1ae23Sclaudio /* 4bde1ae23Sclaudio * Copyright (c) 2009 Claudio Jeker <claudio@openbsd.org> 5bde1ae23Sclaudio * 6bde1ae23Sclaudio * Permission to use, copy, modify, and distribute this software for any 7bde1ae23Sclaudio * purpose with or without fee is hereby granted, provided that the above 8bde1ae23Sclaudio * copyright notice and this permission notice appear in all copies. 9bde1ae23Sclaudio * 10bde1ae23Sclaudio * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11bde1ae23Sclaudio * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12bde1ae23Sclaudio * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13bde1ae23Sclaudio * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14bde1ae23Sclaudio * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15bde1ae23Sclaudio * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16bde1ae23Sclaudio * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17bde1ae23Sclaudio */ 18bde1ae23Sclaudio #include <sys/types.h> 19bde1ae23Sclaudio #include <sys/queue.h> 20bde1ae23Sclaudio #include <sys/socket.h> 21bde1ae23Sclaudio #include <sys/uio.h> 22bde1ae23Sclaudio 23bde1ae23Sclaudio #include <scsi/iscsi.h> 24bde1ae23Sclaudio 25bde1ae23Sclaudio #include <errno.h> 26bde1ae23Sclaudio #include <event.h> 274125a3c4Sclaudio #include <limits.h> 28bde1ae23Sclaudio #include <stdio.h> 29bde1ae23Sclaudio #include <stdlib.h> 302f43ab01Smmcc #include <string.h> 31bde1ae23Sclaudio #include <unistd.h> 32bde1ae23Sclaudio 33bde1ae23Sclaudio #include "iscsid.h" 34bde1ae23Sclaudio #include "log.h" 35bde1ae23Sclaudio 36bde1ae23Sclaudio size_t pdu_readbuf_read(struct pdu_readbuf *, void *, size_t); 37bde1ae23Sclaudio size_t pdu_readbuf_len(struct pdu_readbuf *); 38bde1ae23Sclaudio 39bde1ae23Sclaudio #define PDU_MIN(_x, _y) ((_x) < (_y) ? (_x) : (_y)) 40bde1ae23Sclaudio 41bde1ae23Sclaudio void * 42bde1ae23Sclaudio pdu_gethdr(struct pdu *p) 43bde1ae23Sclaudio { 44bde1ae23Sclaudio void *hdr; 45bde1ae23Sclaudio 46bde1ae23Sclaudio if (!(hdr = calloc(1, sizeof(struct iscsi_pdu)))) 47bde1ae23Sclaudio return NULL; 48bde1ae23Sclaudio if (pdu_addbuf(p, hdr, sizeof(struct iscsi_pdu), PDU_HEADER)) { 49bde1ae23Sclaudio free(hdr); 50bde1ae23Sclaudio return NULL; 51bde1ae23Sclaudio } 52bde1ae23Sclaudio return hdr; 53bde1ae23Sclaudio } 54bde1ae23Sclaudio 55bde1ae23Sclaudio int 56bde1ae23Sclaudio text_to_pdu(struct kvp *k, struct pdu *p) 57bde1ae23Sclaudio { 58bde1ae23Sclaudio char *buf, *s; 59bde1ae23Sclaudio size_t len = 0, rem; 60bde1ae23Sclaudio int n, nk; 61bde1ae23Sclaudio 624125a3c4Sclaudio if (k == NULL) 63be16f395Sclaudio return 0; 644125a3c4Sclaudio 65bde1ae23Sclaudio nk = 0; 66bde1ae23Sclaudio while(k[nk].key) { 67bde1ae23Sclaudio len += 2 + strlen(k[nk].key) + strlen(k[nk].value); 68bde1ae23Sclaudio nk++; 69bde1ae23Sclaudio } 70bde1ae23Sclaudio 71bde1ae23Sclaudio if (!(buf = pdu_alloc(len))) 72bde1ae23Sclaudio return -1; 73bde1ae23Sclaudio s = buf; 74bde1ae23Sclaudio rem = len; 75bde1ae23Sclaudio nk = 0; 76bde1ae23Sclaudio while(k[nk].key) { 77bde1ae23Sclaudio n = snprintf(s, rem, "%s=%s", k[nk].key, k[nk].value); 78515e489cSderaadt if (n < 0 || (size_t)n >= rem) 79bde1ae23Sclaudio fatalx("text_to_pdu"); 80bde1ae23Sclaudio rem -= n + 1; 81bde1ae23Sclaudio s += n + 1; 82bde1ae23Sclaudio nk++; 83bde1ae23Sclaudio } 84bde1ae23Sclaudio 85bde1ae23Sclaudio if (pdu_addbuf(p, buf, len, PDU_DATA)) 86bde1ae23Sclaudio return -1; 87bde1ae23Sclaudio return len; 88bde1ae23Sclaudio } 89bde1ae23Sclaudio 90bde1ae23Sclaudio struct kvp * 91bde1ae23Sclaudio pdu_to_text(char *buf, size_t len) 92bde1ae23Sclaudio { 93bde1ae23Sclaudio struct kvp *k; 94bde1ae23Sclaudio size_t n; 95bde1ae23Sclaudio char *eq; 96bde1ae23Sclaudio unsigned int nkvp = 0, i; 97bde1ae23Sclaudio 988b9a361cSclaudio /* remove padding zeros */ 99cb408c6cSclaudio for (n = len; n > 0 && buf[n - 1] == '\0'; n--) 1008b9a361cSclaudio ; 1018b9a361cSclaudio if (n == len) { 102bde1ae23Sclaudio log_debug("pdu_to_text: badly terminated text data"); 103bde1ae23Sclaudio return NULL; 104bde1ae23Sclaudio } 1058b9a361cSclaudio len = n + 1; 1068b9a361cSclaudio 107bde1ae23Sclaudio for(n = 0; n < len; n++) 108bde1ae23Sclaudio if (buf[n] == '\0') 109bde1ae23Sclaudio nkvp++; 110bde1ae23Sclaudio 111bde1ae23Sclaudio if (!(k = calloc(nkvp + 1, sizeof(*k)))) 112bde1ae23Sclaudio return NULL; 113bde1ae23Sclaudio 114bde1ae23Sclaudio for (i = 0; i < nkvp; i++) { 115bde1ae23Sclaudio eq = strchr(buf, '='); 116bde1ae23Sclaudio if (!eq) { 117bde1ae23Sclaudio log_debug("pdu_to_text: badly encoded text data"); 118bde1ae23Sclaudio free(k); 119bde1ae23Sclaudio return NULL; 120bde1ae23Sclaudio } 121bde1ae23Sclaudio *eq++ = '\0'; 122bde1ae23Sclaudio k[i].key = buf; 123bde1ae23Sclaudio k[i].value = eq; 124bde1ae23Sclaudio buf = eq + strlen(eq) + 1; 125bde1ae23Sclaudio } 126bde1ae23Sclaudio return k; 127bde1ae23Sclaudio } 128bde1ae23Sclaudio 1294125a3c4Sclaudio /* Modified version of strtonum() to fit iscsid's need 1304125a3c4Sclaudio * 1314125a3c4Sclaudio * Copyright (c) 2004 Ted Unangst and Todd Miller 1324125a3c4Sclaudio * All rights reserved. 1334125a3c4Sclaudio * 1344125a3c4Sclaudio * Permission to use, copy, modify, and distribute this software for any 1354125a3c4Sclaudio * purpose with or without fee is hereby granted, provided that the above 1364125a3c4Sclaudio * copyright notice and this permission notice appear in all copies. 1374125a3c4Sclaudio * 1384125a3c4Sclaudio * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1394125a3c4Sclaudio * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1404125a3c4Sclaudio * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1414125a3c4Sclaudio * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1424125a3c4Sclaudio * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1434125a3c4Sclaudio * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1444125a3c4Sclaudio * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1454125a3c4Sclaudio */ 1464125a3c4Sclaudio u_int64_t 1474125a3c4Sclaudio text_to_num(const char *numstr, u_int64_t minval, u_int64_t maxval, 1484125a3c4Sclaudio const char **errstrp) 1494125a3c4Sclaudio { 1504125a3c4Sclaudio unsigned long long ull = 0; 1514125a3c4Sclaudio char *ep; 1524125a3c4Sclaudio int error = 0; 1534125a3c4Sclaudio struct errval { 1544125a3c4Sclaudio const char *errstr; 1554125a3c4Sclaudio int err; 1564125a3c4Sclaudio } ev[4] = { 1574125a3c4Sclaudio { NULL, 0 }, 1584125a3c4Sclaudio { "invalid", EINVAL }, 1594125a3c4Sclaudio { "too small", ERANGE }, 1604125a3c4Sclaudio { "too large", ERANGE } 1614125a3c4Sclaudio }; 1624125a3c4Sclaudio #define INVALID 1 1634125a3c4Sclaudio #define TOOSMALL 2 1644125a3c4Sclaudio #define TOOLARGE 3 1654125a3c4Sclaudio 1664125a3c4Sclaudio ev[0].err = errno; 1674125a3c4Sclaudio errno = 0; 1684125a3c4Sclaudio if (minval > maxval) 1694125a3c4Sclaudio error = INVALID; 1704125a3c4Sclaudio else { 1714125a3c4Sclaudio ull = strtoull(numstr, &ep, 0); 1724125a3c4Sclaudio if (numstr == ep || *ep != '\0') 1734125a3c4Sclaudio error = INVALID; 1744125a3c4Sclaudio else if (ull < minval) 1754125a3c4Sclaudio error = TOOSMALL; 1764125a3c4Sclaudio else if ((ull == ULLONG_MAX && errno == ERANGE) || ull > maxval) 1774125a3c4Sclaudio error = TOOLARGE; 1784125a3c4Sclaudio } 1794125a3c4Sclaudio if (errstrp != NULL) 1804125a3c4Sclaudio *errstrp = ev[error].errstr; 1814125a3c4Sclaudio errno = ev[error].err; 1824125a3c4Sclaudio if (error) 1834125a3c4Sclaudio ull = 0; 1844125a3c4Sclaudio 185be16f395Sclaudio return ull; 1864125a3c4Sclaudio #undef INVALID 1874125a3c4Sclaudio #undef TOOSMALL 1884125a3c4Sclaudio #undef TOOLARGE 1894125a3c4Sclaudio } 1904125a3c4Sclaudio 1914125a3c4Sclaudio int 1924125a3c4Sclaudio text_to_bool(const char *buf, const char **errstrp) 1934125a3c4Sclaudio { 194*f8e180f0Sclaudio int val; 1954125a3c4Sclaudio 196aeec9c16Sclaudio if (strcmp(buf, "Yes") == 0) 1974125a3c4Sclaudio val = 1; 198*f8e180f0Sclaudio else if (strcmp(buf, "No") == 0) 199*f8e180f0Sclaudio val = 0; 200*f8e180f0Sclaudio else { 201aeec9c16Sclaudio if (errstrp != NULL) 2024125a3c4Sclaudio *errstrp = "invalid"; 203*f8e180f0Sclaudio return 0; 2044125a3c4Sclaudio } 205*f8e180f0Sclaudio if (errstrp != NULL) 206*f8e180f0Sclaudio *errstrp = NULL; 207be16f395Sclaudio return val; 2084125a3c4Sclaudio } 2094125a3c4Sclaudio 210aeec9c16Sclaudio int 211aeec9c16Sclaudio text_to_digest(const char *buf, const char **errstrp) 212aeec9c16Sclaudio { 213aeec9c16Sclaudio int val = 0; 214aeec9c16Sclaudio size_t len; 215aeec9c16Sclaudio const char *p; 216aeec9c16Sclaudio 217aeec9c16Sclaudio while (buf != NULL) { 218aeec9c16Sclaudio p = strchr(buf, ','); 219aeec9c16Sclaudio if (p == NULL) 220aeec9c16Sclaudio len = strlen(buf); 221aeec9c16Sclaudio else 222aeec9c16Sclaudio len = p++ - buf; 223aeec9c16Sclaudio 224aeec9c16Sclaudio if (strncmp(buf, "None", len) == 0) 225aeec9c16Sclaudio val |= DIGEST_NONE; 226aeec9c16Sclaudio else if (strncmp(buf, "CRC32C", len) == 0) 227aeec9c16Sclaudio val |= DIGEST_CRC32C; 228aeec9c16Sclaudio else { 229aeec9c16Sclaudio if (errstrp != NULL) 230aeec9c16Sclaudio *errstrp = "invalid"; 231aeec9c16Sclaudio return 0; 232aeec9c16Sclaudio } 233aeec9c16Sclaudio buf = p; 234aeec9c16Sclaudio } 235*f8e180f0Sclaudio if (errstrp != NULL) 236*f8e180f0Sclaudio *errstrp = NULL; 237aeec9c16Sclaudio return val; 238aeec9c16Sclaudio } 2394125a3c4Sclaudio 240bde1ae23Sclaudio /* 241bde1ae23Sclaudio * Internal functions to send/recv pdus. 242bde1ae23Sclaudio */ 243bde1ae23Sclaudio 244bde1ae23Sclaudio void 245bde1ae23Sclaudio pdu_free_queue(struct pduq *channel) 246bde1ae23Sclaudio { 247bde1ae23Sclaudio struct pdu *p; 248bde1ae23Sclaudio 249bde1ae23Sclaudio while ((p = TAILQ_FIRST(channel))) { 250bde1ae23Sclaudio TAILQ_REMOVE(channel, p, entry); 251bde1ae23Sclaudio pdu_free(p); 252bde1ae23Sclaudio } 253bde1ae23Sclaudio } 254bde1ae23Sclaudio 255bde1ae23Sclaudio ssize_t 256bde1ae23Sclaudio pdu_read(struct connection *c) 257bde1ae23Sclaudio { 258bde1ae23Sclaudio struct iovec iov[2]; 259bde1ae23Sclaudio unsigned int niov = 1; 260bde1ae23Sclaudio ssize_t n; 261bde1ae23Sclaudio 262bde1ae23Sclaudio bzero(&iov, sizeof(iov)); 263bde1ae23Sclaudio iov[0].iov_base = c->prbuf.buf + c->prbuf.wpos; 264bde1ae23Sclaudio if (c->prbuf.wpos < c->prbuf.rpos) 265bde1ae23Sclaudio iov[0].iov_len = c->prbuf.rpos - c->prbuf.wpos; 266bde1ae23Sclaudio else { 267bde1ae23Sclaudio iov[0].iov_len = c->prbuf.size - c->prbuf.wpos; 268bde1ae23Sclaudio if (c->prbuf.rpos > 0) { 269bde1ae23Sclaudio niov++; 270bde1ae23Sclaudio iov[1].iov_base = c->prbuf.buf; 271bde1ae23Sclaudio iov[1].iov_len = c->prbuf.rpos - 1; 272bde1ae23Sclaudio } 273bde1ae23Sclaudio } 274bde1ae23Sclaudio 275f9cc11ecSclaudio if ((n = readv(c->fd, iov, niov)) == -1) 276bde1ae23Sclaudio return -1; 277bde1ae23Sclaudio if (n == 0) 278bde1ae23Sclaudio /* XXX what should we do on close with remaining data? */ 279bde1ae23Sclaudio return 0; 280bde1ae23Sclaudio 281bde1ae23Sclaudio c->prbuf.wpos += n; 282bde1ae23Sclaudio if (c->prbuf.wpos >= c->prbuf.size) 283bde1ae23Sclaudio c->prbuf.wpos -= c->prbuf.size; 284bde1ae23Sclaudio 285be16f395Sclaudio return n; 286bde1ae23Sclaudio } 287bde1ae23Sclaudio 288bde1ae23Sclaudio ssize_t 289bde1ae23Sclaudio pdu_write(struct connection *c) 290bde1ae23Sclaudio { 291bde1ae23Sclaudio struct iovec iov[PDU_WRIOV]; 292bde1ae23Sclaudio struct pdu *b, *nb; 293bde1ae23Sclaudio unsigned int niov = 0, j; 294bde1ae23Sclaudio size_t off, resid, size; 295bde1ae23Sclaudio ssize_t n; 296bde1ae23Sclaudio 297bde1ae23Sclaudio TAILQ_FOREACH(b, &c->pdu_w, entry) { 298bde1ae23Sclaudio if (niov >= PDU_WRIOV) 299bde1ae23Sclaudio break; 300bde1ae23Sclaudio off = b->resid; 301bde1ae23Sclaudio for (j = 0; j < PDU_MAXIOV && niov < PDU_WRIOV; j++) { 302bde1ae23Sclaudio if (!b->iov[j].iov_len) 303bde1ae23Sclaudio continue; 304bde1ae23Sclaudio if (off >= b->iov[j].iov_len) { 305bde1ae23Sclaudio off -= b->iov[j].iov_len; 306bde1ae23Sclaudio continue; 307bde1ae23Sclaudio } 308bde1ae23Sclaudio iov[niov].iov_base = (char *)b->iov[j].iov_base + off; 309bde1ae23Sclaudio iov[niov++].iov_len = b->iov[j].iov_len - off; 310bde1ae23Sclaudio off = 0; 311bde1ae23Sclaudio } 312bde1ae23Sclaudio } 313bde1ae23Sclaudio 314bde1ae23Sclaudio if ((n = writev(c->fd, iov, niov)) == -1) { 315bde1ae23Sclaudio if (errno == EAGAIN || errno == ENOBUFS || 316bde1ae23Sclaudio errno == EINTR) /* try later */ 317bde1ae23Sclaudio return 0; 318bde1ae23Sclaudio else { 319bde1ae23Sclaudio log_warn("pdu_write"); 320bde1ae23Sclaudio return -1; 321bde1ae23Sclaudio } 322bde1ae23Sclaudio } 323bde1ae23Sclaudio if (n == 0) 324bde1ae23Sclaudio return 0; 325bde1ae23Sclaudio 326bde1ae23Sclaudio size = n; 327bde1ae23Sclaudio for (b = TAILQ_FIRST(&c->pdu_w); b != NULL && size > 0; b = nb) { 328bde1ae23Sclaudio nb = TAILQ_NEXT(b, entry); 329bde1ae23Sclaudio resid = b->resid; 330bde1ae23Sclaudio for (j = 0; j < PDU_MAXIOV; j++) { 331bde1ae23Sclaudio if (resid >= b->iov[j].iov_len) 332bde1ae23Sclaudio resid -= b->iov[j].iov_len; 333bde1ae23Sclaudio else if (size >= b->iov[j].iov_len - resid) { 334bde1ae23Sclaudio size -= b->iov[j].iov_len - resid; 335bde1ae23Sclaudio b->resid += b->iov[j].iov_len - resid; 336bde1ae23Sclaudio resid = 0; 337bde1ae23Sclaudio } else { 338bde1ae23Sclaudio b->resid += size; 339bde1ae23Sclaudio size = 0; 340bde1ae23Sclaudio break; 341bde1ae23Sclaudio } 342bde1ae23Sclaudio } 343bde1ae23Sclaudio if (j == PDU_MAXIOV) { 344bde1ae23Sclaudio /* all written */ 345bde1ae23Sclaudio TAILQ_REMOVE(&c->pdu_w, b, entry); 346bde1ae23Sclaudio pdu_free(b); 347bde1ae23Sclaudio } 348bde1ae23Sclaudio } 349bde1ae23Sclaudio return n; 350bde1ae23Sclaudio } 351bde1ae23Sclaudio 352bde1ae23Sclaudio int 353bde1ae23Sclaudio pdu_pending(struct connection *c) 354bde1ae23Sclaudio { 355bde1ae23Sclaudio if (TAILQ_EMPTY(&c->pdu_w)) 356bde1ae23Sclaudio return 0; 357bde1ae23Sclaudio else 358bde1ae23Sclaudio return 1; 359bde1ae23Sclaudio } 360bde1ae23Sclaudio 361bde1ae23Sclaudio void 362bde1ae23Sclaudio pdu_parse(struct connection *c) 363bde1ae23Sclaudio { 364bde1ae23Sclaudio struct pdu *p; 365bde1ae23Sclaudio struct iscsi_pdu *ipdu; 366bde1ae23Sclaudio char *ahb, *db; 367bde1ae23Sclaudio size_t ahslen, dlen, off; 368bde1ae23Sclaudio ssize_t n; 369bde1ae23Sclaudio unsigned int j; 370bde1ae23Sclaudio 371bde1ae23Sclaudio /* XXX XXX I DON'T LIKE YOU. CAN I REWRITE YOU? */ 372bde1ae23Sclaudio 373bde1ae23Sclaudio do { 374bde1ae23Sclaudio if (!(p = c->prbuf.wip)) { 375bde1ae23Sclaudio /* get and parse base header */ 376bde1ae23Sclaudio if (pdu_readbuf_len(&c->prbuf) < sizeof(*ipdu)) 377bde1ae23Sclaudio return; 378bde1ae23Sclaudio if (!(p = pdu_new())) 379bde1ae23Sclaudio goto fail; 380bde1ae23Sclaudio if (!(ipdu = pdu_gethdr(p))) 381bde1ae23Sclaudio goto fail; 382bde1ae23Sclaudio 383bde1ae23Sclaudio c->prbuf.wip = p; 384bde1ae23Sclaudio /* 385bde1ae23Sclaudio * XXX maybe a pdu_readbuf_peek() would allow a better 386bde1ae23Sclaudio * error handling. 387bde1ae23Sclaudio */ 388bde1ae23Sclaudio pdu_readbuf_read(&c->prbuf, ipdu, sizeof(*ipdu)); 389bde1ae23Sclaudio 390bde1ae23Sclaudio ahslen = ipdu->ahslen * sizeof(u_int32_t); 391bde1ae23Sclaudio if (ahslen != 0) { 392bde1ae23Sclaudio if (!(ahb = pdu_alloc(ahslen)) || 393bde1ae23Sclaudio pdu_addbuf(p, ahb, ahslen, PDU_AHS)) 394bde1ae23Sclaudio goto fail; 395bde1ae23Sclaudio } 396bde1ae23Sclaudio 397bde1ae23Sclaudio dlen = ipdu->datalen[0] << 16 | ipdu->datalen[1] << 8 | 398bde1ae23Sclaudio ipdu->datalen[2]; 399bde1ae23Sclaudio if (dlen != 0) { 400bde1ae23Sclaudio if (!(db = pdu_alloc(dlen)) || 401bde1ae23Sclaudio pdu_addbuf(p, db, dlen, PDU_DATA)) 402bde1ae23Sclaudio goto fail; 403bde1ae23Sclaudio } 404bde1ae23Sclaudio 405bde1ae23Sclaudio p->resid = sizeof(*ipdu); 406bde1ae23Sclaudio } else { 407bde1ae23Sclaudio off = p->resid; 408bde1ae23Sclaudio for (j = 0; j < PDU_MAXIOV; j++) { 409bde1ae23Sclaudio if (off >= p->iov[j].iov_len) 410bde1ae23Sclaudio off -= p->iov[j].iov_len; 411bde1ae23Sclaudio else { 412bde1ae23Sclaudio n = pdu_readbuf_read(&c->prbuf, 413bde1ae23Sclaudio (char *)p->iov[j].iov_base + off, 414bde1ae23Sclaudio p->iov[j].iov_len - off); 415bde1ae23Sclaudio p->resid += n; 416bde1ae23Sclaudio if (n == 0 || off + n != 417bde1ae23Sclaudio p->iov[j].iov_len) 418bde1ae23Sclaudio return; 419bde1ae23Sclaudio } 420bde1ae23Sclaudio } 4219decbecbSclaudio p->resid = 0; /* reset resid so pdu can be reused */ 422bde1ae23Sclaudio c->prbuf.wip = NULL; 4232337c7c9Sclaudio task_pdu_cb(c, p); 424bde1ae23Sclaudio } 425bde1ae23Sclaudio } while (1); 426bde1ae23Sclaudio fail: 427bde1ae23Sclaudio fatalx("pdu_parse hit a space oddity"); 428bde1ae23Sclaudio } 429bde1ae23Sclaudio 430bde1ae23Sclaudio size_t 431bde1ae23Sclaudio pdu_readbuf_read(struct pdu_readbuf *rb, void *ptr, size_t len) 432bde1ae23Sclaudio { 433bde1ae23Sclaudio size_t l; 434bde1ae23Sclaudio 435bde1ae23Sclaudio if (rb->rpos == rb->wpos) { 436be16f395Sclaudio return 0; 437bde1ae23Sclaudio } else if (rb->rpos < rb->wpos) { 438bde1ae23Sclaudio l = PDU_MIN(rb->wpos - rb->rpos, len); 439a86db512Sclaudio memcpy(ptr, rb->buf + rb->rpos, l); 440bde1ae23Sclaudio rb->rpos += l; 441bde1ae23Sclaudio return l; 442bde1ae23Sclaudio } else { 443bde1ae23Sclaudio l = PDU_MIN(rb->size - rb->rpos, len); 444a86db512Sclaudio memcpy(ptr, rb->buf + rb->rpos, l); 445bde1ae23Sclaudio rb->rpos += l; 446bde1ae23Sclaudio if (rb->rpos == rb->size) 447bde1ae23Sclaudio rb->rpos = 0; 448bde1ae23Sclaudio if (l < len) 449bde1ae23Sclaudio return l + pdu_readbuf_read(rb, (char *)ptr + l, 450bde1ae23Sclaudio len - l); 451bde1ae23Sclaudio return l; 452bde1ae23Sclaudio } 453bde1ae23Sclaudio } 454bde1ae23Sclaudio 455bde1ae23Sclaudio size_t 456bde1ae23Sclaudio pdu_readbuf_len(struct pdu_readbuf *rb) 457bde1ae23Sclaudio { 458bde1ae23Sclaudio if (rb->rpos <= rb->wpos) 459bde1ae23Sclaudio return rb->wpos - rb->rpos; 460bde1ae23Sclaudio else 461bde1ae23Sclaudio return rb->size - (rb->rpos - rb->wpos); 462bde1ae23Sclaudio } 463bde1ae23Sclaudio 464bde1ae23Sclaudio int 465bde1ae23Sclaudio pdu_readbuf_set(struct pdu_readbuf *rb, size_t bsize) 466bde1ae23Sclaudio { 467bde1ae23Sclaudio char *nb; 468bde1ae23Sclaudio 469bde1ae23Sclaudio if (bsize < rb->size) 470bde1ae23Sclaudio /* can't shrink */ 471bde1ae23Sclaudio return 0; 472bde1ae23Sclaudio if ((nb = realloc(rb->buf, bsize)) == NULL) { 473bde1ae23Sclaudio free(rb->buf); 474bde1ae23Sclaudio return -1; 475bde1ae23Sclaudio } 476bde1ae23Sclaudio rb->buf = nb; 477bde1ae23Sclaudio rb->size = bsize; 478bde1ae23Sclaudio return 0; 479bde1ae23Sclaudio } 480bde1ae23Sclaudio 481bde1ae23Sclaudio void 482bde1ae23Sclaudio pdu_readbuf_free(struct pdu_readbuf *rb) 483bde1ae23Sclaudio { 484bde1ae23Sclaudio free(rb->buf); 485bde1ae23Sclaudio } 486