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 }