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