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 #include <sys/types.h>
32 #include <sys/stream.h>
33 #include <sys/strsun.h>
34 #include <sys/strsubr.h>
35 #include <sys/stropts.h>
36 #include <sys/strlog.h>
37 #define _SUN_TPI_VERSION 2
38 #include <sys/tihdr.h>
39 #include <sys/suntpi.h>
40 #include <sys/xti_inet.h>
41 #include <sys/squeue_impl.h>
42 #include <sys/squeue.h>
43 #include <sys/tsol/tnet.h>
44
45 #include <inet/common.h>
46 #include <inet/ip.h>
47
48 #include <sys/cmn_err.h>
49
50 #include "dccp_impl.h"
51
52 static mblk_t *dccp_conn_create_v4(conn_t *, conn_t *, mblk_t *,
53 ip_recv_attr_t *);
54 static mblk_t *dccp_conn_create_v6(conn_t *, conn_t *, mblk_t *,
55 ip_recv_attr_t *);
56 static void dccp_input_listener(void *, mblk_t *, void *, ip_recv_attr_t *);
57
58 void
59 dccp_input_data(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira)
60 {
61 cmn_err(CE_NOTE, "dccp_input.c: dccp_input_data");
62 }
63
64 void
65 dccp_icmp_input(void *arg1, mblk_t *mp, void *arg2, ip_recv_attr_t *ira)
66 {
67 cmn_err(CE_NOTE, "dccp_input.c: dccp_icmp_input");
68 }
69
70 void
71 dccp_rsrv(queue_t *q)
72 {
73 cmn_err(CE_NOTE, "dccp_input.c: dccp_rsrv");
74 }
75
76 static mblk_t *
77 dccp_conn_create_v6(conn_t *lconnp, conn_t *connp, mblk_t *mp,
78 ip_recv_attr_t *ira)
79 {
80 return (NULL);
81 }
82
83 static mblk_t *
84 dccp_conn_create_v4(conn_t *lconnp, conn_t *connp, mblk_t *mp,
85 ip_recv_attr_t *ira)
86 {
87 dccp_t *ldccp = lconnp->conn_dccp;
88 dccp_t *dccp = connp->conn_dccp;
89 dccp_stack_t *dccps = dccp->dccp_dccps;
90 ipha_t *ipha;
91 mblk_t *tpi_mp;
92 sin_t sin;
93
94 ASSERT(ira->ira_flags & IRAF_IS_IPV4);
95 ipha = (ipha_t *)mp->b_rptr;
96
97 connp->conn_ipversion = IPV4_VERSION;
98 IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &connp->conn_laddr_v6);
99 IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &connp->conn_faddr_v6);
100 connp->conn_saddr_v6 = connp->conn_laddr_v6;
101
102 sin = sin_null;
103 sin.sin_addr.s_addr = connp->conn_faddr_v4;
104 sin.sin_port = connp->conn_fport;
105 sin.sin_family = AF_INET;
106
107 if (lconnp->conn_recv_ancillary.crb_recvdstaddr) {
108 cmn_err(CE_NOTE, "ancillary");
109
110 sin_t sind;
111
112 sind = sin_null;
113 sind.sin_addr.s_addr = connp->conn_laddr_v4;
114 sind.sin_port = connp->conn_lport;
115 sind.sin_family = AF_INET;
116
117 tpi_mp = mi_tpi_extconn_ind(NULL,
118 (char *)&sind, sizeof (sin_t), (char *)&dccp,
119 (t_scalar_t)sizeof (intptr_t), (char *)&sind,
120 sizeof (sin_t), (t_scalar_t) 1); /* XXX */
121
122 } else {
123 tpi_mp = mi_tpi_conn_ind(NULL,
124 (char *)&sin, sizeof (sin_t),
125 (char *)&dccp, (t_scalar_t)sizeof (intptr_t),
126 (t_scalar_t) 1); /* XXX */
127 }
128
129 return (tpi_mp);
130 }
131
132 static void
133 dccp_input_listener(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira)
134 {
135 conn_t *lconnp = (conn_t *)arg;
136 conn_t *econnp;
137 dccp_t *listener = lconnp->conn_dccp;
138 dccp_t *eager;
139 dccp_stack_t *dccps = listener->dccp_dccps;
140 ip_stack_t *ipst = dccps->dccps_netstack->netstack_ip;
141 dccpha_t *dccpha;
142 squeue_t *new_sqp;
143 mblk_t *tpi_mp;
144 mblk_t *mp1;
145 uint_t ip_hdr_len;
146 uint_t type;
147 int error;
148
149 cmn_err(CE_NOTE, "dccp_input.c: dccp_input_listener");
150
151 ip_hdr_len = ira->ira_ip_hdr_length;
152 dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
153 type = (uint_t)dccpha->dha_type;
154
155 if (type != DCCP_PKT_REQUEST) {
156 cmn_err(CE_NOTE, "not request pkt");
157
158 /* XXX do something with a reset packet sent? */
159 freemsg(mp);
160 return;
161 }
162
163 /* XXX memory pressure */
164
165 /* XXX request defense */
166
167 /* XXX number of connections per listener */
168
169 ASSERT(ira->ira_sqp != NULL);
170 new_sqp = ira->ira_sqp;
171
172 econnp = (conn_t *)dccp_get_conn(arg2, dccps);
173 if (econnp == NULL) {
174 cmn_err(CE_NOTE, "econnp not found (eager)");
175 goto error2;
176 }
177
178 ASSERT(econnp->conn_netstack == lconnp->conn_netstack);
179 econnp->conn_sqp = new_sqp;
180 econnp->conn_initial_sqp = new_sqp;
181 econnp->conn_ixa->ixa_sqp = new_sqp;
182
183 econnp->conn_fport = dccpha->dha_lport;
184 econnp->conn_lport = dccpha->dha_fport;
185
186 error = conn_inherit_parent(lconnp, econnp);
187 if (error != 0) {
188 cmn_err(CE_NOTE, "conn_inherit_parent failed");
189 goto error3;
190 }
191
192 econnp->conn_ixa->ixa_src_generation = ipst->ips_src_generation;
193
194
195 ASSERT(OK_32PTR(mp->b_rptr));
196 ASSERT(IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION ||
197 IPH_HDR_VERSION(mp->b_rptr) == IPV6_VERSION);
198
199 if (lconnp->conn_family == AF_INET) {
200 ASSERT(IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION);
201 tpi_mp = dccp_conn_create_v4(lconnp, econnp, mp, ira);
202 } else {
203 tpi_mp = dccp_conn_create_v6(lconnp, econnp, mp, ira);
204 }
205
206 if (tpi_mp == NULL) {
207 cmn_err(CE_NOTE, "tpi_mo == NULL");
208 goto error3;
209 }
210
211 eager = econnp->conn_dccp;
212 SOCK_CONNID_INIT(eager->dccp_connid);
213
214 dccp_init_values(eager, listener);
215
216 ASSERT((econnp->conn_ixa->ixa_flags &
217 (IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE |
218 IXAF_VERIFY_PMTU | IXAF_VERIFY_LSO)) ==
219 (IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE |
220 IXAF_VERIFY_PMTU | IXAF_VERIFY_LSO));
221
222 if (ira->ira_cred != NULL) {
223 mblk_setcred(tpi_mp, ira->ira_cred, ira->ira_cpid);
224 }
225
226 if (IPCL_IS_NONSTR(lconnp)) {
227 econnp->conn_flags |= IPCL_NONSTR;
228 }
229
230 /* XXX dccps is right? */
231 dccp_bind_hash_insert(&dccps->dccps_bind_fanout[
232 DCCP_BIND_HASH(econnp->conn_lport, dccps->dccps_bind_fanout_size)], eager, 0);
233
234 SOCK_CONNID_BUMP(eager->dccp_connid);
235
236 error = dccp_set_destination(eager);
237 if (error != 0) {
238 cmn_err(CE_NOTE, "dccp_set_destination failed.");
239 dccp_bind_hash_remove(eager);
240 goto error3;
241 }
242
243 CONN_INC_REF(lconnp);
244
245 /*
246 mp1 = dccp_xmit_mp(eager, eager->dccp_xmit_head, 0,
247 NULL, NULL, 0, B_FALSE, NULL, B_FALSE);
248 */
249 mp1 = dccp_generate_packet(lconnp, mp);
250 if (mp1 == NULL) {
251 cmn_err(CE_NOTE, "dccp_xmit_mp failed");
252
253 CONN_INC_REF(econnp);
254 goto error;
255 }
256
257 CONN_INC_REF(econnp);
258
259 error = ipcl_conn_insert(econnp);
260 if (error != 0) {
261 cmn_err(CE_NOTE, "ipcl_conn_insert(econnp) failed");
262 goto error;
263 }
264
265 freemsg(mp);
266
267 if (econnp->conn_sqp == lconnp->conn_sqp) {
268 (void) conn_ip_output(mp1, econnp->conn_ixa);
269 CONN_DEC_REF(econnp);
270 } else {
271 SQUEUE_ENTER_ONE(econnp->conn_sqp, mp1, dccp_send_synack,
272 econnp, NULL, SQ_PROCESS, SQTAG_TCP_SEND_SYNACK); /* XXX */
273 }
274
275 return;
276 error:
277 error2:
278 error3:
279 freemsg(mp);
280 }
281
282 void
283 dccp_input_listener_unbound(void *arg, mblk_t *mp, void *arg2,
284 ip_recv_attr_t *ira)
285 {
286 conn_t *connp = (conn_t *)arg;
287 squeue_t *sqp = (squeue_t *)arg2;
288 squeue_t *new_sqp;
289 uint32_t conn_flags;
290
291 cmn_err(CE_NOTE, "dccp_input.c: dccp_input_listener_unbound");
292
293 ASSERT(ira->ira_sqp != NULL);
294 new_sqp = ira->ira_sqp;
295
296 if (connp->conn_fanout == NULL) {
297 goto done;
298 }
299
300 /*
301 * Bind to correct squeue.
302 */
303 if (!(connp->conn_flags & IPCL_FULLY_BOUND)) {
304 cmn_err(CE_NOTE, "not fully bound");
305
306 mutex_enter(&connp->conn_fanout->connf_lock);
307 mutex_enter(&connp->conn_lock);
308
309 if (connp->conn_ref != 4 ||
310 connp->conn_dccp->dccp_state != DCCPS_LISTEN) {
311 mutex_exit(&connp->conn_lock);
312 mutex_exit(&connp->conn_fanout->connf_lock);
313 goto done;
314 }
315
316 if (connp->conn_sqp != new_sqp) {
317 while (connp->conn_sqp != new_sqp) {
318 (void) casptr(&connp->conn_sqp, sqp, new_sqp);
319 }
320 connp->conn_ixa->ixa_sqp = new_sqp;
321 }
322
323 do {
324 conn_flags = connp->conn_flags;
325 conn_flags |= IPCL_FULLY_BOUND;
326 (void) cas32(&connp->conn_flags, connp->conn_flags,
327 conn_flags);
328 } while (!(connp->conn_flags & IPCL_FULLY_BOUND));
329
330 mutex_exit(&connp->conn_lock);
331 mutex_exit(&connp->conn_fanout->connf_lock);
332
333 connp->conn_recv = dccp_input_listener;
334 }
335
336 done:
337 if (connp->conn_sqp != sqp) {
338 CONN_INC_REF(connp);
339 SQUEUE_ENTER_ONE(connp->conn_sqp, mp, connp->conn_recv, connp,
340 ira, SQ_FILL, SQTAG_DCCP_CONN_REQ_UNBOUND);
341 } else {
342 dccp_input_listener(connp, mp, sqp, ira);
343 }
344 }
345
346 boolean_t
347 dccp_verifyicmp(conn_t *connp, void *arg2, icmph_t *icmph, icmp6_t *icmp6,
348 ip_recv_attr_t *ira)
349 {
350 cmn_err(CE_NOTE, "dccp_input.c: dccp_verifyicmp");
351
352 return (B_TRUE);
353 }