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
52 #include <sys/cmn_err.h>
53
54 #include "dccp_impl.h"
55 #include "dccp_stack.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\n");
68 }
69
70 /*
71 * Send a reset as response to an incoming packet or
72 * reset a connection.
73 */
74 void
75 dccp_xmit_listeners_reset(mblk_t *mp, ip_recv_attr_t *ira, ip_stack_t *ipst,
76 conn_t *connp)
77 {
78 dccpha_t *dccpha;
79 uint32_t seg_seq;
80 uint32_t seg_ack;
81 uint32_t seq_len;
82 uint_t ip_hdr_len = ira->ira_ip_hdr_length;
83 uchar_t *rptr;
84
85 cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_listeners_reset");
86
87 rptr = mp->b_rptr;
88
89 dccpha = (dccpha_t *)&rptr[ip_hdr_len];
90
91 //seg_seq = ntonl(dccpha->dha_seq);
92 //seg_ack = htonl(dccpha->dha_ack);
93
94 seq_len = msgdsize(mp) - (ip_hdr_len);
95
96 dccp_xmit_early_reset("no dccp, reset", mp, 0,
97 0, 0, ira, ipst, connp);
98 }
99
100 /*
101 * RFC 4340, Section 8.1.3
102 */
103 static void
104 dccp_xmit_early_reset(char *str, mblk_t *mp, uint32_t seq, uint32_t ack, int ctl,
105 ip_recv_attr_t *ira, ip_stack_t *ipst, conn_t *connp)
106 {
107 dccpha_t *dccpha;
108 dccpha_t *nmp_dccpha;
109 dccpha_ack_t *nmp_dccpha_ack;
110 dccpha_reset_t *dccpha_reset;
111 dccpha_reset_t *nmp_dccpha_reset;
112 dccpha_ext_t *dccpha_ext;
113 dccpha_ext_t *nmp_dccpha_ext;
114 netstack_t *ns = ipst->ips_netstack;
115 dccp_stack_t *dccps = ns->netstack_dccp;
116 ip6_t *ip6h;
117 ipha_t *ipha;
118 ipha_t *nmp_ipha;
119 ip_xmit_attr_t ixas;
120 ip_xmit_attr_t *ixa;
121 in6_addr_t v6addr;
122 ipaddr_t v4addr;
123 mblk_t *nmp;
124 uint64_t pkt_ack;
125 uint_t ip_hdr_len = ira->ira_ip_hdr_length;
126 ushort_t port;
127 ushort_t len;
128
129 cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_early_reset");
130
131 if (!dccp_send_rst_chk(dccps)) {
132 cmn_err(CE_NOTE, "dccp_output.c: not sending reset packet");
133 DCCP_STAT(dccps, dccp_rst_unsent);
134 freemsg(mp);
135 return;
136 }
137
138 bzero(&ixas, sizeof (ixas));
139 ixa = &ixas;
140
141 ixa->ixa_flags |= IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE;
142 ixa->ixa_protocol = IPPROTO_DCCP;
143 ixa->ixa_zoneid = ira->ira_zoneid;
144 ixa->ixa_ifindex = 0;
145 ixa->ixa_ipst = ipst;
146 ixa->ixa_cred = kcred;
147 ixa->ixa_cpid = NOPID;
148
149 if (str && dccps->dccps_dbg) {
150 (void) strlog(DCCP_MOD_ID, 0, 1, SL_TRACE,
151 "dccp_xmit_early_reset: '%s', seq 0x%x, ack 0x%x, "
152 "flags 0x%x",
153 str, seq, ack, ctl);
154 }
155
156 if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
157 ipha = (ipha_t *)mp->b_rptr;
158
159 } else {
160 /* XXX */
161 }
162
163 /*
164 * Allocate a new DCCP reset message
165 */
166 len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t);
167 nmp = allocb(len, BPRI_MED);
168 if (nmp == NULL) {
169 cmn_err(CE_NOTE, "alloc failed");
170 return;
171 }
172 bcopy(mp->b_rptr, nmp->b_wptr, ip_hdr_len + sizeof (dccpha_t));
173
174 nmp_dccpha = (dccpha_t *)&nmp->b_rptr[ip_hdr_len];
175 nmp_dccpha->dha_offset = 7;
176
177 if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
178 nmp_ipha = (ipha_t *)nmp->b_rptr;
179
180 nmp_ipha->ipha_length = htons(len);
181 nmp_ipha->ipha_src = ipha->ipha_dst;
182 nmp_ipha->ipha_dst = ipha->ipha_src;
183
184 ixa->ixa_flags |= IXAF_IS_IPV4;
185 ixa->ixa_ip_hdr_length = ip_hdr_len;
186 } else {
187 cmn_err(CE_NOTE, "not v4");
188 }
189
190 dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
191
192 nmp->b_wptr = &nmp->b_rptr[len];
193
194 ixa->ixa_pktlen = len; // ?
195
196 nmp_dccpha->dha_fport = dccpha->dha_lport;
197 nmp_dccpha->dha_lport = dccpha->dha_fport;
198 nmp_dccpha->dha_type = DCCP_PKT_RESET;
199 nmp_dccpha->dha_x = 1;
200 nmp_dccpha->dha_res_seq = 0;
201 nmp_dccpha->dha_seq = 0;
202
203 nmp_dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t));
204
205 dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
206 nmp_dccpha_ext = (dccpha_ext_t *)&nmp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
207 nmp_dccpha_ext->dha_ext_seq = 0;
208
209 len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t);
210 nmp_dccpha_ack = (dccpha_ack_t *)&nmp->b_rptr[len];
211 nmp_dccpha_ack->dha_ack_high = dccpha->dha_seq;
212 nmp_dccpha_ack->dha_ack_low = dccpha_ext->dha_ext_seq;
213
214 len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t);
215 nmp_dccpha_reset = (dccpha_reset_t *)&nmp->b_rptr[len];
216 nmp_dccpha_reset->dha_reset_code = 7;
217 nmp_dccpha_reset->dha_reset_data[0] = 0;
218 nmp_dccpha_reset->dha_reset_data[1] = 0;
219 nmp_dccpha_reset->dha_reset_data[2] = 0;
220
221 (void) ip_output_simple(nmp, ixa);
222
223 ixa_cleanup(ixa);
224 }
225
226 /*
227 *
228 */
229 static boolean_t
230 dccp_send_rst_chk(dccp_stack_t *dccps)
231 {
232 int64_t now;
233
234 if (dccps->dccps_rst_sent_rate_enabled != 0) {
235 now = ddi_get_lbolt64();
236 if (TICK_TO_MSEC(now - dccps->dccps_last_rst_intrvl) >
237 1 * SECONDS) {
238 dccps->dccps_last_rst_intrvl = now;
239 dccps->dccps_rst_cnt = 1;
240 } else if (++dccps->dccps_rst_cnt > dccps->dccps_rst_sent_rate) {
241 return (B_FALSE);
242 }
243 }
244
245 return (B_TRUE);
246 }
247
248 void
249 dccp_send_synack(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
250 {
251 cmn_err(CE_NOTE, "dccp_output.c: dccp_send_synack");
252 }
253
254 mblk_t *
255 dccp_xmit_mp(dccp_t *dccp, mblk_t *mp, int32_t max_to_send, int32_t *offset,
256 mblk_t **end_mp, uint32_t seq, boolean_t sendall, uint32_t *seg_len,
257 boolean_t rexmit)
258 {
259 conn_t *connp = dccp->dccp_connp;
260 dccp_stack_t *dccps = dccp->dccp_dccps;
261 dccpha_t *dccpha;
262 dccpha_ext_t *dccpha_ext;
263 dccpha_ack_t *dccpha_ack;
264 dccpha_srv_t *dccpha_srv;
265 ip_xmit_attr_t *ixa = connp->conn_ixa;
266 mblk_t *mp1;
267 uchar_t *rptr;
268 ushort_t len;
269 int data_length;
270
271 cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_mp");
272
273 // dccpha_t already in iphc_len?
274 len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4;
275
276 //mp1 = dccp_generate_packet(connp, mp);
277 mp1 = allocb(len, BPRI_MED);
278 if (mp1 == NULL) {
279 cmn_err(CE_NOTE, "allocb failed");
280 return (NULL);
281 }
282
283 data_length = 0;
284
285 rptr = mp1->b_rptr;
286 mp1->b_wptr = &mp1->b_rptr[len];
287 bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
288 dccpha = (dccpha_t *)&rptr[ixa->ixa_ip_hdr_length];
289 dccpha->dha_type = DCCP_PKT_RESPONSE;
290 dccpha->dha_offset = 8;
291 dccpha->dha_x = 1;
292 dccpha->dha_ccval = 0;
293 dccpha->dha_cscov = 0;
294 dccpha->dha_reserved = 0;
295 dccpha->dha_res_seq = 0;
296 dccpha->dha_seq = 0;
297
298 dccpha_ext = (dccpha_ext_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t)];
299 dccpha_ext->dha_ext_seq = 0;
300
301 dccpha_ack = (dccpha_ack_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t)];
302 dccpha_ack->dha_ack_reserved = 0;
303 dccpha_ack->dha_ack_high = 0;
304 dccpha_ack->dha_ack_low = 0;
305
306 dccpha_srv = (dccpha_srv_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t)];
307 dccpha_srv->dha_srv_code = 0;
308
309 return (mp1);
310 }
311
312 mblk_t *
313 dccp_generate_packet(conn_t *connp, mblk_t *mp)
314 {
315 dccpha_t *dccpha;
316 dccpha_ext_t *dccpha_ext;
317 dccpha_ack_t *dccpha_ack;
318 mblk_t *mp1;
319 uint16_t ack_high;
320 uint32_t ack_low;
321 // uint_t ip_hdr_len = ira->ira_ip_hdr_length;
322 ip_xmit_attr_t *ixa = connp->conn_ixa;
323 uint_t ip_hdr_len;
324 uint_t len;
325 uchar_t *rptr;
326
327 cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_packet");
328
329 ip_hdr_len = ixa->ixa_ip_hdr_length;
330
331 if (mp == NULL) {
332 cmn_err(CE_NOTE, "NULL pointer mp");
333 return (NULL);
334 }
335
336 dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
337 dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
338
339 ack_high = dccpha->dha_seq;
340 ack_low = dccpha_ext->dha_ext_seq;
341
342 len = connp->conn_ht_iphc_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4;
343 //len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4;
344 mp1 = allocb(len, BPRI_MED);
345 if (mp1 == NULL) {
346 cmn_err(CE_NOTE, "allocb failed");
347 return (NULL);
348 }
349
350 rptr = mp1->b_rptr;
351 mp1->b_wptr = &mp1->b_rptr[len];
352
353 bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
354 dccpha = (dccpha_t *)&rptr[ixa->ixa_ip_hdr_length];
355 //dccpha = (dccpha_t *)&mp1->b_rptr[ip_hdr_len];
356
357 dccpha->dha_type = DCCP_PKT_RESPONSE;
358 dccpha->dha_offset = 8;
359 dccpha->dha_x = 1;
360 dccpha->dha_ccval = 0;
361 dccpha->dha_cscov = 0;
362 dccpha->dha_reserved = 0;
363 dccpha->dha_res_seq = 0;
364 dccpha->dha_seq = 1;
365 dccpha->dha_sum = htons(len);
366
367 dccpha_ext = (dccpha_ext_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
368 dccpha_ext->dha_ext_seq = 1;
369
370 dccpha_ack = (dccpha_ack_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t)];
371 dccpha_ack->dha_ack_high = ack_high;
372 dccpha_ack->dha_ack_low = ack_low;
373
374 return (mp1);
375 }