sctp_init.c revision 3448:aaf16568054b
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 2007 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <sys/types.h>
30#include <sys/stream.h>
31#include <sys/ddi.h>
32#include <sys/sunddi.h>
33
34#include <netinet/in.h>
35#include <netinet/ip6.h>
36
37#include <inet/common.h>
38#include <inet/ipclassifier.h>
39#include <inet/ip.h>
40#include <inet/ip6.h>
41#include <inet/mib2.h>
42#include <inet/nd.h>
43#include <inet/optcom.h>
44#include <inet/ipclassifier.h>
45#include "sctp_impl.h"
46#include "sctp_addr.h"
47
48/*
49 * This will compute the checksum over the SCTP packet, so this
50 * function should only be called after the whole packet has been
51 * built.
52 *
53 * rptr should point to the IP / SCTP composite header.
54 * len should be the length of the entire packet, including the IP
55 *     header.
56 */
57void
58sctp_add_hdr(sctp_t *sctp, uchar_t *rptr, size_t len)
59{
60	ipha_t *iphdr;
61	short iplen;
62
63	ASSERT(len >= sctp->sctp_hdr_len);
64
65	/* Copy the common header from the template */
66	bcopy(sctp->sctp_iphc, rptr, sctp->sctp_hdr_len);
67
68	/* Set the total length in the IP hdr */
69	iplen = (short)len;
70	iphdr = (ipha_t *)rptr;
71	U16_TO_ABE16(iplen, &iphdr->ipha_length);
72}
73
74/*ARGSUSED*/
75size_t
76sctp_supaddr_param_len(sctp_t *sctp)
77{
78	return (sizeof (sctp_parm_hdr_t) + sizeof (int32_t));
79}
80
81size_t
82sctp_supaddr_param(sctp_t *sctp, uchar_t *p)
83{
84	sctp_parm_hdr_t *sph;
85	uint16_t *addrtype;
86
87	sph = (sctp_parm_hdr_t *)p;
88	sph->sph_type = htons(PARM_SUPP_ADDRS);
89	addrtype = (uint16_t *)(sph + 1);
90	switch (sctp->sctp_ipversion) {
91	case IPV4_VERSION:
92		*addrtype++ = htons(PARM_ADDR4);
93		*addrtype = 0;
94		sph->sph_len = htons(sizeof (*sph) + sizeof (*addrtype));
95		break;
96	case IPV6_VERSION:
97		*addrtype++ = htons(PARM_ADDR6);
98		if (!sctp->sctp_connp->conn_ipv6_v6only) {
99			*addrtype = htons(PARM_ADDR4);
100			sph->sph_len = htons(sizeof (*sph) +
101			    sizeof (*addrtype) * 2);
102		} else {
103			*addrtype = 0;
104			sph->sph_len = htons(sizeof (*sph) +
105			    sizeof (*addrtype));
106		}
107		break;
108	default:
109		break;
110	}
111	return (sizeof (*sph) + (sizeof (*addrtype) * 2));
112}
113
114/*
115 * Currently, we support on PRSCTP option, there is more to come.
116 */
117/*ARGSUSED*/
118size_t
119sctp_options_param_len(const sctp_t *sctp, int option)
120{
121	size_t	optlen;
122
123	switch (option) {
124	case SCTP_PRSCTP_OPTION:
125		optlen = sizeof (sctp_parm_hdr_t);
126		break;
127	default:
128		ASSERT(0);
129	}
130
131	return (optlen);
132}
133
134/*ARGSUSED*/
135size_t
136sctp_options_param(const sctp_t *sctp, void *p, int option)
137{
138	sctp_parm_hdr_t	*sph = (sctp_parm_hdr_t *)p;
139
140	switch (option) {
141	case SCTP_PRSCTP_OPTION:
142		sph->sph_type = htons(PARM_FORWARD_TSN);
143		sph->sph_len = htons(sizeof (*sph));
144		break;
145	default:
146		ASSERT(0);
147	}
148
149	return (sizeof (*sph));
150
151}
152
153size_t
154sctp_adaption_code_param(sctp_t *sctp, uchar_t *p)
155{
156	sctp_parm_hdr_t *sph;
157
158	if (!sctp->sctp_send_adaption) {
159		return (0);
160	}
161	sph = (sctp_parm_hdr_t *)p;
162	sph->sph_type = htons(PARM_ADAPT_LAYER_IND);
163	sph->sph_len = htons(sizeof (*sph) + sizeof (uint32_t));
164	*(uint32_t *)(sph + 1) = htonl(sctp->sctp_tx_adaption_code);
165
166	return (sizeof (*sph) + sizeof (uint32_t));
167}
168
169mblk_t *
170sctp_init_mp(sctp_t *sctp)
171{
172	mblk_t			*mp;
173	uchar_t			*p;
174	size_t			initlen;
175	sctp_init_chunk_t	*icp;
176	sctp_chunk_hdr_t	*chp;
177	uint16_t		schlen;
178	int			supp_af;
179	sctp_stack_t	*sctps = sctp->sctp_sctps;
180
181	if (sctp->sctp_family == AF_INET) {
182		supp_af = PARM_SUPP_V4;
183	} else {
184		/* Assume here that a v6 endpoint supports v4 address. */
185		if (sctp->sctp_connp->conn_ipv6_v6only)
186			supp_af = PARM_SUPP_V6;
187		else
188			supp_af = PARM_SUPP_V6 | PARM_SUPP_V4;
189	}
190	initlen = sizeof (*chp) + sizeof (*icp);
191	if (sctp->sctp_send_adaption) {
192		initlen += (sizeof (sctp_parm_hdr_t) + sizeof (uint32_t));
193	}
194	initlen += sctp_supaddr_param_len(sctp);
195	initlen += sctp_addr_params_len(sctp, supp_af, B_TRUE);
196	if (sctp->sctp_prsctp_aware && sctps->sctps_prsctp_enabled)
197		initlen += sctp_options_param_len(sctp, SCTP_PRSCTP_OPTION);
198
199	/*
200	 * This could be a INIT retransmission in which case sh_verf may
201	 * be non-zero, zero it out just to be sure.
202	 */
203	sctp->sctp_sctph->sh_verf = 0;
204	sctp->sctp_sctph6->sh_verf = 0;
205
206	mp = sctp_make_mp(sctp, NULL, initlen);
207	if (mp == NULL) {
208		SCTP_KSTAT(sctps, sctp_send_init_failed);
209		return (NULL);
210	}
211
212	/* Lay in a new INIT chunk, starting with the chunk header */
213	chp = (sctp_chunk_hdr_t *)mp->b_wptr;
214	chp->sch_id = CHUNK_INIT;
215	chp->sch_flags = 0;
216	schlen = (uint16_t)initlen;
217	U16_TO_ABE16(schlen, &(chp->sch_len));
218
219	mp->b_wptr += initlen;
220
221	icp = (sctp_init_chunk_t *)(chp + 1);
222	icp->sic_inittag = sctp->sctp_lvtag;
223	U32_TO_ABE32(sctp->sctp_rwnd, &(icp->sic_a_rwnd));
224	U16_TO_ABE16(sctp->sctp_num_ostr, &(icp->sic_outstr));
225	U16_TO_ABE16(sctp->sctp_num_istr, &(icp->sic_instr));
226	U32_TO_ABE32(sctp->sctp_ltsn, &(icp->sic_inittsn));
227
228	p = (uchar_t *)(icp + 1);
229
230	/* Adaption layer param */
231	p += sctp_adaption_code_param(sctp, p);
232
233	/* Add supported address types parameter */
234	p += sctp_supaddr_param(sctp, p);
235
236	/* Add address parameters */
237	p += sctp_addr_params(sctp, supp_af, p);
238
239	/* Add Forward-TSN-Supported param */
240	if (sctp->sctp_prsctp_aware && sctps->sctps_prsctp_enabled)
241		p += sctp_options_param(sctp, p, SCTP_PRSCTP_OPTION);
242
243	BUMP_LOCAL(sctp->sctp_obchunks);
244
245	sctp_set_iplen(sctp, mp);
246
247	return (mp);
248}
249
250/*
251 * Extracts the verification tag from an INIT chunk. If the INIT
252 * chunk is truncated or malformed, returns 0.
253 */
254uint32_t
255sctp_init2vtag(sctp_chunk_hdr_t *initch)
256{
257	sctp_init_chunk_t *init;
258
259	init = (sctp_init_chunk_t *)(initch + 1);
260	return (init->sic_inittag);
261}
262
263size_t
264sctp_addr_params_len(sctp_t *sctp, int af, boolean_t modify)
265{
266	ASSERT(sctp->sctp_nsaddrs > 0);
267
268	/*
269	 * If we have only one local address or it is a loopback or linklocal
270	 * association, we let the peer pull the address from the IP header.
271	 */
272	if (sctp->sctp_nsaddrs == 1 || sctp->sctp_loopback ||
273	    sctp->sctp_linklocal) {
274		return (0);
275	}
276
277	return (sctp_saddr_info(sctp, af, NULL, modify));
278}
279
280size_t
281sctp_addr_params(sctp_t *sctp, int af, uchar_t *p)
282{
283	/*
284	 * If we have only one local address or it is a loopback or linklocal
285	 * association, we let the peer pull the address from the IP header.
286	 */
287	if (sctp->sctp_nsaddrs == 1 || sctp->sctp_loopback ||
288	    sctp->sctp_linklocal) {
289		return (0);
290	}
291	return (sctp_saddr_info(sctp, af, p, B_FALSE));
292}
293