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 /*
  32  * Functions related to the output path.
  33  */
  34 
  35 #include <sys/types.h>
  36 #include <sys/stream.h>
  37 #include <sys/strsun.h>
  38 #include <sys/strsubr.h>
  39 #include <sys/stropts.h>
  40 #include <sys/strlog.h>
  41 #define _SUN_TPI_VERSION 2
  42 #include <sys/tihdr.h>
  43 #include <sys/suntpi.h>
  44 #include <sys/xti_inet.h>
  45 #include <sys/squeue_impl.h>
  46 #include <sys/squeue.h>
  47 #include <sys/tsol/tnet.h>
  48 
  49 #include <inet/common.h>
  50 #include <inet/dccp_impl.h>
  51 #include <inet/dccp_stack.h>
  52 #include <inet/ip.h>
  53 #include <inet/ipsec_impl.h>
  54 
  55 #include <sys/cmn_err.h>
  56 
  57 static void     dccp_xmit_early_reset(char *, mblk_t *, uint32_t, uint32_t,
  58                     int, ip_recv_attr_t *, ip_stack_t *, conn_t *);
  59 static boolean_t        dccp_send_rst_chk(dccp_stack_t *);
  60 
  61 /*
  62  * STREAMS
  63  */
  64 void
  65 dccp_wput(queue_t *q, mblk_t *mp)
  66 {
  67         cmn_err(CE_NOTE, "dccp_output.c: dccp_wput");
  68 }
  69 
  70 /*
  71  * Fast path write put.
  72  */
  73 void
  74 dccp_wput_data(dccp_t *dccp, mblk_t *mp, boolean_t urgent)
  75 {
  76         cmn_err(CE_NOTE, "dccp_output.c: dccp_wput_data");
  77 }
  78 
  79 /*
  80  *
  81  */
  82 void
  83 dccp_wput_sock(queue_t *wq, mblk_t *mp)
  84 {
  85         conn_t  *connp = Q_TO_CONN(wq);
  86         dccp_t  *dccp = connp->conn_dccp;
  87         struct T_capability_req *car = (struct T_capability_req *)mp->b_rptr;
  88 
  89         ASSERT(wq->q_qinfo == &dccp_sock_winit);
  90         wq->q_qinfo = &dccp_winit;
  91 
  92         ASSERT(IPCL_IS_TCP(connp));
  93         ASSERT(DCCP_IS_SOCKET(dccp));
  94 
  95         if (DB_TYPE(mp) == M_PCPROTO &&
  96             MBLKL(mp) == sizeof (struct T_capability_req) &&
  97             car->PRIM_type == T_CAPABILITY_REQ) {
  98                 dccp_capability_req(dccp, mp);
  99                 return;
 100         }
 101 
 102         dccp_wput(wq, mp);
 103 }
 104 
 105 /* ARGSUSED */
 106 void
 107 dccp_wput_fallback(queue_t *eq, mblk_t *mp)
 108 {
 109         cmn_err(CE_NOTE, "dccp_output.c: dccp_wput_fallback");
 110 
 111 #ifdef DEBUG
 112         cmn_err(CE_CONT, "tcp_wput_fallback: Message during fallback \n");
 113 #endif /* DEBUG */
 114 
 115         freemsg(mp);
 116 }
 117 
 118 /*
 119  * Output fast path.
 120  */
 121 void
 122 dccp_output(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
 123 {
 124         conn_t          *connp = (conn_t *)arg;
 125         dccp_t          *dccp = connp->conn_dccp;
 126         dccp_stack_t    *dccps = dccp->dccp_dccps;
 127         dccpha_t        *dccpha;
 128         mblk_t          *mp1;
 129         ip_xmit_attr_t  *ixa;
 130         struct datab    *db;
 131         uchar_t         *rptr;
 132         uint32_t        msize;
 133         uint32_t        sum;
 134         int             len;
 135         int             plen;
 136 
 137         cmn_err(CE_NOTE, "dccp_output.c: dccp_output");
 138 
 139         ASSERT((connp->conn_fanout != NULL && connp->conn_ref >= 4) ||
 140             (connp->conn_fanout == NULL && connp->conn_ref >= 3));
 141 
 142         ASSERT(DB_TYPE(mp) == M_DATA);
 143         msize = (mp->b_cont == NULL) ? MBLKL(mp) : msgdsize(mp);
 144 
 145         ASSERT((uintptr_t)(mp->b_wptr - mp->b_rptr) <= (uintptr_t)INT_MAX);
 146         len = (int)(mp->b_wptr - mp->b_rptr);
 147 
 148         if ((mp->b_cont != NULL) ||
 149             (dccp->dccp_state != DCCPS_OPEN) ||
 150             (len == 0)) {
 151                 dccp_wput_data(dccp, mp, B_FALSE);
 152                 return;
 153         }
 154 
 155         mp1 = dupb(mp);
 156         if (mp1 == NULL) {
 157                 goto no_memory;
 158         }
 159 
 160         /* Adjust header information */
 161         dccpha = dccp->dccp_dccpha;
 162 
 163         sum = len + connp->conn_ht_ulp_len + connp->conn_sum;
 164         sum = (sum >> 16) + (sum & 0xffff);
 165         dccpha->dha_sum = htons(sum);
 166 
 167         DCCPS_BUMP_MIB(dccps, dccpOutDataSegs);
 168         DCCPS_UPDATE_MIB(dccps, dccpOutDataBytes, len);
 169         BUMP_LOCAL(dccp->dccp_obsegs);
 170 
 171         plen = len + connp->conn_ht_iphc_len;
 172 
 173         ixa = connp->conn_ixa;
 174         ixa->ixa_pktlen = plen;
 175 
 176         if (ixa->ixa_flags & IXAF_IS_IPV4) {
 177                 dccp->dccp_ipha->ipha_length = htons(plen);
 178         } else {
 179                 dccp->dccp_ip6h->ip6_plen = htons(plen - IPV6_HDR_LEN);
 180         }
 181 
 182         rptr = mp1->b_rptr;
 183         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 184 
 185         dccp_send_data(dccp, mp1);
 186 
 187         return;
 188 
 189 no_memory:
 190         return;
 191 }
 192 
 193 void
 194 dccp_output_urgent(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
 195 {
 196         cmn_err(CE_NOTE, "dccp_output.c: dccp_output_urgent");
 197 }
 198 
 199 void
 200 dccp_close_output(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
 201 {
 202         conn_t          *connp = (conn_t *)arg;
 203         dccp_t          *dccp = connp->conn_dccp;
 204         dccp_stack_t    *dccps = dccp->dccp_dccps;
 205         char            *msg;
 206 
 207         cmn_err(CE_NOTE, "dccp_output.c: dccp_close_output");
 208 
 209         /*
 210          * When a non-STREAMS socket is being closed, it does not always
 211          * stick around waiting for tcp_close_output to run and can therefore
 212          * have dropped a reference already. So adjust the asserts accordingly.
 213          */
 214         ASSERT((connp->conn_fanout != NULL &&
 215             connp->conn_ref >= (IPCL_IS_NONSTR(connp) ? 3 : 4)) ||
 216             (connp->conn_fanout == NULL &&
 217             connp->conn_ref >= (IPCL_IS_NONSTR(connp) ? 2 : 3)));
 218 
 219         msg = NULL;
 220         switch (dccp->dccp_state) {
 221         case DCCPS_CLOSED:
 222                 break;
 223         case DCCPS_BOUND:
 224                 break;
 225         case DCCPS_REQUEST:
 226                 msg = "dccp_close, during connect";
 227                 break;
 228         case DCCPS_RESPOND:
 229                 /* FALLTHRU */
 230         default:
 231                 /*
 232                  * If SO_LINGER has set a zero linger time, abort the
 233                  * connection with a reset.
 234                  */
 235                 if (connp->conn_linger && connp->conn_lingertime == 0) {
 236                         msg = "dccp_close, zero lingertime";
 237                         break;
 238                 }
 239         }
 240 }
 241 
 242 #pragma inline(dccp_send_data)
 243 
 244 void
 245 dccp_send_data(dccp_t *dccp, mblk_t *mp)
 246 {
 247         conn_t  *connp = dccp->dccp_connp;
 248         int     error;
 249 
 250         cmn_err(CE_NOTE, "dccp_output.c: dccp_sent_data");
 251 
 252         /* XXX zcopy aware */
 253 
 254         DTRACE_DCCP5(send, mblk_t *, NULL, ip_xmit_attr_t *, connp->conn_ixa,
 255             __dtrace_dccp_void_ip_t *, mp->b_rptr, dccp_t *, dccp,
 256             __dtrace_dccp_dccph_t *,
 257             &mp->b_rptr[connp->conn_ixa->ixa_ip_hdr_length]);
 258 
 259         ASSERT(connp->conn_ixa->ixa_notify_cookie == connp->conn_tcp);
 260         error = conn_ip_output(mp, connp->conn_ixa);
 261         if (error != 0) {
 262                 cmn_err(CE_NOTE, "conn_ip_output failed with code %d\n", error);
 263         }
 264 }
 265 
 266 /*
 267  * Send a reset as response to an incoming packet or
 268  * reset a connection.
 269  */
 270 void
 271 dccp_xmit_listeners_reset(mblk_t *mp, ip_recv_attr_t *ira, ip_stack_t *ipst,
 272     conn_t *connp)
 273 {
 274         netstack_t      *ns = ipst->ips_netstack;
 275         dccp_stack_t    *dccps = ns->netstack_dccp;
 276         ipsec_stack_t   *ipss = dccps->dccps_netstack->netstack_ipsec;
 277         dccpha_t        *dccpha;
 278         ipha_t          *ipha;
 279         ip6_t           *ip6h;
 280         uchar_t         *rptr;
 281         uint32_t        seq_len;
 282         uint_t          ip_hdr_len = ira->ira_ip_hdr_length;
 283         boolean_t       policy_present;
 284 
 285         cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_listeners_reset");
 286 
 287         DCCP_STAT(dccps, dccp_no_listener);
 288 
 289         if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
 290                 policy_present = ipss->ipsec_inbound_v4_policy_present;
 291                 ipha = (ipha_t *)mp->b_rptr;
 292                 ip6h = NULL;
 293         } else {
 294                 policy_present = ipss->ipsec_inbound_v6_policy_present;
 295                 ipha = NULL;
 296                 ip6h = (ip6_t *)mp->b_rptr;
 297         }
 298 
 299         if (policy_present) {
 300                 mp = ipsec_check_global_policy(mp, (conn_t *)NULL, ipha, ip6h,
 301                     ira, ns);
 302                 if (mp == NULL) {
 303                         return;
 304                 }
 305         }
 306 
 307         rptr = mp->b_rptr;
 308 
 309         dccpha = (dccpha_t *)&rptr[ip_hdr_len];
 310 
 311         seq_len = msgdsize(mp) - (ip_hdr_len);
 312 
 313         dccp_xmit_early_reset("no dccp, reset", mp, 0,
 314             0, 0, ira, ipst, connp);
 315 }
 316 
 317 /*
 318  * RFC 4340, Section 8.1.3
 319  */
 320 static void
 321 dccp_xmit_early_reset(char *str, mblk_t *mp, uint32_t seq, uint32_t ack, int ctl,
 322     ip_recv_attr_t *ira, ip_stack_t *ipst, conn_t *connp)
 323 {
 324         dccpha_t        *dccpha;
 325         dccpha_t        *nmp_dccpha;
 326         dccpha_ack_t    *nmp_dccpha_ack;
 327         dccpha_reset_t  *dccpha_reset;
 328         dccpha_reset_t  *nmp_dccpha_reset;
 329         dccpha_ext_t    *dccpha_ext;
 330         dccpha_ext_t    *nmp_dccpha_ext;
 331         netstack_t      *ns = ipst->ips_netstack;
 332         dccp_stack_t    *dccps = ns->netstack_dccp;
 333         ip6_t           *ip6h;
 334         ipha_t          *ipha;
 335         ipha_t          *nmp_ipha;
 336         ip_xmit_attr_t  ixas;
 337         ip_xmit_attr_t  *ixa;
 338         in6_addr_t      v6addr;
 339         ipaddr_t        v4addr;
 340         mblk_t          *nmp;
 341         uint64_t        pkt_ack;
 342         uint_t          ip_hdr_len = ira->ira_ip_hdr_length;
 343         ushort_t        port;
 344         ushort_t        len;
 345 
 346         cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_early_reset");
 347 
 348         if (!dccp_send_rst_chk(dccps)) {
 349                 cmn_err(CE_NOTE, "dccp_output.c: not sending reset packet");
 350                 DCCP_STAT(dccps, dccp_rst_unsent);
 351                 freemsg(mp);
 352                 return;
 353         }
 354 
 355                 bzero(&ixas, sizeof (ixas));
 356                 ixa = &ixas;
 357 
 358                 ixa->ixa_flags |= IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE;
 359                 ixa->ixa_protocol = IPPROTO_DCCP;
 360                 ixa->ixa_zoneid = ira->ira_zoneid;
 361                 ixa->ixa_ifindex = 0;
 362                 ixa->ixa_ipst = ipst;
 363                 ixa->ixa_cred = kcred;
 364                 ixa->ixa_cpid = NOPID;
 365 
 366         if (str && dccps->dccps_dbg) {
 367                 (void) strlog(DCCP_MOD_ID, 0, 1, SL_TRACE,
 368                     "dccp_xmit_early_reset: '%s', seq 0x%x, ack 0x%x, "
 369                     "flags 0x%x",
 370                     str, seq, ack, ctl);
 371         }
 372 
 373         if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
 374                 ipha = (ipha_t *)mp->b_rptr;
 375 
 376         } else {
 377                 /* XXX */
 378         }
 379 
 380         /*
 381          * Allocate a new DCCP reset message
 382          */
 383         len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t);
 384         nmp = allocb(len, BPRI_MED);
 385         if (nmp == NULL) {
 386                 cmn_err(CE_NOTE, "alloc failed");
 387                 return;
 388         }
 389         bcopy(mp->b_rptr, nmp->b_wptr, ip_hdr_len + sizeof (dccpha_t));
 390 
 391         nmp_dccpha = (dccpha_t *)&nmp->b_rptr[ip_hdr_len];
 392         nmp_dccpha->dha_offset = 7;
 393 
 394         if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
 395                 nmp_ipha = (ipha_t *)nmp->b_rptr;
 396 
 397                 nmp_ipha->ipha_length = htons(len);
 398                 nmp_ipha->ipha_src = ipha->ipha_dst;
 399                 nmp_ipha->ipha_dst = ipha->ipha_src;
 400 
 401                 ixa->ixa_flags |= IXAF_IS_IPV4;
 402                 ixa->ixa_ip_hdr_length = ip_hdr_len;
 403         } else {
 404                 cmn_err(CE_NOTE, "not v4");
 405         }
 406 
 407         dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
 408 
 409         nmp->b_wptr = &nmp->b_rptr[len];
 410 
 411         ixa->ixa_pktlen = len; // ?
 412 
 413         nmp_dccpha->dha_fport = dccpha->dha_lport;
 414         nmp_dccpha->dha_lport = dccpha->dha_fport;
 415         nmp_dccpha->dha_type = DCCP_PKT_RESET;
 416         nmp_dccpha->dha_x = 1;
 417         nmp_dccpha->dha_res_seq = 0;
 418         nmp_dccpha->dha_seq = 0;
 419 
 420         nmp_dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t));
 421 
 422         dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 423         nmp_dccpha_ext = (dccpha_ext_t *)&nmp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 424         nmp_dccpha_ext->dha_ext_seq = 0;
 425 
 426         len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t);
 427         nmp_dccpha_ack = (dccpha_ack_t *)&nmp->b_rptr[len];
 428         nmp_dccpha_ack->dha_ack_high = dccpha->dha_seq;
 429         nmp_dccpha_ack->dha_ack_low = dccpha_ext->dha_ext_seq;
 430 
 431         len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t);
 432         nmp_dccpha_reset = (dccpha_reset_t *)&nmp->b_rptr[len];
 433         nmp_dccpha_reset->dha_reset_code = DCCP_RESET_CONNECTION_REFUSED;
 434         nmp_dccpha_reset->dha_reset_data[0] = 0;
 435         nmp_dccpha_reset->dha_reset_data[1] = 0;
 436         nmp_dccpha_reset->dha_reset_data[2] = 0;
 437 
 438         (void) ip_output_simple(nmp, ixa);
 439 
 440         ixa_cleanup(ixa);
 441 }
 442 
 443 /*
 444  *
 445  */
 446 static boolean_t
 447 dccp_send_rst_chk(dccp_stack_t *dccps)
 448 {
 449         int64_t now;
 450 
 451         if (dccps->dccps_rst_sent_rate_enabled != 0) {
 452                 now = ddi_get_lbolt64();
 453                 if (TICK_TO_MSEC(now - dccps->dccps_last_rst_intrvl) >
 454                     1 * SECONDS) {
 455                         dccps->dccps_last_rst_intrvl = now;
 456                         dccps->dccps_rst_cnt = 1;
 457                 } else if (++dccps->dccps_rst_cnt > dccps->dccps_rst_sent_rate) {
 458                         return (B_FALSE);
 459                 }
 460         }
 461 
 462         return (B_TRUE);
 463 }
 464 
 465 /* ARGSUSED2 */
 466 void
 467 dccp_send_synack(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
 468 {
 469         conn_t          *econnp = (conn_t *)arg;
 470         dccp_t          *dccp = econnp->conn_dccp;
 471         ip_xmit_attr_t  *ixa = econnp->conn_ixa;
 472 
 473         cmn_err(CE_NOTE, "dccp_output.c: dccp_send_synack");
 474 
 475         /*
 476          * Guard against a RESET having blown it away while on the
 477          * squeue.
 478          */
 479         if (dccp->dccp_state == DCCPS_CLOSED) {
 480                 freemsg(mp);
 481                 return;
 482         }
 483 
 484         ixa->ixa_pktlen = msgdsize(mp);
 485         (void) conn_ip_output(mp, ixa);
 486 }
 487 
 488 mblk_t *
 489 dccp_xmit_mp(dccp_t *dccp, mblk_t *mp, int32_t max_to_send, int32_t *offset,
 490     mblk_t **end_mp, uint32_t seq, boolean_t sendall, uint32_t *seg_len,
 491     boolean_t rexmit)
 492 {
 493         conn_t          *connp = dccp->dccp_connp;
 494         dccp_stack_t    *dccps = dccp->dccp_dccps;
 495         dccpha_t        *dccpha;
 496         dccpha_ext_t    *dccpha_ext;
 497         dccpha_ack_t    *dccpha_ack;
 498         dccpha_srv_t    *dccpha_srv;
 499         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 500         mblk_t          *mp1;
 501         uchar_t         *rptr;
 502         ushort_t        len;
 503         int             data_length;
 504 
 505         cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_mp");
 506 
 507         // dccpha_t already in iphc_len?
 508         len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4;
 509 
 510         mp1 = allocb(len, BPRI_MED);
 511         if (mp1 == NULL) {
 512                 cmn_err(CE_NOTE, "allocb failed");
 513                 return (NULL);
 514         }
 515 
 516         data_length = 0;
 517 
 518         rptr = mp1->b_rptr;
 519         mp1->b_wptr = &mp1->b_rptr[len];
 520         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 521         dccpha = (dccpha_t *)&rptr[ixa->ixa_ip_hdr_length];
 522         dccpha->dha_type = DCCP_PKT_RESPONSE;
 523         dccpha->dha_offset = 8;
 524         dccpha->dha_x = 1;
 525         dccpha->dha_ccval = 0;
 526         dccpha->dha_cscov = 0;
 527         dccpha->dha_reserved = 0;
 528         dccpha->dha_res_seq = 0;
 529         dccpha->dha_seq = 0;
 530 
 531         dccpha_ext = (dccpha_ext_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t)];
 532         dccpha_ext->dha_ext_seq = 0;
 533 
 534         dccpha_ack = (dccpha_ack_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t)];
 535         dccpha_ack->dha_ack_reserved = 0;
 536         dccpha_ack->dha_ack_high = 0;
 537         dccpha_ack->dha_ack_low = 0;
 538 
 539         dccpha_srv = (dccpha_srv_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t)];
 540         dccpha_srv->dha_srv_code = 0;
 541 
 542         return (mp1);
 543 }
 544 
 545 /*
 546  * Generate a DCCP-Response packet.
 547  */
 548 mblk_t *
 549 dccp_generate_response(conn_t *connp, mblk_t *mp)
 550 {
 551         dccpha_t        *dccpha;
 552         dccpha_ext_t    *dccpha_ext;
 553         dccpha_ack_t    *dccpha_ack;
 554         dccpha_srv_t    *dccpha_srv;
 555         mblk_t          *mp1;
 556         uint64_t        seq;
 557         uint64_t        ack;
 558         uint16_t        ack_high;
 559         uint32_t        ack_low;
 560 //      uint_t          ip_hdr_len = ira->ira_ip_hdr_length;
 561         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 562         uint_t          ip_hdr_len;
 563         uint_t          len;
 564         uint_t          total_hdr_len;
 565         uchar_t         *rptr;
 566         dccp_t          *dccp = connp->conn_dccp;
 567         void            *options;
 568         size_t          opt_len;
 569         int             error;
 570 
 571         cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_packet");
 572 
 573         ip_hdr_len = ixa->ixa_ip_hdr_length;
 574 
 575         if (mp == NULL) {
 576                 cmn_err(CE_NOTE, "NULL pointer mp");
 577                 return (NULL);
 578         }
 579 
 580         dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
 581         dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 582 
 583         ack_high = dccpha->dha_seq;
 584         ack_low = dccpha_ext->dha_ext_seq;
 585 
 586         seq = ntohs(ack_high) << 31;
 587         seq |= ntohl(ack_low);
 588 
 589         dccp->dccp_isr = seq;
 590         dccp->dccp_gsr = seq;
 591         dccp->dccp_swl = seq;
 592         dccp->dccp_swh = seq;
 593         dccp->dccp_gss++;
 594 
 595         error = dccp_generate_options(dccp, &options, &opt_len);
 596         if (error != 0) {
 597                 cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_options failed");
 598         }
 599         cmn_err(CE_NOTE, "generated options len: %d", (int) opt_len);
 600 
 601 
 602         /*
 603          * conn_ht_iphc_len = ip_hdr_length (20) + ulp_hdr_length
 604          * (20) simple ip header (without vtag or options)
 605          */
 606         total_hdr_len = len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4 + opt_len;
 607         mp1 = allocb(len, BPRI_MED);
 608         if (mp1 == NULL) {
 609                 cmn_err(CE_NOTE, "allocb failed");
 610                 return (NULL);
 611         }
 612 
 613         rptr = mp1->b_rptr;
 614         mp1->b_wptr = &mp1->b_rptr[len];
 615 
 616         bcopy(options, &mp1->b_rptr[len-opt_len], opt_len);
 617         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 618         dccpha = (dccpha_t *)&rptr[ip_hdr_len];
 619 
 620         dccpha->dha_type = DCCP_PKT_RESPONSE;
 621         dccpha->dha_offset = 7 + (opt_len / 4);
 622         dccpha->dha_x = 1;
 623         dccpha->dha_ccval = 0;
 624         dccpha->dha_cscov = 0;
 625         dccpha->dha_reserved = 0;
 626         dccpha->dha_res_seq = 0;
 627         dccpha->dha_seq = htons(dccp->dccp_gss >> 32);;
 628         dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4 + opt_len);
 629 
 630 
 631         dccpha_ext = (dccpha_ext_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 632         dccpha_ext->dha_ext_seq = htonl(dccp->dccp_gss & 0xffffffff);
 633 
 634         dccpha_ack = (dccpha_ack_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t)];
 635         dccpha_ack->dha_ack_high = ack_high;
 636         dccpha_ack->dha_ack_low = ack_low;
 637 
 638         dccpha_srv = (dccpha_srv_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t)];
 639         dccpha_srv->dha_srv_code = 0;
 640 
 641         ixa->ixa_pktlen = total_hdr_len;
 642 
 643         if (ixa->ixa_flags & IXAF_IS_IPV4) {
 644                 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
 645         } else {
 646                 ip6_t *ip6 = (ip6_t *)rptr;
 647 
 648                 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
 649         }
 650 
 651         cmn_err(CE_NOTE, "IPHC LEN: %d", connp->conn_ht_iphc_len);
 652         cmn_err(CE_NOTE, "TOTAL LEN: %d", total_hdr_len);
 653 
 654         kmem_free(options, opt_len);
 655 
 656         return (mp1);
 657 }
 658 
 659 /*
 660  * Generate a request packet. Must use 48-bit sequence
 661  * numbers.
 662  */
 663 mblk_t *
 664 dccp_generate_request(conn_t *connp)
 665 {
 666         dccp_t          *dccp = connp->conn_dccp;
 667         dccpha_t        *dccpha;
 668         dccpha_ext_t    *dccpha_ext;
 669         dccpha_srv_t    *dccpha_srv;
 670         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 671         mblk_t          *mp;
 672         uchar_t         *rptr;
 673         uint_t          total_hdr_len;
 674         uint_t          len;
 675 
 676         cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_request");
 677 
 678         total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) +
 679             sizeof (dccpha_srv_t);
 680         mp = allocb(total_hdr_len, BPRI_MED);
 681         if (mp == NULL) {
 682                 cmn_err(CE_NOTE, "allocb failed");
 683                 return (NULL);
 684         }
 685 
 686         rptr = mp->b_rptr;
 687         mp->b_wptr = &mp->b_rptr[total_hdr_len];
 688 
 689         /* Copy in the template header */
 690         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 691 
 692         len = ixa->ixa_ip_hdr_length;
 693         dccpha = (dccpha_t *)&rptr[len];
 694         dccpha->dha_type = DCCP_PKT_REQUEST;
 695         dccpha->dha_offset = (sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
 696             sizeof (dccpha_srv_t)) / 4;
 697         dccpha->dha_x = 1;
 698         dccpha->dha_ccval = 0;
 699         dccpha->dha_cscov = 0;
 700         dccpha->dha_reserved = 0;
 701         dccpha->dha_res_seq = 0;
 702         dccpha->dha_seq = 0;
 703         dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
 704             sizeof (dccpha_srv_t));
 705 
 706         /* Extended sequence number */
 707         len += sizeof (dccpha_t);
 708         dccpha_ext = (dccpha_ext_t *)&rptr[len];
 709 
 710         /* Service number */
 711         len += sizeof (dccpha_ext_t);
 712         dccpha_srv = (dccpha_srv_t *)&rptr[len];
 713         dccpha_srv->dha_srv_code = 0;
 714 
 715         ixa->ixa_pktlen = total_hdr_len;
 716 
 717         if (ixa->ixa_flags & IXAF_IS_IPV4) {
 718                 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
 719         } else {
 720                 ip6_t *ip6 = (ip6_t *)rptr;
 721 
 722                 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
 723         }
 724 
 725         return (mp);
 726 }
 727 
 728 /*
 729  * Close packet.
 730  */
 731 mblk_t *
 732 dccp_generate_reset(conn_t *connp)
 733 {
 734         dccp_t          *dccp = connp->conn_dccp;
 735         dccpha_t        *dccpha;
 736         dccpha_ext_t    *dccpha_ext;
 737         dccpha_ack_t    *dccpha_ack;
 738         dccpha_reset_t  *dccpha_reset;
 739         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 740         mblk_t          *mp;
 741         uint64_t        gss;
 742         uchar_t         *rptr;
 743         uint_t          total_hdr_len;
 744         uint_t          len = ixa->ixa_ip_hdr_length;
 745 
 746         cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_reset");
 747 
 748         /* XXX */
 749         dccp->dccp_gss++;
 750 
 751         /*
 752          * Allocate a new DCCP reset message
 753          */
 754         total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) +
 755             sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t);
 756         mp = allocb(total_hdr_len, BPRI_MED);
 757         if (mp == NULL) {
 758                 cmn_err(CE_NOTE, "allocb failed");
 759                 return(NULL);
 760         }
 761 
 762         rptr = mp->b_rptr;
 763         mp->b_wptr = &mp->b_rptr[total_hdr_len];
 764 
 765         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 766 
 767         len = ixa->ixa_ip_hdr_length;
 768         dccpha = (dccpha_t *)&mp->b_rptr[len];
 769         dccpha->dha_type = DCCP_PKT_RESET;
 770         dccpha->dha_offset = 7;
 771         dccpha->dha_x = 1;
 772         dccpha->dha_ccval = 0;
 773         dccpha->dha_cscov = 0;
 774         dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
 775             sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t));
 776         dccpha->dha_seq = htons(dccp->dccp_gss >> 32);
 777 
 778         len += sizeof (dccpha_t);
 779         dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[len];
 780         dccpha_ext->dha_ext_seq = htonl(dccp->dccp_gss & 0xffffffff);
 781 
 782         len += sizeof (dccpha_ext_t);
 783         dccpha_ack = (dccpha_ack_t *)&mp->b_rptr[len];
 784         dccpha_ack->dha_ack_high = htons(dccp->dccp_gsr >> 32);
 785         dccpha_ack->dha_ack_low = htonl(dccp->dccp_gsr & 0xffffffff);
 786 
 787         len += sizeof (dccpha_ack_t);
 788         dccpha_reset = (dccpha_reset_t *)&mp->b_rptr[len];
 789         dccpha_reset->dha_reset_code = DCCP_RESET_CLOSED;
 790         dccpha_reset->dha_reset_data[0] = 0;
 791         dccpha_reset->dha_reset_data[1] = 0;
 792         dccpha_reset->dha_reset_data[2] = 0;
 793 
 794         ixa->ixa_pktlen = total_hdr_len;
 795 
 796         if (ixa->ixa_flags & IXAF_IS_IPV4) {
 797                 cmn_err(CE_NOTE, "setting ip len for ipv4: %d", total_hdr_len);
 798                 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
 799         } else {
 800                 ip6_t *ip6 = (ip6_t *)rptr;
 801 
 802                 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
 803         }
 804 
 805         return (mp);
 806 }