xref: /illumos-gate/usr/src/uts/common/inet/sctp/sctp_init.c (revision 0dee7919e2f2a6479d16b370af93747b9416b242)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 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 "sctp_impl.h"
45 #include "sctp_addr.h"
46 
47 /*
48  * This will compute the checksum over the SCTP packet, so this
49  * function should only be called after the whole packet has been
50  * built.
51  *
52  * rptr should point to the IP / SCTP composite header.
53  * len should be the length of the entire packet, including the IP
54  *     header.
55  */
56 void
57 sctp_add_hdr(sctp_t *sctp, uchar_t *rptr, size_t len)
58 {
59 	ipha_t *iphdr;
60 	short iplen;
61 
62 	ASSERT(len >= sctp->sctp_hdr_len);
63 
64 	/* Copy the common header from the template */
65 	bcopy(sctp->sctp_iphc, rptr, sctp->sctp_hdr_len);
66 
67 	/* Set the total length in the IP hdr */
68 	iplen = (short)len;
69 	iphdr = (ipha_t *)rptr;
70 	U16_TO_ABE16(iplen, &iphdr->ipha_length);
71 }
72 
73 /*ARGSUSED*/
74 size_t
75 sctp_supaddr_param_len(sctp_t *sctp)
76 {
77 	return (sizeof (sctp_parm_hdr_t) + sizeof (int32_t));
78 }
79 
80 size_t
81 sctp_supaddr_param(sctp_t *sctp, uchar_t *p)
82 {
83 	sctp_parm_hdr_t *sph;
84 	uint16_t *addrtype;
85 
86 	sph = (sctp_parm_hdr_t *)p;
87 	sph->sph_type = htons(PARM_SUPP_ADDRS);
88 	addrtype = (uint16_t *)(sph + 1);
89 	switch (sctp->sctp_ipversion) {
90 	case IPV4_VERSION:
91 		*addrtype++ = htons(PARM_ADDR4);
92 		*addrtype = 0;
93 		sph->sph_len = htons(sizeof (*sph) + sizeof (*addrtype));
94 		break;
95 	case IPV6_VERSION:
96 		*addrtype++ = htons(PARM_ADDR6);
97 		if (!sctp->sctp_connp->conn_ipv6_v6only) {
98 			*addrtype = htons(PARM_ADDR4);
99 			sph->sph_len = htons(sizeof (*sph) +
100 			    sizeof (*addrtype) * 2);
101 		} else {
102 			*addrtype = 0;
103 			sph->sph_len = htons(sizeof (*sph) +
104 			    sizeof (*addrtype));
105 		}
106 		break;
107 	default:
108 		break;
109 	}
110 	return (sizeof (*sph) + (sizeof (*addrtype) * 2));
111 }
112 
113 /*
114  * Currently, we support on PRSCTP option, there is more to come.
115  */
116 /*ARGSUSED*/
117 size_t
118 sctp_options_param_len(const sctp_t *sctp, int option)
119 {
120 	size_t	optlen;
121 
122 	switch (option) {
123 	case SCTP_PRSCTP_OPTION:
124 		optlen = sizeof (sctp_parm_hdr_t);
125 		break;
126 	default:
127 		ASSERT(0);
128 	}
129 
130 	return (optlen);
131 }
132 
133 /*ARGSUSED*/
134 size_t
135 sctp_options_param(const sctp_t *sctp, void *p, int option)
136 {
137 	sctp_parm_hdr_t	*sph = (sctp_parm_hdr_t *)p;
138 
139 	switch (option) {
140 	case SCTP_PRSCTP_OPTION:
141 		sph->sph_type = htons(PARM_FORWARD_TSN);
142 		sph->sph_len = htons(sizeof (*sph));
143 		break;
144 	default:
145 		ASSERT(0);
146 	}
147 
148 	return (sizeof (*sph));
149 
150 }
151 
152 size_t
153 sctp_adaption_code_param(sctp_t *sctp, uchar_t *p)
154 {
155 	sctp_parm_hdr_t *sph;
156 
157 	if (!sctp->sctp_send_adaption) {
158 		return (0);
159 	}
160 	sph = (sctp_parm_hdr_t *)p;
161 	sph->sph_type = htons(PARM_ADAPT_LAYER_IND);
162 	sph->sph_len = htons(sizeof (*sph) + sizeof (uint32_t));
163 	*(uint32_t *)(sph + 1) = htonl(sctp->sctp_tx_adaption_code);
164 
165 	return (sizeof (*sph) + sizeof (uint32_t));
166 }
167 
168 mblk_t *
169 sctp_init_mp(sctp_t *sctp)
170 {
171 	mblk_t			*mp;
172 	uchar_t			*p;
173 	size_t			initlen;
174 	sctp_init_chunk_t	*icp;
175 	sctp_chunk_hdr_t	*chp;
176 	uint16_t		schlen;
177 	int			supp_af;
178 
179 	if (sctp->sctp_family == AF_INET) {
180 		supp_af = PARM_SUPP_V4;
181 	} else {
182 		/* Assume here that a v6 endpoint supports v4 address. */
183 		if (sctp->sctp_connp->conn_ipv6_v6only)
184 			supp_af = PARM_SUPP_V6;
185 		else
186 			supp_af = PARM_SUPP_V6 | PARM_SUPP_V4;
187 	}
188 	initlen = sizeof (*chp) + sizeof (*icp);
189 	if (sctp->sctp_send_adaption) {
190 		initlen += (sizeof (sctp_parm_hdr_t) + sizeof (uint32_t));
191 	}
192 	initlen += sctp_supaddr_param_len(sctp);
193 	initlen += sctp_addr_params_len(sctp, supp_af, B_TRUE);
194 	if (sctp->sctp_prsctp_aware && sctp_prsctp_enabled)
195 		initlen += sctp_options_param_len(sctp, SCTP_PRSCTP_OPTION);
196 
197 	/*
198 	 * This could be a INIT retransmission in which case sh_verf may
199 	 * be non-zero, zero it out just to be sure.
200 	 */
201 	sctp->sctp_sctph->sh_verf = 0;
202 	sctp->sctp_sctph6->sh_verf = 0;
203 
204 	mp = sctp_make_mp(sctp, NULL, initlen);
205 	if (mp == NULL)
206 		return (NULL);
207 
208 	/* Lay in a new INIT chunk, starting with the chunk header */
209 	chp = (sctp_chunk_hdr_t *)mp->b_wptr;
210 	chp->sch_id = CHUNK_INIT;
211 	chp->sch_flags = 0;
212 	schlen = (uint16_t)initlen;
213 	U16_TO_ABE16(schlen, &(chp->sch_len));
214 
215 	mp->b_wptr += initlen;
216 
217 	icp = (sctp_init_chunk_t *)(chp + 1);
218 	icp->sic_inittag = sctp->sctp_lvtag;
219 	U32_TO_ABE32(sctp->sctp_rwnd, &(icp->sic_a_rwnd));
220 	U16_TO_ABE16(sctp->sctp_num_ostr, &(icp->sic_outstr));
221 	U16_TO_ABE16(sctp->sctp_num_istr, &(icp->sic_instr));
222 	U32_TO_ABE32(sctp->sctp_ltsn, &(icp->sic_inittsn));
223 
224 	p = (uchar_t *)(icp + 1);
225 
226 	/* Adaption layer param */
227 	p += sctp_adaption_code_param(sctp, p);
228 
229 	/* Add supported address types parameter */
230 	p += sctp_supaddr_param(sctp, p);
231 
232 	/* Add address parameters */
233 	p += sctp_addr_params(sctp, supp_af, p);
234 
235 	/* Add Forward-TSN-Supported param */
236 	if (sctp->sctp_prsctp_aware && sctp_prsctp_enabled)
237 		p += sctp_options_param(sctp, p, SCTP_PRSCTP_OPTION);
238 
239 	BUMP_LOCAL(sctp->sctp_obchunks);
240 
241 	sctp_set_iplen(sctp, mp);
242 
243 	return (mp);
244 }
245 
246 /*
247  * Extracts the verification tag from an INIT chunk. If the INIT
248  * chunk is truncated or malformed, returns 0.
249  */
250 uint32_t
251 sctp_init2vtag(sctp_chunk_hdr_t *initch)
252 {
253 	sctp_init_chunk_t *init;
254 
255 	init = (sctp_init_chunk_t *)(initch + 1);
256 	return (init->sic_inittag);
257 }
258 
259 size_t
260 sctp_addr_params_len(sctp_t *sctp, int af, boolean_t modify)
261 {
262 	ASSERT(sctp->sctp_nsaddrs > 0);
263 
264 	/*
265 	 * If we have only one local address or it is a loopback or linklocal
266 	 * association, we let the peer pull the address from the IP header.
267 	 */
268 	if (sctp->sctp_nsaddrs == 1 || sctp->sctp_loopback ||
269 	    sctp->sctp_linklocal) {
270 		return (0);
271 	}
272 
273 	return (sctp_saddr_info(sctp, af, NULL, modify));
274 }
275 
276 size_t
277 sctp_addr_params(sctp_t *sctp, int af, uchar_t *p)
278 {
279 	/*
280 	 * If we have only one local address or it is a loopback or linklocal
281 	 * association, we let the peer pull the address from the IP header.
282 	 */
283 	if (sctp->sctp_nsaddrs == 1 || sctp->sctp_loopback ||
284 	    sctp->sctp_linklocal) {
285 		return (0);
286 	}
287 	return (sctp_saddr_info(sctp, af, p, B_FALSE));
288 }
289