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/dccp_impl.h>
  47 #include <inet/ip.h>
  48 
  49 #include <sys/cmn_err.h>
  50 
  51 static mblk_t   *dccp_conn_create_v4(conn_t *, conn_t *, mblk_t *,
  52                     ip_recv_attr_t *);
  53 static mblk_t   *dccp_conn_create_v6(conn_t *, conn_t *, mblk_t *,
  54                     ip_recv_attr_t *);
  55 static void     dccp_input_listener(void *, mblk_t *, void *, ip_recv_attr_t *);
  56 static void     dccp_icmp_error_ipv6(dccp_t *, mblk_t *, ip_recv_attr_t *);
  57 static int      dccp_check_input(conn_t *, mblk_t *, ip_recv_attr_t *);
  58 
  59 void
  60 dccp_icmp_input(void *arg1, mblk_t *mp, void *arg2, ip_recv_attr_t *ira)
  61 {
  62         conn_t  *connp = (conn_t *)arg1;
  63         dccp_t  *dccp = connp->conn_dccp;
  64         ipha_t  *ipha;
  65         icmph_t *icmph;
  66         sin_t   sin;
  67         sin6_t  sin6;
  68         int     iph_hdr_length;
  69         int     error;
  70 
  71         cmn_err(CE_NOTE, "dccp_input.c: dccp_icmp_input");
  72 
  73         ipha = (ipha_t *)mp->b_rptr;
  74 
  75         /* Assume IP provides aligned packets */
  76         ASSERT(OK_32PTR(mp->b_rptr));
  77         ASSERT((MBLKL(mp) >= sizeof (ipha_t)));
  78 
  79         if (dccp->dccp_state == DCCPS_CLOSED) {
  80                 freemsg(mp);
  81                 return;
  82         }
  83 
  84         /*
  85          * Verify IP version. Anything other than IPv4 or IPv6 packet is sent
  86          * upstream. ICMPv6 is handled in dccp_icmp_error_ipv6.
  87          */
  88         if (IPH_HDR_VERSION(ipha) != IPV4_VERSION) {
  89                 ASSERT(IPH_HDR_VERSION(ipha) == IPV6_VERSION);
  90                 dccp_icmp_error_ipv6(dccp, mp, ira);
  91                 return;
  92         }
  93         ASSERT(IPH_HDR_VERSION(ipha) == IPV4_VERSION);
  94 
  95         ASSERT(IPH_HDR_LENGTH(ipha) == ira->ira_ip_hdr_length);
  96         /* Skip past the outer IP and ICMP headers */
  97         iph_hdr_length = ira->ira_ip_hdr_length;
  98         icmph = (icmph_t *)&mp->b_rptr[iph_hdr_length];
  99 
 100         switch (icmph->icmph_type) {
 101         case ICMP_DEST_UNREACHABLE:
 102                 switch (icmph->icmph_code) {
 103                 case ICMP_FRAGMENTATION_NEEDED:
 104                 case ICMP_PORT_UNREACHABLE:
 105                 case ICMP_PROTOCOL_UNREACHABLE:
 106                 case ICMP_HOST_UNREACHABLE:
 107                 case ICMP_NET_UNREACHABLE:
 108                         break;
 109                 default:
 110                         break;
 111                 }
 112                 break;
 113         case ICMP_SOURCE_QUENCH:
 114                 break;
 115         }
 116 
 117         freemsg(mp);
 118 }
 119 
 120 /*
 121  * Handler for ICMPv6 error messages.
 122  */
 123 static void
 124 dccp_icmp_error_ipv6(dccp_t *dccp, mblk_t *mp, ip_recv_attr_t *ira)
 125 {
 126         ip6_t           *ip6h;
 127         icmp6_t         *icmp6;
 128         uint16_t        iph_hdr_length = ira->ira_ip_hdr_length;
 129 
 130         cmn_err(CE_NOTE, "dccp_input.c: dccp_icmp_error_ipv6");
 131 
 132         ASSERT((MBLKL(mp) >= sizeof (ip6_t)));
 133 
 134         icmp6 = (icmp6_t *)&mp->b_rptr[iph_hdr_length];
 135         ip6h = (ip6_t *)&icmp6[1];
 136 
 137 }
 138 
 139 void
 140 dccp_rsrv(queue_t *q)
 141 {
 142         cmn_err(CE_NOTE, "dccp_input.c: dccp_rsrv");
 143 }
 144 
 145 /*
 146  * Handle a REQUEST on an AF_INET6 socket; can be either IPv4 or IPv6.
 147  */
 148 static mblk_t *
 149 dccp_conn_create_v6(conn_t *lconnp, conn_t *connp, mblk_t *mp,
 150     ip_recv_attr_t *ira)
 151 {
 152         dccp_t          *ldccp = lconnp->conn_dccp;
 153         dccp_t          *dccp = connp->conn_dccp;
 154         dccp_stack_t    *dccps = dccp->dccp_dccps;
 155         ipha_t          *ipha;
 156         ip6_t           *ip6h;
 157         mblk_t          *tpi_mp;
 158         sin6_t          sin6;
 159         uint_t          ifindex = ira->ira_ruifindex;
 160 
 161         if (ira->ira_flags & IRAF_IS_IPV4) {
 162                 ipha = (ipha_t *)mp->b_rptr;
 163 
 164                 connp->conn_ipversion = IPV4_VERSION;
 165                 IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &connp->conn_laddr_v6);
 166                 IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &connp->conn_faddr_v6);
 167                 connp->conn_saddr_v6 = connp->conn_laddr_v6;
 168 
 169                 sin6 = sin6_null;
 170                 sin6.sin6_addr = connp->conn_faddr_v6;
 171                 sin6.sin6_port = connp->conn_fport;
 172                 sin6.sin6_family = AF_INET6;
 173                 sin6.__sin6_src_id = ip_srcid_find_addr(&connp->conn_laddr_v6,
 174                     IPCL_ZONEID(lconnp), dccps->dccps_netstack);
 175 
 176                 if (connp->conn_recv_ancillary.crb_recvdstaddr) {
 177                         sin6_t  sin6d;
 178 
 179                         sin6d = sin6_null;
 180                         sin6d.sin6_addr = connp->conn_laddr_v6;
 181                         sin6d.sin6_port = connp->conn_lport;
 182                         sin6d.sin6_family = AF_INET;
 183                         tpi_mp = mi_tpi_extconn_ind(NULL,
 184                             (char *)&sin6d, sizeof (sin6_t),
 185                             (char *)&dccp,
 186                             (t_scalar_t)sizeof (intptr_t),
 187                             (char *)&sin6d, sizeof (sin6_t),
 188                             (t_scalar_t)ldccp->dccp_conn_req_seqnum);
 189                 } else {
 190                         tpi_mp = mi_tpi_conn_ind(NULL,
 191                             (char *)&sin6, sizeof (sin6_t),
 192                             (char *)&dccp, (t_scalar_t)sizeof (intptr_t),
 193                             (t_scalar_t)ldccp->dccp_conn_req_seqnum);
 194                 }
 195         } else {
 196                 ip6h = (ip6_t *)mp->b_rptr;
 197 
 198                 connp->conn_ipversion = IPV6_VERSION;
 199                 connp->conn_laddr_v6 = ip6h->ip6_dst;
 200                 connp->conn_faddr_v6 = ip6h->ip6_src;
 201                 connp->conn_saddr_v6 = connp->conn_laddr_v6;
 202 
 203                 sin6 = sin6_null;
 204                 sin6.sin6_addr = connp->conn_faddr_v6;
 205                 sin6.sin6_port = connp->conn_fport;
 206                 sin6.sin6_family = AF_INET6;
 207                 sin6.sin6_flowinfo = ip6h->ip6_vcf & ~IPV6_VERS_AND_FLOW_MASK;
 208                 sin6.__sin6_src_id = ip_srcid_find_addr(&connp->conn_laddr_v6,
 209                     IPCL_ZONEID(lconnp), dccps->dccps_netstack);
 210 
 211                 if (IN6_IS_ADDR_LINKSCOPE(&ip6h->ip6_src)) {
 212                         /* Pass up the scope_id of remote addr */
 213                         sin6.sin6_scope_id = ifindex;
 214                 } else {
 215                         sin6.sin6_scope_id = 0;
 216                 }
 217                 if (connp->conn_recv_ancillary.crb_recvdstaddr) {
 218                         sin6_t  sin6d;
 219 
 220                         sin6d = sin6_null;
 221                         sin6.sin6_addr = connp->conn_laddr_v6;
 222                         sin6d.sin6_port = connp->conn_lport;
 223                         sin6d.sin6_family = AF_INET6;
 224                         if (IN6_IS_ADDR_LINKSCOPE(&connp->conn_laddr_v6))
 225                                 sin6d.sin6_scope_id = ifindex;
 226 
 227                         tpi_mp = mi_tpi_extconn_ind(NULL,
 228                             (char *)&sin6d, sizeof (sin6_t),
 229                             (char *)&dccp, (t_scalar_t)sizeof (intptr_t),
 230                             (char *)&sin6d, sizeof (sin6_t),
 231                             (t_scalar_t)ldccp->dccp_conn_req_seqnum);
 232                 } else {
 233                         tpi_mp = mi_tpi_conn_ind(NULL,
 234                             (char *)&sin6, sizeof (sin6_t),
 235                             (char *)&dccp, (t_scalar_t)sizeof (intptr_t),
 236                             (t_scalar_t)ldccp->dccp_conn_req_seqnum);
 237                 }
 238         }
 239 
 240         /* XXX mss */
 241         return (tpi_mp);
 242 }
 243 
 244 /*
 245  * Handle a REQUEST on an AF_INET socket.
 246  */
 247 static mblk_t *
 248 dccp_conn_create_v4(conn_t *lconnp, conn_t *connp, mblk_t *mp,
 249     ip_recv_attr_t *ira)
 250 {
 251         dccp_t          *ldccp = lconnp->conn_dccp;
 252         dccp_t          *dccp = connp->conn_dccp;
 253         dccp_stack_t    *dccps = dccp->dccp_dccps;
 254         ipha_t          *ipha;
 255         mblk_t          *tpi_mp;
 256         sin_t           sin;
 257 
 258         ASSERT(ira->ira_flags & IRAF_IS_IPV4);
 259         ipha = (ipha_t *)mp->b_rptr;
 260 
 261         connp->conn_ipversion = IPV4_VERSION;
 262         IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &connp->conn_laddr_v6);
 263         IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &connp->conn_faddr_v6);
 264         connp->conn_saddr_v6 = connp->conn_laddr_v6;
 265 
 266         sin = sin_null;
 267         sin.sin_addr.s_addr = connp->conn_faddr_v4;
 268         sin.sin_port = connp->conn_fport;
 269         sin.sin_family = AF_INET;
 270 
 271         if (lconnp->conn_recv_ancillary.crb_recvdstaddr) {
 272                 cmn_err(CE_NOTE, "ancillary");
 273 
 274                 sin_t   sind;
 275 
 276                 sind = sin_null;
 277                 sind.sin_addr.s_addr = connp->conn_laddr_v4;
 278                 sind.sin_port = connp->conn_lport;
 279                 sind.sin_family = AF_INET;
 280 
 281                 tpi_mp = mi_tpi_extconn_ind(NULL,
 282                     (char *)&sind, sizeof (sin_t), (char *)&dccp,
 283                     (t_scalar_t)sizeof (intptr_t), (char *)&sind,
 284                     sizeof (sin_t), (t_scalar_t)ldccp->dccp_conn_req_seqnum);
 285 
 286         } else {
 287                 tpi_mp = mi_tpi_conn_ind(NULL,
 288                 (char *)&sin, sizeof (sin_t),
 289                 (char *)&dccp, (t_scalar_t)sizeof (intptr_t),
 290                 (t_scalar_t)ldccp->dccp_conn_req_seqnum);
 291         }
 292 
 293         /* XXX mss */
 294 
 295         return (tpi_mp);
 296 }
 297 
 298 static void
 299 dccp_input_listener(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira)
 300 {
 301         conn_t          *lconnp = (conn_t *)arg;
 302         conn_t          *econnp;
 303         dccp_t          *listener = lconnp->conn_dccp;
 304         dccp_t          *eager;
 305         dccp_stack_t    *dccps = listener->dccp_dccps;
 306         ip_stack_t      *ipst = dccps->dccps_netstack->netstack_ip;
 307         dccpha_t        *dccpha;
 308         squeue_t        *new_sqp;
 309         mblk_t          *tpi_mp;
 310         mblk_t          *mp1;
 311         uint_t          ifindex = ira->ira_ruifindex;
 312         uint_t          ip_hdr_len;
 313         uint_t          type;
 314         int             error;
 315 
 316         cmn_err(CE_NOTE, "dccp_input.c: dccp_input_listener");
 317 
 318         ip_hdr_len = ira->ira_ip_hdr_length;
 319         dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
 320         type = (uint_t)dccpha->dha_type;
 321 
 322         DTRACE_DCCP5(receive, mblk_t *, NULL, ip_xmit_attr_t *, lconnp->conn_ixa,
 323             __dtrace_dccp_void_ip_t *, mp->b_rptr, dccp_t *, listener,
 324             __dtrace_dccp_dccph_t *, dccpha);
 325 
 326         dccp_check_input(lconnp, mp, ira);
 327 
 328         if (type != DCCP_PKT_REQUEST) {
 329                 cmn_err(CE_NOTE, "--- not request pkt");
 330                 if (type != DCCP_PKT_RESET) {
 331                         /* XXX send Reset(No Connection) */
 332                 }
 333 
 334                 freemsg(mp);
 335                 return;
 336         }
 337 
 338         /* XXX memory pressure */
 339 
 340         /* XXX request defense */
 341 
 342         /* XXX number of connections per listener */
 343 
 344         ASSERT(ira->ira_sqp != NULL);
 345         new_sqp = ira->ira_sqp;
 346 
 347         econnp = (conn_t *)dccp_get_conn(arg2, dccps);
 348         if (econnp == NULL) {
 349                 cmn_err(CE_NOTE, "econnp not found (eager)");
 350                 goto error2;
 351         }
 352 
 353         ASSERT(econnp->conn_netstack == lconnp->conn_netstack);
 354         econnp->conn_sqp = new_sqp;
 355         econnp->conn_initial_sqp = new_sqp;
 356         econnp->conn_ixa->ixa_sqp = new_sqp;
 357 
 358         econnp->conn_fport = dccpha->dha_lport;
 359         econnp->conn_lport = dccpha->dha_fport;
 360 
 361         error = conn_inherit_parent(lconnp, econnp);
 362         if (error != 0) {
 363                 cmn_err(CE_NOTE, "conn_inherit_parent failed");
 364                 goto error3;
 365         }
 366 
 367         /* We already know the laddr of the new connection is ours */
 368         econnp->conn_ixa->ixa_src_generation = ipst->ips_src_generation;
 369 
 370         ASSERT(OK_32PTR(mp->b_rptr));
 371         ASSERT(IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION ||
 372             IPH_HDR_VERSION(mp->b_rptr) == IPV6_VERSION);
 373 
 374         if (lconnp->conn_family == AF_INET) {
 375                 ASSERT(IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION);
 376                 tpi_mp = dccp_conn_create_v4(lconnp, econnp, mp, ira);
 377         } else {
 378                 tpi_mp = dccp_conn_create_v6(lconnp, econnp, mp, ira);
 379         }
 380 
 381         if (tpi_mp == NULL) {
 382                 cmn_err(CE_NOTE, "tpi_mo == NULL");
 383                 goto error3;
 384         }
 385 
 386         eager = econnp->conn_dccp;
 387         SOCK_CONNID_INIT(eager->dccp_connid);
 388 
 389         dccp_init_values(eager, listener);
 390 
 391         ASSERT((econnp->conn_ixa->ixa_flags &
 392             (IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE |
 393             IXAF_VERIFY_PMTU | IXAF_VERIFY_LSO)) ==
 394             (IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE |
 395             IXAF_VERIFY_PMTU | IXAF_VERIFY_LSO));
 396 
 397         if (!(ira->ira_flags & IRAF_IS_IPV4) && econnp->conn_bound_if == 0) {
 398                 if (IN6_IS_ADDR_LINKSCOPE(&econnp->conn_faddr_v6) ||
 399                     IN6_IS_ADDR_LINKSCOPE(&econnp->conn_laddr_v6)) {
 400                         econnp->conn_incoming_ifindex = ifindex;
 401                         econnp->conn_ixa->ixa_flags |= IXAF_SCOPEID_SET;
 402                         econnp->conn_ixa->ixa_scopeid = ifindex;
 403                 }
 404         }
 405 
 406         if (ira->ira_cred != NULL) {
 407                 mblk_setcred(tpi_mp, ira->ira_cred, ira->ira_cpid);
 408         }
 409 
 410         if (IPCL_IS_NONSTR(lconnp)) {
 411                 econnp->conn_flags |= IPCL_NONSTR;
 412         }
 413 
 414         /* XXX dccps is right? */
 415         dccp_bind_hash_insert(&dccps->dccps_bind_fanout[
 416             DCCP_BIND_HASH(econnp->conn_lport, dccps->dccps_bind_fanout_size)],
 417             eager, 0);
 418 
 419         /* XXX CLUSTER */
 420 
 421         SOCK_CONNID_BUMP(eager->dccp_connid);
 422 
 423         error = dccp_set_destination(eager);
 424         if (error != 0) {
 425                 cmn_err(CE_NOTE, "dccp_set_destination failed.");
 426                 dccp_bind_hash_remove(eager);
 427                 goto error3;
 428         }
 429 
 430         /* Process all DCCP options */
 431         dccp_process_options(eager, dccpha);
 432 
 433         /* Eager lock */
 434         CONN_INC_REF(lconnp);
 435 
 436         /* Set tcp_listener before adding it to tcp_conn_fanout */
 437         eager->dccp_listener = listener;
 438         eager->dccp_saved_listener = listener;
 439 
 440         eager->dccp_conn_req_seqnum = listener->dccp_conn_req_seqnum;
 441         if (++listener->dccp_conn_req_seqnum == -1) {
 442                 /*
 443                  * -1 is "special" and defined in TPI as something
 444                  * that should never be used in T_CONN_IND
 445                  */
 446                 ++listener->dccp_conn_req_seqnum;
 447         }
 448 
 449         /* XXX SYN DEFENSE */
 450 
 451         eager->dccp_state = DCCPS_RESPOND;
 452         DTRACE_DCCP6(state__change, void, NULL, ip_xmit_attr_t *,
 453             econnp->conn_ixa, void, NULL, dccp_t *, eager, void, NULL,
 454             int32_t, DCCPS_LISTEN);
 455 
 456         /* ISS was set in set_destionation */
 457         eager->dccp_gar = eager->dccp_iss;
 458 
 459         mp1 = dccp_generate_response(econnp, mp);
 460         if (mp1 == NULL) {
 461                 cmn_err(CE_NOTE, "dccp_generate_packet failed");
 462                 /*
 463                  * Increment the ref count as we are going to
 464                  * enqueueing an mp in squeue
 465                  */
 466                 CONN_INC_REF(econnp);
 467                 goto error;
 468         }
 469 
 470         CONN_INC_REF(econnp);
 471 
 472         error = ipcl_conn_insert(econnp);
 473         if (error != 0) {
 474                 cmn_err(CE_NOTE, "ipcl_conn_insert(econnp) failed");
 475                 goto error;
 476         }
 477 
 478         ASSERT(econnp->conn_ixa->ixa_notify_cookie == econnp->conn_dccp);
 479         freemsg(mp);
 480 
 481         /*
 482          * Send the RESPONSE. Use the right squeue so that conn_ixa is
 483          * only used by one thread at a time.
 484          */
 485         if (econnp->conn_sqp == lconnp->conn_sqp) {
 486                 DTRACE_DCCP5(send, mblk_t *, NULL, ip_xmit_attr_t *,
 487                     econnp->conn_ixa, __dtrace_dccp_void_ip_t *, mp1->b_rptr,
 488                     dccp_t *, eager, __dtrace_dccp_dccph_t *,
 489                     &mp1->b_rptr[econnp->conn_ixa->ixa_ip_hdr_length]);
 490                 (void) conn_ip_output(mp1, econnp->conn_ixa);
 491                 CONN_DEC_REF(econnp);
 492         } else {
 493                 SQUEUE_ENTER_ONE(econnp->conn_sqp, mp1, dccp_send_synack,
 494                     econnp, NULL, SQ_PROCESS, SQTAG_DCCP_SEND_RESPONSE);
 495         }
 496 
 497         return;
 498 error:
 499         freemsg(mp1);
 500 error2:
 501         CONN_DEC_REF(econnp);
 502 error3:
 503         freemsg(mp);
 504 }
 505 
 506 void
 507 dccp_input_listener_unbound(void *arg, mblk_t *mp, void *arg2,
 508     ip_recv_attr_t *ira)
 509 {
 510         conn_t          *connp = (conn_t *)arg;
 511         squeue_t        *sqp = (squeue_t *)arg2;
 512         squeue_t        *new_sqp;
 513         uint32_t        conn_flags;
 514 
 515         cmn_err(CE_NOTE, "dccp_input.c: dccp_input_listener_unbound");
 516 
 517         ASSERT(ira->ira_sqp != NULL);
 518         new_sqp = ira->ira_sqp;
 519 
 520         if (connp->conn_fanout == NULL) {
 521                 goto done;
 522         }
 523 
 524         /*
 525          * Bind to correct squeue.
 526          */
 527         if (!(connp->conn_flags & IPCL_FULLY_BOUND)) {
 528                 cmn_err(CE_NOTE, "not fully bound");
 529 
 530                 mutex_enter(&connp->conn_fanout->connf_lock);
 531                 mutex_enter(&connp->conn_lock);
 532 
 533                 if (connp->conn_ref != 4 ||
 534                     connp->conn_dccp->dccp_state != DCCPS_LISTEN) {
 535                         mutex_exit(&connp->conn_lock);
 536                         mutex_exit(&connp->conn_fanout->connf_lock);
 537                         goto done;
 538                 }
 539 
 540                 if (connp->conn_sqp != new_sqp) {
 541                         while (connp->conn_sqp != new_sqp) {
 542                                 (void) casptr(&connp->conn_sqp, sqp, new_sqp);
 543                         }
 544                         connp->conn_ixa->ixa_sqp = new_sqp;
 545                 }
 546 
 547                 do {
 548                         conn_flags = connp->conn_flags;
 549                         conn_flags |= IPCL_FULLY_BOUND;
 550                         (void) cas32(&connp->conn_flags, connp->conn_flags,
 551                             conn_flags);
 552                 } while (!(connp->conn_flags & IPCL_FULLY_BOUND));
 553 
 554                 mutex_exit(&connp->conn_lock);
 555                 mutex_exit(&connp->conn_fanout->connf_lock);
 556 
 557                 connp->conn_recv = dccp_input_listener;
 558         }
 559 
 560 done:
 561         if (connp->conn_sqp != sqp) {
 562                 CONN_INC_REF(connp);
 563                 SQUEUE_ENTER_ONE(connp->conn_sqp, mp, connp->conn_recv, connp,
 564                     ira, SQ_FILL, SQTAG_DCCP_CONN_REQ_UNBOUND);
 565         } else {
 566                 dccp_input_listener(connp, mp, sqp, ira);
 567         }
 568 }
 569 
 570 boolean_t
 571 dccp_verifyicmp(conn_t *connp, void *arg2, icmph_t *icmph, icmp6_t *icmp6,
 572     ip_recv_attr_t *ira)
 573 {
 574         cmn_err(CE_NOTE, "dccp_input.c: dccp_verifyicmp");
 575 
 576         return (B_TRUE);
 577 }
 578 
 579 /*
 580  * Basic sanity checks on all input packets.
 581  */
 582 static int
 583 dccp_check_input(conn_t *connp, mblk_t *mp, ip_recv_attr_t *ira)
 584 {
 585         dccp_t          *dccp = connp->conn_dccp;
 586         dccpha_t        *dccpha;
 587         uint32_t        size;
 588         uint32_t        pkt_size;
 589         uint_t          ip_hdr_len = ira->ira_ip_hdr_length;
 590 
 591         cmn_err(CE_NOTE, "dccp_input.c: dccp_check_input");
 592 
 593         size = msgdsize(mp) - (ip_hdr_len);
 594         dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
 595         pkt_size = dccpha->dha_offset * 4;
 596 
 597         /* Is packet shorter then 12 bytes? */
 598         if (size < DCCP_MIN_HEADER_LENGTH) {
 599                 return (0);
 600         }
 601 
 602         /* Data offset is greater then the packet itself */
 603         if (pkt_size > size) {
 604                 return (0);
 605         }
 606 
 607         /* Check if known packet type */
 608         if (dccpha->dha_type > DCCP_PKT_SYNCACK) {
 609                 return (0);
 610         }
 611 
 612         /*
 613          * Check data offset for this packet type and
 614          * Data, Ack, or DataAck and P.X == 0
 615          */
 616         if (dccpha->dha_x == 0) {
 617                 switch (dccpha->dha_type) {
 618                 case DCCP_PKT_DATA:
 619                         if (size < 12 || pkt_size < 12)
 620                                 return (0);
 621                         break;
 622                 case DCCP_PKT_ACK:
 623                 case DCCP_PKT_DATAACK:
 624                         if (size < 16 || pkt_size < 16)
 625                                 return (0);
 626                         break;
 627                 default:
 628                         return (0);
 629                 }
 630         } else {
 631                 switch (dccpha->dha_type) {
 632                 case DCCP_PKT_REQUEST:
 633                         if (size < 20 || pkt_size < 20)
 634                                 return (0);
 635                         break;
 636                 case DCCP_PKT_RESPONSE:
 637                 case DCCP_PKT_RESET:
 638                         if (size < 28 || pkt_size < 28)
 639                                 return (0);
 640                         break;
 641                 case DCCP_PKT_DATA:
 642                         if (size < 16 || pkt_size < 16)
 643                                 return (0);
 644                         break;
 645                 case DCCP_PKT_ACK:
 646                 case DCCP_PKT_DATAACK:
 647                 case DCCP_PKT_CLOSEREQ:
 648                 case DCCP_PKT_CLOSE:
 649                 case DCCP_PKT_SYNC:
 650                 case DCCP_PKT_SYNCACK:
 651                         if (size < 24 || pkt_size < 24)
 652                                 return (0);
 653                         break;
 654                 default:
 655                         return (0);
 656                 }
 657         }
 658 
 659         return (1);
 660 }
 661 
 662 /*
 663  * After a request-response-ack all packets end up here.
 664  */
 665 void
 666 dccp_input_data(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira)
 667 {
 668         conn_t          *connp = (conn_t *)arg;
 669         squeue_t        *sqp = (squeue_t *)arg2;
 670         dccp_t          *dccp = connp->conn_dccp;
 671         dccp_stack_t    *dccps = dccp->dccp_dccps;
 672         dccpha_t        *dccpha;
 673         dccpha_ack_t    *dccpha_ack;
 674         dccpha_ext_t    *dccpha_ext;
 675         mblk_t          *mp1;
 676         uint64_t        seq_seq;
 677         uint64_t        seq_ack;
 678         uchar_t         *iphdr;
 679         uchar_t         *rptr;
 680         sock_upcalls_t  *sockupcalls;
 681         ip_pkt_t        ipp;
 682         uint_t          ip_hdr_len;
 683         uint_t          len;
 684         int             seg_len;
 685         int             pkt_len;
 686         int             hdr_length;
 687 
 688         cmn_err(CE_NOTE, "dccp_input.c: dccp_input_data");
 689 
 690         ASSERT(DB_TYPE(mp) == M_DATA);
 691         ASSERT(mp->b_next == NULL);
 692 
 693         iphdr = mp->b_rptr;
 694         rptr = mp->b_rptr;
 695         ASSERT(OK_32PTR(rptr));
 696 
 697         /* Check basic packet characteristics */
 698         if (dccp_check_input(connp, mp, ira) == 0) {
 699                 cmn_err(CE_NOTE, "reject packet");
 700                 return;
 701         }
 702 
 703         ip_hdr_len = ira->ira_ip_hdr_length;
 704         if (connp->conn_recv_ancillary.crb_all != 0) {
 705                 /*
 706                  * Record packet information in the ip_pkt_t
 707                  */
 708                 ipp.ipp_fields = 0;
 709                 if (ira->ira_flags & IRAF_IS_IPV4) {
 710                         (void) ip_find_hdr_v4((ipha_t *)rptr, &ipp,
 711                             B_FALSE);
 712                 } else {
 713                         uint8_t nexthdrp;
 714 
 715                         /*
 716                          * IPv6 packets can only be received by applications
 717                          * that are prepared to receive IPv6 addresses.
 718                          * The IP fanout must ensure this.
 719                          */
 720                         ASSERT(connp->conn_family == AF_INET6);
 721 
 722                         (void) ip_find_hdr_v6(mp, (ip6_t *)rptr, B_TRUE, &ipp,
 723                              &nexthdrp);
 724                         ASSERT(nexthdrp == IPPROTO_DCCP);
 725 
 726                         /* Could have caused a pullup? */
 727                         iphdr = mp->b_rptr;
 728                         rptr = mp->b_rptr;
 729                 }
 730         }
 731 
 732         len = ip_hdr_len;
 733         dccpha = (dccpha_t *)&rptr[len];
 734 
 735         ASSERT((uintptr_t)(mp->b_wptr - rptr) <= (uintptr_t)INT_MAX);
 736         seg_len = (int)(mp->b_wptr - rptr) -
 737             (ip_hdr_len + DCCP_HDR_LENGTH(dccpha));
 738         if ((mp1 = mp->b_cont) != NULL && mp1->b_datap->db_type == M_DATA) {
 739                 do {
 740                         ASSERT((uintptr_t)(mp1->b_wptr - mp1->b_rptr) <=
 741                             (uintptr_t)INT_MAX);
 742                         seg_len += (int)(mp1->b_wptr - mp1->b_rptr);
 743                 } while ((mp1 = mp1->b_cont) != NULL &&
 744                     mp1->b_datap->db_type == M_DATA);
 745         }
 746 
 747         DTRACE_DCCP5(receive, mblk_t *, NULL, ip_xmit_attr_t *, connp->conn_ixa,
 748             __dtrace_dccp_void_ip_t *, iphdr, dccp_t *, dccp,
 749             __dtrace_dccp_dccph_t *, dccpha);
 750 
 751         BUMP_LOCAL(dccp->dccp_ibsegs);
 752         DTRACE_PROBE2(dccp__trace__recv, mblk_t *, mp, dccp_t *, dccp);
 753 
 754         sockupcalls = connp->conn_upcalls;
 755 
 756         len += sizeof (dccpha_t);
 757         dccpha_ext = (dccpha_ext_t *)&rptr[len];
 758 
 759         /* XXX length checks */
 760         if (dccpha->dha_x == 1) {
 761                 seq_seq = ntohs(dccpha->dha_seq);
 762                 seq_seq = seq_seq << 32;
 763                 seq_seq |= ntohl(dccpha_ext->dha_ext_seq);
 764         } else {
 765                 /* XXX */
 766         }
 767 
 768         dccp->dccp_gsr = seq_seq;
 769 
 770         switch (dccp->dccp_state) {
 771         case DCCPS_REQUEST:
 772                 cmn_err(CE_NOTE, "DCCPS_REQUEST");
 773                 break;
 774         case DCCPS_RESPOND:
 775                 cmn_err(CE_NOTE, "DCCPS_RESPOND");
 776                 break;
 777         case DCCPS_PARTOPEN:
 778                 cmn_err(CE_NOTE, "DCCPS_PARTOPEN");
 779                 break;
 780         case DCCPS_LISTEN:
 781                 cmn_err(CE_NOTE, "DCCPS_LISTEN");
 782                 break;
 783         case DCCPS_BOUND:
 784                 cmn_err(CE_NOTE, "DCCPS_BOUND");
 785                 break;
 786         case DCCPS_OPEN:
 787                 cmn_err(CE_NOTE, "DCCPS_OPEN");
 788                 break;
 789         default:
 790                 cmn_err(CE_NOTE, "Unknow state");
 791                 break;
 792         }
 793 
 794         if (dccp->dccp_state == DCCPS_RESPOND) {
 795                 dccp->dccp_state = DCCPS_OPEN;
 796                 //dccp->dccp_osr = DCCP_SEQNO_GET(mp);
 797 
 798                 if (dccp->dccp_active_open) {
 799                         cmn_err(CE_NOTE, "dccp_active_open");
 800                         if (!dccp_conn_con(dccp, iphdr, mp, NULL, ira)) {
 801                                 cmn_err(CE_NOTE, "dccp_conn_con failed");
 802                                 freemsg(mp);
 803                                 dccp->dccp_state = DCCPS_RESPOND;
 804                                 return;
 805                         }
 806 
 807                         DTRACE_DCCP5(connect__established, mblk_t *, NULL,
 808                             ip_xmit_attr_t *, connp->conn_ixa, void_ip_t *,
 809                             iphdr, dccp_t *, dccp, dccph_t *, dccpha);
 810                 } else if (IPCL_IS_NONSTR(connp)) {
 811                         /*
 812                          * Passive open socket
 813                          */
 814                         cmn_err(CE_NOTE, "nonstr");
 815 
 816                         CONN_INC_REF(connp);
 817 
 818                         if (!dccp_newconn_notify(dccp, ira)) {
 819                                 cmn_err(CE_NOTE, "dccp_newconn_notify failed");
 820                                 dccp->dccp_state = DCCPS_RESPOND;
 821                                 freemsg(mp);
 822 
 823                                 CONN_DEC_REF(connp);
 824                                 return;
 825                         }
 826 
 827                         /*
 828                          * dccp_newconn_notify() changes conn_upcalls.
 829                          */
 830                         if (connp->conn_upcalls != NULL) {
 831                                 sockupcalls = connp->conn_upcalls;
 832                         }
 833 
 834                         DTRACE_DCCP5(accept__established, mlbk_t *, NULL,
 835                             ip_xmit_attr_t *, connp->conn_ixa, void_ip_t *,
 836                             iphdr, dccp_t *, dccp, dccph_t *, dccpha);
 837                 } else {
 838                         cmn_err(CE_NOTE, "str stream");
 839                         dccp_t  *listener = dccp->dccp_listener;
 840 
 841                         ASSERT(mp != NULL);
 842                         CONN_INC_REF(connp);
 843                 }
 844         }
 845 
 846         switch (dccpha->dha_type) {
 847         case DCCP_PKT_REQUEST:
 848                 cmn_err(CE_NOTE, "DCCP_REQUEST");
 849                 break;
 850         case DCCP_PKT_RESPONSE:
 851                 cmn_err(CE_NOTE, "DCCP_RESPONSE");
 852                 break;
 853         case DCCP_PKT_DATA:
 854                 cmn_err(CE_NOTE, "DCCP_DATA");
 855                 break;
 856         case DCCP_PKT_ACK:
 857                 cmn_err(CE_NOTE, "DCCP_PKT_ACK");
 858                 break;
 859         case DCCP_PKT_DATAACK:
 860                 cmn_err(CE_NOTE, "DCCP_DATAACK");
 861                 break;
 862         case DCCP_PKT_CLOSEREQ:
 863                 cmn_err(CE_NOTE, "DCCP_CLOSEREQ");
 864                 break;
 865         case DCCP_PKT_CLOSE:
 866                 cmn_err(CE_NOTE, "DCCP_CLOSE");
 867                 break;
 868         case DCCP_PKT_RESET:
 869                 cmn_err(CE_NOTE, "DCCP_RESET");
 870                 break;
 871         case DCCP_PKT_SYNC:
 872                 cmn_err(CE_NOTE, "DCCP_SYNC");
 873                 break;
 874         case DCCP_PKT_SYNCACK:
 875                 cmn_err(CE_NOTE, "DCCP_SYNCACK");
 876                 break;
 877         default:
 878                 break;
 879         }
 880 
 881         switch (dccpha->dha_type) {
 882         case DCCP_PKT_ACK:
 883                 dccp->dccp_state = DCCPS_OPEN;
 884                 return;
 885         case DCCP_PKT_DATAACK:
 886                 dccp->dccp_state = DCCPS_OPEN;
 887                 break;
 888         case DCCP_PKT_CLOSE: {
 889                 mblk_t  *reset_mp;
 890 
 891                 reset_mp = dccp_generate_reset(connp);
 892                 dccp_send_data(dccp, reset_mp);
 893                 dccp->dccp_state = DCCPS_CLOSED;
 894                 return;
 895         }
 896         default:
 897                 break;
 898         }
 899 
 900         hdr_length = ira->ira_ip_hdr_length;
 901         hdr_length += DCCP_HDR_LENGTH(dccpha);
 902         pkt_len = ira->ira_pktlen;
 903 
 904         mp->b_wptr = rptr + pkt_len;
 905         mp->b_rptr = (uchar_t *)&mp->b_rptr[hdr_length];
 906         pkt_len -= hdr_length;
 907 
 908         if (IPCL_IS_NONSTR(connp)) {
 909                 /*
 910                  * Non-STREAMS socket.
 911                  */
 912                 boolean_t       push;
 913                 int             error;
 914 
 915                 if ((*sockupcalls->su_recv)(connp->conn_upper_handle,
 916                     mp, pkt_len, 0, &error, NULL) <= 0) {
 917                         cmn_err(CE_NOTE, "su_recv failed");
 918                         ASSERT(error != EOPNOTSUPP);
 919                 }
 920         } else if (dccp->dccp_listener != NULL) {
 921                 // dccp_recv_enqueue(dccp, mp, seq_len, ira->ira_cred);
 922         } else {
 923                 /*
 924                  * Active-STREAMS socket.
 925                  */
 926         }
 927 }