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