1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 /*
30  * University Copyright- Copyright (c) 1982, 1986, 1988
31  * The Regents of the University of California
32  * All Rights Reserved
33  *
34  * University Acknowledgment- Portions of this document are derived from
35  * software developed by the University of California, Berkeley, and its
36  * contributors.
37  */
38 
39 /*
40  * TLI-like function to send datagrams over a specified
41  * transport endpoint.
42  *
43  * Returns:
44  * 	0 on success or positive error code.
45  */
46 
47 #include <sys/param.h>
48 #include <sys/types.h>
49 #include <sys/user.h>
50 #include <sys/file.h>
51 #include <sys/errno.h>
52 #include <sys/stream.h>
53 #include <sys/strsubr.h>
54 #include <sys/vnode.h>
55 #include <sys/ioctl.h>
56 #include <sys/stropts.h>
57 #include <sys/tihdr.h>
58 #include <sys/timod.h>
59 #include <sys/tiuser.h>
60 #include <sys/t_kuser.h>
61 #include <sys/debug.h>
62 
63 
64 int
t_ksndudata(TIUSER * tiptr,struct t_kunitdata * unitdata,frtn_t * frtn)65 t_ksndudata(TIUSER *tiptr, struct t_kunitdata *unitdata, frtn_t *frtn)
66 {
67 	int			msgsz;
68 	file_t			*fp;
69 	mblk_t			*bp;
70 	mblk_t			*dbp;
71 	struct T_unitdata_req	*udreq;
72 	int			error;
73 	int			flag;
74 
75 	error = 0;
76 	fp = tiptr->fp;
77 	msgsz = unitdata->udata.len;
78 
79 	/*
80 	 * See if Class 0 is required
81 	 */
82 	if (frtn != NULL) {
83 		ASSERT(unitdata->udata.udata_mp == NULL);
84 		ASSERT(unitdata->udata.buf != NULL);
85 		/*
86 		 * user has supplied their own buffer, all we have to
87 		 * do is allocate a class 0 streams buffer and set it
88 		 * up.
89 		 */
90 		if ((dbp = (mblk_t *)esballoc((uchar_t *)unitdata->udata.buf,
91 		    (size_t)msgsz, BPRI_LO, frtn)) == NULL)
92 			return (ENOSR);
93 
94 		dbp->b_datap->db_type = M_DATA;
95 		KTLILOG(2, "t_ksndudata: bp %x, ", dbp);
96 		KTLILOG(2, "len %d, ", msgsz);
97 		KTLILOG(2, "free func %x\n", frtn->free_func);
98 
99 	} else if (unitdata->udata.buf) {
100 		ASSERT(unitdata->udata.udata_mp == NULL);
101 		while (!(dbp = allocb(msgsz, BPRI_LO)))
102 			if (strwaitbuf((size_t)msgsz, BPRI_LO))
103 				return (ENOSR);
104 
105 		bcopy(unitdata->udata.buf, dbp->b_wptr, unitdata->udata.len);
106 		dbp->b_datap->db_type = M_DATA;
107 
108 	} else if (unitdata->udata.udata_mp) {
109 		ASSERT(unitdata->udata.buf == NULL);
110 		/*
111 		 * user has done it all
112 		 */
113 		dbp = unitdata->udata.udata_mp;
114 		goto gotdp;
115 
116 	} else {
117 		/*
118 		 * zero length message.
119 		 */
120 		dbp = NULL;
121 	}
122 
123 	if (dbp)
124 		dbp->b_wptr += msgsz;		/* on behalf of the user */
125 
126 	/*
127 	 * Okay, put the control part in
128 	 */
129 gotdp:
130 	msgsz = (int)TUNITDATAREQSZ;
131 	/*
132 	 * Usually sendto()s are performed with the credential of the caller;
133 	 * in this particular case we specifically use the credential of
134 	 * the opener as this call is typically done in the context of a user
135 	 * process but on behalf of the kernel, e.g., a client connection
136 	 * to a server which is later shared by different users.
137 	 * At open time, we make sure to set fp->f_cred to kcred if such is
138 	 * the case.
139 	 *
140 	 * Note: if the receiver uses SCM_UCRED/getpeerucred the pid will
141 	 * appear as -1.
142 	 */
143 	while (!(bp = allocb_cred(msgsz + unitdata->addr.len +
144 	    unitdata->opt.len, fp->f_cred, NOPID))) {
145 		if (strwaitbuf(msgsz + unitdata->addr.len + unitdata->opt.len,
146 		    BPRI_LO)) {
147 			if (dbp && (dbp != unitdata->udata.udata_mp))
148 				freeb(dbp);
149 			return (ENOSR);
150 		}
151 	}
152 
153 	/* LINTED pointer alignment */
154 	udreq = (struct T_unitdata_req *)bp->b_wptr;
155 	udreq->PRIM_type = T_UNITDATA_REQ;
156 	udreq->DEST_length = unitdata->addr.len;
157 	if (unitdata->addr.len) {
158 		bcopy(unitdata->addr.buf, bp->b_wptr + msgsz,
159 		    unitdata->addr.len);
160 		udreq->DEST_offset = (t_scalar_t)msgsz;
161 		msgsz += unitdata->addr.len;
162 	} else
163 		udreq->DEST_offset = 0;
164 
165 	udreq->OPT_length = unitdata->opt.len;
166 	if (unitdata->opt.len) {
167 		bcopy(unitdata->opt.buf, bp->b_wptr + msgsz, unitdata->opt.len);
168 		udreq->OPT_offset = (t_scalar_t)msgsz;
169 		msgsz += unitdata->opt.len;
170 	} else
171 		udreq->OPT_offset = 0;
172 
173 	bp->b_datap->db_type = M_PROTO;
174 	bp->b_wptr += msgsz;
175 
176 	/*
177 	 * link the two.
178 	 */
179 	linkb(bp, dbp);
180 
181 	/*
182 	 * Put it to the transport provider.
183 	 * tli_send() always consumes the message.
184 	 */
185 	flag = fp->f_flag;
186 	error = tli_send(tiptr, bp, flag);
187 	unitdata->udata.udata_mp = NULL;
188 
189 	return (error);
190 }
191