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 }