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 #include <inet/ipsec_impl.h> 52 53 #include <sys/cmn_err.h> 54 55 #include "dccp_impl.h" 56 #include "dccp_stack.h" 57 58 static void dccp_xmit_early_reset(char *, mblk_t *, uint32_t, uint32_t, 59 int, ip_recv_attr_t *, ip_stack_t *, conn_t *); 60 static boolean_t dccp_send_rst_chk(dccp_stack_t *); 61 62 /* 63 * STREAMS 64 */ 65 void 66 dccp_wput(queue_t *q, mblk_t *mp) 67 { 68 cmn_err(CE_NOTE, "dccp_output.c: dccp_wput\n"); 69 } 70 71 /* 72 * 73 */ 74 void 75 dccp_wput_sock(queue_t *wq, mblk_t *mp) 76 { 77 conn_t *connp = Q_TO_CONN(wq); 78 dccp_t *dccp = connp->conn_dccp; 79 struct T_capability_req *car = (struct T_capability_req *)mp->b_rptr; 80 81 ASSERT(wq->q_qinfo == &dccp_sock_winit); 82 wq->q_qinfo = &dccp_winit; 83 84 ASSERT(IPCL_IS_TCP(connp)); 85 ASSERT(DCCP_IS_SOCKET(dccp)); 86 87 if (DB_TYPE(mp) == M_PCPROTO && 88 MBLKL(mp) == sizeof (struct T_capability_req) && 89 car->PRIM_type == T_CAPABILITY_REQ) { 90 dccp_capability_req(dccp, mp); 91 return; 92 } 93 94 dccp_wput(wq, mp); 95 } 96 97 /* ARGSUSED */ 98 void 99 dccp_wput_fallback(queue_t *eq, mblk_t *mp) 100 { 101 cmn_err(CE_NOTE, "dccp_output.c: dccp_wput_fallback"); 102 103 #ifdef DEBUG 104 cmn_err(CE_CONT, "tcp_wput_fallback: Message during fallback \n"); 105 #endif /* DEBUG */ 106 107 freemsg(mp); 108 } 109 110 void 111 dccp_output(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy) 112 { 113 cmn_err(CE_NOTE, "dccp_output.c: dccp_output"); 114 } 115 116 void 117 dccp_output_urgent(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy) 118 { 119 cmn_err(CE_NOTE, "dccp_output.c: dccp_output_urgent"); 120 } 121 122 // XXX */ 123 124 #pragma inline(dccp_send_data) 125 126 void 127 dccp_send_data(dccp_t *dccp, mblk_t *mp) 128 { 129 conn_t *connp = dccp->dccp_connp; 130 131 /* XXX dtrace */ 132 133 ASSERT(connp->conn_ixa->ixa_notify_cookie == connp->conn_tcp); 134 (void) conn_ip_output(mp, connp->conn_ixa); 135 } 136 137 /* 138 * Send a reset as response to an incoming packet or 139 * reset a connection. 140 */ 141 void 142 dccp_xmit_listeners_reset(mblk_t *mp, ip_recv_attr_t *ira, ip_stack_t *ipst, 143 conn_t *connp) 144 { 145 netstack_t *ns = ipst->ips_netstack; 146 dccp_stack_t *dccps = ns->netstack_dccp; 147 ipsec_stack_t *ipss = dccps->dccps_netstack->netstack_ipsec; 148 dccpha_t *dccpha; 149 ipha_t *ipha; 150 ip6_t *ip6h; 151 uchar_t *rptr; 152 uint32_t seq_len; 153 uint_t ip_hdr_len = ira->ira_ip_hdr_length; 154 boolean_t policy_present; 155 156 cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_listeners_reset"); 157 158 DCCP_STAT(dccps, dccp_no_listener); 159 160 if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) { 161 policy_present = ipss->ipsec_inbound_v4_policy_present; 162 ipha = (ipha_t *)mp->b_rptr; 163 ip6h = NULL; 164 } else { 165 policy_present = ipss->ipsec_inbound_v6_policy_present; 166 ipha = NULL; 167 ip6h = (ip6_t *)mp->b_rptr; 168 } 169 170 if (policy_present) { 171 mp = ipsec_check_global_policy(mp, (conn_t *)NULL, ipha, ip6h, 172 ira, ns); 173 if (mp == NULL) { 174 return; 175 } 176 } 177 178 rptr = mp->b_rptr; 179 180 dccpha = (dccpha_t *)&rptr[ip_hdr_len]; 181 182 seq_len = msgdsize(mp) - (ip_hdr_len); 183 184 dccp_xmit_early_reset("no dccp, reset", mp, 0, 185 0, 0, ira, ipst, connp); 186 } 187 188 /* 189 * RFC 4340, Section 8.1.3 190 */ 191 static void 192 dccp_xmit_early_reset(char *str, mblk_t *mp, uint32_t seq, uint32_t ack, int ctl, 193 ip_recv_attr_t *ira, ip_stack_t *ipst, conn_t *connp) 194 { 195 dccpha_t *dccpha; 196 dccpha_t *nmp_dccpha; 197 dccpha_ack_t *nmp_dccpha_ack; 198 dccpha_reset_t *dccpha_reset; 199 dccpha_reset_t *nmp_dccpha_reset; 200 dccpha_ext_t *dccpha_ext; 201 dccpha_ext_t *nmp_dccpha_ext; 202 netstack_t *ns = ipst->ips_netstack; 203 dccp_stack_t *dccps = ns->netstack_dccp; 204 ip6_t *ip6h; 205 ipha_t *ipha; 206 ipha_t *nmp_ipha; 207 ip_xmit_attr_t ixas; 208 ip_xmit_attr_t *ixa; 209 in6_addr_t v6addr; 210 ipaddr_t v4addr; 211 mblk_t *nmp; 212 uint64_t pkt_ack; 213 uint_t ip_hdr_len = ira->ira_ip_hdr_length; 214 ushort_t port; 215 ushort_t len; 216 217 cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_early_reset"); 218 219 if (!dccp_send_rst_chk(dccps)) { 220 cmn_err(CE_NOTE, "dccp_output.c: not sending reset packet"); 221 DCCP_STAT(dccps, dccp_rst_unsent); 222 freemsg(mp); 223 return; 224 } 225 226 bzero(&ixas, sizeof (ixas)); 227 ixa = &ixas; 228 229 ixa->ixa_flags |= IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE; 230 ixa->ixa_protocol = IPPROTO_DCCP; 231 ixa->ixa_zoneid = ira->ira_zoneid; 232 ixa->ixa_ifindex = 0; 233 ixa->ixa_ipst = ipst; 234 ixa->ixa_cred = kcred; 235 ixa->ixa_cpid = NOPID; 236 237 if (str && dccps->dccps_dbg) { 238 (void) strlog(DCCP_MOD_ID, 0, 1, SL_TRACE, 239 "dccp_xmit_early_reset: '%s', seq 0x%x, ack 0x%x, " 240 "flags 0x%x", 241 str, seq, ack, ctl); 242 } 243 244 if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) { 245 ipha = (ipha_t *)mp->b_rptr; 246 247 } else { 248 /* XXX */ 249 } 250 251 /* 252 * Allocate a new DCCP reset message 253 */ 254 len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t); 255 nmp = allocb(len, BPRI_MED); 256 if (nmp == NULL) { 257 cmn_err(CE_NOTE, "alloc failed"); 258 return; 259 } 260 bcopy(mp->b_rptr, nmp->b_wptr, ip_hdr_len + sizeof (dccpha_t)); 261 262 nmp_dccpha = (dccpha_t *)&nmp->b_rptr[ip_hdr_len]; 263 nmp_dccpha->dha_offset = 7; 264 265 if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) { 266 nmp_ipha = (ipha_t *)nmp->b_rptr; 267 268 nmp_ipha->ipha_length = htons(len); 269 nmp_ipha->ipha_src = ipha->ipha_dst; 270 nmp_ipha->ipha_dst = ipha->ipha_src; 271 272 ixa->ixa_flags |= IXAF_IS_IPV4; 273 ixa->ixa_ip_hdr_length = ip_hdr_len; 274 } else { 275 cmn_err(CE_NOTE, "not v4"); 276 } 277 278 dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len]; 279 280 nmp->b_wptr = &nmp->b_rptr[len]; 281 282 ixa->ixa_pktlen = len; // ? 283 284 nmp_dccpha->dha_fport = dccpha->dha_lport; 285 nmp_dccpha->dha_lport = dccpha->dha_fport; 286 nmp_dccpha->dha_type = DCCP_PKT_RESET; 287 nmp_dccpha->dha_x = 1; 288 nmp_dccpha->dha_res_seq = 0; 289 nmp_dccpha->dha_seq = 0; 290 291 nmp_dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t)); 292 293 dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)]; 294 nmp_dccpha_ext = (dccpha_ext_t *)&nmp->b_rptr[ip_hdr_len + sizeof (dccpha_t)]; 295 nmp_dccpha_ext->dha_ext_seq = 0; 296 297 len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t); 298 nmp_dccpha_ack = (dccpha_ack_t *)&nmp->b_rptr[len]; 299 nmp_dccpha_ack->dha_ack_high = dccpha->dha_seq; 300 nmp_dccpha_ack->dha_ack_low = dccpha_ext->dha_ext_seq; 301 302 len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t); 303 nmp_dccpha_reset = (dccpha_reset_t *)&nmp->b_rptr[len]; 304 nmp_dccpha_reset->dha_reset_code = 7; 305 nmp_dccpha_reset->dha_reset_data[0] = 0; 306 nmp_dccpha_reset->dha_reset_data[1] = 0; 307 nmp_dccpha_reset->dha_reset_data[2] = 0; 308 309 (void) ip_output_simple(nmp, ixa); 310 311 ixa_cleanup(ixa); 312 } 313 314 /* 315 * 316 */ 317 static boolean_t 318 dccp_send_rst_chk(dccp_stack_t *dccps) 319 { 320 int64_t now; 321 322 if (dccps->dccps_rst_sent_rate_enabled != 0) { 323 now = ddi_get_lbolt64(); 324 if (TICK_TO_MSEC(now - dccps->dccps_last_rst_intrvl) > 325 1 * SECONDS) { 326 dccps->dccps_last_rst_intrvl = now; 327 dccps->dccps_rst_cnt = 1; 328 } else if (++dccps->dccps_rst_cnt > dccps->dccps_rst_sent_rate) { 329 return (B_FALSE); 330 } 331 } 332 333 return (B_TRUE); 334 } 335 336 void 337 dccp_send_synack(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy) 338 { 339 cmn_err(CE_NOTE, "dccp_output.c: dccp_send_synack"); 340 } 341 342 mblk_t * 343 dccp_xmit_mp(dccp_t *dccp, mblk_t *mp, int32_t max_to_send, int32_t *offset, 344 mblk_t **end_mp, uint32_t seq, boolean_t sendall, uint32_t *seg_len, 345 boolean_t rexmit) 346 { 347 conn_t *connp = dccp->dccp_connp; 348 dccp_stack_t *dccps = dccp->dccp_dccps; 349 dccpha_t *dccpha; 350 dccpha_ext_t *dccpha_ext; 351 dccpha_ack_t *dccpha_ack; 352 dccpha_srv_t *dccpha_srv; 353 ip_xmit_attr_t *ixa = connp->conn_ixa; 354 mblk_t *mp1; 355 uchar_t *rptr; 356 ushort_t len; 357 int data_length; 358 359 cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_mp"); 360 361 // dccpha_t already in iphc_len? 362 len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4; 363 364 //mp1 = dccp_generate_packet(connp, mp); 365 mp1 = allocb(len, BPRI_MED); 366 if (mp1 == NULL) { 367 cmn_err(CE_NOTE, "allocb failed"); 368 return (NULL); 369 } 370 371 data_length = 0; 372 373 rptr = mp1->b_rptr; 374 mp1->b_wptr = &mp1->b_rptr[len]; 375 bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len); 376 dccpha = (dccpha_t *)&rptr[ixa->ixa_ip_hdr_length]; 377 dccpha->dha_type = DCCP_PKT_RESPONSE; 378 dccpha->dha_offset = 8; 379 dccpha->dha_x = 1; 380 dccpha->dha_ccval = 0; 381 dccpha->dha_cscov = 0; 382 dccpha->dha_reserved = 0; 383 dccpha->dha_res_seq = 0; 384 dccpha->dha_seq = 0; 385 386 dccpha_ext = (dccpha_ext_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t)]; 387 dccpha_ext->dha_ext_seq = 0; 388 389 dccpha_ack = (dccpha_ack_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t)]; 390 dccpha_ack->dha_ack_reserved = 0; 391 dccpha_ack->dha_ack_high = 0; 392 dccpha_ack->dha_ack_low = 0; 393 394 dccpha_srv = (dccpha_srv_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t)]; 395 dccpha_srv->dha_srv_code = 0; 396 397 return (mp1); 398 } 399 400 mblk_t * 401 dccp_generate_packet(conn_t *connp, mblk_t *mp) 402 { 403 dccpha_t *dccpha; 404 dccpha_ext_t *dccpha_ext; 405 dccpha_ack_t *dccpha_ack; 406 dccpha_srv_t *dccpha_srv; 407 mblk_t *mp1; 408 uint16_t ack_high; 409 uint32_t ack_low; 410 // uint_t ip_hdr_len = ira->ira_ip_hdr_length; 411 ip_xmit_attr_t *ixa = connp->conn_ixa; 412 uint_t ip_hdr_len; 413 uint_t len; 414 uint_t total_hdr_len; 415 uchar_t *rptr; 416 dccp_t *dccp = connp->conn_dccp; 417 void *options; 418 size_t opt_len; 419 int error; 420 421 cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_packet"); 422 423 ip_hdr_len = ixa->ixa_ip_hdr_length; 424 425 if (mp == NULL) { 426 cmn_err(CE_NOTE, "NULL pointer mp"); 427 return (NULL); 428 } 429 430 dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len]; 431 dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)]; 432 433 ack_high = dccpha->dha_seq; 434 ack_low = dccpha_ext->dha_ext_seq; 435 436 error = dccp_generate_options(dccp, &options, &opt_len); 437 if (error != 0) { 438 cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_options failed"); 439 } 440 cmn_err(CE_NOTE, "generated options len: %d", (int) opt_len); 441 442 443 /* 444 * conn_ht_iphc_len = ip_hdr_length (20) + ulp_hdr_length 445 * (20) simple ip header (without vtag or options) 446 */ 447 total_hdr_len = len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4 + opt_len; 448 mp1 = allocb(len, BPRI_MED); 449 if (mp1 == NULL) { 450 cmn_err(CE_NOTE, "allocb failed"); 451 return (NULL); 452 } 453 454 rptr = mp1->b_rptr; 455 mp1->b_wptr = &mp1->b_rptr[len]; 456 457 bcopy(options, &mp1->b_rptr[len-opt_len], opt_len); 458 bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len); 459 dccpha = (dccpha_t *)&rptr[ip_hdr_len]; 460 461 dccpha->dha_type = DCCP_PKT_RESPONSE; 462 dccpha->dha_offset = 7 + (opt_len / 4); 463 dccpha->dha_x = 1; 464 dccpha->dha_ccval = 0; 465 dccpha->dha_cscov = 0; 466 dccpha->dha_reserved = 0; 467 dccpha->dha_res_seq = 0; 468 dccpha->dha_seq = 0; 469 dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4 + opt_len); 470 471 472 dccpha_ext = (dccpha_ext_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t)]; 473 dccpha_ext->dha_ext_seq = 1234567; 474 475 dccpha_ack = (dccpha_ack_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t)]; 476 dccpha_ack->dha_ack_high = ack_high; 477 dccpha_ack->dha_ack_low = ack_low; 478 479 dccpha_srv = (dccpha_srv_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t)]; 480 dccpha_srv->dha_srv_code = 0; 481 482 ixa->ixa_pktlen = total_hdr_len; 483 484 if (ixa->ixa_flags & IXAF_IS_IPV4) { 485 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len); 486 } else { 487 ip6_t *ip6 = (ip6_t *)rptr; 488 489 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN); 490 } 491 492 cmn_err(CE_NOTE, "IPHC LEN: %d", connp->conn_ht_iphc_len); 493 cmn_err(CE_NOTE, "TOTAL LEN: %d", total_hdr_len); 494 495 kmem_free(options, opt_len); 496 497 return (mp1); 498 } 499 500 /* 501 * Generate a request packet. Must use 48-bit sequence 502 * numbers. 503 */ 504 mblk_t * 505 dccp_generate_request(conn_t *connp) 506 { 507 dccp_t *dccp = connp->conn_dccp; 508 dccpha_t *dccpha; 509 dccpha_ext_t *dccpha_ext; 510 dccpha_srv_t *dccpha_srv; 511 ip_xmit_attr_t *ixa = connp->conn_ixa; 512 mblk_t *mp; 513 uchar_t *rptr; 514 uint_t total_hdr_len; 515 uint_t len = ixa->ixa_ip_hdr_length; 516 517 cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_request"); 518 519 total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_srv_t); 520 mp = allocb(total_hdr_len, BPRI_MED); 521 if (mp == NULL) { 522 return (NULL); 523 } 524 525 rptr = mp->b_rptr; 526 /* Copy in the template header */ 527 bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len); 528 529 dccpha = (dccpha_t *)&rptr[ixa->ixa_ip_hdr_length]; 530 dccpha->dha_type = DCCP_PKT_REQUEST; 531 dccpha->dha_x = 1; 532 533 /* Extended sequence number */ 534 len += sizeof (dccpha_t); 535 dccpha_ext = (dccpha_ext_t *)&rptr[len]; 536 537 /* Service number */ 538 len += sizeof (dccpha_ext_t); 539 dccpha_srv = (dccpha_srv_t *)&rptr[len]; 540 dccpha_srv->dha_srv_code = 0; 541 542 ixa->ixa_pktlen = total_hdr_len; 543 if (ixa->ixa_flags & IXAF_IS_IPV4) { 544 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len); 545 } else { 546 ip6_t *ip6 = (ip6_t *)rptr; 547 548 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN); 549 } 550 551 return (mp); 552 }