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 /* 23 * Functions related to TPI. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/stream.h> 28 #include <sys/strsun.h> 29 #include <sys/strsubr.h> 30 #include <sys/stropts.h> 31 #include <sys/strlog.h> 32 #define _SUN_TPI_VERSION 2 33 #include <sys/tihdr.h> 34 #include <sys/suntpi.h> 35 #include <sys/xti_inet.h> 36 #include <sys/squeue_impl.h> 37 #include <sys/squeue.h> 38 #include <sys/tsol/tnet.h> 39 40 #include <inet/common.h> 41 #include <inet/dccp_impl.h> 42 #include <inet/ip.h> 43 #include <inet/proto_set.h> 44 45 #include <sys/cmn_err.h> 46 47 48 /* 49 * This file contains functions related to the TPI interface. 50 */ 51 52 /* 53 * XXX 54 */ 55 static void 56 dccp_copy_info(struct T_info_ack *tia, dccp_t *dccp) 57 { 58 conn_t *connp = dccp->dccp_connp; 59 dccp_stack_t *dccps = dccp->dccp_dccps; 60 extern struct T_info_ack dccp_g_t_info_ack; 61 extern struct T_info_ack dccp_g_t_info_ack_v6; 62 63 if (connp->conn_family == AF_INET6) { 64 *tia = dccp_g_t_info_ack_v6; 65 } else { 66 *tia = dccp_g_t_info_ack; 67 } 68 69 /* XXX */ 70 } 71 72 /* 73 * XXX 74 */ 75 void 76 dccp_do_capability_ack(dccp_t *dccp, struct T_capability_ack *tcap, 77 t_uscalar_t cap_bits1) 78 { 79 tcap->CAP_bits1 = 0; 80 81 if (cap_bits1 & TC1_INFO) { 82 dccp_copy_info(&tcap->INFO_ack, dccp); 83 tcap->CAP_bits1 |= TC1_INFO; 84 } 85 86 if (cap_bits1 & TC1_ACCEPTOR_ID) { 87 tcap->ACCEPTOR_id = dccp->dccp_acceptor_id; 88 tcap->CAP_bits1 |= TC1_ACCEPTOR_ID; 89 } 90 } 91 92 /* 93 * This routine responds to T_CAPABILITY_REQ messages. 94 */ 95 void 96 dccp_capability_req(dccp_t *dccp, mblk_t *mp) 97 { 98 struct T_capability_ack *tcap; 99 t_uscalar_t cap_bits1; 100 101 if (MBLKL(mp) < sizeof (struct T_capability_req)) { 102 freemsg(mp); 103 return; 104 } 105 106 cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1; 107 108 mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack), 109 mp->b_datap->db_type, T_CAPABILITY_ACK); 110 if (mp == NULL) { 111 return; 112 } 113 114 tcap = (struct T_capability_ack *)mp->b_rptr; 115 dccp_do_capability_ack(dccp, tcap, cap_bits1); 116 117 putnext(dccp->dccp_connp->conn_rq, mp); 118 } 119 120 /* 121 * Helper function to generate TPI errors acks. 122 */ 123 void 124 dccp_err_ack(dccp_t *dccp, mblk_t *mp, int t_error, int sys_error) 125 { 126 if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL) { 127 putnext(dccp->dccp_connp->conn_rq, mp); 128 } 129 } 130 131 void 132 dccp_tpi_connect(dccp_t *dccp, mblk_t *mp) 133 { 134 conn_t *connp = dccp->dccp_connp; 135 queue_t *q = connp->conn_wq; 136 struct sockaddr *sa; 137 struct T_conn_req *tcr; 138 sin_t *sin; 139 sin6_t *sin6; 140 cred_t *cr; 141 pid_t cpid; 142 socklen_t len; 143 int error; 144 145 cmn_err(CE_NOTE, "dccp_tpi.c: dccp_tpi_connect"); 146 147 cr = msg_getcred(mp, &cpid); 148 ASSERT(cr != NULL); 149 if (cr == NULL) { 150 dccp_err_ack(dccp, mp, TSYSERR, EINVAL); 151 return; 152 } 153 154 tcr = (struct T_conn_req *)mp->b_rptr; 155 156 ASSERT((uintptr_t)(mp->b_wptr - mp->b_rptr) <= (uintptr_t)INT_MAX); 157 if ((mp->b_wptr - mp->b_rptr) < sizeof (*tcr)) { 158 dccp_err_ack(dccp, mp, TPROTO, 0); 159 return; 160 } 161 162 error = proto_verify_ip_addr(connp->conn_family, sa, len); 163 if (error != 0) { 164 dccp_err_ack(dccp, mp, TSYSERR, 0); 165 return; 166 } 167 168 error = dccp_do_connect(dccp->dccp_connp, sa, len, cr, cpid); 169 if (error < 0) { 170 mp = mi_tpi_err_ack_alloc(mp, -error, 0); 171 } else if (error > 0) { 172 mp = mi_tpi_err_ack_alloc(mp, TSYSERR, error); 173 } else { 174 mp = mi_tpi_ok_ack_alloc(mp); 175 } 176 } 177 178 int 179 dccp_tpi_close(queue_t *q, int flags) 180 { 181 conn_t *connp; 182 183 ASSERT(WR(q)->q_next == NULL); 184 185 connp = Q_TO_CONN(q); 186 187 dccp_close_common(connp, flags); 188 189 qprocsoff(q); 190 inet_minor_free(connp->conn_minor_arena, connp->conn_dev); 191 192 return (0); 193 } 194 195 int 196 dccp_tpi_close_accept(queue_t *q) 197 { 198 vmem_t *minor_arena; 199 dev_t conn_dev; 200 201 cmn_err(CE_NOTE, "dccp_tpi.c: dccp_tpi_close_accept"); 202 203 return (0); 204 } 205 206 boolean_t 207 dccp_conn_con(dccp_t *dccp, uchar_t *iphdr, mblk_t *idmp, 208 mblk_t **defermp, ip_recv_attr_t *ira) 209 { 210 conn_t *connp = dccp->dccp_connp; 211 sin_t sin; 212 sin6_t sin6; 213 mblk_t *mp; 214 char *optp = NULL; 215 int optlen = 0; 216 217 cmn_err(CE_NOTE, "dccp_tpi.c: dccp_conn_con"); 218 219 if (defermp != NULL) { 220 *defermp = NULL; 221 } 222 223 if (IPH_HDR_VERSION(iphdr) == IPV4_VERSION) { 224 /* Packet is IPv4 */ 225 if (connp->conn_family == AF_INET) { 226 sin = sin_null; 227 sin.sin_addr.s_addr = connp->conn_faddr_v4; 228 sin.sin_port = connp->conn_fport; 229 sin.sin_family = AF_INET; 230 mp = mi_tpi_conn_con(NULL, (char *)&sin, 231 (int)sizeof (sin_t), optp, optlen); 232 } else { 233 sin6 = sin6_null; 234 sin6.sin6_addr = connp->conn_faddr_v6; 235 sin6.sin6_port = connp->conn_fport; 236 sin6.sin6_family = AF_INET6; 237 mp = mi_tpi_conn_con(NULL, (char *)&sin6, 238 (int)sizeof (sin6_t), optp, optlen); 239 } 240 } else { 241 ip6_t *ip6h = (ip6_t *)iphdr; 242 243 ASSERT(IPH_HDR_VERSION(iphdr) == IPV6_VERSION); 244 ASSERT(connp->conn_family == AF_INET6); 245 246 sin6 = sin6_null; 247 sin6.sin6_addr = connp->conn_faddr_v6; 248 sin6.sin6_port = connp->conn_fport; 249 sin6.sin6_family = AF_INET6; 250 sin6.sin6_flowinfo = ip6h->ip6_vcf & ~IPV6_VERS_AND_FLOW_MASK; 251 mp = mi_tpi_conn_con(NULL, (char *)&sin6, 252 (int)sizeof (sin6_t), optp, optlen); 253 } 254 255 if (!mp) { 256 return (B_FALSE); 257 } 258 259 mblk_copycred(mp, idmp); 260 261 if (defermp == NULL) { 262 if (IPCL_IS_NONSTR(connp)) { 263 cmn_err(CE_NOTE, "calling su_connected"); 264 (*connp->conn_upcalls->su_connected) 265 (connp->conn_upper_handle, dccp->dccp_connid, 266 ira->ira_cred, ira->ira_cpid); 267 freemsg(mp); 268 } else { 269 if (ira->ira_cred != NULL) { 270 /* So that getpeerucred works for TPI sockfs */ 271 mblk_setcred(mp, ira->ira_cred, ira->ira_cpid); 272 } 273 putnext(connp->conn_rq, mp); 274 } 275 } else { 276 *defermp = mp; 277 } 278 279 /* XXX */ 280 return (B_TRUE); 281 } 282 283 /* 284 * Options related functions. 285 */ 286 int 287 dccp_tpi_opt_get(queue_t *q, int level, int name, uchar_t *ptr) 288 { 289 return (dccp_opt_get(Q_TO_CONN(q), level, name, ptr)); 290 } 291 292 /* ARGSUSED */ 293 int 294 dccp_tpi_opt_set(queue_t *q, uint_t optset_context, int level, int name, 295 uint_t inlen, uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp, 296 void *thisdg_attrs, cred_t *cr) 297 { 298 conn_t *connp = Q_TO_CONN(q); 299 300 return (dccp_opt_set(connp, optset_context, level, name, inlen, invalp, 301 outlenp, outvalp, thisdg_attrs, cr)); 302 } 303 304 void 305 dccp_tpi_accept(queue_t *q, mblk_t *mp) 306 { 307 queue_t *rq = RD(q); 308 309 cmn_err(CE_NOTE, "dccp_tpi.c: dccp_tpi_accept"); 310 }