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/ip.h>
  51 
  52 #include <sys/cmn_err.h>
  53 
  54 #include "dccp_impl.h"
  55 #include "dccp_stack.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\n");
  68 }
  69 
  70 /*
  71  * Send a reset as response to an incoming packet or
  72  * reset a connection.
  73  */
  74 void
  75 dccp_xmit_listeners_reset(mblk_t *mp, ip_recv_attr_t *ira, ip_stack_t *ipst,
  76     conn_t *connp)
  77 {
  78         dccpha_t        *dccpha;
  79         uint32_t        seg_seq;
  80         uint32_t        seg_ack;
  81         uint32_t        seq_len;
  82         uint_t          ip_hdr_len = ira->ira_ip_hdr_length;
  83         uchar_t         *rptr;
  84 
  85         cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_listeners_reset");
  86 
  87         rptr = mp->b_rptr;
  88 
  89         dccpha = (dccpha_t *)&rptr[ip_hdr_len];
  90 
  91         //seg_seq = ntonl(dccpha->dha_seq);
  92         //seg_ack = htonl(dccpha->dha_ack);
  93 
  94         seq_len = msgdsize(mp) - (ip_hdr_len);
  95 
  96         dccp_xmit_early_reset("no dccp, reset", mp, 0,
  97             0, 0, ira, ipst, connp);
  98 }
  99 
 100 /*
 101  * RFC 4340, Section 8.1.3
 102  */
 103 static void
 104 dccp_xmit_early_reset(char *str, mblk_t *mp, uint32_t seq, uint32_t ack, int ctl,
 105     ip_recv_attr_t *ira, ip_stack_t *ipst, conn_t *connp)
 106 {
 107         dccpha_t        *dccpha;
 108         dccpha_t        *nmp_dccpha;
 109         dccpha_ack_t    *nmp_dccpha_ack;
 110         dccpha_reset_t  *dccpha_reset;
 111         dccpha_reset_t  *nmp_dccpha_reset;
 112         dccpha_ext_t    *dccpha_ext;
 113         dccpha_ext_t    *nmp_dccpha_ext;
 114         netstack_t      *ns = ipst->ips_netstack;
 115         dccp_stack_t    *dccps = ns->netstack_dccp;
 116         ip6_t           *ip6h;
 117         ipha_t          *ipha;
 118         ipha_t          *nmp_ipha;
 119         ip_xmit_attr_t  ixas;
 120         ip_xmit_attr_t  *ixa;
 121         in6_addr_t      v6addr;
 122         ipaddr_t        v4addr;
 123         mblk_t          *nmp;
 124         uint64_t        pkt_ack;
 125         uint_t          ip_hdr_len = ira->ira_ip_hdr_length;
 126         ushort_t        port;
 127         ushort_t        len;
 128 
 129         cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_early_reset");
 130 
 131         if (!dccp_send_rst_chk(dccps)) {
 132                 cmn_err(CE_NOTE, "dccp_output.c: not sending reset packet");
 133                 DCCP_STAT(dccps, dccp_rst_unsent);
 134                 freemsg(mp);
 135                 return;
 136         }
 137 
 138                 bzero(&ixas, sizeof (ixas));
 139                 ixa = &ixas;
 140 
 141                 ixa->ixa_flags |= IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE;
 142                 ixa->ixa_protocol = IPPROTO_DCCP;
 143                 ixa->ixa_zoneid = ira->ira_zoneid;
 144                 ixa->ixa_ifindex = 0;
 145                 ixa->ixa_ipst = ipst;
 146                 ixa->ixa_cred = kcred;
 147                 ixa->ixa_cpid = NOPID;
 148 
 149         if (str && dccps->dccps_dbg) {
 150                 (void) strlog(DCCP_MOD_ID, 0, 1, SL_TRACE,
 151                     "dccp_xmit_early_reset: '%s', seq 0x%x, ack 0x%x, "
 152                     "flags 0x%x",
 153                     str, seq, ack, ctl);
 154         }
 155 
 156         if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
 157                 ipha = (ipha_t *)mp->b_rptr;
 158 
 159         } else {
 160                 /* XXX */
 161         }
 162 
 163         /*
 164          * Allocate a new DCCP reset message
 165          */
 166         len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t);
 167         nmp = allocb(len, BPRI_MED);
 168         if (nmp == NULL) {
 169                 cmn_err(CE_NOTE, "alloc failed");
 170                 return;
 171         }
 172         bcopy(mp->b_rptr, nmp->b_wptr, ip_hdr_len + sizeof (dccpha_t));
 173 
 174         nmp_dccpha = (dccpha_t *)&nmp->b_rptr[ip_hdr_len];
 175         nmp_dccpha->dha_offset = 7;
 176 
 177         if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
 178                 nmp_ipha = (ipha_t *)nmp->b_rptr;
 179 
 180                 nmp_ipha->ipha_length = htons(len);
 181                 nmp_ipha->ipha_src = ipha->ipha_dst;
 182                 nmp_ipha->ipha_dst = ipha->ipha_src;
 183 
 184                 ixa->ixa_flags |= IXAF_IS_IPV4;
 185                 ixa->ixa_ip_hdr_length = ip_hdr_len;
 186         } else {
 187                 cmn_err(CE_NOTE, "not v4");
 188         }
 189 
 190         dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
 191 
 192         nmp->b_wptr = &nmp->b_rptr[len];
 193 
 194         ixa->ixa_pktlen = len; // ?
 195 
 196         nmp_dccpha->dha_fport = dccpha->dha_lport;
 197         nmp_dccpha->dha_lport = dccpha->dha_fport;
 198         nmp_dccpha->dha_type = DCCP_PKT_RESET;
 199         nmp_dccpha->dha_x = 1;
 200         nmp_dccpha->dha_res_seq = 0;
 201         nmp_dccpha->dha_seq = 0;
 202 
 203         nmp_dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t));
 204 
 205         dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 206         nmp_dccpha_ext = (dccpha_ext_t *)&nmp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 207         nmp_dccpha_ext->dha_ext_seq = 0;
 208 
 209         len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t);
 210         nmp_dccpha_ack = (dccpha_ack_t *)&nmp->b_rptr[len];
 211         nmp_dccpha_ack->dha_ack_high = dccpha->dha_seq;
 212         nmp_dccpha_ack->dha_ack_low = dccpha_ext->dha_ext_seq;
 213 
 214         len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t);
 215         nmp_dccpha_reset = (dccpha_reset_t *)&nmp->b_rptr[len];
 216         nmp_dccpha_reset->dha_reset_code = 7;
 217         nmp_dccpha_reset->dha_reset_data[0] = 0;
 218         nmp_dccpha_reset->dha_reset_data[1] = 0;
 219         nmp_dccpha_reset->dha_reset_data[2] = 0;
 220 
 221         (void) ip_output_simple(nmp, ixa);
 222 
 223         ixa_cleanup(ixa);
 224 }
 225 
 226 /*
 227  *
 228  */
 229 static boolean_t
 230 dccp_send_rst_chk(dccp_stack_t *dccps)
 231 {
 232         int64_t now;
 233 
 234         if (dccps->dccps_rst_sent_rate_enabled != 0) {
 235                 now = ddi_get_lbolt64();
 236                 if (TICK_TO_MSEC(now - dccps->dccps_last_rst_intrvl) >
 237                     1 * SECONDS) {
 238                         dccps->dccps_last_rst_intrvl = now;
 239                         dccps->dccps_rst_cnt = 1;
 240                 } else if (++dccps->dccps_rst_cnt > dccps->dccps_rst_sent_rate) {
 241                         return (B_FALSE);
 242                 }
 243         }
 244 
 245         return (B_TRUE);
 246 }
 247 
 248 void
 249 dccp_send_synack(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
 250 {
 251         cmn_err(CE_NOTE, "dccp_output.c: dccp_send_synack");
 252 }
 253 
 254 mblk_t *
 255 dccp_xmit_mp(dccp_t *dccp, mblk_t *mp, int32_t max_to_send, int32_t *offset,
 256     mblk_t **end_mp, uint32_t seq, boolean_t sendall, uint32_t *seg_len,
 257     boolean_t rexmit)
 258 {
 259         conn_t          *connp = dccp->dccp_connp;
 260         dccp_stack_t    *dccps = dccp->dccp_dccps;
 261         dccpha_t        *dccpha;
 262         dccpha_ext_t    *dccpha_ext;
 263         dccpha_ack_t    *dccpha_ack;
 264         dccpha_srv_t    *dccpha_srv;
 265         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 266         mblk_t          *mp1;
 267         uchar_t         *rptr;
 268         ushort_t        len;
 269         int             data_length;
 270 
 271         cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_mp");
 272 
 273         // dccpha_t already in iphc_len?
 274         len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4;
 275 
 276         //mp1 = dccp_generate_packet(connp, mp);
 277         mp1 = allocb(len, BPRI_MED);
 278         if (mp1 == NULL) {
 279                 cmn_err(CE_NOTE, "allocb failed");
 280                 return (NULL);
 281         }
 282 
 283         data_length = 0;
 284 
 285         rptr = mp1->b_rptr;
 286         mp1->b_wptr = &mp1->b_rptr[len];
 287         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 288         dccpha = (dccpha_t *)&rptr[ixa->ixa_ip_hdr_length];
 289         dccpha->dha_type = DCCP_PKT_RESPONSE;
 290         dccpha->dha_offset = 8;
 291         dccpha->dha_x = 1;
 292         dccpha->dha_ccval = 0;
 293         dccpha->dha_cscov = 0;
 294         dccpha->dha_reserved = 0;
 295         dccpha->dha_res_seq = 0;
 296         dccpha->dha_seq = 0;
 297 
 298         dccpha_ext = (dccpha_ext_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t)];
 299         dccpha_ext->dha_ext_seq = 0;
 300 
 301         dccpha_ack = (dccpha_ack_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t)];
 302         dccpha_ack->dha_ack_reserved = 0;
 303         dccpha_ack->dha_ack_high = 0;
 304         dccpha_ack->dha_ack_low = 0;
 305 
 306         dccpha_srv = (dccpha_srv_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t)];
 307         dccpha_srv->dha_srv_code = 0;
 308 
 309         return (mp1);
 310 }
 311 
 312 mblk_t *
 313 dccp_generate_packet(conn_t *connp, mblk_t *mp)
 314 {
 315         dccpha_t        *dccpha;
 316         dccpha_ext_t    *dccpha_ext;
 317         dccpha_ack_t    *dccpha_ack;
 318         mblk_t          *mp1;
 319         uint16_t        ack_high;
 320         uint32_t        ack_low;
 321 //      uint_t          ip_hdr_len = ira->ira_ip_hdr_length;
 322         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 323         uint_t          ip_hdr_len;
 324         uint_t          len;
 325         uchar_t         *rptr;
 326 
 327         cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_packet");
 328 
 329         ip_hdr_len = ixa->ixa_ip_hdr_length;
 330 
 331         if (mp == NULL) {
 332                 cmn_err(CE_NOTE, "NULL pointer mp");
 333                 return (NULL);
 334         }
 335 
 336         dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
 337         dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 338 
 339         ack_high = dccpha->dha_seq;
 340         ack_low = dccpha_ext->dha_ext_seq;
 341 
 342         len = connp->conn_ht_iphc_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4;
 343         //len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4;
 344         mp1 = allocb(len, BPRI_MED);
 345         if (mp1 == NULL) {
 346                 cmn_err(CE_NOTE, "allocb failed");
 347                 return (NULL);
 348         }
 349 
 350         rptr = mp1->b_rptr;
 351         mp1->b_wptr = &mp1->b_rptr[len];
 352 
 353         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 354         dccpha = (dccpha_t *)&rptr[ixa->ixa_ip_hdr_length];
 355         //dccpha = (dccpha_t *)&mp1->b_rptr[ip_hdr_len];
 356 
 357         dccpha->dha_type = DCCP_PKT_RESPONSE;
 358         dccpha->dha_offset = 8;
 359         dccpha->dha_x = 1;
 360         dccpha->dha_ccval = 0;
 361         dccpha->dha_cscov = 0;
 362         dccpha->dha_reserved = 0;
 363         dccpha->dha_res_seq = 0;
 364         dccpha->dha_seq = 1;
 365         dccpha->dha_sum = htons(len);
 366 
 367         dccpha_ext = (dccpha_ext_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 368         dccpha_ext->dha_ext_seq = 1;
 369 
 370         dccpha_ack = (dccpha_ack_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t)];
 371         dccpha_ack->dha_ack_high = ack_high;
 372         dccpha_ack->dha_ack_low = ack_low;
 373 
 374         return (mp1);
 375 }