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  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright 2012 David Hoeppner.  All rights reserved.
  29  */
  30 
  31 #include <sys/types.h>
  32 #include <sys/stream.h>
  33 #include <sys/strsun.h>
  34 #include <sys/strsubr.h>
  35 #include <sys/stropts.h>
  36 #include <sys/strlog.h>
  37 #define _SUN_TPI_VERSION 2
  38 #include <sys/tihdr.h>
  39 #include <sys/suntpi.h>
  40 #include <sys/xti_inet.h>
  41 #include <sys/squeue_impl.h>
  42 #include <sys/squeue.h>
  43 #include <sys/tsol/tnet.h>
  44 
  45 #include <inet/common.h>
  46 #include <inet/ip.h>
  47 
  48 #include <sys/cmn_err.h>
  49 
  50 #include "dccp_impl.h"
  51 
  52 static mblk_t   *dccp_conn_create_v4(conn_t *, conn_t *, mblk_t *,
  53                     ip_recv_attr_t *);
  54 static mblk_t   *dccp_conn_create_v6(conn_t *, conn_t *, mblk_t *,
  55                     ip_recv_attr_t *);
  56 static void     dccp_input_listener(void *, mblk_t *, void *, ip_recv_attr_t *);
  57 
  58 void
  59 dccp_input_data(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira)
  60 {
  61         cmn_err(CE_NOTE, "dccp_input.c: dccp_input_data");
  62 }
  63 
  64 void
  65 dccp_icmp_input(void *arg1, mblk_t *mp, void *arg2, ip_recv_attr_t *ira)
  66 {
  67         cmn_err(CE_NOTE, "dccp_input.c: dccp_icmp_input");
  68 }
  69 
  70 void
  71 dccp_rsrv(queue_t *q)
  72 {
  73         cmn_err(CE_NOTE, "dccp_input.c: dccp_rsrv");
  74 }
  75 
  76 static mblk_t *
  77 dccp_conn_create_v6(conn_t *lconnp, conn_t *connp, mblk_t *mp,
  78     ip_recv_attr_t *ira)
  79 {
  80         return (NULL);
  81 }
  82 
  83 static mblk_t *
  84 dccp_conn_create_v4(conn_t *lconnp, conn_t *connp, mblk_t *mp,
  85     ip_recv_attr_t *ira)
  86 {
  87         dccp_t          *ldccp = lconnp->conn_dccp;
  88         dccp_t          *dccp = connp->conn_dccp;
  89         dccp_stack_t    *dccps = dccp->dccp_dccps;
  90         ipha_t          *ipha;
  91         mblk_t          *tpi_mp;
  92         sin_t           sin;
  93 
  94         ASSERT(ira->ira_flags & IRAF_IS_IPV4);
  95         ipha = (ipha_t *)mp->b_rptr;
  96 
  97         connp->conn_ipversion = IPV4_VERSION;
  98         IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &connp->conn_laddr_v6);
  99         IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &connp->conn_faddr_v6);
 100         connp->conn_saddr_v6 = connp->conn_laddr_v6;
 101 
 102         sin = sin_null;
 103         sin.sin_addr.s_addr = connp->conn_faddr_v4;
 104         sin.sin_port = connp->conn_fport;
 105         sin.sin_family = AF_INET;
 106 
 107         if (lconnp->conn_recv_ancillary.crb_recvdstaddr) {
 108                 cmn_err(CE_NOTE, "ancillary");
 109 
 110                 sin_t   sind;
 111 
 112                 sind = sin_null;
 113                 sind.sin_addr.s_addr = connp->conn_laddr_v4;
 114                 sind.sin_port = connp->conn_lport;
 115                 sind.sin_family = AF_INET;
 116 
 117                 tpi_mp = mi_tpi_extconn_ind(NULL,
 118                     (char *)&sind, sizeof (sin_t), (char *)&dccp,
 119                     (t_scalar_t)sizeof (intptr_t), (char *)&sind,
 120                     sizeof (sin_t), (t_scalar_t) 1); /* XXX */
 121 
 122         } else {
 123                 tpi_mp = mi_tpi_conn_ind(NULL,
 124                 (char *)&sin, sizeof (sin_t),
 125                 (char *)&dccp, (t_scalar_t)sizeof (intptr_t),
 126                 (t_scalar_t) 1); /* XXX */
 127         }
 128 
 129         return (tpi_mp);
 130 }
 131 
 132 static void
 133 dccp_input_listener(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira)
 134 {
 135         conn_t          *lconnp = (conn_t *)arg;
 136         conn_t          *econnp;
 137         dccp_t          *listener = lconnp->conn_dccp;
 138         dccp_t          *eager;
 139         dccp_stack_t    *dccps = listener->dccp_dccps;
 140         ip_stack_t      *ipst = dccps->dccps_netstack->netstack_ip;
 141         dccpha_t        *dccpha;
 142         squeue_t        *new_sqp;
 143         mblk_t          *tpi_mp;
 144         mblk_t          *mp1;
 145         uint_t          ip_hdr_len;
 146         uint_t          type;
 147         int             error;
 148 
 149         cmn_err(CE_NOTE, "dccp_input.c: dccp_input_listener");
 150 
 151         ip_hdr_len = ira->ira_ip_hdr_length;
 152         dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
 153         type = (uint_t)dccpha->dha_type;
 154 
 155         if (type != DCCP_PKT_REQUEST) {
 156                 cmn_err(CE_NOTE, "not request pkt");
 157 
 158                 /* XXX do something with a reset packet sent? */
 159                 freemsg(mp);
 160                 return;
 161         }
 162 
 163         /* XXX memory pressure */
 164 
 165         /* XXX request defense */
 166 
 167         /* XXX number of connections per listener */
 168 
 169         ASSERT(ira->ira_sqp != NULL);
 170         new_sqp = ira->ira_sqp;
 171 
 172         econnp = (conn_t *)dccp_get_conn(arg2, dccps);
 173         if (econnp == NULL) {
 174                 cmn_err(CE_NOTE, "econnp not found (eager)");
 175                 goto error2;
 176         }
 177 
 178         ASSERT(econnp->conn_netstack == lconnp->conn_netstack);
 179         econnp->conn_sqp = new_sqp;
 180         econnp->conn_initial_sqp = new_sqp;
 181         econnp->conn_ixa->ixa_sqp = new_sqp;
 182 
 183         econnp->conn_fport = dccpha->dha_lport;
 184         econnp->conn_lport = dccpha->dha_fport;
 185 
 186         error = conn_inherit_parent(lconnp, econnp);
 187         if (error != 0) {
 188                 cmn_err(CE_NOTE, "conn_inherit_parent failed");
 189                 goto error3;
 190         }
 191 
 192         econnp->conn_ixa->ixa_src_generation = ipst->ips_src_generation;
 193 
 194 
 195         ASSERT(OK_32PTR(mp->b_rptr));
 196         ASSERT(IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION ||
 197             IPH_HDR_VERSION(mp->b_rptr) == IPV6_VERSION);
 198 
 199         if (lconnp->conn_family == AF_INET) {
 200                 ASSERT(IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION);
 201                 tpi_mp = dccp_conn_create_v4(lconnp, econnp, mp, ira);
 202         } else {
 203                 tpi_mp = dccp_conn_create_v6(lconnp, econnp, mp, ira);
 204         }
 205 
 206         if (tpi_mp == NULL) {
 207                 cmn_err(CE_NOTE, "tpi_mo == NULL");
 208                 goto error3;
 209         }
 210 
 211         eager = econnp->conn_dccp;
 212         SOCK_CONNID_INIT(eager->dccp_connid);
 213 
 214         dccp_init_values(eager, listener);
 215 
 216         ASSERT((econnp->conn_ixa->ixa_flags &
 217             (IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE |
 218             IXAF_VERIFY_PMTU | IXAF_VERIFY_LSO)) ==
 219             (IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE |
 220             IXAF_VERIFY_PMTU | IXAF_VERIFY_LSO));
 221 
 222         if (ira->ira_cred != NULL) {
 223                 mblk_setcred(tpi_mp, ira->ira_cred, ira->ira_cpid);
 224         }
 225 
 226         if (IPCL_IS_NONSTR(lconnp)) {
 227                 econnp->conn_flags |= IPCL_NONSTR;
 228         }
 229 
 230         /* XXX dccps is right? */
 231         dccp_bind_hash_insert(&dccps->dccps_bind_fanout[
 232             DCCP_BIND_HASH(econnp->conn_lport, dccps->dccps_bind_fanout_size)], eager, 0);
 233 
 234         SOCK_CONNID_BUMP(eager->dccp_connid);
 235 
 236         error = dccp_set_destination(eager);
 237         if (error != 0) {
 238                 cmn_err(CE_NOTE, "dccp_set_destination failed.");
 239                 dccp_bind_hash_remove(eager);
 240                 goto error3;
 241         }
 242 
 243         CONN_INC_REF(lconnp);
 244 
 245 /*
 246         mp1 = dccp_xmit_mp(eager, eager->dccp_xmit_head, 0,
 247             NULL, NULL, 0, B_FALSE, NULL, B_FALSE);
 248 */
 249         mp1 = dccp_generate_packet(lconnp, mp);
 250         if (mp1 == NULL) {
 251                 cmn_err(CE_NOTE, "dccp_xmit_mp failed");
 252 
 253                 CONN_INC_REF(econnp);
 254                 goto error;
 255         }
 256 
 257         CONN_INC_REF(econnp);
 258 
 259         error = ipcl_conn_insert(econnp);
 260         if (error != 0) {
 261                 cmn_err(CE_NOTE, "ipcl_conn_insert(econnp) failed");
 262                 goto error;
 263         }
 264 
 265         freemsg(mp);
 266 
 267         if (econnp->conn_sqp == lconnp->conn_sqp) {
 268                 (void) conn_ip_output(mp1, econnp->conn_ixa);
 269                 CONN_DEC_REF(econnp);
 270         } else {
 271                 SQUEUE_ENTER_ONE(econnp->conn_sqp, mp1, dccp_send_synack,
 272                     econnp, NULL, SQ_PROCESS, SQTAG_TCP_SEND_SYNACK); /* XXX */
 273         }
 274 
 275         return;
 276 error:
 277 error2:
 278 error3:
 279         freemsg(mp);
 280 }
 281 
 282 void
 283 dccp_input_listener_unbound(void *arg, mblk_t *mp, void *arg2,
 284     ip_recv_attr_t *ira)
 285 {
 286         conn_t          *connp = (conn_t *)arg;
 287         squeue_t        *sqp = (squeue_t *)arg2;
 288         squeue_t        *new_sqp;
 289         uint32_t        conn_flags;
 290 
 291         cmn_err(CE_NOTE, "dccp_input.c: dccp_input_listener_unbound");
 292 
 293         ASSERT(ira->ira_sqp != NULL);
 294         new_sqp = ira->ira_sqp;
 295 
 296         if (connp->conn_fanout == NULL) {
 297                 goto done;
 298         }
 299 
 300         /*
 301          * Bind to correct squeue.
 302          */
 303         if (!(connp->conn_flags & IPCL_FULLY_BOUND)) {
 304                 cmn_err(CE_NOTE, "not fully bound");
 305 
 306                 mutex_enter(&connp->conn_fanout->connf_lock);
 307                 mutex_enter(&connp->conn_lock);
 308 
 309                 if (connp->conn_ref != 4 ||
 310                     connp->conn_dccp->dccp_state != DCCPS_LISTEN) {
 311                         mutex_exit(&connp->conn_lock);
 312                         mutex_exit(&connp->conn_fanout->connf_lock);
 313                         goto done;
 314                 }
 315 
 316                 if (connp->conn_sqp != new_sqp) {
 317                         while (connp->conn_sqp != new_sqp) {
 318                                 (void) casptr(&connp->conn_sqp, sqp, new_sqp);
 319                         }
 320                         connp->conn_ixa->ixa_sqp = new_sqp;
 321                 }
 322 
 323                 do {
 324                         conn_flags = connp->conn_flags;
 325                         conn_flags |= IPCL_FULLY_BOUND;
 326                         (void) cas32(&connp->conn_flags, connp->conn_flags,
 327                             conn_flags);
 328                 } while (!(connp->conn_flags & IPCL_FULLY_BOUND));
 329 
 330                 mutex_exit(&connp->conn_lock);
 331                 mutex_exit(&connp->conn_fanout->connf_lock);
 332 
 333                 connp->conn_recv = dccp_input_listener;
 334         }
 335 
 336 done:
 337         if (connp->conn_sqp != sqp) {
 338                 CONN_INC_REF(connp);
 339                 SQUEUE_ENTER_ONE(connp->conn_sqp, mp, connp->conn_recv, connp,
 340                     ira, SQ_FILL, SQTAG_DCCP_CONN_REQ_UNBOUND);
 341         } else {
 342                 dccp_input_listener(connp, mp, sqp, ira);
 343         }
 344 }
 345 
 346 boolean_t
 347 dccp_verifyicmp(conn_t *connp, void *arg2, icmph_t *icmph, icmp6_t *icmp6,
 348     ip_recv_attr_t *ira)
 349 {
 350         cmn_err(CE_NOTE, "dccp_input.c: dccp_verifyicmp");
 351 
 352         return (B_TRUE);
 353 }