xref: /titanic_44/usr/src/uts/common/inet/sctp/sctp_init.c (revision 62a1b812a0c45c0d4c10ef645dda42bf71080108)
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  */
57 void
58 sctp_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*/
75 size_t
76 sctp_supaddr_param_len(sctp_t *sctp)
77 {
78 	return (sizeof (sctp_parm_hdr_t) + sizeof (int32_t));
79 }
80 
81 size_t
82 sctp_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*/
118 size_t
119 sctp_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*/
135 size_t
136 sctp_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 
153 size_t
154 sctp_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 
169 mblk_t *
170 sctp_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  */
254 uint32_t
255 sctp_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 
263 size_t
264 sctp_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 
280 size_t
281 sctp_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