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 * This file implements the Data Congestion Control Protocol (DCCP).
33 */
34
35 #include <sys/types.h>
36 #include <sys/stream.h>
37 #include <sys/stropts.h>
38 #include <sys/strlog.h>
39 #include <sys/strsun.h>
40 #define _SUN_TPI_VERSION 2
41 #include <sys/tihdr.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/sockio.h>
45 #include <sys/priv.h>
46 #include <sys/vtrace.h>
47 #include <sys/sdt.h>
48 #include <sys/debug.h>
49 #include <sys/ddi.h>
50 #include <sys/isa_defs.h>
51 #include <sys/policy.h>
52 #include <sys/tsol/label.h>
53 #include <sys/tsol/tnet.h>
54
55 #include <inet/common.h>
56 #include <inet/ip.h>
57 #include <inet/ip_impl.h>
58 #include <inet/ip6.h>
59 #include <inet/dccp.h>
60 #include <inet/dccp_impl.h>
61 #include <inet/dccp_stack.h>
62 #include <inet/kstatcom.h>
63 #include <inet/snmpcom.h>
64
65 #include <sys/cmn_err.h>
66
67 int dccp_squeue_flag;
68
69 /* Setable in /etc/system */
70 uint_t dccp_bind_fanout_size = DCCP_BIND_FANOUT_SIZE;
71
72 static void dccp_notify(void *, ip_xmit_attr_t *, ixa_notify_type_t,
73 ixa_notify_arg_t);
74
75 /* Functions to register netstack */
76 static void *dccp_stack_init(netstackid_t, netstack_t *);
77 static void dccp_stack_fini(netstackid_t, void *);
78
79 /* Stream device open functions */
80 static int dccp_openv4(queue_t *, dev_t *, int, int, cred_t *);
81 static int dccp_openv6(queue_t *, dev_t *, int, int, cred_t *);
82 static int dccp_open(queue_t *, dev_t *, int, int, cred_t *,
83 boolean_t);
84
85 /* Write service routine */
86 static void dccp_wsrv(queue_t *);
87
88 /* Connection related functions */
89 static int dccp_connect_ipv4(dccp_t *, ipaddr_t *, in_port_t, uint_t);
90 static int dccp_connect_ipv6(dccp_t *, in6_addr_t *, in_port_t, uint32_t,
91 uint_t, uint32_t);
92
93 /* Initialise ISS */
94 static void dccp_iss_init(dccp_t *);
95 static void dccp_reinit(dccp_t *);
96
97 struct module_info dccp_rinfo = {
98 DCCP_MOD_ID, DCCP_MOD_NAME, 0, INFPSZ, DCCP_RECV_HIWATER,
99 DCCP_RECV_LOWATER
100 };
101
102 static struct module_info dccp_winfo = {
103 DCCP_MOD_ID, DCCP_MOD_NAME, 0, INFPSZ, 127, 16
104 };
105
106 /*
107 * Queue information structure with DCCP entry points.
108 */
109 struct qinit dccp_rinitv4 = {
110 NULL, (pfi_t)dccp_rsrv, dccp_openv4, dccp_tpi_close, NULL, &dccp_rinfo
111 };
112
113 struct qinit dccp_rinitv6 = {
114 NULL, (pfi_t)dccp_rsrv, dccp_openv6, dccp_tpi_close, NULL, &dccp_rinfo
115 };
116
117 struct qinit dccp_winit = {
118 (pfi_t)dccp_wput, (pfi_t)dccp_wsrv, NULL, NULL, NULL, &dccp_winfo
119 };
120
121 /* Initial entry point for TCP in socket mode */
122 struct qinit dccp_sock_winit = {
123 (pfi_t)dccp_wput_sock, (pfi_t)dccp_wsrv, NULL, NULL, NULL, &dccp_winfo
124 };
125
126 struct qinit dccp_fallback_sock_winit = {
127 (pfi_t)dccp_wput_fallback, NULL, NULL, NULL, NULL, &dccp_winfo
128 };
129 /*
130 * DCCP as acceptor STREAM.
131 */
132 struct qinit dccp_acceptor_rinit = {
133 NULL, (pfi_t)dccp_rsrv, NULL, dccp_tpi_close_accept, NULL, &dccp_winfo
134 };
135
136 struct qinit dccp_acceptor_winit = {
137 (pfi_t)dccp_tpi_accept, NULL, NULL, NULL, NULL, &dccp_winfo
138 };
139
140 /* AF_INET /dev/dccp */
141 struct streamtab dccpinfov4 = {
142 &dccp_rinitv4, &dccp_winit
143 };
144
145 /* AF_INET6 /dev/dccp6 */
146 struct streamtab dccpinfov6 = {
147 &dccp_rinitv6, &dccp_winit
148 };
149
150 /* Template for response to info request */
151 struct T_info_ack dccp_g_t_info_ack = {
152 T_INFO_ACK, /* PRIM_type */
153 0, /* TSDU_size */
154 T_INFINITE, /* ETSDU_size */
155 T_INVALID, /* CDATA_size */
156 T_INVALID, /* DDATA_size */
157 sizeof (sin_t), /* ADDR_size */
158 0, /* OPT_size - not initialized here */
159 TIDUSZ, /* TIDU_size */
160 T_COTS_ORD, /* SERV_type */
161 DCCPS_CLOSED, /* CURRENT_state */
162 (XPG4_1|EXPINLINE) /* PROVIDER_flag */
163 };
164
165 struct T_info_ack dccp_g_t_info_ack_v6 = {
166 T_INFO_ACK, /* PRIM_type */
167 0, /* TSDU_size */
168 T_INFINITE, /* ETSDU_size */
169 T_INVALID, /* CDATA_size */
170 T_INVALID, /* DDATA_size */
171 sizeof (sin6_t), /* ADDR_size */
172 0, /* OPT_size - not initialized here */
173 TIDUSZ, /* TIDU_size */
174 T_COTS_ORD, /* SERV_type */
175 DCCPS_CLOSED, /* CURRENT_state */
176 (XPG4_1|EXPINLINE) /* PROVIDER_flag */
177 };
178
179 /*
180 * DCCP Tunables.
181 */
182 extern mod_prop_info_t dccp_propinfo_tbl[];
183 extern int dccp_propinfo_count;
184
185 /*
186 * Register DCCP in ip netstack.
187 */
188 void
189 dccp_ddi_g_init(void)
190 {
191 /* Global timer cache */
192 dccp_timercache = kmem_cache_create("dccp_timercache",
193 sizeof (dccp_timer_t) + sizeof (mblk_t), 0,
194 NULL, NULL, NULL, NULL, NULL, 0);
195
196 netstack_register(NS_DCCP, dccp_stack_init, NULL, dccp_stack_fini);
197 }
198
199 /*
200 * Unregister DCCP from ip netstack.
201 */
202 void
203 dccp_ddi_g_destroy(void)
204 {
205 /* Global timer cache */
206 kmem_cache_destroy(dccp_timercache);
207
208 netstack_unregister(NS_DCCP);
209 }
210
211 #define INET_NAME "ip"
212
213 /*
214 * Initialize this DCCP stack instance.
215 */
216 static void *
217 dccp_stack_init(netstackid_t stackid, netstack_t *ns)
218 {
219 dccp_stack_t *dccps;
220 major_t major;
221 size_t arrsz;
222 int error;
223 int i;
224
225 dccps = kmem_zalloc(sizeof (*dccps), KM_SLEEP);
226 if (dccps == NULL) {
227 return (NULL);
228 }
229 dccps->dccps_netstack = ns;
230
231 /* Ports */
232 mutex_init(&dccps->dccps_epriv_port_lock, NULL, MUTEX_DEFAULT, NULL);
233 dccps->dccps_num_epriv_ports = DCCP_NUM_EPRIV_PORTS;
234 dccps->dccps_epriv_ports[0] = ULP_DEF_EPRIV_PORT1;
235 dccps->dccps_epriv_ports[1] = ULP_DEF_EPRIV_PORT2;
236 dccps->dccps_min_anonpriv_port = 512;
237
238 dccps->dccps_bind_fanout_size = dccp_bind_fanout_size;
239
240 /* Bind fanout */
241 dccps->dccps_bind_fanout = kmem_zalloc(dccps->dccps_bind_fanout_size *
242 sizeof (dccp_df_t), KM_SLEEP);
243 for (i = 0; i < dccps->dccps_bind_fanout_size; i++) {
244 mutex_init(&dccps->dccps_bind_fanout[i].df_lock, NULL,
245 MUTEX_DEFAULT, NULL);
246 }
247
248 /* Tunable properties */
249 arrsz = dccp_propinfo_count * sizeof (mod_prop_info_t);
250 dccps->dccps_propinfo_tbl = kmem_alloc(arrsz, KM_SLEEP);
251 if (dccps->dccps_propinfo_tbl == NULL) {
252 kmem_free(dccps, sizeof (*dccps));
253 return (NULL);
254 }
255 bcopy(dccp_propinfo_tbl, dccps->dccps_propinfo_tbl, arrsz);
256
257 /* Allocate per netstack cpu stats */
258 mutex_enter(&cpu_lock);
259 dccps->dccps_sc_cnt = MAX(ncpus, boot_ncpus);
260 mutex_exit(&cpu_lock);
261
262 dccps->dccps_sc = kmem_zalloc(max_ncpus * sizeof (dccp_stats_cpu_t *),
263 KM_SLEEP);
264 for (i = 0; i < dccps->dccps_sc_cnt; i++) {
265 dccps->dccps_sc[i] = kmem_zalloc(sizeof (dccp_stats_cpu_t),
266 KM_SLEEP);
267 }
268
269 /* Kernel statistics */
270 //dccps->dccps_kstat = dccp_kstat2_init(stackid);
271 //dccps->dccps_mibkp = dccp_kstat_init(stackid);
272
273 /* Driver major number */
274 major = mod_name_to_major(INET_NAME);
275 error = ldi_ident_from_major(major, &dccps->dccps_ldi_ident);
276 ASSERT(error == 0);
277
278 return (dccps);
279 }
280
281 /*
282 * Destroy this DCCP netstack instance.
283 */
284 static void
285 dccp_stack_fini(netstackid_t stackid, void *arg)
286 {
287 dccp_stack_t *dccps = (dccp_stack_t *)arg;
288 int i;
289
290 /* Free cpu stats */
291 for (i = 0; i < dccps->dccps_sc_cnt; i++) {
292 kmem_free(dccps->dccps_sc[i], sizeof (dccp_stats_cpu_t));
293 }
294 kmem_free(dccps->dccps_sc, max_ncpus * sizeof (dccp_stats_cpu_t *));
295
296 /* Free tunable properties */
297 kmem_free(dccps->dccps_propinfo_tbl,
298 dccp_propinfo_count * sizeof (mod_prop_info_t));
299 dccps->dccps_propinfo_tbl = NULL;
300
301 /* Free bind fanout */
302 for (i = 0; i < dccps->dccps_bind_fanout_size; i++) {
303 ASSERT(dccps->dccps_bind_fanout[i].df_dccp == NULL);
304 mutex_destroy(&dccps->dccps_bind_fanout[i].df_lock);
305 }
306 kmem_free(dccps->dccps_bind_fanout, dccps->dccps_bind_fanout_size *
307 sizeof (dccp_df_t));
308 dccps->dccps_bind_fanout = NULL;
309
310 /* Kernel statistics */
311 dccp_kstat_fini(stackid, dccps->dccps_mibkp);
312 dccps->dccps_mibkp = NULL;
313 dccp_kstat2_fini(stackid, dccps->dccps_kstat);
314 dccps->dccps_kstat = NULL;
315
316 ldi_ident_release(dccps->dccps_ldi_ident);
317
318 kmem_free(dccps, sizeof (*dccps));
319 }
320
321 /* /dev/dccp */
322 static int
323 dccp_openv4(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
324 {
325 cmn_err(CE_NOTE, "dccp.c: dccp_openv4\n");
326
327 return (dccp_open(q, devp, flag, sflag, credp, B_FALSE));
328 }
329
330 /* /dev/dccp6 */
331 static int
332 dccp_openv6(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
333 {
334 cmn_err(CE_NOTE, "dccp.c: dccp_openv6\n");
335
336 return (dccp_open(q, devp, flag, sflag, credp, B_TRUE));
337 }
338
339 /*
340 * Common open function for v4 and v6 devices.
341 */
342 static int
343 dccp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp,
344 boolean_t isv6)
345 {
346 conn_t *connp;
347 dccp_t *dccp;
348 vmem_t *minor_arena;
349 dev_t conn_dev;
350 boolean_t issocket;
351 int error;
352
353 cmn_err(CE_NOTE, "dccp.c: dccp_open");
354
355 /* If the stream is already open, return immediately */
356 if (q->q_ptr != NULL) {
357 return (0);
358 }
359
360 if (sflag == MODOPEN) {
361 return (EINVAL);
362 }
363
364 if ((ip_minor_arena_la != NULL) && (flag & SO_SOCKSTR) &&
365 ((conn_dev = inet_minor_alloc(ip_minor_arena_la)) != 0)) {
366 minor_arena = ip_minor_arena_la;
367 } else {
368 /*
369 * Either minor numbers in the large arena were exhausted
370 * or a non socket application is doing the open.
371 * Try to allocate from the small arena.
372 */
373 if ((conn_dev = inet_minor_alloc(ip_minor_arena_sa)) == 0) {
374 return (EBUSY);
375 }
376 minor_arena = ip_minor_arena_sa;
377 }
378
379 ASSERT(minor_arena != NULL);
380
381 *devp = makedevice(getmajor(*devp), (minor_t)conn_dev);
382
383 if (flag & SO_FALLBACK) {
384 /*
385 * Non streams socket needs a stream to fallback to.
386 */
387 RD(q)->q_ptr = (void *)conn_dev;
388 WR(q)->q_qinfo = &dccp_fallback_sock_winit;
389 WR(q)->q_ptr = (void *)minor_arena;
390 qprocson(q);
391 return (0);
392 } else if (flag & SO_ACCEPTOR) {
393 q->q_qinfo = &dccp_acceptor_rinit;
394 /*
395 * The conn_dev and minor_arena will be subsequently used by
396 * dccp_tli_accept() and dccp_tpi_close_accept() to figure out
397 * the minor device number for this connection from the q_ptr.
398 */
399 RD(q)->q_ptr = (void *)conn_dev;
400 WR(q)->q_qinfo = &dccp_acceptor_winit;
401 WR(q)->q_ptr = (void *)minor_arena;
402 qprocson(q);
403 return (0);
404 }
405
406 issocket = flag & SO_SOCKSTR;
407 connp = dccp_create_common(credp, isv6, issocket, &error);
408 if (connp == NULL) {
409 inet_minor_free(minor_arena, conn_dev);
410 q->q_ptr = WR(q)->q_ptr = NULL;
411 return (error);
412 }
413
414 connp->conn_rq = q;
415 connp->conn_wq = WR(q);
416 q->q_ptr = WR(q)->q_ptr = connp;
417
418 connp->conn_dev = conn_dev;
419 connp->conn_minor_arena = minor_arena;
420
421 ASSERT(q->q_qinfo == &dccp_rinitv4 || q->q_qinfo == &dccp_rinitv6);
422 ASSERT(WR(q)->q_qinfo == &dccp_winit);
423
424 dccp = connp->conn_dccp;
425
426 if (issocket) {
427 WR(q)->q_qinfo = &dccp_sock_winit;
428 } else {
429 #ifdef _ILP32
430 dccp->dccp_acceptor_id = (t_uscalar_t)RD(q);
431 #else
432 dccp->dccp_acceptor_id = conn_dev;
433 #endif /* _ILP32 */
434 }
435
436 /*
437 * Put the ref for DCCP. Ref for IP was already put
438 * by ipcl_conn_create. Also Make the conn_t globally
439 * visible to walkers.
440 */
441 mutex_enter(&connp->conn_lock);
442 CONN_INC_REF_LOCKED(connp);
443 ASSERT(connp->conn_ref == 2);
444 connp->conn_state_flags &= ~CONN_INCIPIENT;
445 mutex_exit(&connp->conn_lock);
446
447 qprocson(q);
448
449 return (0);
450 }
451
452 /*
453 * IXA notify
454 */
455 static void
456 dccp_notify(void *arg, ip_xmit_attr_t *ixa, ixa_notify_type_t ntype,
457 ixa_notify_arg_t narg)
458 {
459 cmn_err(CE_NOTE, "dccp.c: dccp_notify");
460 }
461
462 /*
463 * Build the template headers.
464 */
465 int
466 dccp_build_hdrs(dccp_t *dccp)
467 {
468 dccp_stack_t *dccps = dccp->dccp_dccps;
469 conn_t *connp = dccp->dccp_connp;
470 dccpha_t *dccpha;
471 uint32_t cksum;
472 char buf[DCCP_MAX_HDR_LENGTH];
473 uint_t buflen;
474 uint_t ulplen = 12;
475 uint_t extralen = 0;
476 int error;
477
478 cmn_err(CE_NOTE, "dccp.c: dccp_build_hdrs");
479
480 buflen = connp->conn_ht_ulp_len;
481 if (buflen != 0) {
482 cmn_err(CE_NOTE, "buflen != 0");
483 bcopy(connp->conn_ht_ulp, buf, buflen);
484 extralen -= buflen - ulplen;
485 ulplen = buflen;
486 }
487
488 mutex_enter(&connp->conn_lock);
489 error = conn_build_hdr_template(connp, ulplen, extralen,
490 &connp->conn_laddr_v6, &connp->conn_faddr_v6, connp->conn_flowinfo);
491 mutex_exit(&connp->conn_lock);
492 if (error != 0) {
493 cmn_err(CE_NOTE, "conn_build_hdr_template failed");
494 return (error);
495 }
496
497 dccpha = (dccpha_t *)connp->conn_ht_ulp;
498 dccp->dccp_dccpha = dccpha;
499
500 if (buflen != 0) {
501 bcopy(buf, connp->conn_ht_ulp, buflen);
502 } else {
503 dccpha->dha_sum = 0;
504 dccpha->dha_lport = connp->conn_lport;
505 dccpha->dha_fport = connp->conn_fport;
506 }
507
508 cksum = sizeof (dccpha_t) + connp->conn_sum;
509 cksum = (cksum >> 16) + (cksum & 0xFFFF);
510 dccpha->dha_sum = htons(cksum);
511 dccpha->dha_offset = 7;
512 dccpha->dha_x = 1;
513
514 if (connp->conn_ipversion == IPV4_VERSION) {
515 dccp->dccp_ipha = (ipha_t *)connp->conn_ht_iphc;
516 } else {
517 dccp->dccp_ip6h = (ip6_t *)connp->conn_ht_iphc;
518 }
519
520 /* XXX */
521
522 return (0);
523 }
524
525 /*
526 * DCCP write service routine.
527 */
528 static void
529 dccp_wsrv(queue_t *q)
530 {
531 dccp_stack_t *dccps = Q_TO_DCCP(q)->dccp_dccps;
532
533 DCCP_STAT(dccps, dccp_wsrv_called);
534 }
535
536 /*
537 * Common create function for streams and sockets.
538 */
539 conn_t *
540 dccp_create_common(cred_t *credp, boolean_t isv6, boolean_t issocket,
541 int *errorp)
542 {
543 conn_t *connp;
544 dccp_t *dccp;
545 dccp_stack_t *dccps;
546 netstack_t *ns;
547 squeue_t *sqp;
548 zoneid_t zoneid;
549 int error;
550
551 cmn_err(CE_NOTE, "dccp.c: dccp_create_common\n");
552
553 ASSERT(errorp != NULL);
554
555 error = secpolicy_basic_net_access(credp);
556 if (error != 0) {
557 *errorp = error;
558 return (NULL);
559 }
560
561 /*
562 * Find the right netstack.
563 */
564 ns = netstack_find_by_cred(credp);
565 ASSERT(ns != NULL);
566 dccps = ns->netstack_dccp;
567 ASSERT(dccps != NULL);
568
569 /*
570 * For exclusive stacks we set the zoneid to zero
571 * to make TCP operate as if in the global zone.
572 */
573 if (ns->netstack_stackid != GLOBAL_NETSTACKID) {
574 zoneid = GLOBAL_ZONEID;
575 } else {
576 zoneid = crgetzoneid(credp);
577 }
578
579 sqp = IP_SQUEUE_GET((uint_t)gethrtime());
580 connp = (conn_t *)dccp_get_conn(sqp, dccps);
581 netstack_rele(dccps->dccps_netstack);
582 if (connp == NULL) {
583 *errorp = ENOSR;
584 return (NULL);
585 }
586 ASSERT(connp->conn_ixa->ixa_protocol == connp->conn_proto);
587
588 connp->conn_sqp = sqp;
589 connp->conn_initial_sqp = connp->conn_sqp;
590 connp->conn_ixa->ixa_sqp = connp->conn_sqp;
591 dccp = connp->conn_dccp;
592
593 /* Setting flags for ip output */
594 connp->conn_ixa->ixa_flags |= IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE |
595 IXAF_VERIFY_PMTU | IXAF_VERIFY_LSO;
596
597 ASSERT(connp->conn_proto == IPPROTO_DCCP);
598 ASSERT(connp->conn_dccp == dccp);
599 ASSERT(dccp->dccp_connp == connp);
600
601 if (isv6) {
602 connp->conn_ixa->ixa_src_preferences = IPV6_PREFER_SRC_DEFAULT;
603 connp->conn_ipversion = IPV6_VERSION;
604 connp->conn_family = AF_INET6;
605 /* XXX mms, ttl */
606 } else {
607 connp->conn_ipversion = IPV4_VERSION;
608 connp->conn_family = AF_INET;
609 /* XXX mms, ttl */
610 }
611 connp->conn_xmit_ipp.ipp_unicast_hops = connp->conn_default_ttl;
612
613 crhold(credp);
614 connp->conn_cred = credp;
615 connp->conn_cpid = curproc->p_pid;
616 connp->conn_open_time = ddi_get_lbolt64();
617
618 ASSERT(!(connp->conn_ixa->ixa_free_flags & IXA_FREE_CRED));
619 connp->conn_ixa->ixa_cred = credp;
620 connp->conn_ixa->ixa_cpid = connp->conn_cpid;
621
622 connp->conn_zoneid = zoneid;
623 connp->conn_zone_is_global = (crgetzoneid(credp) == GLOBAL_ZONEID);
624 connp->conn_ixa->ixa_zoneid = zoneid;
625 connp->conn_mlp_type = mlptSingle;
626
627 dccp->dccp_dccps = dccps;
628 dccp->dccp_state = DCCPS_CLOSED;
629
630 ASSERT(connp->conn_netstack == dccps->dccps_netstack);
631 ASSERT(dccp->dccp_dccps == dccps);
632
633 /*
634 * If the caller has the process-wide flag set, then default to MAC
635 * exempt mode. This allows read-down to unlabeled hosts.
636 */
637 if (getpflags(NET_MAC_AWARE, credp) != 0) {
638 connp->conn_mac_mode = CONN_MAC_AWARE;
639 }
640
641 if (issocket) {
642 dccp->dccp_issocket = 1;
643 }
644
645 /* XXX rcvbuf, sndbuf etc */
646
647 connp->conn_so_type = SOCK_STREAM;
648
649 SOCK_CONNID_INIT(dccp->dccp_connid);
650 dccp_init_values(dccp, NULL);
651
652 return (connp);
653 }
654
655 /*
656 * Common close function for streams and sockets.
657 */
658 void
659 dccp_close_common(conn_t *connp, int flags)
660 {
661 dccp_t *dccp = connp->conn_dccp;
662 mblk_t *mp;
663 boolean_t conn_ioctl_cleanup_reqd = B_FALSE;
664
665 cmn_err(CE_NOTE, "dccp.c: dccp_close_common");
666
667 ASSERT(connp->conn_ref >= 2);
668
669 /*
670 * Mark the conn as closing. ipsq_pending_mp_add will not
671 * add any mp to the pending mp list, after this conn has
672 * started closing.
673 */
674 mutex_enter(&connp->conn_lock);
675 connp->conn_state_flags |= CONN_CLOSING;
676
677 if (connp->conn_oper_pending_ill != NULL) {
678 conn_ioctl_cleanup_reqd = B_TRUE;
679 }
680
681 CONN_INC_REF_LOCKED(connp);
682 mutex_exit(&connp->conn_lock);
683
684 ASSERT(connp->conn_ref >= 3);
685
686 /*
687 * Cleanup any queued ioctls here. This must be done before the wq/rq
688 * are re-written by dccp_close_output().
689 */
690 if (conn_ioctl_cleanup_reqd) {
691 conn_ioctl_cleanup(connp);
692 }
693
694 mutex_enter(&connp->conn_lock);
695 while (connp->conn_ioctlref > 0) {
696 cv_wait(&connp->conn_cv, &connp->conn_lock);
697 }
698 ASSERT(connp->conn_ioctlref == 0);
699 ASSERT(connp->conn_oper_pending_ill == NULL);
700 mutex_exit(&connp->conn_lock);
701
702 /* generate close */
703 /*
704 SQUEUE_ENTER_ONE(connp->conn_sqp, mp, dccp_close_output, connp,
705 NULL, dccp_squeue_flag, SQTAG_IP_DCCP_CLOSE);
706
707 */
708
709 nowait:
710 connp->conn_cpid = NOPID;
711 }
712
713 /*
714 * Common bind function.
715 */
716 int
717 dccp_do_bind(conn_t *connp, struct sockaddr *sa, socklen_t len, cred_t *cr,
718 boolean_t bind_to_req_port_only)
719 {
720 dccp_t *dccp = connp->conn_dccp;
721 int error;
722
723 cmn_err(CE_NOTE, "dccp.c: dccp_do_bind");
724
725 if (dccp->dccp_state >= DCCPS_BOUND) {
726 if (connp->conn_debug) {
727 (void) strlog(DCCP_MOD_ID, 0, 1, SL_ERROR|SL_TRACE,
728 "dccp_bind: bad state, %d", dccp->dccp_state);
729 }
730 return (-TOUTSTATE);
731 }
732
733 error = dccp_bind_check(connp, sa, len, cr, bind_to_req_port_only);
734 if (error != 0) {
735 return (error);
736 }
737
738 ASSERT(dccp->dccp_state == DCCPS_LISTEN);
739 /* XXX dccp_conn_req_max = 0 */
740
741 return (0);
742 }
743
744 /*
745 * Common unbind function.
746 */
747 int
748 dccp_do_unbind(conn_t *connp)
749 {
750 dccp_t *dccp = connp->conn_dccp;
751 int32_t oldstate;
752
753 cmn_err(CE_NOTE, "dccp.c: dccp_do_unbind");
754
755 switch (dccp->dccp_state) {
756 case DCCPS_OPEN:
757 case DCCPS_LISTEN:
758 break;
759 default:
760 return (-TOUTSTATE);
761 }
762
763 connp->conn_laddr_v6 = ipv6_all_zeros;
764 connp->conn_saddr_v6 = ipv6_all_zeros;
765
766 dccp_bind_hash_remove(dccp);
767
768 oldstate = dccp->dccp_state;
769 dccp->dccp_state = DCCPS_CLOSED;
770 DTRACE_DCCP6(state__change, void, NULL, ip_xmit_attr_t *,
771 connp->conn_ixa, void, NULL, dccp_t *, dccp, void, NULL,
772 int32_t, oldstate);
773
774 ip_unbind(connp);
775 bzero(&connp->conn_ports, sizeof (connp->conn_ports));
776
777 return (0);
778 }
779
780 /*
781 * Common listen function.
782 */
783 int
784 dccp_do_listen(conn_t *connp, struct sockaddr *sa, socklen_t len,
785 int backlog, cred_t *cr, boolean_t bind_to_req_port_only)
786 {
787 dccp_t *dccp = connp->conn_dccp;
788 dccp_stack_t *dccps = dccp->dccp_dccps;
789 int32_t oldstate;
790 int error;
791
792 cmn_err(CE_NOTE, "dccp.c: dccp_do_listen");
793
794 /* All Solaris components should pass a cred for this operation */
795 ASSERT(cr != NULL);
796
797 if (dccp->dccp_state >= DCCPS_BOUND) {
798
799 if ((dccp->dccp_state == DCCPS_BOUND ||
800 dccp->dccp_state == DCCPS_LISTEN) && backlog > 0) {
801 goto do_listen;
802 }
803 cmn_err(CE_NOTE, "DCCPS_BOUND, bad state");
804
805 if (connp->conn_debug) {
806 (void) strlog(DCCP_MOD_ID, 0, 1, SL_ERROR|SL_TRACE,
807 "dccp_listen: bad state, %d", dccp->dccp_state);
808 }
809 return (-TOUTSTATE);
810 } else {
811 if (sa == NULL) {
812 sin6_t addr;
813 sin6_t *sin6;
814 sin_t *sin;
815
816 ASSERT(IPCL_IS_NONSTR(connp));
817
818 if (connp->conn_family == AF_INET) {
819 len = sizeof (sin_t);
820 sin = (sin_t *)&addr;
821 *sin = sin_null;
822 sin->sin_family = AF_INET;
823 } else {
824 ASSERT(connp->conn_family == AF_INET6);
825
826 len = sizeof (sin6_t);
827 sin6 = (sin6_t *)&addr;
828 *sin6 = sin6_null;
829 sin6->sin6_family = AF_INET6;
830 }
831
832 sa = (struct sockaddr *)&addr;
833 }
834
835 error = dccp_bind_check(connp, sa, len, cr,
836 bind_to_req_port_only);
837 if (error != 0) {
838 cmn_err(CE_NOTE, "dccp_bind_check failed");
839 return (error);
840 }
841 /* Fall through and do the fanout insertion */
842 }
843
844 do_listen:
845 ASSERT(dccp->dccp_state == DCCPS_BOUND ||
846 dccp->dccp_state == DCCPS_LISTEN);
847
848 dccp->dccp_conn_req_max = backlog;
849 if (dccp->dccp_conn_req_max) {
850 if (dccp->dccp_state != DCCPS_LISTEN) {
851 dccp->dccp_state = DCCPS_LISTEN;
852 DTRACE_DCCP6(state__change, void, NULL,
853 ip_xmit_attr_t *, connp->conn_ixa, void, NULL,
854 dccp_t *, dccp, void, NULL, int32_t, DCCPS_BOUND);
855
856 dccp->dccp_second_ctimer_threshold =
857 dccps->dccps_ip_abort_linterval;
858 }
859 }
860
861 /* XXX */
862
863 connp->conn_recv = dccp_input_listener_unbound;
864
865 /* Insert into the classifier table */
866 error = ip_laddr_fanout_insert(connp);
867 if (error != 0) {
868 /* Error - undo the bind */
869 oldstate = dccp->dccp_state;
870 dccp->dccp_state = DCCPS_CLOSED;
871 DTRACE_DCCP6(state__change, void, NULL, ip_xmit_attr_t *,
872 connp->conn_ixa, void, NULL, dccp_t *, dccp, void, NULL,
873 int32_t, oldstate);
874
875 connp->conn_bound_addr_v6 = ipv6_all_zeros;
876 connp->conn_laddr_v6 = ipv6_all_zeros;
877 connp->conn_saddr_v6 = ipv6_all_zeros;
878 connp->conn_ports = 0;
879
880 if (connp->conn_anon_port) {
881 zone_t *zone;
882
883 zone = crgetzone(cr);
884 connp->conn_anon_port = B_FALSE;
885 (void) tsol_mlp_anon(zone, connp->conn_mlp_type,
886 connp->conn_proto, connp->conn_lport, B_FALSE);
887 }
888 connp->conn_mlp_type = mlptSingle;
889
890 dccp_bind_hash_remove(dccp);
891
892 return (error);
893 } else {
894 /* XXX connection limits */
895 }
896
897 return (error);
898 }
899
900 /*
901 * Common connect function.
902 */
903 int
904 dccp_do_connect(conn_t *connp, const struct sockaddr *sa, socklen_t len,
905 cred_t *cr, pid_t pid)
906 {
907 dccp_t *dccp = connp->conn_dccp;
908 dccp_stack_t *dccps = dccp->dccp_dccps;
909 ip_xmit_attr_t *ixa = connp->conn_ixa;
910 mblk_t *req_mp;
911 sin_t *sin = (sin_t *)sa;
912 sin6_t *sin6 = (sin6_t *)sa;
913 ipaddr_t *dstaddrp;
914 in_port_t dstport;
915 uint_t srcid;
916 int32_t oldstate;
917 int error;
918
919 cmn_err(CE_NOTE, "dccp.c: dccp_do_connect");
920
921 oldstate = dccp->dccp_state;
922
923 switch (len) {
924 case sizeof (sin_t):
925 sin = (sin_t *)sa;
926 if (sin->sin_port == 0) {
927 return (-TBADADDR);
928 }
929 if (connp->conn_ipv6_v6only) {
930 return (EAFNOSUPPORT);
931 }
932 break;
933
934 case sizeof (sin6_t):
935 sin6 = (sin6_t *)sa;
936 if (sin6->sin6_port == 0) {
937 return (-TBADADDR);
938 }
939 break;
940
941 default:
942 return (EINVAL);
943 }
944
945 if (connp->conn_family == AF_INET6 &&
946 connp->conn_ipversion == IPV6_VERSION &&
947 IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
948 if (connp->conn_ipv6_v6only) {
949 return (EADDRNOTAVAIL);
950 }
951
952 connp->conn_ipversion = IPV4_VERSION;
953 }
954
955 switch (dccp->dccp_state) {
956 case DCCPS_LISTEN:
957 /*
958 * Listening sockets are not allowed to issue connect().
959 */
960 if (IPCL_IS_NONSTR(connp)) {
961 return (EOPNOTSUPP);
962 }
963
964 case DCCPS_CLOSED:
965 /*
966 * We support quick connect.
967 */
968 /* FALLTHRU */
969 case DCCPS_OPEN:
970 break;
971
972 default:
973 return (-TOUTSTATE);
974 }
975
976 /*
977 * We update our cred/cpid based on the caller of connect.
978 */
979 if (connp->conn_cred != cr) {
980 crhold(cr);
981 crfree(connp->conn_cred);
982 connp->conn_cred = cr;
983 }
984 connp->conn_cpid = pid;
985
986 /* Cache things in the ixa without any refhold */
987 ASSERT(!(ixa->ixa_free_flags & IXA_FREE_CRED));
988 ixa->ixa_cred = cr;
989 ixa->ixa_cpid = pid;
990
991 if (is_system_labeled()) {
992 ip_xmit_attr_restore_tsl(ixa, ixa->ixa_cred);
993 }
994
995 if (connp->conn_family == AF_INET6) {
996 if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
997 error = dccp_connect_ipv6(dccp, &sin6->sin6_addr,
998 sin6->sin6_port, sin6->sin6_flowinfo,
999 sin6->__sin6_src_id, sin6->sin6_scope_id);
1000 } else {
1001 /*
1002 * Destination adress is mapped IPv6 address.
1003 * Source bound address should be unspecified or
1004 * IPv6 mapped address as well.
1005 */
1006 if (!IN6_IS_ADDR_UNSPECIFIED(
1007 &connp->conn_bound_addr_v6) &&
1008 !IN6_IS_ADDR_V4MAPPED(&connp->conn_bound_addr_v6)) {
1009 return (EADDRNOTAVAIL);
1010 }
1011
1012 dstaddrp = &V4_PART_OF_V6((sin6->sin6_addr));
1013 dstport = sin6->sin6_port;
1014 srcid = sin6->__sin6_src_id;
1015 error = dccp_connect_ipv4(dccp, dstaddrp, dstport,
1016 srcid);
1017 }
1018 } else {
1019 dstaddrp = &sin->sin_addr.s_addr;
1020 dstport = sin->sin_port;
1021 srcid = 0;
1022 error = dccp_connect_ipv4(dccp, dstaddrp, dstport, srcid);
1023 }
1024
1025 if (error != 0) {
1026 cmn_err(CE_NOTE, "dccp_connect_ip failed");
1027 goto connect_failed;
1028 }
1029
1030 /* XXX cluster */
1031
1032 /* Connect succeeded */
1033 DCCPS_BUMP_MIB(dccps, dccpActiveOpens);
1034 dccp->dccp_active_open = 1;
1035
1036 DTRACE_DCCP6(state__change, void, NULL, ip_xmit_attr_t *,
1037 connp->conn_ixa, void, NULL, dccp_t *, dccp, void, NULL,
1038 int32_t, DCCPS_BOUND);
1039
1040 DCCP_TIMER_RESTART(dccp, 100);
1041 req_mp = dccp_generate_request(connp);
1042 if (req_mp != NULL) {
1043 /*
1044 * We must bump the generation before sending the request
1045 * to ensure that we use the right generation in case
1046 * this thread issues a "connected" up call.
1047 */
1048 SOCK_CONNID_BUMP(dccp->dccp_connid);
1049
1050 DTRACE_DCCP5(connect__request, mblk_t *, NULL,
1051 ip_xmit_attr_t *, connp->conn_ixa,
1052 void_ip_t *, req_mp->b_rptr, dccp_t *, dccp,
1053 dccpha_t *,
1054 &req_mp->b_rptr[connp->conn_ixa->ixa_ip_hdr_length]);
1055
1056 dccp_send_data(dccp, req_mp);
1057 }
1058
1059 return (0);
1060
1061 connect_failed:
1062 cmn_err(CE_NOTE, "dccp_do_connect failed");
1063
1064 connp->conn_faddr_v6 = ipv6_all_zeros;
1065 connp->conn_fport = 0;
1066 dccp->dccp_state = oldstate;
1067
1068 /* XXX */
1069 return (error);
1070 }
1071
1072 /*
1073 * Init values of a connection.
1074 */
1075 void
1076 dccp_init_values(dccp_t *dccp, dccp_t *parent)
1077 {
1078 conn_t *connp = dccp->dccp_connp;
1079 dccp_stack_t *dccps = dccp->dccp_dccps;
1080
1081 ASSERT((connp->conn_family == AF_INET &&
1082 connp->conn_ipversion == IPV4_VERSION) ||
1083 (connp->conn_family == AF_INET6 &&
1084 (connp->conn_ipversion == IPV4_VERSION ||
1085 connp->conn_ipversion == IPV6_VERSION)));
1086
1087 if (parent == NULL) {
1088
1089 dccp->dccp_first_ctimer_threshold =
1090 dccps->dccps_ip_notify_cinterval;
1091 dccp->dccp_second_ctimer_threshold =
1092 dccps->dccps_ip_abort_cinterval;
1093 dccp->dccp_first_timer_threshold =
1094 dccps->dccps_ip_notify_interval;
1095 dccp->dccp_second_timer_threshold =
1096 dccps->dccps_ip_abort_interval;
1097
1098 dccp->dccp_ka_interval =
1099 dccps->dccps_keepalive_interval;
1100 dccp->dccp_ka_abort_thres =
1101 dccps->dccps_keepalive_abort_interval;
1102 dccp->dccp_ka_cnt = 0;
1103 dccp->dccp_ka_rinterval = 0;
1104 } else {
1105 /* Inherit various DCCP parameters from the parent */
1106 dccp->dccp_first_ctimer_threshold =
1107 parent->dccp_first_ctimer_threshold;
1108 dccp->dccp_second_ctimer_threshold =
1109 parent->dccp_second_ctimer_threshold;
1110 dccp->dccp_first_timer_threshold =
1111 parent->dccp_first_timer_threshold;
1112 dccp->dccp_second_timer_threshold =
1113 parent->dccp_second_timer_threshold;
1114
1115 dccp->dccp_ka_interval = parent->dccp_ka_interval;
1116 dccp->dccp_ka_abort_thres = parent->dccp_ka_abort_thres;
1117 dccp->dccp_ka_cnt = parent->dccp_ka_cnt;
1118 dccp->dccp_ka_rinterval = parent->dccp_ka_rinterval;
1119 }
1120
1121 dccp->dccp_last_recv_time = ddi_get_lbolt();
1122 dccp->dccp_sequence_window = 100;
1123
1124 connp->conn_mlp_type = mlptSingle;
1125
1126 if (!connp->conn_debug) {
1127 connp->conn_debug = dccps->dccps_dbg;
1128 }
1129 }
1130
1131 /*
1132 * Free dccp structure.
1133 */
1134 void
1135 dccp_free(dccp_t *dccp)
1136 {
1137 conn_t *connp = dccp->dccp_connp;
1138
1139 cmn_err(CE_NOTE, "dccp.c: dccp_free");
1140
1141 connp->conn_rq = NULL;
1142 connp->conn_wq = NULL;
1143
1144 if (connp->conn_upper_handle != NULL) {
1145 if (IPCL_IS_NONSTR(connp)) {
1146 (*connp->conn_upcalls->su_closed)(
1147 connp->conn_upper_handle);
1148 dccp->dccp_detached = B_TRUE;
1149 }
1150
1151 connp->conn_upper_handle = NULL;
1152 connp->conn_upcalls = NULL;
1153 }
1154 }
1155
1156 void *
1157 dccp_get_conn(void *arg, dccp_stack_t *dccps)
1158 {
1159 conn_t *connp;
1160 dccp_t *dccp = NULL;
1161 squeue_t *sqp = (squeue_t *)arg;
1162 netstack_t *ns;
1163
1164 /* XXX timewait */
1165
1166 connp = ipcl_conn_create(IPCL_DCCPCONN, KM_NOSLEEP,
1167 dccps->dccps_netstack);
1168 if (connp == NULL) {
1169 return (NULL);
1170 }
1171
1172 dccp = connp->conn_dccp;
1173 dccp->dccp_dccps = dccps;
1174
1175 /* List of features being negotated */
1176 list_create(&dccp->dccp_features, sizeof (dccp_feature_t),
1177 offsetof(dccp_feature_t, df_next));
1178
1179 connp->conn_recv = dccp_input_data;
1180 connp->conn_recvicmp = dccp_icmp_input;
1181 connp->conn_verifyicmp = dccp_verifyicmp;
1182
1183 connp->conn_ixa->ixa_notify = dccp_notify;
1184 connp->conn_ixa->ixa_notify_cookie = dccp;
1185
1186 return ((void *)connp);
1187 }
1188
1189 /*
1190 * Collect protocol properties to send to the upper handle.
1191 */
1192 void
1193 dccp_get_proto_props(dccp_t *dccp, struct sock_proto_props *sopp)
1194 {
1195 conn_t *connp = dccp->dccp_connp;
1196
1197 cmn_err(CE_NOTE, "dccp.c: dccp_get_proto_props");
1198
1199 sopp->sopp_flags = SOCKOPT_RCVHIWAT | SOCKOPT_MAXBLK | SOCKOPT_WROFF;
1200 }
1201
1202 /*
1203 * IPv4 connect.
1204 */
1205 static int
1206 dccp_connect_ipv4(dccp_t *dccp, ipaddr_t *dstaddrp, in_port_t dstport,
1207 uint_t srcid)
1208 {
1209 conn_t *connp = dccp->dccp_connp;
1210 dccp_stack_t *dccps = dccp->dccp_dccps;
1211 ipaddr_t dstaddr = *dstaddrp;
1212 uint16_t lport;
1213 int error;
1214
1215 cmn_err(CE_NOTE, "dccp.c: dccp_connect_ipv4");
1216
1217 ASSERT(connp->conn_ipversion == IPV4_VERSION);
1218
1219 if (dstaddr == INADDR_ANY) {
1220 dstaddr = htonl(INADDR_LOOPBACK);
1221 *dstaddrp = dstaddr;
1222 }
1223
1224 /* Handle __sin6_src_id if socket not bound to an IP address */
1225 if (srcid != 0 && connp->conn_laddr_v4 == INADDR_ANY) {
1226 ip_srcid_find_id(srcid, &connp->conn_laddr_v6,
1227 IPCL_ZONEID(connp), dccps->dccps_netstack);
1228 connp->conn_saddr_v6 = connp->conn_laddr_v6;
1229 }
1230
1231 IN6_IPADDR_TO_V4MAPPED(dstaddr, &connp->conn_faddr_v6);
1232 connp->conn_fport = dstport;
1233
1234 if (dccp->dccp_state == DCCPS_CLOSED) {
1235 lport = dccp_update_next_port(dccps->dccps_next_port_to_try,
1236 dccp, B_TRUE);
1237 lport = dccp_bindi(dccp, lport, &connp->conn_laddr_v6, 0,
1238 B_TRUE, B_FALSE, B_FALSE);
1239 if (lport == 0) {
1240 return (-TNOADDR);
1241 }
1242 }
1243
1244 error = dccp_set_destination(dccp);
1245 if (error != 0) {
1246 return (error);
1247 }
1248
1249 /*
1250 * Don't connect to oneself.
1251 */
1252 if (connp->conn_faddr_v4 == connp->conn_laddr_v4 &&
1253 connp->conn_fport == connp->conn_lport) {
1254 return (-TBADADDR);
1255 }
1256
1257 dccp->dccp_state = DCCPS_REQUEST;
1258
1259 return (ipcl_conn_insert_v4(connp));
1260 }
1261
1262 /*
1263 * IPv6 connect.
1264 */
1265 static int
1266 dccp_connect_ipv6(dccp_t *dccp, in6_addr_t *dstaddrp, in_port_t dstport,
1267 uint32_t flowinfo, uint_t srcid, uint32_t scope_id)
1268 {
1269 cmn_err(CE_NOTE, "dccp.c: dccp_connect_ipv6");
1270
1271 return (0);
1272 }
1273
1274 /*
1275 * Set the ports via conn_connect and build the template
1276 * header.
1277 */
1278 int
1279 dccp_set_destination(dccp_t *dccp)
1280 {
1281 conn_t *connp = dccp->dccp_connp;
1282 dccp_stack_t *dccps = dccp->dccp_dccps;
1283 iulp_t uinfo;
1284 uint32_t flags;
1285 int error;
1286
1287 flags = IPDF_LSO | IPDF_ZCOPY;
1288 flags |= IPDF_UNIQUE_DCE;
1289
1290 mutex_enter(&connp->conn_lock);
1291 error = conn_connect(connp, &uinfo, flags);
1292 mutex_exit(&connp->conn_lock);
1293 if (error != 0) {
1294 cmn_err(CE_NOTE, "conn_connect failed");
1295 return (error);
1296 }
1297
1298 error = dccp_build_hdrs(dccp);
1299 if (error != 0) {
1300 cmn_err(CE_NOTE, "dccp_build_hdrs failed");
1301 return (error);
1302 }
1303
1304 /* XXX */
1305
1306 /* Initialise the ISS */
1307 dccp_iss_init(dccp);
1308
1309 mutex_enter(&connp->conn_lock);
1310 connp->conn_state_flags &= ~CONN_INCIPIENT;
1311 mutex_exit(&connp->conn_lock);
1312
1313 return (0);
1314 }
1315
1316 /*
1317 * Clean up.
1318 */
1319 int
1320 dccp_clean_death(dccp_t *dccp, int error)
1321 {
1322 conn_t *connp = dccp->dccp_connp;
1323 dccp_stack_t *dccps = dccp->dccp_dccps;
1324
1325 ASSERT(dccp != NULL);
1326 ASSERT((connp->conn_family == AF_INET &&
1327 connp->conn_ipversion == IPV4_VERSION) ||
1328 (connp->conn_family == AF_INET6 &&
1329 (connp->conn_ipversion == IPV4_VERSION ||
1330 connp->conn_ipversion == IPV6_VERSION)));
1331
1332 dccp_reinit(dccp);
1333 if (IPCL_IS_NONSTR(connp)) {
1334 (void) dccp_do_unbind(connp);
1335 }
1336
1337 return (-1);
1338 }
1339
1340 /*
1341 * Init the ISS.
1342 */
1343 static void
1344 dccp_iss_init(dccp_t *dccp)
1345 {
1346 cmn_err(CE_NOTE, "dccp.c: dccp_iss_init");
1347
1348 dccp->dccp_iss += gethrtime();
1349 dccp->dccp_gss = dccp->dccp_iss;
1350 }
1351
1352 /*
1353 * Reinitialization of a dccp structure.
1354 */
1355 static void
1356 dccp_reinit(dccp_t *dccp)
1357 {
1358 conn_t *connp = dccp->dccp_connp;
1359 dccp_stack_t *dccps = dccp->dccp_dccps;
1360
1361 ASSERT(dccp->dccp_listener == NULL);
1362 ASSERT((connp->conn_family == AF_INET &&
1363 connp->conn_ipversion == IPV4_VERSION) ||
1364 (connp->conn_family == AF_INET6 &&
1365 (connp->conn_ipversion == IPV4_VERSION ||
1366 connp->conn_ipversion == IPV6_VERSION)));
1367
1368 /* Cancel outstanding timers */
1369 dccp_timers_stop(dccp);
1370 }