19454b2d8SWarner Losh /*- 28a36da99SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 38a36da99SPedro F. Giffuni * 44784a469SIan Dowse * Copyright (c) 2003 Ian Dowse. All rights reserved. 54784a469SIan Dowse * 64784a469SIan Dowse * Redistribution and use in source and binary forms, with or without 74784a469SIan Dowse * modification, are permitted provided that the following conditions 84784a469SIan Dowse * are met: 94784a469SIan Dowse * 1. Redistributions of source code must retain the above copyright 104784a469SIan Dowse * notice, this list of conditions and the following disclaimer. 114784a469SIan Dowse * 2. Redistributions in binary form must reproduce the above copyright 124784a469SIan Dowse * notice, this list of conditions and the following disclaimer in the 134784a469SIan Dowse * documentation and/or other materials provided with the distribution. 144784a469SIan Dowse * 154784a469SIan Dowse * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 164784a469SIan Dowse * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 174784a469SIan Dowse * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 184784a469SIan Dowse * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 194784a469SIan Dowse * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 204784a469SIan Dowse * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 214784a469SIan Dowse * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 224784a469SIan Dowse * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 234784a469SIan Dowse * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 244784a469SIan Dowse * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 254784a469SIan Dowse * SUCH DAMAGE. 264784a469SIan Dowse * 274784a469SIan Dowse * $FreeBSD$ 284784a469SIan Dowse */ 294784a469SIan Dowse 304784a469SIan Dowse /* 314784a469SIan Dowse * Generic message buffer support routines. 324784a469SIan Dowse */ 334784a469SIan Dowse 344784a469SIan Dowse #include <sys/param.h> 354784a469SIan Dowse #include <sys/systm.h> 36d42a4eb5SKenneth D. Merry #include <sys/lock.h> 37f17a6f1bSEitan Adler #include <sys/kernel.h> 38d42a4eb5SKenneth D. Merry #include <sys/mutex.h> 394784a469SIan Dowse #include <sys/msgbuf.h> 40f17a6f1bSEitan Adler #include <sys/sysctl.h> 414784a469SIan Dowse 42d42a4eb5SKenneth D. Merry /* 43d42a4eb5SKenneth D. Merry * Maximum number conversion buffer length: uintmax_t in base 2, plus <> 44d42a4eb5SKenneth D. Merry * around the priority, and a terminating NUL. 45d42a4eb5SKenneth D. Merry */ 46d42a4eb5SKenneth D. Merry #define MAXPRIBUF (sizeof(intmax_t) * NBBY + 3) 47d42a4eb5SKenneth D. Merry 484784a469SIan Dowse /* Read/write sequence numbers are modulo a multiple of the buffer size. */ 494784a469SIan Dowse #define SEQMOD(size) ((size) * 16) 504784a469SIan Dowse 514784a469SIan Dowse static u_int msgbuf_cksum(struct msgbuf *mbp); 524784a469SIan Dowse 534784a469SIan Dowse /* 5424c10828SEitan Adler * Timestamps in msgbuf are useful when trying to diagnose when core dumps 55e3043798SPedro F. Giffuni * or other actions occurred. 56f17a6f1bSEitan Adler */ 57f17a6f1bSEitan Adler static int msgbuf_show_timestamp = 0; 58af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, msgbuf_show_timestamp, CTLFLAG_RWTUN, 59f17a6f1bSEitan Adler &msgbuf_show_timestamp, 0, "Show timestamp in msgbuf"); 60f17a6f1bSEitan Adler 61f17a6f1bSEitan Adler /* 624784a469SIan Dowse * Initialize a message buffer of the specified size at the specified 634784a469SIan Dowse * location. This also zeros the buffer area. 644784a469SIan Dowse */ 654784a469SIan Dowse void 664784a469SIan Dowse msgbuf_init(struct msgbuf *mbp, void *ptr, int size) 674784a469SIan Dowse { 684784a469SIan Dowse 694784a469SIan Dowse mbp->msg_ptr = ptr; 704784a469SIan Dowse mbp->msg_size = size; 714784a469SIan Dowse mbp->msg_seqmod = SEQMOD(size); 724784a469SIan Dowse msgbuf_clear(mbp); 734784a469SIan Dowse mbp->msg_magic = MSG_MAGIC; 74d42a4eb5SKenneth D. Merry mbp->msg_lastpri = -1; 75f17a6f1bSEitan Adler mbp->msg_flags = 0; 76534917efSKenneth D. Merry bzero(&mbp->msg_lock, sizeof(mbp->msg_lock)); 77d42a4eb5SKenneth D. Merry mtx_init(&mbp->msg_lock, "msgbuf", NULL, MTX_SPIN); 784784a469SIan Dowse } 794784a469SIan Dowse 804784a469SIan Dowse /* 814784a469SIan Dowse * Reinitialize a message buffer, retaining its previous contents if 824784a469SIan Dowse * the size and checksum are correct. If the old contents cannot be 834784a469SIan Dowse * recovered, the message buffer is cleared. 844784a469SIan Dowse */ 854784a469SIan Dowse void 864784a469SIan Dowse msgbuf_reinit(struct msgbuf *mbp, void *ptr, int size) 874784a469SIan Dowse { 884784a469SIan Dowse u_int cksum; 894784a469SIan Dowse 904784a469SIan Dowse if (mbp->msg_magic != MSG_MAGIC || mbp->msg_size != size) { 914784a469SIan Dowse msgbuf_init(mbp, ptr, size); 924784a469SIan Dowse return; 934784a469SIan Dowse } 944784a469SIan Dowse mbp->msg_seqmod = SEQMOD(size); 954784a469SIan Dowse mbp->msg_wseq = MSGBUF_SEQNORM(mbp, mbp->msg_wseq); 964784a469SIan Dowse mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq); 974784a469SIan Dowse mbp->msg_ptr = ptr; 984784a469SIan Dowse cksum = msgbuf_cksum(mbp); 994784a469SIan Dowse if (cksum != mbp->msg_cksum) { 100ce914a08SPoul-Henning Kamp if (bootverbose) { 1014784a469SIan Dowse printf("msgbuf cksum mismatch (read %x, calc %x)\n", 1024784a469SIan Dowse mbp->msg_cksum, cksum); 103ce914a08SPoul-Henning Kamp printf("Old msgbuf not recovered\n"); 104ce914a08SPoul-Henning Kamp } 1054784a469SIan Dowse msgbuf_clear(mbp); 1064784a469SIan Dowse } 107d42a4eb5SKenneth D. Merry 108d42a4eb5SKenneth D. Merry mbp->msg_lastpri = -1; 109d42a4eb5SKenneth D. Merry /* Assume that the old message buffer didn't end in a newline. */ 110f17a6f1bSEitan Adler mbp->msg_flags |= MSGBUF_NEEDNL; 111534917efSKenneth D. Merry bzero(&mbp->msg_lock, sizeof(mbp->msg_lock)); 112d42a4eb5SKenneth D. Merry mtx_init(&mbp->msg_lock, "msgbuf", NULL, MTX_SPIN); 1134784a469SIan Dowse } 1144784a469SIan Dowse 1154784a469SIan Dowse /* 1164784a469SIan Dowse * Clear the message buffer. 1174784a469SIan Dowse */ 1184784a469SIan Dowse void 1194784a469SIan Dowse msgbuf_clear(struct msgbuf *mbp) 1204784a469SIan Dowse { 1214784a469SIan Dowse 1224784a469SIan Dowse bzero(mbp->msg_ptr, mbp->msg_size); 1234784a469SIan Dowse mbp->msg_wseq = 0; 1244784a469SIan Dowse mbp->msg_rseq = 0; 1254784a469SIan Dowse mbp->msg_cksum = 0; 1264784a469SIan Dowse } 1274784a469SIan Dowse 1284784a469SIan Dowse /* 1294784a469SIan Dowse * Get a count of the number of unread characters in the message buffer. 1304784a469SIan Dowse */ 1314784a469SIan Dowse int 1324784a469SIan Dowse msgbuf_getcount(struct msgbuf *mbp) 1334784a469SIan Dowse { 1344784a469SIan Dowse u_int len; 1354784a469SIan Dowse 1364784a469SIan Dowse len = MSGBUF_SEQSUB(mbp, mbp->msg_wseq, mbp->msg_rseq); 1374784a469SIan Dowse if (len > mbp->msg_size) 1384784a469SIan Dowse len = mbp->msg_size; 1394784a469SIan Dowse return (len); 1404784a469SIan Dowse } 1414784a469SIan Dowse 1424784a469SIan Dowse /* 143d42a4eb5SKenneth D. Merry * Add a character into the message buffer, and update the checksum and 144d42a4eb5SKenneth D. Merry * sequence number. 145d42a4eb5SKenneth D. Merry * 146d42a4eb5SKenneth D. Merry * The caller should hold the message buffer spinlock. 147d42a4eb5SKenneth D. Merry */ 14824c10828SEitan Adler 14924c10828SEitan Adler static void 15024c10828SEitan Adler msgbuf_do_addchar(struct msgbuf * const mbp, u_int * const seq, const int c) 151d42a4eb5SKenneth D. Merry { 152d42a4eb5SKenneth D. Merry u_int pos; 153d42a4eb5SKenneth D. Merry 154d42a4eb5SKenneth D. Merry /* Make sure we properly wrap the sequence number. */ 155d42a4eb5SKenneth D. Merry pos = MSGBUF_SEQ_TO_POS(mbp, *seq); 15624c10828SEitan Adler mbp->msg_cksum += (u_int)(u_char)c - 157d42a4eb5SKenneth D. Merry (u_int)(u_char)mbp->msg_ptr[pos]; 158d42a4eb5SKenneth D. Merry mbp->msg_ptr[pos] = c; 159d42a4eb5SKenneth D. Merry *seq = MSGBUF_SEQNORM(mbp, *seq + 1); 160d42a4eb5SKenneth D. Merry } 161d42a4eb5SKenneth D. Merry 162d42a4eb5SKenneth D. Merry /* 163d42a4eb5SKenneth D. Merry * Append a character to a message buffer. 1644784a469SIan Dowse */ 1654784a469SIan Dowse void 1664784a469SIan Dowse msgbuf_addchar(struct msgbuf *mbp, int c) 1674784a469SIan Dowse { 168d42a4eb5SKenneth D. Merry mtx_lock_spin(&mbp->msg_lock); 1694784a469SIan Dowse 170d42a4eb5SKenneth D. Merry msgbuf_do_addchar(mbp, &mbp->msg_wseq, c); 171d42a4eb5SKenneth D. Merry 172d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 173d42a4eb5SKenneth D. Merry } 174d42a4eb5SKenneth D. Merry 175d42a4eb5SKenneth D. Merry /* 176d42a4eb5SKenneth D. Merry * Append a NUL-terminated string with a priority to a message buffer. 177d42a4eb5SKenneth D. Merry * Filter carriage returns if the caller requests it. 178d42a4eb5SKenneth D. Merry * 179d42a4eb5SKenneth D. Merry * XXX The carriage return filtering behavior is present in the 180d42a4eb5SKenneth D. Merry * msglogchar() API, however testing has shown that we don't seem to send 181d42a4eb5SKenneth D. Merry * carriage returns down this path. So do we still need it? 182d42a4eb5SKenneth D. Merry */ 183d42a4eb5SKenneth D. Merry void 18421aa6e83SKyle Evans msgbuf_addstr(struct msgbuf *mbp, int pri, const char *str, int filter_cr) 185d42a4eb5SKenneth D. Merry { 186d42a4eb5SKenneth D. Merry u_int seq; 187d42a4eb5SKenneth D. Merry size_t len, prefix_len; 188d42a4eb5SKenneth D. Merry char prefix[MAXPRIBUF]; 18924c10828SEitan Adler char buf[32]; 190151ba793SAlexander Kabaev int i, j, needtime; 191d42a4eb5SKenneth D. Merry 192d42a4eb5SKenneth D. Merry len = strlen(str); 193d42a4eb5SKenneth D. Merry prefix_len = 0; 194d42a4eb5SKenneth D. Merry 195d42a4eb5SKenneth D. Merry /* If we have a zero-length string, no need to do anything. */ 196d42a4eb5SKenneth D. Merry if (len == 0) 197d42a4eb5SKenneth D. Merry return; 198d42a4eb5SKenneth D. Merry 199d42a4eb5SKenneth D. Merry mtx_lock_spin(&mbp->msg_lock); 200d42a4eb5SKenneth D. Merry 201d42a4eb5SKenneth D. Merry /* 202d42a4eb5SKenneth D. Merry * If this is true, we may need to insert a new priority sequence, 203d42a4eb5SKenneth D. Merry * so prepare the prefix. 204d42a4eb5SKenneth D. Merry */ 205d42a4eb5SKenneth D. Merry if (pri != -1) 206d42a4eb5SKenneth D. Merry prefix_len = sprintf(prefix, "<%d>", pri); 207d42a4eb5SKenneth D. Merry 208d42a4eb5SKenneth D. Merry /* 209d42a4eb5SKenneth D. Merry * Starting write sequence number. 210d42a4eb5SKenneth D. Merry */ 2114784a469SIan Dowse seq = mbp->msg_wseq; 212d42a4eb5SKenneth D. Merry 213d42a4eb5SKenneth D. Merry /* 214d42a4eb5SKenneth D. Merry * Whenever there is a change in priority, we have to insert a 215d42a4eb5SKenneth D. Merry * newline, and a priority prefix if the priority is not -1. Here 216d42a4eb5SKenneth D. Merry * we detect whether there was a priority change, and whether we 217d42a4eb5SKenneth D. Merry * did not end with a newline. If that is the case, we need to 218d42a4eb5SKenneth D. Merry * insert a newline before this string. 219d42a4eb5SKenneth D. Merry */ 220f17a6f1bSEitan Adler if (mbp->msg_lastpri != pri && (mbp->msg_flags & MSGBUF_NEEDNL) != 0) { 221d42a4eb5SKenneth D. Merry 222d42a4eb5SKenneth D. Merry msgbuf_do_addchar(mbp, &seq, '\n'); 223f17a6f1bSEitan Adler mbp->msg_flags &= ~MSGBUF_NEEDNL; 224d42a4eb5SKenneth D. Merry } 225d42a4eb5SKenneth D. Merry 22624c10828SEitan Adler needtime = 1; 227d42a4eb5SKenneth D. Merry for (i = 0; i < len; i++) { 228d42a4eb5SKenneth D. Merry /* 229d42a4eb5SKenneth D. Merry * If we just had a newline, and the priority is not -1 230d42a4eb5SKenneth D. Merry * (and therefore prefix_len != 0), then we need a priority 231d42a4eb5SKenneth D. Merry * prefix for this line. 232d42a4eb5SKenneth D. Merry */ 233f17a6f1bSEitan Adler if ((mbp->msg_flags & MSGBUF_NEEDNL) == 0 && prefix_len != 0) { 234d42a4eb5SKenneth D. Merry int j; 235d42a4eb5SKenneth D. Merry 236d42a4eb5SKenneth D. Merry for (j = 0; j < prefix_len; j++) 237d42a4eb5SKenneth D. Merry msgbuf_do_addchar(mbp, &seq, prefix[j]); 238d42a4eb5SKenneth D. Merry } 239d42a4eb5SKenneth D. Merry 24024c10828SEitan Adler if (msgbuf_show_timestamp && needtime == 1 && 24124c10828SEitan Adler (mbp->msg_flags & MSGBUF_NEEDNL) == 0) { 24224c10828SEitan Adler 24324c10828SEitan Adler snprintf(buf, sizeof(buf), "[%jd] ", 24424c10828SEitan Adler (intmax_t)time_uptime); 24524c10828SEitan Adler for (j = 0; buf[j] != '\0'; j++) 24624c10828SEitan Adler msgbuf_do_addchar(mbp, &seq, buf[j]); 24724c10828SEitan Adler needtime = 0; 24824c10828SEitan Adler } 24924c10828SEitan Adler 250d42a4eb5SKenneth D. Merry /* 251d42a4eb5SKenneth D. Merry * Don't copy carriage returns if the caller requested 252d42a4eb5SKenneth D. Merry * filtering. 253d42a4eb5SKenneth D. Merry * 254d42a4eb5SKenneth D. Merry * XXX This matches the behavior of msglogchar(), but is it 255d42a4eb5SKenneth D. Merry * necessary? Testing has shown that we don't seem to get 256d42a4eb5SKenneth D. Merry * carriage returns here. 257d42a4eb5SKenneth D. Merry */ 258d42a4eb5SKenneth D. Merry if ((filter_cr != 0) && (str[i] == '\r')) 259d42a4eb5SKenneth D. Merry continue; 260d42a4eb5SKenneth D. Merry 261d42a4eb5SKenneth D. Merry /* 262d42a4eb5SKenneth D. Merry * Clear this flag if we see a newline. This affects whether 263d42a4eb5SKenneth D. Merry * we need to insert a new prefix or insert a newline later. 264d42a4eb5SKenneth D. Merry */ 265d42a4eb5SKenneth D. Merry if (str[i] == '\n') 266f17a6f1bSEitan Adler mbp->msg_flags &= ~MSGBUF_NEEDNL; 267d42a4eb5SKenneth D. Merry else 268f17a6f1bSEitan Adler mbp->msg_flags |= MSGBUF_NEEDNL; 269d42a4eb5SKenneth D. Merry 270d42a4eb5SKenneth D. Merry msgbuf_do_addchar(mbp, &seq, str[i]); 271d42a4eb5SKenneth D. Merry } 272d42a4eb5SKenneth D. Merry /* 273d42a4eb5SKenneth D. Merry * Update the write sequence number for the actual number of 274d42a4eb5SKenneth D. Merry * characters we put in the message buffer. (Depends on whether 275d42a4eb5SKenneth D. Merry * carriage returns are filtered.) 276d42a4eb5SKenneth D. Merry */ 277d42a4eb5SKenneth D. Merry mbp->msg_wseq = seq; 278d42a4eb5SKenneth D. Merry 279d42a4eb5SKenneth D. Merry /* 280d42a4eb5SKenneth D. Merry * Set the last priority. 281d42a4eb5SKenneth D. Merry */ 282d42a4eb5SKenneth D. Merry mbp->msg_lastpri = pri; 283d42a4eb5SKenneth D. Merry 284d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 285d42a4eb5SKenneth D. Merry 2864784a469SIan Dowse } 2874784a469SIan Dowse 2884784a469SIan Dowse /* 2894784a469SIan Dowse * Read and mark as read a character from a message buffer. 2904784a469SIan Dowse * Returns the character, or -1 if no characters are available. 2914784a469SIan Dowse */ 2924784a469SIan Dowse int 2934784a469SIan Dowse msgbuf_getchar(struct msgbuf *mbp) 2944784a469SIan Dowse { 2954784a469SIan Dowse u_int len, wseq; 2964784a469SIan Dowse int c; 2974784a469SIan Dowse 298d42a4eb5SKenneth D. Merry mtx_lock_spin(&mbp->msg_lock); 299d42a4eb5SKenneth D. Merry 3004784a469SIan Dowse wseq = mbp->msg_wseq; 3014784a469SIan Dowse len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq); 302d42a4eb5SKenneth D. Merry if (len == 0) { 303d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 3044784a469SIan Dowse return (-1); 305d42a4eb5SKenneth D. Merry } 3064784a469SIan Dowse if (len > mbp->msg_size) 3074784a469SIan Dowse mbp->msg_rseq = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size); 3084784a469SIan Dowse c = (u_char)mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq)]; 3094784a469SIan Dowse mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq + 1); 310d42a4eb5SKenneth D. Merry 311d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 312d42a4eb5SKenneth D. Merry 3134784a469SIan Dowse return (c); 3144784a469SIan Dowse } 3154784a469SIan Dowse 3164784a469SIan Dowse /* 3174784a469SIan Dowse * Read and mark as read a number of characters from a message buffer. 3184784a469SIan Dowse * Returns the number of characters that were placed in `buf'. 3194784a469SIan Dowse */ 3204784a469SIan Dowse int 3214784a469SIan Dowse msgbuf_getbytes(struct msgbuf *mbp, char *buf, int buflen) 3224784a469SIan Dowse { 3234784a469SIan Dowse u_int len, pos, wseq; 3244784a469SIan Dowse 325d42a4eb5SKenneth D. Merry mtx_lock_spin(&mbp->msg_lock); 326d42a4eb5SKenneth D. Merry 3274784a469SIan Dowse wseq = mbp->msg_wseq; 3284784a469SIan Dowse len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq); 329d42a4eb5SKenneth D. Merry if (len == 0) { 330d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 3314784a469SIan Dowse return (0); 332d42a4eb5SKenneth D. Merry } 3334784a469SIan Dowse if (len > mbp->msg_size) { 3344784a469SIan Dowse mbp->msg_rseq = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size); 3354784a469SIan Dowse len = mbp->msg_size; 3364784a469SIan Dowse } 3374784a469SIan Dowse pos = MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq); 3384784a469SIan Dowse len = min(len, mbp->msg_size - pos); 3394784a469SIan Dowse len = min(len, (u_int)buflen); 3404784a469SIan Dowse 3414784a469SIan Dowse bcopy(&mbp->msg_ptr[pos], buf, len); 3424784a469SIan Dowse mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq + len); 343d42a4eb5SKenneth D. Merry 344d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 345d42a4eb5SKenneth D. Merry 3464784a469SIan Dowse return (len); 3474784a469SIan Dowse } 3484784a469SIan Dowse 3494784a469SIan Dowse /* 3504784a469SIan Dowse * Peek at the full contents of a message buffer without marking any 3514784a469SIan Dowse * data as read. `seqp' should point to an unsigned integer that 3524784a469SIan Dowse * msgbuf_peekbytes() can use to retain state between calls so that 3534784a469SIan Dowse * the whole message buffer can be read in multiple short reads. 3544784a469SIan Dowse * To initialise this variable to the start of the message buffer, 3554784a469SIan Dowse * call msgbuf_peekbytes() with a NULL `buf' parameter. 3564784a469SIan Dowse * 3574784a469SIan Dowse * Returns the number of characters that were placed in `buf'. 3584784a469SIan Dowse */ 3594784a469SIan Dowse int 3604784a469SIan Dowse msgbuf_peekbytes(struct msgbuf *mbp, char *buf, int buflen, u_int *seqp) 3614784a469SIan Dowse { 3624784a469SIan Dowse u_int len, pos, wseq; 3634784a469SIan Dowse 364d42a4eb5SKenneth D. Merry mtx_lock_spin(&mbp->msg_lock); 365d42a4eb5SKenneth D. Merry 3664784a469SIan Dowse if (buf == NULL) { 3674784a469SIan Dowse /* Just initialise *seqp. */ 3684784a469SIan Dowse *seqp = MSGBUF_SEQNORM(mbp, mbp->msg_wseq - mbp->msg_size); 369d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 3704784a469SIan Dowse return (0); 3714784a469SIan Dowse } 3724784a469SIan Dowse 3734784a469SIan Dowse wseq = mbp->msg_wseq; 3744784a469SIan Dowse len = MSGBUF_SEQSUB(mbp, wseq, *seqp); 375d42a4eb5SKenneth D. Merry if (len == 0) { 376d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 3774784a469SIan Dowse return (0); 378d42a4eb5SKenneth D. Merry } 3794784a469SIan Dowse if (len > mbp->msg_size) { 3804784a469SIan Dowse *seqp = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size); 3814784a469SIan Dowse len = mbp->msg_size; 3824784a469SIan Dowse } 3834784a469SIan Dowse pos = MSGBUF_SEQ_TO_POS(mbp, *seqp); 3844784a469SIan Dowse len = min(len, mbp->msg_size - pos); 3854784a469SIan Dowse len = min(len, (u_int)buflen); 3864784a469SIan Dowse bcopy(&mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, *seqp)], buf, len); 3874784a469SIan Dowse *seqp = MSGBUF_SEQNORM(mbp, *seqp + len); 388d42a4eb5SKenneth D. Merry 389d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 390d42a4eb5SKenneth D. Merry 3914784a469SIan Dowse return (len); 3924784a469SIan Dowse } 3934784a469SIan Dowse 3944784a469SIan Dowse /* 3954784a469SIan Dowse * Compute the checksum for the complete message buffer contents. 3964784a469SIan Dowse */ 3974784a469SIan Dowse static u_int 3984784a469SIan Dowse msgbuf_cksum(struct msgbuf *mbp) 3994784a469SIan Dowse { 4004784a469SIan Dowse u_int i, sum; 4014784a469SIan Dowse 4024784a469SIan Dowse sum = 0; 4034784a469SIan Dowse for (i = 0; i < mbp->msg_size; i++) 4044784a469SIan Dowse sum += (u_char)mbp->msg_ptr[i]; 4054784a469SIan Dowse return (sum); 4064784a469SIan Dowse } 4074784a469SIan Dowse 4084784a469SIan Dowse /* 4094784a469SIan Dowse * Copy from one message buffer to another. 4104784a469SIan Dowse */ 4114784a469SIan Dowse void 4124784a469SIan Dowse msgbuf_copy(struct msgbuf *src, struct msgbuf *dst) 4134784a469SIan Dowse { 4144784a469SIan Dowse int c; 4154784a469SIan Dowse 4164784a469SIan Dowse while ((c = msgbuf_getchar(src)) >= 0) 4174784a469SIan Dowse msgbuf_addchar(dst, c); 4184784a469SIan Dowse } 419