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 * This routine responds to T_INFO_REQ messages. 122 */ 123 void 124 dccp_info_req(dccp_t *dccp, mblk_t *mp) 125 { 126 mp = tpi_ack_alloc(mp, sizeof (struct T_info_ack), M_PCPROTO, 127 T_INFO_ACK); 128 if (mp == NULL) { 129 dccp_err_ack(dccp, mp, TSYSERR, ENOMEM); 130 return; 131 } 132 133 dccp_copy_info((struct T_info_ack *)mp->b_rptr, dccp); 134 putnext(dccp->dccp_connp->conn_rq, mp); 135 } 136 137 /* 138 * This routine responds to T_ADDR_REQ messages. 139 */ 140 void 141 dccp_addr_req(dccp_t *dccp, mblk_t *mp) 142 { 143 conn_t *connp = dccp->dccp_connp; 144 mblk_t *ackmp; 145 uint_t addrlen; 146 struct sockaddr *sa; 147 struct T_addr_ack *taa; 148 149 /* XXX */ 150 } 151 152 /* 153 * Helper function to generate TPI errors acks. 154 */ 155 void 156 dccp_err_ack(dccp_t *dccp, mblk_t *mp, int t_error, int sys_error) 157 { 158 if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL) { 159 putnext(dccp->dccp_connp->conn_rq, mp); 160 } 161 } 162 163 void 164 dccp_tpi_connect(dccp_t *dccp, mblk_t *mp) 165 { 166 conn_t *connp = dccp->dccp_connp; 167 queue_t *q = connp->conn_wq; 168 struct sockaddr *sa; 169 struct T_conn_req *tcr; 170 sin_t *sin; 171 sin6_t *sin6; 172 cred_t *cr; 173 pid_t cpid; 174 socklen_t len; 175 int error; 176 177 cmn_err(CE_NOTE, "dccp_tpi.c: dccp_tpi_connect"); 178 179 cr = msg_getcred(mp, &cpid); 180 ASSERT(cr != NULL); 181 if (cr == NULL) { 182 dccp_err_ack(dccp, mp, TSYSERR, EINVAL); 183 return; 184 } 185 186 tcr = (struct T_conn_req *)mp->b_rptr; 187 188 ASSERT((uintptr_t)(mp->b_wptr - mp->b_rptr) <= (uintptr_t)INT_MAX); 189 if ((mp->b_wptr - mp->b_rptr) < sizeof (*tcr)) { 190 dccp_err_ack(dccp, mp, TPROTO, 0); 191 return; 192 } 193 194 error = proto_verify_ip_addr(connp->conn_family, sa, len); 195 if (error != 0) { 196 dccp_err_ack(dccp, mp, TSYSERR, 0); 197 return; 198 } 199 200 error = dccp_do_connect(dccp->dccp_connp, sa, len, cr, cpid); 201 if (error < 0) { 202 mp = mi_tpi_err_ack_alloc(mp, -error, 0); 203 } else if (error > 0) { 204 mp = mi_tpi_err_ack_alloc(mp, TSYSERR, error); 205 } else { 206 mp = mi_tpi_ok_ack_alloc(mp); 207 } 208 } 209 210 int 211 dccp_tpi_close(queue_t *q, int flags) 212 { 213 conn_t *connp; 214 215 ASSERT(WR(q)->q_next == NULL); 216 217 connp = Q_TO_CONN(q); 218 219 dccp_close_common(connp, flags); 220 221 qprocsoff(q); 222 inet_minor_free(connp->conn_minor_arena, connp->conn_dev); 223 224 return (0); 225 } 226 227 int 228 dccp_tpi_close_accept(queue_t *q) 229 { 230 vmem_t *minor_arena; 231 dev_t conn_dev; 232 233 cmn_err(CE_NOTE, "dccp_tpi.c: dccp_tpi_close_accept"); 234 235 return (0); 236 } 237 238 boolean_t 239 dccp_conn_con(dccp_t *dccp, uchar_t *iphdr, mblk_t *idmp, 240 mblk_t **defermp, ip_recv_attr_t *ira) 241 { 242 conn_t *connp = dccp->dccp_connp; 243 sin_t sin; 244 sin6_t sin6; 245 mblk_t *mp; 246 char *optp = NULL; 247 int optlen = 0; 248 249 cmn_err(CE_NOTE, "dccp_tpi.c: dccp_conn_con"); 250 251 if (defermp != NULL) { 252 *defermp = NULL; 253 } 254 255 if (IPH_HDR_VERSION(iphdr) == IPV4_VERSION) { 256 /* Packet is IPv4 */ 257 if (connp->conn_family == AF_INET) { 258 sin = sin_null; 259 sin.sin_addr.s_addr = connp->conn_faddr_v4; 260 sin.sin_port = connp->conn_fport; 261 sin.sin_family = AF_INET; 262 mp = mi_tpi_conn_con(NULL, (char *)&sin, 263 (int)sizeof (sin_t), optp, optlen); 264 } else { 265 sin6 = sin6_null; 266 sin6.sin6_addr = connp->conn_faddr_v6; 267 sin6.sin6_port = connp->conn_fport; 268 sin6.sin6_family = AF_INET6; 269 mp = mi_tpi_conn_con(NULL, (char *)&sin6, 270 (int)sizeof (sin6_t), optp, optlen); 271 } 272 } else { 273 ip6_t *ip6h = (ip6_t *)iphdr; 274 275 ASSERT(IPH_HDR_VERSION(iphdr) == IPV6_VERSION); 276 ASSERT(connp->conn_family == AF_INET6); 277 278 sin6 = sin6_null; 279 sin6.sin6_addr = connp->conn_faddr_v6; 280 sin6.sin6_port = connp->conn_fport; 281 sin6.sin6_family = AF_INET6; 282 sin6.sin6_flowinfo = ip6h->ip6_vcf & ~IPV6_VERS_AND_FLOW_MASK; 283 mp = mi_tpi_conn_con(NULL, (char *)&sin6, 284 (int)sizeof (sin6_t), optp, optlen); 285 } 286 287 if (!mp) { 288 return (B_FALSE); 289 } 290 291 mblk_copycred(mp, idmp); 292 293 if (defermp == NULL) { 294 if (IPCL_IS_NONSTR(connp)) { 295 cmn_err(CE_NOTE, "calling su_connected"); 296 (*connp->conn_upcalls->su_connected) 297 (connp->conn_upper_handle, dccp->dccp_connid, 298 ira->ira_cred, ira->ira_cpid); 299 freemsg(mp); 300 } else { 301 if (ira->ira_cred != NULL) { 302 /* So that getpeerucred works for TPI sockfs */ 303 mblk_setcred(mp, ira->ira_cred, ira->ira_cpid); 304 } 305 putnext(connp->conn_rq, mp); 306 } 307 } else { 308 *defermp = mp; 309 } 310 311 /* XXX */ 312 return (B_TRUE); 313 } 314 315 /* 316 * Routine to get the values of options. 317 */ 318 int 319 dccp_tpi_opt_get(queue_t *q, int level, int name, uchar_t *ptr) 320 { 321 return (dccp_opt_get(Q_TO_CONN(q), level, name, ptr)); 322 } 323 324 /* 325 * Routine to set the values of options. 326 */ 327 /* ARGSUSED */ 328 int 329 dccp_tpi_opt_set(queue_t *q, uint_t optset_context, int level, int name, 330 uint_t inlen, uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp, 331 void *thisdg_attrs, cred_t *cr) 332 { 333 conn_t *connp = Q_TO_CONN(q); 334 335 return (dccp_opt_set(connp, optset_context, level, name, inlen, invalp, 336 outlenp, outvalp, thisdg_attrs, cr)); 337 } 338 339 void 340 dccp_tpi_accept(queue_t *q, mblk_t *mp) 341 { 342 struct T_ok_ack *ok; 343 struct T_conn_res *conn_res; 344 conn_t *econnp; 345 dccp_t *eager; 346 dccp_t *listener; 347 queue_t *rq = RD(q); 348 mblk_t *discon_mp; 349 cred_t *cr; 350 351 cmn_err(CE_NOTE, "dccp_tpi.c: dccp_tpi_accept"); 352 353 ASSERT(DB_TYPE(mp) == M_PROTO); 354 355 cr = msg_getcred(mp, NULL); 356 ASSERT(cr != NULL); 357 if (cr == NULL) { 358 mp = mi_tpi_err_ack_alloc(mp, TSYSERR, EINVAL); 359 if (mp != NULL) { 360 putnext(rq, mp); 361 } 362 return; 363 } 364 365 conn_res = (struct T_conn_res *)mp->b_rptr; 366 ASSERT((uintptr_t)(mp->b_wptr - mp->b_rptr) <= (uintptr_t)INT_MAX); 367 if ((mp->b_wptr - mp->b_rptr) < sizeof (struct T_conn_res)) { 368 mp = mi_tpi_err_ack_alloc(mp, TPROTO, 0); 369 if (mp != NULL) { 370 putnext(rq, mp); 371 } 372 return; 373 } 374 375 switch (conn_res->PRIM_type) { 376 case O_T_CONN_RES: 377 case T_CONN_RES: 378 putnext(rq, mp); 379 return; 380 default: 381 mp = mi_tpi_err_ack_alloc(mp, TNOTSUPPORT, 0); 382 if (mp != NULL) { 383 putnext(rq, mp); 384 } 385 return; 386 } 387 } 388 389 static void 390 dccp_accept_swap(dccp_t *listener, dccp_t *acceptor, dccp_t *eager) 391 { 392 conn_t *econnp; 393 conn_t *aconnp; 394 } 395 396 /* 397 * This runs at the tail end of accept processing on the squeue of the 398 * new connection. 399 */ 400 static void 401 dccp_accept_finish(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy) 402 { 403 conn_t *connp = (conn_t *)arg; 404 dccp_t *dccp = connp->conn_dccp; 405 dccp_stack_t *dccps = dccp->dccp_dccps; 406 queue_t *q = connp->conn_rq; 407 struct stroptions *stropt; 408 struct sock_proto_props sopp; 409 410 /* Should never be called for non-STREAMS sockets */ 411 ASSERT(!IPCL_IS_NONSTR(connp)); 412 413 /* We should just receive a single mblk that fits a T_discon_ind */ 414 ASSERT(mp->b_cont == NULL); 415 416 /* XXX */ 417 418 dccp_get_proto_props(dccp, &sopp); 419 420 ASSERT(DB_REF(mp) == 1); 421 ASSERT(MBLKSIZE(mp) >= sizeof (struct stroptions)); 422 423 DB_TYPE(mp) = M_SETOPTS; 424 425 /* XXX */ 426 427 dccp->dccp_hard_binding = B_FALSE; 428 429 if (connp->conn_keepalive) { 430 dccp->dccp_ka_last_intrvl = 0; 431 dccp->dccp_ka_tid = DCCP_TIMER(dccp, dccp_keepalive_timer, 432 dccp->dccp_ka_interval); 433 } 434 }