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