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 }