/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * University Copyright- Copyright (c) 1982, 1986, 1988 * The Regents of the University of California * All Rights Reserved * * University Acknowledgment- Portions of this document are derived from * software developed by the University of California, Berkeley, and its * contributors. */ /* * TLI-like function to send datagrams over a specified * transport endpoint. * * Returns: * 0 on success or positive error code. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int t_ksndudata(TIUSER *tiptr, struct t_kunitdata *unitdata, frtn_t *frtn) { int msgsz; file_t *fp; mblk_t *bp; mblk_t *dbp; struct T_unitdata_req *udreq; int error; int flag; error = 0; fp = tiptr->fp; msgsz = unitdata->udata.len; /* * See if Class 0 is required */ if (frtn != NULL) { ASSERT(unitdata->udata.udata_mp == NULL); ASSERT(unitdata->udata.buf != NULL); /* * user has supplied their own buffer, all we have to * do is allocate a class 0 streams buffer and set it * up. */ if ((dbp = (mblk_t *)esballoc((uchar_t *)unitdata->udata.buf, (size_t)msgsz, BPRI_LO, frtn)) == NULL) return (ENOSR); dbp->b_datap->db_type = M_DATA; KTLILOG(2, "t_ksndudata: bp %x, ", dbp); KTLILOG(2, "len %d, ", msgsz); KTLILOG(2, "free func %x\n", frtn->free_func); } else if (unitdata->udata.buf) { ASSERT(unitdata->udata.udata_mp == NULL); while (!(dbp = allocb(msgsz, BPRI_LO))) if (strwaitbuf((size_t)msgsz, BPRI_LO)) return (ENOSR); bcopy(unitdata->udata.buf, dbp->b_wptr, unitdata->udata.len); dbp->b_datap->db_type = M_DATA; } else if (unitdata->udata.udata_mp) { ASSERT(unitdata->udata.buf == NULL); /* * user has done it all */ dbp = unitdata->udata.udata_mp; goto gotdp; } else { /* * zero length message. */ dbp = NULL; } if (dbp) dbp->b_wptr += msgsz; /* on behalf of the user */ /* * Okay, put the control part in */ gotdp: msgsz = (int)TUNITDATAREQSZ; /* * Usually sendto()s are performed with the credential of the caller; * in this particular case we specifically use the credential of * the opener as this call is typically done in the context of a user * process but on behalf of the kernel, e.g., a client connection * to a server which is later shared by different users. * At open time, we make sure to set fp->f_cred to kcred if such is * the case. * * Note: if the receiver uses SCM_UCRED/getpeerucred the pid will * appear as -1. */ while (!(bp = allocb_cred(msgsz + unitdata->addr.len + unitdata->opt.len, fp->f_cred, NOPID))) { if (strwaitbuf(msgsz + unitdata->addr.len + unitdata->opt.len, BPRI_LO)) { if (dbp && (dbp != unitdata->udata.udata_mp)) freeb(dbp); return (ENOSR); } } /* LINTED pointer alignment */ udreq = (struct T_unitdata_req *)bp->b_wptr; udreq->PRIM_type = T_UNITDATA_REQ; udreq->DEST_length = unitdata->addr.len; if (unitdata->addr.len) { bcopy(unitdata->addr.buf, bp->b_wptr + msgsz, unitdata->addr.len); udreq->DEST_offset = (t_scalar_t)msgsz; msgsz += unitdata->addr.len; } else udreq->DEST_offset = 0; udreq->OPT_length = unitdata->opt.len; if (unitdata->opt.len) { bcopy(unitdata->opt.buf, bp->b_wptr + msgsz, unitdata->opt.len); udreq->OPT_offset = (t_scalar_t)msgsz; msgsz += unitdata->opt.len; } else udreq->OPT_offset = 0; bp->b_datap->db_type = M_PROTO; bp->b_wptr += msgsz; /* * link the two. */ linkb(bp, dbp); /* * Put it to the transport provider. * tli_send() always consumes the message. */ flag = fp->f_flag; error = tli_send(tiptr, bp, flag); unitdata->udata.udata_mp = NULL; return (error); }