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 static int      dccp_xmit_end(dccp_t *);
  61 static mblk_t   *dccp_generate_common(conn_t *, uint8_t, uint_t);
  62 
  63 /*
  64  * STREAMS
  65  */
  66 void
  67 dccp_wput(queue_t *q, mblk_t *mp)
  68 {
  69         cmn_err(CE_NOTE, "dccp_output.c: dccp_wput");
  70 }
  71 
  72 /*
  73  * Fast path write put.
  74  */
  75 void
  76 dccp_wput_data(dccp_t *dccp, mblk_t *mp, boolean_t urgent)
  77 {
  78         cmn_err(CE_NOTE, "dccp_output.c: dccp_wput_data");
  79 }
  80 
  81 /*
  82  *
  83  */
  84 void
  85 dccp_wput_sock(queue_t *wq, mblk_t *mp)
  86 {
  87         conn_t  *connp = Q_TO_CONN(wq);
  88         dccp_t  *dccp = connp->conn_dccp;
  89         struct T_capability_req *car = (struct T_capability_req *)mp->b_rptr;
  90 
  91         cmn_err(CE_NOTE, "dccp_wput_sock");
  92 
  93         ASSERT(wq->q_qinfo == &dccp_sock_winit);
  94         wq->q_qinfo = &dccp_winit;
  95 
  96         ASSERT(IPCL_IS_TCP(connp));
  97         ASSERT(DCCP_IS_SOCKET(dccp));
  98 
  99         if (DB_TYPE(mp) == M_PCPROTO &&
 100             MBLKL(mp) == sizeof (struct T_capability_req) &&
 101             car->PRIM_type == T_CAPABILITY_REQ) {
 102                 dccp_capability_req(dccp, mp);
 103                 return;
 104         }
 105 
 106         dccp_wput(wq, mp);
 107 }
 108 
 109 /* ARGSUSED */
 110 void
 111 dccp_wput_fallback(queue_t *eq, mblk_t *mp)
 112 {
 113         cmn_err(CE_NOTE, "dccp_output.c: dccp_wput_fallback");
 114 
 115 #ifdef DEBUG
 116         cmn_err(CE_CONT, "tcp_wput_fallback: Message during fallback \n");
 117 #endif /* DEBUG */
 118 
 119         freemsg(mp);
 120 }
 121 
 122 /*
 123  * Initiate closedown sequence on an active connection.
 124  */
 125 static int
 126 dccp_xmit_end(dccp_t *dccp)
 127 {
 128         conn_t  *connp = dccp->dccp_connp;
 129         mblk_t  *mp;
 130 
 131         /* XXX */
 132 
 133         return (0);
 134 }
 135 
 136 /*
 137  * Output fast path.
 138  */
 139 void
 140 dccp_output(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
 141 {
 142         conn_t          *connp = (conn_t *)arg;
 143         dccp_t          *dccp = connp->conn_dccp;
 144         dccp_stack_t    *dccps = dccp->dccp_dccps;
 145         dccpha_t        *dccpha;
 146         mblk_t          *mp1;
 147         ip_xmit_attr_t  *ixa;
 148         struct datab    *db;
 149         uchar_t         *rptr;
 150         uint32_t        msize;
 151         uint32_t        sum;
 152         int             len;
 153         int             plen;
 154 
 155         cmn_err(CE_NOTE, "dccp_output.c: dccp_output");
 156 
 157         ASSERT((connp->conn_fanout != NULL && connp->conn_ref >= 4) ||
 158             (connp->conn_fanout == NULL && connp->conn_ref >= 3));
 159 
 160         ASSERT(DB_TYPE(mp) == M_DATA);
 161         msize = (mp->b_cont == NULL) ? MBLKL(mp) : msgdsize(mp);
 162 
 163         ASSERT((uintptr_t)(mp->b_wptr - mp->b_rptr) <= (uintptr_t)INT_MAX);
 164         len = (int)(mp->b_wptr - mp->b_rptr);
 165 
 166         if ((mp->b_cont != NULL) ||
 167             (dccp->dccp_state != DCCPS_OPEN) ||
 168             (len == 0)) {
 169                 dccp_wput_data(dccp, mp, B_FALSE);
 170                 return;
 171         }
 172 
 173         mp1 = dupb(mp);
 174         if (mp1 == NULL) {
 175                 goto no_memory;
 176         }
 177 
 178         /* Adjust header information */
 179         dccpha = dccp->dccp_dccpha;
 180 
 181         sum = len + connp->conn_ht_ulp_len + connp->conn_sum;
 182         sum = (sum >> 16) + (sum & 0xffff);
 183         dccpha->dha_sum = htons(sum);
 184 
 185         DCCPS_BUMP_MIB(dccps, dccpOutDataSegs);
 186         DCCPS_UPDATE_MIB(dccps, dccpOutDataBytes, len);
 187         BUMP_LOCAL(dccp->dccp_obsegs);
 188 
 189         plen = len + connp->conn_ht_iphc_len;
 190 
 191         ixa = connp->conn_ixa;
 192         ixa->ixa_pktlen = plen;
 193 
 194         if (ixa->ixa_flags & IXAF_IS_IPV4) {
 195                 dccp->dccp_ipha->ipha_length = htons(plen);
 196         } else {
 197                 dccp->dccp_ip6h->ip6_plen = htons(plen - IPV6_HDR_LEN);
 198         }
 199 
 200         rptr = mp1->b_rptr;
 201         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 202 
 203         dccp_send_data(dccp, mp1);
 204 
 205         return;
 206 
 207 no_memory:
 208         return;
 209 }
 210 
 211 void
 212 dccp_output_urgent(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
 213 {
 214         cmn_err(CE_NOTE, "dccp_output.c: dccp_output_urgent");
 215 }
 216 
 217 void
 218 dccp_close_output(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
 219 {
 220         conn_t          *connp = (conn_t *)arg;
 221         dccp_t          *dccp = connp->conn_dccp;
 222         dccp_stack_t    *dccps = dccp->dccp_dccps;
 223         char            *msg;
 224 
 225         cmn_err(CE_NOTE, "dccp_output.c: dccp_close_output");
 226 
 227         /*
 228          * When a non-STREAMS socket is being closed, it does not always
 229          * stick around waiting for tcp_close_output to run and can therefore
 230          * have dropped a reference already. So adjust the asserts accordingly.
 231          */
 232         ASSERT((connp->conn_fanout != NULL &&
 233             connp->conn_ref >= (IPCL_IS_NONSTR(connp) ? 3 : 4)) ||
 234             (connp->conn_fanout == NULL &&
 235             connp->conn_ref >= (IPCL_IS_NONSTR(connp) ? 2 : 3)));
 236 
 237         msg = NULL;
 238         switch (dccp->dccp_state) {
 239         case DCCPS_CLOSED:
 240                 break;
 241         case DCCPS_BOUND:
 242                 break;
 243         case DCCPS_REQUEST:
 244                 msg = "dccp_close, during connect";
 245                 break;
 246         case DCCPS_RESPOND:
 247                 /* FALLTHRU */
 248         default:
 249                 /*
 250                  * If SO_LINGER has set a zero linger time, abort the
 251                  * connection with a reset.
 252                  */
 253                 if (connp->conn_linger && connp->conn_lingertime == 0) {
 254                         msg = "dccp_close, zero lingertime";
 255                         break;
 256                 }
 257         }
 258 }
 259 
 260 /* ARGSUSED */
 261 void
 262 dccp_shutdown_output(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
 263 {
 264         conn_t  *connp = (conn_t *)arg;
 265         dccp_t  *dccp = connp->conn_dccp;
 266 
 267         freemsg(mp);
 268 
 269         if (dccp_xmit_end(dccp) != 0) {
 270                 /*
 271                  * We were crossing FINs and got a reset from
 272                  * the other side. Just ignore it.
 273                  */
 274                 if (connp->conn_debug) {
 275                         (void) strlog(DCCP_MOD_ID, 0, 1,
 276                             SL_ERROR|SL_TRACE,
 277                             "dccp_shutdown_output() out of state %s",
 278                             dccp_display(dccp, NULL, DISP_ADDR_AND_PORT));
 279                 }
 280         }
 281 }
 282 
 283 #pragma inline(dccp_send_data)
 284 
 285 void
 286 dccp_send_data(dccp_t *dccp, mblk_t *mp)
 287 {
 288         conn_t  *connp = dccp->dccp_connp;
 289         int     error;
 290 
 291         cmn_err(CE_NOTE, "dccp_output.c: dccp_sent_data");
 292 
 293         /* XXX zcopy aware */
 294 
 295         DTRACE_DCCP5(send, mblk_t *, NULL, ip_xmit_attr_t *, connp->conn_ixa,
 296             __dtrace_dccp_void_ip_t *, mp->b_rptr, dccp_t *, dccp,
 297             __dtrace_dccp_dccph_t *,
 298             &mp->b_rptr[connp->conn_ixa->ixa_ip_hdr_length]);
 299 
 300         ASSERT(connp->conn_ixa->ixa_notify_cookie == connp->conn_tcp);
 301         error = conn_ip_output(mp, connp->conn_ixa);
 302         if (error != 0) {
 303                 cmn_err(CE_NOTE, "conn_ip_output failed with code %d\n", error);
 304         }
 305 }
 306 
 307 /*
 308  * Send a reset as response to an incoming packet or
 309  * reset a connection.
 310  */
 311 void
 312 dccp_xmit_listeners_reset(mblk_t *mp, ip_recv_attr_t *ira, ip_stack_t *ipst,
 313     conn_t *connp)
 314 {
 315         netstack_t      *ns = ipst->ips_netstack;
 316         dccp_stack_t    *dccps = ns->netstack_dccp;
 317         ipsec_stack_t   *ipss = dccps->dccps_netstack->netstack_ipsec;
 318         dccpha_t        *dccpha;
 319         ipha_t          *ipha;
 320         ip6_t           *ip6h;
 321         uchar_t         *rptr;
 322         uint32_t        seq_len;
 323         uint_t          ip_hdr_len = ira->ira_ip_hdr_length;
 324         boolean_t       policy_present;
 325 
 326         cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_listeners_reset");
 327 
 328         DCCP_STAT(dccps, dccp_no_listener);
 329 
 330         if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
 331                 policy_present = ipss->ipsec_inbound_v4_policy_present;
 332                 ipha = (ipha_t *)mp->b_rptr;
 333                 ip6h = NULL;
 334         } else {
 335                 policy_present = ipss->ipsec_inbound_v6_policy_present;
 336                 ipha = NULL;
 337                 ip6h = (ip6_t *)mp->b_rptr;
 338         }
 339 
 340         if (policy_present) {
 341                 mp = ipsec_check_global_policy(mp, (conn_t *)NULL, ipha, ip6h,
 342                     ira, ns);
 343                 if (mp == NULL) {
 344                         return;
 345                 }
 346         }
 347 
 348         rptr = mp->b_rptr;
 349 
 350         dccpha = (dccpha_t *)&rptr[ip_hdr_len];
 351 
 352         seq_len = msgdsize(mp) - (ip_hdr_len);
 353 
 354         dccp_xmit_early_reset("no dccp, reset", mp, 0,
 355             0, 0, ira, ipst, connp);
 356 }
 357 
 358 /*
 359  * RFC 4340, Section 8.1.3
 360  */
 361 static void
 362 dccp_xmit_early_reset(char *str, mblk_t *mp, uint32_t seq, uint32_t ack, int ctl,
 363     ip_recv_attr_t *ira, ip_stack_t *ipst, conn_t *connp)
 364 {
 365         dccpha_t        *dccpha;
 366         dccpha_t        *nmp_dccpha;
 367         dccpha_ack_t    *nmp_dccpha_ack;
 368         dccpha_reset_t  *dccpha_reset;
 369         dccpha_reset_t  *nmp_dccpha_reset;
 370         dccpha_ext_t    *dccpha_ext;
 371         dccpha_ext_t    *nmp_dccpha_ext;
 372         netstack_t      *ns = ipst->ips_netstack;
 373         dccp_stack_t    *dccps = ns->netstack_dccp;
 374         ip6_t           *ip6h;
 375         ipha_t          *ipha;
 376         ipha_t          *nmp_ipha;
 377         ip_xmit_attr_t  ixas;
 378         ip_xmit_attr_t  *ixa;
 379         in6_addr_t      v6addr;
 380         ipaddr_t        v4addr;
 381         mblk_t          *nmp;
 382         uint64_t        pkt_ack;
 383         uint_t          ip_hdr_len = ira->ira_ip_hdr_length;
 384         ushort_t        port;
 385         ushort_t        len;
 386 
 387         cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_early_reset");
 388 
 389         if (!dccp_send_rst_chk(dccps)) {
 390                 cmn_err(CE_NOTE, "dccp_output.c: not sending reset packet");
 391                 DCCP_STAT(dccps, dccp_rst_unsent);
 392                 freemsg(mp);
 393                 return;
 394         }
 395 
 396                 bzero(&ixas, sizeof (ixas));
 397                 ixa = &ixas;
 398 
 399                 ixa->ixa_flags |= IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE;
 400                 ixa->ixa_protocol = IPPROTO_DCCP;
 401                 ixa->ixa_zoneid = ira->ira_zoneid;
 402                 ixa->ixa_ifindex = 0;
 403                 ixa->ixa_ipst = ipst;
 404                 ixa->ixa_cred = kcred;
 405                 ixa->ixa_cpid = NOPID;
 406 
 407         if (str && dccps->dccps_dbg) {
 408                 (void) strlog(DCCP_MOD_ID, 0, 1, SL_TRACE,
 409                     "dccp_xmit_early_reset: '%s', seq 0x%x, ack 0x%x, "
 410                     "flags 0x%x",
 411                     str, seq, ack, ctl);
 412         }
 413 
 414         if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
 415                 ipha = (ipha_t *)mp->b_rptr;
 416 
 417         } else {
 418                 /* XXX */
 419         }
 420 
 421         /*
 422          * Allocate a new DCCP reset message
 423          */
 424         len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t);
 425         nmp = allocb(len, BPRI_MED);
 426         if (nmp == NULL) {
 427                 cmn_err(CE_NOTE, "alloc failed");
 428                 return;
 429         }
 430         bcopy(mp->b_rptr, nmp->b_wptr, ip_hdr_len + sizeof (dccpha_t));
 431 
 432         nmp_dccpha = (dccpha_t *)&nmp->b_rptr[ip_hdr_len];
 433         nmp_dccpha->dha_offset = 7;
 434 
 435         if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
 436                 nmp_ipha = (ipha_t *)nmp->b_rptr;
 437 
 438                 nmp_ipha->ipha_length = htons(len);
 439                 nmp_ipha->ipha_src = ipha->ipha_dst;
 440                 nmp_ipha->ipha_dst = ipha->ipha_src;
 441 
 442                 ixa->ixa_flags |= IXAF_IS_IPV4;
 443                 ixa->ixa_ip_hdr_length = ip_hdr_len;
 444         } else {
 445                 cmn_err(CE_NOTE, "not v4");
 446         }
 447 
 448         dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
 449 
 450         nmp->b_wptr = &nmp->b_rptr[len];
 451 
 452         ixa->ixa_pktlen = len; // ?
 453 
 454         nmp_dccpha->dha_fport = dccpha->dha_lport;
 455         nmp_dccpha->dha_lport = dccpha->dha_fport;
 456         nmp_dccpha->dha_type = DCCP_PKT_RESET;
 457         nmp_dccpha->dha_x = 1;
 458         nmp_dccpha->dha_res_seq = 0;
 459         nmp_dccpha->dha_seq = 0;
 460 
 461         nmp_dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
 462             sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t));
 463 
 464         dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 465         nmp_dccpha_ext = (dccpha_ext_t *)&nmp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 466         nmp_dccpha_ext->dha_ext_seq = 0;
 467 
 468         len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t);
 469         nmp_dccpha_ack = (dccpha_ack_t *)&nmp->b_rptr[len];
 470         nmp_dccpha_ack->dha_ack_high = dccpha->dha_seq;
 471         nmp_dccpha_ack->dha_ack_low = dccpha_ext->dha_ext_seq;
 472         nmp_dccpha_ack->dha_ack_reserved = 0;
 473 
 474         len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t);
 475         nmp_dccpha_reset = (dccpha_reset_t *)&nmp->b_rptr[len];
 476 
 477         if (connp != NULL) {
 478                 nmp_dccpha_reset->dha_reset_code =
 479                     connp->conn_dccp->dccp_reset_code;
 480         } else {
 481                 nmp_dccpha_reset->dha_reset_code =
 482                     DCCP_RESET_CONNECTION_REFUSED;
 483         }
 484         nmp_dccpha_reset->dha_reset_data[0] = 0;
 485         nmp_dccpha_reset->dha_reset_data[1] = 0;
 486         nmp_dccpha_reset->dha_reset_data[2] = 0;
 487 
 488         (void) ip_output_simple(nmp, ixa);
 489 
 490         ixa_cleanup(ixa);
 491 }
 492 
 493 /*
 494  *
 495  */
 496 static boolean_t
 497 dccp_send_rst_chk(dccp_stack_t *dccps)
 498 {
 499         int64_t now;
 500 
 501         if (dccps->dccps_rst_sent_rate_enabled != 0) {
 502                 now = ddi_get_lbolt64();
 503                 if (TICK_TO_MSEC(now - dccps->dccps_last_rst_intrvl) >
 504                     1 * SECONDS) {
 505                         dccps->dccps_last_rst_intrvl = now;
 506                         dccps->dccps_rst_cnt = 1;
 507                 } else if (++dccps->dccps_rst_cnt > dccps->dccps_rst_sent_rate) {
 508                         return (B_FALSE);
 509                 }
 510         }
 511 
 512         return (B_TRUE);
 513 }
 514 
 515 /* ARGSUSED2 */
 516 void
 517 dccp_send_synack(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
 518 {
 519         conn_t          *econnp = (conn_t *)arg;
 520         dccp_t          *dccp = econnp->conn_dccp;
 521         ip_xmit_attr_t  *ixa = econnp->conn_ixa;
 522 
 523         cmn_err(CE_NOTE, "dccp_output.c: dccp_send_synack");
 524 
 525         /*
 526          * Guard against a RESET having blown it away while on the
 527          * squeue.
 528          */
 529         if (dccp->dccp_state == DCCPS_CLOSED) {
 530                 freemsg(mp);
 531                 return;
 532         }
 533 
 534         ixa->ixa_pktlen = msgdsize(mp);
 535         (void) conn_ip_output(mp, ixa);
 536 }
 537 
 538 mblk_t *
 539 dccp_xmit_mp(dccp_t *dccp, mblk_t *mp, int32_t max_to_send, int32_t *offset,
 540     mblk_t **end_mp, uint32_t seq, boolean_t sendall, uint32_t *seg_len,
 541     boolean_t rexmit)
 542 {
 543         conn_t          *connp = dccp->dccp_connp;
 544         dccp_stack_t    *dccps = dccp->dccp_dccps;
 545         dccpha_t        *dccpha;
 546         dccpha_ext_t    *dccpha_ext;
 547         dccpha_ack_t    *dccpha_ack;
 548         dccpha_srv_t    *dccpha_srv;
 549         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 550         mblk_t          *mp1;
 551         uchar_t         *rptr;
 552         ushort_t        len;
 553         int             data_length;
 554 
 555         cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_mp");
 556 
 557         // dccpha_t already in iphc_len?
 558         len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4;
 559 
 560         mp1 = allocb(len, BPRI_MED);
 561         if (mp1 == NULL) {
 562                 cmn_err(CE_NOTE, "allocb failed");
 563                 return (NULL);
 564         }
 565 
 566         data_length = 0;
 567 
 568         rptr = mp1->b_rptr;
 569         mp1->b_wptr = &mp1->b_rptr[len];
 570         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 571         dccpha = (dccpha_t *)&rptr[ixa->ixa_ip_hdr_length];
 572         dccpha->dha_type = DCCP_PKT_RESPONSE;
 573         dccpha->dha_offset = 8;
 574         dccpha->dha_x = 1;
 575         dccpha->dha_ccval = 0;
 576         dccpha->dha_cscov = 0;
 577         dccpha->dha_reserved = 0;
 578         dccpha->dha_res_seq = 0;
 579         dccpha->dha_seq = 0;
 580 
 581         dccpha_ext = (dccpha_ext_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t)];
 582         dccpha_ext->dha_ext_seq = 0;
 583 
 584         dccpha_ack = (dccpha_ack_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t)];
 585         dccpha_ack->dha_ack_reserved = 0;
 586         dccpha_ack->dha_ack_high = 0;
 587         dccpha_ack->dha_ack_low = 0;
 588 
 589         dccpha_srv = (dccpha_srv_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t)];
 590         dccpha_srv->dha_srv_code = 0;
 591 
 592         return (mp1);
 593 }
 594 
 595 /*
 596  * Generate a DCCP-Response packet.
 597  */
 598 mblk_t *
 599 dccp_generate_response(conn_t *connp, mblk_t *mp)
 600 {
 601         dccpha_t        *dccpha;
 602         dccpha_ext_t    *dccpha_ext;
 603         dccpha_ack_t    *dccpha_ack;
 604         dccpha_srv_t    *dccpha_srv;
 605         mblk_t          *mp1;
 606         uint64_t        seq;
 607         uint64_t        ack;
 608         uint16_t        ack_high;
 609         uint32_t        ack_low;
 610 //      uint_t          ip_hdr_len = ira->ira_ip_hdr_length;
 611         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 612         uint_t          ip_hdr_len;
 613         uint_t          len;
 614         uint_t          total_hdr_len;
 615         uchar_t         *rptr;
 616         dccp_t          *dccp = connp->conn_dccp;
 617         void            *options;
 618         size_t          opt_len;
 619         int             error;
 620 
 621         cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_packet");
 622 
 623         ip_hdr_len = ixa->ixa_ip_hdr_length;
 624 
 625         if (mp == NULL) {
 626                 cmn_err(CE_NOTE, "NULL pointer mp");
 627                 return (NULL);
 628         }
 629 
 630         dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
 631         dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 632 
 633         ack_high = dccpha->dha_seq;
 634         ack_low = dccpha_ext->dha_ext_seq;
 635 
 636         seq = ntohs(ack_high) << 31;
 637         seq |= ntohl(ack_low);
 638 
 639         dccp->dccp_isr = seq;
 640         dccp->dccp_gsr = seq;
 641         dccp->dccp_swl = seq;
 642         dccp->dccp_swh = seq;
 643         dccp->dccp_gss++;
 644 
 645         error = dccp_generate_options(dccp, &options, &opt_len);
 646         if (error != 0) {
 647                 cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_options failed");
 648         }
 649         cmn_err(CE_NOTE, "generated options len: %d", (int) opt_len);
 650 
 651 
 652         /*
 653          * conn_ht_iphc_len = ip_hdr_length (20) + ulp_hdr_length
 654          * (20) simple ip header (without vtag or options)
 655          */
 656         total_hdr_len = len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4 + opt_len;
 657         mp1 = allocb(len, BPRI_MED);
 658         if (mp1 == NULL) {
 659                 cmn_err(CE_NOTE, "allocb failed");
 660                 return (NULL);
 661         }
 662 
 663         rptr = mp1->b_rptr;
 664         mp1->b_wptr = &mp1->b_rptr[len];
 665 
 666         bcopy(options, &mp1->b_rptr[len-opt_len], opt_len);
 667         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 668         dccpha = (dccpha_t *)&rptr[ip_hdr_len];
 669 
 670         dccpha->dha_type = DCCP_PKT_RESPONSE;
 671         dccpha->dha_offset = 7 + (opt_len / 4);
 672         dccpha->dha_x = 1;
 673         dccpha->dha_ccval = 0;
 674         dccpha->dha_cscov = 0;
 675         dccpha->dha_reserved = 0;
 676         dccpha->dha_res_seq = 0;
 677         dccpha->dha_seq = htons(dccp->dccp_gss >> 32);;
 678         dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4 + opt_len);
 679 
 680 
 681         dccpha_ext = (dccpha_ext_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 682         dccpha_ext->dha_ext_seq = htonl(dccp->dccp_gss & 0xffffffff);
 683 
 684         dccpha_ack = (dccpha_ack_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t)];
 685         dccpha_ack->dha_ack_high = ack_high;
 686         dccpha_ack->dha_ack_low = ack_low;
 687         dccpha_ack->dha_ack_reserved = 0;
 688 
 689         dccpha_srv = (dccpha_srv_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t)];
 690         dccpha_srv->dha_srv_code = 0;
 691 
 692         ixa->ixa_pktlen = total_hdr_len;
 693 
 694         if (ixa->ixa_flags & IXAF_IS_IPV4) {
 695                 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
 696         } else {
 697                 ip6_t *ip6 = (ip6_t *)rptr;
 698 
 699                 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
 700         }
 701 
 702         cmn_err(CE_NOTE, "IPHC LEN: %d", connp->conn_ht_iphc_len);
 703         cmn_err(CE_NOTE, "TOTAL LEN: %d", total_hdr_len);
 704 
 705         kmem_free(options, opt_len);
 706 
 707         return (mp1);
 708 }
 709 
 710 /*
 711  * Generate a request packet. Must use 48-bit sequence
 712  * numbers.
 713  */
 714 mblk_t *
 715 dccp_generate_request(conn_t *connp)
 716 {
 717         dccp_t          *dccp = connp->conn_dccp;
 718         dccpha_t        *dccpha;
 719         dccpha_ext_t    *dccpha_ext;
 720         dccpha_srv_t    *dccpha_srv;
 721         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 722         mblk_t          *mp;
 723         uchar_t         *rptr;
 724         uint_t          total_hdr_len;
 725         uint_t          len;
 726 
 727         cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_request");
 728 
 729         total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) +
 730             sizeof (dccpha_srv_t);
 731         mp = allocb(total_hdr_len, BPRI_MED);
 732         if (mp == NULL) {
 733                 cmn_err(CE_NOTE, "allocb failed");
 734                 return (NULL);
 735         }
 736 
 737         rptr = mp->b_rptr;
 738         mp->b_wptr = &mp->b_rptr[total_hdr_len];
 739 
 740         /* Copy in the template header */
 741         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 742 
 743         len = ixa->ixa_ip_hdr_length;
 744         dccpha = (dccpha_t *)&rptr[len];
 745         dccpha->dha_type = DCCP_PKT_REQUEST;
 746         dccpha->dha_offset = (sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
 747             sizeof (dccpha_srv_t)) / 4;
 748         dccpha->dha_x = 1;
 749         dccpha->dha_ccval = 0;
 750         dccpha->dha_cscov = 0;
 751         dccpha->dha_reserved = 0;
 752         dccpha->dha_res_seq = 0;
 753         dccpha->dha_seq = 0;
 754         dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
 755             sizeof (dccpha_srv_t));
 756 
 757         /* Extended sequence number */
 758         len += sizeof (dccpha_t);
 759         dccpha_ext = (dccpha_ext_t *)&rptr[len];
 760 
 761         /* Service number */
 762         len += sizeof (dccpha_ext_t);
 763         dccpha_srv = (dccpha_srv_t *)&rptr[len];
 764         dccpha_srv->dha_srv_code = 0;
 765 
 766         ixa->ixa_pktlen = total_hdr_len;
 767 
 768         if (ixa->ixa_flags & IXAF_IS_IPV4) {
 769                 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
 770         } else {
 771                 ip6_t *ip6 = (ip6_t *)rptr;
 772 
 773                 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
 774         }
 775 
 776         return (mp);
 777 }
 778 
 779 /*
 780  * Close packet.
 781  */
 782 mblk_t *
 783 dccp_generate_reset(conn_t *connp)
 784 {
 785         dccp_t          *dccp = connp->conn_dccp;
 786         dccpha_t        *dccpha;
 787         dccpha_ext_t    *dccpha_ext;
 788         dccpha_ack_t    *dccpha_ack;
 789         dccpha_reset_t  *dccpha_reset;
 790         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 791         mblk_t          *mp;
 792         uint64_t        gss;
 793         uchar_t         *rptr;
 794         uint_t          total_hdr_len;
 795         uint_t          len = ixa->ixa_ip_hdr_length;
 796 
 797         cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_reset");
 798 
 799         /* XXX */
 800         dccp->dccp_gss++;
 801 
 802         /*
 803          * Allocate a new DCCP reset message
 804          */
 805         total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) +
 806             sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t);
 807         mp = allocb(total_hdr_len, BPRI_MED);
 808         if (mp == NULL) {
 809                 cmn_err(CE_NOTE, "allocb failed");
 810                 return(NULL);
 811         }
 812 
 813         rptr = mp->b_rptr;
 814         mp->b_wptr = &mp->b_rptr[total_hdr_len];
 815 
 816         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 817 
 818         len = ixa->ixa_ip_hdr_length;
 819         dccpha = (dccpha_t *)&mp->b_rptr[len];
 820         dccpha->dha_type = DCCP_PKT_RESET;
 821         dccpha->dha_offset = 7;
 822         dccpha->dha_x = 1;
 823         dccpha->dha_ccval = 0;
 824         dccpha->dha_cscov = 0;
 825         dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
 826             sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t));
 827         dccpha->dha_seq = htons(dccp->dccp_gss >> 32);
 828         dccpha->dha_res_seq = 0;
 829 
 830         len += sizeof (dccpha_t);
 831         dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[len];
 832         dccpha_ext->dha_ext_seq = htonl(dccp->dccp_gss & 0xffffffff);
 833 
 834         /* Set ack */
 835         len += sizeof (dccpha_ext_t);
 836         dccpha_ack = (dccpha_ack_t *)&mp->b_rptr[len];
 837         dccpha_ack->dha_ack_high = htons(dccp->dccp_gsr >> 32);
 838         dccpha_ack->dha_ack_low = htonl(dccp->dccp_gsr & 0xffffffff);
 839         dccpha_ack->dha_ack_reserved = 0;
 840 
 841         len += sizeof (dccpha_ack_t);
 842         dccpha_reset = (dccpha_reset_t *)&mp->b_rptr[len];
 843         dccpha_reset->dha_reset_code = dccp->dccp_reset_code;
 844         dccpha_reset->dha_reset_data[0] = dccp->dccp_reset_data[0];
 845         dccpha_reset->dha_reset_data[1] = dccp->dccp_reset_data[1];
 846         dccpha_reset->dha_reset_data[2] = dccp->dccp_reset_data[2];
 847 
 848         ixa->ixa_pktlen = total_hdr_len;
 849 
 850         if (ixa->ixa_flags & IXAF_IS_IPV4) {
 851                 cmn_err(CE_NOTE, "setting ip len for ipv4: %d", total_hdr_len);
 852                 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
 853         } else {
 854                 ip6_t *ip6 = (ip6_t *)rptr;
 855 
 856                 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
 857         }
 858 
 859         return (mp);
 860 }
 861 
 862 /*
 863  * Acknowledgement packet.
 864  */
 865 mblk_t *
 866 dccp_generate_ack(conn_t *connp)
 867 {
 868         dccp_t          *dccp = connp->conn_dccp;
 869         dccpha_t        *dccpha;
 870         dccpha_ext_t    *dccpha_ext;
 871         dccpha_ack_t    *dccpha_ack;
 872         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 873         mblk_t          *mp;
 874         uint64_t        gss;
 875         uchar_t         *rptr;
 876         uint_t          total_hdr_len;
 877         uint_t          len = ixa->ixa_ip_hdr_length;
 878 
 879         cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_ack");
 880 
 881         /* XXX */
 882         dccp->dccp_gss++;
 883 
 884         /*
 885          * Allocate a new DCCP reset message
 886          */
 887         total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) +
 888             sizeof (dccpha_ack_t);
 889         mp = allocb(total_hdr_len, BPRI_MED);
 890         if (mp == NULL) {
 891                 cmn_err(CE_NOTE, "allocb failed");
 892                 return(NULL);
 893         }
 894 
 895         rptr = mp->b_rptr;
 896         mp->b_wptr = &mp->b_rptr[total_hdr_len];
 897 
 898         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 899 
 900         len = ixa->ixa_ip_hdr_length;
 901         dccpha = (dccpha_t *)&mp->b_rptr[len];
 902         dccpha->dha_type = DCCP_PKT_ACK;
 903         dccpha->dha_offset = 6;
 904         dccpha->dha_x = 1;
 905         dccpha->dha_ccval = 0;
 906         dccpha->dha_cscov = 0;
 907         dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
 908             sizeof (dccpha_ack_t));
 909         dccpha->dha_seq = htons(dccp->dccp_gss >> 32);
 910         dccpha->dha_res_seq = 0;
 911 
 912         len += sizeof (dccpha_t);
 913         dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[len];
 914         dccpha_ext->dha_ext_seq = htonl(dccp->dccp_gss & 0xffffffff);
 915 
 916         len += sizeof (dccpha_ext_t);
 917         dccpha_ack = (dccpha_ack_t *)&mp->b_rptr[len];
 918         dccpha_ack->dha_ack_high = htons(dccp->dccp_gsr >> 32);
 919         dccpha_ack->dha_ack_low = htonl(dccp->dccp_gsr & 0xffffffff);
 920         dccpha_ack->dha_ack_reserved = 0;
 921 
 922         ixa->ixa_pktlen = total_hdr_len;
 923 
 924         if (ixa->ixa_flags & IXAF_IS_IPV4) {
 925                 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
 926         } else {
 927                 ip6_t *ip6 = (ip6_t *)rptr;
 928 
 929                 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
 930         }
 931 
 932         return (mp);
 933 }
 934 
 935 /*
 936  * Common to all packet generating functions.
 937  */
 938 static mblk_t *
 939 dccp_generate_common(conn_t *connp, uint8_t packet_type,
 940     uint_t total_hdr_len)
 941 {
 942         dccp_t          *dccp = connp->conn_dccp;
 943         dccpha_t        *dccpha;
 944         dccpha_ext_t    *dccpha_ext;
 945         dccpha_ack_t    *dccpha_ack;
 946         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 947         mblk_t          *mp;
 948         uchar_t         *rptr;
 949         uint_t          len;
 950         boolean_t       extended;
 951 
 952         /*
 953          * Allocate a new DCCP reset message
 954          */
 955         mp = allocb(total_hdr_len, BPRI_MED);
 956         if (mp == NULL) {
 957                 return(NULL);
 958         }
 959 
 960         dccp->dccp_gss++;
 961 
 962         rptr = mp->b_rptr;
 963         mp->b_wptr = &mp->b_rptr[total_hdr_len];
 964 
 965         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 966 
 967         /* Basic header */
 968         len = ixa->ixa_ip_hdr_length;
 969         dccpha = (dccpha_t *)&mp->b_rptr[len];
 970         dccpha->dha_type = packet_type;
 971         dccpha->dha_offset = 6;
 972         dccpha->dha_x = 1;
 973         dccpha->dha_ccval = 0;
 974         dccpha->dha_cscov = 0;
 975         dccpha->dha_sum = htons(total_hdr_len - len);
 976         dccpha->dha_seq = htons(dccp->dccp_gss >> 32);
 977         dccpha->dha_res_seq = 0;
 978 
 979         /* Extended sequence number */
 980         len += sizeof (dccpha_t);
 981         dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[len];
 982         dccpha_ext->dha_ext_seq = htonl(dccp->dccp_gss & 0xffffffff);
 983 
 984         /* Acknowledgement number */
 985         len += sizeof (dccpha_ext_t);
 986         dccpha_ack = (dccpha_ack_t *)&mp->b_rptr[len];
 987         dccpha_ack->dha_ack_high = htons(dccp->dccp_gsr >> 32);
 988         dccpha_ack->dha_ack_low = htonl(dccp->dccp_gsr & 0xffffffff);
 989         dccpha_ack->dha_ack_reserved = 0;
 990 
 991         ixa->ixa_pktlen = total_hdr_len;
 992 
 993         if (ixa->ixa_flags & IXAF_IS_IPV4) {
 994                 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
 995         } else {
 996                 ip6_t *ip6 = (ip6_t *)rptr;
 997 
 998                 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
 999         }
1000 
1001         return (mp);
1002 }
1003 
1004 /*
1005  * Acknowledgement packet.
1006  */
1007 mblk_t *
1008 dccp_generate_sync(conn_t *connp)
1009 {
1010         dccp_t          *dccp = connp->conn_dccp;
1011         dccpha_t        *dccpha;
1012         dccpha_ext_t    *dccpha_ext;
1013         dccpha_ack_t    *dccpha_ack;
1014         ip_xmit_attr_t  *ixa = connp->conn_ixa;
1015         mblk_t          *mp;
1016         uchar_t         *rptr;
1017         uint_t          total_hdr_len;
1018         uint_t          len = ixa->ixa_ip_hdr_length;
1019 
1020         cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_ack");
1021 
1022         total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) +
1023             sizeof (dccpha_ack_t);
1024         mp = dccp_generate_common(connp, DCCP_PACKET_SYNC, total_hdr_len);
1025         if (mp == NULL) {
1026                 cmn_err(CE_NOTE, "allocb failed");
1027                 return(NULL);
1028         }
1029 
1030         rptr = mp->b_rptr;
1031         mp->b_wptr = &mp->b_rptr[total_hdr_len];
1032 
1033         return (mp);
1034 }