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