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 static int dccp_xmit_end(dccp_t *);
61 static mblk_t *dccp_generate_common(conn_t *, uint8_t, uint_t);
62
63 /*
64 * STREAMS
65 */
66 void
67 dccp_wput(queue_t *q, mblk_t *mp)
68 {
69 cmn_err(CE_NOTE, "dccp_output.c: dccp_wput");
70 }
71
72 /*
73 * Fast path write put.
74 */
75 void
76 dccp_wput_data(dccp_t *dccp, mblk_t *mp, boolean_t urgent)
77 {
78 cmn_err(CE_NOTE, "dccp_output.c: dccp_wput_data");
79 }
80
81 /*
82 *
83 */
84 void
85 dccp_wput_sock(queue_t *wq, mblk_t *mp)
86 {
87 conn_t *connp = Q_TO_CONN(wq);
88 dccp_t *dccp = connp->conn_dccp;
89 struct T_capability_req *car = (struct T_capability_req *)mp->b_rptr;
90
91 cmn_err(CE_NOTE, "dccp_wput_sock");
92
93 ASSERT(wq->q_qinfo == &dccp_sock_winit);
94 wq->q_qinfo = &dccp_winit;
95
96 ASSERT(IPCL_IS_TCP(connp));
97 ASSERT(DCCP_IS_SOCKET(dccp));
98
99 if (DB_TYPE(mp) == M_PCPROTO &&
100 MBLKL(mp) == sizeof (struct T_capability_req) &&
101 car->PRIM_type == T_CAPABILITY_REQ) {
102 dccp_capability_req(dccp, mp);
103 return;
104 }
105
106 dccp_wput(wq, mp);
107 }
108
109 /* ARGSUSED */
110 void
111 dccp_wput_fallback(queue_t *eq, mblk_t *mp)
112 {
113 cmn_err(CE_NOTE, "dccp_output.c: dccp_wput_fallback");
114
115 #ifdef DEBUG
116 cmn_err(CE_CONT, "tcp_wput_fallback: Message during fallback \n");
117 #endif /* DEBUG */
118
119 freemsg(mp);
120 }
121
122 /*
123 * Initiate closedown sequence on an active connection.
124 */
125 static int
126 dccp_xmit_end(dccp_t *dccp)
127 {
128 conn_t *connp = dccp->dccp_connp;
129 mblk_t *mp;
130
131 /* XXX */
132
133 return (0);
134 }
135
136 /*
137 * Output fast path.
138 */
139 void
140 dccp_output(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
141 {
142 conn_t *connp = (conn_t *)arg;
143 dccp_t *dccp = connp->conn_dccp;
144 dccp_stack_t *dccps = dccp->dccp_dccps;
145 dccpha_t *dccpha;
146 mblk_t *mp1;
147 ip_xmit_attr_t *ixa;
148 struct datab *db;
149 uchar_t *rptr;
150 uint32_t msize;
151 uint32_t sum;
152 int len;
153 int plen;
154
155 cmn_err(CE_NOTE, "dccp_output.c: dccp_output");
156
157 ASSERT((connp->conn_fanout != NULL && connp->conn_ref >= 4) ||
158 (connp->conn_fanout == NULL && connp->conn_ref >= 3));
159
160 ASSERT(DB_TYPE(mp) == M_DATA);
161 msize = (mp->b_cont == NULL) ? MBLKL(mp) : msgdsize(mp);
162
163 ASSERT((uintptr_t)(mp->b_wptr - mp->b_rptr) <= (uintptr_t)INT_MAX);
164 len = (int)(mp->b_wptr - mp->b_rptr);
165
166 if ((mp->b_cont != NULL) ||
167 (dccp->dccp_state != DCCPS_OPEN) ||
168 (len == 0)) {
169 dccp_wput_data(dccp, mp, B_FALSE);
170 return;
171 }
172
173 mp1 = dupb(mp);
174 if (mp1 == NULL) {
175 goto no_memory;
176 }
177
178 /* Adjust header information */
179 dccpha = dccp->dccp_dccpha;
180
181 sum = len + connp->conn_ht_ulp_len + connp->conn_sum;
182 sum = (sum >> 16) + (sum & 0xffff);
183 dccpha->dha_sum = htons(sum);
184
185 DCCPS_BUMP_MIB(dccps, dccpOutDataSegs);
186 DCCPS_UPDATE_MIB(dccps, dccpOutDataBytes, len);
187 BUMP_LOCAL(dccp->dccp_obsegs);
188
189 plen = len + connp->conn_ht_iphc_len;
190
191 ixa = connp->conn_ixa;
192 ixa->ixa_pktlen = plen;
193
194 if (ixa->ixa_flags & IXAF_IS_IPV4) {
195 dccp->dccp_ipha->ipha_length = htons(plen);
196 } else {
197 dccp->dccp_ip6h->ip6_plen = htons(plen - IPV6_HDR_LEN);
198 }
199
200 rptr = mp1->b_rptr;
201 bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
202
203 dccp_send_data(dccp, mp1);
204
205 return;
206
207 no_memory:
208 return;
209 }
210
211 void
212 dccp_output_urgent(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
213 {
214 cmn_err(CE_NOTE, "dccp_output.c: dccp_output_urgent");
215 }
216
217 void
218 dccp_close_output(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
219 {
220 conn_t *connp = (conn_t *)arg;
221 dccp_t *dccp = connp->conn_dccp;
222 dccp_stack_t *dccps = dccp->dccp_dccps;
223 char *msg;
224
225 cmn_err(CE_NOTE, "dccp_output.c: dccp_close_output");
226
227 /*
228 * When a non-STREAMS socket is being closed, it does not always
229 * stick around waiting for tcp_close_output to run and can therefore
230 * have dropped a reference already. So adjust the asserts accordingly.
231 */
232 ASSERT((connp->conn_fanout != NULL &&
233 connp->conn_ref >= (IPCL_IS_NONSTR(connp) ? 3 : 4)) ||
234 (connp->conn_fanout == NULL &&
235 connp->conn_ref >= (IPCL_IS_NONSTR(connp) ? 2 : 3)));
236
237 msg = NULL;
238 switch (dccp->dccp_state) {
239 case DCCPS_CLOSED:
240 break;
241 case DCCPS_BOUND:
242 break;
243 case DCCPS_REQUEST:
244 msg = "dccp_close, during connect";
245 break;
246 case DCCPS_RESPOND:
247 /* FALLTHRU */
248 default:
249 /*
250 * If SO_LINGER has set a zero linger time, abort the
251 * connection with a reset.
252 */
253 if (connp->conn_linger && connp->conn_lingertime == 0) {
254 msg = "dccp_close, zero lingertime";
255 break;
256 }
257 }
258 }
259
260 /* ARGSUSED */
261 void
262 dccp_shutdown_output(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
263 {
264 conn_t *connp = (conn_t *)arg;
265 dccp_t *dccp = connp->conn_dccp;
266
267 freemsg(mp);
268
269 if (dccp_xmit_end(dccp) != 0) {
270 /*
271 * We were crossing FINs and got a reset from
272 * the other side. Just ignore it.
273 */
274 if (connp->conn_debug) {
275 (void) strlog(DCCP_MOD_ID, 0, 1,
276 SL_ERROR|SL_TRACE,
277 "dccp_shutdown_output() out of state %s",
278 dccp_display(dccp, NULL, DISP_ADDR_AND_PORT));
279 }
280 }
281 }
282
283 #pragma inline(dccp_send_data)
284
285 void
286 dccp_send_data(dccp_t *dccp, mblk_t *mp)
287 {
288 conn_t *connp = dccp->dccp_connp;
289 int error;
290
291 cmn_err(CE_NOTE, "dccp_output.c: dccp_sent_data");
292
293 /* XXX zcopy aware */
294
295 DTRACE_DCCP5(send, mblk_t *, NULL, ip_xmit_attr_t *, connp->conn_ixa,
296 __dtrace_dccp_void_ip_t *, mp->b_rptr, dccp_t *, dccp,
297 __dtrace_dccp_dccph_t *,
298 &mp->b_rptr[connp->conn_ixa->ixa_ip_hdr_length]);
299
300 ASSERT(connp->conn_ixa->ixa_notify_cookie == connp->conn_tcp);
301 error = conn_ip_output(mp, connp->conn_ixa);
302 if (error != 0) {
303 cmn_err(CE_NOTE, "conn_ip_output failed with code %d\n", error);
304 }
305 }
306
307 /*
308 * Send a reset as response to an incoming packet or
309 * reset a connection.
310 */
311 void
312 dccp_xmit_listeners_reset(mblk_t *mp, ip_recv_attr_t *ira, ip_stack_t *ipst,
313 conn_t *connp)
314 {
315 netstack_t *ns = ipst->ips_netstack;
316 dccp_stack_t *dccps = ns->netstack_dccp;
317 ipsec_stack_t *ipss = dccps->dccps_netstack->netstack_ipsec;
318 dccpha_t *dccpha;
319 ipha_t *ipha;
320 ip6_t *ip6h;
321 uchar_t *rptr;
322 uint32_t seq_len;
323 uint_t ip_hdr_len = ira->ira_ip_hdr_length;
324 boolean_t policy_present;
325
326 cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_listeners_reset");
327
328 DCCP_STAT(dccps, dccp_no_listener);
329
330 if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
331 policy_present = ipss->ipsec_inbound_v4_policy_present;
332 ipha = (ipha_t *)mp->b_rptr;
333 ip6h = NULL;
334 } else {
335 policy_present = ipss->ipsec_inbound_v6_policy_present;
336 ipha = NULL;
337 ip6h = (ip6_t *)mp->b_rptr;
338 }
339
340 if (policy_present) {
341 mp = ipsec_check_global_policy(mp, (conn_t *)NULL, ipha, ip6h,
342 ira, ns);
343 if (mp == NULL) {
344 return;
345 }
346 }
347
348 rptr = mp->b_rptr;
349
350 dccpha = (dccpha_t *)&rptr[ip_hdr_len];
351
352 seq_len = msgdsize(mp) - (ip_hdr_len);
353
354 dccp_xmit_early_reset("no dccp, reset", mp, 0,
355 0, 0, ira, ipst, connp);
356 }
357
358 /*
359 * RFC 4340, Section 8.1.3
360 */
361 static void
362 dccp_xmit_early_reset(char *str, mblk_t *mp, uint32_t seq, uint32_t ack, int ctl,
363 ip_recv_attr_t *ira, ip_stack_t *ipst, conn_t *connp)
364 {
365 dccpha_t *dccpha;
366 dccpha_t *nmp_dccpha;
367 dccpha_ack_t *nmp_dccpha_ack;
368 dccpha_reset_t *dccpha_reset;
369 dccpha_reset_t *nmp_dccpha_reset;
370 dccpha_ext_t *dccpha_ext;
371 dccpha_ext_t *nmp_dccpha_ext;
372 netstack_t *ns = ipst->ips_netstack;
373 dccp_stack_t *dccps = ns->netstack_dccp;
374 ip6_t *ip6h;
375 ipha_t *ipha;
376 ipha_t *nmp_ipha;
377 ip_xmit_attr_t ixas;
378 ip_xmit_attr_t *ixa;
379 in6_addr_t v6addr;
380 ipaddr_t v4addr;
381 mblk_t *nmp;
382 uint64_t pkt_ack;
383 uint_t ip_hdr_len = ira->ira_ip_hdr_length;
384 ushort_t port;
385 ushort_t len;
386
387 cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_early_reset");
388
389 if (!dccp_send_rst_chk(dccps)) {
390 cmn_err(CE_NOTE, "dccp_output.c: not sending reset packet");
391 DCCP_STAT(dccps, dccp_rst_unsent);
392 freemsg(mp);
393 return;
394 }
395
396 bzero(&ixas, sizeof (ixas));
397 ixa = &ixas;
398
399 ixa->ixa_flags |= IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE;
400 ixa->ixa_protocol = IPPROTO_DCCP;
401 ixa->ixa_zoneid = ira->ira_zoneid;
402 ixa->ixa_ifindex = 0;
403 ixa->ixa_ipst = ipst;
404 ixa->ixa_cred = kcred;
405 ixa->ixa_cpid = NOPID;
406
407 if (str && dccps->dccps_dbg) {
408 (void) strlog(DCCP_MOD_ID, 0, 1, SL_TRACE,
409 "dccp_xmit_early_reset: '%s', seq 0x%x, ack 0x%x, "
410 "flags 0x%x",
411 str, seq, ack, ctl);
412 }
413
414 if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
415 ipha = (ipha_t *)mp->b_rptr;
416
417 } else {
418 /* XXX */
419 }
420
421 /*
422 * Allocate a new DCCP reset message
423 */
424 len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t);
425 nmp = allocb(len, BPRI_MED);
426 if (nmp == NULL) {
427 cmn_err(CE_NOTE, "alloc failed");
428 return;
429 }
430 bcopy(mp->b_rptr, nmp->b_wptr, ip_hdr_len + sizeof (dccpha_t));
431
432 nmp_dccpha = (dccpha_t *)&nmp->b_rptr[ip_hdr_len];
433 nmp_dccpha->dha_offset = 7;
434
435 if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
436 nmp_ipha = (ipha_t *)nmp->b_rptr;
437
438 nmp_ipha->ipha_length = htons(len);
439 nmp_ipha->ipha_src = ipha->ipha_dst;
440 nmp_ipha->ipha_dst = ipha->ipha_src;
441
442 ixa->ixa_flags |= IXAF_IS_IPV4;
443 ixa->ixa_ip_hdr_length = ip_hdr_len;
444 } else {
445 cmn_err(CE_NOTE, "not v4");
446 }
447
448 dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
449
450 nmp->b_wptr = &nmp->b_rptr[len];
451
452 ixa->ixa_pktlen = len; // ?
453
454 nmp_dccpha->dha_fport = dccpha->dha_lport;
455 nmp_dccpha->dha_lport = dccpha->dha_fport;
456 nmp_dccpha->dha_type = DCCP_PKT_RESET;
457 nmp_dccpha->dha_x = 1;
458 nmp_dccpha->dha_res_seq = 0;
459 nmp_dccpha->dha_seq = 0;
460
461 nmp_dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
462 sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t));
463
464 dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
465 nmp_dccpha_ext = (dccpha_ext_t *)&nmp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
466 nmp_dccpha_ext->dha_ext_seq = 0;
467
468 len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t);
469 nmp_dccpha_ack = (dccpha_ack_t *)&nmp->b_rptr[len];
470 nmp_dccpha_ack->dha_ack_high = dccpha->dha_seq;
471 nmp_dccpha_ack->dha_ack_low = dccpha_ext->dha_ext_seq;
472 nmp_dccpha_ack->dha_ack_reserved = 0;
473
474 len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t);
475 nmp_dccpha_reset = (dccpha_reset_t *)&nmp->b_rptr[len];
476
477 if (connp != NULL) {
478 nmp_dccpha_reset->dha_reset_code =
479 connp->conn_dccp->dccp_reset_code;
480 } else {
481 nmp_dccpha_reset->dha_reset_code =
482 DCCP_RESET_CONNECTION_REFUSED;
483 }
484 nmp_dccpha_reset->dha_reset_data[0] = 0;
485 nmp_dccpha_reset->dha_reset_data[1] = 0;
486 nmp_dccpha_reset->dha_reset_data[2] = 0;
487
488 (void) ip_output_simple(nmp, ixa);
489
490 ixa_cleanup(ixa);
491 }
492
493 /*
494 *
495 */
496 static boolean_t
497 dccp_send_rst_chk(dccp_stack_t *dccps)
498 {
499 int64_t now;
500
501 if (dccps->dccps_rst_sent_rate_enabled != 0) {
502 now = ddi_get_lbolt64();
503 if (TICK_TO_MSEC(now - dccps->dccps_last_rst_intrvl) >
504 1 * SECONDS) {
505 dccps->dccps_last_rst_intrvl = now;
506 dccps->dccps_rst_cnt = 1;
507 } else if (++dccps->dccps_rst_cnt > dccps->dccps_rst_sent_rate) {
508 return (B_FALSE);
509 }
510 }
511
512 return (B_TRUE);
513 }
514
515 /* ARGSUSED2 */
516 void
517 dccp_send_synack(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
518 {
519 conn_t *econnp = (conn_t *)arg;
520 dccp_t *dccp = econnp->conn_dccp;
521 ip_xmit_attr_t *ixa = econnp->conn_ixa;
522
523 cmn_err(CE_NOTE, "dccp_output.c: dccp_send_synack");
524
525 /*
526 * Guard against a RESET having blown it away while on the
527 * squeue.
528 */
529 if (dccp->dccp_state == DCCPS_CLOSED) {
530 freemsg(mp);
531 return;
532 }
533
534 ixa->ixa_pktlen = msgdsize(mp);
535 (void) conn_ip_output(mp, ixa);
536 }
537
538 mblk_t *
539 dccp_xmit_mp(dccp_t *dccp, mblk_t *mp, int32_t max_to_send, int32_t *offset,
540 mblk_t **end_mp, uint32_t seq, boolean_t sendall, uint32_t *seg_len,
541 boolean_t rexmit)
542 {
543 conn_t *connp = dccp->dccp_connp;
544 dccp_stack_t *dccps = dccp->dccp_dccps;
545 dccpha_t *dccpha;
546 dccpha_ext_t *dccpha_ext;
547 dccpha_ack_t *dccpha_ack;
548 dccpha_srv_t *dccpha_srv;
549 ip_xmit_attr_t *ixa = connp->conn_ixa;
550 mblk_t *mp1;
551 uchar_t *rptr;
552 ushort_t len;
553 int data_length;
554
555 cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_mp");
556
557 // dccpha_t already in iphc_len?
558 len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4;
559
560 mp1 = allocb(len, BPRI_MED);
561 if (mp1 == NULL) {
562 cmn_err(CE_NOTE, "allocb failed");
563 return (NULL);
564 }
565
566 data_length = 0;
567
568 rptr = mp1->b_rptr;
569 mp1->b_wptr = &mp1->b_rptr[len];
570 bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
571 dccpha = (dccpha_t *)&rptr[ixa->ixa_ip_hdr_length];
572 dccpha->dha_type = DCCP_PKT_RESPONSE;
573 dccpha->dha_offset = 8;
574 dccpha->dha_x = 1;
575 dccpha->dha_ccval = 0;
576 dccpha->dha_cscov = 0;
577 dccpha->dha_reserved = 0;
578 dccpha->dha_res_seq = 0;
579 dccpha->dha_seq = 0;
580
581 dccpha_ext = (dccpha_ext_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t)];
582 dccpha_ext->dha_ext_seq = 0;
583
584 dccpha_ack = (dccpha_ack_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t)];
585 dccpha_ack->dha_ack_reserved = 0;
586 dccpha_ack->dha_ack_high = 0;
587 dccpha_ack->dha_ack_low = 0;
588
589 dccpha_srv = (dccpha_srv_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t)];
590 dccpha_srv->dha_srv_code = 0;
591
592 return (mp1);
593 }
594
595 /*
596 * Generate a DCCP-Response packet.
597 */
598 mblk_t *
599 dccp_generate_response(conn_t *connp, mblk_t *mp)
600 {
601 dccpha_t *dccpha;
602 dccpha_ext_t *dccpha_ext;
603 dccpha_ack_t *dccpha_ack;
604 dccpha_srv_t *dccpha_srv;
605 mblk_t *mp1;
606 uint64_t seq;
607 uint64_t ack;
608 uint16_t ack_high;
609 uint32_t ack_low;
610 // uint_t ip_hdr_len = ira->ira_ip_hdr_length;
611 ip_xmit_attr_t *ixa = connp->conn_ixa;
612 uint_t ip_hdr_len;
613 uint_t len;
614 uint_t total_hdr_len;
615 uchar_t *rptr;
616 dccp_t *dccp = connp->conn_dccp;
617 void *options;
618 size_t opt_len;
619 int error;
620
621 cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_packet");
622
623 ip_hdr_len = ixa->ixa_ip_hdr_length;
624
625 if (mp == NULL) {
626 cmn_err(CE_NOTE, "NULL pointer mp");
627 return (NULL);
628 }
629
630 dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
631 dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
632
633 ack_high = dccpha->dha_seq;
634 ack_low = dccpha_ext->dha_ext_seq;
635
636 seq = ntohs(ack_high) << 31;
637 seq |= ntohl(ack_low);
638
639 dccp->dccp_isr = seq;
640 dccp->dccp_gsr = seq;
641 dccp->dccp_swl = seq;
642 dccp->dccp_swh = seq;
643 dccp->dccp_gss++;
644
645 error = dccp_generate_options(dccp, &options, &opt_len);
646 if (error != 0) {
647 cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_options failed");
648 }
649 cmn_err(CE_NOTE, "generated options len: %d", (int) opt_len);
650
651
652 /*
653 * conn_ht_iphc_len = ip_hdr_length (20) + ulp_hdr_length
654 * (20) simple ip header (without vtag or options)
655 */
656 total_hdr_len = len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4 + opt_len;
657 mp1 = allocb(len, BPRI_MED);
658 if (mp1 == NULL) {
659 cmn_err(CE_NOTE, "allocb failed");
660 return (NULL);
661 }
662
663 rptr = mp1->b_rptr;
664 mp1->b_wptr = &mp1->b_rptr[len];
665
666 bcopy(options, &mp1->b_rptr[len-opt_len], opt_len);
667 bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
668 dccpha = (dccpha_t *)&rptr[ip_hdr_len];
669
670 dccpha->dha_type = DCCP_PKT_RESPONSE;
671 dccpha->dha_offset = 7 + (opt_len / 4);
672 dccpha->dha_x = 1;
673 dccpha->dha_ccval = 0;
674 dccpha->dha_cscov = 0;
675 dccpha->dha_reserved = 0;
676 dccpha->dha_res_seq = 0;
677 dccpha->dha_seq = htons(dccp->dccp_gss >> 32);;
678 dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4 + opt_len);
679
680
681 dccpha_ext = (dccpha_ext_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
682 dccpha_ext->dha_ext_seq = htonl(dccp->dccp_gss & 0xffffffff);
683
684 dccpha_ack = (dccpha_ack_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t)];
685 dccpha_ack->dha_ack_high = ack_high;
686 dccpha_ack->dha_ack_low = ack_low;
687 dccpha_ack->dha_ack_reserved = 0;
688
689 dccpha_srv = (dccpha_srv_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t)];
690 dccpha_srv->dha_srv_code = 0;
691
692 ixa->ixa_pktlen = total_hdr_len;
693
694 if (ixa->ixa_flags & IXAF_IS_IPV4) {
695 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
696 } else {
697 ip6_t *ip6 = (ip6_t *)rptr;
698
699 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
700 }
701
702 cmn_err(CE_NOTE, "IPHC LEN: %d", connp->conn_ht_iphc_len);
703 cmn_err(CE_NOTE, "TOTAL LEN: %d", total_hdr_len);
704
705 kmem_free(options, opt_len);
706
707 return (mp1);
708 }
709
710 /*
711 * Generate a request packet. Must use 48-bit sequence
712 * numbers.
713 */
714 mblk_t *
715 dccp_generate_request(conn_t *connp)
716 {
717 dccp_t *dccp = connp->conn_dccp;
718 dccpha_t *dccpha;
719 dccpha_ext_t *dccpha_ext;
720 dccpha_srv_t *dccpha_srv;
721 ip_xmit_attr_t *ixa = connp->conn_ixa;
722 mblk_t *mp;
723 uchar_t *rptr;
724 uint_t total_hdr_len;
725 uint_t len;
726
727 cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_request");
728
729 total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) +
730 sizeof (dccpha_srv_t);
731 mp = allocb(total_hdr_len, BPRI_MED);
732 if (mp == NULL) {
733 cmn_err(CE_NOTE, "allocb failed");
734 return (NULL);
735 }
736
737 rptr = mp->b_rptr;
738 mp->b_wptr = &mp->b_rptr[total_hdr_len];
739
740 /* Copy in the template header */
741 bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
742
743 len = ixa->ixa_ip_hdr_length;
744 dccpha = (dccpha_t *)&rptr[len];
745 dccpha->dha_type = DCCP_PKT_REQUEST;
746 dccpha->dha_offset = (sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
747 sizeof (dccpha_srv_t)) / 4;
748 dccpha->dha_x = 1;
749 dccpha->dha_ccval = 0;
750 dccpha->dha_cscov = 0;
751 dccpha->dha_reserved = 0;
752 dccpha->dha_res_seq = 0;
753 dccpha->dha_seq = 0;
754 dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
755 sizeof (dccpha_srv_t));
756
757 /* Extended sequence number */
758 len += sizeof (dccpha_t);
759 dccpha_ext = (dccpha_ext_t *)&rptr[len];
760
761 /* Service number */
762 len += sizeof (dccpha_ext_t);
763 dccpha_srv = (dccpha_srv_t *)&rptr[len];
764 dccpha_srv->dha_srv_code = 0;
765
766 ixa->ixa_pktlen = total_hdr_len;
767
768 if (ixa->ixa_flags & IXAF_IS_IPV4) {
769 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
770 } else {
771 ip6_t *ip6 = (ip6_t *)rptr;
772
773 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
774 }
775
776 return (mp);
777 }
778
779 /*
780 * Close packet.
781 */
782 mblk_t *
783 dccp_generate_reset(conn_t *connp)
784 {
785 dccp_t *dccp = connp->conn_dccp;
786 dccpha_t *dccpha;
787 dccpha_ext_t *dccpha_ext;
788 dccpha_ack_t *dccpha_ack;
789 dccpha_reset_t *dccpha_reset;
790 ip_xmit_attr_t *ixa = connp->conn_ixa;
791 mblk_t *mp;
792 uint64_t gss;
793 uchar_t *rptr;
794 uint_t total_hdr_len;
795 uint_t len = ixa->ixa_ip_hdr_length;
796
797 cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_reset");
798
799 /* XXX */
800 dccp->dccp_gss++;
801
802 /*
803 * Allocate a new DCCP reset message
804 */
805 total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) +
806 sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t);
807 mp = allocb(total_hdr_len, BPRI_MED);
808 if (mp == NULL) {
809 cmn_err(CE_NOTE, "allocb failed");
810 return(NULL);
811 }
812
813 rptr = mp->b_rptr;
814 mp->b_wptr = &mp->b_rptr[total_hdr_len];
815
816 bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
817
818 len = ixa->ixa_ip_hdr_length;
819 dccpha = (dccpha_t *)&mp->b_rptr[len];
820 dccpha->dha_type = DCCP_PKT_RESET;
821 dccpha->dha_offset = 7;
822 dccpha->dha_x = 1;
823 dccpha->dha_ccval = 0;
824 dccpha->dha_cscov = 0;
825 dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
826 sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t));
827 dccpha->dha_seq = htons(dccp->dccp_gss >> 32);
828 dccpha->dha_res_seq = 0;
829
830 len += sizeof (dccpha_t);
831 dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[len];
832 dccpha_ext->dha_ext_seq = htonl(dccp->dccp_gss & 0xffffffff);
833
834 /* Set ack */
835 len += sizeof (dccpha_ext_t);
836 dccpha_ack = (dccpha_ack_t *)&mp->b_rptr[len];
837 dccpha_ack->dha_ack_high = htons(dccp->dccp_gsr >> 32);
838 dccpha_ack->dha_ack_low = htonl(dccp->dccp_gsr & 0xffffffff);
839 dccpha_ack->dha_ack_reserved = 0;
840
841 len += sizeof (dccpha_ack_t);
842 dccpha_reset = (dccpha_reset_t *)&mp->b_rptr[len];
843 dccpha_reset->dha_reset_code = dccp->dccp_reset_code;
844 dccpha_reset->dha_reset_data[0] = dccp->dccp_reset_data[0];
845 dccpha_reset->dha_reset_data[1] = dccp->dccp_reset_data[1];
846 dccpha_reset->dha_reset_data[2] = dccp->dccp_reset_data[2];
847
848 ixa->ixa_pktlen = total_hdr_len;
849
850 if (ixa->ixa_flags & IXAF_IS_IPV4) {
851 cmn_err(CE_NOTE, "setting ip len for ipv4: %d", total_hdr_len);
852 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
853 } else {
854 ip6_t *ip6 = (ip6_t *)rptr;
855
856 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
857 }
858
859 return (mp);
860 }
861
862 /*
863 * Acknowledgement packet.
864 */
865 mblk_t *
866 dccp_generate_ack(conn_t *connp)
867 {
868 dccp_t *dccp = connp->conn_dccp;
869 dccpha_t *dccpha;
870 dccpha_ext_t *dccpha_ext;
871 dccpha_ack_t *dccpha_ack;
872 ip_xmit_attr_t *ixa = connp->conn_ixa;
873 mblk_t *mp;
874 uint64_t gss;
875 uchar_t *rptr;
876 uint_t total_hdr_len;
877 uint_t len = ixa->ixa_ip_hdr_length;
878
879 cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_ack");
880
881 /* XXX */
882 dccp->dccp_gss++;
883
884 /*
885 * Allocate a new DCCP reset message
886 */
887 total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) +
888 sizeof (dccpha_ack_t);
889 mp = allocb(total_hdr_len, BPRI_MED);
890 if (mp == NULL) {
891 cmn_err(CE_NOTE, "allocb failed");
892 return(NULL);
893 }
894
895 rptr = mp->b_rptr;
896 mp->b_wptr = &mp->b_rptr[total_hdr_len];
897
898 bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
899
900 len = ixa->ixa_ip_hdr_length;
901 dccpha = (dccpha_t *)&mp->b_rptr[len];
902 dccpha->dha_type = DCCP_PKT_ACK;
903 dccpha->dha_offset = 6;
904 dccpha->dha_x = 1;
905 dccpha->dha_ccval = 0;
906 dccpha->dha_cscov = 0;
907 dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
908 sizeof (dccpha_ack_t));
909 dccpha->dha_seq = htons(dccp->dccp_gss >> 32);
910 dccpha->dha_res_seq = 0;
911
912 len += sizeof (dccpha_t);
913 dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[len];
914 dccpha_ext->dha_ext_seq = htonl(dccp->dccp_gss & 0xffffffff);
915
916 len += sizeof (dccpha_ext_t);
917 dccpha_ack = (dccpha_ack_t *)&mp->b_rptr[len];
918 dccpha_ack->dha_ack_high = htons(dccp->dccp_gsr >> 32);
919 dccpha_ack->dha_ack_low = htonl(dccp->dccp_gsr & 0xffffffff);
920 dccpha_ack->dha_ack_reserved = 0;
921
922 ixa->ixa_pktlen = total_hdr_len;
923
924 if (ixa->ixa_flags & IXAF_IS_IPV4) {
925 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
926 } else {
927 ip6_t *ip6 = (ip6_t *)rptr;
928
929 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
930 }
931
932 return (mp);
933 }
934
935 /*
936 * Common to all packet generating functions.
937 */
938 static mblk_t *
939 dccp_generate_common(conn_t *connp, uint8_t packet_type,
940 uint_t total_hdr_len)
941 {
942 dccp_t *dccp = connp->conn_dccp;
943 dccpha_t *dccpha;
944 dccpha_ext_t *dccpha_ext;
945 dccpha_ack_t *dccpha_ack;
946 ip_xmit_attr_t *ixa = connp->conn_ixa;
947 mblk_t *mp;
948 uchar_t *rptr;
949 uint_t len;
950 boolean_t extended;
951
952 /*
953 * Allocate a new DCCP reset message
954 */
955 mp = allocb(total_hdr_len, BPRI_MED);
956 if (mp == NULL) {
957 return(NULL);
958 }
959
960 dccp->dccp_gss++;
961
962 rptr = mp->b_rptr;
963 mp->b_wptr = &mp->b_rptr[total_hdr_len];
964
965 bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
966
967 /* Basic header */
968 len = ixa->ixa_ip_hdr_length;
969 dccpha = (dccpha_t *)&mp->b_rptr[len];
970 dccpha->dha_type = packet_type;
971 dccpha->dha_offset = 6;
972 dccpha->dha_x = 1;
973 dccpha->dha_ccval = 0;
974 dccpha->dha_cscov = 0;
975 dccpha->dha_sum = htons(total_hdr_len - len);
976 dccpha->dha_seq = htons(dccp->dccp_gss >> 32);
977 dccpha->dha_res_seq = 0;
978
979 /* Extended sequence number */
980 len += sizeof (dccpha_t);
981 dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[len];
982 dccpha_ext->dha_ext_seq = htonl(dccp->dccp_gss & 0xffffffff);
983
984 /* Acknowledgement number */
985 len += sizeof (dccpha_ext_t);
986 dccpha_ack = (dccpha_ack_t *)&mp->b_rptr[len];
987 dccpha_ack->dha_ack_high = htons(dccp->dccp_gsr >> 32);
988 dccpha_ack->dha_ack_low = htonl(dccp->dccp_gsr & 0xffffffff);
989 dccpha_ack->dha_ack_reserved = 0;
990
991 ixa->ixa_pktlen = total_hdr_len;
992
993 if (ixa->ixa_flags & IXAF_IS_IPV4) {
994 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
995 } else {
996 ip6_t *ip6 = (ip6_t *)rptr;
997
998 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
999 }
1000
1001 return (mp);
1002 }
1003
1004 /*
1005 * Acknowledgement packet.
1006 */
1007 mblk_t *
1008 dccp_generate_sync(conn_t *connp)
1009 {
1010 dccp_t *dccp = connp->conn_dccp;
1011 dccpha_t *dccpha;
1012 dccpha_ext_t *dccpha_ext;
1013 dccpha_ack_t *dccpha_ack;
1014 ip_xmit_attr_t *ixa = connp->conn_ixa;
1015 mblk_t *mp;
1016 uchar_t *rptr;
1017 uint_t total_hdr_len;
1018 uint_t len = ixa->ixa_ip_hdr_length;
1019
1020 cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_ack");
1021
1022 total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) +
1023 sizeof (dccpha_ack_t);
1024 mp = dccp_generate_common(connp, DCCP_PACKET_SYNC, total_hdr_len);
1025 if (mp == NULL) {
1026 cmn_err(CE_NOTE, "allocb failed");
1027 return(NULL);
1028 }
1029
1030 rptr = mp->b_rptr;
1031 mp->b_wptr = &mp->b_rptr[total_hdr_len];
1032
1033 return (mp);
1034 }