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 * Kernel TLI-like function to allow a trasnport endpoint to initiate a 41 * connection to another transport endpoint. This function will wait for 42 * an ack and a T_CONN_CON before returning. 43 * 44 * Returns: 45 * 0 on success, and if rcvcall is non-NULL it shall be 46 * filled with the connection confirm data. 47 * Otherwise a positive error code. 48 */ 49 50 #include <sys/param.h> 51 #include <sys/types.h> 52 #include <sys/user.h> 53 #include <sys/file.h> 54 #include <sys/vnode.h> 55 #include <sys/errno.h> 56 #include <sys/stream.h> 57 #include <sys/ioctl.h> 58 #include <sys/stropts.h> 59 #include <sys/tihdr.h> 60 #include <sys/timod.h> 61 #include <sys/tiuser.h> 62 #include <sys/t_kuser.h> 63 #include <sys/strsubr.h> 64 #include <sys/sysmacros.h> 65 #include <sys/strsun.h> 66 67 68 int 69 t_kconnect(TIUSER *tiptr, struct t_call *sndcall, struct t_call *rcvcall) 70 { 71 int len; 72 int msgsz; 73 size_t hdrsz; 74 struct T_conn_req *creq; 75 union T_primitives *pptr; 76 mblk_t *nbp; 77 file_t *fp; 78 mblk_t *bp; 79 int error; 80 int flag; 81 82 error = 0; 83 84 fp = tiptr->fp; 85 msgsz = (int)TCONNREQSZ; 86 /* 87 * Usually connect()s are performed with the credential of the caller; 88 * in this particular case we specifically use the credential of 89 * the opener as this call is typically done in the context of a user 90 * process but on behalf of the kernel, e.g., a client connection 91 * to a server which is later shared by different users. 92 * At open time, we make sure to set fp->f_cred to kcred if such is 93 * the case. 94 * 95 * Note: if the receiver uses SCM_UCRED/getpeerucred the pid will 96 * appear as -1. 97 */ 98 while (!(bp = allocb_cred(msgsz + sndcall->addr.len + sndcall->opt.len, 99 fp->f_cred, NOPID))) { 100 if (strwaitbuf(msgsz + sndcall->addr.len + sndcall->opt.len, 101 BPRI_LO)) 102 return (ENOSR); 103 } 104 105 /* LINTED pointer alignment */ 106 creq = (struct T_conn_req *)bp->b_wptr; 107 creq->PRIM_type = T_CONN_REQ; 108 creq->DEST_length = (t_scalar_t)sndcall->addr.len; 109 creq->OPT_length = (t_scalar_t)sndcall->opt.len; 110 111 if (sndcall->addr.len) { 112 bcopy(sndcall->addr.buf, (bp->b_wptr+msgsz), sndcall->addr.len); 113 creq->DEST_offset = (t_scalar_t)msgsz; 114 msgsz += sndcall->addr.len; 115 } else 116 creq->DEST_offset = (t_scalar_t)0; 117 118 if (sndcall->opt.len) { 119 bcopy(sndcall->opt.buf, (bp->b_wptr+msgsz), sndcall->opt.len); 120 creq->OPT_offset = (t_scalar_t)msgsz; 121 msgsz += sndcall->opt.len; 122 } else 123 creq->OPT_offset = (t_scalar_t)0; 124 125 bp->b_datap->db_type = M_PROTO; 126 bp->b_wptr += msgsz; 127 128 /* 129 * copy the users data, if any. 130 */ 131 if (sndcall->udata.len) { 132 /* 133 * if CO then we would allocate a data block and 134 * put the users connect data into it. 135 */ 136 KTLILOG(1, 137 "Attempt to send connectionless data on T_CONN_REQ\n", 0); 138 freemsg(bp); 139 return (EPROTO); 140 } 141 142 flag = fp->f_flag; 143 144 /* 145 * send it 146 */ 147 if ((error = tli_send(tiptr, bp, flag)) != 0) 148 return (error); 149 150 /* 151 * wait for acknowledgment 152 */ 153 if ((error = get_ok_ack(tiptr, T_CONN_REQ, flag)) != 0) 154 return (error); 155 156 bp = NULL; 157 /* 158 * wait for CONfirm 159 */ 160 if ((error = tli_recv(tiptr, &bp, flag)) != 0) 161 return (error); 162 163 if (bp->b_datap->db_type != M_PROTO) { 164 freemsg(bp); 165 return (EPROTO); 166 } 167 168 /* LINTED pointer alignment */ 169 pptr = (union T_primitives *)bp->b_rptr; 170 switch (pptr->type) { 171 case T_CONN_CON: 172 hdrsz = MBLKL(bp); 173 174 /* 175 * check everything for consistency 176 */ 177 if (hdrsz < TCONNCONSZ || 178 hdrsz < (pptr->conn_con.OPT_length + 179 pptr->conn_con.OPT_offset) || 180 hdrsz < (pptr->conn_con.RES_length + 181 pptr->conn_con.RES_offset)) { 182 error = EPROTO; 183 freemsg(bp); 184 break; 185 } 186 187 if (rcvcall != NULL) { 188 /* 189 * okay, so now we copy them 190 */ 191 len = MIN(pptr->conn_con.RES_length, 192 rcvcall->addr.maxlen); 193 bcopy(bp->b_rptr + pptr->conn_con.RES_offset, 194 rcvcall->addr.buf, len); 195 rcvcall->addr.len = len; 196 197 len = MIN(pptr->conn_con.OPT_length, 198 rcvcall->opt.maxlen); 199 bcopy(bp->b_rptr + pptr->conn_con.OPT_offset, 200 rcvcall->opt.buf, len); 201 rcvcall->opt.len = len; 202 203 if (bp->b_cont) { 204 nbp = bp; 205 bp = bp->b_cont; 206 msgsz = (int)MBLKL(bp); 207 len = MIN(msgsz, rcvcall->udata.maxlen); 208 bcopy(bp->b_rptr, rcvcall->udata.buf, len); 209 rcvcall->udata.len = len; 210 freemsg(nbp); 211 } 212 } else { 213 freemsg(bp); 214 } 215 break; 216 217 case T_DISCON_IND: 218 /* 219 * TCP puts the errno here, i.e. 220 * ETIMEDOUT, ECONNREFUSED 221 */ 222 error = pptr->discon_ind.DISCON_reason; 223 freemsg(bp); 224 break; 225 226 default: 227 error = EPROTO; 228 freemsg(bp); 229 break; 230 } 231 return (error); 232 } 233