1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/systm.h>
31*0Sstevel@tonic-gate #include <sys/stream.h>
32*0Sstevel@tonic-gate #include <sys/cmn_err.h>
33*0Sstevel@tonic-gate #include <sys/socket.h>
34*0Sstevel@tonic-gate #include <sys/kmem.h>
35*0Sstevel@tonic-gate #include <sys/strsubr.h>
36*0Sstevel@tonic-gate #include <sys/strsun.h>
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate #include <netinet/in.h>
39*0Sstevel@tonic-gate #include <netinet/ip6.h>
40*0Sstevel@tonic-gate #include <netinet/sctp.h>
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate #include <inet/common.h>
43*0Sstevel@tonic-gate #include <inet/ip.h>
44*0Sstevel@tonic-gate #include <inet/ip6.h>
45*0Sstevel@tonic-gate #include <inet/mib2.h>
46*0Sstevel@tonic-gate #include "sctp_impl.h"
47*0Sstevel@tonic-gate #include "sctp_asconf.h"
48*0Sstevel@tonic-gate #include "sctp_addr.h"
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate typedef struct sctp_asconf_s {
51*0Sstevel@tonic-gate 	mblk_t *head;
52*0Sstevel@tonic-gate 	uint32_t cid;
53*0Sstevel@tonic-gate } sctp_asconf_t;
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate /*
56*0Sstevel@tonic-gate  * The ASCONF chunk per-parameter request interface. ph is the
57*0Sstevel@tonic-gate  * parameter header for the parameter in the request, and cid
58*0Sstevel@tonic-gate  * is the parameters correlation ID. cont should be set to 1
59*0Sstevel@tonic-gate  * if the ASCONF framework should continue processing request
60*0Sstevel@tonic-gate  * parameters following this one, or 0 if it should stop. If
61*0Sstevel@tonic-gate  * cont is -1, this indicates complete memory depletion, which
62*0Sstevel@tonic-gate  * will cause the ASCONF framework to abort building a reply. If
63*0Sstevel@tonic-gate  * act is 1, the callback should take whatever action it needs
64*0Sstevel@tonic-gate  * to fulfil this request. If act is 0, this request has already
65*0Sstevel@tonic-gate  * been processed, so the callback should only verify and pass
66*0Sstevel@tonic-gate  * back error parameters, and not take any action.
67*0Sstevel@tonic-gate  *
68*0Sstevel@tonic-gate  * The callback should return an mblk with any reply enclosed,
69*0Sstevel@tonic-gate  * with the correlation ID in the first four bytes of the
70*0Sstevel@tonic-gate  * message. A NULL return implies implicit success to the
71*0Sstevel@tonic-gate  * requestor.
72*0Sstevel@tonic-gate  */
73*0Sstevel@tonic-gate typedef mblk_t *sctp_asconf_func_t(sctp_t *, sctp_parm_hdr_t *ph, uint32_t cid,
74*0Sstevel@tonic-gate     sctp_faddr_t *, int *cont, int act);
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate /*
77*0Sstevel@tonic-gate  * The ASCONF chunk per-parameter ACK interface. ph is the parameter
78*0Sstevel@tonic-gate  * header for the parameter returned in the ACK, and oph is the
79*0Sstevel@tonic-gate  * original parameter sent out in the ASCONF request.
80*0Sstevel@tonic-gate  * If the peer implicitly responded OK (by not including an
81*0Sstevel@tonic-gate  * explicit OK for the request), ph will be NULL.
82*0Sstevel@tonic-gate  * ph can also point to an Unrecognized Parameter parameter,
83*0Sstevel@tonic-gate  * in which case the peer did not understand the request
84*0Sstevel@tonic-gate  * parameter.
85*0Sstevel@tonic-gate  *
86*0Sstevel@tonic-gate  * ph and oph parameter headers are in host byte order. Encapsulated
87*0Sstevel@tonic-gate  * parameters will still be in network byte order.
88*0Sstevel@tonic-gate  */
89*0Sstevel@tonic-gate typedef void sctp_asconf_ack_func_t(sctp_t *, sctp_parm_hdr_t *ph,
90*0Sstevel@tonic-gate     sctp_parm_hdr_t *oph, sctp_faddr_t *);
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate typedef struct {
93*0Sstevel@tonic-gate 	uint16_t id;
94*0Sstevel@tonic-gate 	sctp_asconf_func_t *asconf;
95*0Sstevel@tonic-gate 	sctp_asconf_ack_func_t *asconf_ack;
96*0Sstevel@tonic-gate } dispatch_t;
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate static sctp_asconf_func_t sctp_addip_req, sctp_setprim_req,
99*0Sstevel@tonic-gate     sctp_asconf_unrec_parm;
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate static sctp_asconf_ack_func_t sctp_addip_ack, sctp_setprim_ack,
102*0Sstevel@tonic-gate     sctp_asconf_ack_unrec_parm;
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate static const dispatch_t sctp_asconf_dispatch_tbl[] = {
105*0Sstevel@tonic-gate /*	ID			ASCONF			ASCONF_ACK */
106*0Sstevel@tonic-gate 	{ PARM_ADD_IP,		sctp_addip_req,		sctp_addip_ack },
107*0Sstevel@tonic-gate 	{ PARM_DEL_IP,		sctp_addip_req,		sctp_addip_ack },
108*0Sstevel@tonic-gate 	{ PARM_SET_PRIMARY,	sctp_setprim_req,	sctp_setprim_ack }
109*0Sstevel@tonic-gate };
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate static const dispatch_t sctp_asconf_default_dispatch = {
112*0Sstevel@tonic-gate 	0, sctp_asconf_unrec_parm, sctp_asconf_ack_unrec_parm
113*0Sstevel@tonic-gate };
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate /*
116*0Sstevel@tonic-gate  * ASCONF framework
117*0Sstevel@tonic-gate  */
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate static const dispatch_t *
120*0Sstevel@tonic-gate sctp_lookup_asconf_dispatch(int id)
121*0Sstevel@tonic-gate {
122*0Sstevel@tonic-gate 	int i;
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	for (i = 0; i < A_CNT(sctp_asconf_dispatch_tbl); i++) {
125*0Sstevel@tonic-gate 		if (sctp_asconf_dispatch_tbl[i].id == id) {
126*0Sstevel@tonic-gate 			return (sctp_asconf_dispatch_tbl + i);
127*0Sstevel@tonic-gate 		}
128*0Sstevel@tonic-gate 	}
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	return (&sctp_asconf_default_dispatch);
131*0Sstevel@tonic-gate }
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate /*
134*0Sstevel@tonic-gate  * Frees mp on failure
135*0Sstevel@tonic-gate  */
136*0Sstevel@tonic-gate static mblk_t *
137*0Sstevel@tonic-gate sctp_asconf_prepend_errwrap(mblk_t *mp, uint32_t cid)
138*0Sstevel@tonic-gate {
139*0Sstevel@tonic-gate 	mblk_t		*wmp;
140*0Sstevel@tonic-gate 	sctp_parm_hdr_t	*wph;
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate 	/* Prepend a wrapper err cause ind param */
143*0Sstevel@tonic-gate 	wmp = allocb(sizeof (*wph) + sizeof (cid), BPRI_MED);
144*0Sstevel@tonic-gate 	if (wmp == NULL) {
145*0Sstevel@tonic-gate 		freemsg(mp);
146*0Sstevel@tonic-gate 		return (NULL);
147*0Sstevel@tonic-gate 	}
148*0Sstevel@tonic-gate 	wmp->b_wptr += sizeof (*wph) + sizeof (cid);
149*0Sstevel@tonic-gate 	wph = (sctp_parm_hdr_t *)wmp->b_rptr;
150*0Sstevel@tonic-gate 	wph->sph_type = htons(PARM_ERROR_IND);
151*0Sstevel@tonic-gate 	wph->sph_len = htons(msgdsize(mp) + sizeof (*wph) + sizeof (cid));
152*0Sstevel@tonic-gate 	bcopy(&cid, wph + 1, sizeof (uint32_t));
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 	wmp->b_cont = mp;
155*0Sstevel@tonic-gate 	return (wmp);
156*0Sstevel@tonic-gate }
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate /*ARGSUSED*/
159*0Sstevel@tonic-gate static mblk_t *
160*0Sstevel@tonic-gate sctp_asconf_unrec_parm(sctp_t *sctp, sctp_parm_hdr_t *ph, uint32_t cid,
161*0Sstevel@tonic-gate     sctp_faddr_t *fp, int *cont, int act)
162*0Sstevel@tonic-gate {
163*0Sstevel@tonic-gate 	mblk_t *mp = NULL;
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	/* Unrecognized param; check the high order bits */
166*0Sstevel@tonic-gate 	if ((ph->sph_type & 0xc000) == 0xc000) {
167*0Sstevel@tonic-gate 		/* report unrecognized param, and keep processing */
168*0Sstevel@tonic-gate 		sctp_add_unrec_parm(ph, &mp);
169*0Sstevel@tonic-gate 		if (mp == NULL) {
170*0Sstevel@tonic-gate 			*cont = -1;
171*0Sstevel@tonic-gate 			return (NULL);
172*0Sstevel@tonic-gate 		}
173*0Sstevel@tonic-gate 		/* Prepend a the CID and a wrapper err cause ind param */
174*0Sstevel@tonic-gate 		mp = sctp_asconf_prepend_errwrap(mp, cid);
175*0Sstevel@tonic-gate 		if (mp == NULL) {
176*0Sstevel@tonic-gate 			*cont = -1;
177*0Sstevel@tonic-gate 			return (NULL);
178*0Sstevel@tonic-gate 		}
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 		*cont = 1;
181*0Sstevel@tonic-gate 		return (mp);
182*0Sstevel@tonic-gate 	}
183*0Sstevel@tonic-gate 	if (ph->sph_type & 0x4000) {
184*0Sstevel@tonic-gate 		/* Stop processing and drop; report unrecognized param */
185*0Sstevel@tonic-gate 		sctp_add_unrec_parm(ph, &mp);
186*0Sstevel@tonic-gate 		if (mp == NULL) {
187*0Sstevel@tonic-gate 			*cont = -1;
188*0Sstevel@tonic-gate 			return (NULL);
189*0Sstevel@tonic-gate 		}
190*0Sstevel@tonic-gate 		/* Prepend a the CID and a wrapper err cause ind param */
191*0Sstevel@tonic-gate 		mp = sctp_asconf_prepend_errwrap(mp, cid);
192*0Sstevel@tonic-gate 		if (mp == NULL) {
193*0Sstevel@tonic-gate 			*cont = -1;
194*0Sstevel@tonic-gate 			return (NULL);
195*0Sstevel@tonic-gate 		}
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate 		*cont = 0;
198*0Sstevel@tonic-gate 		return (mp);
199*0Sstevel@tonic-gate 	}
200*0Sstevel@tonic-gate 	if (ph->sph_type & 0x8000) {
201*0Sstevel@tonic-gate 		/* skip and continue processing */
202*0Sstevel@tonic-gate 		*cont = 1;
203*0Sstevel@tonic-gate 		return (NULL);
204*0Sstevel@tonic-gate 	}
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	/* 2 high bits are clear; stop processing and drop packet */
207*0Sstevel@tonic-gate 	*cont = 0;
208*0Sstevel@tonic-gate 	return (NULL);
209*0Sstevel@tonic-gate }
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate /*ARGSUSED*/
212*0Sstevel@tonic-gate static void
213*0Sstevel@tonic-gate sctp_asconf_ack_unrec_parm(sctp_t *sctp, sctp_parm_hdr_t *ph,
214*0Sstevel@tonic-gate     sctp_parm_hdr_t *oph, sctp_faddr_t *fp)
215*0Sstevel@tonic-gate {
216*0Sstevel@tonic-gate 	ASSERT(ph);
217*0Sstevel@tonic-gate 	sctp_error_event(sctp, (sctp_chunk_hdr_t *)ph);
218*0Sstevel@tonic-gate }
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate static void
221*0Sstevel@tonic-gate sctp_asconf_init(sctp_asconf_t *asc)
222*0Sstevel@tonic-gate {
223*0Sstevel@tonic-gate 	ASSERT(asc != NULL);
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	asc->head = NULL;
226*0Sstevel@tonic-gate 	asc->cid = 0;
227*0Sstevel@tonic-gate }
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate static int
230*0Sstevel@tonic-gate sctp_asconf_add(sctp_asconf_t *asc, mblk_t *mp)
231*0Sstevel@tonic-gate {
232*0Sstevel@tonic-gate 	uint32_t *cp;
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 	/* XXX can't exceed MTU */
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 	cp = (uint32_t *)(mp->b_rptr + sizeof (sctp_parm_hdr_t));
237*0Sstevel@tonic-gate 	*cp = asc->cid++;
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 	if (asc->head == NULL)
240*0Sstevel@tonic-gate 		asc->head = mp;
241*0Sstevel@tonic-gate 	else
242*0Sstevel@tonic-gate 		linkb(asc->head, mp);
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 	return (0);
245*0Sstevel@tonic-gate }
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate static void
248*0Sstevel@tonic-gate sctp_asconf_destroy(sctp_asconf_t *asc)
249*0Sstevel@tonic-gate {
250*0Sstevel@tonic-gate 	if (asc->head != NULL) {
251*0Sstevel@tonic-gate 		freemsg(asc->head);
252*0Sstevel@tonic-gate 		asc->head = NULL;
253*0Sstevel@tonic-gate 	}
254*0Sstevel@tonic-gate 	asc->cid = 0;
255*0Sstevel@tonic-gate }
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate static int
258*0Sstevel@tonic-gate sctp_asconf_send(sctp_t *sctp, sctp_asconf_t *asc, sctp_faddr_t *fp)
259*0Sstevel@tonic-gate {
260*0Sstevel@tonic-gate 	mblk_t			*mp, *nmp;
261*0Sstevel@tonic-gate 	sctp_chunk_hdr_t	*ch;
262*0Sstevel@tonic-gate 	boolean_t		isv4;
263*0Sstevel@tonic-gate 	size_t			msgsize;
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	ASSERT(asc != NULL && asc->head != NULL);
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 	isv4 = (fp != NULL) ? fp->isv4 : sctp->sctp_current->isv4;
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	/* SCTP chunk header + Serial Number + Address Param TLV */
270*0Sstevel@tonic-gate 	msgsize = sizeof (*ch) + sizeof (uint32_t) +
271*0Sstevel@tonic-gate 	    (isv4 ? PARM_ADDR4_LEN : PARM_ADDR6_LEN);
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	mp = allocb(msgsize, BPRI_MED);
274*0Sstevel@tonic-gate 	if (mp == NULL)
275*0Sstevel@tonic-gate 		return (ENOMEM);
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	mp->b_wptr += msgsize;
278*0Sstevel@tonic-gate 	mp->b_cont = asc->head;
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 	ch = (sctp_chunk_hdr_t *)mp->b_rptr;
281*0Sstevel@tonic-gate 	ch->sch_id = CHUNK_ASCONF;
282*0Sstevel@tonic-gate 	ch->sch_flags = 0;
283*0Sstevel@tonic-gate 	ch->sch_len = htons(msgdsize(mp));
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	nmp = msgpullup(mp, -1);
286*0Sstevel@tonic-gate 	if (nmp == NULL) {
287*0Sstevel@tonic-gate 		freeb(mp);
288*0Sstevel@tonic-gate 		return (ENOMEM);
289*0Sstevel@tonic-gate 	}
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	/* Clean up the temporary mblk chain */
292*0Sstevel@tonic-gate 	freemsg(mp);
293*0Sstevel@tonic-gate 	asc->head = NULL;
294*0Sstevel@tonic-gate 	asc->cid = 0;
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	/* Queue it ... */
297*0Sstevel@tonic-gate 	if (sctp->sctp_cxmit_list == NULL) {
298*0Sstevel@tonic-gate 		sctp->sctp_cxmit_list = nmp;
299*0Sstevel@tonic-gate 	} else {
300*0Sstevel@tonic-gate 		linkb(sctp->sctp_cxmit_list, nmp);
301*0Sstevel@tonic-gate 	}
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 	BUMP_LOCAL(sctp->sctp_obchunks);
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 	/* And try to send it. */
306*0Sstevel@tonic-gate 	sctp_wput_asconf(sctp, fp);
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	return (0);
309*0Sstevel@tonic-gate }
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate /*
312*0Sstevel@tonic-gate  * If the peer does not understand an ASCONF chunk, we simply
313*0Sstevel@tonic-gate  * clear out the cxmit_list, since we can send nothing further
314*0Sstevel@tonic-gate  * that the peer will understand.
315*0Sstevel@tonic-gate  *
316*0Sstevel@tonic-gate  * Assumes chunk length has already been checked.
317*0Sstevel@tonic-gate  */
318*0Sstevel@tonic-gate /*ARGSUSED*/
319*0Sstevel@tonic-gate void
320*0Sstevel@tonic-gate sctp_asconf_unrec_chunk(sctp_t *sctp, sctp_chunk_hdr_t *ch)
321*0Sstevel@tonic-gate {
322*0Sstevel@tonic-gate 	if (sctp->sctp_cxmit_list == NULL) {
323*0Sstevel@tonic-gate 		/* Nothing pending */
324*0Sstevel@tonic-gate 		return;
325*0Sstevel@tonic-gate 	}
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	freemsg(sctp->sctp_cxmit_list);
328*0Sstevel@tonic-gate 	sctp->sctp_cxmit_list = NULL;
329*0Sstevel@tonic-gate }
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate void
332*0Sstevel@tonic-gate sctp_input_asconf(sctp_t *sctp, sctp_chunk_hdr_t *ch, sctp_faddr_t *fp)
333*0Sstevel@tonic-gate {
334*0Sstevel@tonic-gate 	const dispatch_t	*dp;
335*0Sstevel@tonic-gate 	mblk_t			*hmp;
336*0Sstevel@tonic-gate 	mblk_t			*mp;
337*0Sstevel@tonic-gate 	uint32_t		*idp;
338*0Sstevel@tonic-gate 	uint32_t		*hidp;
339*0Sstevel@tonic-gate 	ssize_t			rlen;
340*0Sstevel@tonic-gate 	sctp_parm_hdr_t		*ph;
341*0Sstevel@tonic-gate 	sctp_chunk_hdr_t	*ach;
342*0Sstevel@tonic-gate 	int			cont;
343*0Sstevel@tonic-gate 	int			act;
344*0Sstevel@tonic-gate 	uint16_t		plen;
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	ASSERT(ch->sch_id == CHUNK_ASCONF);
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate 	idp = (uint32_t *)(ch + 1);
349*0Sstevel@tonic-gate 	rlen = ntohs(ch->sch_len) - sizeof (*ch) - sizeof (*idp);
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 	if (rlen < 0 || rlen < sizeof (*idp)) {
352*0Sstevel@tonic-gate 		/* nothing there; bail out */
353*0Sstevel@tonic-gate 		return;
354*0Sstevel@tonic-gate 	}
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 	/* Check for duplicates */
357*0Sstevel@tonic-gate 	*idp = ntohl(*idp);
358*0Sstevel@tonic-gate 	if (*idp == (sctp->sctp_fcsn + 1)) {
359*0Sstevel@tonic-gate 		act = 1;
360*0Sstevel@tonic-gate 	} else if (*idp == sctp->sctp_fcsn) {
361*0Sstevel@tonic-gate 		act = 0;
362*0Sstevel@tonic-gate 	} else {
363*0Sstevel@tonic-gate 		/* stale or malicious packet; drop */
364*0Sstevel@tonic-gate 		return;
365*0Sstevel@tonic-gate 	}
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	/* Create the ASCONF_ACK header */
368*0Sstevel@tonic-gate 	hmp = sctp_make_mp(sctp, fp, sizeof (*ach) + sizeof (*idp));
369*0Sstevel@tonic-gate 	if (hmp == NULL) {
370*0Sstevel@tonic-gate 		/* Let the peer retransmit */
371*0Sstevel@tonic-gate 		return;
372*0Sstevel@tonic-gate 	}
373*0Sstevel@tonic-gate 	ach = (sctp_chunk_hdr_t *)hmp->b_wptr;
374*0Sstevel@tonic-gate 	ach->sch_id = CHUNK_ASCONF_ACK;
375*0Sstevel@tonic-gate 	ach->sch_flags = 0;
376*0Sstevel@tonic-gate 	/* Set the length later */
377*0Sstevel@tonic-gate 	hidp = (uint32_t *)(ach + 1);
378*0Sstevel@tonic-gate 	*hidp = htonl(*idp);
379*0Sstevel@tonic-gate 	hmp->b_wptr = (uchar_t *)(hidp + 1);
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 	/* Move to the Address Parameter */
382*0Sstevel@tonic-gate 	ph = (sctp_parm_hdr_t *)(idp + 1);
383*0Sstevel@tonic-gate 	if (rlen <= ntohs(ph->sph_len)) {
384*0Sstevel@tonic-gate 		freeb(hmp);
385*0Sstevel@tonic-gate 		return;
386*0Sstevel@tonic-gate 	}
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	/*
389*0Sstevel@tonic-gate 	 * We already have the association here, so this address parameter
390*0Sstevel@tonic-gate 	 * doesn't seem to be very useful, should we make sure this is part
391*0Sstevel@tonic-gate 	 * of the association and send an error, if not?
392*0Sstevel@tonic-gate 	 * Ignore it for now.
393*0Sstevel@tonic-gate 	 */
394*0Sstevel@tonic-gate 	rlen -= ntohs(ph->sph_len);
395*0Sstevel@tonic-gate 	ph = (sctp_parm_hdr_t *)((char *)ph + ntohs(ph->sph_len));
396*0Sstevel@tonic-gate 	cont = 1;
397*0Sstevel@tonic-gate 	while (rlen > 0 && cont) {
398*0Sstevel@tonic-gate 		/* Sanity checks */
399*0Sstevel@tonic-gate 		if (rlen < sizeof (*ph))
400*0Sstevel@tonic-gate 			break;
401*0Sstevel@tonic-gate 		plen = ntohs(ph->sph_len);
402*0Sstevel@tonic-gate 		if (plen < sizeof (*ph) || plen > rlen) {
403*0Sstevel@tonic-gate 			break;
404*0Sstevel@tonic-gate 		}
405*0Sstevel@tonic-gate 		idp = (uint32_t *)(ph + 1);
406*0Sstevel@tonic-gate 		dp = sctp_lookup_asconf_dispatch(ntohs(ph->sph_type));
407*0Sstevel@tonic-gate 		ASSERT(dp);
408*0Sstevel@tonic-gate 		if (dp->asconf) {
409*0Sstevel@tonic-gate 			mp = dp->asconf(sctp, ph, *idp, fp, &cont, act);
410*0Sstevel@tonic-gate 			if (cont == -1) {
411*0Sstevel@tonic-gate 				/*
412*0Sstevel@tonic-gate 				 * Not even enough memory to create
413*0Sstevel@tonic-gate 				 * an out-of-resources error. Free
414*0Sstevel@tonic-gate 				 * everything and return; the peer
415*0Sstevel@tonic-gate 				 * should retransmit.
416*0Sstevel@tonic-gate 				 */
417*0Sstevel@tonic-gate 				freemsg(hmp);
418*0Sstevel@tonic-gate 				return;
419*0Sstevel@tonic-gate 			}
420*0Sstevel@tonic-gate 			if (mp != NULL) {
421*0Sstevel@tonic-gate 				linkb(hmp, mp);
422*0Sstevel@tonic-gate 			}
423*0Sstevel@tonic-gate 		}
424*0Sstevel@tonic-gate 		ph = sctp_next_parm(ph, &rlen);
425*0Sstevel@tonic-gate 		if (ph == NULL)
426*0Sstevel@tonic-gate 			break;
427*0Sstevel@tonic-gate 	}
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 	/* Now that the params have been processed, increment the fcsn */
430*0Sstevel@tonic-gate 	if (act) {
431*0Sstevel@tonic-gate 		sctp->sctp_fcsn++;
432*0Sstevel@tonic-gate 	}
433*0Sstevel@tonic-gate 	BUMP_LOCAL(sctp->sctp_obchunks);
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	if (fp->isv4)
436*0Sstevel@tonic-gate 		ach->sch_len = htons(msgdsize(hmp) - sctp->sctp_hdr_len);
437*0Sstevel@tonic-gate 	else
438*0Sstevel@tonic-gate 		ach->sch_len = htons(msgdsize(hmp) - sctp->sctp_hdr6_len);
439*0Sstevel@tonic-gate 	sctp_set_iplen(sctp, hmp);
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 	sctp_add_sendq(sctp, hmp);
442*0Sstevel@tonic-gate 	sctp_validate_peer(sctp);
443*0Sstevel@tonic-gate }
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate static sctp_parm_hdr_t *
446*0Sstevel@tonic-gate sctp_lookup_asconf_param(sctp_parm_hdr_t *ph, uint32_t cid, ssize_t rlen)
447*0Sstevel@tonic-gate {
448*0Sstevel@tonic-gate 	uint32_t *idp;
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	while (rlen > 0) {
451*0Sstevel@tonic-gate 		idp = (uint32_t *)(ph + 1);
452*0Sstevel@tonic-gate 		if (*idp == cid) {
453*0Sstevel@tonic-gate 			return (ph);
454*0Sstevel@tonic-gate 		}
455*0Sstevel@tonic-gate 		ph = sctp_next_parm(ph, &rlen);
456*0Sstevel@tonic-gate 		if (ph == NULL)
457*0Sstevel@tonic-gate 			break;
458*0Sstevel@tonic-gate 	}
459*0Sstevel@tonic-gate 	return (NULL);
460*0Sstevel@tonic-gate }
461*0Sstevel@tonic-gate 
462*0Sstevel@tonic-gate void
463*0Sstevel@tonic-gate sctp_input_asconf_ack(sctp_t *sctp, sctp_chunk_hdr_t *ch, sctp_faddr_t *fp)
464*0Sstevel@tonic-gate {
465*0Sstevel@tonic-gate 	const dispatch_t	*dp;
466*0Sstevel@tonic-gate 	uint32_t		*idp;
467*0Sstevel@tonic-gate 	uint32_t		*snp;
468*0Sstevel@tonic-gate 	ssize_t			rlen;
469*0Sstevel@tonic-gate 	ssize_t			plen;
470*0Sstevel@tonic-gate 	sctp_parm_hdr_t		*ph;
471*0Sstevel@tonic-gate 	sctp_parm_hdr_t		*oph;
472*0Sstevel@tonic-gate 	sctp_parm_hdr_t		*fph;
473*0Sstevel@tonic-gate 	mblk_t			*mp;
474*0Sstevel@tonic-gate 	sctp_chunk_hdr_t	*och;
475*0Sstevel@tonic-gate 	int			redosrcs = 0;
476*0Sstevel@tonic-gate 	uint16_t		param_len;
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	ASSERT(ch->sch_id == CHUNK_ASCONF_ACK);
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate 	snp = (uint32_t *)(ch + 1);
481*0Sstevel@tonic-gate 	rlen = ntohs(ch->sch_len) - sizeof (*ch) - sizeof (*snp);
482*0Sstevel@tonic-gate 	if (rlen < 0) {
483*0Sstevel@tonic-gate 		return;
484*0Sstevel@tonic-gate 	}
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 	/* Accept only an ACK for the current serial number */
487*0Sstevel@tonic-gate 	*snp = ntohl(*snp);
488*0Sstevel@tonic-gate 	if (sctp->sctp_cxmit_list == NULL || *snp != (sctp->sctp_lcsn - 1)) {
489*0Sstevel@tonic-gate 		/* Need to send an abort */
490*0Sstevel@tonic-gate 		return;
491*0Sstevel@tonic-gate 	}
492*0Sstevel@tonic-gate 	sctp->sctp_cchunk_pend = 0;
493*0Sstevel@tonic-gate 	SCTP_FADDR_RC_TIMER_STOP(fp);
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 	/*
496*0Sstevel@tonic-gate 	 * Pass explicit replies to callbacks:
497*0Sstevel@tonic-gate 	 * For each reply in the ACK, look up the corresponding
498*0Sstevel@tonic-gate 	 * original parameter in the request using the correlation
499*0Sstevel@tonic-gate 	 * ID, and pass it to the right callback.
500*0Sstevel@tonic-gate 	 */
501*0Sstevel@tonic-gate 	och = (sctp_chunk_hdr_t *)sctp->sctp_cxmit_list->b_rptr;
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 	plen = ntohs(och->sch_len) - sizeof (*och) - sizeof (*idp);
504*0Sstevel@tonic-gate 	idp = (uint32_t *)(och + 1);
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 	/* Get to the 1st ASCONF param, need to skip Address TLV parm */
507*0Sstevel@tonic-gate 	fph = (sctp_parm_hdr_t *)(idp + 1);
508*0Sstevel@tonic-gate 	plen -= ntohs(fph->sph_len);
509*0Sstevel@tonic-gate 	fph = (sctp_parm_hdr_t *)((char *)fph + ntohs(fph->sph_len));
510*0Sstevel@tonic-gate 	ph = (sctp_parm_hdr_t *)(snp + 1);
511*0Sstevel@tonic-gate 	while (rlen > 0) {
512*0Sstevel@tonic-gate 		/* Sanity checks */
513*0Sstevel@tonic-gate 		if (rlen < sizeof (*ph)) {
514*0Sstevel@tonic-gate 			break;
515*0Sstevel@tonic-gate 		}
516*0Sstevel@tonic-gate 		param_len = ntohs(ph->sph_len);
517*0Sstevel@tonic-gate 		if (param_len < sizeof (*ph) || param_len > rlen) {
518*0Sstevel@tonic-gate 			break;
519*0Sstevel@tonic-gate 		}
520*0Sstevel@tonic-gate 		idp = (uint32_t *)(ph + 1);
521*0Sstevel@tonic-gate 		oph = sctp_lookup_asconf_param(fph, *idp, plen);
522*0Sstevel@tonic-gate 		if (oph != NULL) {
523*0Sstevel@tonic-gate 			dp = sctp_lookup_asconf_dispatch(ntohs(oph->sph_type));
524*0Sstevel@tonic-gate 			ASSERT(dp);
525*0Sstevel@tonic-gate 			if (dp->asconf_ack) {
526*0Sstevel@tonic-gate 				dp->asconf_ack(sctp, ph, oph, fp);
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 				/* hack. see below */
529*0Sstevel@tonic-gate 				if (oph->sph_type == htons(PARM_ADD_IP) ||
530*0Sstevel@tonic-gate 				    oph->sph_type == htons(PARM_DEL_IP)) {
531*0Sstevel@tonic-gate 					redosrcs = 1;
532*0Sstevel@tonic-gate 				}
533*0Sstevel@tonic-gate 			}
534*0Sstevel@tonic-gate 		}
535*0Sstevel@tonic-gate 
536*0Sstevel@tonic-gate 		ph = sctp_next_parm(ph, &rlen);
537*0Sstevel@tonic-gate 		if (ph == NULL)
538*0Sstevel@tonic-gate 			break;
539*0Sstevel@tonic-gate 	}
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate 	/*
542*0Sstevel@tonic-gate 	 * Pass implicit replies to callbacks:
543*0Sstevel@tonic-gate 	 * For each original request, look up its parameter
544*0Sstevel@tonic-gate 	 * in the ACK. If there is no corresponding reply,
545*0Sstevel@tonic-gate 	 * call the callback with a NULL parameter, indicating
546*0Sstevel@tonic-gate 	 * success.
547*0Sstevel@tonic-gate 	 */
548*0Sstevel@tonic-gate 	rlen = plen;
549*0Sstevel@tonic-gate 	plen = ntohs(ch->sch_len) - sizeof (*ch) - sizeof (*idp);
550*0Sstevel@tonic-gate 	oph = fph;
551*0Sstevel@tonic-gate 	fph = (sctp_parm_hdr_t *)((char *)ch + sizeof (sctp_chunk_hdr_t) +
552*0Sstevel@tonic-gate 	    sizeof (uint32_t));
553*0Sstevel@tonic-gate 	while (rlen > 0) {
554*0Sstevel@tonic-gate 		idp = (uint32_t *)(oph + 1);
555*0Sstevel@tonic-gate 		ph = sctp_lookup_asconf_param(fph, *idp, plen);
556*0Sstevel@tonic-gate 		if (ph == NULL) {
557*0Sstevel@tonic-gate 			dp = sctp_lookup_asconf_dispatch(ntohs(oph->sph_type));
558*0Sstevel@tonic-gate 			ASSERT(dp);
559*0Sstevel@tonic-gate 			if (dp->asconf_ack) {
560*0Sstevel@tonic-gate 				dp->asconf_ack(sctp, NULL, oph, fp);
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 				/* hack. see below */
563*0Sstevel@tonic-gate 				if (oph->sph_type == htons(PARM_ADD_IP) ||
564*0Sstevel@tonic-gate 				    oph->sph_type == htons(PARM_DEL_IP)) {
565*0Sstevel@tonic-gate 					redosrcs = 1;
566*0Sstevel@tonic-gate 				}
567*0Sstevel@tonic-gate 			}
568*0Sstevel@tonic-gate 		}
569*0Sstevel@tonic-gate 		oph = sctp_next_parm(oph, &rlen);
570*0Sstevel@tonic-gate 		if (oph == NULL) {
571*0Sstevel@tonic-gate 			break;
572*0Sstevel@tonic-gate 		}
573*0Sstevel@tonic-gate 	}
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate 	/* We can now free up the first chunk in the cxmit list */
576*0Sstevel@tonic-gate 	mp = sctp->sctp_cxmit_list;
577*0Sstevel@tonic-gate 	sctp->sctp_cxmit_list = mp->b_cont;
578*0Sstevel@tonic-gate 	mp->b_cont = NULL;
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 	fp = SCTP_CHUNK_DEST(mp);
581*0Sstevel@tonic-gate 	ASSERT(fp != NULL && fp->suna >= MBLKL(mp));
582*0Sstevel@tonic-gate 	fp->suna -= MBLKL(mp);
583*0Sstevel@tonic-gate 	freeb(mp);
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 	/* can now send the next control chunk */
586*0Sstevel@tonic-gate 	if (sctp->sctp_cxmit_list != NULL)
587*0Sstevel@tonic-gate 		sctp_wput_asconf(sctp, NULL);
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 	/*
590*0Sstevel@tonic-gate 	 * If an add-ip or del-ip has completed (successfully or
591*0Sstevel@tonic-gate 	 * unsuccessfully), the pool of available source addresses
592*0Sstevel@tonic-gate 	 * may have changed, so we need to redo faddr source
593*0Sstevel@tonic-gate 	 * address selections. This is a bit of a hack since
594*0Sstevel@tonic-gate 	 * this really belongs in the add/del-ip code. However,
595*0Sstevel@tonic-gate 	 * that code consists of callbacks called for *each*
596*0Sstevel@tonic-gate 	 * add/del-ip parameter, and sctp_redo_faddr_srcs() is
597*0Sstevel@tonic-gate 	 * expensive enough that we really don't want to be
598*0Sstevel@tonic-gate 	 * doing it for each one. So we do it once here.
599*0Sstevel@tonic-gate 	 */
600*0Sstevel@tonic-gate 	if (redosrcs)
601*0Sstevel@tonic-gate 		sctp_redo_faddr_srcs(sctp);
602*0Sstevel@tonic-gate }
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate static void
605*0Sstevel@tonic-gate sctp_rc_timer(sctp_t *sctp, sctp_faddr_t *fp)
606*0Sstevel@tonic-gate {
607*0Sstevel@tonic-gate #define	SCTP_CLR_SENT_FLAG(mp)	((mp)->b_flag &= ~SCTP_CHUNK_FLAG_SENT)
608*0Sstevel@tonic-gate 	sctp_faddr_t	*nfp;
609*0Sstevel@tonic-gate 	sctp_faddr_t	*ofp;
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 	ASSERT(fp != NULL);
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 	fp->rc_timer_running = 0;
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate 	if (sctp->sctp_state != SCTPS_ESTABLISHED ||
616*0Sstevel@tonic-gate 	    sctp->sctp_cxmit_list == NULL) {
617*0Sstevel@tonic-gate 		return;
618*0Sstevel@tonic-gate 	}
619*0Sstevel@tonic-gate 	/*
620*0Sstevel@tonic-gate 	 * Not a retransmission, this was deferred due to some error
621*0Sstevel@tonic-gate 	 * condition
622*0Sstevel@tonic-gate 	 */
623*0Sstevel@tonic-gate 	if (!SCTP_CHUNK_ISSENT(sctp->sctp_cxmit_list)) {
624*0Sstevel@tonic-gate 		sctp_wput_asconf(sctp, fp);
625*0Sstevel@tonic-gate 		return;
626*0Sstevel@tonic-gate 	}
627*0Sstevel@tonic-gate 	/*
628*0Sstevel@tonic-gate 	 * The sent flag indicates if the msg has been sent on this fp.
629*0Sstevel@tonic-gate 	 */
630*0Sstevel@tonic-gate 	SCTP_CLR_SENT_FLAG(sctp->sctp_cxmit_list);
631*0Sstevel@tonic-gate 	/* Retransmission */
632*0Sstevel@tonic-gate 	if (sctp->sctp_strikes >= sctp->sctp_pa_max_rxt) {
633*0Sstevel@tonic-gate 		/* time to give up */
634*0Sstevel@tonic-gate 		BUMP_MIB(&sctp_mib, sctpAborted);
635*0Sstevel@tonic-gate 		sctp_assoc_event(sctp, SCTP_COMM_LOST, 0, NULL);
636*0Sstevel@tonic-gate 		sctp_clean_death(sctp, ETIMEDOUT);
637*0Sstevel@tonic-gate 		return;
638*0Sstevel@tonic-gate 	}
639*0Sstevel@tonic-gate 	if (fp->strikes >= fp->max_retr) {
640*0Sstevel@tonic-gate 		if (sctp_faddr_dead(sctp, fp, SCTP_FADDRS_DOWN) == -1)
641*0Sstevel@tonic-gate 			return;
642*0Sstevel@tonic-gate 	}
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 	fp->strikes++;
645*0Sstevel@tonic-gate 	sctp->sctp_strikes++;
646*0Sstevel@tonic-gate 	SCTP_CALC_RXT(fp, sctp->sctp_rto_max);
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 	nfp = sctp_rotate_faddr(sctp, fp);
649*0Sstevel@tonic-gate 	sctp->sctp_cchunk_pend = 0;
650*0Sstevel@tonic-gate 	ofp = SCTP_CHUNK_DEST(sctp->sctp_cxmit_list);
651*0Sstevel@tonic-gate 	SCTP_SET_CHUNK_DEST(sctp->sctp_cxmit_list, NULL);
652*0Sstevel@tonic-gate 	ASSERT(ofp != NULL && ofp == fp);
653*0Sstevel@tonic-gate 	ASSERT(ofp->suna >= MBLKL(sctp->sctp_cxmit_list));
654*0Sstevel@tonic-gate 	/*
655*0Sstevel@tonic-gate 	 * Enter slow start for this destination.
656*0Sstevel@tonic-gate 	 * XXX anything in the data path that needs to be considered?
657*0Sstevel@tonic-gate 	 */
658*0Sstevel@tonic-gate 	ofp->ssthresh = ofp->cwnd / 2;
659*0Sstevel@tonic-gate 	if (ofp->ssthresh < 2 * ofp->sfa_pmss)
660*0Sstevel@tonic-gate 		ofp->ssthresh = 2 * ofp->sfa_pmss;
661*0Sstevel@tonic-gate 	ofp->cwnd = ofp->sfa_pmss;
662*0Sstevel@tonic-gate 	ofp->pba = 0;
663*0Sstevel@tonic-gate 	ofp->suna -= MBLKL(sctp->sctp_cxmit_list);
664*0Sstevel@tonic-gate 	/*
665*0Sstevel@tonic-gate 	 * The rexmit flags is used to determine if a serial number needs to
666*0Sstevel@tonic-gate 	 * be assigned or not, so once set we leave it there.
667*0Sstevel@tonic-gate 	 */
668*0Sstevel@tonic-gate 	if (!SCTP_CHUNK_WANT_REXMIT(sctp->sctp_cxmit_list))
669*0Sstevel@tonic-gate 		SCTP_CHUNK_REXMIT(sctp->sctp_cxmit_list);
670*0Sstevel@tonic-gate 	sctp_wput_asconf(sctp, nfp);
671*0Sstevel@tonic-gate #undef	SCTP_CLR_SENT_FLAG
672*0Sstevel@tonic-gate }
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate void
675*0Sstevel@tonic-gate sctp_wput_asconf(sctp_t *sctp, sctp_faddr_t *fp)
676*0Sstevel@tonic-gate {
677*0Sstevel@tonic-gate #define	SCTP_SET_SENT_FLAG(mp)	((mp)->b_flag = SCTP_CHUNK_FLAG_SENT)
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 	mblk_t 			*mp;
680*0Sstevel@tonic-gate 	mblk_t			*ipmp;
681*0Sstevel@tonic-gate 	uint32_t 		*snp;
682*0Sstevel@tonic-gate 	sctp_parm_hdr_t		*ph;
683*0Sstevel@tonic-gate 	boolean_t		isv4;
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 	if (sctp->sctp_cchunk_pend || sctp->sctp_cxmit_list == NULL ||
686*0Sstevel@tonic-gate 	    /* Queue it for later transmission if not yet established */
687*0Sstevel@tonic-gate 	    sctp->sctp_state < SCTPS_ESTABLISHED) {
688*0Sstevel@tonic-gate 		ip2dbg(("sctp_wput_asconf: cchunk pending? (%d) or null "\
689*0Sstevel@tonic-gate 		    "sctp_cxmit_list? (%s) or incorrect state? (%x)\n",
690*0Sstevel@tonic-gate 		    sctp->sctp_cchunk_pend, sctp->sctp_cxmit_list == NULL ?
691*0Sstevel@tonic-gate 		    "yes" : "no", sctp->sctp_state));
692*0Sstevel@tonic-gate 		return;
693*0Sstevel@tonic-gate 	}
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 	if (fp == NULL)
696*0Sstevel@tonic-gate 		fp = sctp->sctp_current;
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate 	/* OK to send */
699*0Sstevel@tonic-gate 	ipmp = sctp_make_mp(sctp, fp, 0);
700*0Sstevel@tonic-gate 	if (ipmp == NULL) {
701*0Sstevel@tonic-gate 		SCTP_FADDR_RC_TIMER_RESTART(sctp, fp, fp->rto);
702*0Sstevel@tonic-gate 		return;
703*0Sstevel@tonic-gate 	}
704*0Sstevel@tonic-gate 	mp = sctp->sctp_cxmit_list;
705*0Sstevel@tonic-gate 	/* Fill in the mandatory  Address Parameter TLV */
706*0Sstevel@tonic-gate 	isv4 = (fp != NULL) ? fp->isv4 : sctp->sctp_current->isv4;
707*0Sstevel@tonic-gate 	ph = (sctp_parm_hdr_t *)(mp->b_rptr + sizeof (sctp_chunk_hdr_t) +
708*0Sstevel@tonic-gate 	    sizeof (uint32_t));
709*0Sstevel@tonic-gate 	if (isv4) {
710*0Sstevel@tonic-gate 		ipha_t		*ipha = (ipha_t *)ipmp->b_rptr;
711*0Sstevel@tonic-gate 		in6_addr_t	ipaddr;
712*0Sstevel@tonic-gate 		ipaddr_t	addr4;
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate 		ph->sph_type = htons(PARM_ADDR4);
715*0Sstevel@tonic-gate 		ph->sph_len = htons(PARM_ADDR4_LEN);
716*0Sstevel@tonic-gate 		if (ipha->ipha_src != INADDR_ANY) {
717*0Sstevel@tonic-gate 			bcopy(&ipha->ipha_src, ph + 1, IP_ADDR_LEN);
718*0Sstevel@tonic-gate 		} else {
719*0Sstevel@tonic-gate 			ipaddr = sctp_get_valid_addr(sctp, B_FALSE);
720*0Sstevel@tonic-gate 			IN6_V4MAPPED_TO_IPADDR(&ipaddr, addr4);
721*0Sstevel@tonic-gate 			bcopy(&addr4, ph + 1, IP_ADDR_LEN);
722*0Sstevel@tonic-gate 		}
723*0Sstevel@tonic-gate 	} else {
724*0Sstevel@tonic-gate 		ip6_t		*ip6 = (ip6_t *)ipmp->b_rptr;
725*0Sstevel@tonic-gate 		in6_addr_t	ipaddr;
726*0Sstevel@tonic-gate 
727*0Sstevel@tonic-gate 		ph->sph_type = htons(PARM_ADDR6);
728*0Sstevel@tonic-gate 		ph->sph_len = htons(PARM_ADDR6_LEN);
729*0Sstevel@tonic-gate 		if (!IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
730*0Sstevel@tonic-gate 			bcopy(&ip6->ip6_src, ph + 1, IPV6_ADDR_LEN);
731*0Sstevel@tonic-gate 		} else {
732*0Sstevel@tonic-gate 			ipaddr = sctp_get_valid_addr(sctp, B_TRUE);
733*0Sstevel@tonic-gate 			bcopy(&ipaddr, ph + 1, IPV6_ADDR_LEN);
734*0Sstevel@tonic-gate 		}
735*0Sstevel@tonic-gate 	}
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate 	/* Don't exceed CWND */
738*0Sstevel@tonic-gate 	if ((MBLKL(mp) > (fp->cwnd - fp->suna)) ||
739*0Sstevel@tonic-gate 	    ((mp = dupb(sctp->sctp_cxmit_list)) == NULL)) {
740*0Sstevel@tonic-gate 		SCTP_FADDR_RC_TIMER_RESTART(sctp, fp, fp->rto);
741*0Sstevel@tonic-gate 		freeb(ipmp);
742*0Sstevel@tonic-gate 		return;
743*0Sstevel@tonic-gate 	}
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 	/* Set the serial number now, if sending for the first time */
746*0Sstevel@tonic-gate 	if (!SCTP_CHUNK_WANT_REXMIT(mp)) {
747*0Sstevel@tonic-gate 		snp = (uint32_t *)(mp->b_rptr + sizeof (sctp_chunk_hdr_t));
748*0Sstevel@tonic-gate 		*snp = htonl(sctp->sctp_lcsn++);
749*0Sstevel@tonic-gate 	}
750*0Sstevel@tonic-gate 	SCTP_CHUNK_CLEAR_FLAGS(mp);
751*0Sstevel@tonic-gate 	fp->suna += MBLKL(mp);
752*0Sstevel@tonic-gate 	/* Attach the header and send the chunk */
753*0Sstevel@tonic-gate 	ipmp->b_cont = mp;
754*0Sstevel@tonic-gate 	sctp_set_iplen(sctp, ipmp);
755*0Sstevel@tonic-gate 	sctp->sctp_cchunk_pend = 1;
756*0Sstevel@tonic-gate 
757*0Sstevel@tonic-gate 	SCTP_SET_SENT_FLAG(sctp->sctp_cxmit_list);
758*0Sstevel@tonic-gate 	SCTP_SET_CHUNK_DEST(sctp->sctp_cxmit_list, fp);
759*0Sstevel@tonic-gate 	sctp_add_sendq(sctp, ipmp);
760*0Sstevel@tonic-gate 	SCTP_FADDR_RC_TIMER_RESTART(sctp, fp, fp->rto);
761*0Sstevel@tonic-gate #undef	SCTP_SET_SENT_FLAG
762*0Sstevel@tonic-gate }
763*0Sstevel@tonic-gate 
764*0Sstevel@tonic-gate /*
765*0Sstevel@tonic-gate  * Generate ASCONF error param, include errph, if present.
766*0Sstevel@tonic-gate  */
767*0Sstevel@tonic-gate static mblk_t *
768*0Sstevel@tonic-gate sctp_asconf_adderr(int err, sctp_parm_hdr_t *errph, uint32_t cid)
769*0Sstevel@tonic-gate {
770*0Sstevel@tonic-gate 	mblk_t		*mp;
771*0Sstevel@tonic-gate 	sctp_parm_hdr_t	*eph;
772*0Sstevel@tonic-gate 	sctp_parm_hdr_t	*wph;
773*0Sstevel@tonic-gate 	size_t		len;
774*0Sstevel@tonic-gate 	size_t		elen = 0;
775*0Sstevel@tonic-gate 
776*0Sstevel@tonic-gate 	len = sizeof (*wph) + sizeof (*eph) + sizeof (cid);
777*0Sstevel@tonic-gate 	if (errph != NULL) {
778*0Sstevel@tonic-gate 		elen = ntohs(errph->sph_len);
779*0Sstevel@tonic-gate 		len += elen;
780*0Sstevel@tonic-gate 	}
781*0Sstevel@tonic-gate 	mp = allocb(len, BPRI_MED);
782*0Sstevel@tonic-gate 	if (mp == NULL) {
783*0Sstevel@tonic-gate 		return (NULL);
784*0Sstevel@tonic-gate 	}
785*0Sstevel@tonic-gate 	wph = (sctp_parm_hdr_t *)mp->b_rptr;
786*0Sstevel@tonic-gate 	/* error cause wrapper */
787*0Sstevel@tonic-gate 	wph->sph_type = htons(PARM_ERROR_IND);
788*0Sstevel@tonic-gate 	wph->sph_len = htons(len);
789*0Sstevel@tonic-gate 	bcopy(&cid, wph + 1, sizeof (uint32_t));
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 	/* error cause */
792*0Sstevel@tonic-gate 	eph = (sctp_parm_hdr_t *)((char *)wph + sizeof (sctp_parm_hdr_t) +
793*0Sstevel@tonic-gate 	    sizeof (cid));
794*0Sstevel@tonic-gate 	eph->sph_type = htons(err);
795*0Sstevel@tonic-gate 	eph->sph_len = htons(len - sizeof (*wph) - sizeof (cid));
796*0Sstevel@tonic-gate 	mp->b_wptr = (uchar_t *)(eph + 1);
797*0Sstevel@tonic-gate 
798*0Sstevel@tonic-gate 	/* details */
799*0Sstevel@tonic-gate 	if (elen > 0) {
800*0Sstevel@tonic-gate 		bcopy(errph, mp->b_wptr, elen);
801*0Sstevel@tonic-gate 		mp->b_wptr += elen;
802*0Sstevel@tonic-gate 	}
803*0Sstevel@tonic-gate 	return (mp);
804*0Sstevel@tonic-gate }
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate static mblk_t *
807*0Sstevel@tonic-gate sctp_check_addip_addr(sctp_parm_hdr_t *ph, sctp_parm_hdr_t *oph, int *cont,
808*0Sstevel@tonic-gate     uint32_t cid, in6_addr_t *raddr)
809*0Sstevel@tonic-gate {
810*0Sstevel@tonic-gate 	uint16_t	atype;
811*0Sstevel@tonic-gate 	uint16_t	alen;
812*0Sstevel@tonic-gate 	mblk_t		*mp;
813*0Sstevel@tonic-gate 	in6_addr_t	addr;
814*0Sstevel@tonic-gate 	ipaddr_t	*addr4;
815*0Sstevel@tonic-gate 
816*0Sstevel@tonic-gate 	atype = ntohs(ph->sph_type);
817*0Sstevel@tonic-gate 	alen = ntohs(ph->sph_len);
818*0Sstevel@tonic-gate 
819*0Sstevel@tonic-gate 	if (atype != PARM_ADDR4 && atype != PARM_ADDR6) {
820*0Sstevel@tonic-gate 		mp = sctp_asconf_adderr(SCTP_ERR_BAD_MANDPARM, oph, cid);
821*0Sstevel@tonic-gate 		if (mp == NULL) {
822*0Sstevel@tonic-gate 			*cont = -1;
823*0Sstevel@tonic-gate 		}
824*0Sstevel@tonic-gate 		return (mp);
825*0Sstevel@tonic-gate 	}
826*0Sstevel@tonic-gate 	if ((atype == PARM_ADDR4 && alen < PARM_ADDR4_LEN) ||
827*0Sstevel@tonic-gate 	    (atype == PARM_ADDR6 && alen < PARM_ADDR6_LEN)) {
828*0Sstevel@tonic-gate 		mp = sctp_asconf_adderr(SCTP_ERR_BAD_MANDPARM, oph, cid);
829*0Sstevel@tonic-gate 		if (mp == NULL) {
830*0Sstevel@tonic-gate 			*cont = -1;
831*0Sstevel@tonic-gate 		}
832*0Sstevel@tonic-gate 		return (mp);
833*0Sstevel@tonic-gate 	}
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	/* Address parameter is present; extract and screen it */
836*0Sstevel@tonic-gate 	if (atype == PARM_ADDR4) {
837*0Sstevel@tonic-gate 		addr4 = (ipaddr_t *)(ph + 1);
838*0Sstevel@tonic-gate 		IN6_IPADDR_TO_V4MAPPED(*addr4, &addr);
839*0Sstevel@tonic-gate 
840*0Sstevel@tonic-gate 		/* screen XXX loopback to scoping */
841*0Sstevel@tonic-gate 		if (*addr4 == 0 || *addr4 == INADDR_BROADCAST ||
842*0Sstevel@tonic-gate 		    *addr4 == htonl(INADDR_LOOPBACK) || IN_MULTICAST(*addr4)) {
843*0Sstevel@tonic-gate 			dprint(1, ("addip: addr not unicast: %x:%x:%x:%x\n",
844*0Sstevel@tonic-gate 			    SCTP_PRINTADDR(addr)));
845*0Sstevel@tonic-gate 			mp = sctp_asconf_adderr(SCTP_ERR_BAD_MANDPARM, oph,
846*0Sstevel@tonic-gate 			    cid);
847*0Sstevel@tonic-gate 			if (mp == NULL) {
848*0Sstevel@tonic-gate 				*cont = -1;
849*0Sstevel@tonic-gate 			}
850*0Sstevel@tonic-gate 			return (mp);
851*0Sstevel@tonic-gate 		}
852*0Sstevel@tonic-gate 		/*
853*0Sstevel@tonic-gate 		 * XXX also need to check for subnet
854*0Sstevel@tonic-gate 		 * broadcasts. This should probably
855*0Sstevel@tonic-gate 		 * wait until we have full access
856*0Sstevel@tonic-gate 		 * to the ILL tables.
857*0Sstevel@tonic-gate 		 */
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate 	} else {
860*0Sstevel@tonic-gate 		bcopy(ph + 1, &addr, sizeof (addr));
861*0Sstevel@tonic-gate 
862*0Sstevel@tonic-gate 		/* screen XXX loopback to scoping */
863*0Sstevel@tonic-gate 		if (IN6_IS_ADDR_LINKLOCAL(&addr) ||
864*0Sstevel@tonic-gate 		    IN6_IS_ADDR_MULTICAST(&addr) ||
865*0Sstevel@tonic-gate 		    IN6_IS_ADDR_LOOPBACK(&addr)) {
866*0Sstevel@tonic-gate 			dprint(1, ("addip: addr not unicast: %x:%x:%x:%x\n",
867*0Sstevel@tonic-gate 			    SCTP_PRINTADDR(addr)));
868*0Sstevel@tonic-gate 			mp = sctp_asconf_adderr(SCTP_ERR_BAD_MANDPARM, oph,
869*0Sstevel@tonic-gate 			    cid);
870*0Sstevel@tonic-gate 			if (mp == NULL) {
871*0Sstevel@tonic-gate 				*cont = -1;
872*0Sstevel@tonic-gate 			}
873*0Sstevel@tonic-gate 			return (mp);
874*0Sstevel@tonic-gate 		}
875*0Sstevel@tonic-gate 
876*0Sstevel@tonic-gate 	}
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate 	/* OK */
879*0Sstevel@tonic-gate 	*raddr = addr;
880*0Sstevel@tonic-gate 	return (NULL);
881*0Sstevel@tonic-gate }
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate /*
884*0Sstevel@tonic-gate  * Handles both add and delete address requests.
885*0Sstevel@tonic-gate  */
886*0Sstevel@tonic-gate static mblk_t *
887*0Sstevel@tonic-gate sctp_addip_req(sctp_t *sctp, sctp_parm_hdr_t *ph, uint32_t cid,
888*0Sstevel@tonic-gate     sctp_faddr_t *fp, int *cont, int act)
889*0Sstevel@tonic-gate {
890*0Sstevel@tonic-gate 	in6_addr_t	addr;
891*0Sstevel@tonic-gate 	uint16_t	type;
892*0Sstevel@tonic-gate 	mblk_t		*mp;
893*0Sstevel@tonic-gate 	sctp_faddr_t	*nfp;
894*0Sstevel@tonic-gate 	sctp_parm_hdr_t	*oph;
895*0Sstevel@tonic-gate 
896*0Sstevel@tonic-gate 	*cont = 1;
897*0Sstevel@tonic-gate 
898*0Sstevel@tonic-gate 	/* Send back an authorization error if addip is disabled */
899*0Sstevel@tonic-gate 	if (!sctp_addip_enabled) {
900*0Sstevel@tonic-gate 		mp = sctp_asconf_adderr(SCTP_ERR_UNAUTHORIZED, ph, cid);
901*0Sstevel@tonic-gate 		if (mp == NULL)
902*0Sstevel@tonic-gate 			*cont = -1;
903*0Sstevel@tonic-gate 		return (mp);
904*0Sstevel@tonic-gate 	}
905*0Sstevel@tonic-gate 	/* Check input */
906*0Sstevel@tonic-gate 	if (ntohs(ph->sph_len) < (sizeof (*ph) * 2)) {
907*0Sstevel@tonic-gate 		mp = sctp_asconf_adderr(SCTP_ERR_BAD_MANDPARM, ph, cid);
908*0Sstevel@tonic-gate 		if (mp == NULL) {
909*0Sstevel@tonic-gate 			*cont = -1;
910*0Sstevel@tonic-gate 		}
911*0Sstevel@tonic-gate 		return (mp);
912*0Sstevel@tonic-gate 	}
913*0Sstevel@tonic-gate 
914*0Sstevel@tonic-gate 	type = ntohs(ph->sph_type);
915*0Sstevel@tonic-gate 	oph = ph;
916*0Sstevel@tonic-gate 	ph = (sctp_parm_hdr_t *)((char *)ph + sizeof (sctp_parm_hdr_t) +
917*0Sstevel@tonic-gate 	    sizeof (cid));
918*0Sstevel@tonic-gate 	mp = sctp_check_addip_addr(ph, oph, cont, cid, &addr);
919*0Sstevel@tonic-gate 	if (mp != NULL)
920*0Sstevel@tonic-gate 		return (mp);
921*0Sstevel@tonic-gate 
922*0Sstevel@tonic-gate 	if (type == PARM_ADD_IP) {
923*0Sstevel@tonic-gate 		if (sctp_lookup_faddr(sctp, &addr) != NULL) {
924*0Sstevel@tonic-gate 			/* Address is already part of association */
925*0Sstevel@tonic-gate 			dprint(1, ("addip: addr already here: %x:%x:%x:%x\n",
926*0Sstevel@tonic-gate 			    SCTP_PRINTADDR(addr)));
927*0Sstevel@tonic-gate 			mp = sctp_asconf_adderr(SCTP_ERR_BAD_MANDPARM, oph,
928*0Sstevel@tonic-gate 			    cid);
929*0Sstevel@tonic-gate 			if (mp == NULL) {
930*0Sstevel@tonic-gate 				*cont = -1;
931*0Sstevel@tonic-gate 			}
932*0Sstevel@tonic-gate 			return (mp);
933*0Sstevel@tonic-gate 		}
934*0Sstevel@tonic-gate 
935*0Sstevel@tonic-gate 		if (!act) {
936*0Sstevel@tonic-gate 			return (NULL);
937*0Sstevel@tonic-gate 		}
938*0Sstevel@tonic-gate 		/* Add the new address */
939*0Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
940*0Sstevel@tonic-gate 		if (sctp_add_faddr(sctp, &addr, KM_NOSLEEP) != 0) {
941*0Sstevel@tonic-gate 			mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
942*0Sstevel@tonic-gate 			/* no memory */
943*0Sstevel@tonic-gate 			*cont = -1;
944*0Sstevel@tonic-gate 			return (NULL);
945*0Sstevel@tonic-gate 		}
946*0Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
947*0Sstevel@tonic-gate 		sctp_intf_event(sctp, addr, SCTP_ADDR_ADDED, 0);
948*0Sstevel@tonic-gate 	} else if (type == PARM_DEL_IP) {
949*0Sstevel@tonic-gate 		nfp = sctp_lookup_faddr(sctp, &addr);
950*0Sstevel@tonic-gate 		if (nfp == NULL) {
951*0Sstevel@tonic-gate 			/*
952*0Sstevel@tonic-gate 			 * Peer is trying to delete an address that is not
953*0Sstevel@tonic-gate 			 * part of the association.
954*0Sstevel@tonic-gate 			 */
955*0Sstevel@tonic-gate 			dprint(1, ("delip: addr not here: %x:%x:%x:%x\n",
956*0Sstevel@tonic-gate 			    SCTP_PRINTADDR(addr)));
957*0Sstevel@tonic-gate 			mp = sctp_asconf_adderr(SCTP_ERR_BAD_MANDPARM, oph,
958*0Sstevel@tonic-gate 			    cid);
959*0Sstevel@tonic-gate 			if (mp == NULL) {
960*0Sstevel@tonic-gate 				*cont = -1;
961*0Sstevel@tonic-gate 			}
962*0Sstevel@tonic-gate 			return (mp);
963*0Sstevel@tonic-gate 		}
964*0Sstevel@tonic-gate 		if (sctp->sctp_faddrs == nfp && nfp->next == NULL) {
965*0Sstevel@tonic-gate 			/* Peer is trying to delete last address */
966*0Sstevel@tonic-gate 			dprint(1, ("delip: del last addr: %x:%x:%x:%x\n",
967*0Sstevel@tonic-gate 			    SCTP_PRINTADDR(addr)));
968*0Sstevel@tonic-gate 			mp = sctp_asconf_adderr(SCTP_ERR_DEL_LAST_ADDR, oph,
969*0Sstevel@tonic-gate 			    cid);
970*0Sstevel@tonic-gate 			if (mp == NULL) {
971*0Sstevel@tonic-gate 				*cont = -1;
972*0Sstevel@tonic-gate 			}
973*0Sstevel@tonic-gate 			return (mp);
974*0Sstevel@tonic-gate 		}
975*0Sstevel@tonic-gate 		if (nfp == fp) {
976*0Sstevel@tonic-gate 			/* Peer is trying to delete source address */
977*0Sstevel@tonic-gate 			dprint(1, ("delip: del src addr: %x:%x:%x:%x\n",
978*0Sstevel@tonic-gate 			    SCTP_PRINTADDR(addr)));
979*0Sstevel@tonic-gate 			mp = sctp_asconf_adderr(SCTP_ERR_DEL_SRC_ADDR, oph,
980*0Sstevel@tonic-gate 			    cid);
981*0Sstevel@tonic-gate 			if (mp == NULL) {
982*0Sstevel@tonic-gate 				*cont = -1;
983*0Sstevel@tonic-gate 			}
984*0Sstevel@tonic-gate 			return (mp);
985*0Sstevel@tonic-gate 		}
986*0Sstevel@tonic-gate 		if (!act) {
987*0Sstevel@tonic-gate 			return (NULL);
988*0Sstevel@tonic-gate 		}
989*0Sstevel@tonic-gate 
990*0Sstevel@tonic-gate 		sctp_unlink_faddr(sctp, nfp);
991*0Sstevel@tonic-gate 		/* Update all references to the deleted faddr */
992*0Sstevel@tonic-gate 		if (sctp->sctp_primary == nfp) {
993*0Sstevel@tonic-gate 			sctp->sctp_primary = fp;
994*0Sstevel@tonic-gate 		}
995*0Sstevel@tonic-gate 		if (sctp->sctp_current == nfp) {
996*0Sstevel@tonic-gate 			sctp->sctp_current = fp;
997*0Sstevel@tonic-gate 			sctp->sctp_mss = fp->sfa_pmss;
998*0Sstevel@tonic-gate 			sctp_faddr2hdraddr(fp, sctp);
999*0Sstevel@tonic-gate 
1000*0Sstevel@tonic-gate 			if (!SCTP_IS_DETACHED(sctp)) {
1001*0Sstevel@tonic-gate 				sctp_set_ulp_prop(sctp);
1002*0Sstevel@tonic-gate 			}
1003*0Sstevel@tonic-gate 		}
1004*0Sstevel@tonic-gate 		if (sctp->sctp_lastdata == nfp) {
1005*0Sstevel@tonic-gate 			sctp->sctp_lastdata = fp;
1006*0Sstevel@tonic-gate 		}
1007*0Sstevel@tonic-gate 		if (sctp->sctp_shutdown_faddr == nfp) {
1008*0Sstevel@tonic-gate 			sctp->sctp_shutdown_faddr = nfp;
1009*0Sstevel@tonic-gate 		}
1010*0Sstevel@tonic-gate 		if (sctp->sctp_lastfaddr == nfp) {
1011*0Sstevel@tonic-gate 			for (fp = sctp->sctp_faddrs; fp->next; fp = fp->next)
1012*0Sstevel@tonic-gate 				;
1013*0Sstevel@tonic-gate 			sctp->sctp_lastfaddr = fp;
1014*0Sstevel@tonic-gate 		}
1015*0Sstevel@tonic-gate 		sctp_intf_event(sctp, addr, SCTP_ADDR_REMOVED, 0);
1016*0Sstevel@tonic-gate 	} else {
1017*0Sstevel@tonic-gate 		ASSERT(0);
1018*0Sstevel@tonic-gate 	}
1019*0Sstevel@tonic-gate 
1020*0Sstevel@tonic-gate 	/* Successful, don't need to return anything. */
1021*0Sstevel@tonic-gate 	return (NULL);
1022*0Sstevel@tonic-gate }
1023*0Sstevel@tonic-gate 
1024*0Sstevel@tonic-gate /*
1025*0Sstevel@tonic-gate  * Handles both add and delete IP ACKs.
1026*0Sstevel@tonic-gate  */
1027*0Sstevel@tonic-gate /*ARGSUSED*/
1028*0Sstevel@tonic-gate static void
1029*0Sstevel@tonic-gate sctp_addip_ack(sctp_t *sctp, sctp_parm_hdr_t *ph, sctp_parm_hdr_t *oph,
1030*0Sstevel@tonic-gate     sctp_faddr_t *fp)
1031*0Sstevel@tonic-gate {
1032*0Sstevel@tonic-gate 	in6_addr_t		addr;
1033*0Sstevel@tonic-gate 	sctp_saddr_ipif_t	*sp;
1034*0Sstevel@tonic-gate 	ipaddr_t		*addr4;
1035*0Sstevel@tonic-gate 	boolean_t		backout = B_FALSE;
1036*0Sstevel@tonic-gate 	uint16_t		type;
1037*0Sstevel@tonic-gate 	uint32_t		*cid;
1038*0Sstevel@tonic-gate 
1039*0Sstevel@tonic-gate 	/* If the peer doesn't understand Add-IP, remember it */
1040*0Sstevel@tonic-gate 	if (ph != NULL && ph->sph_type == htons(PARM_UNRECOGNIZED)) {
1041*0Sstevel@tonic-gate 		sctp->sctp_understands_addip = B_FALSE;
1042*0Sstevel@tonic-gate 		backout = B_TRUE;
1043*0Sstevel@tonic-gate 	}
1044*0Sstevel@tonic-gate 
1045*0Sstevel@tonic-gate 	/*
1046*0Sstevel@tonic-gate 	 * If OK, continue with the add / delete action, otherwise
1047*0Sstevel@tonic-gate 	 * back out the action.
1048*0Sstevel@tonic-gate 	 */
1049*0Sstevel@tonic-gate 	if (ph != NULL && ph->sph_type != htons(PARM_SUCCESS)) {
1050*0Sstevel@tonic-gate 		backout = B_TRUE;
1051*0Sstevel@tonic-gate 		sctp_error_event(sctp, (sctp_chunk_hdr_t *)ph);
1052*0Sstevel@tonic-gate 	}
1053*0Sstevel@tonic-gate 
1054*0Sstevel@tonic-gate 	type = ntohs(oph->sph_type);
1055*0Sstevel@tonic-gate 	cid = (uint32_t *)(oph + 1);
1056*0Sstevel@tonic-gate 	oph = (sctp_parm_hdr_t *)(cid + 1);
1057*0Sstevel@tonic-gate 	if (oph->sph_type == htons(PARM_ADDR4)) {
1058*0Sstevel@tonic-gate 		addr4 = (ipaddr_t *)(oph + 1);
1059*0Sstevel@tonic-gate 		IN6_IPADDR_TO_V4MAPPED(*addr4, &addr);
1060*0Sstevel@tonic-gate 	} else {
1061*0Sstevel@tonic-gate 		bcopy(oph + 1, &addr, sizeof (addr));
1062*0Sstevel@tonic-gate 	}
1063*0Sstevel@tonic-gate 
1064*0Sstevel@tonic-gate 	sp = sctp_saddr_lookup(sctp, &addr);
1065*0Sstevel@tonic-gate 	ASSERT(sp != NULL);
1066*0Sstevel@tonic-gate 
1067*0Sstevel@tonic-gate 	if (type == PARM_ADD_IP) {
1068*0Sstevel@tonic-gate 		if (backout) {
1069*0Sstevel@tonic-gate 			sctp_del_saddr(sctp, sp);
1070*0Sstevel@tonic-gate 		} else {
1071*0Sstevel@tonic-gate 			sp->saddr_ipif_dontsrc = 0;
1072*0Sstevel@tonic-gate 		}
1073*0Sstevel@tonic-gate 	} else if (type == PARM_DEL_IP) {
1074*0Sstevel@tonic-gate 		if (backout) {
1075*0Sstevel@tonic-gate 			sp->saddr_ipif_delete_pending = 0;
1076*0Sstevel@tonic-gate 			sp->saddr_ipif_dontsrc = 0;
1077*0Sstevel@tonic-gate 		} else {
1078*0Sstevel@tonic-gate 			sctp_del_saddr(sctp, sp);
1079*0Sstevel@tonic-gate 		}
1080*0Sstevel@tonic-gate 	} else {
1081*0Sstevel@tonic-gate 		/* Must be either PARM_ADD_IP or PARM_DEL_IP */
1082*0Sstevel@tonic-gate 		ASSERT(0);
1083*0Sstevel@tonic-gate 	}
1084*0Sstevel@tonic-gate }
1085*0Sstevel@tonic-gate 
1086*0Sstevel@tonic-gate /*ARGSUSED*/
1087*0Sstevel@tonic-gate static mblk_t *
1088*0Sstevel@tonic-gate sctp_setprim_req(sctp_t *sctp, sctp_parm_hdr_t *ph, uint32_t cid,
1089*0Sstevel@tonic-gate     sctp_faddr_t *fp, int *cont, int act)
1090*0Sstevel@tonic-gate {
1091*0Sstevel@tonic-gate 	mblk_t *mp;
1092*0Sstevel@tonic-gate 	sctp_parm_hdr_t *oph;
1093*0Sstevel@tonic-gate 	sctp_faddr_t *nfp;
1094*0Sstevel@tonic-gate 	in6_addr_t addr;
1095*0Sstevel@tonic-gate 
1096*0Sstevel@tonic-gate 	*cont = 1;
1097*0Sstevel@tonic-gate 
1098*0Sstevel@tonic-gate 	/* Check input */
1099*0Sstevel@tonic-gate 	if (ntohs(ph->sph_len) < (sizeof (*ph) * 2)) {
1100*0Sstevel@tonic-gate 		mp = sctp_asconf_adderr(SCTP_ERR_BAD_MANDPARM, ph, cid);
1101*0Sstevel@tonic-gate 		if (mp == NULL) {
1102*0Sstevel@tonic-gate 			*cont = -1;
1103*0Sstevel@tonic-gate 		}
1104*0Sstevel@tonic-gate 		return (mp);
1105*0Sstevel@tonic-gate 	}
1106*0Sstevel@tonic-gate 
1107*0Sstevel@tonic-gate 	oph = ph;
1108*0Sstevel@tonic-gate 	ph = (sctp_parm_hdr_t *)((char *)ph + sizeof (sctp_parm_hdr_t) +
1109*0Sstevel@tonic-gate 	    sizeof (cid));
1110*0Sstevel@tonic-gate 	mp = sctp_check_addip_addr(ph, oph, cont, cid, &addr);
1111*0Sstevel@tonic-gate 	if (mp != NULL) {
1112*0Sstevel@tonic-gate 		return (mp);
1113*0Sstevel@tonic-gate 	}
1114*0Sstevel@tonic-gate 
1115*0Sstevel@tonic-gate 	nfp = sctp_lookup_faddr(sctp, &addr);
1116*0Sstevel@tonic-gate 	if (nfp == NULL) {
1117*0Sstevel@tonic-gate 		/*
1118*0Sstevel@tonic-gate 		 * Peer is trying to set an address that is not
1119*0Sstevel@tonic-gate 		 * part of the association.
1120*0Sstevel@tonic-gate 		 */
1121*0Sstevel@tonic-gate 		dprint(1, ("setprim: addr not here: %x:%x:%x:%x\n",
1122*0Sstevel@tonic-gate 		    SCTP_PRINTADDR(addr)));
1123*0Sstevel@tonic-gate 		mp = sctp_asconf_adderr(SCTP_ERR_BAD_MANDPARM, oph, cid);
1124*0Sstevel@tonic-gate 		if (mp == NULL) {
1125*0Sstevel@tonic-gate 			*cont = -1;
1126*0Sstevel@tonic-gate 		}
1127*0Sstevel@tonic-gate 		return (mp);
1128*0Sstevel@tonic-gate 	}
1129*0Sstevel@tonic-gate 
1130*0Sstevel@tonic-gate 	sctp_intf_event(sctp, addr, SCTP_ADDR_MADE_PRIM, 0);
1131*0Sstevel@tonic-gate 	sctp->sctp_primary = nfp;
1132*0Sstevel@tonic-gate 	if (nfp->state != SCTP_FADDRS_ALIVE || nfp == sctp->sctp_current) {
1133*0Sstevel@tonic-gate 		return (NULL);
1134*0Sstevel@tonic-gate 	}
1135*0Sstevel@tonic-gate 	sctp->sctp_current = nfp;
1136*0Sstevel@tonic-gate 	sctp->sctp_mss = nfp->sfa_pmss;
1137*0Sstevel@tonic-gate 
1138*0Sstevel@tonic-gate 	/* Reset the addrs in the composite header */
1139*0Sstevel@tonic-gate 	sctp_faddr2hdraddr(nfp, sctp);
1140*0Sstevel@tonic-gate 	if (!SCTP_IS_DETACHED(sctp)) {
1141*0Sstevel@tonic-gate 		sctp_set_ulp_prop(sctp);
1142*0Sstevel@tonic-gate 	}
1143*0Sstevel@tonic-gate 
1144*0Sstevel@tonic-gate 	return (NULL);
1145*0Sstevel@tonic-gate }
1146*0Sstevel@tonic-gate 
1147*0Sstevel@tonic-gate /*ARGSUSED*/
1148*0Sstevel@tonic-gate static void
1149*0Sstevel@tonic-gate sctp_setprim_ack(sctp_t *sctp, sctp_parm_hdr_t *ph, sctp_parm_hdr_t *oph,
1150*0Sstevel@tonic-gate     sctp_faddr_t *fp)
1151*0Sstevel@tonic-gate {
1152*0Sstevel@tonic-gate 	if (ph != NULL && ph->sph_type != htons(PARM_SUCCESS)) {
1153*0Sstevel@tonic-gate 		/* If the peer doesn't understand Add-IP, remember it */
1154*0Sstevel@tonic-gate 		if (ph->sph_type == htons(PARM_UNRECOGNIZED)) {
1155*0Sstevel@tonic-gate 			sctp->sctp_understands_addip = B_FALSE;
1156*0Sstevel@tonic-gate 		}
1157*0Sstevel@tonic-gate 		sctp_error_event(sctp, (sctp_chunk_hdr_t *)ph);
1158*0Sstevel@tonic-gate 	}
1159*0Sstevel@tonic-gate 
1160*0Sstevel@tonic-gate 	/* On success we do nothing */
1161*0Sstevel@tonic-gate }
1162*0Sstevel@tonic-gate 
1163*0Sstevel@tonic-gate int
1164*0Sstevel@tonic-gate sctp_add_ip(sctp_t *sctp, const void *addrs, uint32_t cnt)
1165*0Sstevel@tonic-gate {
1166*0Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
1167*0Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
1168*0Sstevel@tonic-gate 	mblk_t			*mp;
1169*0Sstevel@tonic-gate 	int			error = 0;
1170*0Sstevel@tonic-gate 	int			i;
1171*0Sstevel@tonic-gate 	sctp_addip4_t		*ad4;
1172*0Sstevel@tonic-gate 	sctp_addip6_t		*ad6;
1173*0Sstevel@tonic-gate 	sctp_asconf_t		asc[1];
1174*0Sstevel@tonic-gate 	uint16_t		type = htons(PARM_ADD_IP);
1175*0Sstevel@tonic-gate 	boolean_t		v4mapped = B_FALSE;
1176*0Sstevel@tonic-gate 
1177*0Sstevel@tonic-gate 	/* Does the peer understand ASCONF and Add-IP? */
1178*0Sstevel@tonic-gate 	if (!sctp->sctp_understands_asconf || !sctp->sctp_understands_addip)
1179*0Sstevel@tonic-gate 		return (EOPNOTSUPP);
1180*0Sstevel@tonic-gate 
1181*0Sstevel@tonic-gate 	sctp_asconf_init(asc);
1182*0Sstevel@tonic-gate 
1183*0Sstevel@tonic-gate 	/*
1184*0Sstevel@tonic-gate 	 * Screen addresses:
1185*0Sstevel@tonic-gate 	 * If adding:
1186*0Sstevel@tonic-gate 	 *   o Must not already be a part of the association
1187*0Sstevel@tonic-gate 	 *   o Must be AF_INET or AF_INET6
1188*0Sstevel@tonic-gate 	 *   o XXX Must be valid source address for this node
1189*0Sstevel@tonic-gate 	 *   o Must be unicast
1190*0Sstevel@tonic-gate 	 *   o XXX Must fit scoping rules
1191*0Sstevel@tonic-gate 	 * If deleting:
1192*0Sstevel@tonic-gate 	 *   o Must be part of the association
1193*0Sstevel@tonic-gate 	 */
1194*0Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
1195*0Sstevel@tonic-gate 		switch (sctp->sctp_family) {
1196*0Sstevel@tonic-gate 		case AF_INET:
1197*0Sstevel@tonic-gate 			sin4 = (struct sockaddr_in *)addrs + i;
1198*0Sstevel@tonic-gate 			v4mapped = B_TRUE;
1199*0Sstevel@tonic-gate 			break;
1200*0Sstevel@tonic-gate 
1201*0Sstevel@tonic-gate 		case AF_INET6:
1202*0Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)addrs + i;
1203*0Sstevel@tonic-gate 			break;
1204*0Sstevel@tonic-gate 		}
1205*0Sstevel@tonic-gate 
1206*0Sstevel@tonic-gate 		if (v4mapped) {
1207*0Sstevel@tonic-gate 			mp = allocb(sizeof (*ad4), BPRI_MED);
1208*0Sstevel@tonic-gate 			if (mp == NULL) {
1209*0Sstevel@tonic-gate 				error = ENOMEM;
1210*0Sstevel@tonic-gate 				goto fail;
1211*0Sstevel@tonic-gate 			}
1212*0Sstevel@tonic-gate 			mp->b_wptr += sizeof (*ad4);
1213*0Sstevel@tonic-gate 			ad4 = (sctp_addip4_t *)mp->b_rptr;
1214*0Sstevel@tonic-gate 			ad4->sad4_addip_ph.sph_type = type;
1215*0Sstevel@tonic-gate 			ad4->sad4_addip_ph.sph_len =
1216*0Sstevel@tonic-gate 			    htons(sizeof (sctp_parm_hdr_t) +
1217*0Sstevel@tonic-gate 			    PARM_ADDR4_LEN + sizeof (ad4->asconf_req_cid));
1218*0Sstevel@tonic-gate 			ad4->sad4_addr4_ph.sph_type = htons(PARM_ADDR4);
1219*0Sstevel@tonic-gate 			ad4->sad4_addr4_ph.sph_len = htons(PARM_ADDR4_LEN);
1220*0Sstevel@tonic-gate 			ad4->sad4_addr = sin4->sin_addr.s_addr;
1221*0Sstevel@tonic-gate 		} else {
1222*0Sstevel@tonic-gate 			mp = allocb(sizeof (*ad6), BPRI_MED);
1223*0Sstevel@tonic-gate 			if (mp == NULL) {
1224*0Sstevel@tonic-gate 				error = ENOMEM;
1225*0Sstevel@tonic-gate 				goto fail;
1226*0Sstevel@tonic-gate 			}
1227*0Sstevel@tonic-gate 			mp->b_wptr += sizeof (*ad6);
1228*0Sstevel@tonic-gate 			ad6 = (sctp_addip6_t *)mp->b_rptr;
1229*0Sstevel@tonic-gate 			ad6->sad6_addip_ph.sph_type = type;
1230*0Sstevel@tonic-gate 			ad6->sad6_addip_ph.sph_len =
1231*0Sstevel@tonic-gate 			    htons(sizeof (sctp_parm_hdr_t) +
1232*0Sstevel@tonic-gate 			    PARM_ADDR6_LEN + sizeof (ad6->asconf_req_cid));
1233*0Sstevel@tonic-gate 			ad6->sad6_addr6_ph.sph_type = htons(PARM_ADDR6);
1234*0Sstevel@tonic-gate 			ad6->sad6_addr6_ph.sph_len = htons(PARM_ADDR6_LEN);
1235*0Sstevel@tonic-gate 			ad6->sad6_addr = sin6->sin6_addr;
1236*0Sstevel@tonic-gate 		}
1237*0Sstevel@tonic-gate 		error = sctp_asconf_add(asc, mp);
1238*0Sstevel@tonic-gate 		if (error != 0)
1239*0Sstevel@tonic-gate 			goto fail;
1240*0Sstevel@tonic-gate 	}
1241*0Sstevel@tonic-gate 	error = sctp_asconf_send(sctp, asc, sctp->sctp_current);
1242*0Sstevel@tonic-gate 	if (error != 0)
1243*0Sstevel@tonic-gate 		goto fail;
1244*0Sstevel@tonic-gate 
1245*0Sstevel@tonic-gate 	return (0);
1246*0Sstevel@tonic-gate 
1247*0Sstevel@tonic-gate fail:
1248*0Sstevel@tonic-gate 	sctp_asconf_destroy(asc);
1249*0Sstevel@tonic-gate 	return (error);
1250*0Sstevel@tonic-gate }
1251*0Sstevel@tonic-gate 
1252*0Sstevel@tonic-gate int
1253*0Sstevel@tonic-gate sctp_del_ip(sctp_t *sctp, const void *addrs, uint32_t cnt)
1254*0Sstevel@tonic-gate {
1255*0Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
1256*0Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
1257*0Sstevel@tonic-gate 	mblk_t			*mp;
1258*0Sstevel@tonic-gate 	int			error = 0;
1259*0Sstevel@tonic-gate 	int			i;
1260*0Sstevel@tonic-gate 	int			addrcnt = 0;
1261*0Sstevel@tonic-gate 	sctp_addip4_t		*ad4;
1262*0Sstevel@tonic-gate 	sctp_addip6_t		*ad6;
1263*0Sstevel@tonic-gate 	sctp_asconf_t		asc[1];
1264*0Sstevel@tonic-gate 	sctp_saddr_ipif_t	*nsp;
1265*0Sstevel@tonic-gate 	uint16_t		type = htons(PARM_DEL_IP);
1266*0Sstevel@tonic-gate 	boolean_t		v4mapped = B_FALSE;
1267*0Sstevel@tonic-gate 	in6_addr_t		addr;
1268*0Sstevel@tonic-gate 	boolean_t		asconf = B_TRUE;
1269*0Sstevel@tonic-gate 
1270*0Sstevel@tonic-gate 	/* Does the peer understand ASCONF and Add-IP? */
1271*0Sstevel@tonic-gate 	if (sctp->sctp_state <= SCTPS_LISTEN || !sctp_addip_enabled ||
1272*0Sstevel@tonic-gate 	    !sctp->sctp_understands_asconf || !sctp->sctp_understands_addip) {
1273*0Sstevel@tonic-gate 		asconf = B_FALSE;
1274*0Sstevel@tonic-gate 	}
1275*0Sstevel@tonic-gate 
1276*0Sstevel@tonic-gate 	if (asconf)
1277*0Sstevel@tonic-gate 		sctp_asconf_init(asc);
1278*0Sstevel@tonic-gate 	/*
1279*0Sstevel@tonic-gate 	 * Screen addresses:
1280*0Sstevel@tonic-gate 	 * If adding:
1281*0Sstevel@tonic-gate 	 *   o Must not already be a part of the association
1282*0Sstevel@tonic-gate 	 *   o Must be AF_INET or AF_INET6
1283*0Sstevel@tonic-gate 	 *   o XXX Must be valid source address for this node
1284*0Sstevel@tonic-gate 	 *   o Must be unicast
1285*0Sstevel@tonic-gate 	 *   o XXX Must fit scoping rules
1286*0Sstevel@tonic-gate 	 * If deleting:
1287*0Sstevel@tonic-gate 	 *   o Must be part of the association
1288*0Sstevel@tonic-gate 	 */
1289*0Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
1290*0Sstevel@tonic-gate 		switch (sctp->sctp_family) {
1291*0Sstevel@tonic-gate 		case AF_INET:
1292*0Sstevel@tonic-gate 			sin4 = (struct sockaddr_in *)addrs + i;
1293*0Sstevel@tonic-gate 			v4mapped = B_TRUE;
1294*0Sstevel@tonic-gate 			IN6_IPADDR_TO_V4MAPPED(sin4->sin_addr.s_addr, &addr);
1295*0Sstevel@tonic-gate 			break;
1296*0Sstevel@tonic-gate 
1297*0Sstevel@tonic-gate 		case AF_INET6:
1298*0Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)addrs + i;
1299*0Sstevel@tonic-gate 			addr = sin6->sin6_addr;
1300*0Sstevel@tonic-gate 			break;
1301*0Sstevel@tonic-gate 		}
1302*0Sstevel@tonic-gate 		nsp = sctp_saddr_lookup(sctp, &addr);
1303*0Sstevel@tonic-gate 		if (nsp == NULL) {
1304*0Sstevel@tonic-gate 			error = EADDRNOTAVAIL;
1305*0Sstevel@tonic-gate 			goto fail;
1306*0Sstevel@tonic-gate 		}
1307*0Sstevel@tonic-gate 
1308*0Sstevel@tonic-gate 		if (!asconf)
1309*0Sstevel@tonic-gate 			continue;
1310*0Sstevel@tonic-gate 
1311*0Sstevel@tonic-gate 		nsp->saddr_ipif_delete_pending = 1;
1312*0Sstevel@tonic-gate 		nsp->saddr_ipif_dontsrc = 1;
1313*0Sstevel@tonic-gate 		addrcnt++;
1314*0Sstevel@tonic-gate 		if (v4mapped) {
1315*0Sstevel@tonic-gate 			mp = allocb(sizeof (*ad4), BPRI_MED);
1316*0Sstevel@tonic-gate 			if (mp == NULL) {
1317*0Sstevel@tonic-gate 				error = ENOMEM;
1318*0Sstevel@tonic-gate 				goto fail;
1319*0Sstevel@tonic-gate 			}
1320*0Sstevel@tonic-gate 			mp->b_wptr += sizeof (*ad4);
1321*0Sstevel@tonic-gate 			ad4 = (sctp_addip4_t *)mp->b_rptr;
1322*0Sstevel@tonic-gate 			ad4->sad4_addip_ph.sph_type = type;
1323*0Sstevel@tonic-gate 			ad4->sad4_addip_ph.sph_len =
1324*0Sstevel@tonic-gate 			    htons(sizeof (sctp_parm_hdr_t) +
1325*0Sstevel@tonic-gate 			    PARM_ADDR4_LEN + sizeof (ad4->asconf_req_cid));
1326*0Sstevel@tonic-gate 			ad4->sad4_addr4_ph.sph_type = htons(PARM_ADDR4);
1327*0Sstevel@tonic-gate 			ad4->sad4_addr4_ph.sph_len = htons(PARM_ADDR4_LEN);
1328*0Sstevel@tonic-gate 			ad4->sad4_addr = sin4->sin_addr.s_addr;
1329*0Sstevel@tonic-gate 		} else {
1330*0Sstevel@tonic-gate 			mp = allocb(sizeof (*ad6), BPRI_MED);
1331*0Sstevel@tonic-gate 			if (mp == NULL) {
1332*0Sstevel@tonic-gate 				error = ENOMEM;
1333*0Sstevel@tonic-gate 				goto fail;
1334*0Sstevel@tonic-gate 			}
1335*0Sstevel@tonic-gate 			mp->b_wptr += sizeof (*ad6);
1336*0Sstevel@tonic-gate 			ad6 = (sctp_addip6_t *)mp->b_rptr;
1337*0Sstevel@tonic-gate 			ad6->sad6_addip_ph.sph_type = type;
1338*0Sstevel@tonic-gate 			ad6->sad6_addip_ph.sph_len =
1339*0Sstevel@tonic-gate 			    htons(sizeof (sctp_parm_hdr_t) + PARM_ADDR6_LEN +
1340*0Sstevel@tonic-gate 			    sizeof (ad6->asconf_req_cid));
1341*0Sstevel@tonic-gate 			ad6->sad6_addr6_ph.sph_type = htons(PARM_ADDR6);
1342*0Sstevel@tonic-gate 			ad6->sad6_addr6_ph.sph_len = htons(PARM_ADDR6_LEN);
1343*0Sstevel@tonic-gate 			ad6->sad6_addr = addr;
1344*0Sstevel@tonic-gate 		}
1345*0Sstevel@tonic-gate 
1346*0Sstevel@tonic-gate 		error = sctp_asconf_add(asc, mp);
1347*0Sstevel@tonic-gate 		if (error != 0)
1348*0Sstevel@tonic-gate 			goto fail;
1349*0Sstevel@tonic-gate 	}
1350*0Sstevel@tonic-gate 
1351*0Sstevel@tonic-gate 	if (!asconf) {
1352*0Sstevel@tonic-gate 		sctp_del_saddr_list(sctp, addrs, cnt, B_FALSE);
1353*0Sstevel@tonic-gate 		return (0);
1354*0Sstevel@tonic-gate 	}
1355*0Sstevel@tonic-gate 	error = sctp_asconf_send(sctp, asc, sctp->sctp_current);
1356*0Sstevel@tonic-gate 	if (error != 0)
1357*0Sstevel@tonic-gate 		goto fail;
1358*0Sstevel@tonic-gate 	sctp_redo_faddr_srcs(sctp);
1359*0Sstevel@tonic-gate 	return (0);
1360*0Sstevel@tonic-gate 
1361*0Sstevel@tonic-gate fail:
1362*0Sstevel@tonic-gate 	if (!asconf)
1363*0Sstevel@tonic-gate 		return (error);
1364*0Sstevel@tonic-gate 	for (i = 0; i < addrcnt; i++) {
1365*0Sstevel@tonic-gate 		switch (sctp->sctp_family) {
1366*0Sstevel@tonic-gate 		case AF_INET:
1367*0Sstevel@tonic-gate 			sin4 = (struct sockaddr_in *)addrs + i;
1368*0Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&(sin4->sin_addr), &addr);
1369*0Sstevel@tonic-gate 			break;
1370*0Sstevel@tonic-gate 		case AF_INET6:
1371*0Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)addrs + i;
1372*0Sstevel@tonic-gate 			addr = sin6->sin6_addr;
1373*0Sstevel@tonic-gate 			break;
1374*0Sstevel@tonic-gate 		}
1375*0Sstevel@tonic-gate 		nsp = sctp_saddr_lookup(sctp, &addr);
1376*0Sstevel@tonic-gate 		ASSERT(nsp != NULL);
1377*0Sstevel@tonic-gate 		nsp->saddr_ipif_delete_pending = 0;
1378*0Sstevel@tonic-gate 		nsp->saddr_ipif_dontsrc = 0;
1379*0Sstevel@tonic-gate 	}
1380*0Sstevel@tonic-gate 	sctp_asconf_destroy(asc);
1381*0Sstevel@tonic-gate 
1382*0Sstevel@tonic-gate 	return (error);
1383*0Sstevel@tonic-gate }
1384*0Sstevel@tonic-gate 
1385*0Sstevel@tonic-gate int
1386*0Sstevel@tonic-gate sctp_set_peerprim(sctp_t *sctp, const void *inp, uint_t inlen)
1387*0Sstevel@tonic-gate {
1388*0Sstevel@tonic-gate 	const struct sctp_setprim	*prim = inp;
1389*0Sstevel@tonic-gate 	const struct sockaddr_storage	*ss;
1390*0Sstevel@tonic-gate 	struct sockaddr_in *sin;
1391*0Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
1392*0Sstevel@tonic-gate 	in6_addr_t addr;
1393*0Sstevel@tonic-gate 	mblk_t *mp;
1394*0Sstevel@tonic-gate 	sctp_saddr_ipif_t *sp;
1395*0Sstevel@tonic-gate 	sctp_addip4_t *ad4;
1396*0Sstevel@tonic-gate 	sctp_addip6_t *ad6;
1397*0Sstevel@tonic-gate 	sctp_asconf_t asc[1];
1398*0Sstevel@tonic-gate 	int error = 0;
1399*0Sstevel@tonic-gate 
1400*0Sstevel@tonic-gate 	/* Does the peer understand ASCONF and Add-IP? */
1401*0Sstevel@tonic-gate 	if (!sctp->sctp_understands_asconf || !sctp->sctp_understands_addip) {
1402*0Sstevel@tonic-gate 		return (EOPNOTSUPP);
1403*0Sstevel@tonic-gate 	}
1404*0Sstevel@tonic-gate 
1405*0Sstevel@tonic-gate 	if (inlen < sizeof (*prim))
1406*0Sstevel@tonic-gate 		return (EINVAL);
1407*0Sstevel@tonic-gate 
1408*0Sstevel@tonic-gate 	/* Don't do anything if we are not connected */
1409*0Sstevel@tonic-gate 	if (sctp->sctp_state != SCTPS_ESTABLISHED)
1410*0Sstevel@tonic-gate 		return (EINVAL);
1411*0Sstevel@tonic-gate 
1412*0Sstevel@tonic-gate 	ss = &prim->ssp_addr;
1413*0Sstevel@tonic-gate 	sin = NULL;
1414*0Sstevel@tonic-gate 	sin6 = NULL;
1415*0Sstevel@tonic-gate 	if (ss->ss_family == AF_INET) {
1416*0Sstevel@tonic-gate 		sin = (struct sockaddr_in *)ss;
1417*0Sstevel@tonic-gate 		IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &addr);
1418*0Sstevel@tonic-gate 	} else if (ss->ss_family == AF_INET6) {
1419*0Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)ss;
1420*0Sstevel@tonic-gate 		addr = sin6->sin6_addr;
1421*0Sstevel@tonic-gate 	} else {
1422*0Sstevel@tonic-gate 		return (EAFNOSUPPORT);
1423*0Sstevel@tonic-gate 	}
1424*0Sstevel@tonic-gate 	sp = sctp_saddr_lookup(sctp, &addr);
1425*0Sstevel@tonic-gate 	if (sp == NULL)
1426*0Sstevel@tonic-gate 		return (EADDRNOTAVAIL);
1427*0Sstevel@tonic-gate 	sctp_asconf_init(asc);
1428*0Sstevel@tonic-gate 	if (sin) {
1429*0Sstevel@tonic-gate 		mp = allocb(sizeof (*ad4), BPRI_MED);
1430*0Sstevel@tonic-gate 		if (mp == NULL) {
1431*0Sstevel@tonic-gate 			error = ENOMEM;
1432*0Sstevel@tonic-gate 			goto fail;
1433*0Sstevel@tonic-gate 		}
1434*0Sstevel@tonic-gate 		mp->b_wptr += sizeof (*ad4);
1435*0Sstevel@tonic-gate 		ad4 = (sctp_addip4_t *)mp->b_rptr;
1436*0Sstevel@tonic-gate 		ad4->sad4_addip_ph.sph_type = htons(PARM_SET_PRIMARY);
1437*0Sstevel@tonic-gate 		ad4->sad4_addip_ph.sph_len = htons(sizeof (sctp_parm_hdr_t) +
1438*0Sstevel@tonic-gate 		    PARM_ADDR4_LEN + sizeof (ad4->asconf_req_cid));
1439*0Sstevel@tonic-gate 		ad4->sad4_addr4_ph.sph_type = htons(PARM_ADDR4);
1440*0Sstevel@tonic-gate 		ad4->sad4_addr4_ph.sph_len = htons(PARM_ADDR4_LEN);
1441*0Sstevel@tonic-gate 		ad4->sad4_addr = sin->sin_addr.s_addr;
1442*0Sstevel@tonic-gate 	} else {
1443*0Sstevel@tonic-gate 		mp = allocb(sizeof (*ad6), BPRI_MED);
1444*0Sstevel@tonic-gate 		if (mp == NULL) {
1445*0Sstevel@tonic-gate 			error = ENOMEM;
1446*0Sstevel@tonic-gate 			goto fail;
1447*0Sstevel@tonic-gate 		}
1448*0Sstevel@tonic-gate 		mp->b_wptr += sizeof (*ad6);
1449*0Sstevel@tonic-gate 		ad6 = (sctp_addip6_t *)mp->b_rptr;
1450*0Sstevel@tonic-gate 		ad6->sad6_addip_ph.sph_type = htons(PARM_SET_PRIMARY);
1451*0Sstevel@tonic-gate 		ad6->sad6_addip_ph.sph_len = htons(sizeof (sctp_parm_hdr_t) +
1452*0Sstevel@tonic-gate 		    PARM_ADDR6_LEN + sizeof (ad6->asconf_req_cid));
1453*0Sstevel@tonic-gate 		ad6->sad6_addr6_ph.sph_type = htons(PARM_ADDR6);
1454*0Sstevel@tonic-gate 		ad6->sad6_addr6_ph.sph_len = htons(PARM_ADDR6_LEN);
1455*0Sstevel@tonic-gate 		ad6->sad6_addr = sin6->sin6_addr;
1456*0Sstevel@tonic-gate 	}
1457*0Sstevel@tonic-gate 
1458*0Sstevel@tonic-gate 	error = sctp_asconf_add(asc, mp);
1459*0Sstevel@tonic-gate 	if (error != 0) {
1460*0Sstevel@tonic-gate 		goto fail;
1461*0Sstevel@tonic-gate 	}
1462*0Sstevel@tonic-gate 
1463*0Sstevel@tonic-gate 	error = sctp_asconf_send(sctp, asc, sctp->sctp_current);
1464*0Sstevel@tonic-gate 	if (error == 0) {
1465*0Sstevel@tonic-gate 		return (0);
1466*0Sstevel@tonic-gate 	}
1467*0Sstevel@tonic-gate 
1468*0Sstevel@tonic-gate fail:
1469*0Sstevel@tonic-gate 	sctp_asconf_destroy(asc);
1470*0Sstevel@tonic-gate 	return (error);
1471*0Sstevel@tonic-gate }
1472